diff --git a/src/hardware.rs b/src/hardware.rs index 948bb9f..03a0a24 100644 --- a/src/hardware.rs +++ b/src/hardware.rs @@ -126,7 +126,7 @@ impl FanControl { pub async fn get_state(&self) -> Result { let jupiter_fan_control = - SystemdUnit::new(self.connection.clone(), "jupiter_2dfan_2dcontrol_2eservice").await?; + SystemdUnit::new(self.connection.clone(), "jupiter-fan-control.service").await?; let active = jupiter_fan_control.active().await?; Ok(match active { true => FanControlState::Os, @@ -137,7 +137,7 @@ impl FanControl { pub async fn set_state(&self, state: FanControlState) -> Result<()> { // Run what steamos-polkit-helpers/jupiter-fan-control does let jupiter_fan_control = - SystemdUnit::new(self.connection.clone(), "jupiter_2dfan_2dcontrol_2eservice").await?; + SystemdUnit::new(self.connection.clone(), "jupiter-fan-control.service").await?; match state { FanControlState::Os => jupiter_fan_control.start().await, FanControlState::Bios => jupiter_fan_control.stop().await, diff --git a/src/main.rs b/src/main.rs index 7a29c6b..6b76e56 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ * SPDX-License-Identifier: MIT */ -use anyhow::{anyhow, bail, Error, Result}; +use anyhow::{anyhow, bail, Result}; use std::path::{Path, PathBuf}; use tokio::fs::File; use tokio::io::AsyncWriteExt; @@ -132,12 +132,19 @@ async fn reload() -> Result<()> { } } -pub fn anyhow_to_zbus(error: Error) -> zbus::Error { +pub fn to_zbus_fdo_error(error: S) -> zbus::fdo::Error { + zbus::fdo::Error::Failed(error.to_string()) +} + +pub fn to_zbus_error(error: S) -> zbus::Error { zbus::Error::Failure(error.to_string()) } -pub fn anyhow_to_zbus_fdo(error: Error) -> zbus::fdo::Error { - zbus::fdo::Error::Failed(error.to_string()) +pub fn zbus_to_zbus_fdo(error: zbus::Error) -> zbus::fdo::Error { + match error { + zbus::Error::FDO(error) => *error, + error => zbus::fdo::Error::Failed(error.to_string()), + } } async fn create_connection() -> Result { diff --git a/src/manager.rs b/src/manager.rs index 86ad436..21052fc 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -22,7 +22,7 @@ use crate::wifi::{ get_wifi_backend, get_wifi_power_management_state, set_wifi_backend, set_wifi_debug_mode, set_wifi_power_management_state, WifiBackend, WifiDebugMode, WifiPowerManagement, }; -use crate::{anyhow_to_zbus, anyhow_to_zbus_fdo}; +use crate::{to_zbus_error, to_zbus_fdo_error}; #[derive(PartialEq, Debug, Copy, Clone)] #[repr(u32)] @@ -70,7 +70,7 @@ impl SteamOSManager { async fn wifi_power_management_state(&self) -> zbus::fdo::Result { match get_wifi_power_management_state().await { Ok(state) => Ok(state as u32), - Err(e) => Err(anyhow_to_zbus_fdo(e)), + Err(e) => Err(to_zbus_fdo_error(e)), } } @@ -82,7 +82,7 @@ impl SteamOSManager { }; set_wifi_power_management_state(state) .await - .map_err(anyhow_to_zbus) + .map_err(to_zbus_error) } #[zbus(property(emits_changed_signal = "false"))] @@ -91,7 +91,7 @@ impl SteamOSManager { .fan_control .get_state() .await - .map_err(anyhow_to_zbus_fdo)? as u32) + .map_err(to_zbus_fdo_error)? as u32) } #[zbus(property)] @@ -104,14 +104,14 @@ impl SteamOSManager { self.fan_control .set_state(state) .await - .map_err(anyhow_to_zbus) + .map_err(to_zbus_error) } #[zbus(property(emits_changed_signal = "const"))] async fn hardware_currently_supported(&self) -> zbus::fdo::Result { match check_support().await { Ok(res) => Ok(res as u32), - Err(e) => Err(anyhow_to_zbus_fdo(e)), + Err(e) => Err(to_zbus_fdo_error(e)), } } @@ -149,7 +149,7 @@ impl SteamOSManager { run_script("/usr/bin/jupiter-biosupdate", &["--auto"]) .await .inspect_err(|message| error!("Error updating BIOS: {message}")) - .map_err(anyhow_to_zbus_fdo) + .map_err(to_zbus_fdo_error) } async fn update_dock(&self) -> zbus::fdo::Result<()> { @@ -160,7 +160,7 @@ impl SteamOSManager { ) .await .inspect_err(|message| error!("Error updating dock: {message}")) - .map_err(anyhow_to_zbus_fdo) + .map_err(to_zbus_fdo_error) } async fn trim_devices(&self) -> zbus::fdo::Result<()> { @@ -168,7 +168,7 @@ impl SteamOSManager { run_script("/usr/lib/hwsupport/trim-devices.sh", &[] as &[String; 0]) .await .inspect_err(|message| error!("Error updating trimming devices: {message}")) - .map_err(anyhow_to_zbus_fdo) + .map_err(to_zbus_fdo_error) } async fn format_device( @@ -184,7 +184,7 @@ impl SteamOSManager { run_script("/usr/lib/hwsupport/format-device.sh", args.as_ref()) .await .inspect_err(|message| error!("Error formatting {device}: {message}")) - .map_err(anyhow_to_zbus_fdo) + .map_err(to_zbus_fdo_error) } #[zbus(property(emits_changed_signal = "false"))] @@ -193,7 +193,7 @@ impl SteamOSManager { Ok(level) => Ok(level as u32), Err(e) => { error!("Error getting GPU performance level: {e}"); - Err(anyhow_to_zbus_fdo(e)) + Err(to_zbus_fdo_error(e)) } } } @@ -207,7 +207,7 @@ impl SteamOSManager { set_gpu_performance_level(level) .await .inspect_err(|message| error!("Error setting GPU performance level: {message}")) - .map_err(anyhow_to_zbus) + .map_err(to_zbus_error) } #[zbus(property(emits_changed_signal = "false"))] @@ -215,7 +215,7 @@ impl SteamOSManager { get_gpu_clocks() .await .inspect_err(|message| error!("Error getting manual GPU clock: {message}")) - .map_err(anyhow_to_zbus_fdo) + .map_err(to_zbus_fdo_error) } #[zbus(property)] @@ -223,7 +223,7 @@ impl SteamOSManager { set_gpu_clocks(clocks) .await .inspect_err(|message| error!("Error setting manual GPU clock: {message}")) - .map_err(anyhow_to_zbus) + .map_err(to_zbus_error) } #[zbus(property(emits_changed_signal = "const"))] @@ -240,12 +240,12 @@ impl SteamOSManager { #[zbus(property(emits_changed_signal = "false"))] async fn tdp_limit(&self) -> zbus::fdo::Result { - get_tdp_limit().await.map_err(anyhow_to_zbus_fdo) + get_tdp_limit().await.map_err(to_zbus_fdo_error) } #[zbus(property)] async fn set_tdp_limit(&self, limit: u32) -> zbus::Result<()> { - set_tdp_limit(limit).await.map_err(anyhow_to_zbus) + set_tdp_limit(limit).await.map_err(to_zbus_error) } #[zbus(property(emits_changed_signal = "const"))] @@ -293,7 +293,7 @@ impl SteamOSManager { } Err(e) => { error!("Error setting wifi debug mode: {e}"); - Err(anyhow_to_zbus_fdo(e)) + Err(to_zbus_fdo_error(e)) } } } @@ -303,7 +303,7 @@ impl SteamOSManager { async fn wifi_backend(&self) -> zbus::fdo::Result { match get_wifi_backend().await { Ok(backend) => Ok(backend as u32), - Err(e) => Err(anyhow_to_zbus_fdo(e)), + Err(e) => Err(to_zbus_fdo_error(e)), } } @@ -321,7 +321,7 @@ impl SteamOSManager { set_wifi_backend(backend) .await .inspect_err(|message| error!("Error setting wifi backend: {message}")) - .map_err(anyhow_to_zbus_fdo) + .map_err(to_zbus_fdo_error) } /// A version property. diff --git a/src/systemd.rs b/src/systemd.rs index 8f9f3e6..688e26b 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -4,8 +4,9 @@ * * SPDX-License-Identifier: MIT */ +#![allow(dead_code)] -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use std::path::PathBuf; use zbus::zvariant::OwnedObjectPath; use zbus::Connection; @@ -17,6 +18,8 @@ use zbus::Connection; trait SystemdUnit { #[zbus(property)] fn active_state(&self) -> Result; + #[zbus(property)] + fn unit_file_state(&self) -> Result; async fn restart(&self, mode: &str) -> Result; async fn start(&self, mode: &str) -> Result; @@ -29,11 +32,45 @@ trait SystemdUnit { default_path = "/org/freedesktop/systemd1" )] trait SystemdManager { + async fn enable_unit_files( + &self, + files: &[&str], + runtime: bool, + force: bool, + ) -> Result<(bool, Vec<(String, String, String)>)>; + + async fn disable_unit_files( + &self, + files: &[&str], + runtime: bool, + ) -> Result>; + + async fn mask_unit_files( + &self, + files: &[&str], + runtime: bool, + ) -> Result>; + + async fn unmask_unit_files( + &self, + files: &[&str], + runtime: bool, + ) -> Result>; + async fn reload(&self) -> Result<()>; } +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum EnableState { + Disbled, + Enabled, + Masked, +} + pub struct SystemdUnit<'dbus> { + connection: Connection, proxy: SystemdUnitProxy<'dbus>, + name: String, } pub async fn daemon_reload(connection: &Connection) -> Result<()> { @@ -44,7 +81,7 @@ pub async fn daemon_reload(connection: &Connection) -> Result<()> { 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 = PathBuf::from("/org/freedesktop/systemd1/unit").join(escape(name)); let path = String::from(path.to_str().ok_or(anyhow!("Unit name {name} invalid"))?); Ok(SystemdUnit { proxy: SystemdUnitProxy::builder(&connection) @@ -52,6 +89,8 @@ impl<'dbus> SystemdUnit<'dbus> { .path(path)? .build() .await?, + connection, + name: String::from(name), }) } @@ -70,7 +109,72 @@ impl<'dbus> SystemdUnit<'dbus> { Ok(()) } + pub async fn enable(&self) -> Result { + let manager = SystemdManagerProxy::new(&self.connection).await?; + let (_, res) = manager + .enable_unit_files(&[self.name.as_str()], false, false) + .await?; + Ok(res.len() > 0) + } + + pub async fn disable(&self) -> Result { + let manager = SystemdManagerProxy::new(&self.connection).await?; + let res = manager + .disable_unit_files(&[self.name.as_str()], false) + .await?; + Ok(res.len() > 0) + } + + pub async fn mask(&self) -> Result { + let manager = SystemdManagerProxy::new(&self.connection).await?; + let res = manager + .mask_unit_files(&[self.name.as_str()], false) + .await?; + Ok(res.len() > 0) + } + + pub async fn unmask(&self) -> Result { + let manager = SystemdManagerProxy::new(&self.connection).await?; + let res = manager + .unmask_unit_files(&[self.name.as_str()], false) + .await?; + Ok(res.len() > 0) + } + pub async fn active(&self) -> Result { Ok(self.proxy.active_state().await? == "active") } + + pub async fn enabled(&self) -> Result { + Ok(match self.proxy.unit_file_state().await?.as_str() { + "enabled" => EnableState::Enabled, + "disabled" => EnableState::Disbled, + "masked" => EnableState::Masked, + state => bail!("Unknown state {state}"), + }) + } +} + +pub fn escape(name: &str) -> String { + let mut parts = String::new(); + for c in name.chars() { + if c.is_ascii_alphanumeric() { + parts.push(c); + } else { + let escaped = format!("_{:02x}", u32::from(c)); + parts.push_str(escaped.as_str()); + } + } + parts +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_escape() { + assert_eq!(escape("systemd"), "systemd"); + assert_eq!(escape("system d"), "system_20d"); + } } diff --git a/src/wifi.rs b/src/wifi.rs index 6a461ad..2daf3ae 100644 --- a/src/wifi.rs +++ b/src/wifi.rs @@ -151,7 +151,7 @@ async fn restart_iwd(connection: Connection) -> Result<()> { .inspect_err(|message| error!("restart_iwd: reload systemd got an error: {message}"))?; // worked, now restart iwd - let unit = SystemdUnit::new(connection, "iwd_2eservice").await?; + let unit = SystemdUnit::new(connection, "iwd.service").await?; unit.restart() .await .inspect_err(|message| error!("restart_iwd: restart unit got an error: {message}"))