Files
brahman/scripts/install-arje-as-init.sh
T
sergio d1b700eb2b fix(init): el reboot-loop de Fedora — remount rw + /run tmpfs + shell de rescate
Diagnóstico: en el VPS Fedora arje-zero caía como PID 1 y el cmdline
traía `panic=10`, así que el kernel rebooteaba cada 10 s. Tres causas
encadenadas, todas arregladas:

1) **Cmdline `ro` + sin `/run` tmpfs.** El menuentry montaba `/` como
   sólo lectura (systemd lo remonta rw temprano; arje no). Sin eso, el
   socket del bus interno se intenta crear sobre un FS de sólo lectura
   y falla con EROFS → spawn_bus devuelve Err → PID 1 sale → kernel
   panic. arje-kernel ahora remonta `/` rw en el bootstrap y monta
   `/run`, `/tmp`, `/dev/pts`, `/dev/shm` como tmpfs — superficies
   escribibles aunque la raíz quede ro.

2) **PID 1 saliendo en cualquier `?`.** Doctrina dura nueva: PID 1
   NUNCA puede salir. Cualquier error de arranque ahora cae a una
   `emergency_shell()` que imprime el diagnóstico en `/dev/console`,
   abre `/bin/sh` y, si la shell muere, la reabre — así el operador
   puede reparar en vez de mirar la máquina reiniciarse en bucle.

3) **El script no conocía grub2 (Fedora).** `install-arje-as-init.sh`
   sólo probaba `update-grub` (Debian) y `grub-mkconfig` (Arch). Ahora
   detecta `grub2-mkconfig` y resuelve el `grub.cfg` correcto
   (UEFI/BIOS, fedora/redhat/centos/almalinux/rocky). El menuentry
   también pasa de `ro` a `rw` — el remount es belt-and-suspenders.
   Mismo arreglo en `uninstall-arje.sh`.

Renaser intacto: estos cambios son Linux-side puro (arje-kernel y
arje-zero usan nix/libc/tracing); renaser sólo comparte mirada-layout y
formato, ninguno tocado.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:02:45 +00:00

200 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# install-arje-as-init.sh — instala arje como init alternativo en una
# máquina real con systemd ya instalado, en coexistencia.
#
# ESTRATEGIA: arje NO reemplaza al systemd default. Se instala en
# paralelo con su propia entrada GRUB. Booteás arje cuando querés,
# volvés a systemd si algo no anda.
#
# QUÉ HACE:
# 1. Compila musl-static todos los binarios del fractal.
# 2. Copia binarios a /usr/sbin/ (init/shims) y /usr/bin/ (CLIs admin)
# del rootfs vivo.
# 3. Copia la seed a /ente/seed.card.json (default: arje-host.card.json).
# 4. Crea menuentry "arje" en /etc/grub.d/40_custom usando init=/sbin/arje-zero
# (conserva initramfs nativo → firmware, módulos kernel, root FS,
# siguen funcionando exactamente igual).
# 5. Ejecuta update-grub o grub-mkconfig según distro.
#
# QUÉ NO HACE:
# - Tocar /sbin/init, /usr/lib/systemd/* (systemd queda intacto y default).
# - Cambiar GRUB_DEFAULT (seguís booteando systemd por default).
# - Cargar arje ahora. Lo elegís manualmente en el próximo boot.
# - Habilitar servicios systemd que arje no necesita (eso es responsabilidad
# tuya, ver docs/arje-replace-systemd.md §4).
#
# REVERTIR: sudo scripts/uninstall-arje.sh
#
# Uso:
# sudo scripts/install-arje-as-init.sh [seed.card.json]
#
# seed default: seeds/arje-host.card.json
set -euo pipefail
SEED="${1:-seeds/arje-host.card.json}"
TARGET="${ARJE_TARGET:-x86_64-unknown-linux-musl}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_DIR"
if [ "$(id -u)" -ne 0 ]; then
echo "[install-arje] hace falta root (modifica /usr/sbin, /etc/grub.d, /ente)" >&2
exit 1
fi
if [ ! -f "$SEED" ]; then
echo "[install-arje] seed no encontrada: $SEED" >&2
exit 2
fi
# Verificar que el systemd default sigue siendo el init — querés saber
# de qué te volvés capaz de regresar.
if [ ! -e /sbin/init ] && [ ! -e /lib/systemd/systemd ] && [ ! -e /usr/lib/systemd/systemd ]; then
echo "[install-arje] WARN: no detecto systemd en esta máquina." >&2
echo " Si esta máquina ya corre arje, este script no es lo que querés." >&2
echo " Continuá sólo si sabés lo que hacés." >&2
read -r -p " ¿continuar? [y/N] " ans
[ "$ans" = "y" ] || exit 3
fi
echo "[install-arje] paso 1/5: compilar binarios musl-static"
"$SCRIPT_DIR/build-arje-initrd.sh" "$SEED" /tmp/arje-noop.cpio.gz >/dev/null
rm -f /tmp/arje-noop.cpio.gz
BIN_DIR="$REPO_DIR/target/$TARGET/release"
EX_DIR="$BIN_DIR/examples"
echo "[install-arje] paso 2/5: instalar binarios en /usr/sbin/ y /usr/bin/"
install -m 0755 "$BIN_DIR/arje-zero" /usr/sbin/arje-zero
for b in arje-echo arje-policy-provider \
arje-logind-compat arje-hostnamed-compat arje-timedated-compat \
arje-localed-compat arje-journald-compat arje-resolved-compat \
arje-polkit-compat arje-machined-compat arje-systemd1-compat \
arje-notify-compat arje-timer-compat arje-tmpfiles-compat \
arje-binfmt-compat; do
install -m 0755 "$BIN_DIR/$b" "/usr/sbin/$b"
done
for e in brahman-status busctl brainctl; do
install -m 0755 "$EX_DIR/$e" "/usr/bin/$e"
done
echo "[install-arje] paso 3/5: instalar seed en /ente/seed.card.json"
mkdir -p /ente
# Backup del seed previo (si lo hay) — nunca sobrescribimos sin guardar.
if [ -f /ente/seed.card.json ]; then
cp /ente/seed.card.json "/ente/seed.card.json.bak-$(date +%s)"
fi
install -m 0644 "$SEED" /ente/seed.card.json
echo "[install-arje] paso 4/5: detectar kernel para menuentry GRUB"
# Reusamos el kernel del host (mismo vmlinuz que usa systemd). Detectamos
# el current; si tenés varios, se elige el del uname.
KVER="$(uname -r)"
VMLINUZ=""
INITRD=""
for cand in "/boot/vmlinuz-$KVER" "/boot/vmlinuz" /boot/vmlinuz-*; do
if [ -f "$cand" ]; then VMLINUZ="$cand"; break; fi
done
for cand in "/boot/initrd.img-$KVER" "/boot/initramfs-$KVER.img" \
"/boot/initrd.img" /boot/initrd.img-* /boot/initramfs-*.img; do
if [ -f "$cand" ]; then INITRD="$cand"; break; fi
done
if [ -z "$VMLINUZ" ] || [ -z "$INITRD" ]; then
echo "[install-arje] ERROR: no encontré vmlinuz o initrd nativo en /boot." >&2
echo " Sin esos no se puede armar la entrada GRUB." >&2
exit 4
fi
echo " kernel: $VMLINUZ"
echo " initrd: $INITRD"
# El root device — leemos /proc/cmdline para reusarlo exactamente como
# está en la entrada systemd actual.
ROOT_OPT="$(awk -v RS=' ' '/^root=/' /proc/cmdline | tr -d '\n')"
if [ -z "$ROOT_OPT" ]; then
echo "[install-arje] WARN: no extraje root= de /proc/cmdline." >&2
echo " Configurá manualmente la entrada GRUB con tu root device." >&2
ROOT_OPT="root=/dev/sda1 # AJUSTAR"
fi
echo "[install-arje] paso 5/5: agregar menuentry GRUB"
CUSTOM=/etc/grub.d/40_custom
# Si ya existe nuestro menuentry, lo reemplazamos (idempotente).
if grep -q "BEGIN ARJE-MENUENTRY" "$CUSTOM"; then
# Borrar el bloque previo.
awk '/BEGIN ARJE-MENUENTRY/{f=1} /END ARJE-MENUENTRY/{f=0; next} !f' "$CUSTOM" \
> "$CUSTOM.tmp" && mv "$CUSTOM.tmp" "$CUSTOM"
fi
cat >> "$CUSTOM" <<EOF
# BEGIN ARJE-MENUENTRY (generated by install-arje-as-init.sh)
menuentry "arje (init=/sbin/arje-zero) — kernel $KVER" {
insmod gzio
insmod part_msdos
insmod ext2
linux $VMLINUZ $ROOT_OPT rw init=/sbin/arje-zero console=tty1 console=ttyS0,115200 panic=10
initrd $INITRD
}
# END ARJE-MENUENTRY
EOF
chmod 0755 "$CUSTOM"
# Regenerar grub.cfg. Detectamos la convención de la distro: Debian /
# Ubuntu usan `update-grub` (wrapper de grub-mkconfig). Fedora / RHEL /
# CentOS usan `grub2-mkconfig` y el .cfg vive en /boot/grub2/ (BIOS) o
# /boot/efi/EFI/<distro>/ (UEFI). Arch usa `grub-mkconfig`.
if command -v update-grub >/dev/null 2>&1; then
echo " ejecutando update-grub (Debian/Ubuntu)"
update-grub
elif command -v grub2-mkconfig >/dev/null 2>&1; then
# Fedora / RHEL: buscar el grub.cfg activo. UEFI primero — su path es
# el que arranca realmente; el de BIOS suele ser un symlink al UEFI.
GRUB_CFG=""
for cand in /boot/efi/EFI/fedora/grub.cfg \
/boot/efi/EFI/redhat/grub.cfg \
/boot/efi/EFI/centos/grub.cfg \
/boot/efi/EFI/almalinux/grub.cfg \
/boot/efi/EFI/rocky/grub.cfg \
/boot/grub2/grub.cfg; do
if [ -f "$cand" ] || [ -L "$cand" ]; then GRUB_CFG="$cand"; break; fi
done
if [ -z "$GRUB_CFG" ]; then
GRUB_CFG="/boot/grub2/grub.cfg"
echo " no detecté grub.cfg existente — usando $GRUB_CFG por default"
fi
echo " ejecutando grub2-mkconfig -o $GRUB_CFG (Fedora/RHEL)"
grub2-mkconfig -o "$GRUB_CFG"
elif command -v grub-mkconfig >/dev/null 2>&1; then
echo " ejecutando grub-mkconfig (Arch/otros)"
grub-mkconfig -o /boot/grub/grub.cfg
else
echo "[install-arje] WARN: no encontré update-grub, grub2-mkconfig ni grub-mkconfig." >&2
echo " Regenerá la grub.cfg manualmente." >&2
fi
cat <<EOF
[install-arje] HECHO.
systemd sigue siendo tu init default — esta máquina arranca systemd
salvo que elijas explícitamente "arje" en GRUB.
- binarios: /usr/sbin/arje-* y /usr/bin/{brahman-status,busctl,brainctl}
- seed activa: /ente/seed.card.json (origen: $SEED)
- menuentry: /etc/grub.d/40_custom (regenerá grub.cfg si lo editás)
Para arrancar arje al próximo boot UNA SOLA VEZ (sin cambiar default):
sudo grub-reboot "arje (init=/sbin/arje-zero) — kernel $KVER"
sudo reboot
Para revertir (quita binarios + menuentry):
sudo scripts/uninstall-arje.sh
Antes del primer boot real, leé docs/arje-replace-systemd.md §3
("Servicios systemd que arje NO arranca") para que NO te quedes sin
red, sin sshd o sin filesystems montados.
EOF