brush: la causa era el desescapado de barras dentro de comillas invertidas — reportada, y adelantar el pin no sirve
Bajando al config.status que genera el libtool apareció el mecanismo, y es de una línea: brush aplica a `...` las reglas de $( ). POSIX manda que dentro de comillas invertidas la barra se ELIMINE cuando precede a $, ` o \ (2.6.3). Que el caso con $( ) sí esté bien es lo que delata la causa. Por eso rompe libtool: el case que decide si cada variable necesita escapado evalúa a cadena vacía bajo brush, así que todas caen en la rama sin escapar. El configure termina bien; el fichero sale mal escrito. Se construyó main de hoy (737dd57e, cuatro meses y medio sobre nuestro pin) y reproduce idéntico los cuatro casos ⇒ adelantar el pin no arregla nada. Reportado: https://github.com/reubeno/brush/issues/1394 Y la recomendación: no pelear el shell. Los pasos 1, 2 y 5 del plan no dependen de él y valen 129 applets y dos piezas de userland. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -249,11 +249,43 @@ Ese fichero ya no lo parsea **nadie** — ni brush ni busybox lo aceptan (`rc=2`
|
||||
368). Y el contraprueba cierra el caso: **el `libtool` del control lo parsea brush sin quejarse
|
||||
(`rc=0`)**. ⇒ El parser de brush está bien; lo que difiere es lo que su shell PRODUCE.
|
||||
|
||||
⚠ **El mecanismo exacto no está determinado, y conviene decirlo así en vez de inventarlo.** Las tres
|
||||
sospechas obvias se probaron aisladas y **las tres dan idéntico** en ambos shells: `echo` con barras
|
||||
invertidas, sustitución de comando preservando `\\`, y el propio `func_quote_for_eval` de libtool
|
||||
(`sed_quote_subst`) aplicado a mano. Lo medido es el diff de 25 líneas y que el `configure` termina
|
||||
bien; el resto es hipótesis.
|
||||
### El mecanismo, encontrado (2026-09-21, después de escribir lo de arriba)
|
||||
|
||||
Primero se escribió acá que la causa no estaba determinada, tras descartar las tres sospechas
|
||||
obvias —`echo` con barras invertidas, sustitución de comando preservando `\\`, y el
|
||||
`func_quote_for_eval` de libtool aplicado a mano—, que dan **idéntico** en ambos shells. La causa
|
||||
apareció bajando al `config.status` que genera el `libtool`. **Es de una línea:**
|
||||
|
||||
```sh
|
||||
V=hola
|
||||
echo "a: [`echo \\$V`]" # POSIX: $V · brush: \hola
|
||||
echo "b: [`echo \\\\`]" # POSIX: \ · brush: \\
|
||||
echo "c: [`echo \$V`]" # POSIX: hola · brush: $V
|
||||
echo "d: [$(echo \\$V)]" # POSIX: \hola · brush: \hola ✅
|
||||
```
|
||||
|
||||
**brush aplica a las comillas invertidas las reglas de `$( )`.** POSIX manda otra cosa: dentro de
|
||||
`` `…` `` la barra invertida conserva su significado literal **salvo** cuando precede a `$`,
|
||||
`` ` `` o `\`, donde se ELIMINA antes de parsear el texto del comando (POSIX.1-2024, 2.6.3). Que el
|
||||
caso **d** sí esté bien es lo que delata la causa.
|
||||
|
||||
Por qué rompe libtool: el `config.status` generado trae este bucle, que decide si cada variable
|
||||
necesita escapado antes de escribirla en el `libtool`:
|
||||
|
||||
```sh
|
||||
for var in SHELL ECHO PATH_SEPARATOR SED GREP …; do
|
||||
case `eval \\$ECHO \\""\\$$var"\\"` in
|
||||
*[\\\`\"\$]*) eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED \"\$sed_quote_subst\"\`\\\"" ;;
|
||||
*) eval "lt_$var=\\\"\$$var\\\"" ;;
|
||||
esac
|
||||
done
|
||||
```
|
||||
|
||||
Bajo brush ese `case` evalúa a **cadena vacía**, así que **todas** las variables caen en la rama sin
|
||||
escapar. De ahí las 25 líneas y de ahí que el `configure` termine bien: no falla nada, sólo sale mal
|
||||
escrito.
|
||||
|
||||
**Reportado upstream: [reubeno/brush#1394](https://github.com/reubeno/brush/issues/1394).**
|
||||
|
||||
## Y el otro dato, que no es un fallo pero decide
|
||||
|
||||
@@ -267,9 +299,34 @@ vuelve medible más lento. Es un argumento independiente del bug, y no se arregl
|
||||
2. **El frente del producto sigue abierto**: las cards, la getty y la shell interactiva no generan
|
||||
libtool. Ahí brush no tiene ninguna evidencia en contra — pero tampoco se probó, y el
|
||||
`product-boot-test.sh` es la prueba que falta.
|
||||
3. **Hay un bug upstream que reportar** (reubeno/brush): `configure` de autotools genera un `libtool`
|
||||
con un nivel de escapado de menos. El reproductor es una receta autotools cualquiera, y el
|
||||
artefacto es el diff de 25 líneas de arriba.
|
||||
3. **Reportado upstream: [reubeno/brush#1394](https://github.com/reubeno/brush/issues/1394)**, con
|
||||
el reproductor de una línea, la tabla de los cuatro casos y el fragmento de `config.status`.
|
||||
4. **El paso 5 del plan (grep/sed POSIX en Rust) sube de prioridad**, porque no depende del shell.
|
||||
5. **No se tocó el lab compartido**: copia con hardlinks y stores tirables. El worker siguió
|
||||
compilando su cola en paralelo, serializado por el `flock`.
|
||||
|
||||
## ¿Parchar, o buscar otra opción?
|
||||
|
||||
**Primero lo que cierra la pregunta barata: adelantar el pin NO sirve.** Nuestra receta apunta a
|
||||
`96a26d0c` (tag `brush-shell-v0.4.0`, mayo 2026), que sigue siendo el último release. Se construyó
|
||||
**`main` de hoy** (`737dd57e`, 2026-09-21 — cuatro meses y medio de trabajo encima) y **reproduce
|
||||
idéntico**, los cuatro casos. No hay nada que esperar de la rama.
|
||||
|
||||
Lo que queda, en orden de coste:
|
||||
|
||||
| opción | qué cuesta | qué deja |
|
||||
|---|---|---|
|
||||
| **Esperar a #1394** | cero | el upstream es activísimo (issue #1393 de anteayer) y el bug es acotado, pero no es nuestro calendario |
|
||||
| **Parchar brush en la receta** | un `.patch` en el árbol, como ya hacen 13 recetas | ⚠ es un parche **al parser de un shell**, que es el componente más cargado de todos. Y el bug apareció en el PRIMER build real: no es prueba de que sea el único |
|
||||
| **dash** | receta nueva, C, ~200 KB. Es el `sh` de referencia POSIX | resuelve el sandbox YA — y no avanza nada la soberanía en Rust |
|
||||
| **bash como `/bin/sh` del producto** | cero: ya está sellada Y en los 7 perfiles | tapa el frente B sin escribir nada. No sirve para el sandbox sin medirlo antes |
|
||||
| **Dejar busybox donde está** | cero | es lo que dice el plan: el shell NO es por donde se empieza |
|
||||
|
||||
**La recomendación es la última, y no por conservadurismo.** El plan ya ordenaba los pasos 1, 2 y 5
|
||||
—recortar el defconfig, declarar lo sellado, escribir `grep`/`sed` POSIX— **sin depender del shell**,
|
||||
y valen 129 applets y dos piezas de userland. Gastar el turno en pelear el shell es empezar por el
|
||||
único frente que está bloqueado por terceros.
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user