gnome: el compositor SUBE ENTERO en headless — el muro DRM es libinput, y aparece accountsservice

Experimento decisivo: `gnome-shell --headless --virtual-monitor 1280x800`. El
backend headless crea el seat con META_SEAT_NATIVE_FLAG_NO_LIBINPUT, o sea que
saltea init_libinput() — justo el último paso del hilo de input antes de señalar
`input_thread_initialized` (meta-seat-impl.c:3098). Resultado:

  libmutter-Message: Added virtual monitor Meta-0
  libmutter-Message: Using Wayland display name 'wayland-0'
  == compositor OK (wayland-0) — el shell ES el display server

⇒ **CONFIRMADO: el bloqueo del camino DRM está en libinput/udev, no en el resto
del arranque.** Todo lo demás de mutter funciona. Primer sospechoso libudev-zero.

Y con el compositor arriba aparece el muro siguiente, que es de otra naturaleza:

  Gjs-CRITICAL: JS ERROR: Requiring AccountsService, version 1.0:
                Typelib file for namespace 'AccountsService' not found

LA LECCIÓN DE MÉTODO: gnome-shell selló con su cierre de build COMPLETO (108/108)
y aun así la sesión muere pidiendo este typelib. **El cierre de build no es el
cierre de runtime**: todo lo que el shell carga por `imports.gi.*` desde
JavaScript es invisible al grafo de deps. Se encuentra ARRANCANDO, no compilando.

Se autoró recipes/incoming-gnome/accountsservice.toml. El configure pasa entero
—tres seds verificados contra el build real: generate-version.sh (deriva la
versión del nombre del DIRECTORIO, que en el sandbox es /src, y la rama git usa
`date`, o sea no-determinista), la aserción de wtmp (musl no define WTMPX_FILENAME
ni _PATH_WTMPX) y subdir('tests') (arrastra mocklibc, que llama fgetgrent, ausente
en musl)—. Ojo: -Dsystemdsystemunitdir tiene que ser literalmente `no`; con la
cadena vacía el meson interpreta "averiguá el directorio" y aserta pidiendo
systemd.pc.

NO SELLA todavía, y la frontera está contada símbolo por símbolo, no estimada:

  · libelogind exporta 14 símbolos (los que pedía mutter) y accountsservice usa
    OCHO que faltan: sd_get_sessions, sd_seat_can_multi_session,
    sd_session_get_display y los cinco de sd_login_monitor_*. Estos últimos son
    la parte con enjundia: no son getters sino una API de NOTIFICACIÓN (un fd
    poll-able). Sobre el diseño actual el camino natural es inotify sobre
    /run/systemd/{sessions,seats,users}.
  · fgetspent_r no existe en musl (extensión glibc de /etc/shadow, usada en
    src/daemon.c:265): necesita shim o parche a la variante no-reentrante.

Ninguno de los dos es de accountsservice: son huecos de NUESTRA capa de compat.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-29 06:07:42 -04:00
co-authored by Claude Opus 5
parent 34c7962b29
commit f56bab72f5
3 changed files with 114 additions and 2 deletions
@@ -0,0 +1,97 @@
# accountsservice 23.13.9 — el servicio D-Bus de cuentas de usuario (nombre, avatar, idioma, si es
# administrador). Lo pide gnome-shell desde JAVASCRIPT, no desde C: por eso no aparecía en el
# meson.build de la cima ni en su cierre de build, y sólo se destapó ARRANCANDO la sesión:
#
# Gjs-CRITICAL: JS ERROR: Requiring AccountsService, version 1.0:
# Typelib file for namespace 'AccountsService', version '1.0' not found
# Execution of main.js threw exception
#
# Lección del método: **el cierre de BUILD no es el cierre de RUNTIME**. gnome-shell selló con
# 108/108 recetas y aun así le falta esto, porque `imports.gi.AccountsService` se resuelve en tiempo
# de ejecución. Toda dep que el shell cargue por typelib desde JS es invisible al build.
#
# -Delogind=true es la pieza que hace que esto entre gratis: accountsservice pide `libsystemd` por
# defecto (meson.build:219) y con esta opción pide `libelogind` (:217), que YA está sellada —
# arje-sdlogin-compat, con Version 255 en su .pc, por encima del >= 229.4 que exige. Es la quinta vez
# en la campaña que la C-ABI de logind aparece, y la primera que se resuelve sin esquivarla.
#
# Apagados:
# -Dvapi=false → no hay valac en el corpus.
# -Ddocbook=false -Dgtk_doc=false → xmlto/gtk-doc.
# -Dsystemdsystemunitdir=no → no instala units de systemd; acá PID1 es arje-zero. Ojo: el valor
# tiene que ser literalmente `no`, NO la cadena vacía — con vacía el meson
# interpreta "averiguá el directorio" y ASERTA pidiendo systemd.pc (:183).
# libxcrypt es `required: false` (meson.build:161) ⇒ no hace falta receta: sin ella el servicio no
# cambia contraseñas, que no es lo que el shell le pide (le pide el usuario y su avatar).
#
# `generate-version.sh` se reemplaza por un `echo` de la versión. El script del tarball deriva la
# versión del NOMBRE DEL DIRECTORIO (`basename $PWD | sed 's/^accountsservice-\(.*\)$/\1/'`), y en el
# sandbox de hammer el árbol de fuentes es `/src` ⇒ no matchea y aborta con "Version unknown". Fijarla
# además la vuelve DETERMINISTA: la otra rama del script (la de checkout git) calcula la versión con
# `date` sobre el último commit, que es exactamente lo que un store direccionable por contenido no
# puede tolerar.
#
# El otro sed borra una ASERCIÓN sobre wtmp (meson.build:107). accountsservice busca el fichero de
# histórico de logins probando `WTMPX_FILENAME` y `_PATH_WTMPX`; **musl no define ninguno de los dos**
# —no implementa wtmp—, así que cae a la rama final, que exige que `/var/log/utx.log` EXISTA en el
# constructor y aborta si no. Se borra sólo la línea del assert: la rama igual deja
# `PATH_WTMP='/var/log/utx.log'`, o sea que el servicio vigila esa ruta y, como nunca aparece, no
# reporta histórico de sesiones. Lo que el shell le pide —el usuario, su nombre y su avatar— no
# depende de wtmp. La alternativa era `touch` ese fichero en el sandbox para que el chequeo pasara,
# que es hacer verdadera una premisa falsa; preferible borrar el chequeo y decir por qué.
#
# Y un tercer sed saca `subdir('tests')` (:235), que accountsservice no expone como opción. No es por
# ahorrar tiempo de build: los tests arrastran el subproyecto `mocklibc`, que llama `fgetgrent()` —
# una extensión GNU que **musl no implementa**. No hay forma de compilarlo acá, y lo que se pierde es
# la suite del upstream, no la librería.
#
# El sed saca `subdir('po')`. QUINTA vez que el msgfmt de gettext-tiny obliga a esto (iso-codes, gcr,
# eds, gnome-shell y ahora ésta). Ya no es un gotcha: es la deuda de autorar el gettext de GNU.
#
# ISLA DINÁMICA: -Dintrospection=true + shared, porque lo que falta es justamente el TYPELIB.
#
# ══ ⛔ NO SELLA TODAVÍA — FRONTERA MEDIDA, NO ADIVINADA (2026-07-29) ═════════════════════════════
# El configure pasa entero (los tres seds y las opciones de arriba están verificados contra el build
# real); lo que corta es el COMPILE, y por dos motivos independientes:
#
# 1. LA C-ABI DE sd-login SE QUEDA CORTA. `libelogind` (arje-sdlogin-compat) exporta 14 símbolos —
# los que necesitaba mutter— y accountsservice usa OCHO que no están:
# sd_get_sessions · sd_seat_can_multi_session · sd_session_get_display
# sd_login_monitor (el tipo) · sd_login_monitor_new · sd_login_monitor_unref
# sd_login_monitor_get_fd · sd_login_monitor_flush
# Los cinco de `sd_login_monitor_*` son la parte con enjundia: no son getters sobre ficheros sino
# una API de NOTIFICACIÓN (un fd que se puede meter en un poll y despierta cuando cambia el
# estado de sesiones). Sobre el diseño actual —leer /run/systemd/{sessions,seats,users}— el
# camino natural es un inotify sobre esos directorios.
#
# 2. `fgetspent_r` NO EXISTE EN musl. Es la variante reentrante de la API de /etc/shadow, extensión
# de glibc. La usa src/daemon.c:265 para saber si una cuenta tiene contraseña. Necesita un shim
# o un parche que use la variante no-reentrante.
#
# NINGUNO DE LOS DOS es de accountsservice: son huecos de NUESTRA capa de compatibilidad. La receta
# queda como mapa honesto de la cadena —el mismo criterio que gnome-session y gnome-settings-daemon
# en esta cola—, con la frontera contada símbolo por símbolo en vez de estimada.
#
# CÓMO SE DESTAPÓ, y es la lección de método: gnome-shell selló con su cierre de build COMPLETO
# (108/108) y aun así la sesión murió pidiendo este typelib. **El cierre de build no es el cierre de
# runtime**: todo lo que el shell carga por `imports.gi.*` desde JavaScript es invisible al grafo de
# deps. Se encuentra arrancando, no compilando.
name = "accountsservice"
version = "23.13.9"
[source]
tarball = "https://www.freedesktop.org/software/accountsservice/accountsservice-23.13.9.tar.xz"
sha256 = "adda4cdeae24fa0992e7df3ffff9effa7090be3ac233a3edfdf69d5a9c9b924f"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
[build.phases]
configure = "printf '#!/bin/sh\\necho 23.13.9\\n' > generate-version.sh && sed -i \"/^subdir('po')$/d\" meson.build && sed -i '/Do not know which filename to watch for wtmp changes/d' meson.build && sed -i \"/^subdir('tests')$/d\" meson.build && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload -Ddefault_library=shared -Delogind=true -Dintrospection=true -Dvapi=false -Ddocbook=false -Dgtk_doc=false -Dsystemdsystemunitdir=no -Dc_args=-Wno-error=date-time"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "py3-setuptools", "gi-foreign-girs", "gobject-introspection", "glib", "glib-introspected", "polkit", "dbus-shared", "libelogind", "libffi", "pcre2", "zlib-shared", "expat"]
+13 -2
View File
@@ -13,6 +13,8 @@
set -u
# getty ejecuta este script DIRECTO ⇒ PATH viene vacío. Primero eso, antes de invocar nada.
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
# El modo lo hornea la imagen (GNOME_MODE=... en scripts/gnome/qemu-desktop-image.sh).
[ -r /etc/gnome-mode ] && . /etc/gnome-mode
say() { echo "== gnome-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; }
@@ -177,8 +179,17 @@ if [ "${DIAG:-1}" = 1 ]; then
fi
say "typelibs visibles: $(ls /usr/lib/girepository-1.0/*.typelib 2>/dev/null | wc -l) sistema + $(ls /usr/lib/gnome-shell/*.typelib 2>/dev/null | wc -l) del shell"
say "lanzando gnome-shell --wayland (DRM virtio, software GL)..."
/usr/bin/gnome-shell --wayland >/tmp/gnome-shell.log 2>&1 &
# GNOME_MODE=headless — EXPERIMENTO DECISIVO, no un modo de producción. El backend headless de
# mutter crea el seat con META_SEAT_NATIVE_FLAG_NO_LIBINPUT, o sea que SALTEA `init_libinput()`,
# que es justo el último paso del hilo de input antes de señalar `input_thread_initialized`
# (meta-seat-impl.c:3098). Si en headless aparece wayland-0, el bloqueo está en libinput/udev y no
# en el resto del arranque; si tampoco aparece, el problema es anterior (keymap, input settings).
case "${GNOME_MODE:-drm}" in
headless) SHELL_ARGS="--headless --virtual-monitor 1280x800" ;;
*) SHELL_ARGS="--wayland" ;;
esac
say "lanzando gnome-shell $SHELL_ARGS (modo=${GNOME_MODE:-drm})..."
/usr/bin/gnome-shell $SHELL_ARGS >/tmp/gnome-shell.log 2>&1 &
SHELL_PID=$!
# stream EN VIVO al serial (busybox sed no soporta -u ⇒ tail -f directo, sin pipes).
( echo "==== gnome-shell.log (stream vivo) ===="; tail -f /tmp/gnome-shell.log ) > /dev/ttyS0 2>/dev/null &
+4
View File
@@ -138,6 +138,10 @@ for f in passwd:messagebus:x:81:81:messagebus:/dev/null:/sbin/nologin group:mess
fi
done
# GNOME_MODE se hornea como fichero: el getty ejecuta gnome-start sin ambiente heredable.
printf 'GNOME_MODE=%s\n' "${GNOME_MODE:-drm}" > "$MERGED/etc/gnome-mode"
echo "==> modo de arranque: ${GNOME_MODE:-drm}"
echo "==> instalando /usr/bin/gnome-start"
install -Dm755 scripts/gnome/gnome-start-qemu.sh "$MERGED/usr/bin/gnome-start"