summaryrefslogtreecommitdiff
path: root/src/daemon.rs
blob: f8588ca6ebbdc6781d6864ff987a5df5aaa92c88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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<Box<dyn Runtime>> {
    #[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")
    }
}