gnome: accountsservice SELLA (b3:0328b0d0) — cae la frontera de la C-ABI de logind
Los dos huecos que bloqueaban esta receta estaban medidos desde ayer símbolo por
símbolo, y ninguno era de accountsservice. Los dos cerrados:
1. libelogind pasa de 14 a 22 símbolos (tawasuyu 8d892151b, re-pineado a b56aeff46,
re-sellado b3:9650ee06). Los ocho nuevos son los que usa accountsservice, con
`sd_login_monitor_*` implementado sobre inotify en /run/systemd/{sessions,seats,users}.
2. `fgetspent_r` no existe en musl ⇒ accountsservice-fgetspent_r-musl.patch. NO es
sustituir por `fgetspent()` a secas: daemon.c guarda los buffers en un GHashTable
y `fgetspent()` devuelve un struct estático que se reescribe en cada llamada —
todas las entradas de la tabla apuntarían al último usuario leído. El parche copia
el registro al buffer del llamador, y sigue el patrón que el propio accountsservice
ya usa para /etc/passwd (`src/fgetpwent.c` bajo `#ifndef HAVE_FGETPWENT`).
Produce `AccountsService-1.0.typelib`, que es exactamente lo que la capa JS pedía.
De paso, dos cosas que este frente enseñó y quedan horneadas:
- libelogind necesitaba `cargo_vendor_dir` (el `vendor/` de smithay entró a la rama
selfhost con el merge de main; el mismo choque que ya tenía arje-logind-compat).
- `hydrate-gnome.sh` ahora hidrata DOS raíces por defecto. accountsservice no es dep
de build de nadie: es dep de RUNTIME, resuelta por gjs al arrancar. **El cierre de
build no es el cierre de runtime**, y lo que el shell carga por `imports.gi.*` hay
que nombrarlo a mano o no entra al rootfs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
accountsservice bajo musl: `fgetspent_r` no existe.
|
||||
|
||||
QUÉ ES: la variante reentrante de la API de /etc/shadow. Es **extensión de glibc** — musl provee
|
||||
`fgetspent()` (no reentrante) y `getspnam_r()`, pero no ésta. La usa `src/daemon.c` en el bucle que
|
||||
lee /etc/shadow para decidir qué cuentas son locales.
|
||||
|
||||
POR QUÉ NO ALCANZA CON USAR `fgetspent()` A SECAS: el llamador GUARDA los buffers. Cada iteración
|
||||
reserva un `shadow_entry_buffers` y lo mete en un GHashTable indexado por nombre de usuario; después
|
||||
de leer el fichero entero, consulta esa tabla. `fgetspent()` devuelve un puntero a un `struct spwd`
|
||||
ESTÁTICO cuyas cadenas se reescriben en la llamada siguiente, así que sustituirla a secas dejaría
|
||||
todas las entradas de la tabla apuntando al último usuario leído. Silencioso y falso — justo lo que
|
||||
no se puede permitir un servicio que responde "¿esta cuenta es local?".
|
||||
|
||||
LO QUE HACE EL PARCHE: implementa `fgetspent_r()` sobre `fgetspent()`, copiando las dos cadenas del
|
||||
registro (`sp_namp`, `sp_pwdp`) al buffer que pasa el llamador y los campos numéricos por valor. Con
|
||||
eso cada entrada de la tabla es dueña de su copia y la semántica vuelve a ser la de glibc.
|
||||
|
||||
DÓNDE VIVE: en `src/fgetspent_r.c`, incluido desde `daemon.c` bajo `#ifndef HAVE_FGETSPENT_R`. **Es
|
||||
el patrón que accountsservice YA usa**: trae un `src/fgetpwent.c` propio incluido bajo
|
||||
`#ifndef HAVE_FGETPWENT` para el mismo problema con /etc/passwd (upstream lo escribió para plataformas
|
||||
sin esa función). O sea que el parche no inventa una estructura: extiende la que el proyecto eligió.
|
||||
El símbolo `HAVE_FGETSPENT_R` no lo define nunca su meson, así que la rama entra siempre; se deja el
|
||||
`#ifndef` igual, para que el día que lo definan esto se apague solo.
|
||||
|
||||
CONTRATO: 0 si leyó un registro; `ENOENT` en fin de fichero; `ERANGE` si el buffer del llamador se
|
||||
queda corto — los mismos valores que devuelve glibc, que es lo que `daemon.c` espera (`ret == 0`, y
|
||||
si no corta el bucle salvo EINTR).
|
||||
|
||||
diff -Naur a/src/daemon.c b/src/daemon.c
|
||||
--- a/src/daemon.c
|
||||
+++ b/src/daemon.c
|
||||
@@ -175,6 +175,10 @@
|
||||
#include "fgetpwent.c"
|
||||
#endif
|
||||
|
||||
+#ifndef HAVE_FGETSPENT_R
|
||||
+#include "fgetspent_r.c"
|
||||
+#endif
|
||||
+
|
||||
#ifndef MAX_LOCAL_USERS
|
||||
#define MAX_LOCAL_USERS 50
|
||||
#endif
|
||||
diff -Naur a/src/fgetspent_r.c b/src/fgetspent_r.c
|
||||
--- a/src/fgetspent_r.c 1969-12-31 20:00:00.000000000 -0400
|
||||
+++ b/src/fgetspent_r.c
|
||||
@@ -0,0 +1,57 @@
|
||||
+/* fgetspent_r() para musl — ver recipes/incoming-gnome/accountsservice-fgetspent_r-musl.patch
|
||||
+ *
|
||||
+ * musl no trae esta extension de glibc. Se implementa sobre fgetspent(), que si tiene, copiando
|
||||
+ * el registro al buffer del llamador: daemon.c GUARDA esos buffers en un GHashTable, asi que no
|
||||
+ * puede quedarse con el struct estatico que fgetspent() reusa en cada llamada.
|
||||
+ */
|
||||
+
|
||||
+static int
|
||||
+fgetspent_r (FILE *fp,
|
||||
+ struct spwd *result_buf,
|
||||
+ char *buffer,
|
||||
+ size_t buflen,
|
||||
+ struct spwd **result)
|
||||
+{
|
||||
+ struct spwd *ent;
|
||||
+ size_t namp_len;
|
||||
+ size_t pwdp_len;
|
||||
+ size_t needed;
|
||||
+
|
||||
+ if (result != NULL) {
|
||||
+ *result = NULL;
|
||||
+ }
|
||||
+ if (fp == NULL || result_buf == NULL || buffer == NULL || result == NULL) {
|
||||
+ return EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ errno = 0;
|
||||
+ ent = fgetspent (fp);
|
||||
+ if (ent == NULL) {
|
||||
+ /* Fin de fichero (o linea invalida): glibc devuelve ENOENT. */
|
||||
+ return errno != 0 ? errno : ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ namp_len = ent->sp_namp != NULL ? strlen (ent->sp_namp) + 1 : 0;
|
||||
+ pwdp_len = ent->sp_pwdp != NULL ? strlen (ent->sp_pwdp) + 1 : 0;
|
||||
+ needed = namp_len + pwdp_len;
|
||||
+ if (needed > buflen) {
|
||||
+ return ERANGE;
|
||||
+ }
|
||||
+
|
||||
+ *result_buf = *ent;
|
||||
+ result_buf->sp_namp = NULL;
|
||||
+ result_buf->sp_pwdp = NULL;
|
||||
+
|
||||
+ if (namp_len > 0) {
|
||||
+ memcpy (buffer, ent->sp_namp, namp_len);
|
||||
+ result_buf->sp_namp = buffer;
|
||||
+ buffer += namp_len;
|
||||
+ }
|
||||
+ if (pwdp_len > 0) {
|
||||
+ memcpy (buffer, ent->sp_pwdp, pwdp_len);
|
||||
+ result_buf->sp_pwdp = buffer;
|
||||
+ }
|
||||
+
|
||||
+ *result = result_buf;
|
||||
+ return 0;
|
||||
+}
|
||||
@@ -50,27 +50,29 @@
|
||||
#
|
||||
# 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:
|
||||
# ══ LOS DOS HUECOS QUE HUBO QUE TAPAR, Y NINGUNO ERA DE accountsservice ═════════════════════════
|
||||
# El configure pasaba entero desde el principio; lo que cortaba era el COMPILE, por dos motivos
|
||||
# independientes, los dos de NUESTRA capa de compatibilidad. Se cuentan acá porque el trabajo real
|
||||
# de esta receta está afuera de ella:
|
||||
#
|
||||
# 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:
|
||||
# 1. LA C-ABI DE sd-login SE QUEDABA CORTA. `libelogind` (arje-sdlogin-compat) exportaba 14 símbolos
|
||||
# —los que necesitaba mutter— y accountsservice usa OCHO que no estaban:
|
||||
# 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.
|
||||
# Los cinco de `sd_login_monitor_*` eran la parte con enjundia: no son getters sobre ficheros sino
|
||||
# una API de NOTIFICACIÓN (un fd que se mete en un poll y despierta cuando cambia el estado de
|
||||
# sesiones). Implementados con inotify sobre /run/systemd/{sessions,seats,users}, que es donde
|
||||
# vive ese estado. Ahora libelogind exporta 22.
|
||||
#
|
||||
# 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.
|
||||
# 2. `fgetspent_r` NO EXISTE EN musl (extensión de glibc; la usa src/daemon.c:265). Se tapa con
|
||||
# `accountsservice-fgetspent_r-musl.patch`, que la implementa sobre el `fgetspent()` que musl SÍ
|
||||
# tiene, copiando el registro al buffer del llamador. La copia no es adorno: daemon.c GUARDA esos
|
||||
# buffers en un GHashTable, y `fgetspent()` devuelve un struct estático que se reescribe en cada
|
||||
# llamada. El parche sigue el patrón que el propio accountsservice ya usa para /etc/passwd
|
||||
# (`src/fgetpwent.c` incluido bajo `#ifndef HAVE_FGETPWENT`).
|
||||
#
|
||||
# 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.
|
||||
# SELLA: b3:0328b0d0. Produce `AccountsService-1.0.typelib`, que es lo que la capa JS del shell pedía.
|
||||
#
|
||||
# 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
|
||||
@@ -82,6 +84,7 @@ version = "23.13.9"
|
||||
[source]
|
||||
tarball = "https://www.freedesktop.org/software/accountsservice/accountsservice-23.13.9.tar.xz"
|
||||
sha256 = "adda4cdeae24fa0992e7df3ffff9effa7090be3ac233a3edfdf69d5a9c9b924f"
|
||||
patches = ["accountsservice-fgetspent_r-musl.patch"]
|
||||
|
||||
[build]
|
||||
compiler = "zig-cc"
|
||||
|
||||
@@ -27,7 +27,14 @@ version = "0.0.1"
|
||||
# versiona el `Cargo.lock` de la raíz: sin él, el vendoreo `--locked` del fetch no es reproducible
|
||||
# (el monorepo lo gitignora en main).
|
||||
repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
|
||||
commit = "0c9857879ae3a115f9f4c10fe2ea0ab7769763fb"
|
||||
commit = "b56aeff46a8f707d08188f807aaabeff06faddad"
|
||||
# El monorepo COMMITEA su propio `vendor/` (`[patch.crates-io] smithay = { path = "vendor/smithay" }`,
|
||||
# la copia parcheada que mirada necesita para el tearing) y el `cargo vendor` de hammer escribe ahí
|
||||
# por defecto, pisándolo: el build muere con `failed to read /src/vendor/smithay/.cargo-checksum.json`
|
||||
# al resolver la dep git de taffy. Se vendorea a un subdir aparte, igual que arje-logind-compat.
|
||||
# Apareció recién ahora porque el `vendor/` entró a esta rama con el merge de main, no antes.
|
||||
# Ver [[hammer-cargo-vendor-clobbers-project-vendor]].
|
||||
cargo_vendor_dir = ".hammer-cargo-vendor"
|
||||
|
||||
[build]
|
||||
compiler = "zig-cc"
|
||||
|
||||
@@ -19,7 +19,17 @@ set -uo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
||||
RFS="${RFS:-work/gnome-rootfs}"; STORE="${STORE:-./store}"; LINK="${LINK:-static}"
|
||||
HAMMER="${HAMMER:-./target/release/hammer}"; KEEP="${KEEP:-0}"
|
||||
TARGETS=("${@:-recipes/incoming-gnome/gnome-shell.toml}")
|
||||
# Por defecto se hidratan DOS raíces, no una. accountsservice no es dep de build de gnome-shell —no
|
||||
# aparece en su meson.build ni en su cierre— sino dep de RUNTIME: la capa JS del shell hace
|
||||
# `imports.gi.AccountsService` y gjs resuelve el typelib al arrancar. Todo lo que el shell carga por
|
||||
# `imports.gi.*` es invisible al grafo de deps, así que hay que nombrarlo acá o no entra al rootfs.
|
||||
# El cierre de BUILD no es el cierre de RUNTIME; ésta es la lista de las raíces que faltan.
|
||||
# (no `${@:-...}`: con dos valores por defecto y comillas, bash los pasaría como UN solo argumento)
|
||||
if [ $# -gt 0 ]; then
|
||||
TARGETS=("$@")
|
||||
else
|
||||
TARGETS=(recipes/incoming-gnome/gnome-shell.toml recipes/incoming-gnome/accountsservice.toml)
|
||||
fi
|
||||
|
||||
# ── cierre transitivo por el grafo de recetas, en orden topológico ──────────────────────────────
|
||||
PLAN=$(python3 - "${TARGETS[@]}" <<'PY'
|
||||
|
||||
Reference in New Issue
Block a user