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.
554 lines
25 KiB
Bash
Executable File
554 lines
25 KiB
Bash
Executable File
#!/bin/sh
|
|
# takana-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/<dev>1 / ext2(montable ext4) + /boot/bzImage + /boot/grub + wrapper /sbin/init
|
|
# /dev/<dev>2 /store ext2
|
|
# /dev/<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/<dev>1 → wrapper /sbin/init.
|
|
#
|
|
# Modo de uso:
|
|
# INTERACTIVO (sin argumentos, con TTY): takana-install
|
|
# TUI en busybox sh: detecta discos, el usuario elige destino + confirma el borrado, recoge
|
|
# hostname / credencial de root / zona horaria / teclado / tamaños de partición, y recién ahí
|
|
# particiona+instala. Es la cara humana del instalador (el /init del ISO installer lo lanza).
|
|
# DESATENDIDO (con device): takana-install /dev/vdb [ROOT_MB] [STORE_MB]
|
|
# Autoinstalador (lo usa iso-install-test.sh con AUTO_INSTALL). La config sale de env:
|
|
# TAKANA_HOSTNAME / TAKANA_ROOT_PW / TAKANA_ROOT_AUTHKEYS / TAKANA_TZ / TAKANA_KEYMAP.
|
|
# Los nombres viejos HAMMER_* se siguen aceptando (ADR 0016); gana el nuevo si están los dos.
|
|
set -eu
|
|
|
|
DEV="${1:-}"
|
|
ROOT_MB="${2:-}"
|
|
STORE_MB="${3:-}" # /var/lib/hammer toma el resto
|
|
PAYLOAD=/usr/lib/hammer/install
|
|
BB="${BB:-/bin/busybox}"
|
|
SYS_BLOCK="${SYS_BLOCK:-/sys/block}" # override para tests
|
|
MOUNTS="${MOUNTS:-/proc/mounts}" # override para tests
|
|
|
|
# bb: usa el busybox del live si existe; si no (p.ej. tests en el host), cae a las herramientas del PATH.
|
|
# Sólo lo usan las funciones NUEVAS (config/TUI). Las ramas EFI/BIOS validadas siguen con "$BB" literal
|
|
# y jamás corren en el host (el dry-run sale antes).
|
|
bb() { if [ -x "$BB" ]; then "$BB" "$@"; else "$@"; fi; }
|
|
|
|
_human() { # bytes → humano
|
|
_b="$1"
|
|
if [ "$_b" -ge 1073741824 ]; then printf '%s.%s GiB' "$((_b/1073741824))" "$(( (_b%1073741824)*10/1073741824 ))"
|
|
elif [ "$_b" -ge 1048576 ]; then printf '%s MiB' "$((_b/1048576))"
|
|
else printf '%s B' "$_b"; fi
|
|
}
|
|
|
|
_is_mounted() { # ¿alguna partición del disco $1 aparece en MOUNTS? (heurística "es el medio live")
|
|
_d="$1"
|
|
while read -r _src _rest; do
|
|
case "$_src" in "/dev/$_d"|"/dev/$_d"[0-9]*|"/dev/$_d"p[0-9]*) return 0 ;; esac
|
|
done < "$MOUNTS" 2>/dev/null
|
|
return 1
|
|
}
|
|
|
|
list_disks() { # emite por disco candidato: name<TAB>bytes<TAB>model<TAB>mounted(0|1)
|
|
for _p in "$SYS_BLOCK"/*; do
|
|
[ -d "$_p" ] || continue
|
|
_n=${_p##*/}
|
|
case "$_n" in loop*|ram*|sr*|fd*|dm-*|md*|zram*) continue ;; esac
|
|
[ -r "$_p/size" ] || continue
|
|
_sz=$(cat "$_p/size" 2>/dev/null || echo 0); [ "$_sz" -gt 0 ] || continue
|
|
_model=$(cat "$_p/device/model" 2>/dev/null | tr -d '\n'); _model=$(printf '%s' "$_model" | sed 's/[[:space:]]*$//')
|
|
_m=0; _is_mounted "$_n" && _m=1
|
|
printf '%s\t%s\t%s\t%s\n' "$_n" "$((_sz*512))" "${_model:-disco}" "$_m"
|
|
done
|
|
}
|
|
|
|
ask() { # ask VAR "prompt" "default"
|
|
if [ -n "$3" ]; then printf '%s [%s]: ' "$2" "$3"; else printf '%s: ' "$2"; fi
|
|
IFS= read -r _ans || _ans=""
|
|
[ -n "$_ans" ] || _ans="$3"
|
|
eval "$1=\$_ans"
|
|
}
|
|
|
|
read_secret() { # read_secret VAR "prompt" (sin eco si hay stty)
|
|
printf '%s: ' "$2"
|
|
bb stty -echo 2>/dev/null || true
|
|
IFS= read -r _sec || _sec=""
|
|
bb stty echo 2>/dev/null || true
|
|
echo
|
|
eval "$1=\$_sec"
|
|
}
|
|
|
|
have_cryptpw() { bb 2>&1 | grep -qw cryptpw; }
|
|
|
|
# Reescribe el campo de contraseña de un usuario en $mnt/etc/shadow (o crea el fichero).
|
|
_set_shadow() {
|
|
_u="$1"; _h="$2"; _f="$3/etc/shadow"
|
|
if [ ! -f "$_f" ]; then
|
|
bb mkdir -p "$3/etc"
|
|
printf '%s:%s:19000:0:99999:7:::\n' "$_u" "$_h" > "$_f"; bb chmod 600 "$_f"; return
|
|
fi
|
|
_t="$_f.hammer-tmp"
|
|
bb awk -F: -v u="$_u" -v h="$_h" 'BEGIN{OFS=":"}
|
|
{ if ($1==u){ $2=h; seen=1 } print }
|
|
END{ if(!seen) print u,h,"19000","0","99999","7","","","" }' "$_f" > "$_t" && bb mv "$_t" "$_f"
|
|
bb chmod 600 "$_f"
|
|
}
|
|
|
|
# Aplica la config recogida al rootfs YA copiado y montado en $1 (llamada por ambas ramas tras la copia).
|
|
apply_post_install_config() {
|
|
_mnt="$1"
|
|
bb mkdir -p "$_mnt/etc/hammer"
|
|
if [ -n "${CFG_HOSTNAME:-}" ]; then
|
|
printf '%s\n' "$CFG_HOSTNAME" > "$_mnt/etc/hostname"
|
|
if ! grep -q "[[:space:]]$CFG_HOSTNAME\$" "$_mnt/etc/hosts" 2>/dev/null; then
|
|
printf '127.0.0.1\tlocalhost %s\n::1\t\tlocalhost %s\n' "$CFG_HOSTNAME" "$CFG_HOSTNAME" >> "$_mnt/etc/hosts"
|
|
fi
|
|
fi
|
|
if [ -n "${CFG_ROOT_HASH:-}" ]; then _set_shadow root "$CFG_ROOT_HASH" "$_mnt"; fi
|
|
if [ -n "${CFG_ROOT_AUTHKEYS:-}" ]; then
|
|
bb mkdir -p "$_mnt/root/.ssh"; bb chmod 700 "$_mnt/root/.ssh"
|
|
printf '%s\n' "$CFG_ROOT_AUTHKEYS" >> "$_mnt/root/.ssh/authorized_keys"
|
|
bb chmod 600 "$_mnt/root/.ssh/authorized_keys"
|
|
fi
|
|
if [ -n "${CFG_TZ:-}" ] && [ -e "$_mnt/usr/share/zoneinfo/$CFG_TZ" ]; then
|
|
bb ln -sf "/usr/share/zoneinfo/$CFG_TZ" "$_mnt/etc/localtime"
|
|
printf '%s\n' "$CFG_TZ" > "$_mnt/etc/timezone"
|
|
fi
|
|
_ts=$(bb date -u +%FT%TZ 2>/dev/null || echo unknown)
|
|
{
|
|
echo "# escrito por hammer-install en $_ts"
|
|
echo "HOSTNAME=${CFG_HOSTNAME:-}"
|
|
echo "TIMEZONE=${CFG_TZ:-}"
|
|
echo "KEYMAP=${CFG_KEYMAP:-}" # best-effort: el producto aún no trae kbd/loadkeys
|
|
echo "TARGET=${DEV:-}"
|
|
} > "$_mnt/etc/hammer/install.conf"
|
|
}
|
|
|
|
# ---- recolección de config: interactiva (TUI) o desde env (desatendido) ----
|
|
CFG_HOSTNAME="${TAKANA_HOSTNAME:-${HAMMER_HOSTNAME:-takana}}"
|
|
CFG_ROOT_AUTHKEYS="${TAKANA_ROOT_AUTHKEYS:-${HAMMER_ROOT_AUTHKEYS:-}}"
|
|
CFG_ROOT_HASH="${TAKANA_ROOT_HASH:-${HAMMER_ROOT_HASH:-}}"
|
|
CFG_TZ="${TAKANA_TZ:-${HAMMER_TZ:-}}"
|
|
CFG_KEYMAP="${TAKANA_KEYMAP:-${HAMMER_KEYMAP:-us}}"
|
|
|
|
interactive_setup() {
|
|
echo
|
|
echo " # instalador de hammer"
|
|
echo " ─────────────────────────"
|
|
echo
|
|
_disks=$(list_disks)
|
|
[ -n "$_disks" ] || { echo "No detecté discos instalables (¿el medio live es el único dispositivo?)."; exit 1; }
|
|
echo "Discos detectados:"
|
|
OLDIFS=$IFS; IFS='
|
|
'; set --
|
|
for _l in $_disks; do set -- "$@" "$_l"; done
|
|
IFS=$OLDIFS
|
|
_i=1
|
|
for _l in "$@"; do
|
|
_n=$(printf '%s' "$_l" | cut -f1); _by=$(printf '%s' "$_l" | cut -f2)
|
|
_mo=$(printf '%s' "$_l" | cut -f3); _mm=$(printf '%s' "$_l" | cut -f4)
|
|
_w=""; [ "$_mm" = 1 ] && _w=" ⚠ montado (¿medio live?)"
|
|
printf ' %s) /dev/%-8s %10s %s%s\n' "$_i" "$_n" "$(_human "$_by")" "$_mo" "$_w"
|
|
_i=$((_i+1))
|
|
done
|
|
_total=$#
|
|
while :; do
|
|
ask _sel "Disco destino (1-$_total)" ""
|
|
case "$_sel" in ''|*[!0-9]*) echo " número inválido"; continue ;; esac
|
|
[ "$_sel" -ge 1 ] && [ "$_sel" -le "$_total" ] && break
|
|
echo " fuera de rango"
|
|
done
|
|
eval "_line=\${$_sel}"
|
|
_name=$(printf '%s' "$_line" | cut -f1); _bytes=$(printf '%s' "$_line" | cut -f2)
|
|
DEV="/dev/$_name"
|
|
_disk_mb=$((_bytes/1048576))
|
|
|
|
# --- tamaños de partición ---
|
|
_esp=64; _slack=16; _avail=$((_disk_mb - _esp - _slack))
|
|
[ "$_avail" -ge 600 ] || { echo "Disco demasiado chico ($(_human "$_bytes")); se necesitan ~700 MiB."; exit 1; }
|
|
_defr=4096; [ "$_defr" -gt $((_avail*6/10)) ] && _defr=$((_avail*6/10))
|
|
_defs=1024; [ "$_defs" -gt $((_avail/5)) ] && _defs=$((_avail/5))
|
|
while :; do
|
|
ask ROOT_MB "Tamaño de / en MB" "$_defr"
|
|
ask STORE_MB "Tamaño de /store en MB" "$_defs"
|
|
case "$ROOT_MB$STORE_MB" in *[!0-9]*) echo " usá sólo números"; continue ;; esac
|
|
if [ $((ROOT_MB + STORE_MB + _esp + _slack)) -le "$_disk_mb" ]; then break; fi
|
|
echo " no entra en el disco ($_disk_mb MiB) — / + /store + ESP deben sumar menos"
|
|
done
|
|
|
|
# --- identidad ---
|
|
ask CFG_HOSTNAME "Hostname" "${CFG_HOSTNAME:-hammer}"
|
|
echo "Credencial de root:"
|
|
echo " 1) contraseña"
|
|
echo " 2) clave SSH (authorized_keys)"
|
|
echo " 3) omitir"
|
|
ask _cred "Opción" "1"
|
|
case "$_cred" in
|
|
1) if have_cryptpw; then
|
|
while :; do
|
|
read_secret _pw1 "Contraseña de root"
|
|
read_secret _pw2 "Repetir"
|
|
[ "$_pw1" = "$_pw2" ] && [ -n "$_pw1" ] && break
|
|
echo " no coinciden (o vacía) — reintentá"
|
|
done
|
|
CFG_ROOT_HASH=$(printf '%s' "$_pw1" | bb cryptpw -m sha512 2>/dev/null || true)
|
|
[ -n "$CFG_ROOT_HASH" ] || echo " ⚠ no pude generar el hash; root queda como está"
|
|
else
|
|
echo " (cryptpw no disponible en este busybox — usá la opción de clave SSH)"
|
|
ask CFG_ROOT_AUTHKEYS "Pegá una línea authorized_keys" ""
|
|
fi ;;
|
|
2) ask CFG_ROOT_AUTHKEYS "Pegá una línea authorized_keys (o ruta a un fichero .pub)" ""
|
|
if [ -n "$CFG_ROOT_AUTHKEYS" ] && [ -f "$CFG_ROOT_AUTHKEYS" ]; then
|
|
CFG_ROOT_AUTHKEYS=$(cat "$CFG_ROOT_AUTHKEYS")
|
|
fi ;;
|
|
*) echo " (root sin credencial nueva)" ;;
|
|
esac
|
|
|
|
# --- locale (best-effort) ---
|
|
_zi="${ZONEINFO:-/usr/share/zoneinfo}"
|
|
if [ -d "$_zi" ]; then
|
|
ask CFG_TZ "Zona horaria (ej. America/La_Paz; vacío = UTC)" "${CFG_TZ:-}"
|
|
if [ -n "$CFG_TZ" ] && [ ! -e "$_zi/$CFG_TZ" ]; then
|
|
echo " ⚠ zona desconocida, se ignora"; CFG_TZ=""
|
|
fi
|
|
else
|
|
echo "(tzdata no instalado — la zona horaria se omite)"; CFG_TZ=""
|
|
fi
|
|
ask CFG_KEYMAP "Layout de teclado" "${CFG_KEYMAP:-us}"
|
|
|
|
# --- resumen + confirmación fuerte ---
|
|
_cd="sin cambios"; [ -n "$CFG_ROOT_HASH" ] && _cd="contraseña"; [ -n "$CFG_ROOT_AUTHKEYS" ] && _cd="clave SSH"
|
|
echo
|
|
echo "Resumen de instalación:"
|
|
echo " destino : $DEV ($(_human "$_bytes"))"
|
|
echo " / = ${ROOT_MB} MiB /store = ${STORE_MB} MiB /var/lib/hammer = resto"
|
|
echo " hostname: $CFG_HOSTNAME"
|
|
echo " root : $_cd"
|
|
echo " zona : ${CFG_TZ:-UTC} teclado: $CFG_KEYMAP"
|
|
echo
|
|
echo " ⚠ ESTO BORRA TODO EN $DEV."
|
|
ask _ok "Escribí el nombre del disco ($DEV) para confirmar, o Enter para cancelar" ""
|
|
[ "$_ok" = "$DEV" ] || { echo "Cancelado — no se tocó ningún disco."; exit 1; }
|
|
}
|
|
|
|
# --- resolución del modo: interactivo (sin device + TTY) vs desatendido (device dado) ---
|
|
if [ -z "$DEV" ]; then
|
|
if [ -t 0 ] || [ "${HAMMER_INSTALL_INTERACTIVE:-}" = 1 ]; then
|
|
interactive_setup
|
|
else
|
|
echo "uso: hammer-install <device> [ROOT_MB] [STORE_MB] (o sin args con un TTY para el modo interactivo)" >&2
|
|
exit 2
|
|
fi
|
|
fi
|
|
ROOT_MB="${ROOT_MB:-1500}"
|
|
STORE_MB="${STORE_MB:-400}"
|
|
# En modo desatendido con contraseña por env, derivar el hash acá (interactivo ya lo hizo).
|
|
if [ -z "$CFG_ROOT_HASH" ] && [ -n "${TAKANA_ROOT_PW:-${HAMMER_ROOT_PW:-}}" ] && have_cryptpw; then
|
|
CFG_ROOT_HASH=$(printf '%s' "${TAKANA_ROOT_PW:-$HAMMER_ROOT_PW}" | bb cryptpw -m sha512 2>/dev/null || true)
|
|
fi
|
|
|
|
# --- gancho de prueba: valida TUI + config sin tocar disco (HAMMER_INSTALL_DRYRUN=1) ---
|
|
if [ "${HAMMER_INSTALL_DRYRUN:-}" = 1 ]; then
|
|
echo "== DRYRUN: plan de instalación =="
|
|
echo " DEV=$DEV ROOT_MB=$ROOT_MB STORE_MB=$STORE_MB"
|
|
echo " HOSTNAME=$CFG_HOSTNAME TZ=${CFG_TZ:-UTC} KEYMAP=$CFG_KEYMAP"
|
|
echo " ROOT_HASH=$([ -n "$CFG_ROOT_HASH" ] && echo set || echo -) AUTHKEYS=$([ -n "$CFG_ROOT_AUTHKEYS" ] && echo set || echo -)"
|
|
if [ -n "${HAMMER_INSTALL_TESTROOT:-}" ]; then
|
|
apply_post_install_config "$HAMMER_INSTALL_TESTROOT"
|
|
echo " config aplicada a $HAMMER_INSTALL_TESTROOT"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
[ -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; }
|
|
|
|
# --- Detección de firmware: UEFI ⇒ rama EFI-stub SOBERANA (ADR 0010 paso 5); BIOS ⇒ MBR+GRUB (abajo) ---
|
|
# La rama EFI usa una ESP tipo 0xEF en tabla MBR (UEFI arranca \EFI\BOOT\BOOTX64.EFI de una ESP MBR igual
|
|
# que de GPT) ⇒ alcanza con busybox fdisk/mkfs.vfat/mount, sin GPT-tool ni mtools. El bzImage metal ES el
|
|
# binario EFI (EFI-stub, cmdline horneada carga el initrd); un initramfs mínimo pivota por LABEL. Mismos
|
|
# artefactos que scripts/install-image-efi.sh (validado en OVMF), armados desde dentro del live.
|
|
if [ -d /sys/firmware/efi ]; then
|
|
[ -r "$PAYLOAD/kernel/bzImage-efi" ] || { echo "hammer-install: live en UEFI pero falta $PAYLOAD/kernel/bzImage-efi (ISO sin kernel metal)" >&2; exit 1; }
|
|
ESP_MB="${ESP_MB:-64}"
|
|
echo "==> hammer-install (UEFI): EFI-stub soberano en $DEV (ESP ${ESP_MB}M, root ${ROOT_MB}M, store ${STORE_MB}M, estado=resto)"
|
|
echo " ¡esto BORRA $DEV!"
|
|
|
|
# MBR, 4 primarias: p1=ESP(0xEF) p2=root p3=store p4=estado. Sectores explícitos (como la rama BIOS).
|
|
SPM=2048
|
|
P1S=2048; P1E=$(( P1S + ESP_MB * SPM - 1 ))
|
|
P2S=$(( P1E + 1 )); P2E=$(( P2S + ROOT_MB * SPM - 1 ))
|
|
P3S=$(( P2E + 1 )); P3E=$(( P3S + STORE_MB* SPM - 1 ))
|
|
P4S=$(( P3E + 1 )) # estado = resto del disco
|
|
echo "==> particionando $DEV (MBR: ESP ${P1S}-${P1E} tipo ef, root ${P2S}-${P2E}, store ${P3S}-${P3E}, estado ${P4S}-fin)"
|
|
"$BB" fdisk "$DEV" >/dev/null 2>&1 <<FDISK || true
|
|
o
|
|
n
|
|
p
|
|
1
|
|
$P1S
|
|
$P1E
|
|
n
|
|
p
|
|
2
|
|
$P2S
|
|
$P2E
|
|
n
|
|
p
|
|
3
|
|
$P3S
|
|
$P3E
|
|
n
|
|
p
|
|
4
|
|
$P4S
|
|
|
|
t
|
|
1
|
|
ef
|
|
a
|
|
1
|
|
w
|
|
FDISK
|
|
"$BB" partprobe "$DEV" 2>/dev/null || true
|
|
"$BB" sync; sleep 1
|
|
P1="${DEV}1"; P2="${DEV}2"; P3="${DEV}3"; P4="${DEV}4"
|
|
for p in "$P1" "$P2" "$P3" "$P4"; do
|
|
[ -b "$p" ] || { echo "hammer-install: no apareció la partición $p tras particionar" >&2; exit 1; }
|
|
done
|
|
|
|
echo "==> formateando (ESP FAT32 + 3 ext2 etiquetadas para el pivote por LABEL)"
|
|
"$BB" mkfs.vfat -F 32 -n HAMMER "$P1" >/dev/null 2>&1
|
|
"$BB" mke2fs -F -L hammer-root "$P2" >/dev/null 2>&1
|
|
"$BB" mke2fs -F -L hammer-store "$P3" >/dev/null 2>&1
|
|
"$BB" mke2fs -F -L hammer-state "$P4" >/dev/null 2>&1
|
|
|
|
# initramfs de pivote (busybox estático del live + /init: findfs LABEL=takana-root → switch_root).
|
|
echo "==> armando el initramfs de pivote (busybox + /init switch_root a hammer-root)"
|
|
IRD_TREE=/run/hammer-efi-ird
|
|
"$BB" rm -rf "$IRD_TREE"
|
|
"$BB" mkdir -p "$IRD_TREE/bin" "$IRD_TREE/dev" "$IRD_TREE/proc" "$IRD_TREE/sys" "$IRD_TREE/newroot"
|
|
cp "$BB" "$IRD_TREE/bin/busybox"; "$BB" chmod 0755 "$IRD_TREE/bin/busybox"
|
|
for a in sh mount umount findfs switch_root mkdir echo sleep; do "$BB" ln -sf busybox "$IRD_TREE/bin/$a"; done
|
|
cat > "$IRD_TREE/init" <<'INIT'
|
|
#!/bin/busybox sh
|
|
export PATH=/bin
|
|
mount -t proc proc /proc 2>/dev/null || true
|
|
mount -t sysfs sys /sys 2>/dev/null || true
|
|
mount -t devtmpfs dev /dev 2>/dev/null || true
|
|
log() { echo "$*"; echo "$*" > /dev/ttyS0 2>/dev/null || true; }
|
|
log "HAMMER-EFI: initramfs de pivote — resolviendo hammer-root por LABEL"
|
|
ROOTDEV=""
|
|
for _try in 1 2 3 4 5; do
|
|
ROOTDEV="$(findfs LABEL=hammer-root 2>/dev/null || true)"
|
|
[ -n "$ROOTDEV" ] && break
|
|
log "HAMMER-EFI: hammer-root aún no visible, reintento $_try…"; sleep 1
|
|
done
|
|
[ -n "$ROOTDEV" ] || { log "HAMMER-EFI-FALLO: no encuentro LABEL=hammer-root"; exec sh; }
|
|
log "HAMMER-EFI: hammer-root = $ROOTDEV → montando en /newroot"
|
|
mount -t ext4 "$ROOTDEV" /newroot || { log "HAMMER-EFI-FALLO: no pude montar $ROOTDEV"; exec sh; }
|
|
STOREDEV="$(findfs LABEL=hammer-store 2>/dev/null || true)"
|
|
STATEDEV="$(findfs LABEL=hammer-state 2>/dev/null || true)"
|
|
[ -n "$STOREDEV" ] && mount -t ext4 "$STOREDEV" /newroot/store 2>/dev/null || true
|
|
[ -n "$STATEDEV" ] && mount -t ext4 "$STATEDEV" /newroot/var/lib/hammer 2>/dev/null || true
|
|
log "HAMMER-EFI-DISK-PIVOT-OK: switch_root → /sbin/init"
|
|
exec switch_root /newroot /sbin/init
|
|
INIT
|
|
"$BB" chmod +x "$IRD_TREE/init"
|
|
( cd "$IRD_TREE" && "$BB" find . | "$BB" cpio -o -H newc 2>/dev/null | "$BB" gzip -1 ) > /run/hammer-efi-ird.cpio.gz
|
|
|
|
# Poblar la ESP (FAT32, montable por el live): BOOTX64.EFI = bzImage metal + el initramfs de pivote.
|
|
echo "==> poblando la ESP (\\EFI\\BOOT\\BOOTX64.EFI = kernel metal + \\initramfs.cpio.gz)"
|
|
ESPMNT=/run/hammer-esp
|
|
"$BB" mkdir -p "$ESPMNT"
|
|
"$BB" mount -t vfat "$P1" "$ESPMNT"
|
|
"$BB" mkdir -p "$ESPMNT/EFI/BOOT"
|
|
cp "$PAYLOAD/kernel/bzImage-efi" "$ESPMNT/EFI/BOOT/BOOTX64.EFI"
|
|
cp /run/hammer-efi-ird.cpio.gz "$ESPMNT/initramfs.cpio.gz"
|
|
"$BB" sync; "$BB" umount "$ESPMNT"
|
|
|
|
# Poblar la root (copia del live) — sin wrapper que monte particiones (el pivote ya montó store/estado).
|
|
echo "==> copiando la raíz del live → $P2 (excluye virtuales/efímeros, /store, /var/lib/hammer, payload)"
|
|
MNT=/run/hammer-install
|
|
"$BB" mkdir -p "$MNT"
|
|
"$BB" mount -t ext4 "$P2" "$MNT"
|
|
for entry in /* /.[!.]*; do
|
|
[ -e "$entry" ] || continue
|
|
name="${entry##*/}"
|
|
case "$name" in
|
|
proc|sys|dev|run|tmp|store|init) continue ;;
|
|
*) cp -a "$entry" "$MNT/" 2>/dev/null || true ;;
|
|
esac
|
|
done
|
|
"$BB" rm -rf "$MNT/var/lib/hammer" 2>/dev/null || true
|
|
"$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"
|
|
# /sbin/init: wrapper que auto-sana un upgrade interrumpido y arranca arje-zero (el pivote ya montó
|
|
# store/estado por LABEL, así que acá NO hace falta montar nada — sólo hammer-recover + exec).
|
|
if [ -x "$PAYLOAD/hammer-recover" ]; then
|
|
"$BB" mkdir -p "$MNT/usr/sbin"
|
|
cp "$PAYLOAD/hammer-recover" "$MNT/usr/sbin/hammer-recover"; "$BB" chmod 0755 "$MNT/usr/sbin/hammer-recover"
|
|
fi
|
|
# CLI takana (static musl) para el menú de arranque por grafo (ADR 0010): lo copia al disco desde el
|
|
# payload; el wrapper lo invoca como `takana boot menu`.
|
|
if [ -x "$PAYLOAD/hammer" ]; then
|
|
cp "$PAYLOAD/hammer" "$MNT/usr/bin/hammer"; "$BB" chmod 0755 "$MNT/usr/bin/hammer"
|
|
fi
|
|
"$BB" rm -f "$MNT/sbin/init"
|
|
cat > "$MNT/sbin/init" <<'INIT'
|
|
#!/bin/sh
|
|
# Wrapper PID1 (rama UEFI): el initramfs de pivote ya montó / /store /var/lib/hammer por LABEL antes del
|
|
# switch_root; sólo auto-sanamos un upgrade interrumpido y arrancamos el init real. El marcador a
|
|
# /dev/ttyS0 sobrevive `quiet` (que suprime el printk kernel-side) ⇒ prueba serie de que llegó a PID1.
|
|
# busybox switch_root NO mueve /dev ⇒ montamos devtmpfs antes (si no, /dev/ttyS0 aún no existe).
|
|
/bin/busybox mount -t devtmpfs dev /dev 2>/dev/null || true
|
|
echo "HAMMER-EFI-INIT-OK: arje-zero PID1" > /dev/ttyS0 2>/dev/null || true
|
|
[ -x /usr/sbin/hammer-recover ] && /usr/sbin/hammer-recover || true
|
|
# Menú de arranque por grafo (ADR 0010): emite /run/hammer/boot-graph.json y, si hay compositor (mirada),
|
|
# lo pinta sobre KMS. Graceful (sin compositor sigue) y al serial (no pinta tty0 ⇒ cero-parpadeo).
|
|
[ -x /usr/bin/hammer ] && /usr/bin/hammer boot menu > /dev/ttyS0 2>&1 || true
|
|
exec /usr/bin/arje-zero
|
|
INIT
|
|
"$BB" chmod +x "$MNT/sbin/init"
|
|
# config del usuario (hostname / root / zona / teclado) recogida al inicio
|
|
apply_post_install_config "$MNT"
|
|
"$BB" sync
|
|
"$BB" umount "$MNT"
|
|
|
|
echo "✓ hammer-install (UEFI): $DEV instalado con EFI-stub SOBERANO (sin GRUB ni systemd-boot). Reiniciá sin el medio live."
|
|
exit 0
|
|
fi
|
|
|
|
# ===================== rama BIOS (MBR + GRUB) — el firmware NO es UEFI ==============================
|
|
[ -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 <enter>
|
|
# 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 <<FDISK || true
|
|
o
|
|
n
|
|
p
|
|
1
|
|
$P1S
|
|
$P1E
|
|
n
|
|
p
|
|
2
|
|
$P2S
|
|
$P2E
|
|
n
|
|
p
|
|
3
|
|
$P3S
|
|
|
|
a
|
|
1
|
|
w
|
|
FDISK
|
|
"$BB" partprobe "$DEV" 2>/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" <<CFG
|
|
set timeout=2
|
|
set default=0
|
|
serial --unit=0 --speed=115200
|
|
terminal_input serial console
|
|
terminal_output serial console
|
|
insmod part_msdos
|
|
insmod ext2
|
|
menuentry "hammer" {
|
|
linux /boot/bzImage console=ttyS0 root=/dev/vda1 rw rdinit=/sbin/init
|
|
}
|
|
CFG
|
|
# hammer-recover: auto-sana un upgrade interrumpido al arranque (E4 #4b). Lo dejamos en /usr/sbin del
|
|
# disco; el wrapper lo corre tras montar /store y /var/lib/hammer (que necesita) y antes de incarnar.
|
|
if [ -x "$PAYLOAD/hammer-recover" ]; then
|
|
"$BB" mkdir -p "$MNT/usr/sbin"
|
|
cp "$PAYLOAD/hammer-recover" "$MNT/usr/sbin/hammer-recover"; "$BB" chmod 0755 "$MNT/usr/sbin/hammer-recover"
|
|
fi
|
|
"$BB" rm -f "$MNT/sbin/init"
|
|
cat > "$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"
|
|
# config del usuario (hostname / root / zona / teclado) recogida al inicio
|
|
apply_post_install_config "$MNT"
|
|
"$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."
|