gioser

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…

TOML 1572Shell 203Rust 109Markdown 993728 Definiciones

⎇ 32627251b1adcc995958bd60e72226040bff6125 scripts/instalador-paquete.sh Shell · 112 líneas · 7.4 KB Historia crudo

fix(instalador): la cuenta de quien va a usar la maquina se pregunta antes de instalar 0f66c9973 · sergio ·

1#!/bin/sh
2# instalador-paquete.sh — arma el PAQUETE que se copia a la máquina donde se va a instalar.
3#
4# ══ POR QUÉ EXISTE ════════════════════════════════════════════════════════════════════════════
5# El paquete se armó a mano dos veces y a la segunda ya mentía: por fuera llevaba el
6# `takana-install-partition.sh` corregido y por dentro —dentro del initramfs, que es el que de
7# verdad corre— el de la víspera. **Un paquete que se arma a mano deriva de sus piezas en silencio**,
8# y la parte que deriva es justamente la que nadie mira porque está comprimida.
9#
10# Acá se arma entero y se COMPRUEBA que lo de adentro y lo de afuera sean el mismo fichero.
11#
12# ── LAS DOS PIEDRAS DEL HUB, QUE NO SON DE ESTE SCRIPT ─────────────────────────────────────────
13#   · `install-image-efi.sh` busca el rootfs y el kernel en `store/` —el enlace del clon, que en
14#     este hub está VACÍO— y no en `/store`, que es donde están. Por eso acá se resuelven y se
15#     pasan explícitos.
16#   · el staging ENLAZA desde el rootfs y `linkat()` no cruza un punto de montaje: con el rootfs en
17#     `/store` y el stage en `/work` sale EXDEV. Se copia el rootfs una vez a este lado.
18#
19# Uso:  scripts/instalador-paquete.sh [--salida <dir>]
20# Vars: ROOTFS KERNEL (si se saben) · SALIDA (def work/instalador-salida)
21set -eu
22ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
23SALIDA="${SALIDA:-work/instalador-salida}"
24[ "${1:-}" = "--salida" ] && { SALIDA="${2:?}"; shift 2; }
25
26TAKANA="${TAKANA:-$ROOT/target/release/takana}"
27[ -x "$TAKANA" ] || { echo "no hay binario en $TAKANA (cargo build --release -p takana-cli)" >&2; exit 1; }
28
29# ── el rootfs y el kernel, resueltos a este lado del montaje ──────────────────────────────────
30if [ -z "${ROOTFS:-}" ]; then
31    _src=$(ls -dt /store/*-product-rootfs store/*-product-rootfs 2>/dev/null | head -1)
32    [ -n "${_src:-}" ] || { echo "no encuentro ningún product-rootfs (set ROOTFS=)" >&2; exit 1; }
33    ROOTFS="work/.rootfs-local/$(basename "$_src")"
34    if [ ! -d "$ROOTFS" ]; then
35        echo "==> copiando $_src → $ROOTFS (una vez, por EXDEV)"
36        mkdir -p work/.rootfs-local; cp -a "$_src" "$ROOTFS"
37    fi
38fi
39if [ -z "${KERNEL:-}" ]; then
40    KERNEL=$(ls -dt /store/*-linux-metal/boot/bzImage store/*-linux-metal/boot/bzImage 2>/dev/null | head -1)
41    [ -n "${KERNEL:-}" ] || { echo "no encuentro un bzImage de linux-metal (set KERNEL=)" >&2; exit 1; }
42fi
43echo "==> rootfs: $ROOTFS"
44echo "==> kernel: $KERNEL"
45
46mkdir -p "$SALIDA/kernel/boot" "$SALIDA/lib"
47
48# ── 1) el instalador en RAM (es lo caro: arma el stage y comprime ~130 M) ──────────────────────
49echo "==> initramfs del instalador"
50ROOTFS="$ROOTFS" KERNEL="$KERNEL" OUT="$SALIDA/takana-instalador.cpio.gz" ./scripts/instalador-initramfs.sh
51
52# ── 2) lo que va al lado ──────────────────────────────────────────────────────────────────────
53# `rm -f` antes de cada `cp`: lo que sale del store viene en modo 0444 y un `cp` encima falla con
54# «Permission denied», que en un script de empaquetado se lee como un problema de permisos del
55# usuario y no como lo que es — el fichero de la corrida anterior, que es de sólo lectura.
56poner() { rm -f "$2"; cp "$1" "$2"; chmod "${3:-0644}" "$2"; }
57poner "$TAKANA" "$SALIDA/takana" 0755
58poner "$KERNEL" "$SALIDA/kernel/boot/bzImage"
59poner scripts/takana-install-partition.sh "$SALIDA/takana-install-partition.sh" 0755
60# ── LAS LIBRERÍAS QUE EL INSTALADOR SOURCEA, DERIVADAS DEL PROPIO SCRIPT ──────────────────────────
61# Acá había UNA copia a mano (`herramientas-desde-store.sh`) y el script sourcea CUATRO:
62# `usuarios-del-home.sh`, `adoptar.sh`, `cuenta.sh` y ésa. Una librería que no viaja no da un error
63# claro: el `.` falla y el instalador sigue hasta que llama a la función, ya con el disco en la mano.
64# Derivarlas del script es lo que hace que agregar la quinta no exija acordarse de este sitio — la
65# lista a mano ya había quedado corta tres veces.
66for _lib in $(sed -n 's|^\. "$(dirname "$0")/lib/\([a-z-]*\.sh\)".*|\1|p' scripts/takana-install-partition.sh); do
67	[ -r "scripts/lib/$_lib" ] || { echo "falta scripts/lib/$_lib, que el instalador sourcea" >&2; exit 1; }
68	poner "scripts/lib/$_lib" "$SALIDA/lib/$_lib"
69done
70echo "   libs del instalador: $(sed -n 's|^\. "$(dirname "$0")/lib/\([a-z-]*\.sh\)".*|\1|p' scripts/takana-install-partition.sh | tr '\n' ' ')"
71# `busybox` viaja suelto en el paquete —2 MiB— y no es redundante: es con lo que se desempaqueta el
72# árbol a instalar cuando NO hace falta saltar. El host puede no tener `cpio` ni `gzip` (en las tres
73# máquinas de este proyecto no hay `cpio`), así que depender de los del sistema ajeno es depender de
74# algo que ya sabemos que falta.
75_bb="${IRD_TREE:-work/.instalador-initramfs-tree}/bin/busybox"
76[ -r "$_bb" ] || { echo "no encuentro busybox en $_bb" >&2; exit 1; }
77poner "$_bb" "$SALIDA/busybox" 0755
78
79# ── 3) la comprobación que justifica este script ──────────────────────────────────────────────
80# El censo que el usuario corre ANTES de saltar (`takana metal survey`, el de afuera) y el que
81# corre el instalador DESPUÉS del salto (el de adentro del initramfs) tienen que ser el mismo
82# fichero. Si divergen, el usuario elige mirando una clasificación y el instalador formatea según
83# otra — y el que decide es el de adentro, que es el que nadie miró.
84echo "==> coherencia: el censo de afuera y el de adentro"
85. "$(dirname "$0")/lib/herramientas-desde-store.sh"
86CPIO=$(herramienta libarchive usr/bin/bsdcpio cpio) || exit 1
87GZIP=$(herramienta gzip bin/gzip gzip)              || exit 1
88_tmp="work/.paquete-verif"; rm -rf "$_tmp"; mkdir -p "$_tmp"
89( cd "$_tmp" && "$GZIP" -d -c "$ROOT/$SALIDA/takana-instalador.cpio.gz" 2>/dev/null \
90    | "$CPIO" -i -d --quiet '*takana-install-partition.sh' 2>/dev/null ) || true
91# `-d` (crear directorios) no es opcional: sin él bsdcpio contesta «Can't create
92# 'instalador/takana-install-partition.sh'» porque el directorio no existe, y con `2>/dev/null`
93# eso se ve exactamente igual que un archivo que no trae el fichero.
94_dentro="$_tmp/instalador/takana-install-partition.sh"
95if [ ! -r "$_dentro" ]; then
96    echo "   ✗ no pude sacar el censo de adentro del initramfs — no puedo afirmar que coincidan" >&2
97    rm -rf "$_tmp"; exit 1
98fi
99_a=$(sha256sum "$_dentro" | cut -d' ' -f1)
100_b=$(sha256sum scripts/takana-install-partition.sh | cut -d' ' -f1)
101rm -rf "$_tmp"
102[ "$_a" = "$_b" ] || {
103    echo "   ✗ el censo de adentro del initramfs NO es el del repo ($(echo "$_a"|cut -c1-12) vs $(echo "$_b"|cut -c1-12))" >&2
104    echo "     El instalador decidiría con una clasificación distinta de la que el usuario vio." >&2
105    exit 1; }
106echo "   ✓ el mismo fichero adentro y afuera ($(echo "$_a" | cut -c1-12))"
107
108echo
109echo "✓ paquete en $SALIDA  ($(du -sm "$SALIDA" | cut -f1) MiB)"
110ls -l "$SALIDA"
111echo
112echo "En la máquina donde se instala:  sudo ./takana metal check → survey → install"