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 84Rust 832898 Definitions

⎇ 2be672415cc85ea8f745ae71d592485acd387c61 scripts/audit-needed.sh Shell · 63 lines · 3.4 KB History raw

audit-needed: cazar deps de ejecución colgantes — firefox no arranca en la distro 2be672415 · Sergio ·

1#!/usr/bin/env bash
2# audit-needed.sh — ¿hay artefactos que piden una librería que NADIE del corpus provee?
3#
4# ── POR QUÉ EXISTE ─────────────────────────────────────────────────────────────────────────────
5# Encontrado el 2026-09-06 corriendo el navegador, no leyendo: `atuq` moría con decenas de
6# «Error relocating: _ZNKSt5ctypeIcE13_M_widen_initEv: symbol not found». El binario sellado de
7# firefox declara
8#
9#     NEEDED libstdc++.so.6      NEEDED libgcc_s.so.1      NEEDED libc.so
10#
11# y las dos primeras NO EXISTEN en el store ni en ningún cierre: sólo en `.dev-fs/alpine`, o sea en
12# el LAB. Es exactamente la lección de `quitar-dep-no-apaga-funcion`: el proyecto la encuentra en el
13# sysroot del lab y el artefacto sella con un NEEDED que nadie provee.
14#
15# LO QUE LO HACE CARO ES QUE NINGUNA MÉTRICA LO VE. `build-state.json` dice `sealed`,
16# `verificar-repro.sh` dice que REPRODUCE bit a bit, los guardianes de la receta pasan — y el
17# binario no arranca en la distro. El verde responde «¿construye?», nunca «¿corre?».
18#
19# ── QUÉ MIDE, EXACTAMENTE ──────────────────────────────────────────────────────────────────────
20# Índice de sonames PROVISTOS = todo `*.so*` que haya en el store. Para cada ELF ejecutable del
21# store, sus `NEEDED` menos lo provisto. Lo que sobra es una dep de ejecución colgante.
22#
23# NO mira el lab a propósito: si mirara `.dev-fs/alpine` diría que todo está bien, que es justo la
24# ilusión que causó el problema. El lab es donde se CONSTRUYE, no donde se corre.
25#
26# Uso:  scripts/audit-needed.sh [--store DIR]        (sale 1 si hay colgantes)
27set -uo pipefail
28STORE="${STORE:-./store}"
29[ "${1:-}" = "--store" ] && STORE="$2"
30[ -d "$STORE" ] || { echo "no existe $STORE" >&2; exit 2; }
31
32tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
33
34# 1. Qué provee el corpus. Sólo el basename: es lo que el loader busca.
35find "$STORE" -maxdepth 5 -name '*.so' -o -maxdepth 5 -name '*.so.*' 2>/dev/null \
36  | sed 's|.*/||' | sort -u > "$tmp/provisto"
37
38echo "== sonames provistos por el store: $(wc -l < "$tmp/provisto")"
39
40# 2. Qué pide cada artefacto.
41colgantes=0
42for d in "$STORE"/*/; do
43  d=${d%/}; nombre=$(basename "$d"); receta=${nombre#*-}
44  falta=""
45  while IFS= read -r f; do
46    n=$(readelf -d "$f" 2>/dev/null | sed -n 's/.*Shared library: \[\(.*\)\]/\1/p')
47    for so in $n; do
48      grep -qxF "$so" "$tmp/provisto" && continue
49      case "$so" in libc.so|ld-musl*) continue ;; esac   # la libc la pone el sistema base
50      case " $falta " in *" $so "*) ;; *) falta="$falta $so" ;; esac
51    done
52  done < <(find "$d" -maxdepth 4 -type f -perm -u+x 2>/dev/null | head -12)
53  [ -n "$falta" ] && { printf '  ✗ %-24s pide y nadie provee:%s\n' "$receta" "$falta"; colgantes=$((colgantes+1)); }
54done
55
56echo "════════════════════════════════════════════════════════════"
57if [ "$colgantes" -eq 0 ]; then
58  echo "  ✅ sin deps de ejecución colgantes"
59else
60  echo "  ⚠ $colgantes artefacto(s) con deps de ejecución COLGANTES"
61  echo "     no arrancan fuera del lab, por más que sellen y reproduzcan"
62fi
63exit $([ "$colgantes" -eq 0 ] && echo 0 || echo 1)