Skip to main content

planarian_backend_linux/
lib.rs

1//! The real backends for Phase A on NixOS 26.05 (§5), behind the schema's
2//! backend traits.
3//!
4//! The process-spawning modules talk to the system through its own command-
5//! line tools (`systemctl`, `loginctl`, `nix`, `systemd-run`, `nmcli`). Their
6//! output formats are stable, and that keeps the dependency set small (see
7//! docs/deviations.md: §17 names zbus). Every mutating call first checks its
8//! OpId's epoch against the transaction's fence file and refuses a stale one
9//! before touching anything (§12 fencing).
10
11pub mod cmd;
12#[cfg(feature = "gym-hooks")]
13pub mod gym;
14pub mod hold;
15pub mod logind;
16pub mod nixos;
17pub mod probe;
18pub mod process;
19pub mod runtime;
20pub mod sysfs;
21pub mod systemd;
22
23use planarian_schema::{Backends, OpId};
24use std::path::{Path, PathBuf};
25
26/// Filesystem locations. Defaults match the NixOS module.
27#[derive(Clone, Debug)]
28pub struct Paths {
29    /// `/var/lib/planarian`
30    pub state: PathBuf,
31    /// The owner's configuration (a flake directory), e.g. `/etc/nixos`.
32    pub owner: PathBuf,
33    /// The flake output holding this machine, e.g. `nixosConfigurations.laptop`.
34    pub flake_attr: String,
35    pub profile: PathBuf,
36    pub gcroots: PathBuf,
37}
38
39impl Default for Paths {
40    fn default() -> Self {
41        Paths {
42            state: "/var/lib/planarian".into(),
43            owner: "/etc/nixos".into(),
44            flake_attr: "nixosConfigurations.default".into(),
45            profile: "/nix/var/nix/profiles/system".into(),
46            gcroots: "/nix/var/nix/gcroots/planarian".into(),
47        }
48    }
49}
50
51impl Paths {
52    pub fn txn_dir(&self) -> PathBuf {
53        self.state.join("txn")
54    }
55
56    pub fn journal_dir(&self) -> PathBuf {
57        self.state.join("journal")
58    }
59}
60
61/// §12 fencing: a mutating call is refused unless its epoch is the one in the
62/// transaction's fence file.
63pub fn admitted(txn_dir: &Path, op: &OpId) -> bool {
64    let p = txn_dir.join(op.txn.0.to_string()).join("lease");
65    let fence = std::fs::read_to_string(p).ok().and_then(|s| s.trim().parse::<u64>().ok());
66    planarian_txn::kernel::fence_admits(fence, op.epoch)
67}
68
69/// Everything, for the daemon and the watchdog.
70#[derive(Clone, Debug)]
71pub struct Real {
72    pub systemd: systemd::Systemd,
73    pub nixos: nixos::Nixos,
74    pub sysfs: sysfs::Sysfs,
75    pub probes: probe::Probes,
76    pub logind: logind::Logind,
77    pub runtime: runtime::Runtime,
78    pub process: process::Processes,
79}
80
81impl Real {
82    pub fn new(paths: Paths, devices: sysfs::DeviceMap) -> Real {
83        let txn_dir = paths.txn_dir();
84        Real {
85            systemd: systemd::Systemd::new(txn_dir.clone()),
86            nixos: nixos::Nixos::new(paths.clone()),
87            sysfs: sysfs::Sysfs::new(devices, txn_dir.clone()),
88            probes: probe::Probes,
89            logind: logind::Logind::default(),
90            runtime: runtime::Runtime::new(txn_dir),
91            process: process::Processes,
92        }
93    }
94}
95
96impl Backends for Real {
97    type Units = systemd::Systemd;
98    type Gens = nixos::Nixos;
99    type Inv = sysfs::Sysfs;
100    type Probes = probe::Probes;
101    type Sessions = logind::Logind;
102    type Runtime = runtime::Runtime;
103    type Procs = process::Processes;
104    type Clock = process::Processes;
105
106    fn units(&self) -> &systemd::Systemd {
107        &self.systemd
108    }
109    fn generations(&self) -> &nixos::Nixos {
110        &self.nixos
111    }
112    fn inventory(&self) -> &sysfs::Sysfs {
113        &self.sysfs
114    }
115    fn probes(&self) -> &probe::Probes {
116        &self.probes
117    }
118    fn sessions(&self) -> &logind::Logind {
119        &self.logind
120    }
121    fn runtime(&self) -> &runtime::Runtime {
122        &self.runtime
123    }
124    fn processes(&self) -> &process::Processes {
125        &self.process
126    }
127    fn clock(&self) -> &process::Processes {
128        &self.process
129    }
130}