tawasuyu

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 Definitions

⎇ 476168bb077db780e49c83e3ca4f0d3d230bd58a scripts/cosmic/cosmic-nested.sh Shell · 142 lines · 8.8 KB History raw

takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4 476168bb0 · Sergio ·

1#!/bin/sh
2# cosmic-nested.sh — arranca `escritorio-cosmic` como una VENTANA del compositor que ya tenés
3# delante, sin QEMU y sin imagen de disco. Hermano de `scripts/wlr/sway-nested.sh`; comparte con él
4# el porqué (ciclo de segundos en vez de una tanda, y defectos que sólo se ven MIRANDO) y las dos
5# capas de overlay, porque ningún perfil de `targets.toml` incluye la libc.
6#
7# ══ LO QUE COSMIC HACE DISTINTO ════════════════════════════════════════════════════════════════
8# · `cosmic-comp` elige backend solo. Con `WAYLAND_DISPLAY` puesto usa winit sobre Wayland; ANTES
9#   intenta X11 y falla ruidosamente («$DISPLAY variable not set»). Ese ERROR es normal acá y no
10#   significa que no haya arrancado: lo que manda es si aparece su socket en `$XDG_RUNTIME_DIR`.
11# · **`cosmic-session` no sirve para nestear**: no le pasa `WAYLAND_DISPLAY` a `cosmic-comp` —para
12#   ella el compositor ES el display server—, así que el comp intenta X11 y DRM/udev y muere antes.
13#   Y su stderr lo captura `launch_pad`, que sólo reporta «cosmic-comp exited with error code 1» y
14#   lo reinicia en bucle: la CAUSA no aparece en ningún log. Medido, con todo lo demás igual:
15#       con WAYLAND_DISPLAY → socket /run/user/0/wayland-1, comp vivo hasta el backend
16#       sin WAYLAND_DISPLAY → comp muerto antes
17#   Por eso el modo por defecto es `bare`: el compositor a mano y los clientes apuntados a SU socket,
18#   igual que hace `cosmic-start.sh` sin sesión. `MODE=session` reproduce el fallo, no lo arregla.
19#
20# ══ ⚠ EL CIERRE DEL PERFIL NO PUEDE HACER GL, Y ESO NO ESTÁ EN `targets.toml` ═══════════════════
21# Medido el 2026-09-04: `/usr/lib/dri` del rootfs hidratado trae **`iris_dri.so` y nada más** — el
22# driver de Intel REAL. Sin `swrast_dri.so`, EGL no inicializa y cosmic-comp muere con
23# `Egl(InitFailed(NotInitialized))` después de dos `MESA-LOADER: failed to open {zink,swrast}`.
24#
25# No es un descubrimiento nuevo, es un hueco de DECLARACIÓN: `scripts/gnome/qemu-desktop-image.sh`
26# ya dice «el rootfs GNOME sólo trae iris_dri, que es Intel real» y copia `mesa-llvmpipe` ENCIMA con
27# `--remove-destination`. O sea que cada script de imagen inyecta a mano algo que el perfil no
28# declara — la misma divergencia que `hydrate-profile.py` existe para hacer visible.
29#
30# **Por qué no se arregla declarándolo y ya:** `mesa` y `mesa-llvmpipe` instalan los MISMOS `.so`
31# (`libEGL`, `libgbm`, `libGLESv2`), así que declarar las dos en un perfil colisiona fichero a
32# fichero — la figura de las dos poppler que dejó a zathura fuera de KDE. Los scripts lo resuelven
33# PISANDO, que es una decisión de imagen, no una arista de grafo. Acá se hace lo mismo y se dice:
34# `mesa-llvmpipe` entra como TERCER overlay, el último, o sea el de mayor prioridad.
35# · **No hay `grim`**: COSMIC no implementa `wlr-screencopy` sino su `zcosmic_screencopy`, así que
36#   la captura sale por `cosmic-screenshot` (cadena del portal). Si el portal no está, no hay foto
37#   y hay que mirar la ventana — se dice, no se falsea con una captura del host.
38#
39#   uso:   scripts/cosmic/cosmic-nested.sh
40#   env:   RFS   (def /mnt/cosecha/escritorios/cosmic-rootfs)  hidratado con hydrate-profile.py
41#          BASE  (def .dev-fs/alpine)                          capa con la libc
42#          MODE  (def session | bare)                          sesión completa o sólo el compositor
43#          OUT   (def /mnt/cosecha/escritorios)                dónde deja la captura
44#          SECS  (def 0 = quedarse abierto)
45#          MESA  (def el artefacto vigente de mesa-llvmpipe)  GL por software; "" para no inyectar
46set -u
47ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
48RFS="${RFS:-/mnt/cosecha/escritorios/cosmic-rootfs}"
49BASE="${BASE:-$ROOT/.dev-fs/alpine}"
50MODE="${MODE:-bare}"; OUT="${OUT:-/mnt/cosecha/escritorios}"; SECS="${SECS:-0}"
51mkdir -p "$OUT"
52
53# GL por software. Se resuelve por HASH VIGENTE (`takana hash`), no por el más reciente del store:
54# con dos artefactos del mismo paquete conviviendo, la fecha miente.
55if [ -z "${MESA+x}" ]; then
56  MH=$(./target/release/takana --store ./store hash recipes/mesa-llvmpipe.toml 2>/dev/null | tr -d "\n" | sed "s/b3://")
57  MESA=$(ls -d store/"$MH"-mesa-llvmpipe 2>/dev/null || true)
58  [ -n "${MESA:-}" ] || echo "   ⚠ sin mesa-llvmpipe sellado: el compositor NO va a poder iniciar EGL" >&2
59fi
60
61[ -d "$RFS" ]  || { echo "falta el rootfs del perfil: $RFS" >&2
62                    echo "   scripts/hydrate-profile.py escritorio-cosmic --store /mnt/cosecha/store --into $RFS" >&2; exit 1; }
63[ -d "$BASE" ] || { echo "falta la capa base con la libc: $BASE" >&2; exit 1; }
64
65HOST_XDG="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
66HOST_WL="${WAYLAND_DISPLAY:-wayland-0}"
67case "$HOST_WL" in /*) SOCK="$HOST_WL" ;; *) SOCK="$HOST_XDG/$HOST_WL" ;; esac
68[ -S "$SOCK" ] || { echo "no hay socket Wayland del host en $SOCK" >&2; exit 1; }
69echo "== host: $SOCK   rootfs: $RFS   modo: $MODE"
70
71# El ORDEN importa: el último `--overlay-src` es el de mayor prioridad, así que mesa-llvmpipe pisa
72# los `.so` de la mesa iris del cierre — que es exactamente lo que hacen los scripts de imagen.
73exec bwrap \
74  --overlay-src "$BASE" --overlay-src "$RFS" ${MESA:+--overlay-src "$MESA"} --tmp-overlay / \
75  --dev /dev --proc /proc --tmpfs /tmp --tmpfs /run \
76  --dev-bind-try /dev/dri /dev/dri \
77  --ro-bind "$SOCK" /run/wl-host \
78  --bind "$OUT" /salida \
79  --unshare-pid --unshare-uts --hostname cosmic-nested \
80  --uid 0 --gid 0 --die-with-parent \
81  --setenv PATH /usr/bin:/bin:/usr/sbin:/sbin \
82  --setenv HOME /root --setenv SHELL /bin/bash --setenv TERM xterm-256color \
83  --setenv XDG_RUNTIME_DIR /run/user/0 \
84  --setenv WAYLAND_DISPLAY /run/wl-host \
85  --setenv XDG_DATA_DIRS /usr/share \
86  --setenv XDG_CURRENT_DESKTOP COSMIC \
87  --setenv XDG_SESSION_TYPE wayland \
88  --setenv RUST_BACKTRACE 1 \
89  /bin/sh -c '
90    set -u
91    mkdir -p /run/user/0 /run/dbus /root/.config /etc; chmod 700 /run/user/0
92    [ -s /etc/passwd ] || echo "root:x:0:0:root:/root:/bin/sh" > /etc/passwd
93    [ -s /etc/machine-id ] || tr -d - < /proc/sys/kernel/random/uuid > /etc/machine-id
94    mkdir -p /dev/shm 2>/dev/null || true
95
96    # El bus de SESIÓN: el panel, el osd y las notificaciones hablan por él. En `session` lo abre
97    # `dbus-run-session`; en `bare` no hay quien lo abra, y sin él los clientes arrancan mudos.
98    export DBUS_SESSION_BUS_ADDRESS=$(dbus-daemon --session --fork --print-address 2>/dev/null)
99    echo "   dbus=${DBUS_SESSION_BUS_ADDRESS:-VACIO}"
100
101    if [ "'"$MODE"'" = session ] && [ -x /usr/bin/start-cosmic ]; then
102      echo "-- start-cosmic (sesión completa) — ⚠ NO NESTEA, ver la cabecera del script"
103      /bin/bash /usr/bin/start-cosmic --in-login-shell >/tmp/cosmic.log 2>&1 &
104    else
105      echo "-- cosmic-comp nesteado (winit sobre el Wayland del host)…"
106      cosmic-comp >/tmp/cosmic.log 2>&1 &
107    fi
108    CS=$!
109    i=0
110    while [ $i -lt 80 ]; do
111      WD=$(ls /run/user/0/wayland-* 2>/dev/null | grep -v lock | head -1)
112      [ -n "${WD:-}" ] && break
113      kill -0 $CS 2>/dev/null || { echo "   !! la sesión murió antes del socket:"; tail -25 /tmp/cosmic.log; exit 1; }
114      i=$((i+1)); sleep 0.5
115    done
116    [ -n "${WD:-}" ] || { echo "   !! sin socket en 40 s:"; tail -25 /tmp/cosmic.log; exit 1; }
117    echo "   compositor OK ($WD) — ventana en tu pantalla"
118    export WAYLAND_DISPLAY=$(basename "$WD")
119
120    # Los clientes, contra el socket que el compositor eligió. Cada uno con `[ -x ]` porque la cola
121    # se construye por partes y un arranque perdido cuesta más que una comprobación de más.
122    if [ "'"$MODE"'" != session ]; then
123      for c in cosmic-bg cosmic-panel cosmic-osd cosmic-notifications cosmic-app-library cosmic-launcher; do
124        [ -x "/usr/bin/$c" ] && { "/usr/bin/$c" >"/tmp/$c.log" 2>&1 & sleep 1; }
125      done
126    fi
127
128    sleep 8
129    echo "== procesos de la sesión =="
130    ps -o comm 2>/dev/null | grep -E "cosmic|pop-launcher|xdg-desktop" | sort | uniq -c
131    # `Initializing X11 Backend failed` es NORMAL acá: cosmic-comp prueba X11 antes de winit. Lo que
132    # importa es el backend que SÍ entró.
133    echo "== backend =="; grep -iE "winit|backend" /tmp/cosmic.log | grep -viE "X11|DISPLAY variable" | head -4
134    if command -v cosmic-screenshot >/dev/null 2>&1; then
135      cosmic-screenshot --interactive=false --save-dir /salida >/tmp/shot.log 2>&1 \
136        && echo "== captura en '"$OUT"'" || { echo "== sin captura (portal):"; tail -2 /tmp/shot.log; }
137    else
138      echo "== sin cosmic-screenshot en la imagen — mirá la ventana"
139    fi
140    echo "== cosmic.log (cola) =="; tail -6 /tmp/cosmic.log; cp /tmp/cosmic.log /salida/cosmic-nested.log 2>/dev/null
141    if [ '"$SECS"' -gt 0 ]; then sleep '"$SECS"'; kill $CS 2>/dev/null; else wait $CS; fi
142  '