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 1572Shell 203Rust 109Markdown 993728 Definitions

⎇ be881ad0996aee773686a36ce014df0d648de2ed crates/hammer-recover/src/main.rs Rust · 73 lines · 3.5 KB History Who touched what raw

auto-recover al arranque: crate hammer-recover + hook /sbin/init (E4 #4b) be881ad09 · sergio ·

1//! `hammer-recover` — auto-recuperación de upgrades al **arranque** (E4 / refinamiento #4b).
2//!
3//! El producto NO lleva el CLI `hammer` completo; este mini-binario (estático musl) es lo único que el
4//! sistema instalado necesita para auto-sanar un upgrade interrumpido. El wrapper `/sbin/init` lo corre
5//! **tras montar `/store` y `/var/lib/hammer`** y **antes** de incarnar arje-zero:
6//!
7//! - Sin intento pendiente ⇒ no-op (el caso normal).
8//! - Con un `pending.json` (un `hammer upgrade apply` cortado por un apagón/reinicio): intenta
9//!   **completar** (roll-forward, re-ejecuta el plan idempotente + commitea); si no puede (p.ej. el árbol
10//!   ya no está en `/store`), **deshace** (roll-back) para dejar el FHS consistente. En cualquier caso el
11//!   sistema arranca en un estado coherente, no a medias.
12//!
13//! Encaja con el modelo de generaciones **in-place** (el FHS es la generación viva): no hay menú de
14//! generaciones tipo NixOS que seleccionar, sino una reparación determinista del estado a medias.
15//!
16//! Paths del producto (overridables por entorno para tests):
17//!   `HAMMER_RECOVER_ROOT=/`  `HAMMER_RECOVER_STORE=/store`
18//!   `HAMMER_RECOVER_STATE=/var/lib/hammer/upgrades`  `HAMMER_RECOVER_JOURNAL=/var/lib/hammer/journal`
19//! Flag: `--rollback` fuerza deshacer en vez de completar.
20//!
21//! NUNCA sale con código ≠0 por un fallo de recuperación: es un hook de arranque, no debe abortar el
22//! boot. Reporta por consola y deja que arje-zero siga (con el estado más consistente que logró).
23
24use std::path::PathBuf;
25
26fn env_path(key: &str, default: &str) -> PathBuf {
27    std::env::var(key).map(PathBuf::from).unwrap_or_else(|_| PathBuf::from(default))
28}
29
30fn main() {
31    let force_rollback = std::env::args().skip(1).any(|a| a == "--rollback");
32    let root = env_path("HAMMER_RECOVER_ROOT", "/");
33    let store = env_path("HAMMER_RECOVER_STORE", "/store");
34    let state = env_path("HAMMER_RECOVER_STATE", "/var/lib/hammer/upgrades");
35    let journal_dir = env_path("HAMMER_RECOVER_JOURNAL", "/var/lib/hammer/journal");
36
37    match hammer_upgrade::pending(&state) {
38        Ok(None) => {
39            println!("hammer-recover: sin upgrade interrumpido");
40            return;
41        }
42        Ok(Some(p)) => {
43            println!("hammer-recover: upgrade interrumpido (generación {}) — recuperando", p.id);
44        }
45        Err(e) => {
46            eprintln!("hammer-recover: no pude leer el estado de upgrades: {e}");
47            return;
48        }
49    }
50
51    let journal = hammer_journal::Journal::open(&journal_dir).ok();
52    let j = journal.as_ref();
53
54    if force_rollback {
55        match hammer_upgrade::recover(&store, &root, &state, j, true) {
56            Ok(r) => println!("hammer-recover: DESHECHO (generación {} descartada)", r.generation),
57            Err(e) => eprintln!("hammer-recover: rollback falló: {e}"),
58        }
59        return;
60    }
61
62    // Optimista: completar el upgrade. Si el roll-forward falla, deshacer ⇒ FHS consistente igual.
63    match hammer_upgrade::recover(&store, &root, &state, j, false) {
64        Ok(r) => println!("hammer-recover: COMPLETADO (generación {})", r.generation),
65        Err(e) => {
66            eprintln!("hammer-recover: roll-forward falló ({e}); deshaciendo para dejar el FHS consistente");
67            match hammer_upgrade::recover(&store, &root, &state, j, true) {
68                Ok(r) => println!("hammer-recover: DESHECHO tras fallo (generación {})", r.generation),
69                Err(e2) => eprintln!("hammer-recover: rollback de respaldo también falló: {e2}"),
70            }
71        }
72    }
73}