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…

⎇ 3ac329ec8fb93eff52ce4491dbe4857837d90620 scripts/hammer-live-install.sh Shell · 300 lines · 13.8 KB History raw

arranque-grafo: cero-parpadeo VERDE + fix marcador INIT-OK tras switch_root 3ac329ec8 · sergio ·

1#!/bin/sh
2# hammer-install — instalador a disco DESDE el medio live (Etapa E5 / refinamiento #1).
3#
4# Se inyecta en el rootfs del producto como /usr/bin/hammer-install (ver scripts/iso-image.sh
5# INSTALLER=1). Corre DENTRO del live, como root real (arje-zero es PID1) ⇒ NO necesita unshare -r
6# ni los rodeos rootless de install-image.sh: particiona, formatea, monta y copia con privilegios
7# reales, usando sólo herramientas que el producto ya trae (busybox fdisk/mke2fs/mount/dd + uutils cp).
8#
9# El sistema que se instala es EL PROPIO LIVE: la raíz en RAM se copia al disco (autoinstalador). El
10# payload de arranque (kernel + GRUB) viaja en /usr/lib/hammer/install/, armado en build-time (el host
11# tiene grub-mkimage; el live no lo necesita).
12#
13# Layout en disco (MBR, no GPT — más simple y busybox-friendly; GRUB va en el hueco post-MBR):
14#   /dev/<dev>1  /                ext2(montable ext4)   + /boot/bzImage + /boot/grub + wrapper /sbin/init
15#   /dev/<dev>2  /store           ext2
16#   /dev/<dev>3  /var/lib/hammer  ext2
17#
18# Cadena de arranque del disco resultante: BIOS → MBR (boot.img) → core.img (hueco post-MBR) →
19# (hd0,msdos1)/boot/grub/grub.cfg → linux /boot/bzImage root=/dev/<dev>1 → wrapper /sbin/init.
20#
21# Uso (en el live):  hammer-install /dev/vdb [ROOT_MB] [STORE_MB]
22set -eu
23
24DEV="${1:-/dev/vdb}"
25ROOT_MB="${2:-1500}"
26STORE_MB="${3:-400}"     # /var/lib/hammer toma el resto
27PAYLOAD=/usr/lib/hammer/install
28BB=/bin/busybox
29
30[ -b "$DEV" ] || { echo "hammer-install: $DEV no es un block device" >&2; exit 1; }
31[ -d "$PAYLOAD" ] || { echo "hammer-install: falta el payload $PAYLOAD (¿ISO sin INSTALLER=1?)" >&2; exit 1; }
32
33# --- Detección de firmware: UEFI ⇒ rama EFI-stub SOBERANA (ADR 0010 paso 5); BIOS ⇒ MBR+GRUB (abajo) ---
34# La rama EFI usa una ESP tipo 0xEF en tabla MBR (UEFI arranca \EFI\BOOT\BOOTX64.EFI de una ESP MBR igual
35# que de GPT) ⇒ alcanza con busybox fdisk/mkfs.vfat/mount, sin GPT-tool ni mtools. El bzImage metal ES el
36# binario EFI (EFI-stub, cmdline horneada carga el initrd); un initramfs mínimo pivota por LABEL. Mismos
37# artefactos que scripts/install-image-efi.sh (validado en OVMF), armados desde dentro del live.
38if [ -d /sys/firmware/efi ]; then
39    [ -r "$PAYLOAD/kernel/bzImage-efi" ] || { echo "hammer-install: live en UEFI pero falta $PAYLOAD/kernel/bzImage-efi (ISO sin kernel metal)" >&2; exit 1; }
40    ESP_MB="${ESP_MB:-64}"
41    echo "==> hammer-install (UEFI): EFI-stub soberano en $DEV (ESP ${ESP_MB}M, root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
42    echo "    ¡esto BORRA $DEV!"
43
44    # MBR, 4 primarias: p1=ESP(0xEF) p2=root p3=store p4=estado. Sectores explícitos (como la rama BIOS).
45    SPM=2048
46    P1S=2048;            P1E=$(( P1S + ESP_MB  * SPM - 1 ))
47    P2S=$(( P1E + 1 ));  P2E=$(( P2S + ROOT_MB * SPM - 1 ))
48    P3S=$(( P2E + 1 ));  P3E=$(( P3S + STORE_MB* SPM - 1 ))
49    P4S=$(( P3E + 1 ))   # estado = resto del disco
50    echo "==> particionando $DEV (MBR: ESP ${P1S}-${P1E} tipo ef, root ${P2S}-${P2E}, store ${P3S}-${P3E}, estado ${P4S}-fin)"
51    "$BB" fdisk "$DEV" >/dev/null 2>&1 <<FDISK || true
52o
53n
54p
551
56$P1S
57$P1E
58n
59p
602
61$P2S
62$P2E
63n
64p
653
66$P3S
67$P3E
68n
69p
704
71$P4S
72
73t
741
75ef
76a
771
78w
79FDISK
80    "$BB" partprobe "$DEV" 2>/dev/null || true
81    "$BB" sync; sleep 1
82    P1="${DEV}1"; P2="${DEV}2"; P3="${DEV}3"; P4="${DEV}4"
83    for p in "$P1" "$P2" "$P3" "$P4"; do
84        [ -b "$p" ] || { echo "hammer-install: no apareció la partición $p tras particionar" >&2; exit 1; }
85    done
86
87    echo "==> formateando (ESP FAT32 + 3 ext2 etiquetadas para el pivote por LABEL)"
88    "$BB" mkfs.vfat -F 32 -n HAMMER "$P1" >/dev/null 2>&1
89    "$BB" mke2fs -F -L hammer-root  "$P2" >/dev/null 2>&1
90    "$BB" mke2fs -F -L hammer-store "$P3" >/dev/null 2>&1
91    "$BB" mke2fs -F -L hammer-state "$P4" >/dev/null 2>&1
92
93    # initramfs de pivote (busybox estático del live + /init: findfs LABEL=hammer-root → switch_root).
94    echo "==> armando el initramfs de pivote (busybox + /init switch_root a hammer-root)"
95    IRD_TREE=/run/hammer-efi-ird
96    "$BB" rm -rf "$IRD_TREE"
97    "$BB" mkdir -p "$IRD_TREE/bin" "$IRD_TREE/dev" "$IRD_TREE/proc" "$IRD_TREE/sys" "$IRD_TREE/newroot"
98    cp "$BB" "$IRD_TREE/bin/busybox"; "$BB" chmod 0755 "$IRD_TREE/bin/busybox"
99    for a in sh mount umount findfs switch_root mkdir echo sleep; do "$BB" ln -sf busybox "$IRD_TREE/bin/$a"; done
100    cat > "$IRD_TREE/init" <<'INIT'
101#!/bin/busybox sh
102export PATH=/bin
103mount -t proc     proc /proc 2>/dev/null || true
104mount -t sysfs    sys  /sys  2>/dev/null || true
105mount -t devtmpfs dev  /dev  2>/dev/null || true
106log() { echo "$*"; echo "$*" > /dev/ttyS0 2>/dev/null || true; }
107log "HAMMER-EFI: initramfs de pivote — resolviendo hammer-root por LABEL"
108ROOTDEV=""
109for _try in 1 2 3 4 5; do
110    ROOTDEV="$(findfs LABEL=hammer-root 2>/dev/null || true)"
111    [ -n "$ROOTDEV" ] && break
112    log "HAMMER-EFI: hammer-root aún no visible, reintento $_try…"; sleep 1
113done
114[ -n "$ROOTDEV" ] || { log "HAMMER-EFI-FALLO: no encuentro LABEL=hammer-root"; exec sh; }
115log "HAMMER-EFI: hammer-root = $ROOTDEV → montando en /newroot"
116mount -t ext4 "$ROOTDEV" /newroot || { log "HAMMER-EFI-FALLO: no pude montar $ROOTDEV"; exec sh; }
117STOREDEV="$(findfs LABEL=hammer-store 2>/dev/null || true)"
118STATEDEV="$(findfs LABEL=hammer-state 2>/dev/null || true)"
119[ -n "$STOREDEV" ] && mount -t ext4 "$STOREDEV" /newroot/store          2>/dev/null || true
120[ -n "$STATEDEV" ] && mount -t ext4 "$STATEDEV" /newroot/var/lib/hammer  2>/dev/null || true
121log "HAMMER-EFI-DISK-PIVOT-OK: switch_root → /sbin/init"
122exec switch_root /newroot /sbin/init
123INIT
124    "$BB" chmod +x "$IRD_TREE/init"
125    ( cd "$IRD_TREE" && "$BB" find . | "$BB" cpio -o -H newc 2>/dev/null | "$BB" gzip -1 ) > /run/hammer-efi-ird.cpio.gz
126
127    # Poblar la ESP (FAT32, montable por el live): BOOTX64.EFI = bzImage metal + el initramfs de pivote.
128    echo "==> poblando la ESP (\\EFI\\BOOT\\BOOTX64.EFI = kernel metal + \\initramfs.cpio.gz)"
129    ESPMNT=/run/hammer-esp
130    "$BB" mkdir -p "$ESPMNT"
131    "$BB" mount -t vfat "$P1" "$ESPMNT"
132    "$BB" mkdir -p "$ESPMNT/EFI/BOOT"
133    cp "$PAYLOAD/kernel/bzImage-efi" "$ESPMNT/EFI/BOOT/BOOTX64.EFI"
134    cp /run/hammer-efi-ird.cpio.gz   "$ESPMNT/initramfs.cpio.gz"
135    "$BB" sync; "$BB" umount "$ESPMNT"
136
137    # Poblar la root (copia del live) — sin wrapper que monte particiones (el pivote ya montó store/estado).
138    echo "==> copiando la raíz del live → $P2 (excluye virtuales/efímeros, /store, /var/lib/hammer, payload)"
139    MNT=/run/hammer-install
140    "$BB" mkdir -p "$MNT"
141    "$BB" mount -t ext4 "$P2" "$MNT"
142    for entry in /* /.[!.]*; do
143        [ -e "$entry" ] || continue
144        name="${entry##*/}"
145        case "$name" in
146            proc|sys|dev|run|tmp|store|init) continue ;;
147            *) cp -a "$entry" "$MNT/" 2>/dev/null || true ;;
148        esac
149    done
150    "$BB" rm -rf "$MNT/var/lib/hammer" 2>/dev/null || true
151    "$BB" rm -rf "$MNT/usr/lib/hammer/install" 2>/dev/null || true
152    "$BB" mkdir -p "$MNT/store" "$MNT/var/lib/hammer" "$MNT/proc" "$MNT/sys" "$MNT/dev" "$MNT/run" "$MNT/tmp"
153    # /sbin/init: wrapper que auto-sana un upgrade interrumpido y arranca arje-zero (el pivote ya montó
154    # store/estado por LABEL, así que acá NO hace falta montar nada — sólo hammer-recover + exec).
155    if [ -x "$PAYLOAD/hammer-recover" ]; then
156        "$BB" mkdir -p "$MNT/usr/sbin"
157        cp "$PAYLOAD/hammer-recover" "$MNT/usr/sbin/hammer-recover"; "$BB" chmod 0755 "$MNT/usr/sbin/hammer-recover"
158    fi
159    "$BB" rm -f "$MNT/sbin/init"
160    cat > "$MNT/sbin/init" <<'INIT'
161#!/bin/sh
162# Wrapper PID1 (rama UEFI): el initramfs de pivote ya montó / /store /var/lib/hammer por LABEL antes del
163# switch_root; sólo auto-sanamos un upgrade interrumpido y arrancamos el init real. El marcador a
164# /dev/ttyS0 sobrevive `quiet` (que suprime el printk kernel-side) ⇒ prueba serie de que llegó a PID1.
165# busybox switch_root NO mueve /dev ⇒ montamos devtmpfs antes (si no, /dev/ttyS0 aún no existe).
166/bin/busybox mount -t devtmpfs dev /dev 2>/dev/null || true
167echo "HAMMER-EFI-INIT-OK: arje-zero PID1" > /dev/ttyS0 2>/dev/null || true
168[ -x /usr/sbin/hammer-recover ] && /usr/sbin/hammer-recover || true
169exec /usr/bin/arje-zero
170INIT
171    "$BB" chmod +x "$MNT/sbin/init"
172    "$BB" sync
173    "$BB" umount "$MNT"
174
175    echo "✓ hammer-install (UEFI): $DEV instalado con EFI-stub SOBERANO (sin GRUB ni systemd-boot). Reiniciá sin el medio live."
176    exit 0
177fi
178
179# ===================== rama BIOS (MBR + GRUB) — el firmware NO es UEFI ==============================
180[ -r "$PAYLOAD/grub/boot.img" ] && [ -r "$PAYLOAD/grub/core.img" ] || { echo "hammer-install: payload GRUB incompleto" >&2; exit 1; }
181[ -r "$PAYLOAD/kernel/bzImage" ] || { echo "hammer-install: falta el kernel en el payload" >&2; exit 1; }
182
183echo "==> hammer-install: instalando el sistema live en $DEV (root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
184echo "    ¡esto BORRA $DEV!"
185
186# --- particionar MBR con busybox fdisk (3 primarias; p1 bootable) ---
187# Pasamos sectores de inicio/fin EXPLÍCITOS para las tres: busybox fdisk, al pedir el inicio por
188# defecto, ofrece el sector LIBRE MÁS BAJO (= el hueco 63..2047 que dejamos antes de p1) ⇒ con <enter>
189# colocaría p2 en ese hueco. Por eso computamos los sectores y los tecleamos.
190#   p1 ARRANCA EN 2048 (1 MiB) A PROPÓSITO: deja un hueco post-MBR de 2047 sectores para el core.img de
191#   GRUB (~281 sectores). El default CHS de busybox (sector 63 ⇒ hueco de 62) lo DESBORDA, pisando el
192#   filesystem de p1 ⇒ GRUB cae a `grub>`.
193SPM=2048
194P1S=2048;                  P1E=$(( P1S + ROOT_MB  * SPM - 1 ))
195P2S=$(( P1E + 1 ));        P2E=$(( P2S + STORE_MB * SPM - 1 ))
196P3S=$(( P2E + 1 ))         # p3 toma hasta el final del disco (último sector = default)
197echo "==> particionando $DEV (MBR: p1 ${P1S}-${P1E}, p2 ${P2S}-${P2E}, p3 ${P3S}-fin)"
198"$BB" fdisk "$DEV" >/dev/null 2>&1 <<FDISK || true
199o
200n
201p
2021
203$P1S
204$P1E
205n
206p
2072
208$P2S
209$P2E
210n
211p
2123
213$P3S
214
215a
2161
217w
218FDISK
219"$BB" partprobe "$DEV" 2>/dev/null || true
220"$BB" sync; sleep 1
221
222P1="${DEV}1"; P2="${DEV}2"; P3="${DEV}3"
223for p in "$P1" "$P2" "$P3"; do
224    [ -b "$p" ] || { echo "hammer-install: no apareció la partición $p tras particionar" >&2; exit 1; }
225done
226
227# --- formatear (busybox mke2fs = ext2; el driver ext4 del kernel lo monta) ---
228echo "==> formateando particiones (ext2, montables como ext4)"
229"$BB" mke2fs -F -L hammer-root  "$P1" >/dev/null 2>&1
230"$BB" mke2fs -F -L hammer-store "$P2" >/dev/null 2>&1
231"$BB" mke2fs -F -L hammer-state "$P3" >/dev/null 2>&1
232
233# --- copiar la raíz del live a la partición root, excluyendo virtuales + el payload ---
234MNT=/run/hammer-install
235"$BB" mkdir -p "$MNT"
236"$BB" mount -t ext4 "$P1" "$MNT"
237echo "==> copiando la raíz del live → $P1 (excluye virtuales/efímeros, /store, /var/lib/hammer y el payload)"
238# Enumeramos TODO el top-level de / y copiamos salvo lo virtual/efímero — así no se nos escapa ningún
239# dir del producto (p.ej. /ente con la seed.card, /linuxrc). uutils cp -a preserva modos/symlinks.
240for entry in /* /.[!.]*; do
241    [ -e "$entry" ] || continue
242    name="${entry##*/}"
243    case "$name" in
244        proc|sys|dev|run|tmp|store|init) continue ;;  # virtuales/efímeros + el /init marcador del live
245        *) cp -a "$entry" "$MNT/" 2>/dev/null || true ;;
246    esac
247done
248# /var sin /var/lib/hammer (estado) — se recrea vacío como mountpoint.
249"$BB" rm -rf "$MNT/var/lib/hammer" 2>/dev/null || true
250# Quitar el payload del disco instalado (sólo sirve en el live) y recrear mountpoints.
251"$BB" rm -rf "$MNT/usr/lib/hammer/install" 2>/dev/null || true
252"$BB" mkdir -p "$MNT/store" "$MNT/var/lib/hammer" "$MNT/proc" "$MNT/sys" "$MNT/dev" "$MNT/run" "$MNT/tmp" "$MNT/boot/grub/i386-pc"
253
254# --- /boot: kernel + módulos GRUB + grub.cfg, y wrapper /sbin/init (monta las particiones dedicadas) ---
255echo "==> poblando /boot (kernel + GRUB) y wrapper /sbin/init"
256cp "$PAYLOAD/kernel/bzImage" "$MNT/boot/bzImage"; "$BB" chmod 0644 "$MNT/boot/bzImage"
257cp "$PAYLOAD"/grub/i386-pc/*.mod "$MNT/boot/grub/i386-pc/" 2>/dev/null || true
258cp "$PAYLOAD"/grub/i386-pc/*.lst "$MNT/boot/grub/i386-pc/" 2>/dev/null || true
259ROOTDEV="${P1##*/}"   # p.ej. vda1 cuando el disco instalado sea el único
260cat > "$MNT/boot/grub/grub.cfg" <<CFG
261set timeout=2
262set default=0
263serial --unit=0 --speed=115200
264terminal_input serial console
265terminal_output serial console
266insmod part_msdos
267insmod ext2
268menuentry "hammer" {
269    linux /boot/bzImage console=ttyS0 root=/dev/vda1 rw rdinit=/sbin/init
270}
271CFG
272# hammer-recover: auto-sana un upgrade interrumpido al arranque (E4 #4b). Lo dejamos en /usr/sbin del
273# disco; el wrapper lo corre tras montar /store y /var/lib/hammer (que necesita) y antes de incarnar.
274if [ -x "$PAYLOAD/hammer-recover" ]; then
275    "$BB" mkdir -p "$MNT/usr/sbin"
276    cp "$PAYLOAD/hammer-recover" "$MNT/usr/sbin/hammer-recover"; "$BB" chmod 0755 "$MNT/usr/sbin/hammer-recover"
277fi
278"$BB" rm -f "$MNT/sbin/init"
279cat > "$MNT/sbin/init" <<'INIT'
280#!/bin/sh
281# Wrapper PID1: el kernel monta la partición root; montamos las dedicadas, auto-sanamos un upgrade
282# interrumpido (si lo hay) y arrancamos el init real.
283/bin/busybox mount -t ext4 /dev/vda2 /store          || echo "init: no pude montar /store (/dev/vda2)"
284/bin/busybox mount -t ext4 /dev/vda3 /var/lib/hammer  || echo "init: no pude montar /var/lib/hammer (/dev/vda3)"
285[ -x /usr/sbin/hammer-recover ] && /usr/sbin/hammer-recover || true
286exec /usr/bin/arje-zero
287INIT
288"$BB" chmod +x "$MNT/sbin/init"
289"$BB" sync
290"$BB" umount "$MNT"
291
292# --- instalar GRUB: boot.img→MBR (440 B, sin pisar la tabla de particiones) + core.img→hueco post-MBR.
293#     Con install contiguo MBR los punteros por defecto de GRUB (kernel_sector=1, blocklist=2) ya valen
294#     ⇒ NO hace falta el parcheo binario que sí pide el caso GPT de install-image.sh.
295echo "==> instalando GRUB (boot.img→MBR + core.img→hueco post-MBR)"
296"$BB" dd if="$PAYLOAD/grub/boot.img"  of="$DEV" bs=1 count=440 conv=notrunc 2>/dev/null
297"$BB" dd if="$PAYLOAD/grub/core.img"  of="$DEV" bs=512 seek=1 conv=notrunc 2>/dev/null
298"$BB" sync
299
300echo "✓ hammer-install: $DEV instalado. Reiniciá sin el medio live para arrancar del disco."