use crate::{ bus::{NAME, PATH, Service}, controller::Controller, runtime::Runtime, subscription::HttpSource, }; use anyhow::{Result, ensure}; use std::{path::Path, sync::Arc, time::Duration}; use tokio::sync::Mutex; pub fn runtime() -> Result> { #[cfg(feature = "linux-runtime")] { Ok(Box::new(crate::linux::LinuxRuntime::default())) } #[cfg(not(feature = "linux-runtime"))] { anyhow::bail!("This build has no Linux runtime; rebuild with --features linux-runtime") } } pub async fn run() -> Result<()> { ensure!( unsafe { libc::geteuid() } == 0, "The controller must run as a root-owned system service" ); let _lock = crate::locking::controller_lock()?; let mut controller = Controller::open_paths( Path::new("/etc/roentgen"), Path::new("/var/lib/roentgen"), runtime()?, Box::new(HttpSource), )?; if let Err(error) = controller.restore().await { controller.report_runtime_error(&error); } let controller = Arc::new(Mutex::new(controller)); let _connection = zbus::connection::Builder::system()? .name(NAME)? .serve_at( PATH, Service { controller: controller.clone(), cancellation: Arc::new(tokio::sync::Notify::new()), }, )? .build() .await?; let mut interval = tokio::time::interval(Duration::from_secs(5)); interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); loop { tokio::select! { _ = tokio::signal::ctrl_c() => break, _ = interval.tick() => { let mut controller = controller.lock().await; if let Err(error) = controller.scheduled_check().await { controller.report_runtime_error(&error); tracing::warn!("{error}"); } } } } // Exiting the controller never releases enabled protection or stops the core. Ok(()) } pub async fn guard() -> Result<()> { ensure!(unsafe { libc::geteuid() } == 0, "The guard requires root"); #[cfg(feature = "linux-runtime")] { crate::linux::restore_guard() } #[cfg(not(feature = "linux-runtime"))] { anyhow::bail!("Rebuild with --features linux-runtime") } }