busybox recortado: 401 -> 277 applets, con vigía y cinco indultos medidos
Paso 1 de docs/plan-botar-busybox.md. 124 applets fuera del defconfig: los 105 que no se reemplazan (dpkg, rpm, httpd, telnetd, ubi*, nand*, i2c*) y 19 cuya función ya hace otro componente (init/runit -> arje-zero, syslogd/klogd/logread -> hammerd). Binario de 1.230.976 a 977.096 bytes. CORRIGE UN ERROR DEL PLAN: arje-zero y hammerd reemplazan la FUNCIÓN, no el COMANDO -- son un binario cada uno. Por eso 5 indultos: setuidgid (la card de gitea lo ejecuta), switch_root (el /init del instalador, antes de que arje exista) y poweroff/halt/reboot (nada más en el corpus apaga la máquina). scripts/busybox-vigia.py falla si alguien invoca un applet retirado; lee la lista de la propia receta para que no haya dos que se desincronicen. Su primera versión daba 91 hits y ninguno real: las cuatro reglas que lo bajaron a 0 están documentadas. El mapa applet->símbolo sale de las líneas //applet: del fuente, no de poner el nombre en mayúsculas: eso falla en 6 casos medidos, dos de ellos en la lista. Verificado: 277 applets exactos, los 5 indultados presentes, y zlib-ng, jq y logrotate reconstruidas y selladas con el busybox recortado -- el sandbox sigue en pie. Son 3 de las 24 dependientes, no las 24, y el boot de la imagen no se probó. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,8 +69,11 @@ migración de llamadores, no un borrado.** Mirar quién los invoca en `scripts/`
|
||||
| `diffutils` | 2 | `diff cmp` |
|
||||
| `findutils` / `findutils-xargs` / `libarchive` | 3 | `find` · `xargs` · `cpio` |
|
||||
|
||||
**Los 24 de `arje-zero` y `hammerd` no cuestan nada**: el reemplazo ya corre en el producto. Son
|
||||
applets instalados que nadie ejecuta. Salen del `defconfig` y se prueba que la imagen arranque igual.
|
||||
⚠ **CORRECCIÓN (2026-09-21, al ejecutar el paso 1): los 24 de `arje-zero` y `hammerd` NO son
|
||||
gratis, y esta tabla decía mal.** Esas dos recetas reemplazan la **función**, no el **comando**:
|
||||
cada una instala UN binario (`-p arje-zero`, `-p hammerd`), así que no existe un `poweroff`, un
|
||||
`logger` ni un `setuidgid` que las respalde. «Cubierto» significaba «nadie necesita correr esto»,
|
||||
y para 5 de los 24 era falso. Ver los indultos del paso 1.
|
||||
|
||||
### 128 · Sin dueño
|
||||
|
||||
@@ -135,9 +138,7 @@ trabajo #1 es medirlo, no adoptarlo.**
|
||||
Cada paso es una unidad de trabajo con su criterio de terminado. Los tres primeros **no tocan el
|
||||
frente C** y se pueden hacer hoy.
|
||||
|
||||
1. **Recortar el `defconfig`.** Sacar los 105 de `BORRAR` + los 24 que `arje-zero`/`hammerd` ya
|
||||
reemplazan = **129 applets menos, cero código escrito**. Terminado cuando la imagen arranca, el
|
||||
E2E de QEMU pasa y `find . -type l | wc -l` baja de 401 a ~272.
|
||||
1. ~~**Recortar el `defconfig`.**~~ **HECHO, 2026-09-21 — 401 → 277 applets. Veredicto al final.**
|
||||
2. **Declarar la munición que ya existe.** `uutils`, `findutils`, `findutils-xargs`, `diffutils`,
|
||||
`brush`, `gzip`, `libarchive` a los perfiles de `targets.toml`. Terminado cuando `build-state.py`
|
||||
los marca con perfil y la imagen los lleva.
|
||||
@@ -330,3 +331,89 @@ y valen 129 applets y dos piezas de userland. Gastar el turno en pelear el shell
|
||||
Lo que sí conviene hacer ya, porque es gratis: **suscribirse a #1394** y **medir brush como `/bin/sh`
|
||||
del PRODUCTO** (`product-boot-test.sh` + las cards), que es un consumidor que no genera libtool y
|
||||
donde brush no tiene ninguna evidencia en contra.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Paso 1 — el recorte, HECHO y MEDIDO
|
||||
|
||||
**Fecha:** 2026-09-21 · **Dónde:** `dev.gioser.net`, bajo `flock -o`, contra un store tirable y con
|
||||
un directorio de recetas por hardlinks — el `recipes/` del worker no se tocó.
|
||||
|
||||
> **401 → 277 applets.** 124 retirados, 5 indultados, binario de **1.230.976 → 977.096 bytes**
|
||||
> (−20,6 %). Nuevo hash `b3:a24fdbf6…` (el vigente era `2a2b1280…`). Y **3 de las 24 recetas que
|
||||
> declaran busybox build-dep se reconstruyeron y sellaron con el recortado**: el sandbox sigue en pie.
|
||||
|
||||
## Lo que el ejercicio corrigió del plan
|
||||
|
||||
**Mi tabla decía que los 24 applets de `arje-zero`/`hammerd` eran gratis. Es falso para 5 de ellos.**
|
||||
Esas recetas instalan **un binario cada una** (`-p arje-zero`, `-p hammerd`): reemplazan la FUNCIÓN,
|
||||
no el COMANDO. No hay un `poweroff` ni un `setuidgid` detrás. Los cinco indultos, con su razón:
|
||||
|
||||
| indultado | por qué se queda |
|
||||
|---|---|
|
||||
| `setuidgid` | la card de **gitea** hace `setuidgid gitea` (`recipes/gitea.toml:89`, «applet de busybox, comprobado presente»). Sin él el servicio arranca, muere y reintenta para siempre |
|
||||
| `switch_root` | el `/init` del initramfs del instalador lo ejecuta (`scripts/takana-live-install.sh:375`), **antes** de que arje exista |
|
||||
| `poweroff` · `halt` · `reboot` | **nada más en el corpus apaga la máquina.** arje-zero es PID 1, no una CLI. Quitarlos deja un producto que no se puede apagar desde la shell |
|
||||
|
||||
Los tres primeros los encontró el vigía; los tres últimos, preguntarse qué instala arje-zero de
|
||||
verdad en vez de creerle a mi propia tabla.
|
||||
|
||||
## El vigía — y por qué un vigía ingenuo no sirve
|
||||
|
||||
`scripts/busybox-vigia.py` falla si alguna receta, script o card invoca un applet retirado. **Lee la
|
||||
lista de la propia receta** (`RETIRADOS='…'`) cruzada con la columna `simbolo_kconfig` del TSV, así
|
||||
que no hay dos listas que se desincronicen.
|
||||
|
||||
Su primera versión daba **91 hits y ninguno real**. Las cuatro reglas que lo bajaron a 0, todas
|
||||
medidas contra falsos positivos concretos:
|
||||
|
||||
| regla | qué mataba |
|
||||
|---|---|
|
||||
| quitar comentarios antes de buscar | `# busybox provee sendmail, no mail` (logrotate), `/// los dos fsync no son prolijidad` |
|
||||
| en Rust/Python, mirar sólo cadenas **que parezcan una línea de comandos** | `"init"` como nombre de capacidad, `tree` como variable, `rx = re.compile(…)` |
|
||||
| ignorar nombres que el propio script define como función | `$(ts)` en los seis scripts de `scripts/farm/` |
|
||||
| ignorar patrones de `case` y `command -v X` | `proc\|sys\|dev\|init) continue ;;` · `command -v dpkg` en el censo de la mudanza |
|
||||
|
||||
Y `[` / `[[` no se vigilan: son palabras del shell, y todo script bash del hub los usa sin que eso
|
||||
sea una llamada a un applet.
|
||||
|
||||
⚠ **El vigía mira ESTE repo.** No ve los `configure` de terceros que corren dentro del sandbox, que
|
||||
son quienes podrían llamar a `which` o `unzip`. Por eso la verificación de abajo no es opcional.
|
||||
|
||||
## El mapa applet → símbolo NO se deriva por mayúsculas
|
||||
|
||||
Sale de las líneas `//applet:` del fuente de busybox 1.36.1 y vive en la columna `simbolo_kconfig`
|
||||
del TSV. Poner el nombre en mayúsculas **falla en 6 casos medidos**: `[`→`TEST1`, `[[`→`TEST2`,
|
||||
`arch`→`BB_ARCH`, `nbd-client`→`NBDCLIENT`, `sh`→`SH_IS_ASH`, `sysctl`→`BB_SYSCTL`. Dos de esos seis
|
||||
estaban en la lista a retirar.
|
||||
|
||||
## Verificación
|
||||
|
||||
| qué | resultado |
|
||||
|---|---|
|
||||
| applets tras el recorte | **277** (401 − 124), exactamente los previstos |
|
||||
| los 5 indultados presentes | ✅ y también `sh` y `getty` |
|
||||
| los que debían irse | ✅ `httpd telnetd dpkg rpm init syslogd runsv tree which unzip` fuera |
|
||||
| **el sandbox sigue construyendo** | ✅ `zlib-ng`, `jq` y `logrotate` reconstruidas y selladas con el busybox recortado |
|
||||
|
||||
⚠ **Son 3 de las 24, no las 24.** Las otras 21 —entre ellas `linux`, `llama-cpp`, `protobuf`,
|
||||
`qdrant`— no se probaron: son horas de cómputo en una caja que está con la campaña de KDE. Si alguna
|
||||
usa un applet retirado, se verá en su próximo build y el vigía **no** lo habría anticipado, porque el
|
||||
llamador estaría en un `configure` de terceros.
|
||||
|
||||
## El coste, dicho antes de que sorprenda
|
||||
|
||||
**Cambiar esta lista re-hashea busybox, y con él las 24 recetas que lo declaran build-dep**:
|
||||
`abseil-cpp chrony cronie crun dwarves firmware-tigerlake ia-modelo-embeddings intel-ucode jq libmnl
|
||||
libnftnl linux linux-firmware llama-cpp logrotate nftables opensmtpd popt protobuf qdrant
|
||||
sof-firmware valkey wireless-regdb zlib-ng`. **`linux` está en la lista**: el kernel se reconstruye.
|
||||
La granja lo hará en su propio ciclo; no se disparó a mano.
|
||||
|
||||
## Lo que queda del paso 1
|
||||
|
||||
- **Arrancar una imagen.** Lo medido es que el artefacto sella y que el sandbox construye. Que el
|
||||
producto **bootee** con 277 applets no se probó: falta `product-boot-test.sh`.
|
||||
- **Las otras 21 dependientes**, cuando la granja llegue.
|
||||
- El siguiente corte natural son los `BORRAR` que no se tocaron por prudencia y los 272 que siguen:
|
||||
el número baja a 0 por el paso 2 (declarar la munición sellada) y el 5 (`grep`/`sed` POSIX).
|
||||
|
||||
Reference in New Issue
Block a user