From 0c332494968515621099273bdc2c99d5a1f6df7f Mon Sep 17 00:00:00 2001 From: Lia Lenckowski Date: Mon, 2 Sep 2024 13:05:47 +0200 Subject: add systemd user units, check systemd units via dbus --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/check.rs | 46 +++++++++++++--------------------------------- src/dbus.rs | 27 +++++++++++++++++++++++++-- 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 436ce74..a5f3cf8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1745,7 +1745,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "statuspage" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index b51b08f..acfcd65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "statuspage" -version = "0.1.0" +version = "0.1.1" edition = "2021" [dependencies] diff --git a/src/check.rs b/src/check.rs index 42812c9..b0230e8 100644 --- a/src/check.rs +++ b/src/check.rs @@ -1,5 +1,5 @@ use crate::{log::update_service, Config, Status, GLOBAL_ERROR, STATUS}; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{anyhow, bail, Result}; use chrono::Utc; use futures::{stream::FuturesUnordered, StreamExt}; use log::info; @@ -17,10 +17,10 @@ use crate::dbus::*; pub enum Check { Systemd(String), SystemdGlobal, -// SystemdUser { -// user: String, -// name: String, -// }, + SystemdUser { + user: String, + name: String, + }, SystemdUserGlobal(String), Pacman(String), Http { @@ -83,38 +83,17 @@ impl Check { output.status.exit_ok()?; Ok(String::from_utf8(output.stdout)?) } - Check::Systemd(sname) => { - let output = Command::new("systemctl") - .arg("show") - .arg("--no-pager") - .arg(sname) - .output() - .await?; - let output = String::from_utf8(output.stdout).context("systemctl output")?; - - let mut active = ""; - let mut sub = ""; - for line in output.split("\n") { - if let Some((key, value)) = line.split_once("=") { - match key { - "ActiveState" => active = value, - "SubState" => sub = value, - _ => (), - } - } - } - let s = format!("{active} ({sub})"); - if active != "active" { - Err(anyhow!(s)) - } else { - Ok(s) - } + Check::Systemd(name) => { + check_systemd_unit(None, name).await } Check::SystemdGlobal => { check_systemd_all(None).await } - Check::SystemdUserGlobal(username) => { - check_systemd_all(Some(username)).await + Check::SystemdUser { user, name } => { + check_systemd_unit(Some(user), name).await + } + Check::SystemdUserGlobal(user) => { + check_systemd_all(Some(user)).await } Check::Shell { command, output, .. @@ -168,6 +147,7 @@ impl Check { Check::Shell { title, .. } => title.to_owned(), Check::Pacman(_) => "Installed".to_string(), Check::SystemdGlobal => "System Services".to_string(), + Check::SystemdUser { user, .. } => format!("User service for {user}"), Check::SystemdUserGlobal(username) => format!("User services for {username}"), } } diff --git a/src/dbus.rs b/src/dbus.rs index 8fd2302..d23c7b6 100644 --- a/src/dbus.rs +++ b/src/dbus.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use zbus::{ - proxy, + proxy, Proxy, zvariant::{OwnedObjectPath, Type}, Connection, connection::Builder, address::{Address, transport::{Unix, Transport, UnixSocket}}, }; @@ -31,7 +31,7 @@ struct ServiceStatus { )] trait Manager { async fn list_units(&self) -> Result>; - async fn get_unit(&self, unit_name: String) -> Result; + async fn get_unit(&self, unit_name: &str) -> Result; } async fn ensure_system_conn() -> Result> { @@ -90,3 +90,26 @@ pub(crate) async fn check_systemd_all(user: Option<&str>) -> Result { Err(anyhow!("Bad services: {}", bad.join(", "))) } } + +pub(crate) async fn check_systemd_unit(user: Option<&str>, unit: &str) -> Result { + let conn = match user { + None => ensure_system_conn().await, + Some(username) => ensure_user_conn(username).await, + }?; + + let manager = ManagerProxy::new(&conn).await?; + let unit_object_path = if unit.contains('.') { + manager.get_unit(unit).await + } else { + manager.get_unit(&format!("{unit}.service")).await + }?; + + let unit_proxy = Proxy::new(&conn, "org.freedesktop.systemd1", unit_object_path, "org.freedesktop.systemd1.Unit").await?; + + let substate: String = unit_proxy.get_property("SubState").await?; + if matches!(substate.as_str(), "active" | "inactive" | "plugged" | "mounted" | "dead" | "listening" | "running" | "exited" | "waiting" | "abandoned" | "elapsed") { + Ok(format!("{unit}: {substate}")) + } else { + Err(anyhow!("{unit}: {substate}")) + } +} -- cgit v1.2.3-70-g09d2