Files
takana/scripts/kde/qemu-desktop-image.sh
T
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

132 lines
7.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# qemu-desktop-image.sh — imagen de disco EFI KDE para QEMU (virtio-gpu + software GL), auto-lanza Plasma.
#
# Igual que metal-desktop-image.sh pero para una VM: parchea swrast (mesa-swrast softpipe, sin LLVM) al
# rootfs runtime-completo, instala plasma-start-qemu.sh (software GL sobre el DRM de virtio) y lo AUTO-
# LANZA desde /etc/profile del console-getty. Así la ventana QEMU bootea → arje-zero → Plasma pinta solo.
#
# work/metal-rootfs base: arje-zero PID1 + busybox + kernel(EFI-stub) + firmware
# work/kde-metal-rootfs KDE runtime-completo (206 pkgs) — ya trae fuentes/iconos/kactivitymanagerd/
# KDEPlasmaPlatformTheme/módulo QML kwindowsystem
# + store/*-mesa-swrast swrast_dri/kms_swrast (software GL, softpipe)
# → work/qemu-desktop-rootfs (hardlinks) → work/hammer-kde-qemu.img
#
# Uso: scripts/kde/qemu-desktop-image.sh # arma la imagen
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
BASE="${BASE:-work/metal-rootfs}"
KDE="${KDE:-work/kde-metal-rootfs}"
# mesa-llvmpipe (GBM/EGL completo, lo que kwin exige) si está sellado; si no, cae a mesa-swrast (softpipe).
MESA="${MESA:-$(ls -dt store/*-mesa-llvmpipe 2>/dev/null | head -1)}"
[ -n "$MESA" ] && [ -d "$MESA" ] || MESA="$(ls -dt store/*-mesa-swrast 2>/dev/null | head -1)"
LLVM="${LLVM:-$(ls -dt store/*-llvm18 2>/dev/null | head -1)}"
MERGED="${MERGED:-work/qemu-desktop-rootfs}"
IMG="${IMG:-work/hammer-kde-qemu.img}"
[ -d "$BASE" ] || { echo "falta $BASE" >&2; exit 1; }
[ -d "$KDE" ] || { echo "falta $KDE" >&2; exit 1; }
[ -n "$MESA" ] && [ -d "$MESA" ] || { echo "falta artefacto mesa-llvmpipe/mesa-swrast en store/" >&2; exit 1; }
case "$MESA" in *mesa-llvmpipe) LLVMPIPE=1;; *) LLVMPIPE=0;; esac
echo "==> fundiendo rootfs por hardlinks (base + KDE)"
rm -rf "$MERGED"
cp -al "$BASE" "$MERGED"
cp -al --remove-destination "$KDE"/. "$MERGED"/
. "$ROOT/scripts/lib/pid1-desde-store.sh"
. "$ROOT/scripts/lib/libs-compartidas-desde-store.sh"
inyectar_pid1 "$MERGED" "$BASE"
inyectar_libs_compartidas "$MERGED"
echo "==> parcheando mesa (software GL) desde $MESA (llvmpipe=$LLVMPIPE)"
# el artefacto trae usr/lib/{dri/*swrast*,libEGL,libgbm,libglapi,libGLESv2}; copiamos SIN --remove para
# no pisar sonames del metal salvo lo que falte, pero swrast_dri debe entrar sí o sí.
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_dri instalado" || { echo " ✗ swrast no entró" >&2; exit 1; }
if [ "$LLVMPIPE" = 1 ]; then
echo "==> inyectando libLLVM.18 + libgcc_s (llvmpipe JIT-linkea libLLVM; ésta NEEDea libgcc_s)"
[ -n "$LLVM" ] && [ -d "$LLVM" ] || { echo " ✗ falta artefacto llvm18 en store/ (set LLVM=)" >&2; exit 1; }
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
# libgcc_s del sandbox (libLLVM.so lo NEEDea; el -static-libgcc no aplica full a un DYLIB)
GCCS="${GCCS:-.dev-fs/alpine/usr/lib/libgcc_s.so.1}"
[ -r "$GCCS" ] && cp -a "$GCCS" "$MERGED"/usr/lib/libgcc_s.so.1 || echo " ⚠ sin libgcc_s ($GCCS)"
# mesa-llvmpipe se construye con gcc/libstdc++ (para matchear el ABI de libLLVM) ⇒ NEEDea libstdc++.so.6
STDCXX="${STDCXX:-.dev-fs/alpine/usr/lib/libstdc++.so.6}"
[ -r "$STDCXX" ] && cp -a "$STDCXX"* "$MERGED"/usr/lib/ 2>/dev/null || echo " ⚠ sin libstdc++ ($STDCXX)"
echo " ✓ libLLVM.18 ($(du -h "$MERGED"/usr/lib/libLLVM.so.18.1 | cut -f1)) + libgcc_s + libstdc++ inyectados"
fi
echo "==> inyectando musl (loader + libc) — los binarios KDE son dinámicos"
# La base metal es 100% ESTÁTICA (arje-zero+busybox) y el KDE-rootfs no trae libc ⇒ el merge no tiene
# loader musl. Los binarios KDE piden interp /lib/ld-musl-x86_64.so.1 + NEEDED libc.so (única lib base
# que falta; el resto del closure Qt/KF6 está). Copiamos el musl soberano del host (mismo que corre la
# mirada del laptop ⇒ ejecuta binarios takana-musl dinámicos). En musl el loader ES libc (mismo fichero).
MUSL="${MUSL:-/usr/lib/musl/lib/libc.so}"
[ -r "$MUSL" ] || { echo "no encuentro musl libc ($MUSL) — set 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" # intérprete
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/usr/lib/libc.so" # NEEDED soname en el search path
echo " ✓ musl inyectado ($(du -h "$MERGED/usr/lib/musl/lib/libc.so" | cut -f1))"
echo "==> usuario messagebus (el system bus de dbus hace setuid a él; falta en el passwd base)"
# dbus-daemon --system lee system.conf que hace <user>messagebus</user> ⇒ sin ese uid, arrancado como
# root, falla el setuid. Lo agregamos rompiendo el hardlink read-only del passwd/group base con `mv`
# (rename reemplaza la entrada de directorio sin tocar el inode fuente). uid/gid 81 = convención Alpine.
if ! grep -q '^messagebus:' "$MERGED/etc/passwd"; then
tmp="$MERGED/etc/passwd.new"
{ cat "$MERGED/etc/passwd"; echo 'messagebus:x:81:81:messagebus:/dev/null:/sbin/nologin'; } > "$tmp"
chmod 644 "$tmp"; mv "$tmp" "$MERGED/etc/passwd"
fi
if ! grep -q '^messagebus:' "$MERGED/etc/group"; then
tmp="$MERGED/etc/group.new"
{ cat "$MERGED/etc/group"; echo 'messagebus:x:81:'; } > "$tmp"
chmod 644 "$tmp"; mv "$tmp" "$MERGED/etc/group"
fi
echo " ✓ messagebus:81 en passwd/group"
echo "==> instalando /usr/bin/plasma-start (variante QEMU software-GL)"
install -Dm755 scripts/kde/plasma-start-qemu.sh "$MERGED/usr/bin/plasma-start"
echo "==> auto-lanzar Plasma: console-getty ejecuta plasma-start (no /bin/sh)"
# El console-getty es un getty de SERIAL (115200 console=ttyS0) que corría /bin/sh — pero /bin/sh así NO
# es login shell, no lee /etc/profile. En vez de eso, hacemos que getty ejecute plasma-start DIRECTO
# (-l /usr/bin/plasma-start). kwin presenta al DRM de virtio-gpu (ventana gráfica), independiente de que
# la consola de texto viva en el serial. Si Plasma falla, plasma-start hace exec /bin/sh ⇒ shell serie.
python3 - "$MERGED/ente/seed.card.json" <<'PY'
import json, sys, os
p = sys.argv[1]
c = json.load(open(p))
for g in c.get("genesis", []):
if g.get("label") == "console-getty":
argv = g["payload"]["Native"]["argv"]
argv[:] = [("/usr/bin/plasma-start" if a == "/bin/sh" else a) for a in argv]
print(" console-getty argv →", argv)
# escribir a temp y reemplazar la ENTRADA de directorio: rompe el hardlink (el seed en MERGED es un
# hardlink read-only a work/metal-rootfs) sin tocar el inode fuente ni chocar con los permisos.
tmp = p + ".new"
with open(tmp, "w") as f:
json.dump(c, f, indent=2)
os.chmod(tmp, 0o644)
os.replace(tmp, p)
PY
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"
export ROOTFS="$MERGED" IMG ROOT_SIZE
export ESP_MB="${ESP_MB:-128}" STORE_SIZE="${STORE_SIZE:-512}" STATE_SIZE="${STATE_SIZE:-768}"
exec ./scripts/install-image-efi.sh