#!/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"