//! `hammerd` — daemon de hammer. Dos responsabilidades: //! 1. Diario de mutaciones: fanotify sobre /bin,/sbin,/lib,/etc → `hammer-journal`. //! 2. Bus de agente: /run/agent.sock (JSON-líneas, SO_PEERCRED). Ver `docs/07-agent-bus.md`. //! //! Fase 3 implementa (1). Fase 5 añadirá (2). Si el daemon arranca sin CAP_SYS_ADMIN, el //! watcher falla en init y el daemon sigue corriendo sin él (warn claro). Esto es //! deliberado para que puedas correr `hammerd` en dev sin sudo y aún así probar la parte //! del bus. use std::path::PathBuf; use clap::Parser; mod watcher; #[derive(Parser)] #[command(name = "hammerd", version, about = "Daemon de hammer: bus de agente + diario.")] struct Args { /// Socket del bus de agente. #[arg(long, default_value = "/run/agent.sock")] agent_sock: String, /// FIFO de control humano del init. #[arg(long, default_value = "/run/init.control")] init_control: String, /// Directorio del diario de mutaciones. #[arg(long, default_value = "/var/lib/hammer/journal")] journal: String, /// Directorio raíz de overlays (para que el watcher pueda filtrar eventos bajo overlays /// activos). Default coincide con `hammer try`. #[arg(long, default_value = hammer_overlay::DEFAULT_STATE_ROOT)] overlay_state_root: String, /// Directorios extra a vigilar; si vacío, usa los defaults del FHS (SDD 05 §2). #[arg(long = "watch")] extra_watch: Vec, } fn main() -> anyhow::Result<()> { tracing_subscriber::fmt() .with_writer(std::io::stderr) .with_env_filter( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "info".into()), ) .init(); let args = Args::parse(); tracing::info!( agent_sock = %args.agent_sock, init_control = %args.init_control, journal = %args.journal, "hammerd: arranque" ); let journal = hammer_journal::Journal::open(&args.journal)?; let mut dirs = watcher::default_watch_dirs(); dirs.extend(args.extra_watch); let overlay_root = PathBuf::from(&args.overlay_state_root); match watcher::Watcher::start(&dirs, journal, Some(overlay_root)) { Ok(w) => { tracing::info!("watcher fanotify activo"); w.run_forever()?; } Err(e) => { tracing::warn!( error = %e, "watcher fanotify NO arrancó; el daemon sigue (sin diario en este run)" ); // TODO(fase-5): aquí entra el bus de agente. De momento sólo dormimos para que // el daemon no salga. std::thread::park(); } } Ok(()) }