gnome: esperar el NOMBRE de PolicyKit1 antes de lanzar a sus clientes

accounts-daemon y upowerd morían al arrancar: el shim de polkit se lanza en
background y tarda ~2s en adquirir org.freedesktop.PolicyKit1, ellos llamaban a
polkit_authority_get_sync() en ese hueco, D-Bus intentaba ACTIVAR el servicio y
fallaba con 'Failed to execute program ... Permission denied'.

Lo peor era el informe: los tres esperar_nombre estaban al final, así que para
cuando corrían el shim ya tenía el nombre y el resumen daba 'PolicyKit1 OK'
sobre dos clientes ya muertos. Un chequeo posterior a la carrera no la mide.

esperar_nombre pasa a definirse antes del primer daemon y el bloque de polkit
espera su propio nombre antes de que arranque ningún cliente suyo. Lanzar en
orden no es estar listo en orden.

De paso queda cerrado el ítem 4 del runbook: validación CON PANTALLA (DISP=gtk)
del Overview con el PID1 sellado nuevo — 689 colores distintos, con evidencia.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-03 10:05:29 -04:00
co-authored by Claude Opus 5
parent 84e088fd13
commit c0055331c7
3 changed files with 84 additions and 31 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+37 -2
View File
@@ -404,8 +404,43 @@ elige `/dev/dri/card0` como primaria sin quejarse. Es el rédito directo de la c
(ver el comentario de la receta: por qué NO se cherry-pickeó, con la medición). (ver el comentario de la receta: por qué NO se cherry-pickeó, con la medición).
**La lección general: antes de arreglar un WARN, buscá quién lo emite y si ya está arreglado **La lección general: antes de arreglar un WARN, buscá quién lo emite y si ya está arreglado
upstream.** Nuestro pin estaba 3951 commits detrás y nadie lo había mirado. upstream.** Nuestro pin estaba 3951 commits detrás y nadie lo había mirado.
4. Con la capa JS viva: validar CON PANTALLA (`DISP=gtk`), nunca sólo por serial — regla heredada de 4. **HECHO (2026-08-03)** validado CON PANTALLA de verdad (`DISP=gtk`, ventana en el laptop) y no
KDE ([[metal-dual-desktop-en-curso]]). sólo por `screendump`: el Overview pinta con el PID1 sellado nuevo, **689 colores distintos**, azul
GNOME `(2,60,136)` y grises del shell `(34,34,38)` al frente, cursor visible.
Evidencia: [`gnome-shell-qemu-2026-08-03-pid1-sellado.png`](../evidencia/gnome-shell-qemu-2026-08-03-pid1-sellado.png).
**Y aplicar la regla pagó otra vez**: el arranque destapó una regresión que el serial daba por
verde — ver abajo.
### La carrera de PolicyKit1: el resumen final decía OK y los clientes ya estaban muertos
Arrancando para la validación con pantalla, `accounts-daemon` y `upowerd` **murieron los dos**:
```
Error calling StartServiceByName for org.freedesktop.PolicyKit1:
Failed to execute program org.freedesktop.PolicyKit1: Permission denied
Failed to initialize daemon
```
El comentario del script ya decía que arje-polkit-compat «VA ANTES que accounts-daemon y upowerd», y
**iba antes** — en el orden de las líneas. Pero se lanza en background y tarda ~2 s en adquirir
`org.freedesktop.PolicyKit1`, mientras los otros dos arrancan de inmediato y llaman a
`polkit_authority_get_sync()` dentro de ese hueco. Sin dueño del nombre, D-Bus intenta ACTIVAR el
servicio, la activación falla, y los dos daemons se mueren.
**Lo peligroso no fue el fallo sino el informe.** Los tres `esperar_nombre` estaban todos al final:
para cuando corrían, el shim ya tenía el nombre y el resumen imprimía `bus: org.freedesktop.PolicyKit1
OK` sobre dos clientes que hacía rato eran cadáveres. Un chequeo que corre después de la carrera no la
mide.
El arreglo es mover la espera al PRODUCTOR: `esperar_nombre` se define antes del primer daemon, y el
bloque de polkit espera su propio nombre **antes** de que se lance ningún cliente suyo. Es la misma
lección de «un pid no es un servicio» aplicada del otro lado: *lanzar en orden no es estar listo en
orden*. Después del fix: `PolicyKit1 OK``accounts-daemon lanzado``upowerd sigue vivo`
`Accounts OK``UPower OK`.
Dato suelto que dejó el mismo arranque: **colord ahora MUERE** («colord MURIÓ al arrancar») en vez de
quedarse vivo sin adquirir el nombre. Su log sigue cortándose después de abrir las tres bases de datos.
Cambió el síntoma, no la causa conocida; el ítem sigue aparcado.
## Recetas nuevas de esta etapa ## Recetas nuevas de esta etapa
+47 -29
View File
@@ -214,14 +214,59 @@ export XDG_SESSION_ID=1
export XDG_SEAT=seat0 export XDG_SEAT=seat0
export XDG_VTNR=1 export XDG_VTNR=1
# ── ESPERAR EL NOMBRE, NO EL PROCESO ────────────────────────────────────────────────────────────
# El paso que faltaba, y es la otra mitad de «un pid no es un servicio»: comprobar que el daemon
# ADQUIRIÓ su nombre en el bus. Se le da tiempo y, si no aparece, se vuelca su log y la lista de
# nombres del bus — que es el dato que dice si el problema es «no arrancó», «arrancó y no pidió el
# nombre» o «lo pidió y se lo negaron».
# $3 = décimas de segundo a esperar (default 20 = 10 s). colord necesita más: en el PRIMER arranque
# crea sus tres bases de datos en /var/lib/colord y escanea los directorios de perfiles ICC antes de
# pedir el nombre, y con 10 s daba «NO apareció» sin estar colgado — o sea un falso negativo.
#
# Se define ACÁ ARRIBA —antes del primer daemon— y no al final junto a las llamadas, porque el bloque
# de polkit de abajo la necesita para poder ESPERAR antes de lanzar a sus clientes.
esperar_nombre() {
n="$1"; log="$2"; lim="${3:-20}"; i=0
while [ $i -lt "$lim" ]; do
if dbus-send --system --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.NameHasOwner "string:$n" 2>/dev/null \
| grep -q "boolean true"; then
say "bus: $n OK"
return 0
fi
i=$((i+1)); sleep 0.5
done
say "!! bus: $n NO apareció en $((lim/2))s"
[ -n "$log" ] && [ -s "$log" ] && dump "$log"
say "nombres en el bus de sistema:"
dbus-send --system --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames 2>/dev/null \
| tr -d '" ' | grep -v '^\s*$' > /tmp/busnames.log
dump /tmp/busnames.log
return 1
}
# arje-polkit-compat: el PolicyKit1 del fractal. **VA ANTES que accounts-daemon y upowerd**, y el # arje-polkit-compat: el PolicyKit1 del fractal. **VA ANTES que accounts-daemon y upowerd**, y el
# orden no es estético: los dos se bloquean en `polkit_authority_get_sync()` al arrancar, así que si # orden no es estético: los dos se bloquean en `polkit_authority_get_sync()` al arrancar, así que si
# `org.freedesktop.PolicyKit1` no está en el bus se quedan conectados pero SIN adquirir su nombre —y # `org.freedesktop.PolicyKit1` no está en el bus se quedan conectados pero SIN adquirir su nombre —y
# gnome-shell después espera 25 s por cada uno—. Nuestra receta `polkit` es libs-only a propósito # gnome-shell después espera 25 s por cada uno—. Nuestra receta `polkit` es libs-only a propósito
# (el demonio lo pone arje). Ojo: el shim autoriza TODO; ver recipes/arje-polkit-compat.toml. # (el demonio lo pone arje). Ojo: el shim autoriza TODO; ver recipes/arje-polkit-compat.toml.
#
# ⚠ Y «antes» tiene que ser POR EL NOMBRE, no por el orden de las líneas. Lanzarlo primero no alcanza:
# se lanza en background y tarda ~2 s en adquirir `org.freedesktop.PolicyKit1`, mientras accounts-daemon
# y upowerd arrancan de inmediato y llaman a `polkit_authority_get_sync()` en ese hueco. Entonces D-Bus
# intenta ACTIVAR el servicio (nadie tiene el nombre todavía) y falla:
# Error calling StartServiceByName for org.freedesktop.PolicyKit1:
# Failed to execute program org.freedesktop.PolicyKit1: Permission denied
# y los dos daemons se MUEREN («Failed to initialize daemon»). Después el shim adquiere el nombre
# tranquilo y el chequeo del final dice `PolicyKit1 OK` — o sea que el resumen final da verde y los
# clientes ya están muertos. La carrera es real y la ganaba cualquiera: es la misma lección de «un pid
# no es un servicio», aplicada al productor en vez de al consumidor.
if [ -x /usr/bin/arje-polkit-compat ]; then if [ -x /usr/bin/arje-polkit-compat ]; then
/usr/bin/arje-polkit-compat >/tmp/polkit-compat.log 2>&1 & /usr/bin/arje-polkit-compat >/tmp/polkit-compat.log 2>&1 &
say "arje-polkit-compat lanzado (pid $!)" say "arje-polkit-compat lanzado (pid $!)"
esperar_nombre org.freedesktop.PolicyKit1 /tmp/polkit-compat.log \
|| say "!! sigo igual: accounts-daemon y upowerd van a fallar al pedir la autoridad"
else else
say "!! sin arje-polkit-compat — accounts-daemon y upowerd se van a colgar pidiendo autorización" say "!! sin arje-polkit-compat — accounts-daemon y upowerd se van a colgar pidiendo autorización"
fi fi
@@ -266,34 +311,6 @@ else
say "!! sin upowerd — el shell va a esperar 25s a su activación D-Bus y seguir sin batería" say "!! sin upowerd — el shell va a esperar 25s a su activación D-Bus y seguir sin batería"
fi fi
# ── ESPERAR EL NOMBRE, NO EL PROCESO ────────────────────────────────────────────────────────────
# El paso que faltaba, y es la otra mitad de «un pid no es un servicio»: comprobar que el daemon
# ADQUIRIÓ su nombre en el bus. Se le da tiempo y, si no aparece, se vuelca su log y la lista de
# nombres del bus — que es el dato que dice si el problema es «no arrancó», «arrancó y no pidió el
# nombre» o «lo pidió y se lo negaron».
# $3 = décimas de segundo a esperar (default 20 = 10 s). colord necesita más: en el PRIMER arranque
# crea sus tres bases de datos en /var/lib/colord y escanea los directorios de perfiles ICC antes de
# pedir el nombre, y con 10 s daba «NO apareció» sin estar colgado — o sea un falso negativo.
esperar_nombre() {
n="$1"; log="$2"; lim="${3:-20}"; i=0
while [ $i -lt "$lim" ]; do
if dbus-send --system --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.NameHasOwner "string:$n" 2>/dev/null \
| grep -q "boolean true"; then
say "bus: $n OK"
return 0
fi
i=$((i+1)); sleep 0.5
done
say "!! bus: $n NO apareció en $((lim/2))s"
[ -n "$log" ] && [ -s "$log" ] && dump "$log"
say "nombres en el bus de sistema:"
dbus-send --system --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames 2>/dev/null \
| tr -d '" ' | grep -v '^\s*$' > /tmp/busnames.log
dump /tmp/busnames.log
return 1
}
# ── AUDIO: PipeWire (decisión del usuario, 2026-07-29) ────────────────────────────────────────── # ── AUDIO: PipeWire (decisión del usuario, 2026-07-29) ──────────────────────────────────────────
# Van TRES procesos y el orden importa, porque cada uno es cliente del anterior: # Van TRES procesos y el orden importa, porque cada uno es cliente del anterior:
# 1. `pipewire` — el servidor. Crea $XDG_RUNTIME_DIR/pipewire-0. # 1. `pipewire` — el servidor. Crea $XDG_RUNTIME_DIR/pipewire-0.
@@ -394,7 +411,8 @@ else
fi fi
esperar_nombre org.freedesktop.login1 /tmp/logind-compat.log esperar_nombre org.freedesktop.login1 /tmp/logind-compat.log
esperar_nombre org.freedesktop.PolicyKit1 /tmp/polkit-compat.log # PolicyKit1 NO se chequea acá: ya se esperó arriba, antes de lanzar a sus clientes. Chequearlo sólo
# al final era precisamente lo que dejaba pasar la carrera con verde.
esperar_nombre org.freedesktop.Accounts /tmp/accounts-daemon.log esperar_nombre org.freedesktop.Accounts /tmp/accounts-daemon.log
esperar_nombre org.freedesktop.UPower /tmp/upowerd.log esperar_nombre org.freedesktop.UPower /tmp/upowerd.log
esperar_nombre org.freedesktop.ColorManager /tmp/colord.log 80 # 40 s: ver el comentario esperar_nombre org.freedesktop.ColorManager /tmp/colord.log 80 # 40 s: ver el comentario