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.
273 lines
17 KiB
Bash
Executable File
273 lines
17 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# selfhost-verify.sh — Verifica el auto-alojamiento bit a bit de Stage 1 de punta a punta
|
||
# (SDD 11 §7; runbook docs/runbooks/stage1-vm-boot.md §8c).
|
||
#
|
||
# Hace TODO el pipeline en una corrida, pensado para un host con KVM + RAM holgada (p. ej. una
|
||
# laptop): construye el store baseline, ensambla el builder, lo empaqueta como initramfs y lo bootea
|
||
# en QEMU, donde `rebuild-stage1` reconstruye stage1' con el toolchain de adentro y compara su
|
||
# content-hash (`of_tree`) con la referencia anclada afuera → ✓ REPRODUCIBLE / ✗ DIVERGENTE.
|
||
#
|
||
# Prerequisitos:
|
||
# - Lab de dev: ./scripts/bootstrap-devfs.sh (deja .dev-fs/alpine + .dev-fs/tools/zig)
|
||
# - qemu-system-x86_64, cpio, gzip; un kernel x86_64 en $KERNEL.
|
||
# - Red (el fetch de Rust hace `cargo vendor` desde crates.io).
|
||
#
|
||
# Variables (override por entorno):
|
||
# STORE store content-addressed (default ./store)
|
||
# KERNEL kernel a bootear en la VM (default /boot/vmlinuz-linux)
|
||
# MEM RAM de la VM en MiB (default 6144; con KVM subí a 8192+)
|
||
# KVM 1 ⇒ -enable-kvm -cpu host (default auto: 1 si hay /dev/kvm)
|
||
# PRESEED "all" rebuild 4/4 in-VM | "hammerd" preseed C+arje, sólo hammerd in-VM
|
||
# (default all; "hammerd" es el camino barato/rápido si la RAM va justa)
|
||
# EXPECT_REF content-hash esperado (cross-check de reproducibilidad entre máquinas; opcional)
|
||
# STAGE0_URL / STAGE0_SHA256 / SEED_VERSION semilla zig (defaults: zig 0.16.0)
|
||
#
|
||
# Uso típico en la laptop (con KVM):
|
||
# KVM=1 MEM=10240 ./scripts/selfhost-verify.sh
|
||
set -euo pipefail
|
||
|
||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||
cd "$REPO_ROOT"
|
||
|
||
STORE="${STORE:-store}"
|
||
KERNEL="${KERNEL:-/boot/vmlinuz-linux}"
|
||
MEM="${MEM:-6144}"
|
||
PRESEED="${PRESEED:-all}"
|
||
SEED_VERSION="${SEED_VERSION:-0.16.0}"
|
||
STAGE0_URL="${STAGE0_URL:-https://ziglang.org/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz}"
|
||
STAGE0_SHA256="${STAGE0_SHA256:-70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00}"
|
||
TOOLCHAIN="${TOOLCHAIN:-.dev-fs/alpine}"
|
||
TOOLCHAIN_TAG="${TOOLCHAIN_TAG:-alpine-3.23.4-builder}"
|
||
# Referencia conocida-buena (store baseline en el host de dev, runbook §8c). Si tu corrida produce
|
||
# otra, o bien cambió algo del pin (toolchain/recipes/seed) o hay un no-determinismo nuevo.
|
||
# Baseline DETERMINISTA con codegen-units=1 + CARGO_BUILD_JOBS=1 en el sandbox: el segundo serializa
|
||
# el backend paralelo de rustc/LLVM (ThinLTO), sin el cual arje-zero divergía ~62 KB a >1 CPU (el
|
||
# viejo 0039b2b9… era un build paralelo no-reproducible). Ver §8c y SDD 09 §2.
|
||
EXPECT_REF="${EXPECT_REF:-b3:9adefb82b8457c8616cc89e6bb725a787ea52641f65d60d989d819e4872735ac}"
|
||
: "${KVM:=$([[ -w /dev/kvm ]] && echo 1 || echo 0)}"
|
||
|
||
say() { printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
|
||
die() { printf '\033[1;31mERROR: %s\033[0m\n' "$*" >&2; exit 1; }
|
||
|
||
[[ -x "$TOOLCHAIN/usr/bin/rustc" ]] || die "falta el lab: corré ./scripts/bootstrap-devfs.sh (no veo $TOOLCHAIN)"
|
||
[[ -r "$KERNEL" ]] || die "no puedo leer el kernel $KERNEL (set KERNEL=…)"
|
||
command -v qemu-system-x86_64 >/dev/null || die "falta qemu-system-x86_64"
|
||
|
||
# 0) Binario takana estático (musl, crt-static) — el builder lo bootea adentro.
|
||
HAMMER_BIN="target/x86_64-unknown-linux-musl/release/hammer"
|
||
say "build hammer estático ($HAMMER_BIN)"
|
||
cargo build --release --target x86_64-unknown-linux-musl -p takana-cli
|
||
HAMMER="./$HAMMER_BIN"
|
||
|
||
say "stage0 — ingerir la semilla zig (idempotente)"
|
||
"$HAMMER" --store "$STORE" bootstrap stage0 \
|
||
--url "$STAGE0_URL" --sha256 "$STAGE0_SHA256" --version "$SEED_VERSION"
|
||
# El seed_hash sale del nombre del artefacto sellado (robusto: no parsea stdout, donde el sha256 del
|
||
# tarball también es 64-hex y podría confundirse).
|
||
SEED_HASH="$(ls -d "$STORE"/*-seed-zig 2>/dev/null | head -1 | sed -E 's#.*/([0-9a-f]{64})-seed-zig#b3:\1#')"
|
||
[[ "$SEED_HASH" == b3:* && ${#SEED_HASH} -eq 67 ]] || die "no encuentro la semilla sellada en $STORE"
|
||
say "semilla: $SEED_HASH"
|
||
|
||
# 0c) Auto-alojamiento del COMPILADOR (variante b, pieza rust). A DIFERENCIA de make/busybox/bwrap/…
|
||
# (herramientas que ORQUESTAN o COPIAN ⇒ bytes idénticos), **rustc EMITE los binarios del 4/4**
|
||
# (arje-zero, hammerd): un rustc distinto ⇒ of_tree DIVERGE del baseline Alpine 9adefb82. Por eso
|
||
# el criterio no es igualdad con Alpine sino AUTO-CONSISTENCIA: el REF se RECOMPUTA con takana-rust
|
||
# (nuevo EXPECT_REF) y la VM debe reproducir ESE. El swap entra en $TOOLCHAIN, que sirve TANTO al
|
||
# build host del REF (este script, abajo) COMO al toolchain in-VM del builder (--toolchain); se
|
||
# restaura al salir (trap). takana-rust se construye con scripts/rust-frontier (climb mrustc→1.91.1).
|
||
# SWAP_RUST=1 → overlay .scratch/rust-1.91.1-prefix sobre /toolchain/usr/{bin,lib}.
|
||
# RUST_PREFIX=DIR → prefix takana-rust alternativo (default .scratch/rust-1.91.1-prefix).
|
||
# RUST_EXPECT_REF=… → REF conocido-bueno de takana-rust (cross-check; vacío ⇒ sólo lo imprime).
|
||
# ⚠️ Usá PRESEED=hammerd con SWAP_RUST: arje-zero (monorepo tawasuyu) vendorea ~1973 crates;
|
||
# en un rebuild in-VM completo (PRESEED=all) ese vendor desborda el rootfs en RAM de la VM
|
||
# (ENOSPC). PRESEED=hammerd preseedea el arje-zero host-built (takana-rust, locked) y sólo
|
||
# reconstruye hammerd in-VM. ✓ REPRODUCIBLE verificado así (2026-06-18, of_tree 7fa6cb4e).
|
||
if [[ "${SWAP_RUST:-0}" == 1 ]]; then
|
||
RUST_PREFIX="${RUST_PREFIX:-.scratch/rust-1.91.1-prefix}"
|
||
[[ -x "$RUST_PREFIX/bin/rustc" ]] || die "SWAP_RUST=1 pero no veo el prefix hammer-rust en $RUST_PREFIX (corré el climb: scripts/rust-frontier/README.md)"
|
||
say "variante b (compilador) — swapear hammer-rust 1.91.1 en $TOOLCHAIN (criterio: auto-consistencia)"
|
||
scripts/rust-frontier/swap-rust-into-toolchain.sh --prefix "$RUST_PREFIX" --toolchain "$TOOLCHAIN"
|
||
trap 'scripts/rust-frontier/swap-rust-into-toolchain.sh --restore --toolchain "$TOOLCHAIN" >/dev/null 2>&1 || true' EXIT
|
||
# OJO: el input-hash del store NO incluye el rustc (recipe.hash_inputs = source+compiler+target+
|
||
# link+patches+flags+phases+deps), así que en el ./store compartido arje-zero/hammerd quedarían
|
||
# CACHEADOS con los bytes de Alpine y el swap sería un no-op. Usamos un store DEDICADO (store-rust)
|
||
# para forzar el rebuild de los 4/4 con takana-rust; así el of_tree refleja el compilador nuevo.
|
||
STORE="${RUST_STORE:-store-rust}"
|
||
say "SWAP_RUST: store dedicado $STORE (el ./store baseline no se toca; fuerza rebuild con hammer-rust)"
|
||
# Con takana-rust el REF NO es el 9adefb82 de Alpine; comparamos contra RUST_EXPECT_REF, el
|
||
# of_tree(stage1) auto-consistente de takana-rust 1.91.1 (reproducido 2× en host, 2026-06-17,
|
||
# store-rust y store-rust2). Override con RUST_EXPECT_REF= para re-anclar.
|
||
EXPECT_REF="${RUST_EXPECT_REF:-b3:7fa6cb4e70a934d72206cf3d95cf46a13f0a6464ec73855b98d547195f4ed047}"
|
||
fi
|
||
|
||
# 1) Store baseline: stage1 (idempotente; rebuildea lo que falte con -mcpu=baseline ya en fuente).
|
||
say "stage1 — construir y sellar el rootfs baseline"
|
||
"$HAMMER" --store "$STORE" bootstrap stage1 --seed-hash "$SEED_HASH" --recipes recipes
|
||
ROOTFS_HASH="$(ls -d "$STORE"/*-stage1-rootfs | head -1 | sed -E 's#.*/([0-9a-f]{64})-stage1-rootfs#b3:\1#')"
|
||
[[ "$ROOTFS_HASH" == b3:* ]] || die "no encuentro el stage1-rootfs en $STORE"
|
||
say "stage1 rootfs: $ROOTFS_HASH"
|
||
|
||
# 2) Referencia of_tree(stage1) que la VM debe reproducir.
|
||
REF="$("$HAMMER" --store "$STORE" bootstrap stage2 --rootfs "$ROOTFS_HASH" 2>&1 \
|
||
| grep -oE 'content-hash: b3:[0-9a-f]{64}|content=b3:[0-9a-f]{64}' | grep -oE 'b3:[0-9a-f]{64}' | tail -1)"
|
||
[[ "$REF" == b3:* ]] || die "no obtuve la referencia de stage2"
|
||
say "referencia of_tree(stage1) = $REF"
|
||
if [[ -n "$EXPECT_REF" && "$REF" != "$EXPECT_REF" ]]; then
|
||
printf '\033[1;33mAVISO: la referencia difiere de la conocida-buena del host de dev:\n esta %s\n espera %s\nReproducibilidad entre máquinas rota O cambió un pin (toolchain/recipes/seed). Seguimos igual.\033[0m\n' "$REF" "$EXPECT_REF"
|
||
fi
|
||
|
||
# 3) Inyectar los módulos del kernel DE ESTA máquina al toolchain (el builder los carga: overlay para
|
||
# el sandbox bwrap, e1000 para la red del vendoring). Deben matchear el kernel que bootea la VM.
|
||
# La versión de los módulos DEBE matchear el kernel que bootea la VM ($KERNEL), no el del host
|
||
# corriendo el script ($(uname -r)) — en máquinas con varios kernels instalados difieren y el
|
||
# insmod falla con "version magic mismatch" → sin overlayfs, bwrap revienta. Sacamos la versión
|
||
# del propio bzImage; si no se puede, caemos a uname -r.
|
||
KVER="$(file -bL "$KERNEL" 2>/dev/null | grep -oE 'version [0-9][^ ]*' | awk '{print $2}')"
|
||
[[ -n "$KVER" && -d "/lib/modules/$KVER" ]] || KVER="$(uname -r)"
|
||
say "inyectar overlay.ko + e1000.ko (kernel $KVER) al toolchain"
|
||
moddir="/lib/modules/$KVER"
|
||
for m in overlay e1000; do
|
||
src="$(find "$moddir" -name "$m.ko*" 2>/dev/null | head -1)"
|
||
if [[ -n "$src" ]]; then
|
||
# Descomprimir si viene .ko.zst/.ko.gz/.ko.xz; el builder hace insmod del .ko crudo.
|
||
case "$src" in
|
||
*.zst) zstd -dqf "$src" -o "$TOOLCHAIN/lib/$m.ko" 2>/dev/null || cp "$src" "$TOOLCHAIN/lib/$(basename "$src")" ;;
|
||
*.gz) gzip -dc "$src" > "$TOOLCHAIN/lib/$m.ko" ;;
|
||
*.xz) xz -dc "$src" > "$TOOLCHAIN/lib/$m.ko" ;;
|
||
*) cp "$src" "$TOOLCHAIN/lib/$m.ko" ;;
|
||
esac
|
||
echo " $m: $src"
|
||
else
|
||
echo " $m: NO encontrado en $moddir (si la VM lo necesita, fallará: bwrap overlay / red)"
|
||
fi
|
||
done
|
||
|
||
# 3b) Auto-alojamiento *puro* (variante b, SDD 11 §7.2b): reemplazar piezas del toolchain Alpine por
|
||
# recetas takana construidas desde fuente, con Stage 2 reverificando que `of_tree(stage1')` NO
|
||
# cambia (el make takana compila los 4/4 igual de bit-a-bit que el de Alpine). Opt-in:
|
||
# SWAP_MAKE=1 → construye recipes/make.toml y lo monta sobre /toolchain/usr/bin/make.
|
||
# SWAP_BUSYBOX=1 → monta el busybox de takana sobre /toolchain/bin/busybox (los symlinks de
|
||
# applets de Alpine — sh/sed/grep/awk/tar/find — pasan a usarlo; cp/mkdir/
|
||
# install siguen siendo GNU coreutils, intactos).
|
||
# SWAP_LINUX_HEADERS=1 → construye recipes/linux-headers.toml y swap-directorio de los 13 subdirs
|
||
# kernel-owned de /toolchain/usr/include (linux/asm/…); musl bits/sys intactos.
|
||
# SWAP_BWRAP=1 → construye recipes/bwrap.toml (+libcap, su dep, vía deps.build) y lo monta
|
||
# sobre /toolchain/usr/bin/bwrap (el sandbox del propio lab).
|
||
# SWAP_COREUTILS=1 → construye recipes/coreutils.toml (multicall) y monta el binario sobre
|
||
# /toolchain/bin/coreutils; los ~100 symlinks (cp/mkdir/install/…) lo siguen.
|
||
# SWAPS="name=hash[:rel] …" → swaps explícitos extra (formato del flag --swap).
|
||
# Por defecto, off ⇒ corrida pura-Alpine (variante a), idéntica a la baseline conocida-buena.
|
||
# Piezas validadas en host: make+busybox reproducen of_tree=9adefb82 in-VM; linux-headers da un
|
||
# header-tree byte-idéntico a Alpine (diff -r vacío); bwrap rebuildea musl byte-idéntico de sandbox.
|
||
SWAP_ARGS=()
|
||
if [[ "${SWAP_MAKE:-0}" == 1 ]]; then
|
||
say "variante b — construir make desde fuente (recipes/make.toml) y swapearlo en /toolchain"
|
||
MAKE_HASH="$("$HAMMER" --store "$STORE" build recipes/make.toml | grep -oE 'b3:[0-9a-f]{64}' | tail -1)"
|
||
[[ "$MAKE_HASH" == b3:* ]] || die "no obtuve el hash sellado de make"
|
||
say "make hammer: $MAKE_HASH"
|
||
SWAP_ARGS+=(--swap "make=$MAKE_HASH")
|
||
fi
|
||
if [[ "${SWAP_BUSYBOX:-0}" == 1 ]]; then
|
||
say "variante b — construir busybox desde fuente y swapearlo en /toolchain/bin/busybox"
|
||
BB_HASH="$("$HAMMER" --store "$STORE" build recipes/busybox.toml | grep -oE 'b3:[0-9a-f]{64}' | tail -1)"
|
||
[[ "$BB_HASH" == b3:* ]] || die "no obtuve el hash sellado de busybox"
|
||
say "busybox hammer: $BB_HASH"
|
||
SWAP_ARGS+=(--swap "busybox=$BB_HASH:bin/busybox")
|
||
fi
|
||
if [[ "${SWAP_LINUX_HEADERS:-0}" == 1 ]]; then
|
||
# Pieza 3: los headers UAPI del kernel. NO es un binario sino un árbol — el swap-directorio
|
||
# (assemble_builder) reemplaza cada subdir entero. Swapeamos exactamente los subdirs que el
|
||
# artefacto sellado produce (linux/asm/asm-generic/cxl/fwctl/misc/mtd/rdma/regulator/scsi/sound/
|
||
# video/xen), que son justo los que el paquete linux-headers de Alpine posee; los de musl
|
||
# (bits/sys/net/…) quedan intactos.
|
||
say "variante b — construir linux-headers desde fuente y swapear /toolchain/usr/include/{linux,asm,…}"
|
||
LH_HASH="$("$HAMMER" --store "$STORE" build recipes/linux-headers.toml | grep -oE 'b3:[0-9a-f]{64}' | tail -1)"
|
||
[[ "$LH_HASH" == b3:* ]] || die "no obtuve el hash sellado de linux-headers"
|
||
say "linux-headers hammer: $LH_HASH"
|
||
LH_INC="$(ls -d "$STORE"/*-linux-headers/usr/include 2>/dev/null | head -1)"
|
||
[[ -d "$LH_INC" ]] || die "no encuentro usr/include en el linux-headers sellado"
|
||
for d in "$LH_INC"/*/; do
|
||
sub="$(basename "$d")"
|
||
SWAP_ARGS+=(--swap "linux-headers=${LH_HASH}:usr/include/$sub")
|
||
done
|
||
fi
|
||
if [[ "${SWAP_BWRAP:-0}" == 1 ]]; then
|
||
# Pieza 4: bwrap (bubblewrap), EL sandbox del lab. Binario estático ⇒ swap de archivo sobre
|
||
# /toolchain/usr/bin/bwrap. Su dep libcap la construye y materializa el lab solo (deps.build).
|
||
# bwrap es herramienta, no input del 4/4: no necesita casar byte-a-byte con Alpine, sólo aislar
|
||
# igual (validado en host — musl rebuildeó byte-idéntico bajo takana-bwrap).
|
||
say "variante b — construir bwrap (+libcap) desde fuente y swapearlo en /toolchain/usr/bin/bwrap"
|
||
BW_HASH="$("$HAMMER" --store "$STORE" build recipes/bwrap.toml | grep -oE 'b3:[0-9a-f]{64}' | tail -1)"
|
||
[[ "$BW_HASH" == b3:* ]] || die "no obtuve el hash sellado de bwrap"
|
||
say "bwrap hammer: $BW_HASH"
|
||
SWAP_ARGS+=(--swap "bwrap=${BW_HASH}:usr/bin/bwrap")
|
||
fi
|
||
if [[ "${SWAP_COREUTILS:-0}" == 1 ]]; then
|
||
# Pieza 5: GNU coreutils (cp/mkdir/ln/chmod/mv/install…). Multicall (--enable-single-binary), igual
|
||
# layout que Alpine: un binario /bin/coreutils + ~100 symlinks. UN swap del binario rutea todos los
|
||
# applets (los symlinks del toolchain ya apuntan a coreutils). Tool, no input: validado en host —
|
||
# musl Y busybox rebuildearon byte-idéntico bajo takana-coreutils.
|
||
say "variante b — construir coreutils desde fuente y swapearlo en /toolchain/bin/coreutils"
|
||
CU_HASH="$("$HAMMER" --store "$STORE" build recipes/coreutils.toml | grep -oE 'b3:[0-9a-f]{64}' | tail -1)"
|
||
[[ "$CU_HASH" == b3:* ]] || die "no obtuve el hash sellado de coreutils"
|
||
say "coreutils hammer: $CU_HASH"
|
||
SWAP_ARGS+=(--swap "coreutils=${CU_HASH}:bin/coreutils")
|
||
fi
|
||
for s in ${SWAPS:-}; do SWAP_ARGS+=(--swap "$s"); done
|
||
|
||
# 4) Ensamblar el builder con la referencia embebida.
|
||
say "ensamblar builder (toolchain in-rootfs + hammer baseline + ref${SWAP_ARGS:+ + swaps})"
|
||
"$HAMMER" --store "$STORE" bootstrap builder \
|
||
--stage1 "$ROOTFS_HASH" --seed-hash "$SEED_HASH" \
|
||
--hammer-bin "$HAMMER_BIN" \
|
||
--toolchain "$TOOLCHAIN" --toolchain-tag "$TOOLCHAIN_TAG" \
|
||
--ref-content "$REF" \
|
||
"${SWAP_ARGS[@]}" \
|
||
--work-cache work --out work/builder-rootfs
|
||
|
||
# 4b) Preseed opcional para abaratar el rebuild in-VM (sólo hammerd se reconstruye).
|
||
if [[ "$PRESEED" == "hammerd" ]]; then
|
||
say "preseed musl+busybox+arje-zero (sólo hammerd se reconstruye in-VM)"
|
||
for n in musl busybox arje-zero; do
|
||
d="$(ls -d "$STORE"/*-"$n" 2>/dev/null | head -1)"
|
||
[[ -n "$d" ]] && cp -a "$d" work/builder-rootfs/store/ && echo " preseed: $(basename "$d")"
|
||
done
|
||
fi
|
||
|
||
# 4c) HAMMER_KERNEL=1 — wrapper /init para escapar del rootfs (frente kernel-from-source).
|
||
# Con un kernel takana-built (recipes/linux.toml) el `/` del initramfs es el rootfs ABSOLUTO del
|
||
# mount-namespace (su propio padre, no movible) y bwrap del sandbox falla en `pivot_root: Invalid
|
||
# argument` (el kernel host no lo exigía — quirk suyo). El fix portable (funciona en cualquier
|
||
# kernel): un /init PID1 que copia el rootfs a un tmpfs y hace `switch_root`, dejando `/` como un
|
||
# mount tmpfs real (pivotable). El kernel debe arrancar con rdinit=/init (ver APPEND abajo). Off por
|
||
# defecto ⇒ el camino del kernel host queda intacto (rdinit=/sbin/init directo).
|
||
if [[ "${TAKANA_KERNEL:-${HAMMER_KERNEL:-0}}" == 1 ]]; then
|
||
say "HAMMER_KERNEL: inyectar /init wrapper (copy-to-tmpfs + switch_root, escapa del rootfs)"
|
||
cat > work/builder-rootfs/init <<'INIT'
|
||
#!/bin/sh
|
||
# PID1 wrapper: el rootfs del initramfs no es pivotable (bwrap pivot_root EINVAL); copiamos a un tmpfs
|
||
# y switch_root para que / sea un mount real. Luego exec del init real (arje-zero).
|
||
/bin/busybox mkdir -p /newroot
|
||
/bin/busybox mount -t tmpfs tmpfs /newroot
|
||
cd /
|
||
for e in /*; do
|
||
[ "$e" = /newroot ] && continue
|
||
/bin/busybox cp -a "$e" /newroot/
|
||
done
|
||
exec /bin/busybox switch_root /newroot /sbin/init
|
||
INIT
|
||
chmod +x work/builder-rootfs/init
|
||
export APPEND="console=ttyS0 rdinit=/init"
|
||
fi
|
||
|
||
# 5) Empaquetar como initramfs. --owner=root:root OBLIGATORIO: si los ficheros viajan con el uid del
|
||
# host, el userns de bwrap (mapea 0→0) no lo mapea y el copy-up de overlay falla con EACCES.
|
||
say "empaquetar initramfs (cpio newc, --owner=root:root)"
|
||
( cd work/builder-rootfs && find . -print0 | cpio --null -o -H newc --owner=root:root 2>/dev/null | gzip -1 ) > work/builder.cpio.gz
|
||
echo " work/builder.cpio.gz: $(du -h work/builder.cpio.gz | cut -f1)"
|
||
|
||
# 6) Bootear + driver no-interactivo → veredicto.
|
||
say "bootear la VM y correr rebuild-stage1 (KVM=$KVM MEM=$MEM)"
|
||
KVM="$KVM" MEM="$MEM" KERNEL="$KERNEL" BUILDER_CPIO="work/builder.cpio.gz" \
|
||
python3 scripts/drive-rebuild.py
|