🖥 cosmic: COMPONE EN QEMU — cosmic-comp presenta frames sobre el kernel de hammer
Pantalla completa en el gris de COSMIC (39,41,42) con el cursor dibujado, 134 colores distintos, validado CON PANTALLA (DISP=gtk + screendump). Entra el andamiaje completo: hydrate-cosmic.sh (44 recetas, 0 faltantes), qemu-desktop-image.sh y cosmic-start-qemu.sh. Tres causas medidas en tres arranques, ninguna donde uno la busca: 1. cosmic-settings-daemon NO es opcional: cosmic-session lo lanza con .expect() (main.rs:255) y panickea si falta. Corrige lo que este runbook afirmaba. De ahi el modo bare del lanzador, que separa como compone de como arranca la sesion. 2. La pantalla negra era libz.so.1: kms_swrast_dri.so lo NEEDea y el corpus solo traia zlib estatica. Sin driver de software no hay GBM y el compositor arranca igual, negro. Causa a tres capas del sintoma. 3. Los clientes no pueden ser estaticos: wayland-client entra con la feature dlopen y un musl estatico no tiene dlopen funcional — moria 'The wayland library could not be loaded' CON el .so presente. Y dos carreras con /run (dbus y XDG_RUNTIME_DIR) de la misma forma que el bug de PolicyKit1 de hoy en GNOME: comprobar al principio y usar al final. Se crea justo antes de usar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
#!/bin/sh
|
||||
# cosmic-start — lo que el console-getty ejecuta en vez de /bin/sh en la imagen COSMIC de QEMU.
|
||||
# Hermano de gnome-start y plasma-start; hereda de ellos todo lo que ya está pago y sólo diverge en
|
||||
# lo que COSMIC necesita.
|
||||
#
|
||||
# Es `/bin/sh` (busybox ash) a propósito, aunque `start-cosmic` de upstream sea bash: este script
|
||||
# corre ANTES, prepara el entorno, y después le pasa la posta. Cuanto menos dependa, más temprano
|
||||
# puede reportar.
|
||||
set -u
|
||||
say() { echo "== cosmic-qemu :: $*" | tee -a /dev/console /dev/ttyS0 2>/dev/null; }
|
||||
dump() { echo "---- $1 ----" > /dev/ttyS0 2>/dev/null; cat "$1" > /dev/ttyS0 2>/dev/null; }
|
||||
alive() { s=$(sed -n 's/^State:[[:space:]]*//p' /proc/$1/status 2>/dev/null); case "$s" in ""|Z*) return 1;; *) return 0;; esac; }
|
||||
|
||||
say "arrancando (pid $$)"
|
||||
|
||||
# ── FS virtuales y directorios de runtime ───────────────────────────────────────────────────────
|
||||
mount -t proc none /proc 2>/dev/null
|
||||
mount -t sysfs none /sys 2>/dev/null
|
||||
mount -t devtmpfs none /dev 2>/dev/null
|
||||
mkdir -p /dev/pts /dev/shm && mount -t devpts none /dev/pts 2>/dev/null && mount -t tmpfs none /dev/shm 2>/dev/null
|
||||
# XDG_RUNTIME_DIR es OBLIGATORIO para Wayland: ahí viven el socket del compositor y los de los
|
||||
# clientes. Sin él el compositor arranca y nadie puede conectarse — y el error que da es del cliente,
|
||||
# no del compositor, que es lo que hace confuso el diagnóstico.
|
||||
export XDG_RUNTIME_DIR=/run/user/0
|
||||
mkdir -p "$XDG_RUNTIME_DIR" && chmod 700 "$XDG_RUNTIME_DIR"
|
||||
# …y COMPROBARLO, porque el primer arranque falló justo acá y el error salía del sitio equivocado:
|
||||
# dbus decía «XDG_RUNTIME_DIR /run/user/0 not available» y eso se lee como un problema de dbus. El
|
||||
# `mkdir -p` de arriba no garantiza nada si /run no es escribible o si algo lo montó encima.
|
||||
if [ -d "$XDG_RUNTIME_DIR" ] && [ -w "$XDG_RUNTIME_DIR" ]; then
|
||||
say "XDG_RUNTIME_DIR OK ($XDG_RUNTIME_DIR)"
|
||||
else
|
||||
say "!! XDG_RUNTIME_DIR NO existe/no escribible — /run es: $(ls -ld /run 2>&1)"
|
||||
say " montando tmpfs en /run"
|
||||
mount -t tmpfs none /run 2>/dev/null
|
||||
mkdir -p "$XDG_RUNTIME_DIR" && chmod 700 "$XDG_RUNTIME_DIR"
|
||||
[ -w "$XDG_RUNTIME_DIR" ] && say " ✓ ahora sí" || say " ✗ sigue sin andar"
|
||||
fi
|
||||
mkdir -p /root/.config /root/.cache /var/lib/dbus /run/dbus /tmp && chmod 1777 /tmp
|
||||
export HOME=/root SHELL=/bin/bash PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
say "kernel $(uname -r) · drm: $(ls /dev/dri 2>/dev/null | tr '\n' ' ')"
|
||||
|
||||
# ── Render por software: la VM no tiene GPU ─────────────────────────────────────────────────────
|
||||
# Las cuatro perillas vienen pagas de las campañas KDE y GNOME. `GBM_ALWAYS_SOFTWARE` + el driver
|
||||
# `kms_swrast` son lo que hace que mesa acepte crear un device GBM sobre virtio-gpu sin acelerador;
|
||||
# `LP_NUM_THREADS=1` evita que llvmpipe se coma los cuatro vcpus y deje al compositor sin planificar.
|
||||
export GBM_ALWAYS_SOFTWARE=1
|
||||
export LIBGL_ALWAYS_SOFTWARE=1
|
||||
export MESA_LOADER_DRIVER_OVERRIDE=kms_swrast
|
||||
export LP_NUM_THREADS=1
|
||||
# COSMIC pinta con tiny-skia (libcosmic entra sin `wgpu`), pero el compositor SÍ usa EGL/GL por
|
||||
# smithay para componer, así que las de arriba siguen haciendo falta.
|
||||
export RUST_BACKTRACE=1
|
||||
export RUST_LOG="${RUST_LOG:-info}"
|
||||
|
||||
# ── seatd: quién le da los devices al compositor ────────────────────────────────────────────────
|
||||
# smithay entra con `backend_session_libseat`, y libseat tiene dos backends: hablar con un `seatd`
|
||||
# corriendo, o —si el proceso ya es root— abrir los devices él mismo (`builtin`). Acá se levanta
|
||||
# seatd de verdad en vez de usar el builtin, porque es el camino que también sirve fuera de QEMU y
|
||||
# porque deja un log donde mirar. Si no sube, se cae al builtin: mejor un escritorio con andamio que
|
||||
# ninguno, pero se dice en el serial para que no pase por bueno.
|
||||
if [ -x /usr/bin/seatd ]; then
|
||||
/usr/bin/seatd -g video >/tmp/seatd.log 2>&1 &
|
||||
SEATD_PID=$!
|
||||
sleep 1
|
||||
if alive $SEATD_PID && [ -S /run/seatd.sock ]; then
|
||||
say "seatd OK (pid $SEATD_PID, /run/seatd.sock)"
|
||||
else
|
||||
say "!! seatd no levantó — caigo a LIBSEAT_BACKEND=builtin (somos root)"; dump /tmp/seatd.log
|
||||
export LIBSEAT_BACKEND=builtin
|
||||
fi
|
||||
else
|
||||
say "!! sin seatd — LIBSEAT_BACKEND=builtin"
|
||||
export LIBSEAT_BACKEND=builtin
|
||||
fi
|
||||
|
||||
# ── bus de SISTEMA ──────────────────────────────────────────────────────────────────────────────
|
||||
# cosmic-comp habla logind por zbus (sesión, inhibidores) y el bus de sesión lo abre después
|
||||
# `start-cosmic` con dbus-run-session. El de sistema hay que levantarlo acá.
|
||||
if [ -x /usr/bin/dbus-daemon ]; then
|
||||
# ⚠ El mkdir de /run/dbus va ACÁ, no arriba con los demás. El primer arranque en modo bare falló
|
||||
# con «Failed to bind socket /run/dbus/system_bus_socket: No such file or directory» aunque el
|
||||
# directorio se creaba al principio del script: entre un punto y otro arje-zero sigue montando, y
|
||||
# un tmpfs sobre /run se lleva puesto lo que hubiera. Crear justo antes de usar es la única forma
|
||||
# de no depender de ese orden. Mismo motivo que el segundo mkdir de XDG_RUNTIME_DIR.
|
||||
mkdir -p /run/dbus /var/lib/dbus
|
||||
[ -f /var/lib/dbus/machine-id ] || dbus-uuidgen > /var/lib/dbus/machine-id 2>/dev/null
|
||||
[ -f /etc/machine-id ] || cp /var/lib/dbus/machine-id /etc/machine-id 2>/dev/null
|
||||
dbus-daemon --system --fork >/tmp/dbus-system.log 2>&1
|
||||
sleep 1
|
||||
[ -S /run/dbus/system_bus_socket ] && say "bus de sistema OK" || { say "!! sin bus de sistema:"; dump /tmp/dbus-system.log; }
|
||||
else
|
||||
say "!! sin dbus-daemon"
|
||||
fi
|
||||
|
||||
# ── login1: el shim de arje ─────────────────────────────────────────────────────────────────────
|
||||
# Mismo eslabón que en GNOME y KDE. cosmic-comp pregunta por su sesión; quien contesta
|
||||
# `org.freedesktop.login1` acá es arje-logind-compat. Se ESPERA el nombre, no el pid: un pid no es un
|
||||
# servicio, y esperar sólo al final deja pasar la carrera (lección de gnome-start, 2026-08-03).
|
||||
if [ -x /usr/bin/arje-logind-compat ]; then
|
||||
ARJE_LOGIN_STATE=1 /usr/bin/arje-logind-compat >/tmp/logind-compat.log 2>&1 &
|
||||
say "arje-logind-compat lanzado (pid $!)"
|
||||
i=0
|
||||
while [ $i -lt 20 ]; do
|
||||
if dbus-send --system --dest=org.freedesktop.DBus --print-reply /org/freedesktop/DBus \
|
||||
org.freedesktop.DBus.NameHasOwner string:org.freedesktop.login1 2>/dev/null | grep -q "boolean true"; then
|
||||
say "bus: org.freedesktop.login1 OK"; break
|
||||
fi
|
||||
i=$((i+1)); sleep 0.5
|
||||
done
|
||||
[ $i -lt 20 ] || { say "!! login1 NO apareció en 10s:"; dump /tmp/logind-compat.log; }
|
||||
else
|
||||
say "!! sin arje-logind-compat — cosmic-comp puede no hallar sesión"
|
||||
fi
|
||||
|
||||
# ── COSMIC ──────────────────────────────────────────────────────────────────────────────────────
|
||||
export XDG_CURRENT_DESKTOP=COSMIC XDG_SESSION_DESKTOP=COSMIC XDG_SESSION_TYPE=wayland
|
||||
export XDG_SESSION_ID=1 XDG_SEAT=seat0 XDG_VTNR=1
|
||||
export XDG_DATA_DIRS=/usr/share XDG_CONFIG_DIRS=/etc/xdg
|
||||
|
||||
# Y otra vez JUSTO ANTES de arrancar, no sólo al principio: entre el getty y este punto pasan varios
|
||||
# segundos en los que arje-zero sigue montando cosas, y un tmpfs sobre /run se lleva puesto el
|
||||
# directorio sin avisar. Comprobar al principio y usar al final es cómo se cuela una carrera.
|
||||
mkdir -p "$XDG_RUNTIME_DIR" && chmod 700 "$XDG_RUNTIME_DIR"
|
||||
[ -w "$XDG_RUNTIME_DIR" ] || say "!! XDG_RUNTIME_DIR se perdió entre el arranque y ahora"
|
||||
|
||||
# ── MODO: bare (default) o session ──────────────────────────────────────────────────────────────
|
||||
# `cosmic-session` es el camino de producción, pero HOY no se puede usar: llama a
|
||||
# `cosmic-settings-daemon` con `.expect("failed to start settings daemon")` (src/main.rs:255) y
|
||||
# PANICKEA si no está — no es opcional ni está detrás de una feature. Y ese daemon todavía no se
|
||||
# puede construir acá (arrastra pipewire; ver el runbook).
|
||||
#
|
||||
# El modo `bare` es la otra mitad que upstream ya soporta (`make install-bare-session`): el
|
||||
# compositor se lanza SOLO y los clientes se levantan a mano contra su WAYLAND_DISPLAY. Sirve para lo
|
||||
# que hace falta ahora, que es saber si el escritorio PINTA — y separa las dos preguntas: «¿compone?»
|
||||
# es del compositor, «¿arranca la sesión?» es del gestor.
|
||||
#
|
||||
# COSMIC_MODE=session para probar el camino de producción cuando el daemon exista.
|
||||
if [ "${COSMIC_MODE:-bare}" = session ]; then
|
||||
say "lanzando cosmic-session vía start-cosmic (modo session)"
|
||||
/bin/bash /usr/bin/start-cosmic --in-login-shell >/tmp/cosmic-session.log 2>&1 &
|
||||
CS_PID=$!
|
||||
else
|
||||
say "lanzando cosmic-comp SOLO (modo bare; cosmic-session necesita settings-daemon)"
|
||||
dbus-daemon --session --fork --print-address=1 >/tmp/dbus-session-addr 2>/tmp/dbus-session.log
|
||||
DBUS_SESSION_BUS_ADDRESS=$(cat /tmp/dbus-session-addr 2>/dev/null)
|
||||
[ -n "$DBUS_SESSION_BUS_ADDRESS" ] && export DBUS_SESSION_BUS_ADDRESS && say "bus de sesión OK" \
|
||||
|| { say "!! sin bus de sesión:"; dump /tmp/dbus-session.log; }
|
||||
/usr/bin/cosmic-comp >/tmp/cosmic-session.log 2>&1 &
|
||||
CS_PID=$!
|
||||
fi
|
||||
|
||||
# ── Reporte: el socket, no el pid ───────────────────────────────────────────────────────────────
|
||||
# «Un pid no es un servicio» — la lección que costó dos iteraciones en GNOME. Lo que dice que el
|
||||
# compositor está VIVO es que exista su socket Wayland, no que el proceso no haya muerto todavía.
|
||||
i=0; WD=""
|
||||
while [ $i -lt 60 ]; do
|
||||
WD=$(ls "$XDG_RUNTIME_DIR" 2>/dev/null | grep -m1 '^wayland-[0-9]$')
|
||||
if [ -n "$WD" ]; then
|
||||
say "compositor OK ($WD) — cosmic-comp ES el display server"
|
||||
break
|
||||
fi
|
||||
alive $CS_PID || { say "!! la sesión MURIÓ antes de crear el socket:"; dump /tmp/cosmic-session.log; break; }
|
||||
i=$((i+1)); sleep 1
|
||||
done
|
||||
[ -n "$WD" ] || say "!! sin socket wayland en ${i}s:"
|
||||
[ -n "$WD" ] || dump /tmp/cosmic-session.log
|
||||
|
||||
# ── Los clientes, contra el socket que el compositor haya elegido ───────────────────────────────
|
||||
# En modo bare no hay quien los levante: `cosmic-session` es el que normalmente hace esto, y por eso
|
||||
# cada uno recibe WAYLAND_DISPLAY explícito. Se lanza sólo lo que ESTÉ instalado — la cola COSMIC se
|
||||
# construye por partes, y un `[ -x ]` de más es más barato que un arranque perdido.
|
||||
if [ -n "$WD" ] && [ "${COSMIC_MODE:-bare}" != session ]; then
|
||||
export WAYLAND_DISPLAY="$WD"
|
||||
for c in cosmic-bg cosmic-panel cosmic-osd cosmic-notifications cosmic-app-library cosmic-launcher cosmic-idle; do
|
||||
if [ -x "/usr/bin/$c" ]; then
|
||||
"/usr/bin/$c" >"/tmp/$c.log" 2>&1 &
|
||||
say "cliente $c lanzado (pid $!)"
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Estado periódico + el log completo al final de cada tramo: el dato que importa no es que siga vivo
|
||||
# sino QUÉ componentes levantó la sesión.
|
||||
n=0
|
||||
while [ $n -lt 12 ]; do
|
||||
sleep 15; n=$((n+1))
|
||||
# `pgrep -c` de busybox devolvía 0 con el compositor VIVO y su socket abierto — o sea que el
|
||||
# contador mentía. Se cuentan los /proc/*/comm, que es el dato del kernel y no una utilería.
|
||||
say "STATUS +$((n*15))s: $(for c in /proc/[0-9]*/comm; do cat "$c" 2>/dev/null; done | grep -c '^cosmic') procesos cosmic · $(for c in /proc/[0-9]*/comm; do cat "$c" 2>/dev/null; done | grep '^cosmic' | sort -u | tr '\n' ' ')"
|
||||
[ $n = 2 ] && { say "log del compositor (primer tramo)"; dump /tmp/cosmic-session.log; for l in /tmp/cosmic-bg.log /tmp/cosmic-panel.log; do [ -s "$l" ] && dump "$l"; done; }
|
||||
done
|
||||
|
||||
say "fin de la ventana de observación"
|
||||
dump /tmp/cosmic-session.log
|
||||
exec /bin/sh
|
||||
@@ -38,6 +38,29 @@ else
|
||||
# Ni binario ni librería: DATOS. El tema de iconos de COSMIC — sin él el escritorio no se ve
|
||||
# «sin iconos», se ve roto, y con el cursor por software ni siquiera hay puntero.
|
||||
recipes/incoming-cosmic/cosmic-icons.toml
|
||||
# …y el tema del que HEREDA (`Inherits=hicolor` en su index.theme). Que un tema herede de otro es
|
||||
# una relación declarada en un fichero de datos, invisible para cualquier grafo de deps.
|
||||
recipes/incoming-cosmic/hicolor-icon-theme.toml
|
||||
|
||||
# ── LO QUE PIDE `start-cosmic`, Y NO LO PIDE NINGÚN `[deps]` ────────────────────────────────
|
||||
# bash de verdad: el script usa `mapfile`, `[[ ]]` y expansión indirecta `${!var}`, así que con el
|
||||
# busybox de la base metal no arranca. Y termina en `exec dbus-run-session -- cosmic-session`,
|
||||
# o sea que el bus de SESIÓN es parte del arranque, no un extra.
|
||||
recipes/bash.toml
|
||||
recipes/dbus.toml
|
||||
|
||||
# ── DATOS QUE UNA LIBRERÍA DEL CIERRE NECESITA EN RUNTIME ───────────────────────────────────
|
||||
# libxkbcommon entra por el grafo (la enlazan comp y clientes) pero sus TABLAS no: sin
|
||||
# `/usr/share/X11/xkb` no puede compilar un keymap y el escritorio queda sin teclado. Es el mismo
|
||||
# patrón que los gschemas en GNOME — la librería es la interfaz, los datos son otro paquete.
|
||||
recipes/incoming-cosmic/xkeyboard-config.toml
|
||||
# Idem tipografías: nada del cierre trae una sola fuente, y sin fuentes el panel sale con tofu.
|
||||
recipes/incoming-cosmic/dejavu-fonts.toml
|
||||
# zlib COMPARTIDA. El corpus trae `zlib` estática, que le sirve a todo el cierre de COSMIC… y no
|
||||
# al driver de mesa: `kms_swrast_dri.so` es un .so que se abre con dlopen y NEEDea `libz.so.1`.
|
||||
# Sin ella mesa no carga NINGÚN driver de software, GBM falla, y el compositor arranca igual y
|
||||
# deja la pantalla NEGRA — el fallo aparece a tres capas de distancia de la causa.
|
||||
recipes/incoming-cosmic/zlib-shared.toml
|
||||
)
|
||||
fi
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env bash
|
||||
# qemu-desktop-image.sh — imagen de disco EFI COSMIC para QEMU (virtio-gpu + GL por software), que
|
||||
# auto-lanza cosmic-session. Hermano de scripts/gnome/qemu-desktop-image.sh y scripts/kde/…: comparte
|
||||
# la base metal, la inyección de mesa-llvmpipe/LLVM/musl y el truco del console-getty.
|
||||
#
|
||||
# work/metal-rootfs base: arje-zero PID1 + busybox + kernel(EFI-stub) + firmware
|
||||
# work/cosmic-rootfs cierre de COSMIC (lo arma scripts/cosmic/hydrate-cosmic.sh)
|
||||
# + store/*-mesa-llvmpipe GBM/EGL de software (el cierre trae mesa con iris_dri, que es Intel real)
|
||||
# + store/*-llvm18 libLLVM que llvmpipe JIT-linkea
|
||||
# → work/cosmic-qemu-rootfs (hardlinks) → work/hammer-cosmic-qemu.img
|
||||
#
|
||||
# Uso: scripts/cosmic/qemu-desktop-image.sh
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
||||
|
||||
BASE="${BASE:-work/metal-rootfs}"
|
||||
COSMIC="${COSMIC:-work/cosmic-rootfs}"
|
||||
MESA="${MESA:-$(ls -dt store/*-mesa-llvmpipe 2>/dev/null | head -1)}"
|
||||
LLVM="${LLVM:-$(ls -dt store/*-llvm18 2>/dev/null | head -1)}"
|
||||
MERGED="${MERGED:-work/cosmic-qemu-rootfs}"
|
||||
IMG="${IMG:-work/hammer-cosmic-qemu.img}"
|
||||
|
||||
[ -d "$BASE" ] || { echo "falta $BASE" >&2; exit 1; }
|
||||
[ -d "$COSMIC" ] || { echo "falta $COSMIC — corré scripts/cosmic/hydrate-cosmic.sh" >&2; exit 1; }
|
||||
[ -n "$MESA" ] && [ -d "$MESA" ] || { echo "falta mesa-llvmpipe en store/" >&2; exit 1; }
|
||||
|
||||
echo "==> fundiendo rootfs por hardlinks (base metal + cierre COSMIC)"
|
||||
rm -rf "$MERGED"
|
||||
cp -al "$BASE" "$MERGED"
|
||||
cp -al --remove-destination "$COSMIC"/. "$MERGED"/
|
||||
|
||||
. "$ROOT/scripts/lib/pid1-desde-store.sh"
|
||||
inyectar_pid1 "$MERGED" "$BASE"
|
||||
|
||||
echo "==> parcheando mesa software desde $(basename "$MESA")"
|
||||
# El cierre trae mesa con SÓLO iris_dri.so (Intel real). En QEMU no hay GPU: hace falta kms_swrast.
|
||||
mkdir -p "$MERGED"/usr/lib/dri
|
||||
cp -a --remove-destination "$MESA"/usr/lib/dri/. "$MERGED"/usr/lib/dri/ 2>/dev/null || true
|
||||
for so in libglapi libgbm libEGL libGLESv2 libGL libgallium; do
|
||||
cp -a --remove-destination "$MESA"/usr/lib/$so* "$MERGED"/usr/lib/ 2>/dev/null || true
|
||||
done
|
||||
ls "$MERGED"/usr/lib/dri/*swrast* >/dev/null 2>&1 && echo " ✓ kms_swrast instalado" || { echo " ✗ swrast no entró" >&2; exit 1; }
|
||||
|
||||
echo "==> inyectando libLLVM.18 (llvmpipe lo JIT-linkea)"
|
||||
[ -n "$LLVM" ] && [ -d "$LLVM" ] || { echo " ✗ falta llvm18 en store/ (set LLVM=)" >&2; exit 1; }
|
||||
cp -a --remove-destination "$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
|
||||
|
||||
echo "==> inyectando el runtime C++ de Alpine (deuda CONOCIDA, no accidente)"
|
||||
# libLLVM y mesa-llvmpipe se construyen con gcc ⇒ NEEDean libstdc++/libgcc_s. Nada de COSMIC los pide
|
||||
# —el compositor cierra con ocho NEEDED y ninguno es de gcc—: esto es deuda de la cadena de mesa.
|
||||
for lib in libgcc_s.so.1 libstdc++.so.6; do
|
||||
src=".dev-fs/alpine/usr/lib/$lib"
|
||||
if [ -r "$src" ]; then cp -a --remove-destination "$src"* "$MERGED"/usr/lib/ 2>/dev/null || true
|
||||
else echo " ⚠ sin $lib ($src)"; fi
|
||||
done
|
||||
|
||||
echo "==> inyectando musl — y los DOS sonames"
|
||||
# La base metal es 100% estática (arje-zero+busybox). En musl el loader ES libc (mismo fichero). Van
|
||||
# dos nombres porque conviven dos toolchains: zig-cc emite NEEDED `libc.so` y el gcc/clang de Alpine
|
||||
# emite `libc.musl-x86_64.so.1`. Es la MISMA libc; sin el segundo symlink lo de gcc no carga.
|
||||
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 --remove-destination "$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"
|
||||
ln -sf /usr/lib/musl/lib/libc.so "$MERGED/usr/lib/libc.musl-x86_64.so.1"
|
||||
echo " ✓ libc.so + libc.musl-x86_64.so.1"
|
||||
|
||||
echo "==> inyectando arje-logind-compat (el login1 del fractal) + su política"
|
||||
# cosmic-comp pregunta por su sesión igual que mutter y kwin. El daemon no entra por el cierre porque
|
||||
# nadie lo declara como dep de build. Se elige por `hammer hash` —la receta de HOY—, no por el más
|
||||
# reciente del store. Su política D-Bus viaja DENTRO del artefacto desde 2026-07-30.
|
||||
if ALC="${ALC:-store/$(./target/release/hammer --store store hash recipes/arje-logind-compat.toml 2>/dev/null | tail -1 | sed 's/^b3://')-arje-logind-compat}"; [ -d "$ALC" ]; then
|
||||
install -Dm755 "$ALC"/usr/bin/arje-logind-compat "$MERGED"/usr/bin/arje-logind-compat
|
||||
install -d "$MERGED/usr/share/dbus-1/system.d"
|
||||
cp -a --remove-destination "$ALC"/usr/share/dbus-1/system.d/. "$MERGED"/usr/share/dbus-1/system.d/ 2>/dev/null || true
|
||||
echo " ✓ $(basename "$ALC" | cut -c1-12)"
|
||||
else
|
||||
echo " ✗ falta arje-logind-compat en store/ — cosmic-comp no hallará sesión" >&2; exit 1
|
||||
fi
|
||||
# Comprobación, que es lo que reemplaza a escribir la política acá: mover algo a un artefacto sólo es
|
||||
# una mejora si se NOTA cuando falta.
|
||||
[ -f "$MERGED/usr/share/dbus-1/system.d/org.freedesktop.login1.conf" ] \
|
||||
&& echo " ✓ org.freedesktop.login1.conf (del artefacto)" \
|
||||
|| { echo " ✗ falta org.freedesktop.login1.conf — re-sellá arje-logind-compat" >&2; exit 1; }
|
||||
|
||||
echo "==> grupo video (seatd lo exige por NOMBRE)"
|
||||
# `seatd -g video` sale con «Could not find group by name 'video'» y no arranca. No es cosmético:
|
||||
# sin seatd, libseat cae al backend `builtin`, que anda sólo porque acá todo corre como root — o sea
|
||||
# que el escritorio funcionaría por un accidente de privilegios y no por el camino real. La base metal
|
||||
# es tan mínima que no trae ni los grupos estándar.
|
||||
if ! grep -q '^video:' "$MERGED/etc/group" 2>/dev/null; then
|
||||
tmp="$MERGED/etc/group.new"
|
||||
{ cat "$MERGED/etc/group"; echo "video:x:44:"; } > "$tmp"
|
||||
chmod 644 "$tmp"; mv "$tmp" "$MERGED/etc/group"
|
||||
echo " ✓ video:x:44"
|
||||
fi
|
||||
|
||||
echo "==> usuario messagebus (el system bus hace setuid a él)"
|
||||
for f in passwd:messagebus:x:81:81:messagebus:/dev/null:/sbin/nologin group:messagebus:x:81:; do
|
||||
file="${f%%:*}"; line="${f#*:}"
|
||||
if ! grep -q '^messagebus:' "$MERGED/etc/$file" 2>/dev/null; then
|
||||
tmp="$MERGED/etc/$file.new"
|
||||
{ cat "$MERGED/etc/$file"; echo "$line"; } > "$tmp"
|
||||
chmod 644 "$tmp"; mv "$tmp" "$MERGED/etc/$file"
|
||||
fi
|
||||
done
|
||||
for h in usr/libexec/dbus-daemon-launch-helper usr/lib/dbus-1.0/dbus-daemon-launch-helper; do
|
||||
if [ -f "$MERGED/$h" ]; then
|
||||
chown 0:81 "$MERGED/$h" 2>/dev/null || true
|
||||
chmod 4750 "$MERGED/$h"
|
||||
echo " ✓ setuid en /$h"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "==> instalando /usr/bin/cosmic-start"
|
||||
install -Dm755 scripts/cosmic/cosmic-start-qemu.sh "$MERGED/usr/bin/cosmic-start"
|
||||
|
||||
echo "==> auto-lanzar COSMIC: console-getty ejecuta cosmic-start (no /bin/sh)"
|
||||
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/cosmic-start" if a == "/bin/sh" else a) for a in argv]
|
||||
print(" console-getty argv →", argv)
|
||||
tmp = p + ".new"
|
||||
with open(tmp, "w") as f:
|
||||
json.dump(c, f, indent=2)
|
||||
os.chmod(tmp, 0o644)
|
||||
os.replace(tmp, p)
|
||||
PY
|
||||
|
||||
# /var/run → /run: arje-logind-compat busca el bus de sistema en la ruta LEGACY y dbus-daemon escucha
|
||||
# en /run. Esta base metal es tan mínima que ni siquiera tiene /var/run; sin el enlace el daemon se va
|
||||
# a modo idle y nunca registra login1.
|
||||
ln -sfn /run "$MERGED/var/run"
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user