Files
takana/scripts/kde/metal-desktop-image-dual.sh
Sergio 476168bb07 takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4
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.
2026-09-09 19:28:48 +00:00

140 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# metal-desktop-image-dual.sh — imagen de disco EFI KDE para METAL que aguanta DOS GPUs (Intel i915 y
# NVIDIA Pascal/nouveau) con render por SOFTWARE (mesa-llvmpipe soberano). USB "live" que se adapta a la
# máquina donde se bootee. Ver [[kde-metal-qemu-desktop]] y el runbook docs/runbooks/kde-qemu-desktop.md.
#
# Por qué software y no iris/nouveau HW: el mesa takana-built es swrast/llvmpipe; una mesa HW con nouveau
# hoy sólo existe como binario Alpine (rompe soberanía). llvmpipe sobre el KMS del kernel (i915 O nouveau)
# funciona idéntico en ambas máquinas y reusa los fixes ya validados. HW-accel = iteración siguiente.
#
# work/metal-rootfs base: arje-zero PID1 + busybox + firmware i915 (static ⇒ hay que inyectar musl)
# work/kde-metal-rootfs KDE runtime-completo (Qt/KF6/Plasma/apps)
# + store/*-mesa-llvmpipe swrast/llvmpipe (software GL) + libLLVM.18
# + firmware nvidia/gp106 de work/mirada-rootfs (nouveau necesita el blob firmado para modeset en Pascal)
# + kernel linux-generic (i915 + nouveau + radeon builtin) ← NO linux-metal (ese apaga nouveau)
# → work/hammer-kde-metal-dual.img
#
# Uso: scripts/kde/metal-desktop-image-dual.sh
# BOOT=1 scripts/kde/metal-desktop-image-dual.sh # + arranca en OVMF para validar el boot chain
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
BASE="${BASE:-work/metal-rootfs}"
KDE="${KDE:-work/kde-metal-rootfs}"
MESA="${MESA:-$(ls -dt store/*-mesa-llvmpipe 2>/dev/null | head -1)}"
LLVM="${LLVM:-$(ls -dt store/*-llvm18 2>/dev/null | head -1)}"
KERNEL="${KERNEL:-$(ls -dt store/*-linux-metal-dual/boot/bzImage 2>/dev/null | head -1)}"
NVFW_SRC="${NVFW_SRC:-work/mirada-rootfs/lib/firmware/nvidia}"
MERGED="${MERGED:-work/metal-desktop-dual-rootfs}"
IMG="${IMG:-work/hammer-kde-metal-dual.img}"
for x in "$BASE" "$KDE"; do [ -d "$x" ] || { echo "falta $x" >&2; exit 1; }; done
[ -n "$MESA" ] && [ -d "$MESA" ] || { echo "falta mesa-llvmpipe en store/" >&2; exit 1; }
[ -n "$LLVM" ] && [ -d "$LLVM" ] || { echo "falta llvm18 en store/" >&2; exit 1; }
[ -n "$KERNEL" ] && [ -r "$KERNEL" ] || { echo "falta kernel linux-generic (build recipes/linux-generic.toml)" >&2; exit 1; }
echo "==> fundiendo rootfs por hardlinks (base metal + KDE)"
rm -rf "$MERGED"
cp -al "$BASE" "$MERGED"
cp -al --remove-destination "$KDE"/. "$MERGED"/
. "$ROOT/scripts/lib/pid1-desde-store.sh"
inyectar_pid1 "$MERGED" "$BASE"
echo "==> inyectando mesa-llvmpipe (software GL) desde $MESA"
cp -a "$MESA"/usr/lib/dri/. "$MERGED"/usr/lib/dri/ 2>/dev/null || true
for so in libglapi libgbm libEGL libGLESv2 libgallium; do
cp -a "$MESA"/usr/lib/$so* "$MERGED"/usr/lib/ 2>/dev/null || true
done
ls "$MERGED"/usr/lib/dri/*swrast* >/dev/null 2>&1 || { echo " ✗ swrast no entró" >&2; exit 1; }
echo "==> inyectando libLLVM.18 + libgcc_s + libstdc++ (llvmpipe JIT los NEEDea)"
cp -a "$LLVM"/usr/lib/libLLVM.so.18.1 "$MERGED"/usr/lib/
ln -sf libLLVM.so.18.1 "$MERGED"/usr/lib/libLLVM.so.18
ln -sf libLLVM.so.18.1 "$MERGED"/usr/lib/libLLVM.so
GCCS="${GCCS:-.dev-fs/alpine/usr/lib/libgcc_s.so.1}"; [ -r "$GCCS" ] && cp -a "$GCCS" "$MERGED"/usr/lib/ || echo " ⚠ sin libgcc_s"
STDCXX="${STDCXX:-.dev-fs/alpine/usr/lib/libstdc++.so.6}"; [ -r "$STDCXX" ] && cp -a "$STDCXX"* "$MERGED"/usr/lib/ 2>/dev/null || echo " ⚠ sin libstdc++"
echo "==> inyectando musl (loader + libc) — los binarios KDE son dinámicos, la base metal es estática"
MUSL="${MUSL:-/usr/lib/musl/lib/libc.so}"
[ -r "$MUSL" ] || { echo "no encuentro musl libc ($MUSL)" >&2; exit 1; }
mkdir -p "$MERGED/usr/lib/musl/lib" "$MERGED/lib"
cp -a "$MUSL" "$MERGED/usr/lib/musl/lib/libc.so"
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/lib/ld-musl-x86_64.so.1"
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/usr/lib/libc.so"
echo "==> inyectando firmware NVIDIA gp106 (nouveau lo exige para modeset en Pascal; i915 ya está en la base)"
if [ -d "$NVFW_SRC" ]; then
mkdir -p "$MERGED/lib/firmware/nvidia"
cp -a "$NVFW_SRC"/. "$MERGED/lib/firmware/nvidia/"
echo " ✓ nvidia fw: $(ls "$MERGED/lib/firmware/nvidia" | tr '\n' ' ')"
else
echo " ⚠ sin $NVFW_SRC — la rama NVIDIA no hará modeset (Intel sí)"
fi
echo "==> instalando /usr/bin/plasma-start (metal software-GL, lanzamiento manual)"
install -Dm755 scripts/kde/plasma-start-metal-sw.sh "$MERGED/usr/bin/plasma-start"
# --- getty en tty1: el prompt TIENE que salir por la PANTALLA -----------------------------------------
# El CMDLINE horneado es "console=tty0 console=ttyS0,115200 …" y el kernel hace /dev/console = la ÚLTIMA
# console= ⇒ ttyS0. La seed card de la base metal supervisa un solo getty, sobre `console` ⇒ en un metal
# sin puerto serie el shell nace INVISIBLE: la pantalla se congela en el último printk del kernel (los
# printk sí van a las dos consolas) y parece que el arranque murió, cuando en realidad está vivo. Eso
# nunca se vio en QEMU porque siempre validamos con -nographic, donde el serial ES la pantalla.
# Fix acá y no en el cmdline: un getty sobre tty1 es independiente del cmdline (en metal siempre hay VT)
# y no obliga a recompilar/re-sellar el kernel. El getty de `console` se conserva (debug por serial).
echo "==> añadiendo getty en tty1 a la seed card (el prompt de console va al SERIAL, invisible en metal)"
cat > "$MERGED/usr/bin/console-login" <<'LOGIN'
#!/bin/sh
# arje-zero lanza el getty con envp VACÍO ⇒ sin PATH no se resuelve ni `cat` ni `plasma-start`.
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
export HOME=/root TERM=linux
[ -r /etc/motd ] && /bin/busybox cat /etc/motd
exec /bin/sh
LOGIN
chmod 0755 "$MERGED/usr/bin/console-login"
python3 - "$MERGED/ente/seed.card.json" <<'PY'
# OJO: $MERGED es un árbol de HARDLINKS a la base metal ⇒ escribir in-place mutaría también
# work/metal-rootfs (y toda otra imagen que comparta el inodo). Se escribe a un temporal y se
# os.replace ⇒ se reemplaza la ENTRADA de directorio, el inodo compartido queda intacto.
import json, sys, copy, os
p = sys.argv[1]
card = json.load(open(p))
gen = card["genesis"]
gen[:] = [g for g in gen if g["label"] != "tty1-getty"] # idempotente
base = next(g for g in gen if g["label"] == "console-getty")
tty1 = copy.deepcopy(base)
tty1["id"] = "01HQAR53D4M2NBV8KZTYXFQA03"
tty1["label"] = "tty1-getty"
tty1["payload"]["Native"]["argv"] = ["getty", "-n", "-l", "/usr/bin/console-login", "38400", "tty1"]
gen.append(tty1)
json.dump(card, open(p + ".new", "w"), indent=2, sort_keys=True)
os.replace(p + ".new", p)
print(" ✓ genesis: " + ", ".join(g["label"] for g in gen))
PY
rm -f "$MERGED/etc/motd" # romper el hardlink: `cat >` escribiría el inodo COMPARTIDO con work/metal-rootfs
cat > "$MERGED/etc/motd" <<'MOTD'
#-- takana :: escritorio KDE Plasma 6 (metal, dual-GPU software) ------------
Render por software (llvmpipe soberano) sobre i915 (Intel) o nouveau (NVIDIA).
Arrancar el escritorio: plasma-start
Logs si algo falla: /tmp/kwin.log /tmp/plasmashell.log
Ver GPU detectada: ls /dev/dri ; dmesg | grep -iE 'i915|nouveau|drm'
---------------------------------------------------------------------------
MOTD
mkdir -p "$MERGED/root/.config" "$MERGED/root/.cache" "$MERGED/run/user/0" "$MERGED/tmp"
chmod 1777 "$MERGED/tmp"
echo "==> rootfs fundido: $(du -sh "$MERGED" | cut -f1)"
need_mb=$(du -sm "$MERGED" | cut -f1)
ROOT_SIZE="${ROOT_SIZE:-$(( need_mb + 1536 ))}"
echo "==> ROOT_SIZE=${ROOT_SIZE} MiB · kernel: $(basename "$(dirname "$(dirname "$KERNEL")")")"
export ROOTFS="$MERGED" IMG ROOT_SIZE KERNEL
export ESP_MB="${ESP_MB:-160}" STORE_SIZE="${STORE_SIZE:-512}" STATE_SIZE="${STATE_SIZE:-768}"
exec ./scripts/install-image-efi.sh