Files
takana/recipes/incoming-gnome/accountsservice-fgetspent_r-musl.patch
sergioandClaude Opus 5 08fc1d4b92 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>
2026-07-29 11:54:52 -04:00

104 lines
4.2 KiB
Diff

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;
+}