tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1182Shell 87Rust 63Markdown 541592 Definiciones

el paquete se arma con un script, y comprueba que el censo de afuera sea el de adentro

El paquete que se copia a la máquina donde se instala se armó a mano dos veces, y a la
segunda ya mentía: por fuera llevaba el takana-install-partition.sh corregido de hoy y por
dentro —dentro del initramfs, que es el que de verdad corre— el de la víspera. Un paquete
armado a mano deriva de sus piezas en silencio, y la parte que deriva es justamente la que
nadie mira porque está comprimida.

El guardián es el punto del script: el censo que el usuario corre ANTES de saltar (`takana
metal survey`) y el que corre el instalador DESPUÉS del salto tienen que ser el mismo
fichero, comparado por sha256. Si divergen, el usuario elige mirando una clasificación y el
instalador formatea según otra — y el que decide es el de adentro, que es el que nadie vio.

Tres piedras del hub quedan dichas en el script en vez de redescubiertas cada vez:
install-image-efi.sh busca rootfs y kernel en `store/` (el enlace del clon, vacío en este
hub) y no en `/store`; el staging enlaza desde el rootfs y linkat() no cruza montajes, así
que el rootfs se copia una vez a este lado; y lo que sale del store viene en 0444, así que
un `cp` encima falla con «Permission denied» y se lee como un problema de permisos del
usuario cuando es el fichero de la corrida anterior.

También `-d` en bsdcpio al extraer: sin él contesta «Can't create …» porque el directorio no
existe, y con 2>/dev/null eso se ve igual que un archivo que no trae el fichero.

Y instalador-initramfs.sh deja de recomendar el motor a la vista: ahora apunta a los tres
verbos (ADR 0021) y deja el `kernel kexec` abajo, para quien lo necesite.

Arnés del salto en verde con el payload rearmado: once comprobaciones.

65253a0e73489020b0fbecba5325e268be3fbd15 · por Sergio · (hace 29 d) · padre 3e699448b · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

2 archivos · +105 −6

diff --git a/scripts/instalador-initramfs.sh b/scripts/instalador-initramfs.sh
index 63e84041..b972cf75 100755
--- a/scripts/instalador-initramfs.sh
+++ b/scripts/instalador-initramfs.sh
@@ -211,11 +211,15 @@ echo "  · takana.root=PARTUUID=…          ⇒ destino por identidad estable"
 echo "  · takana.free takana.disk=/dev/…  ⇒ instalar al lado, en espacio sin asignar"
 echo "  · takana.yes                      ⇒ sin preguntar (sólo junto a lo de arriba)"
 echo
-echo "Para SALTAR a él sin pasar por el firmware (el userspace de esta máquina muere ACÁ):"
-echo "  sudo takana kernel kexec --probe          # ¿se puede? exit 0 = sí"
-echo "  sudo takana kernel kexec <linux-metal> --initrd $OUT \\"
-echo "       --cmdline 'console=ttyS0,115200 console=tty0' --jump   # tty0 ÚLTIMO = la pantalla"
-echo
-echo "Para probarlo SIN saltar (y sin riesgo), en QEMU:"
+echo "Para SALTAR a él sin pasar por el firmware (el userspace de esta máquina muere ACÁ), lo normal
+es NO tocar esto y usar el verbo, que comprueba, avisa y arma la cmdline solo (ADR 0021):
+  sudo takana metal check      # ¿se puede?
+  sudo takana metal survey     # el terreno
+  sudo takana metal install    # el viaje entero
+El motor a la vista, por si hace falta:
+  sudo takana kernel kexec <linux-metal> --initrd work/instalador-salida/takana-instalador.cpio.gz \
+       --cmdline 'console=ttyS0,115200 console=tty0' --jump   # tty0 ÚLTIMO = la pantalla
+
+Para probarlo SIN saltar (y sin riesgo), en QEMU:"
 echo "  qemu-system-x86_64 -m 4096 -kernel $KERNEL -initrd $OUT \\"
 echo "       -append 'console=ttyS0' -drive file=<disco.img>,format=raw -nographic"
diff --git a/scripts/instalador-paquete.sh b/scripts/instalador-paquete.sh
new file mode 100755
index 00000000..5137c984
--- /dev/null
+++ b/scripts/instalador-paquete.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+# instalador-paquete.sh — arma el PAQUETE que se copia a la máquina donde se va a instalar.
+#
+# ══ POR QUÉ EXISTE ════════════════════════════════════════════════════════════════════════════
+# El paquete se armó a mano dos veces y a la segunda ya mentía: por fuera llevaba el
+# `takana-install-partition.sh` corregido y por dentro —dentro del initramfs, que es el que de
+# verdad corre— el de la víspera. **Un paquete que se arma a mano deriva de sus piezas en silencio**,
+# y la parte que deriva es justamente la que nadie mira porque está comprimida.
+#
+# Acá se arma entero y se COMPRUEBA que lo de adentro y lo de afuera sean el mismo fichero.
+#
+# ── LAS DOS PIEDRAS DEL HUB, QUE NO SON DE ESTE SCRIPT ─────────────────────────────────────────
+#   · `install-image-efi.sh` busca el rootfs y el kernel en `store/` —el enlace del clon, que en
+#     este hub está VACÍO— y no en `/store`, que es donde están. Por eso acá se resuelven y se
+#     pasan explícitos.
+#   · el staging ENLAZA desde el rootfs y `linkat()` no cruza un punto de montaje: con el rootfs en
+#     `/store` y el stage en `/work` sale EXDEV. Se copia el rootfs una vez a este lado.
+#
+# Uso:  scripts/instalador-paquete.sh [--salida <dir>]
+# Vars: ROOTFS KERNEL (si se saben) · SALIDA (def work/instalador-salida)
+set -eu
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
+SALIDA="${SALIDA:-work/instalador-salida}"
+[ "${1:-}" = "--salida" ] && { SALIDA="${2:?}"; shift 2; }
+
+TAKANA="${TAKANA:-$ROOT/target/release/takana}"
+[ -x "$TAKANA" ] || { echo "no hay binario en $TAKANA (cargo build --release -p takana-cli)" >&2; exit 1; }
+
+# ── el rootfs y el kernel, resueltos a este lado del montaje ──────────────────────────────────
+if [ -z "${ROOTFS:-}" ]; then
+    _src=$(ls -dt /store/*-product-rootfs store/*-product-rootfs 2>/dev/null | head -1)
+    [ -n "${_src:-}" ] || { echo "no encuentro ningún product-rootfs (set ROOTFS=)" >&2; exit 1; }
+    ROOTFS="work/.rootfs-local/$(basename "$_src")"
+    if [ ! -d "$ROOTFS" ]; then
+        echo "==> copiando $_src → $ROOTFS (una vez, por EXDEV)"
+        mkdir -p work/.rootfs-local; cp -a "$_src" "$ROOTFS"
+    fi
+fi
+if [ -z "${KERNEL:-}" ]; then
+    KERNEL=$(ls -dt /store/*-linux-metal/boot/bzImage store/*-linux-metal/boot/bzImage 2>/dev/null | head -1)
+    [ -n "${KERNEL:-}" ] || { echo "no encuentro un bzImage de linux-metal (set KERNEL=)" >&2; exit 1; }
+fi
+echo "==> rootfs: $ROOTFS"
+echo "==> kernel: $KERNEL"
+
+mkdir -p "$SALIDA/kernel/boot" "$SALIDA/lib"
+
+# ── 1) el instalador en RAM (es lo caro: arma el stage y comprime ~130 M) ──────────────────────
+echo "==> initramfs del instalador"
+ROOTFS="$ROOTFS" KERNEL="$KERNEL" OUT="$SALIDA/takana-instalador.cpio.gz" ./scripts/instalador-initramfs.sh
+
+# ── 2) lo que va al lado ──────────────────────────────────────────────────────────────────────
+# `rm -f` antes de cada `cp`: lo que sale del store viene en modo 0444 y un `cp` encima falla con
+# «Permission denied», que en un script de empaquetado se lee como un problema de permisos del
+# usuario y no como lo que es — el fichero de la corrida anterior, que es de sólo lectura.
+poner() { rm -f "$2"; cp "$1" "$2"; chmod "${3:-0644}" "$2"; }
+poner "$TAKANA" "$SALIDA/takana" 0755
+poner "$KERNEL" "$SALIDA/kernel/boot/bzImage"
+poner scripts/takana-install-partition.sh "$SALIDA/takana-install-partition.sh" 0755
+poner scripts/lib/herramientas-desde-store.sh "$SALIDA/lib/herramientas-desde-store.sh"
+
+# ── 3) la comprobación que justifica este script ──────────────────────────────────────────────
+# El censo que el usuario corre ANTES de saltar (`takana metal survey`, el de afuera) y el que
+# corre el instalador DESPUÉS del salto (el de adentro del initramfs) tienen que ser el mismo
+# fichero. Si divergen, el usuario elige mirando una clasificación y el instalador formatea según
+# otra — y el que decide es el de adentro, que es el que nadie miró.
+echo "==> coherencia: el censo de afuera y el de adentro"
+. "$(dirname "$0")/lib/herramientas-desde-store.sh"
+CPIO=$(herramienta libarchive usr/bin/bsdcpio cpio) || exit 1
+GZIP=$(herramienta gzip bin/gzip gzip)              || exit 1
+_tmp="work/.paquete-verif"; rm -rf "$_tmp"; mkdir -p "$_tmp"
+( cd "$_tmp" && "$GZIP" -d -c "$ROOT/$SALIDA/takana-instalador.cpio.gz" 2>/dev/null \
+    | "$CPIO" -i -d --quiet '*takana-install-partition.sh' 2>/dev/null ) || true
+# `-d` (crear directorios) no es opcional: sin él bsdcpio contesta «Can't create
+# 'instalador/takana-install-partition.sh'» porque el directorio no existe, y con `2>/dev/null`
+# eso se ve exactamente igual que un archivo que no trae el fichero.
+_dentro="$_tmp/instalador/takana-install-partition.sh"
+if [ ! -r "$_dentro" ]; then
+    echo "   ✗ no pude sacar el censo de adentro del initramfs — no puedo afirmar que coincidan" >&2
+    rm -rf "$_tmp"; exit 1
+fi
+_a=$(sha256sum "$_dentro" | cut -d' ' -f1)
+_b=$(sha256sum scripts/takana-install-partition.sh | cut -d' ' -f1)
+rm -rf "$_tmp"
+[ "$_a" = "$_b" ] || {
+    echo "   ✗ el censo de adentro del initramfs NO es el del repo ($(echo "$_a"|cut -c1-12) vs $(echo "$_b"|cut -c1-12))" >&2
+    echo "     El instalador decidiría con una clasificación distinta de la que el usuario vio." >&2
+    exit 1; }
+echo "   ✓ el mismo fichero adentro y afuera ($(echo "$_a" | cut -c1-12))"
+
+echo
+echo "✓ paquete en $SALIDA  ($(du -sm "$SALIDA" | cut -f1) MiB)"
+ls -l "$SALIDA"
+echo
+echo "En la máquina donde se instala:  sudo ./takana metal check → survey → install"