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 1411Shell 141Markdown 85Rust 842918 Definiciones

atuq: el lanzador deja de ser un symlink, y un runner para abrirlo en la pantalla que ya tenés

Dos cosas que salieron de intentar ABRIRLO, que es lo único que distingue «sellado» de «usable».

1. EL LANZADOR. Con `/usr/bin/atuq` como symlink, el navegador moría antes de pintar:

     XPCOMGlueLoad error for file /usr/lib/atuq/libmozsandbox.so:
     Error loading shared library libnspr4.so: No such file or directory

   El motor carga sus propias librerías desde `/usr/lib/atuq` y ni el binario ni esas `.so` traen
   RPATH/RUNPATH — comprobado con `readelf -d`, no supuesto. Pasa a ser un script que exporta
   `LD_LIBRARY_PATH` (lo mismo que hacen Debian y Fedora) y hace `exec`, para que el proceso que
   queda sea el motor y `/proc/self/exe` siga resolviendo el appdir. El `LD_LIBRARY_PATH` además
   tiene que HEREDARSE: Firefox lanza un proceso por pestaña y todos cargan las mismas librerías.
   La alternativa limpia es grabar RPATH=$ORIGIN con `patchelf` —es lo que hace Alpine— pero
   `patchelf` todavía no existe como receta del corpus; cuando exista, esto vuelve a ser un symlink.

2. `scripts/atuq-nested.sh` — hidrata el cierre de runtime y abre atuq como ventana anidada en el
   compositor que ya está delante (waypipe, mirada, sway). Trae dos cosas aprendidas a golpes:

   · EL ROOTFS VA EN EL MISMO MOUNT QUE EL STORE. `hydrate` proyecta con hardlinks y `linkat()`
     rechaza cruzar un punto de montaje aunque sea el mismo filesystem. Acá el store es /dev/sdb
     bind-monteado y `work/` vive en /dev/sdc: hidratar a `work/…` muere con «Invalid cross-device
     link (os error 18)». El volumen entero está en /mnt/cosecha, así que el rootfs va ahí. Se
     comprueba con `findmnt -T`, nunca con `stat -c %d`.
   · `dejavu-fonts` va en las raíces por necesidad, no por completismo: un navegador sin una sola
     fuente arranca, pinta y muestra cuadraditos. Ya nos costó una tarde en GNOME.

   Y no saltea en silencio: si falta un artefacto de la lista, sale con error en vez de armar un
   rootfs al que le faltan tres paquetes y falla tres capas más abajo.

0f7d19232ea4bb2e9c0254e6e79296b272212c6e · por Sergio · (hace 1 mes) · padre c9c6727c3 · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

3 archivos · +116 −1

diff --git a/recipes/atuq.toml b/recipes/atuq.toml
index 59ec0bb1..6d190e49 100644
--- a/recipes/atuq.toml
+++ b/recipes/atuq.toml
@@ -85,7 +85,11 @@ python3 /src/tools/rebrand.py "$DST" /src /out
 # ── INTEGRACIÓN CON EL ESCRITORIO ─────────────────────────────────────────────────────────────
 mkdir -p /out/usr/bin /out/usr/share/applications
 cp /src/atuq.desktop /out/usr/share/applications/atuq.desktop
-ln -sf ../lib/atuq/atuq /out/usr/bin/atuq
+# El lanzador es un script y no un symlink: ni el binario ni sus `.so` traen RPATH (comprobado con
+# `readelf -d`), así que sin `LD_LIBRARY_PATH` el motor no encuentra su propio libnspr4 y muere en
+# XPCOMGlueLoad antes de pintar nada. El porqué completo está en el propio fichero.
+cp /src/bin/atuq /out/usr/bin/atuq
+chmod 0755 /out/usr/bin/atuq
 
 # ── INVENTARIO ────────────────────────────────────────────────────────────────────────────────
 # Lo que distingue este artefacto de su base, listado con tamaños, para que el log del build
@@ -96,6 +100,7 @@ for f in defaults/pref/autoconfig.js atuq.cfg chrome/atuq.css distribution/polic
   echo "  $f ($(wc -c < "$DST/$f") bytes)"
 done
 [ -x "$DST/atuq" ] || { echo "atuq: el binario renombrado no quedó ejecutable" >&2; exit 1; }
+[ -x /out/usr/bin/atuq ] || { echo "atuq: el lanzador no quedó ejecutable" >&2; exit 1; }
 grep -q '^Name=atuq' "$DST/application.ini" || { echo "atuq: application.ini no quedó rebrandeado" >&2; exit 1; }
 '''
 
diff --git a/recipes/atuq/bin/atuq b/recipes/atuq/bin/atuq
new file mode 100755
index 00000000..ac19b1e6
--- /dev/null
+++ b/recipes/atuq/bin/atuq
@@ -0,0 +1,24 @@
+#!/bin/sh
+# Lanzador de atuq. Va a /usr/bin/atuq.
+#
+# ── POR QUÉ NO ES UN SYMLINK (que es lo que era en la v0.1) ────────────────────────────────────
+# El motor carga sus propias librerías —libnspr4, libnss3, libmozsandbox…— desde `/usr/lib/atuq`, y
+# ni el binario ni esas `.so` traen `RPATH`/`RUNPATH`: se comprobó con `readelf -d` y no hay
+# ninguno. Con el symlink, el navegador moría antes de pintar nada:
+#
+#     XPCOMGlueLoad error for file /usr/lib/atuq/libmozsandbox.so:
+#     Error loading shared library libnspr4.so: No such file or directory
+#
+# El `LD_LIBRARY_PATH` es además lo que necesitan los procesos HIJOS: Firefox lanza un proceso por
+# pestaña y todos cargan las mismas librerías, así que tiene que heredarse.
+#
+# La alternativa más limpia sería grabar `RPATH=$ORIGIN` en los ELF —es lo que hace el APKBUILD de
+# Alpine, que trae `patchelf` en sus makedepends—, pero `patchelf` no existe todavía como receta del
+# corpus. Cuando exista, esto se puede simplificar a un symlink otra vez.
+#
+# `exec` y no una llamada normal: así el proceso que queda es el motor, `/proc/self/exe` apunta a
+# `/usr/lib/atuq/atuq` y Gecko resuelve su appdir correctamente. Con un `sh` de por medio quedaría
+# un proceso zombi de más y el nombre en `ps` sería el del script.
+LD_LIBRARY_PATH="/usr/lib/atuq${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
+export LD_LIBRARY_PATH
+exec /usr/lib/atuq/atuq "$@"
diff --git a/scripts/atuq-nested.sh b/scripts/atuq-nested.sh
new file mode 100755
index 00000000..863e5712
--- /dev/null
+++ b/scripts/atuq-nested.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# atuq-nested.sh — hidrata `atuq` con su cierre de runtime y lo abre como VENTANA ANIDADA en el
+# compositor que ya tenés delante (waypipe, mirada, sway…). No toca la GPU como master: atuq es un
+# cliente wayland más.
+#
+#   scripts/atuq-nested.sh            # abre atuq y lo deja corriendo SECS segundos
+#   SECS=60 scripts/atuq-nested.sh
+#
+# ── POR QUÉ HIDRATAR Y NO EJECUTAR DESDE EL STORE ──────────────────────────────────────────────
+# El binario es musl y el host es glibc: no hay `/lib/ld-musl-x86_64.so.1` afuera. Un artefacto que
+# no arranca desde la ruta del store NO está roto — corre HIDRATADO, y ésa es la prueba que vale.
+#
+# ── LAS FUENTES NO SON OPCIONALES ──────────────────────────────────────────────────────────────
+# Un navegador sin una sola fuente arranca, pinta y muestra cuadraditos. Es el modo de fallo que ya
+# nos costó una tarde en GNOME: la clausura decía 100% y la pantalla decía otra cosa. `dejavu-fonts`
+# va en la lista de raíces por eso, no por completismo.
+set -eu
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
+H="$ROOT/target/release/hammer"
+
+# ── EL ROOTFS VA EN EL MISMO MOUNT QUE EL STORE, Y NO ES UN CAPRICHO ───────────────────────────
+# `hydrate` proyecta con HARDLINKS, y `linkat()` rechaza cruzar un punto de montaje aunque los dos
+# lados sean el mismo filesystem. Acá el store es `/dev/sdb` bind-monteado en `hammer/store`
+# mientras `work/` vive en `/dev/sdc`: hidratar a `work/…` muere con
+# «Invalid cross-device link (os error 18)» — medido, no supuesto.
+# El volumen entero está montado en /mnt/cosecha, así que store y destino comparten mount ahí.
+# Se comprueba con `findmnt -T`, NUNCA con `stat -c %d` (que dice el device, no el mount).
+STORE="${STORE:-/mnt/cosecha/store}"
+RFS="${RFS:-/mnt/cosecha/escritorios/atuq-rootfs}"
+ALPINE="$ROOT/.dev-fs/alpine"
+SECS="${SECS:-25}"
+URL="${URL:-about:support}"
+
+# Las raíces: atuq y lo que su motor abre en RUNTIME. `wayland-protocols` y compañía no están —son
+# de build— y meterlas engordaría el rootfs sin cambiar nada de lo que se ve.
+RAICES="atuq gtk3 atk gdk-pixbuf pango cairo libepoxy glib-shared pcre2-shared libffi-shared
+        zlib-shared harfbuzz fribidi freetype-shared fontconfig-shared pixman libpng-shared
+        libjpeg-turbo-shared wayland libxkbcommon mesa libdrm dbus pipewire pulseaudio alsa-lib
+        libxml2-shared dejavu-fonts"
+
+if [ "${REHIDRATAR:-0}" = "1" ] || [ ! -d "$RFS/usr/lib/atuq" ]; then
+  echo "==> hidratando $(echo $RAICES | wc -w) raíces en $RFS"
+  rm -rf "$RFS"; mkdir -p "$RFS"
+  faltan=""
+  for r in $RAICES; do
+    h="$("$H" --store "$STORE" hash "recipes/$r.toml" 2>/dev/null | tail -1 | sed 's/^b3://')"
+    if [ -z "$h" ] || [ ! -d "$STORE/$h-$r" ]; then faltan="$faltan $r"; continue; fi
+    "$H" --store "$STORE" hydrate "$h" --into "$RFS" >/dev/null
+  done
+  # Un nodo sin artefacto NO se saltea en silencio: un rootfs al que le faltan tres paquetes
+  # arranca y falla tres capas más abajo.
+  [ -z "$faltan" ] || { echo "✗ faltan artefactos:$faltan" >&2; exit 1; }
+  echo "==> hidratado: $(find "$RFS" -type f | wc -l) ficheros"
+fi
+
+[ -n "${WAYLAND_DISPLAY:-}" ] || { echo "✗ no hay WAYLAND_DISPLAY — esto necesita una pantalla" >&2; exit 1; }
+SOCK="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/$WAYLAND_DISPLAY"
+[ -S "$SOCK" ] || { echo "✗ no existe el socket $SOCK" >&2; exit 1; }
+echo "==> pantalla: $SOCK"
+
+exec bwrap --overlay-src "$ALPINE" --overlay-src "$RFS" --tmp-overlay / \
+  --dev-bind /dev /dev --proc /proc --bind /sys /sys --tmpfs /tmp --tmpfs /run \
+  --ro-bind "$SOCK" /run/wayland-0 \
+  --uid 0 --gid 0 \
+  --setenv PATH /usr/bin:/bin:/usr/sbin:/sbin \
+  --setenv LD_LIBRARY_PATH /usr/lib:/lib \
+  --setenv XDG_RUNTIME_DIR /run --setenv WAYLAND_DISPLAY wayland-0 \
+  --setenv XDG_DATA_DIRS /usr/share --setenv HOME /root \
+  --setenv GDK_BACKEND wayland --setenv MOZ_ENABLE_WAYLAND 1 \
+  --setenv LIBGL_DRIVERS_PATH /usr/lib/dri \
+  --setenv MOZ_LOG_FILE /tmp/atuq-moz.log \
+  sh -c '
+    mkdir -p /root /run/cache /etc
+    [ -s /etc/machine-id ] || tr -d - < /proc/sys/kernel/random/uuid > /etc/machine-id
+    echo "=== identidad del artefacto ==="
+    sed -n "/^\[App\]/,/^$/p" /usr/lib/atuq/application.ini
+    echo "=== fuentes visibles ==="
+    fc-list 2>/dev/null | wc -l
+    timeout '"$SECS"' /usr/bin/atuq --no-remote '"$URL"' >/tmp/atuq.log 2>&1 &
+    PID=$!
+    sleep 8
+    echo "=== ¿vive? ==="
+    if kill -0 $PID 2>/dev/null; then echo "  ✓ atuq corriendo (PID $PID) — mirá tu pantalla"; else echo "  ✗ murió"; fi
+    echo "=== log ==="; tail -25 /tmp/atuq.log
+    wait $PID 2>/dev/null || true
+  '