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 1463Shell 157Markdown 91Rust 853029 Sutichaykuna

⎇ ce2668598e4d8b60e5e070a0e422cd1dd12f0033 scripts/servidor/arje-botones.sh Shell · 136 siq'ikuna · 6.8 KB Ñawpa willay ch'uya

fix(servidor): la imagen ya se puede reiniciar, y el tope de 10 Claudes deja de ser una pared 28cd6d029 · Sergio ·

1#!/bin/sh
2# =============================================================================
3#  arje-botones.sh — que `reboot`, `poweroff`, `halt` y `shutdown` hagan algo
4#  en una imagen cuyo PID 1 es `arje-zero`. Se corre SOBRE UN ROOTFS, al armar
5#  la imagen, no sobre la máquina viva.
6#
7#  Uso:  ./scripts/servidor/arje-botones.sh <rootfs>
8#
9#  ── POR QUÉ EXISTE (2026-09-25) ─────────────────────────────────────────────
10#
11#  `servidor-image.sh` §3 ya se ocupa de que `/sbin/init` sea `arje-zero`. Esto
12#  es el paso siguiente y sin él la imagen queda con un defecto silencioso: con
13#  arje-zero de PID 1, **`reboot` no reinicia y no dice nada**.
14#
15#  La causa, medida en `takana` el 2026-09-25 (y antes en `momento`, 26-ago):
16#  el `reboot` de la caja —sea el de OpenRC, sea el applet de busybox— termina
17#  mandándole una señal a PID 1. arje-zero atrapa **SIGINT y sólo SIGINT**
18#  (`/proc/1/status` → `SigCgt: 0000000000000442`; los otros dos bits son el
19#  SIGBUS/SIGSEGV que instala el runtime de Rust). Y el kernel **descarta** las
20#  señales sin handler dirigidas a PID 1 — no es que falle: no pasa nada, sin
21#  error y sin mensaje. Es el peor modo de fallar, y costó una tarde cada vez.
22#
23#  Del otro lado, `arje-zero::apagar_maquina()` está implementado de verdad
24#  (cascade topológico, kill(-1), sync, remount-ro, reboot(2)) y se dispara
25#  justo con SIGINT, que es lo que el kernel entrega ante Ctrl+Alt+Del con
26#  `kernel.ctrl-alt-del = 0`. O sea: el camino existía entero y no estaba
27#  conectado a ningún botón. Esto lo conecta.
28#
29#  ⚠ ASIMETRÍA QUE NO SE PUEDE TAPAR: hay señal para REINICIAR y no la hay para
30#  APAGAR. Por eso `poweroff` va por SysRq y **se saltea el cascade**. El camino
31#  bueno es `BusRequest::PowerOff` por el bus de arje; cuando `arje-ctl` esté en
32#  la imagen, el shim de poweroff debería delegarle en vez de hacer esto.
33#
34#  ⚠ EL BOTÓN DEL PANEL DEL PROVEEDOR NO SE ARREGLA ACÁ, y no por falta de
35#  ganas: en una caja musl `acpid` es el applet de **busybox**, que encuentra su
36#  handler y **no puede ejecutarlo** (`/bin/sh: can't open './PWRF/00000080':
37#  No file descriptors available` — EMFILE; a mano, parado en el mismo
38#  directorio, el mismo `/bin/sh` lo corre perfecto). Es un defecto de su
39#  `spawn()`. Hasta que haya un `acpid` de verdad, del panel sólo sirve «Reset»,
40#  que es el hipervisor. La línea de comandos sí queda arreglada, que es lo que
41#  este script promete.
42#
43#  ⚠ VAN EN /usr/local/bin A PROPÓSITO: el `secure_path` de sudo lo mira ANTES
44#  que /usr/bin y /sbin, así que estos ganan sin pisar el `reboot` de la caja —
45#  que sigue ahí para el día que el init sea otro.
46#
47#  ⚠ ESTO ES UNA COPIA de la lógica de `tawasuyu/scripts/install-arje-reboot.sh`
48#  (que hace lo mismo sobre una máquina VIVA). Está duplicada a propósito: al
49#  armar la imagen el repo tawasuyu no existe, y una imagen que sólo reinicia si
50#  alguien se acuerda de correr un script de OTRO repo es la clase de arreglo
51#  que se pierde en la siguiente instalación. Si tocás los shims, tocá los dos.
52# =============================================================================
53set -eu
54
55RFS=${1:-}
56[ -n "$RFS" ] || { echo "uso: $0 <rootfs>" >&2; exit 2; }
57[ -d "$RFS" ] || { echo "!! no existe el rootfs '$RFS'" >&2; exit 1; }
58
59install -d -m 755 "$RFS/usr/local/bin"
60
61cat > "$RFS/usr/local/bin/reboot" <<'SH'
62#!/bin/sh
63# reboot — el de verdad, para una máquina con arje-zero de PID 1.
64# El de la caja le manda una señal a PID 1 que arje-zero no atrapa, y el kernel
65# la descarta: vuelve el prompt y no pasa nada. SIGINT es la que sí atiende, y
66# de ahí sale su apagar_maquina(): cascade, kill(-1), sync, remount-ro, reboot(2).
67[ "$(id -u)" = 0 ] || { echo "reboot: hace falta root (probá: sudo reboot)" >&2; exit 1; }
68[ "$(ps -p 1 -o comm=)" = "arje-zero" ] || {
69  echo "reboot: el PID 1 NO es arje-zero — este shim no aplica." >&2
70  echo "        usá el reboot de tu init: /sbin/reboot" >&2
71  exit 1
72}
73sync
74echo "reboot: SIGINT a PID 1 (arje-zero) — reinicio ordenado en curso" >&2
75exec kill -INT 1
76SH
77
78cat > "$RFS/usr/local/bin/poweroff" <<'SH'
79#!/bin/sh
80# poweroff — apaga de verdad, PERO SIN el cascade de arje: arje-zero instala
81# SIGINT y sólo SIGINT, así que no hay señal de apagado que mandarle. Va directo
82# al kernel por SysRq: 'u' = remount-ro de emergencia (evita el fsck del próximo
83# arranque), 'o' = apagar. Los servicios NO reciben su SIGTERM. El camino bueno
84# es BusRequest::PowerOff por el bus de arje, cuando arje-ctl esté en la imagen.
85[ "$(id -u)" = 0 ] || { echo "poweroff: hace falta root" >&2; exit 1; }
86[ "$(cat /proc/sys/kernel/sysrq 2>/dev/null)" = 0 ] && {
87  echo "poweroff: kernel.sysrq está en 0 — no hay por dónde. Ponelo en 1." >&2
88  exit 1
89}
90echo "poweroff: sin cascade (arje no expone señal de apagado) — sync + SysRq u,o" >&2
91sync
92echo u > /proc/sysrq-trigger
93sleep 1
94echo o > /proc/sysrq-trigger
95SH
96
97cat > "$RFS/usr/local/bin/shutdown" <<'SH'
98#!/bin/sh
99# shutdown — traduce las banderas de siempre a los dos shims que sí andan.
100# No implementa el retardo (`shutdown -r +5`): esta máquina no tiene un init que
101# lo agende, y fingir que sí es cómo se llega a «creí que se iba a apagar».
102# Sin argumentos NO se apaga nada: el shutdown de siempre exige un TIME, y un
103# shim que apague en el acto ante un `shutdown` tipeado a medias es una trampa.
104[ $# -gt 0 ] || { echo "uso: shutdown [-r|-h] now   (el retardo no está implementado)" >&2; exit 1; }
105modo=poweroff
106for a in "$@"; do
107  case "$a" in
108    -r) modo=reboot ;;
109    -h|-P|-H) modo=poweroff ;;
110    -c) echo "shutdown: acá no hay nada agendado que cancelar." >&2; exit 0 ;;
111    now|-*) ;;
112    +*|[0-9]*:[0-9]*)
113      echo "shutdown: el retardo '$a' NO está implementado — sin init que lo agende." >&2
114      echo "          corré 'shutdown -r now' cuando de verdad quieras." >&2
115      exit 1 ;;
116  esac
117done
118exec "/usr/local/bin/$modo"
119SH
120
121ln -sf poweroff "$RFS/usr/local/bin/halt"
122chmod 755 "$RFS/usr/local/bin/reboot" "$RFS/usr/local/bin/poweroff" "$RFS/usr/local/bin/shutdown"
123
124# Ctrl+Alt+Del tiene que llegarle a arje como SIGINT, no reiniciar a lo bruto, y
125# SysRq tiene que estar encendido o el shim de poweroff no tiene por dónde. Los
126# dos son el default de esta imagen, pero un default no es una garantía.
127install -d -m 755 "$RFS/etc/sysctl.d"
128cat > "$RFS/etc/sysctl.d/60-arje-botones.conf" <<'CONF'
129# Ctrl+Alt+Del => SIGINT a PID 1 (que es de donde arje saca su reinicio ordenado).
130kernel.ctrl-alt-del = 0
131# SysRq encendido: es por donde apaga /usr/local/bin/poweroff, y es el escape
132# que siempre funciona (`sync; echo u > /proc/sysrq-trigger; echo b > ...`).
133kernel.sysrq = 1
134CONF
135
136echo "==> botones : reboot/poweroff/halt/shutdown en /usr/local/bin + sysctl (SIGINT a PID 1)"