use std::process::Command; use crate::error::RogError; /// An action for `systemctl` #[derive(Debug, Copy, Clone)] pub enum SystemdUnitAction { Stop, Start, Restart, } impl From for &str { fn from(s: SystemdUnitAction) -> Self { match s { SystemdUnitAction::Stop => "stop", SystemdUnitAction::Start => "start", SystemdUnitAction::Restart => "restart", } } } #[derive(Debug, Copy, Clone)] pub enum SystemdUnitState { Active, Inactive, } impl From for &str { fn from(s: SystemdUnitState) -> Self { match s { SystemdUnitState::Active => "active", SystemdUnitState::Inactive => "inactive", } } } /// Change the state of a systemd unit. Blocks while running command. pub fn do_systemd_unit_action(action: SystemdUnitAction, unit: &str) -> Result<(), RogError> { let mut cmd = Command::new("systemctl"); cmd.arg(<&str>::from(action)); cmd.arg(unit); let status = cmd .status() .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; if !status.success() { let msg = format!("systemctl {action:?} {unit} failed: {status:?}",); return Err(RogError::SystemdUnitAction(msg)); } Ok(()) } /// Get systemd unit state. Blocks while command is run. pub fn is_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result { let mut cmd = Command::new("systemctl"); cmd.arg("is-active"); cmd.arg(unit); let output = cmd .output() .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; if output.stdout.starts_with(<&str>::from(state).as_bytes()) { return Ok(true); } Ok(false) } /// Wait for a systemd unit to change to `state`. Checks state every 250ms for 3 seconds. Blocks while running wait. pub fn wait_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<(), RogError> { let mut cmd = Command::new("systemctl"); cmd.arg("is-active"); cmd.arg(unit); let mut count = 0; while count <= (4 * 3) { // 3 seconds max let output = cmd .output() .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; if output.stdout.starts_with(<&str>::from(state).as_bytes()) { return Ok(()); } // fine to block here, nobody doing shit now std::thread::sleep(std::time::Duration::from_millis(250)); count += 1; } Err(RogError::SystemdUnitWaitTimeout(<&str>::from(state).into())) }