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…
el saltito sin USB: kexec primero, espacio libre si la máquina no puede, y nunca desde adentro
1#!/bin/sh
2# install-particion-test.sh — banco de pruebas de `takana-install-partition.sh` sobre un disco REAL
3# (loop device) que trae vecinos: una ESP con Windows simulado y una partición con datos del usuario.
4#
5# ── QUÉ PRUEBA, Y POR QUÉ ASÍ ──────────────────────────────────────────────────────────────────
6# Este instalador se define por lo que NO hace, y eso no se valida leyendo su salida: se valida
7# comprobando que los BYTES de al lado siguen ahí. Por eso el test no mira mensajes, mira hashes:
8#
9# 1. la partición vecina queda idéntica byte a byte (sha256 del device entero, antes y después)
10# 2. la tabla de particiones queda idéntica (`sfdisk -d`)
11# 3. el `\EFI\BOOT\BOOTX64.EFI` y el `\EFI\Microsoft\` del vecino no se tocan
12# 4. nuestro kernel llega entero a `\EFI\takana\takanax64.efi` (mismo sha256 que el bzImage)
13# 5. las tres GUARDAS disparan: disco entero, partición montada, partición = ESP
14# 6. el guardián de capacidad NO se cree al filesystem: una ESP cuyo FAT declara más espacio del
15# que la partición tiene (pasa de verdad con ESPs encogidas sin reformatear) se cota al tamaño
16# real. El `df` del kernel repite la mentira, así que creerle al FS no alcanza.
17#
18# Requiere root (losetup + mount). Usa las herramientas SELLADAS del store, no las del host.
19# sudo scripts/install-particion-test.sh
20set -eu
21ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
22[ "$(id -u)" = "0" ] || { echo "este test necesita root (losetup, mount)" >&2; exit 2; }
23
24P="${P:-work/.install-particion-test}"
25ROOTFS="${ROOTFS:-}"
26KERNEL="${KERNEL:-$(ls -dt /store/*-linux-metal/boot/bzImage store/*-linux-metal/boot/bzImage 2>/dev/null | head -1)}"
27[ -n "${KERNEL:-}" ] && [ -r "$KERNEL" ] || { echo "no encuentro un bzImage de linux-metal (set KERNEL=)" >&2; exit 1; }
28if [ -z "$ROOTFS" ]; then
29 # ⚠ El rootfs tiene que estar en el MISMO filesystem que el stage: el armado usa `cp -al`
30 # (hardlinks) y `linkat()` no cruza mounts (EXDEV). En el hub el store está en otro disco, así
31 # que se copia una vez acá. No es un capricho del test: es el mismo motivo por el que
32 # install-image-efi.sh trae la `sonda_hardlink`.
33 _src=$(ls -dt /store/*-product-rootfs store/*-product-rootfs 2>/dev/null | head -1)
34 [ -n "${_src:-}" ] || { echo "no encuentro un product-rootfs (set ROOTFS=)" >&2; exit 1; }
35 ROOTFS="$P/rootfs"
36 [ -d "$ROOTFS" ] || { mkdir -p "$P"; echo "==> copiando $_src → $ROOTFS (una vez, por EXDEV)"; cp -a "$_src" "$ROOTFS"; }
37fi
38
39. "$(dirname "$0")/lib/herramientas-desde-store.sh"
40SFDISK=$(herramienta util-linux sbin/sfdisk sfdisk) || exit 1
41MKE2FS=$(herramienta e2fsprogs sbin/mke2fs mke2fs) || exit 1
42MFORMAT=$(herramienta mtools usr/bin/mformat mformat) || exit 1
43MMD=$(herramienta mtools usr/bin/mmd mmd) || exit 1
44MCOPY=$(herramienta mtools usr/bin/mcopy mcopy) || exit 1
45
46mkdir -p "$P"
47D="$P/disco.img"; LOOP=""
48limpiar() { [ -n "$LOOP" ] && losetup -d "$LOOP" 2>/dev/null || true; }
49trap limpiar EXIT INT TERM
50FALLOS=0
51ok() { echo " ✓ $*"; }
52falla(){ echo " ✗ $*" >&2; FALLOS=$(( FALLOS + 1 )); }
53
54# ── el disco de mentira, con vecinos de verdad ────────────────────────────────────────────────
55# ESP_SANA=0 formatea la ESP con el tamaño del FICHERO ENTERO (el FAT miente sobre su capacidad);
56# es el escenario del punto 6. Con 1, la ESP se formatea aparte y se empalma en su offset — que es
57# la forma correcta, y la que usa install-image-efi.sh.
58ESP_SANA="${ESP_SANA:-1}"
59echo "==> fabricando $D (GPT: ESP 64M + destino 1200M + datos 500M + ~3,2G SIN ASIGNAR) ESP_SANA=$ESP_SANA"
60# 5000 MiB (sparse, no ocupan en disco) para que quede un HUECO SIN ASIGNAR al final: es lo que
61# necesita el escenario de `--use-free-space`, que instala al lado en vez de encima.
62rm -f "$D"; truncate -s 5000M "$D"
63"$SFDISK" --quiet "$D" <<EOF
64label: gpt
65start=2048, size=131072, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name="EFI System Partition"
66start=133120, size=2457600, type=linux, name="destino-takana"
67start=2590720, size=1024000, type=linux, name="datos-del-usuario"
68EOF
69head -c 3000000 /dev/urandom > "$P/ajeno.bin"
70if [ "$ESP_SANA" = "1" ]; then
71 rm -f "$P/esp.img"; truncate -s 64M "$P/esp.img"; _esp="$P/esp.img"
72else
73 _esp="$D@@1048576"
74fi
75"$MFORMAT" -F -v VECINO -i "$_esp" ::
76"$MMD" -i "$_esp" ::/EFI ::/EFI/BOOT ::/EFI/Microsoft ::/EFI/Microsoft/Boot
77"$MCOPY" -i "$_esp" "$P/ajeno.bin" ::/EFI/BOOT/BOOTX64.EFI
78"$MCOPY" -i "$_esp" "$P/ajeno.bin" ::/EFI/Microsoft/Boot/bootmgfw.efi
79[ "$ESP_SANA" = "1" ] && dd if="$P/esp.img" of="$D" bs=1M seek=1 conv=notrunc status=none
80rm -rf "$P/datos"; mkdir -p "$P/datos"; echo "la tesis del usuario, 2026" > "$P/datos/NO-BORRAR.txt"
81rm -f "$P/p3.img"; "$MKE2FS" -q -t ext4 -L datos-usuario -d "$P/datos" "$P/p3.img" 500M
82dd if="$P/p3.img" of="$D" bs=512 seek=2590720 conv=notrunc status=none
83
84LOOP=$(losetup -P -f --show "$D")
85echo "==> $D → $LOOP (p1=ESP p2=destino p3=datos)"
86"$SFDISK" -d "$LOOP" 2>/dev/null | grep -E "^${LOOP}p" > "$P/tabla-antes"
87
88# ── las guardas: cada una tiene que ABORTAR ───────────────────────────────────────────────────
89echo "==> guardas (las tres tienen que abortar SIN escribir)"
90corre() { ROOTFS="$ROOTFS" KERNEL="$KERNEL" STAGE="$P/stage" ./scripts/takana-install-partition.sh "$@" >/dev/null 2>&1; }
91corre --root-part "$LOOP" --esp "${LOOP}p1" --no-nvram --yes && falla "aceptó el DISCO ENTERO" || ok "rechaza el disco entero"
92mkdir -p "$P/mnt"; mount "${LOOP}p3" "$P/mnt"
93corre --root-part "${LOOP}p3" --esp "${LOOP}p1" --no-nvram --yes && falla "aceptó una partición MONTADA" || ok "rechaza una partición montada"
94umount "$P/mnt"
95corre --root-part "${LOOP}p1" --esp "${LOOP}p1" --no-nvram --yes && falla "aceptó root-part = ESP" || ok "rechaza root-part = ESP"
96
97# ── la instalación de verdad ──────────────────────────────────────────────────────────────────
98# ⚠ La huella de la vecina se toma ACÁ y no antes de las guardas, y la primera corrida de este test
99# explicó por qué: **montar un ext4 lo MODIFICA** (el superbloque guarda el último montaje y marca
100# el fs como montado), así que el `mount`/`umount` de la guarda de «partición montada» ya cambia el
101# sha256 del device. Medirlo antes daba un ROJO que no era del instalador — un test que acusa al
102# inocente se desactiva a la semana, que es peor que no tenerlo. Lo que este test tiene que probar
103# es que **la instalación** no la toca, y eso es exactamente lo que mide desde acá.
104sha256sum "${LOOP}p3" | cut -d' ' -f1 > "$P/p3-antes"
105echo "==> instalando en ${LOOP}p2"
106ROOTFS="$ROOTFS" KERNEL="$KERNEL" STAGE="$P/stage" \
107 ./scripts/takana-install-partition.sh --root-part "${LOOP}p2" --esp "${LOOP}p1" --no-nvram --yes 2>"$P/stderr" | tail -4
108if [ "$ESP_SANA" = "0" ]; then
109 grep -q "declara más espacio del que existe" "$P/stderr" \
110 && ok "el guardián de capacidad NO se cree al FAT mentiroso" \
111 || falla "el FAT mentiroso pasó sin advertencia"
112fi
113
114# ── lo que hay que comprobar es lo que NO cambió ──────────────────────────────────────────────
115echo "==> veredicto"
116[ "$(sha256sum "${LOOP}p3" | cut -d' ' -f1)" = "$(cat "$P/p3-antes")" ] \
117 && ok "la partición del usuario quedó idéntica byte a byte" || falla "LA PARTICIÓN DEL USUARIO CAMBIÓ"
118"$SFDISK" -d "$LOOP" 2>/dev/null | grep -E "^${LOOP}p" > "$P/tabla-ahora"
119cmp -s "$P/tabla-antes" "$P/tabla-ahora" && ok "la tabla de particiones no se tocó" || falla "LA TABLA CAMBIÓ"
120mkdir -p "$P/esp"; mount -t vfat "${LOOP}p1" "$P/esp"
121_a=$(sha256sum "$P/ajeno.bin" | cut -d' ' -f1)
122[ "$(sha256sum "$P/esp/EFI/BOOT/BOOTX64.EFI" | cut -d' ' -f1)" = "$_a" ] \
123 && ok "\\EFI\\BOOT\\BOOTX64.EFI del vecino intacto" || falla "SE PISÓ EL FALLBACK DEL VECINO"
124[ "$(sha256sum "$P/esp/EFI/Microsoft/Boot/bootmgfw.efi" | cut -d' ' -f1)" = "$_a" ] \
125 && ok "\\EFI\\Microsoft\\ intacto" || falla "SE TOCÓ EL WINDOWS DEL VECINO"
126[ "$(sha256sum "$P/esp/EFI/takana/takanax64.efi" | cut -d' ' -f1)" = "$(sha256sum "$KERNEL" | cut -d' ' -f1)" ] \
127 && ok "nuestro kernel llegó entero a \\EFI\\takana\\" || falla "el kernel de la ESP no coincide con el bzImage"
128[ -r "$P/esp/initramfs.cpio.gz" ] && ok "el initramfs de pivote está en la raíz de la ESP" || falla "falta \\initramfs.cpio.gz"
129umount "$P/esp"
130_lbl=$(blkid -s LABEL -o value "${LOOP}p2" 2>/dev/null || true)
131[ "$_lbl" = "hammer-root" ] && ok "el destino quedó ext4 LABEL=hammer-root" || falla "LABEL del destino = '${_lbl:-}' (esperaba hammer-root)"
132mkdir -p "$P/dst"; mount "${LOOP}p2" "$P/dst"
133[ -x "$P/dst/sbin/init" ] && ok "/sbin/init instalado (el wrapper que reconcilia el arranque)" || falla "el destino no tiene /sbin/init"
134umount "$P/dst"
135# Y el contenido del vecino, no sólo su hash: un fichero que sigue ahí y se lee es la prueba que el
136# usuario entiende.
137mount "${LOOP}p3" "$P/mnt"
138[ "$(cat "$P/mnt/NO-BORRAR.txt" 2>/dev/null)" = "la tesis del usuario, 2026" ] \
139 && ok "el fichero del usuario se sigue leyendo en la partición vecina" || falla "SE PERDIÓ EL FICHERO DEL USUARIO"
140umount "$P/mnt"
141
142# ── escenario 2: instalar AL LADO, en el hueco sin asignar ────────────────────────────────────
143# Es el camino al que cae la política de la raíz viva cuando la máquina no puede kexec, así que
144# tiene que estar igual de probado. Lo que se comprueba es que la tabla crece en UNA entrada y que
145# las que ya estaban no se mueven ni un sector.
146echo
147echo "==> escenario 2: --use-free-space (instalar al lado, en el hueco)"
148"$SFDISK" -d "$LOOP" 2>/dev/null | grep -E "^${LOOP}p" > "$P/tabla-antes2"
149_n_antes=$(wc -l < "$P/tabla-antes2")
150sha256sum "${LOOP}p3" | cut -d' ' -f1 > "$P/p3-antes2"
151ROOTFS="$ROOTFS" KERNEL="$KERNEL" STAGE="$P/stage" \
152 ./scripts/takana-install-partition.sh --use-free-space --disk "$LOOP" --esp "${LOOP}p1" \
153 --no-nvram --yes 2>"$P/stderr2" | tail -3
154"$SFDISK" -d "$LOOP" 2>/dev/null | grep -E "^${LOOP}p" > "$P/tabla-ahora2"
155_n_ahora=$(wc -l < "$P/tabla-ahora2")
156[ "$_n_ahora" = "$(( _n_antes + 1 ))" ] && ok "la tabla creció en UNA entrada ($_n_antes → $_n_ahora)" \
157 || falla "la tabla pasó de $_n_antes a $_n_ahora entradas"
158head -n "$_n_antes" "$P/tabla-ahora2" > "$P/tabla-viejas2"
159cmp -s "$P/tabla-antes2" "$P/tabla-viejas2" && ok "las particiones que ya estaban no se movieron" \
160 || falla "SE MODIFICÓ ALGUNA ENTRADA EXISTENTE"
161[ "$(sha256sum "${LOOP}p3" | cut -d' ' -f1)" = "$(cat "$P/p3-antes2")" ] \
162 && ok "los datos del usuario siguen idénticos tras instalar al lado" || falla "LA VECINA CAMBIÓ AL INSTALAR AL LADO"
163_nueva=$(tail -1 "$P/tabla-ahora2" | cut -d' ' -f1 | tr -d ':')
164[ "$(blkid -s LABEL -o value "$_nueva" 2>/dev/null)" = "hammer-root" ] \
165 && ok "la partición nueva ($_nueva) quedó ext4 LABEL=hammer-root" || falla "la partición nueva no tiene el filesystem esperado"
166
167echo
168[ "$FALLOS" = "0" ] && { echo "VERDE: instaló sin tocar nada de lo ajeno ($LOOP)"; exit 0; }
169echo "ROJO: $FALLOS comprobación(es) fallaron" >&2; exit 1