From 853ce3dd84831cd630b726442b0c5a9d6111b9fd Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 29 Mar 2024 17:58:11 -0700 Subject: [PATCH] systemd: Add new module for interacting with systemd --- src/main.rs | 15 ++++++----- src/manager.rs | 46 +++++++++++++++++++------------- src/process.rs | 2 -- src/systemd.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/wifi.rs | 28 ++++++++++---------- 5 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 src/systemd.rs diff --git a/src/main.rs b/src/main.rs index 714f7d3..47219ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ mod manager; mod power; mod process; mod sls; +mod systemd; mod wifi; #[cfg(test)] @@ -132,14 +133,16 @@ pub fn anyhow_to_zbus_fdo(error: Error) -> zbus::fdo::Error { } async fn create_connection() -> Result { - let manager = manager::SteamOSManager::new().await?; - - ConnectionBuilder::system()? + let connection = ConnectionBuilder::system()? .name("com.steampowered.SteamOSManager1.Manager")? - .serve_at("/com/steampowered/SteamOSManager1", manager)? .build() - .await - .map_err(|e| e.into()) + .await?; + let manager = manager::SteamOSManager::new(connection.clone()).await?; + connection + .object_server() + .at("/com/steampowered/SteamOSManager1", manager) + .await?; + Ok(connection) } #[tokio::main] diff --git a/src/manager.rs b/src/manager.rs index 5d2bc10..4202588 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -10,14 +10,16 @@ use anyhow::Result; use std::fmt; use tokio::fs::File; use tracing::error; -use zbus::{interface, zvariant::Fd}; +use zbus::zvariant::Fd; +use zbus::{interface, Connection}; use crate::hardware::{check_support, variant, HardwareVariant}; use crate::power::{ get_gpu_performance_level, set_gpu_clocks, set_gpu_performance_level, set_tdp_limit, GPUPerformanceLevel, }; -use crate::process::{run_script, script_output, SYSTEMCTL_PATH}; +use crate::process::{run_script, script_output}; +use crate::systemd::SystemdUnit; use crate::wifi::{ get_wifi_backend_from_conf, get_wifi_backend_from_script, set_wifi_backend, set_wifi_debug_mode, WifiBackend, WifiDebugMode, WifiPowerManagement, @@ -59,6 +61,7 @@ impl fmt::Display for FanControl { } pub struct SteamOSManager { + connection: Connection, wifi_backend: WifiBackend, wifi_debug_mode: WifiDebugMode, // Whether we should use trace-cmd or not. @@ -67,8 +70,9 @@ pub struct SteamOSManager { } impl SteamOSManager { - pub async fn new() -> Result { + pub async fn new(connection: Connection) -> Result { Ok(SteamOSManager { + connection, wifi_backend: get_wifi_backend_from_conf().await?, wifi_debug_mode: WifiDebugMode::Off, should_trace: variant().await? == HardwareVariant::Galileo, @@ -136,18 +140,15 @@ impl SteamOSManager { Ok(state) => state, Err(err) => return Err(zbus::fdo::Error::InvalidArgs(err.to_string()).into()), }; - let state = match state { - FanControl::OS => "stop", - FanControl::BIOS => "start", - }; - // Run what steamos-polkit-helpers/jupiter-fan-control does - run_script( - "enable fan control", - SYSTEMCTL_PATH, - &[state, "jupiter-fan-control-service"], - ) - .await + let jupiter_fan_control = + SystemdUnit::new(self.connection.clone(), "jupiter_2dfan_2dcontrol_2eservice") + .await + .map_err(anyhow_to_zbus)?; + match state { + FanControl::OS => jupiter_fan_control.start().await, + FanControl::BIOS => jupiter_fan_control.stop().await, + } .map_err(anyhow_to_zbus) } @@ -320,7 +321,14 @@ impl SteamOSManager { Ok(mode) => mode, Err(e) => return Err(zbus::fdo::Error::InvalidArgs(e.to_string())), }; - match set_wifi_debug_mode(wanted_mode, buffer_size, self.should_trace).await { + match set_wifi_debug_mode( + wanted_mode, + buffer_size, + self.should_trace, + self.connection.clone(), + ) + .await + { Ok(()) => { self.wifi_debug_mode = wanted_mode; Ok(()) @@ -373,16 +381,18 @@ mod test { .await .expect("write"); - let manager = SteamOSManager::new().await.unwrap(); let connection = ConnectionBuilder::session() .unwrap() .name("com.steampowered.SteamOSManager1.Test") .unwrap() - .serve_at("/com/steampowered/SteamOSManager1", manager) - .unwrap() .build() .await .unwrap(); + let manager = SteamOSManager::new(connection.clone()).await.unwrap(); + connection.object_server() + .at("/com/steampowered/SteamOSManager1", manager) + .await + .expect("object_server at"); TestHandle { handle, connection } } diff --git a/src/process.rs b/src/process.rs index 0398ad1..443ffd8 100644 --- a/src/process.rs +++ b/src/process.rs @@ -10,8 +10,6 @@ use std::ffi::OsStr; use tokio::process::Command; use tracing::warn; -pub const SYSTEMCTL_PATH: &str = "/usr/bin/systemctl"; - pub async fn script_exit_code(executable: &str, args: &[impl AsRef]) -> Result { // Run given script and return the exit code let mut child = Command::new(executable).args(args).spawn()?; diff --git a/src/systemd.rs b/src/systemd.rs new file mode 100644 index 0000000..e8d4395 --- /dev/null +++ b/src/systemd.rs @@ -0,0 +1,72 @@ +/* + * Copyright © 2023 Collabora Ltd. + * Copyright © 2024 Valve Software + * + * SPDX-License-Identifier: MIT + */ + +use anyhow::{anyhow, Result}; +use std::path::PathBuf; +use zbus::zvariant::OwnedObjectPath; +use zbus::Connection; + +#[zbus::proxy( + interface = "org.freedesktop.systemd1.Unit", + default_service = "org.freedesktop.systemd1" +)] +trait SystemdUnit { + #[zbus(property)] + fn active_state(&self) -> Result; + + async fn restart(&self, mode: &str) -> Result; + async fn start(&self, mode: &str) -> Result; + async fn stop(&self, mode: &str) -> Result; +} + +#[zbus::proxy( + interface = "org.freedesktop.systemd1.Manager", + default_service = "org.freedesktop.systemd1", + default_path = "/org/freedesktop/systemd1" +)] +trait SystemdManager { + async fn reload(&self) -> Result<()>; +} + +pub struct SystemdUnit<'dbus> { + proxy: SystemdUnitProxy<'dbus>, +} + +pub async fn daemon_reload(connection: &Connection) -> Result<()> { + let proxy = SystemdManagerProxy::new(&connection).await?; + proxy.reload().await?; + Ok(()) +} + +impl<'dbus> SystemdUnit<'dbus> { + pub async fn new(connection: Connection, name: &str) -> Result> { + let path = PathBuf::from("/org/freedesktop/systemd1/unit").join(name); + let path = String::from(path.to_str().ok_or(anyhow!("Unit name {name} invalid"))?); + Ok(SystemdUnit { + proxy: SystemdUnitProxy::builder(&connection) + .cache_properties(zbus::CacheProperties::No) + .path(path)? + .build() + .await?, + }) + } + + pub async fn restart(&self) -> Result<()> { + self.proxy.restart("fail").await?; + Ok(()) + } + + pub async fn start(&self) -> Result<()> { + self.proxy.start("fail").await?; + Ok(()) + } + + pub async fn stop(&self) -> Result<()> { + self.proxy.stop("fail").await?; + Ok(()) + } +} diff --git a/src/wifi.rs b/src/wifi.rs index 5ac9e4f..65035c6 100644 --- a/src/wifi.rs +++ b/src/wifi.rs @@ -10,9 +10,11 @@ use std::fmt; use std::str::FromStr; use tokio::fs; use tracing::error; +use zbus::Connection; use crate::path; -use crate::process::{run_script, script_output, SYSTEMCTL_PATH}; +use crate::process::{run_script, script_output}; +use crate::systemd::{daemon_reload, SystemdUnit}; const OVERRIDE_CONTENTS: &str = "[Service] ExecStart= @@ -138,19 +140,16 @@ pub async fn setup_iwd_config(want_override: bool) -> std::io::Result<()> { } } -async fn restart_iwd() -> Result<()> { +async fn restart_iwd(connection: Connection) -> Result<()> { // First reload systemd since we modified the config most likely // otherwise we wouldn't be restarting iwd. - match run_script("reload systemd", SYSTEMCTL_PATH, &["daemon-reload"]).await { - Ok(_) => { - // worked, now restart iwd - run_script("restart iwd", SYSTEMCTL_PATH, &["restart", "iwd"]).await - } - Err(message) => { - error!("restart_iwd: reload systemd got an error: {message}"); - Err(message) - } - } + daemon_reload(&connection).await.inspect_err(|message| + error!("restart_iwd: reload systemd got an error: {message}"))?; + + // worked, now restart iwd + let unit = SystemdUnit::new(connection, "iwd_2eservice").await?; + unit.restart().await.inspect_err(|message| + error!("restart_iwd: restart unit got an error: {message}")) } async fn stop_tracing() -> Result<()> { @@ -180,6 +179,7 @@ pub async fn set_wifi_debug_mode( mode: WifiDebugMode, buffer_size: u32, should_trace: bool, + connection: Connection, ) -> Result<()> { // Set the wifi debug mode to mode, using an int for flexibility going forward but only // doing things on 0 or 1 for now @@ -199,7 +199,7 @@ pub async fn set_wifi_debug_mode( bail!("setup_iwd_config false got an error: {message}"); }; // setup_iwd_config false worked - if let Err(message) = restart_iwd().await { + if let Err(message) = restart_iwd(connection).await { bail!("restart_iwd got an error: {message}"); }; } @@ -210,7 +210,7 @@ pub async fn set_wifi_debug_mode( bail!("setup_iwd_config true got an error: {message}"); } // setup_iwd_config worked - if let Err(message) = restart_iwd().await { + if let Err(message) = restart_iwd(connection).await { bail!("restart_iwd got an error: {message}"); }; // restart_iwd worked