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 1411Shell 141Markdown 85Rust 842918 Definiciones

E5 medio live: ISO El Torito booteable con xorriso de hammer (primer corte)

scripts/iso-image.sh arma un ISO 9660/El Torito isohybrid usando el xorriso
construido por hammer (recipes/xorriso.toml, dogfooding): GRUB core El Torito
(grub-mkimage -O i386-pc-eltorito + iso9660) carga kernel + initramfs del ISO;
el rootfs del producto va como cpio.gz (live de RAM). scripts/iso-boot-test.sh
valida E2E in-VM: SeaBIOS->GRUB 2.14->Linux 6.16.12->/init (marcador
HAMMER-ISO-LIVE-OK)->arje-zero PID1->hammerd->netup(DHCP)->sshd escuchando.
El producto entero corre desde el medio live, sin tocar disco. ISO 113M.
SDD 13 E5 marcado primer corte.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

2976f3e5fd75db194f0445d017cef6fd707bfcba · por sergio · (hace 4 meses) · padre a1b8b5767 · ver el árbol en este commit

Delta semántico

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

3 archivos · +198 −2

diff --git a/docs/13-release-engineering.md b/docs/13-release-engineering.md
index d2c2aae8..bbf50c02 100644
--- a/docs/13-release-engineering.md
+++ b/docs/13-release-engineering.md
@@ -85,5 +85,21 @@ kernel en `/boot`, los módulos GRUB en `/boot/grub/i386-pc` y los pasos `grub-m
   recorta la cadena a sus N más nuevas (limita la profundidad de rollback, como `delete-generations` en
   NixOS). **Endurecimiento pendiente:** journal de *intención* + replay para sobrevivir un kernel-panic a
   media escritura; cableado del init de boot para que el rollback sea seleccionable al arranque.
-- **E5 — ISO/medio de arranque:** medio live para correr el instalador (xorriso/grub-mkrescue;
-  herramental a construir).
+- **E5 — ISO/medio de arranque: ✅ primer corte** (`recipes/xorriso.toml` + `scripts/iso-image.sh` +
+  `scripts/iso-boot-test.sh`). Medio **live** que arranca ENTERO desde RAM: GRUB (El Torito) carga
+  kernel + initramfs desde el ISO 9660, el kernel desempaqueta el rootfs del producto a un tmpfs y corre
+  `/init` — sin tocar disco. Es el medio para correr el instalador (`hammer install /dev/sdX`) en
+  hardware nuevo o probar el sistema sin instalarlo. **Herramental construido por hammer:** el host no
+  trae `xorriso` (y `grub-mkrescue` lo exige) ⇒ `recipes/xorriso.toml` lo construye desde fuente (GNU
+  xorriso 1.5.8 = libburn+libisofs+libisoburn, zig 0.13.0, estático musl, libs opcionales off ⇒ binario
+  autocontenido). `iso-image.sh` lo **dogfooda**: arma el ISO con el xorriso del store. **Cadena de
+  boot BIOS:** reusa los módulos GRUB i386-pc de E1 pero con el core El Torito (`grub-mkimage -O
+  i386-pc-eltorito` + módulos `iso9660`/`biosdisk`) en vez del core de disco (ext2); `xorriso -as
+  mkisofs -b …/eltorito.img -no-emul-boot -boot-info-table --grub2-boot-info --grub2-mbr boot_hybrid.img`
+  ⇒ ISO **isohybrid** (booteable como CD *y* USB/disco). El initramfs es el `product-rootfs` lean
+  empaquetado como `cpio.gz` (live de RAM; la variante con squashfs+overlay para rootfs grandes es
+  refinamiento). Validado E2E in-VM (`iso-boot-test.sh`, ISO 113M): SeaBIOS → GRUB 2.14 (El Torito) →
+  Linux 6.16.12 hammer-built → `/init` (marcador `HAMMER-ISO-LIVE-OK`) → arje-zero PID1 → hammerd +
+  netup (lease DHCP) → **sshd escuchando**: el producto entero corriendo desde el medio live. **Pendiente
+  (refinamiento):** correr el instalador `hammer install` interactivamente desde el live; squashfs+overlay
+  para no cargar todo el rootfs en RAM; build EFI (el kernel ya trae EFI_STUB, falta poblar la ESP).
diff --git a/scripts/iso-boot-test.sh b/scripts/iso-boot-test.sh
new file mode 100755
index 00000000..5af96efd
--- /dev/null
+++ b/scripts/iso-boot-test.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+# iso-boot-test.sh — valida E5 (medio live): arma el ISO 9660 / El Torito con scripts/iso-image.sh y lo
+# arranca en QEMU desde el CD (sin -kernel ni disco), comprobando que la cadena El Torito → GRUB →
+# kernel → initramfs → /init → producto funciona ENTERA desde RAM. El xorriso que arma el ISO es el
+# construido por hammer (recipes/xorriso.toml), así que el test dogfooda también esa receta.
+#
+# Asserts: (1) GRUB arrancó del El Torito; (2) el marcador del /init live; (3) arje-zero PID1 vivo;
+# (4) sshd escuchando — i.e. el PRODUCTO llega a servicio corriendo enteramente desde el medio live.
+#
+# Uso:  PRODUCT=<hash-o-prefijo> ./scripts/iso-boot-test.sh
+#       (default: el product-rootfs más reciente del store)
+# Vars: KERNEL MEM (def 4096) KVM (def 1) DEADLINE (def 120)
+set -euo pipefail
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
+KERNEL="${KERNEL:-$(ls store/*-linux/boot/bzImage 2>/dev/null | head -1)}"
+MEM="${MEM:-4096}"; KVM="${KVM:-1}"; DEADLINE="${DEADLINE:-120}"
+WORK="$ROOT/work/iso-boot"; ISO="$WORK/hammer-live.iso"; LOG="$WORK/console.log"
+mkdir -p "$WORK"
+
+# localizar el product-rootfs lean (lo idóneo para un medio live: sin toolchain)
+if [ -n "${PRODUCT:-}" ]; then
+  PDIR=$(ls -d store/"${PRODUCT#b3:}"*-product-rootfs 2>/dev/null | head -1)
+else
+  PDIR=$(ls -dt store/*-product-rootfs 2>/dev/null | head -1)
+fi
+[ -n "$PDIR" ] && [ -d "$PDIR" ] || { echo "no encuentro product-rootfs (corré 'hammer bootstrap product')"; exit 1; }
+[ -n "$KERNEL" ] && [ -e "$KERNEL" ] || { echo "no encuentro kernel"; exit 1; }
+echo "==> product-rootfs: $PDIR"
+
+echo "==> armando ISO con scripts/iso-image.sh (xorriso de hammer)"
+ROOTFS="$PDIR" ISO="$ISO" KERNEL="$KERNEL" ./scripts/iso-image.sh >/dev/null
+echo "==> ISO: $(du -h "$ISO" | cut -f1)"
+
+accel=()
+if [ "$KVM" = 1 ] && [ -w /dev/kvm ]; then accel=(-enable-kvm -cpu host); fi
+echo "==> arrancando desde el CD El Torito (deadline ${DEADLINE}s)"
+timeout "$DEADLINE" qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "${accel[@]}" \
+    -cdrom "$ISO" -boot d > "$LOG" 2>&1 || true
+
+fail=0
+check() { if grep -qiE "$1" "$LOG"; then echo "  ✓ $2"; else echo "  ✗ $2" >&2; fail=1; fi; }
+echo "==> asserts sobre el log serie:"
+check "GNU GRUB"                         "GRUB arrancó del El Torito"
+check "Linux version 6\.16"              "kernel hammer-built cargado del ISO"
+check "HAMMER-ISO-LIVE-OK"               "marcador /init del medio live"
+check "arje-zero"                        "arje-zero PID1 vivo"
+check "Server listening on .* port 22"   "sshd escuchando (producto en servicio desde RAM)"
+
+if [ "$fail" = 0 ]; then
+  echo; echo "✓✓ E5 ISO LIVE VERDE: medio El Torito bootea el producto entero desde RAM (GRUB→kernel→initramfs→arje→sshd)"
+else
+  echo; echo "✗ E5 ISO boot test FALLÓ — ver $LOG" >&2; exit 1
+fi
diff --git a/scripts/iso-image.sh b/scripts/iso-image.sh
new file mode 100755
index 00000000..bea4c77f
--- /dev/null
+++ b/scripts/iso-image.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+# iso-image.sh — Etapa E5 (SDD 13): produce un MEDIO LIVE booteable como ISO 9660 / El Torito.
+#
+# A diferencia de install-image.sh (E1, disco GPT con / persistente en vda2), un medio live arranca
+# ENTERO desde RAM: GRUB (El Torito) carga kernel + initramfs desde el ISO 9660, el kernel desempaqueta
+# el initramfs (el rootfs del producto) a un tmpfs y corre /init — sin tocar disco. Es el medio para
+# correr el instalador (`hammer install /dev/sdX`) en hardware nuevo, o para probar el sistema sin
+# instalarlo.
+#
+# El ISO lo ARMA `xorriso` construido por hammer desde fuente (recipes/xorriso.toml) — el host no lo
+# trae. La cadena de boot BIOS reusa los módulos GRUB i386-pc de E1, pero con el core El Torito
+# (formato i386-pc-eltorito + iso9660) en vez del core de disco (ext2 + biosdisk).
+#
+# Cadena: SeaBIOS → El Torito boot catalog → eltorito.img (cdboot+core GRUB) → lee (cd0)/boot/grub/
+# grub.cfg → `linux /boot/bzImage rdinit=/init` + `initrd /boot/initramfs.cpio.gz` → kernel desempaqueta
+# → /init (marcador + exec del init real del rootfs).
+#
+# Uso:
+#   ./scripts/iso-image.sh                       # crea work/hammer-live.iso
+#   BOOT=1 KVM=1 ./scripts/iso-image.sh          # además lo arranca desde el CD (auto-boot)
+#
+# Variables:
+#   ROOTFS   dir rootfs a empaquetar como initramfs   (default work/builder-rootfs)
+#   KERNEL   bzImage a embeber                          (default store/*-linux/boot/bzImage)
+#   ISO      ISO de salida                              (default work/hammer-live.iso)
+#   XORRISO  binario xorriso                            (default el del store; si no, host)
+#   GRUB_LIB módulos GRUB i386-pc                       (default /usr/lib/grub/i386-pc)
+#   CMDLINE  cmdline del kernel             (default "console=ttyS0 rdinit=/init")
+#   BOOT/KVM/MEM  passthrough al arranque de prueba
+set -eu
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+cd "$ROOT"
+
+ROOTFS="${ROOTFS:-work/builder-rootfs}"
+ISO="${ISO:-work/hammer-live.iso}"
+KERNEL="${KERNEL:-$(ls store/*-linux/boot/bzImage 2>/dev/null | head -1)}"
+GRUB_LIB="${GRUB_LIB:-/usr/lib/grub/i386-pc}"
+CMDLINE="${CMDLINE:-console=ttyS0 rdinit=/init}"
+# xorriso: preferimos el construido por hammer (dogfooding de recipes/xorriso.toml); fallback al host.
+XORRISO="${XORRISO:-$(ls store/*-xorriso/usr/bin/xorriso 2>/dev/null | head -1)}"
+[ -n "$XORRISO" ] && [ -x "$XORRISO" ] || XORRISO="$(command -v xorriso 2>/dev/null || true)"
+
+[ -d "$ROOTFS" ] || { echo "no existe ROOTFS: $ROOTFS" >&2; exit 1; }
+[ -e "$ROOTFS/sbin/init" ] || { echo "ROOTFS sin /sbin/init" >&2; exit 1; }
+[ -n "$KERNEL" ] && [ -r "$KERNEL" ] || { echo "no encuentro el kernel (set KERNEL=<bzImage>)" >&2; exit 1; }
+[ -n "$XORRISO" ] || { echo "no encuentro xorriso (build recipes/xorriso.toml)" >&2; exit 1; }
+[ -d "$GRUB_LIB" ] && [ -r "$GRUB_LIB/cdboot.img" ] || { echo "faltan módulos GRUB i386-pc en $GRUB_LIB" >&2; exit 1; }
+command -v grub-mkimage >/dev/null 2>&1 || { echo "falta grub-mkimage" >&2; exit 1; }
+command -v cpio >/dev/null 2>&1 || { echo "falta cpio" >&2; exit 1; }
+
+echo "==> xorriso: $XORRISO ($("$XORRISO" -version 2>&1 | grep -m1 'xorriso version' || echo '?'))"
+
+STAGE="work/.iso-stage"
+rm -rf "$STAGE"
+ISO_ROOT="$STAGE/iso"
+RFS="$STAGE/rfs"
+mkdir -p "$ISO_ROOT/boot/grub/i386-pc" "$RFS"
+
+# --- initramfs: rootfs (hardlinks) + /init marcador que arranca el init real ---
+echo "==> staging initramfs desde $ROOTFS (hardlinks) + /init marcador"
+cp -al "$ROOTFS" "$RFS/root"
+# El cpio se arma desde $RFS/root; inyectamos /init ahí (rdinit=/init lo busca en la raíz del initramfs).
+cat > "$RFS/root/init" <<'INIT'
+#!/bin/sh
+# /init del medio live (Etapa E5): monta lo básico, deja un marcador inequívoco y arranca el init real.
+/bin/busybox mount -t proc     proc /proc 2>/dev/null || true
+/bin/busybox mount -t sysfs    sys  /sys  2>/dev/null || true
+/bin/busybox mount -t devtmpfs dev  /dev  2>/dev/null || true
+echo "HAMMER-ISO-LIVE-OK: medio live arrancado desde El Torito"
+exec /sbin/init
+INIT
+chmod +x "$RFS/root/init"
+
+echo "==> empaquetando initramfs.cpio.gz"
+( cd "$RFS/root" && find . -print0 | cpio --null -o -H newc -R 0:0 2>/dev/null | gzip -1 ) > "$ISO_ROOT/boot/initramfs.cpio.gz"
+
+# --- kernel + módulos GRUB + grub.cfg en el árbol del ISO ---
+cp "$KERNEL" "$ISO_ROOT/boot/bzImage"; chmod 0644 "$ISO_ROOT/boot/bzImage"
+cp "$GRUB_LIB"/*.mod "$GRUB_LIB"/*.lst "$ISO_ROOT/boot/grub/i386-pc/" 2>/dev/null || true
+cat > "$ISO_ROOT/boot/grub/grub.cfg" <<CFG
+set timeout=2
+set default=0
+serial --unit=0 --speed=115200
+terminal_input serial console
+terminal_output serial console
+insmod iso9660
+insmod normal
+menuentry "hammer (live)" {
+    linux /boot/bzImage $CMDLINE
+    initrd /boot/initramfs.cpio.gz
+}
+CFG
+
+# --- core GRUB El Torito: igual que el de disco pero con iso9660+biosdisk en vez de ext2 ---
+echo "==> grub-mkimage El Torito (formato i386-pc-eltorito, módulos iso9660)"
+grub-mkimage -O i386-pc-eltorito -p '/boot/grub' -o "$ISO_ROOT/boot/grub/i386-pc/eltorito.img" \
+    biosdisk iso9660 part_gpt part_msdos normal configfile linux echo ls boot search
+
+# --- armar el ISO con xorriso (personalidad mkisofs), El Torito + isohybrid MBR ---
+echo "==> xorriso: armando $ISO (El Torito BIOS + isohybrid MBR)"
+rm -f "$ISO"
+MBR_ARGS=""
+[ -r "$GRUB_LIB/boot_hybrid.img" ] && MBR_ARGS="--grub2-mbr $GRUB_LIB/boot_hybrid.img"
+# shellcheck disable=SC2086
+"$XORRISO" -as mkisofs \
+    -volid HAMMER_LIVE \
+    -graft-points \
+    $MBR_ARGS \
+    -b boot/grub/i386-pc/eltorito.img \
+    -no-emul-boot -boot-load-size 4 -boot-info-table \
+    --grub2-boot-info \
+    -o "$ISO" \
+    "$ISO_ROOT" 2>&1 | grep -viE "^xorriso : NOTE|Drive current|Media current|Media status|Media summary|libisofs:|^xorriso : UPDATE" || true
+
+[ -s "$ISO" ] || { echo "FALLO: xorriso no produjo el ISO" >&2; exit 1; }
+rm -rf "$STAGE"
+echo "==> ISO live creado: $(du -h "$ISO" | cut -f1) — $ISO"
+echo "    auto-boot: qemu-system-x86_64 -cdrom $ISO -boot d -nographic"
+
+if [ "${BOOT:-0}" = 1 ]; then
+    echo "==> arranque de prueba (desde el CD El Torito)"
+    accel=""
+    [ "${KVM:-0}" = 1 ] && [ -w /dev/kvm ] && accel="-enable-kvm -cpu host"
+    # shellcheck disable=SC2086
+    exec qemu-system-x86_64 -m "${MEM:-4096}" -no-reboot -nographic $accel \
+        -cdrom "$ISO" -boot d
+fi