From 19f82493de9b528776e0ec3c0e66e107949f60d4 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Thu, 5 Jan 2023 19:56:51 +1300 Subject: [PATCH] Better config fie handling for the asusd daemon Should address #304 --- CHANGELOG.md | 2 ++ daemon/src/config.rs | 30 ++++++++++------------- daemon/src/ctrl_anime/config.rs | 36 ++++++++++----------------- daemon/src/ctrl_aura/config.rs | 39 +++++++++++------------------- daemon/src/ctrl_profiles/config.rs | 35 ++++++++++++++------------- daemon/src/daemon.rs | 4 +-- daemon/src/lib.rs | 26 ++++++++++++++++++++ 7 files changed, 87 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d266993..03bdc2da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed +- Better handling of `/etc/asusd` not existing +- Better handling of non-existant config files - Added option to set `disable_nvidia_powerd_on_battery` - Add short log entry to throttle_thermal_policy change detection - ROGCC: Don't notify user if changing to same mux mode diff --git a/daemon/src/config.rs b/daemon/src/config.rs index 7b320107..f57786a0 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -1,11 +1,12 @@ use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; -use std::path::PathBuf; use log::{error, warn}; use serde_derive::{Deserialize, Serialize}; -pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; +use crate::config_file_open; + +pub static CONFIG_FILE: &str = "/etc/asusd/asusd.conf"; #[derive(Deserialize, Serialize, Default)] pub struct Config { @@ -30,12 +31,7 @@ impl Config { /// `load` will attempt to read the config, and panic if the dir is missing pub fn load() -> Self { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(&PathBuf::from(CONFIG_PATH)) - .unwrap_or_else(|e| panic!("Error opening {}, {}", CONFIG_PATH, e)); // okay to cause panic here + let mut file = config_file_open(CONFIG_FILE); let mut buf = String::new(); let config; if let Ok(read_len) = file.read_to_string(&mut buf) { @@ -50,13 +46,13 @@ impl Config { } else { warn!( "Could not deserialise {}.\nWill rename to {}-old and recreate config", - CONFIG_PATH, CONFIG_PATH + CONFIG_FILE, CONFIG_FILE ); - let cfg_old = CONFIG_PATH.to_owned() + "-old"; - std::fs::rename(CONFIG_PATH, cfg_old).unwrap_or_else(|err| { + let cfg_old = CONFIG_FILE.to_owned() + "-old"; + std::fs::rename(CONFIG_FILE, cfg_old).unwrap_or_else(|err| { panic!( "Could not rename. Please remove {} then restart service: Error {}", - CONFIG_PATH, err + CONFIG_FILE, err ) }); config = Self::new(); @@ -71,21 +67,21 @@ impl Config { pub fn read(&mut self) { let mut file = OpenOptions::new() .read(true) - .open(CONFIG_PATH) - .unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err)); + .open(CONFIG_FILE) + .unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_FILE, err)); let mut buf = String::new(); if let Ok(l) = file.read_to_string(&mut buf) { if l == 0 { - warn!("File is empty {}", CONFIG_PATH); + warn!("File is empty {}", CONFIG_FILE); } else { *self = serde_json::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH)); + .unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_FILE)); } } } pub fn write(&self) { - let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config"); + let mut file = File::create(CONFIG_FILE).expect("Couldn't overwrite config"); let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed"); file.write_all(json.as_bytes()) .unwrap_or_else(|err| error!("Could not write config: {}", err)); diff --git a/daemon/src/ctrl_anime/config.rs b/daemon/src/ctrl_anime/config.rs index 76e087d2..f940cce6 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -7,9 +7,9 @@ use rog_anime::error::AnimeError; use rog_anime::{ActionData, ActionLoader, AnimTime, AnimeType, Fade, Vec2}; use serde_derive::{Deserialize, Serialize}; -use crate::VERSION; +use crate::{config_file_open, VERSION}; -pub static ANIME_CONFIG_PATH: &str = "/etc/asusd/anime.conf"; +pub static CONFIG_FILE: &str = "anime.conf"; pub static ANIME_CACHE_PATH: &str = "/etc/asusd/anime-cache.conf"; #[derive(Deserialize, Serialize)] @@ -143,17 +143,7 @@ impl Default for AnimeConfig { impl AnimeConfig { /// `load` will attempt to read the config, and panic if the dir is missing pub fn load() -> Self { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(ANIME_CONFIG_PATH) - .unwrap_or_else(|_| { - panic!( - "The file {} or directory /etc/asusd/ is missing", - ANIME_CONFIG_PATH - ) - }); // okay to cause panic here + let mut file = config_file_open(CONFIG_FILE); let mut buf = String::new(); if let Ok(read_len) = file.read_to_string(&mut buf) { if read_len == 0 { @@ -177,13 +167,13 @@ impl AnimeConfig { } warn!( "Could not deserialise {}.\nWill rename to {}-old and recreate config", - ANIME_CONFIG_PATH, ANIME_CONFIG_PATH + CONFIG_FILE, CONFIG_FILE ); - let cfg_old = ANIME_CONFIG_PATH.to_string() + "-old"; - std::fs::rename(ANIME_CONFIG_PATH, cfg_old).unwrap_or_else(|err| { + let cfg_old = CONFIG_FILE.to_string() + "-old"; + std::fs::rename(CONFIG_FILE, cfg_old).unwrap_or_else(|err| { panic!( "Could not rename. Please remove {} then restart service: Error {}", - ANIME_CONFIG_PATH, err + CONFIG_FILE, err ) }); } @@ -244,29 +234,29 @@ impl AnimeConfig { // Should be okay to unwrap this as is since it is a Default let json = serde_json::to_string_pretty(&config).unwrap(); file.write_all(json.as_bytes()) - .unwrap_or_else(|_| panic!("Could not write {}", ANIME_CONFIG_PATH)); + .unwrap_or_else(|_| panic!("Could not write {}", CONFIG_FILE)); config } pub fn read(&mut self) { let mut file = OpenOptions::new() .read(true) - .open(ANIME_CONFIG_PATH) - .unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err)); + .open(CONFIG_FILE) + .unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_FILE, err)); let mut buf = String::new(); if let Ok(l) = file.read_to_string(&mut buf) { if l == 0 { - warn!("File is empty {}", ANIME_CONFIG_PATH); + warn!("File is empty {}", CONFIG_FILE); } else { let x: AnimeConfig = serde_json::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", ANIME_CONFIG_PATH)); + .unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_FILE)); *self = x; } } } pub fn write(&self) { - let mut file = File::create(ANIME_CONFIG_PATH).expect("Couldn't overwrite config"); + let mut file = File::create(CONFIG_FILE).expect("Couldn't overwrite config"); let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed"); file.write_all(json.as_bytes()) .unwrap_or_else(|err| error!("Could not write config: {}", err)); diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index 8e52583d..f315e2c9 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeMap, HashSet}; -use std::fs::{File, OpenOptions}; +use std::fs::File; use std::io::{Read, Write}; use log::{error, warn}; @@ -10,7 +10,9 @@ use rog_platform::hid_raw::HidRaw; use rog_platform::keyboard_led::KeyboardLed; use serde_derive::{Deserialize, Serialize}; -pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; +use crate::config_file_open; + +static CONFIG_FILE: &str = "aura.conf"; /// Enable/disable LED control in various states such as /// when the device is awake, suspended, shutting down or @@ -190,17 +192,7 @@ impl Default for AuraConfig { impl AuraConfig { /// `load` will attempt to read the config, and panic if the dir is missing pub fn load(supported_led_modes: &LaptopLedData) -> Self { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(AURA_CONFIG_PATH) - .unwrap_or_else(|_| { - panic!( - "The file {} or directory /etc/asusd/ is missing", - AURA_CONFIG_PATH - ) - }); // okay to cause panic here + let mut file = config_file_open(CONFIG_FILE); let mut buf = String::new(); if let Ok(read_len) = file.read_to_string(&mut buf) { if read_len == 0 { @@ -211,13 +203,13 @@ impl AuraConfig { } warn!( "Could not deserialise {}.\nWill rename to {}-old and recreate config", - AURA_CONFIG_PATH, AURA_CONFIG_PATH + CONFIG_FILE, CONFIG_FILE ); - let cfg_old = AURA_CONFIG_PATH.to_string() + "-old"; - std::fs::rename(AURA_CONFIG_PATH, cfg_old).unwrap_or_else(|err| { + let cfg_old = CONFIG_FILE.to_string() + "-old"; + std::fs::rename(CONFIG_FILE, cfg_old).unwrap_or_else(|err| { panic!( "Could not rename. Please remove {} then restart service: Error {}", - AURA_CONFIG_PATH, err + CONFIG_FILE, err ) }); } @@ -259,29 +251,26 @@ impl AuraConfig { // Should be okay to unwrap this as is since it is a Default let json = serde_json::to_string(&config).unwrap(); file.write_all(json.as_bytes()) - .unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH)); + .unwrap_or_else(|_| panic!("Could not write {}", CONFIG_FILE)); config } pub fn read(&mut self) { - let mut file = OpenOptions::new() - .read(true) - .open(AURA_CONFIG_PATH) - .unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err)); + let mut file = config_file_open(CONFIG_FILE); let mut buf = String::new(); if let Ok(l) = file.read_to_string(&mut buf) { if l == 0 { - warn!("File is empty {}", AURA_CONFIG_PATH); + warn!("File is empty {}", CONFIG_FILE); } else { let x = serde_json::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH)); + .unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_FILE)); *self = x; } } } pub fn write(&self) { - let mut file = File::create(AURA_CONFIG_PATH).expect("Couldn't overwrite config"); + let mut file = File::create(CONFIG_FILE).expect("Couldn't overwrite config"); let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed"); file.write_all(json.as_bytes()) .unwrap_or_else(|err| error!("Could not write config: {}", err)); diff --git a/daemon/src/ctrl_profiles/config.rs b/daemon/src/ctrl_profiles/config.rs index 4addc171..92752a08 100644 --- a/daemon/src/ctrl_profiles/config.rs +++ b/daemon/src/ctrl_profiles/config.rs @@ -1,14 +1,19 @@ use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; +use std::path::PathBuf; use log::{error, warn}; use rog_profiles::{FanCurveProfiles, Profile}; use serde_derive::{Deserialize, Serialize}; +use crate::{config_file, config_file_open}; + +static CONFIG_FILE: &str = "profile.conf"; + #[derive(Deserialize, Serialize, Debug)] pub struct ProfileConfig { #[serde(skip)] - config_path: String, + config_path: PathBuf, /// For restore on boot pub active_profile: Profile, /// States to restore @@ -16,7 +21,7 @@ pub struct ProfileConfig { } impl ProfileConfig { - fn new(config_path: String) -> Self { + fn new(config_path: PathBuf) -> Self { Self { config_path, active_profile: Profile::Balanced, @@ -24,13 +29,9 @@ impl ProfileConfig { } } - pub fn load(config_path: String) -> Self { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(&config_path) - .unwrap_or_else(|_| panic!("The directory /etc/asusd/ is missing")); // okay to cause panic here + pub fn load() -> Self { + let config_path = config_file(CONFIG_FILE); + let mut file = config_file_open(CONFIG_FILE); let mut buf = String::new(); let mut config; if let Ok(read_len) = file.read_to_string(&mut buf) { @@ -41,15 +42,15 @@ impl ProfileConfig { config.config_path = config_path; } else { warn!( - "Could not deserialise {}.\nWill rename to {}-old and recreate config", - config_path, config_path + "Could not deserialise {config_path:?}.\nWill rename to {config_path:?}-old \ + and recreate config", ); let mut cfg_old = config_path.clone(); - cfg_old.push_str("-old"); + cfg_old.push("-old"); std::fs::rename(config_path.clone(), cfg_old).unwrap_or_else(|err| { panic!( - "Could not rename. Please remove {} then restart service: Error {}", - config_path, err + "Could not rename. Please remove {config_path:?} then restart service: \ + Error {err}", ) }); config = Self::new(config_path); @@ -64,15 +65,15 @@ impl ProfileConfig { let mut file = OpenOptions::new() .read(true) .open(&self.config_path) - .unwrap_or_else(|err| panic!("Error reading {}: {}", self.config_path, err)); + .unwrap_or_else(|err| panic!("Error reading {:?}: {}", self.config_path, err)); let mut buf = String::new(); if let Ok(l) = file.read_to_string(&mut buf) { if l == 0 { - warn!("File is empty {}", self.config_path); + warn!("File is empty {:?}", self.config_path); } else { let mut data: ProfileConfig = toml::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", self.config_path)); + .unwrap_or_else(|_| panic!("Could not deserialise {:?}", self.config_path)); // copy over serde skipped values data.config_path = self.config_path.clone(); *self = data; diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 7f5feead..562b1528 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -27,8 +27,6 @@ use rog_profiles::Profile; use tokio::time::sleep; use zbus::SignalContext; -static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf"; - #[tokio::main] async fn main() -> Result<(), Box> { let mut logger = env_logger::Builder::new(); @@ -98,7 +96,7 @@ async fn start_daemon() -> Result<(), Box> { } if Profile::is_platform_profile_supported() { - let profile_config = ProfileConfig::load(PROFILE_CONFIG_PATH.into()); + let profile_config = ProfileConfig::load(); match CtrlPlatformProfile::new(profile_config) { Ok(ctrl) => { let zbus = ProfileZbus(Arc::new(Mutex::new(ctrl))); diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index d46a0c11..7a09d23e 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -17,7 +17,9 @@ pub mod ctrl_supported; pub mod error; +use std::fs::{create_dir, File, OpenOptions}; use std::future::Future; +use std::path::PathBuf; use async_trait::async_trait; use log::{debug, info, warn}; @@ -28,6 +30,30 @@ use zbus::{Connection, SignalContext}; use crate::error::RogError; +static CONFIG_PATH_BASE: &str = "/etc/asusd/"; + +/// Create a `PathBuf` for `file`. If the base config dir `CONFIG_PATH_BASE` +/// does not exist it is created. +fn config_file(file: &str) -> PathBuf { + let mut config = PathBuf::from(CONFIG_PATH_BASE); + if !config.exists() { + create_dir(config.as_path()).unwrap_or_else(|_| panic!("Could not create {config:?}")); + } + config.push(file); + config +} + +/// Open a config file as read/write. If the file or dir does not exist then +/// both are created. +pub fn config_file_open(file: &str) -> File { + OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(config_file(file)) + .unwrap_or_else(|_| panic!("The file {file} or directory {CONFIG_PATH_BASE} is missing")) +} + /// This macro adds a function which spawns an `inotify` task on the passed in /// `Executor`. ///