#!/bin/sh
# instalador-paquete.sh — arma el PAQUETE que se copia a la máquina donde se va a instalar.
#
# ══ POR QUÉ EXISTE ════════════════════════════════════════════════════════════════════════════
# El paquete se armó a mano dos veces y a la segunda ya mentía: por fuera llevaba el
# `takana-install-partition.sh` corregido y por dentro —dentro del initramfs, que es el que de
# verdad corre— el de la víspera. **Un paquete que se arma a mano deriva de sus piezas en silencio**,
# y la parte que deriva es justamente la que nadie mira porque está comprimida.
#
# Acá se arma entero y se COMPRUEBA que lo de adentro y lo de afuera sean el mismo fichero.
#
# ── LAS DOS PIEDRAS DEL HUB, QUE NO SON DE ESTE SCRIPT ─────────────────────────────────────────
# · `install-image-efi.sh` busca el rootfs y el kernel en `store/` —el enlace del clon, que en
# este hub está VACÍO— y no en `/store`, que es donde están. Por eso acá se resuelven y se
# pasan explícitos.
# · el staging ENLAZA desde el rootfs y `linkat()` no cruza un punto de montaje: con el rootfs en
# `/store` y el stage en `/work` sale EXDEV. Se copia el rootfs una vez a este lado.
#
# Uso: scripts/instalador-paquete.sh [--salida
]
# Vars: ROOTFS KERNEL (si se saben) · SALIDA (def work/instalador-salida)
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
SALIDA="${SALIDA:-work/instalador-salida}"
[ "${1:-}" = "--salida" ] && { SALIDA="${2:?}"; shift 2; }
TAKANA="${TAKANA:-$ROOT/target/release/takana}"
[ -x "$TAKANA" ] || { echo "no hay binario en $TAKANA (cargo build --release -p takana-cli)" >&2; exit 1; }
# ── el rootfs y el kernel, resueltos a este lado del montaje ──────────────────────────────────
if [ -z "${ROOTFS:-}" ]; then
_src=$(ls -dt /store/*-product-rootfs store/*-product-rootfs 2>/dev/null | head -1)
[ -n "${_src:-}" ] || { echo "no encuentro ningún product-rootfs (set ROOTFS=)" >&2; exit 1; }
ROOTFS="work/.rootfs-local/$(basename "$_src")"
if [ ! -d "$ROOTFS" ]; then
echo "==> copiando $_src → $ROOTFS (una vez, por EXDEV)"
mkdir -p work/.rootfs-local; cp -a "$_src" "$ROOTFS"
fi
fi
if [ -z "${KERNEL:-}" ]; then
KERNEL=$(ls -dt /store/*-linux-metal/boot/bzImage store/*-linux-metal/boot/bzImage 2>/dev/null | head -1)
[ -n "${KERNEL:-}" ] || { echo "no encuentro un bzImage de linux-metal (set KERNEL=)" >&2; exit 1; }
fi
echo "==> rootfs: $ROOTFS"
echo "==> kernel: $KERNEL"
mkdir -p "$SALIDA/kernel/boot" "$SALIDA/lib"
# ── 1) el instalador en RAM (es lo caro: arma el stage y comprime ~130 M) ──────────────────────
echo "==> initramfs del instalador"
ROOTFS="$ROOTFS" KERNEL="$KERNEL" OUT="$SALIDA/takana-instalador.cpio.gz" ./scripts/instalador-initramfs.sh
# ── 2) lo que va al lado ──────────────────────────────────────────────────────────────────────
# `rm -f` antes de cada `cp`: lo que sale del store viene en modo 0444 y un `cp` encima falla con
# «Permission denied», que en un script de empaquetado se lee como un problema de permisos del
# usuario y no como lo que es — el fichero de la corrida anterior, que es de sólo lectura.
poner() { rm -f "$2"; cp "$1" "$2"; chmod "${3:-0644}" "$2"; }
poner "$TAKANA" "$SALIDA/takana" 0755
poner "$KERNEL" "$SALIDA/kernel/boot/bzImage"
poner scripts/takana-install-partition.sh "$SALIDA/takana-install-partition.sh" 0755
# ── LAS LIBRERÍAS QUE EL INSTALADOR SOURCEA, DERIVADAS DEL PROPIO SCRIPT ──────────────────────────
# Acá había UNA copia a mano (`herramientas-desde-store.sh`) y el script sourcea CUATRO:
# `usuarios-del-home.sh`, `adoptar.sh`, `cuenta.sh` y ésa. Una librería que no viaja no da un error
# claro: el `.` falla y el instalador sigue hasta que llama a la función, ya con el disco en la mano.
# Derivarlas del script es lo que hace que agregar la quinta no exija acordarse de este sitio — la
# lista a mano ya había quedado corta tres veces.
for _lib in $(sed -n 's|^\. "$(dirname "$0")/lib/\([a-z-]*\.sh\)".*|\1|p' scripts/takana-install-partition.sh); do
[ -r "scripts/lib/$_lib" ] || { echo "falta scripts/lib/$_lib, que el instalador sourcea" >&2; exit 1; }
poner "scripts/lib/$_lib" "$SALIDA/lib/$_lib"
done
echo " libs del instalador: $(sed -n 's|^\. "$(dirname "$0")/lib/\([a-z-]*\.sh\)".*|\1|p' scripts/takana-install-partition.sh | tr '\n' ' ')"
# `busybox` viaja suelto en el paquete —2 MiB— y no es redundante: es con lo que se desempaqueta el
# árbol a instalar cuando NO hace falta saltar. El host puede no tener `cpio` ni `gzip` (en las tres
# máquinas de este proyecto no hay `cpio`), así que depender de los del sistema ajeno es depender de
# algo que ya sabemos que falta.
_bb="${IRD_TREE:-work/.instalador-initramfs-tree}/bin/busybox"
[ -r "$_bb" ] || { echo "no encuentro busybox en $_bb" >&2; exit 1; }
poner "$_bb" "$SALIDA/busybox" 0755
# ── 3) la comprobación que justifica este script ──────────────────────────────────────────────
# El censo que el usuario corre ANTES de saltar (`takana metal survey`, el de afuera) y el que
# corre el instalador DESPUÉS del salto (el de adentro del initramfs) tienen que ser el mismo
# fichero. Si divergen, el usuario elige mirando una clasificación y el instalador formatea según
# otra — y el que decide es el de adentro, que es el que nadie miró.
echo "==> coherencia: el censo de afuera y el de adentro"
. "$(dirname "$0")/lib/herramientas-desde-store.sh"
CPIO=$(herramienta libarchive usr/bin/bsdcpio cpio) || exit 1
GZIP=$(herramienta gzip bin/gzip gzip) || exit 1
_tmp="work/.paquete-verif"; rm -rf "$_tmp"; mkdir -p "$_tmp"
( cd "$_tmp" && "$GZIP" -d -c "$ROOT/$SALIDA/takana-instalador.cpio.gz" 2>/dev/null \
| "$CPIO" -i -d --quiet '*takana-install-partition.sh' 2>/dev/null ) || true
# `-d` (crear directorios) no es opcional: sin él bsdcpio contesta «Can't create
# 'instalador/takana-install-partition.sh'» porque el directorio no existe, y con `2>/dev/null`
# eso se ve exactamente igual que un archivo que no trae el fichero.
_dentro="$_tmp/instalador/takana-install-partition.sh"
if [ ! -r "$_dentro" ]; then
echo " ✗ no pude sacar el censo de adentro del initramfs — no puedo afirmar que coincidan" >&2
rm -rf "$_tmp"; exit 1
fi
_a=$(sha256sum "$_dentro" | cut -d' ' -f1)
_b=$(sha256sum scripts/takana-install-partition.sh | cut -d' ' -f1)
rm -rf "$_tmp"
[ "$_a" = "$_b" ] || {
echo " ✗ el censo de adentro del initramfs NO es el del repo ($(echo "$_a"|cut -c1-12) vs $(echo "$_b"|cut -c1-12))" >&2
echo " El instalador decidiría con una clasificación distinta de la que el usuario vio." >&2
exit 1; }
echo " ✓ el mismo fichero adentro y afuera ($(echo "$_a" | cut -c1-12))"
echo
echo "✓ paquete en $SALIDA ($(du -sm "$SALIDA" | cut -f1) MiB)"
ls -l "$SALIDA"
echo
echo "En la máquina donde se instala: sudo ./takana metal check → survey → install"