250 líneas de comentario en 151 scripts. Control verificado: el diff no toca NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa. El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces: las tres eran el MOTD que el script escribe DENTRO de la imagen construida — texto del producto, no comentario del script. Se cambiaron aparte y a propósito, que es rebranding, no limpieza. Y el hallazgo caro: casaba contra , que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate. La etapa 4 lo movió a y el script quedó casando NADA. No fallaba: imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja. Además 14 rutas de módulo en docs, que el barrido anterior no tocó porque no es frontera de palabra.
239 lines
14 KiB
Bash
Executable File
239 lines
14 KiB
Bash
Executable File
#!/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 (`takana install /dev/sdX`) en hardware nuevo, o para probar el sistema sin
|
|
# instalarlo.
|
|
#
|
|
# El ISO lo ARMA `xorriso` construido por takana 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}"
|
|
GRUB_EFI_LIB="${GRUB_EFI_LIB:-/usr/lib/grub/x86_64-efi}"
|
|
CMDLINE="${CMDLINE:-console=ttyS0 rdinit=/init}"
|
|
# xorriso: preferimos el construido por takana (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)"
|
|
# mtools (mformat/mcopy): para poblar la ESP FAT del arranque EFI. Preferimos el de takana (dogfooding).
|
|
MTOOLS_DIR="${MTOOLS_DIR:-$(ls -d store/*-mtools/usr/bin 2>/dev/null | head -1)}"
|
|
|
|
[ -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).
|
|
# /init del medio live: monta lo básico + marcador. Con AUTO_INSTALL=<dev>, instala desatendido a ese
|
|
# disco y apaga (instalación unattended + scaffolding del test); si no, arranca el init real (live).
|
|
{
|
|
echo '#!/bin/sh'
|
|
echo '# /init del medio live (Etapa E5).'
|
|
echo '/bin/busybox mount -t proc proc /proc 2>/dev/null || true'
|
|
echo '/bin/busybox mount -t sysfs sys /sys 2>/dev/null || true'
|
|
echo '/bin/busybox mount -t devtmpfs dev /dev 2>/dev/null || true'
|
|
echo 'echo "HAMMER-ISO-LIVE-OK: medio live arrancado desde El Torito"'
|
|
if [ -n "${AUTO_INSTALL:-}" ]; then
|
|
echo "echo 'HAMMER-AUTO-INSTALL: instalando a ${AUTO_INSTALL}'"
|
|
echo "if /usr/bin/hammer-install '${AUTO_INSTALL}'; then echo 'HAMMER-INSTALL-OK'; else echo 'HAMMER-INSTALL-FAIL'; fi"
|
|
echo '/bin/busybox sync'
|
|
echo '/bin/busybox poweroff -f'
|
|
elif [ "${INSTALLER:-0}" = 1 ] && [ "${INSTALLER_INTERACTIVE:-1}" = 1 ]; then
|
|
# ISO instalador SIN AUTO_INSTALL ⇒ recibir al usuario con la TUI del instalador en la consola.
|
|
# Tras instalar (o cancelar) ofrece reiniciar o caer al live. HAMMER_INSTALL_INTERACTIVE fuerza el
|
|
# modo aunque /dev/console no pase el test -t (a esta altura stdin puede no ser un tty).
|
|
echo '[ -e /dev/console ] && exec 0</dev/console 1>/dev/console 2>/dev/console'
|
|
echo 'HAMMER_INSTALL_INTERACTIVE=1 /usr/bin/hammer-install || true'
|
|
echo 'echo; echo "Instalación finalizada. [r] reiniciar · [Enter] shell en vivo"'
|
|
echo 'read -r _a || _a=""'
|
|
echo 'case "$_a" in r|R) /bin/busybox reboot -f ;; *) exec /sbin/init ;; esac'
|
|
else
|
|
echo 'exec /sbin/init'
|
|
fi
|
|
} > "$RFS/root/init"
|
|
chmod +x "$RFS/root/init"
|
|
|
|
# --- INSTALLER=1: payload de instalación a disco DESDE el live (refinamiento #1) ---
|
|
# Bundle kernel + GRUB (boot.img + core.img MBR-prefix + módulos) bajo /usr/lib/hammer/install/ y el
|
|
# instalador en /usr/bin/hammer-install. El core.img se arma acá (build-time, el host tiene
|
|
# grub-mkimage); el live NO lo necesita — sólo dd's. core prefix (hd0,msdos1)/boot/grub para boot MBR.
|
|
if [ "${INSTALLER:-0}" = 1 ]; then
|
|
echo "==> INSTALLER=1: bundling payload de instalación a disco (kernel + GRUB MBR + hammer-install)"
|
|
IPL="$RFS/root/usr/lib/hammer/install"
|
|
mkdir -p "$IPL/grub/i386-pc" "$IPL/kernel"
|
|
cp "$KERNEL" "$IPL/kernel/bzImage"; chmod 0644 "$IPL/kernel/bzImage"
|
|
# Rama EFI del instalador (ADR 0010 paso 5): el kernel `linux-metal` hornea CONFIG_CMDLINE con
|
|
# initrd=/initramfs.cpio.gz rdinit=/init ⇒ arranca por EFI-stub como \EFI\BOOT\BOOTX64.EFI sin
|
|
# bootloader. Lo bundleamos junto al genérico; takana-install lo usa si el live corre en UEFI.
|
|
EFI_KERNEL="${EFI_KERNEL:-$(ls -dt store/*-linux-metal/boot/bzImage 2>/dev/null | head -1)}"
|
|
if [ -n "${EFI_KERNEL:-}" ] && [ -r "$EFI_KERNEL" ]; then
|
|
cp "$EFI_KERNEL" "$IPL/kernel/bzImage-efi"; chmod 0644 "$IPL/kernel/bzImage-efi"
|
|
echo " + kernel EFI-stub (metal) para la rama UEFI del instalador"
|
|
else
|
|
echo " ! sin kernel linux-metal en el store ⇒ el instalador sólo tendrá rama BIOS/MBR" >&2
|
|
fi
|
|
cp "$GRUB_LIB/boot.img" "$IPL/grub/boot.img"
|
|
cp "$GRUB_LIB"/*.mod "$GRUB_LIB"/*.lst "$IPL/grub/i386-pc/" 2>/dev/null || true
|
|
# core.img para disco MBR: prefix a la 1ª partición msdos, módulos de disco (biosdisk/part_msdos/ext2).
|
|
grub-mkimage -O i386-pc -p '(hd0,msdos1)/boot/grub' -o "$IPL/grub/core.img" \
|
|
biosdisk part_msdos ext2 normal configfile linux echo ls boot search
|
|
install -m 0755 "$ROOT/scripts/hammer-live-install.sh" "$RFS/root/usr/bin/hammer-install"
|
|
# hammer-recover (static musl): auto-sana un upgrade interrumpido al arranque del sistema instalado.
|
|
RECOVER_BIN="$ROOT/target/x86_64-unknown-linux-musl/release/hammer-recover"
|
|
if [ ! -x "$RECOVER_BIN" ]; then
|
|
echo "==> compilando hammer-recover (static musl) para el payload"
|
|
cargo build --release --target x86_64-unknown-linux-musl -p takana-recover --manifest-path "$ROOT/Cargo.toml" >/dev/null 2>&1
|
|
fi
|
|
[ -x "$RECOVER_BIN" ] || { echo "no pude construir hammer-recover (target musl?)" >&2; exit 1; }
|
|
install -m 0755 "$RECOVER_BIN" "$IPL/hammer-recover"
|
|
# CLI `takana` (static musl) para el menú de arranque por grafo (ADR 0010): el hook de init del
|
|
# sistema instalado lo invoca como `takana boot menu`. El producto trae arje-zero/hammerd pero NO el
|
|
# CLI ⇒ lo bundleamos al payload; takana-install lo copia a /usr/bin/hammer del disco.
|
|
HAMMER_BIN="$ROOT/target/x86_64-unknown-linux-musl/release/hammer"
|
|
if [ ! -x "$HAMMER_BIN" ]; then
|
|
echo "==> compilando hammer CLI (static musl) para el payload"
|
|
cargo build --release --target x86_64-unknown-linux-musl -p takana-cli --manifest-path "$ROOT/Cargo.toml" >/dev/null 2>&1
|
|
fi
|
|
[ -x "$HAMMER_BIN" ] || { echo "no pude construir el CLI hammer (target musl?)" >&2; exit 1; }
|
|
install -m 0755 "$HAMMER_BIN" "$IPL/hammer"
|
|
fi
|
|
|
|
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
|
|
|
|
# --- EFI=1: rama UEFI (refinamiento #3). Construye grubx64.efi (mismo grub.cfg, lee kernel+initrd del
|
|
# iso9660) y una ESP FAT con EFI/BOOT/BOOTX64.EFI, poblada con mtools (sin root). El kernel ya trae
|
|
# EFI_STUB; aquí GRUB EFI es el cargador (espeja la rama BIOS). xorriso añade un 2º El Torito (EFI). ---
|
|
EFI_ARGS=""
|
|
if [ "${EFI:-0}" = 1 ]; then
|
|
MFORMAT="$MTOOLS_DIR/mformat"; MCOPY="$MTOOLS_DIR/mcopy"; MMD="$MTOOLS_DIR/mmd"
|
|
[ -x "$MFORMAT" ] && [ -x "$MCOPY" ] || MFORMAT="$(command -v mformat 2>/dev/null || true)"
|
|
[ -n "$MFORMAT" ] && [ -x "$MFORMAT" ] || { echo "no encuentro mtools (build recipes/mtools.toml)" >&2; exit 1; }
|
|
[ -x "$MCOPY" ] || { MCOPY="$(command -v mcopy)"; MMD="$(command -v mmd)"; }
|
|
ESP="$ISO_ROOT/boot/grub/efi.img"
|
|
if [ "${EFI_STUB:-0}" = 1 ]; then
|
|
# --- EFI_STUB=1: arranque por EFI-STUB DIRECTO (sin GRUB-EFI). El bzImage ES el BOOTX64.EFI; la
|
|
# firmware lo lanza por el path de medio removible \EFI\BOOT\BOOTX64.EFI. El cmdline va
|
|
# HORNEADO en el kernel (CONFIG_CMDLINE, recipes/linux-metal.toml) con initrd=/initramfs.cpio.gz
|
|
# ⇒ el EFI-stub carga el initrd de la PROPIA ESP (file.c convierte '/'→'\'). Esquiva el bug de
|
|
# GRUB 2.14 que cuelga la rama UEFI con cualquier kernel. ---
|
|
INITRAMFS="$ISO_ROOT/boot/initramfs.cpio.gz"
|
|
[ -r "$INITRAMFS" ] || { echo "no encuentro $INITRAMFS para la ESP EFI-stub" >&2; exit 1; }
|
|
echo "==> EFI=1 EFI_STUB=1: kernel→BOOTX64.EFI + initramfs en la ESP (FAT32, sin GRUB-EFI)"
|
|
# ESP grande (kernel + initramfs + holgura) ⇒ FAT32 (-F), válido y recomendado para ESP en metal.
|
|
espkb=$(( ( $(stat -c%s "$KERNEL") + $(stat -c%s "$INITRAMFS") ) / 1024 + 8192 ))
|
|
rm -f "$ESP"; truncate -s "$(( espkb * 1024 ))" "$ESP"
|
|
"$MFORMAT" -F -i "$ESP" ::
|
|
"$MMD" -i "$ESP" ::/EFI ::/EFI/BOOT
|
|
"$MCOPY" -i "$ESP" "$KERNEL" ::/EFI/BOOT/BOOTX64.EFI
|
|
"$MCOPY" -i "$ESP" "$INITRAMFS" ::/initramfs.cpio.gz
|
|
else
|
|
# --- EFI=1 (default): GRUB EFI como cargador (espeja la rama BIOS, lee kernel+initrd del iso9660). ---
|
|
[ -d "$GRUB_EFI_LIB" ] || { echo "faltan módulos GRUB x86_64-efi en $GRUB_EFI_LIB" >&2; exit 1; }
|
|
echo "==> EFI=1: grub-mkimage x86_64-efi + ESP FAT (mtools: $MFORMAT)"
|
|
mkdir -p "$STAGE/efi"
|
|
grub-mkimage -O x86_64-efi -p '/boot/grub' -o "$STAGE/efi/bootx64.efi" \
|
|
part_gpt part_msdos fat iso9660 normal configfile linux echo ls boot search search_fs_uuid efi_gop efi_uga
|
|
# Tamaño ≥ 1.44 MiB; mformat SIN -F auto-elige FAT12/16 por nº de clusters (FAT32 exige ~33 MiB).
|
|
espkb=$(( ( $(stat -c%s "$STAGE/efi/bootx64.efi") / 1024 ) + 512 ))
|
|
[ "$espkb" -lt 1440 ] && espkb=1440
|
|
rm -f "$ESP"; truncate -s "$(( espkb * 1024 ))" "$ESP"
|
|
"$MFORMAT" -i "$ESP" ::
|
|
"$MMD" -i "$ESP" ::/EFI ::/EFI/BOOT
|
|
"$MCOPY" -i "$ESP" "$STAGE/efi/bootx64.efi" ::/EFI/BOOT/BOOTX64.EFI
|
|
fi
|
|
EFI_ARGS="-eltorito-alt-boot -e boot/grub/efi.img -no-emul-boot -isohybrid-gpt-basdat"
|
|
fi
|
|
|
|
# --- armar el ISO con xorriso (personalidad mkisofs), El Torito BIOS (+EFI si EFI=1) + isohybrid MBR ---
|
|
echo "==> xorriso: armando $ISO (El Torito BIOS${EFI_ARGS:+ + EFI} + 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 \
|
|
$EFI_ARGS \
|
|
-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
|