#!/bin/sh # hammer-install — instalador a disco DESDE el medio live (Etapa E5 / refinamiento #1). # # Se inyecta en el rootfs del producto como /usr/bin/hammer-install (ver scripts/iso-image.sh # INSTALLER=1). Corre DENTRO del live, como root real (arje-zero es PID1) ⇒ NO necesita unshare -r # ni los rodeos rootless de install-image.sh: particiona, formatea, monta y copia con privilegios # reales, usando sólo herramientas que el producto ya trae (busybox fdisk/mke2fs/mount/dd + uutils cp). # # El sistema que se instala es EL PROPIO LIVE: la raíz en RAM se copia al disco (autoinstalador). El # payload de arranque (kernel + GRUB) viaja en /usr/lib/hammer/install/, armado en build-time (el host # tiene grub-mkimage; el live no lo necesita). # # Layout en disco (MBR, no GPT — más simple y busybox-friendly; GRUB va en el hueco post-MBR): # /dev/1 / ext2(montable ext4) + /boot/bzImage + /boot/grub + wrapper /sbin/init # /dev/2 /store ext2 # /dev/3 /var/lib/hammer ext2 # # Cadena de arranque del disco resultante: BIOS → MBR (boot.img) → core.img (hueco post-MBR) → # (hd0,msdos1)/boot/grub/grub.cfg → linux /boot/bzImage root=/dev/1 → wrapper /sbin/init. # # Uso (en el live): hammer-install /dev/vdb [ROOT_MB] [STORE_MB] set -eu DEV="${1:-/dev/vdb}" ROOT_MB="${2:-1500}" STORE_MB="${3:-400}" # /var/lib/hammer toma el resto PAYLOAD=/usr/lib/hammer/install BB=/bin/busybox [ -b "$DEV" ] || { echo "hammer-install: $DEV no es un block device" >&2; exit 1; } [ -d "$PAYLOAD" ] || { echo "hammer-install: falta el payload $PAYLOAD (¿ISO sin INSTALLER=1?)" >&2; exit 1; } [ -r "$PAYLOAD/grub/boot.img" ] && [ -r "$PAYLOAD/grub/core.img" ] || { echo "hammer-install: payload GRUB incompleto" >&2; exit 1; } [ -r "$PAYLOAD/kernel/bzImage" ] || { echo "hammer-install: falta el kernel en el payload" >&2; exit 1; } echo "==> hammer-install: instalando el sistema live en $DEV (root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)" echo " ¡esto BORRA $DEV!" # --- particionar MBR con busybox fdisk (3 primarias; p1 bootable) --- # Pasamos sectores de inicio/fin EXPLÍCITOS para las tres: busybox fdisk, al pedir el inicio por # defecto, ofrece el sector LIBRE MÁS BAJO (= el hueco 63..2047 que dejamos antes de p1) ⇒ con # colocaría p2 en ese hueco. Por eso computamos los sectores y los tecleamos. # p1 ARRANCA EN 2048 (1 MiB) A PROPÓSITO: deja un hueco post-MBR de 2047 sectores para el core.img de # GRUB (~281 sectores). El default CHS de busybox (sector 63 ⇒ hueco de 62) lo DESBORDA, pisando el # filesystem de p1 ⇒ GRUB cae a `grub>`. SPM=2048 P1S=2048; P1E=$(( P1S + ROOT_MB * SPM - 1 )) P2S=$(( P1E + 1 )); P2E=$(( P2S + STORE_MB * SPM - 1 )) P3S=$(( P2E + 1 )) # p3 toma hasta el final del disco (último sector = default) echo "==> particionando $DEV (MBR: p1 ${P1S}-${P1E}, p2 ${P2S}-${P2E}, p3 ${P3S}-fin)" "$BB" fdisk "$DEV" >/dev/null 2>&1 </dev/null || true "$BB" sync; sleep 1 P1="${DEV}1"; P2="${DEV}2"; P3="${DEV}3" for p in "$P1" "$P2" "$P3"; do [ -b "$p" ] || { echo "hammer-install: no apareció la partición $p tras particionar" >&2; exit 1; } done # --- formatear (busybox mke2fs = ext2; el driver ext4 del kernel lo monta) --- echo "==> formateando particiones (ext2, montables como ext4)" "$BB" mke2fs -F -L hammer-root "$P1" >/dev/null 2>&1 "$BB" mke2fs -F -L hammer-store "$P2" >/dev/null 2>&1 "$BB" mke2fs -F -L hammer-state "$P3" >/dev/null 2>&1 # --- copiar la raíz del live a la partición root, excluyendo virtuales + el payload --- MNT=/run/hammer-install "$BB" mkdir -p "$MNT" "$BB" mount -t ext4 "$P1" "$MNT" echo "==> copiando la raíz del live → $P1 (excluye virtuales/efímeros, /store, /var/lib/hammer y el payload)" # Enumeramos TODO el top-level de / y copiamos salvo lo virtual/efímero — así no se nos escapa ningún # dir del producto (p.ej. /ente con la seed.card, /linuxrc). uutils cp -a preserva modos/symlinks. for entry in /* /.[!.]*; do [ -e "$entry" ] || continue name="${entry##*/}" case "$name" in proc|sys|dev|run|tmp|store|init) continue ;; # virtuales/efímeros + el /init marcador del live *) cp -a "$entry" "$MNT/" 2>/dev/null || true ;; esac done # /var sin /var/lib/hammer (estado) — se recrea vacío como mountpoint. "$BB" rm -rf "$MNT/var/lib/hammer" 2>/dev/null || true # Quitar el payload del disco instalado (sólo sirve en el live) y recrear mountpoints. "$BB" rm -rf "$MNT/usr/lib/hammer/install" 2>/dev/null || true "$BB" mkdir -p "$MNT/store" "$MNT/var/lib/hammer" "$MNT/proc" "$MNT/sys" "$MNT/dev" "$MNT/run" "$MNT/tmp" "$MNT/boot/grub/i386-pc" # --- /boot: kernel + módulos GRUB + grub.cfg, y wrapper /sbin/init (monta las particiones dedicadas) --- echo "==> poblando /boot (kernel + GRUB) y wrapper /sbin/init" cp "$PAYLOAD/kernel/bzImage" "$MNT/boot/bzImage"; "$BB" chmod 0644 "$MNT/boot/bzImage" cp "$PAYLOAD"/grub/i386-pc/*.mod "$MNT/boot/grub/i386-pc/" 2>/dev/null || true cp "$PAYLOAD"/grub/i386-pc/*.lst "$MNT/boot/grub/i386-pc/" 2>/dev/null || true ROOTDEV="${P1##*/}" # p.ej. vda1 cuando el disco instalado sea el único cat > "$MNT/boot/grub/grub.cfg" < "$MNT/sbin/init" <<'INIT' #!/bin/sh # Wrapper PID1: el kernel monta la partición root; montamos las dedicadas, auto-sanamos un upgrade # interrumpido (si lo hay) y arrancamos el init real. /bin/busybox mount -t ext4 /dev/vda2 /store || echo "init: no pude montar /store (/dev/vda2)" /bin/busybox mount -t ext4 /dev/vda3 /var/lib/hammer || echo "init: no pude montar /var/lib/hammer (/dev/vda3)" [ -x /usr/sbin/hammer-recover ] && /usr/sbin/hammer-recover || true exec /usr/bin/arje-zero INIT "$BB" chmod +x "$MNT/sbin/init" "$BB" sync "$BB" umount "$MNT" # --- instalar GRUB: boot.img→MBR (440 B, sin pisar la tabla de particiones) + core.img→hueco post-MBR. # Con install contiguo MBR los punteros por defecto de GRUB (kernel_sector=1, blocklist=2) ya valen # ⇒ NO hace falta el parcheo binario que sí pide el caso GPT de install-image.sh. echo "==> instalando GRUB (boot.img→MBR + core.img→hueco post-MBR)" "$BB" dd if="$PAYLOAD/grub/boot.img" of="$DEV" bs=1 count=440 conv=notrunc 2>/dev/null "$BB" dd if="$PAYLOAD/grub/core.img" of="$DEV" bs=512 seek=1 conv=notrunc 2>/dev/null "$BB" sync echo "✓ hammer-install: $DEV instalado. Reiniciá sin el medio live para arrancar del disco."