# smartmontools 7.5 — SMART: preguntarle a un disco si se está muriendo. # # ══ POR QUÉ ENTRA ══════════════════════════════════════════════════════════════════════════════ # `censo-distro.py` marca «discos y salud del equipo» **4 de 4 ausente**, con el comentario «nada # que avise de un disco muriéndose». Y en este proyecto eso no es hipotético: la memoria del repo # tiene documentados un disco de 5,9 G que **al llenarse no se degrada, se cae entero**, 19 G de # montones muertos, y un «0 fallan» que era mentira porque no quedaban inodos para escribir el # `.fail`. Todo eso es espacio; **la salud del hardware no la mira nadie**. # # Un disco con sectores reasignados en aumento avisa días antes de morir — pero sólo si alguien # pregunta. `smartctl` es quien pregunta. # # ══ CUESTA UNA RECETA: TODAS SUS DEPS SON OPCIONALES ═══════════════════════════════════════════ # Medido sobre su `configure.ac`: sus únicas deps externas son `AC_CHECK_LIB` de `cap`, `systemd`, # `selinux` y `usb` — **las cuatro opcionales**, y ninguna hace falta para lo que importa (hablar # ATA/SCSI/NVMe por ioctl). El tarball del release trae `configure` generado, así que tampoco # necesita autotools. # # ══ LAS PERILLAS ═══════════════════════════════════════════════════════════════════════════════ # --without-libsystemd no hay systemd en esta distro; es para que `smartd` notifique por él # --without-libcap-ng `libcap-ng` no está en el corpus. Lo que se pierde es que `smartd` # suelte capacidades al arrancar — relevante sólo para el daemon # --without-selinux no hay SELinux acá # --without-libusb los puentes USB-SATA. Sin esto no se lee el SMART de un disco externo # por USB; los internos (ATA/SCSI/NVMe) van por ioctl y no lo necesitan. # **Se dice porque es la limitación que alguien va a notar** # --with-nvme-devicescan que `smartd`/`smartctl --scan` encuentren los NVMe, que es lo que tiene # esta clase de máquina. Sin esto hay que nombrar el dispositivo a mano # --without-update-smart-drivedb el script que BAJA la base de datos de modelos desde internet. # No en una distro que se construye entera desde fuente y sin red # # ⚠ `--with-initscriptdir=no` y `--without-systemdsystemunitdir`: el init de esta distro es `arje`, # no systemd ni sysvinit, así que instalar un script de arranque ajeno sería basura en la imagen. # `smartd` se declara en `arje` cuando alguien decida vigilar discos de forma continua; hoy lo que # cierra el hueco es `smartctl`, que se invoca a mano. name = "smartmontools" version = "7.5" license = "GPL-2.0-or-later" [source] tarball = "https://sourceforge.net/projects/smartmontools/files/smartmontools/7.5/smartmontools-7.5.tar.gz/download" sha256 = "690b83ca331378da9ea0d9d61008c4b22dde391387b9bbad7f29387f2595f76e" [build] # Sus deps son todas opcionales y ninguna se enciende ⇒ no hay dep shared-only que fuerce dinámico. # (La regla: `link` tiene que coincidir con lo que publican las deps de la receta — ver la nota de # `recipes/gdb.toml`, donde `gmp`/`mpfr` son sólo `.so` y el estático falló.) compiler = "zig-cc" target = "x86_64-linux-musl" link = "static" flags = [] [build.phases] configure = ''' set -e [ -f ./configure ] || { echo "smartmontools: el tarball no trae ./configure" >&2; exit 1; } ./configure --build=$CBUILD --host=$CHOST --prefix=/usr --sysconfdir=/etc \ --without-libsystemd --without-libcap-ng --without-selinux --without-libusb \ --with-nvme-devicescan \ --without-update-smart-drivedb \ --with-initscriptdir=no --without-systemdsystemunitdir ''' compile = 'make -j"$(nproc)"' # ⚠ EL GUARDIÁN LO EJECUTA Y LE PIDE LA BASE DE DATOS DE MODELOS. # # `smartctl` sin `drivedb.h` compilada adentro **arranca igual** y pierde lo que lo hace útil: los # nombres y los umbrales específicos de cada modelo de disco. Daría atributos crudos numerados sin # saber qué significan — sellado, con contenido, y sin la función que promete. # # No se intenta consultar un disco de verdad: el sandbox va con `--unshare-all` y sin `/dev` # propio, así que pedirlo haría fallar un build correcto (el error que ya pagué cinco veces hoy). # Lo que sí se puede comprobar es que el binario arranque y que la base de datos esté dentro. install = ''' set -e make install DESTDIR=/out for b in smartctl smartd; do [ -x "/out/usr/sbin/$b" ] || [ -x "/out/usr/bin/$b" ] || { echo "smartmontools: falta $b" >&2; find /out -maxdepth 4 -type f -perm -u+x >&2; exit 1; } done SC=$(find /out -name smartctl -type f -perm -u+x | head -1) # Ejecución y truncado SEPARADOS: el estado de una tubería es el del último comando. sal=$("$SC" --version 2>&1) || { echo "smartmontools: smartctl no arranca" >&2; printf '%s\n' "$sal" >&2; exit 1; } printf '%s\n' "$sal" | head -1 | grep -qE 'smartctl 7\.5' || { echo "smartmontools: --version inesperado: $(printf '%s\n' "$sal" | head -1)" >&2; exit 1; } # La base de datos de modelos: es lo que traduce «atributo 5» a «sectores reasignados». Sin ella # `smartctl` arranca y devuelve números crudos sin nombre — sellado y sin la función que promete. # # ⚠ **EL ANCLA SALE DE LEER SU FUENTE, no de suponer el formato.** Mi primera versión contaba # «líneas que empiezan por letra» de `-P showall`, que es frágil y podía rechazar un build correcto. # `knowndrives.cpp:showallpresets()` imprime una línea literal al final: # # pout("Total number of entries :%5u\n" …, knowndrives.size(), …) # # ⇒ se lee ESE número, que es exactamente el tamaño de la base compilada. Y de paso: esa función # devuelve `errcnt`, o sea que sale ≠ 0 **sólo** si la base tiene errores de sintaxis — otra cosa # que vale saber antes de tratar su estado como «no arrancó». db=$("$SC" -P showall 2>&1) || true n=$(printf '%s\n' "$db" | sed -n 's/^Total number of entries *: *\([0-9]\+\).*/\1/p' | head -1) [ -n "$n" ] || { echo "smartmontools: -P showall no imprimió la línea 'Total number of entries' — el formato cambió o la base no se compiló" >&2 printf '%s\n' "$db" | tail -5 >&2 exit 1 } [ "$n" -gt 50 ] || { echo "smartmontools: la base de modelos trae $n entrada(s) — esperaba más de 50; smartctl daría atributos crudos numerados sin saber qué significan" >&2 exit 1 } echo "smartmontools: $(printf '%s\n' "$sal" | head -1) · smartctl + smartd · $n entrada(s) de drivedb" ''' [deps] build = ["make", "pkgconf"]