From ff10fecac58731e521f18dc0a9aa4f0c126f9c2a Mon Sep 17 00:00:00 2001 From: innocentzero Date: Tue, 26 Mar 2024 23:18:16 +0530 Subject: [PATCH] [refactor] environment for swhkd (#246) * refactor: New Env for swhkd * Refactor Functions * Fix Spelling in environ * Fix spelling in daemon * Add Path Validations * Run formatting Signed-off-by: innocentzero --- swhkd/src/daemon.rs | 35 +++-------- swhkd/src/environ.rs | 141 +++++++++++++++++++++++++++++++++++++++++++ swhks/src/environ.rs | 12 ++-- 3 files changed, 158 insertions(+), 30 deletions(-) create mode 100644 swhkd/src/environ.rs diff --git a/swhkd/src/daemon.rs b/swhkd/src/daemon.rs index 6c08a8b..2ba1e57 100644 --- a/swhkd/src/daemon.rs +++ b/swhkd/src/daemon.rs @@ -26,6 +26,7 @@ use tokio_stream::{StreamExt, StreamMap}; use tokio_udev::{AsyncMonitorSocket, EventType, MonitorBuilder}; mod config; +mod environ; mod perms; mod uinput; @@ -77,27 +78,19 @@ async fn main() -> Result<(), Box> { env_logger::init(); log::trace!("Logger initialized."); - let invoking_uid = match env::var("PKEXEC_UID") { - Ok(uid) => { - let uid = uid.parse::().unwrap(); - log::trace!("Invoking UID: {}", uid); - uid - } - Err(_) => { - log::error!("Failed to launch swhkd!!!"); - log::error!("Make sure to launch the binary with pkexec."); - exit(1); - } - }; + let env = environ::Env::construct(); + log::trace!("Environment Aquired"); + + let invoking_uid = env.pkexec_id; - setup_swhkd(invoking_uid); + setup_swhkd(invoking_uid, env.xdg_runtime_dir.clone().to_string_lossy().to_string()); let load_config = || { // Drop privileges to the invoking user. perms::drop_privileges(invoking_uid); let config_file_path: PathBuf = - args.config.as_ref().map_or_else(|| fetch_xdg_config_path(), |file| file.clone()); + args.config.as_ref().map_or_else(fetch_xdg_config_path, |file| file.clone()); log::debug!("Using config file path: {:#?}", config_file_path); @@ -246,7 +239,7 @@ async fn main() -> Result<(), Box> { tokio::pin!(hotkey_repeat_timer); // The socket we're sending the commands to. - let socket_file_path = fetch_xdg_runtime_socket_path(); + let socket_file_path = env.fetch_xdg_runtime_socket_path(); loop { select! { _ = &mut hotkey_repeat_timer, if &last_hotkey.is_some() => { @@ -514,22 +507,12 @@ pub fn fetch_xdg_runtime_socket_path() -> PathBuf { } } -pub fn setup_swhkd(invoking_uid: u32) { +pub fn setup_swhkd(invoking_uid: u32, runtime_path: String) { // Set a sane process umask. log::trace!("Setting process umask."); umask(Mode::S_IWGRP | Mode::S_IWOTH); // Get the runtime path and create it if needed. - let runtime_path: String = match env::var("XDG_RUNTIME_DIR") { - Ok(runtime_path) => { - log::debug!("XDG_RUNTIME_DIR exists: {:#?}", runtime_path); - Path::new(&runtime_path).join("swhkd").to_str().unwrap().to_owned() - } - Err(_) => { - log::error!("XDG_RUNTIME_DIR has not been set."); - String::from("/run/swhkd/") - } - }; if !Path::new(&runtime_path).exists() { match fs::create_dir_all(Path::new(&runtime_path)) { Ok(_) => { diff --git a/swhkd/src/environ.rs b/swhkd/src/environ.rs new file mode 100644 index 0000000..1cb1bae --- /dev/null +++ b/swhkd/src/environ.rs @@ -0,0 +1,141 @@ +use std::{ + env::VarError, + path::{Path, PathBuf}, +}; + +pub struct Env { + pub pkexec_id: u32, + pub xdg_config_home: PathBuf, + pub xdg_runtime_socket: PathBuf, + pub xdg_runtime_dir: PathBuf, +} + +#[derive(Debug)] +pub enum EnvError { + PkexecNotFound, + XdgConfigNotFound, + XdgRuntimeNotFound, + PathNotFound, + GenericError(String), +} + +impl Env { + pub fn construct() -> Self { + let pkexec_id = match Self::get_env("PKEXEC_UID") { + Ok(val) => match val.parse::() { + Ok(val) => val, + Err(_) => { + log::error!("Failed to launch swhkd!!!"); + log::error!("Make sure to launch the binary with pkexec."); + std::process::exit(1); + } + }, + Err(_) => { + log::error!("Failed to launch swhkd!!!"); + log::error!("Make sure to launch the binary with pkexec."); + std::process::exit(1); + } + }; + + let xdg_config_home = match Self::get_env("XDG_CONFIG_HOME") { + Ok(val) => match validate_path(&PathBuf::from(val)) { + Ok(val) => val, + Err(e) => match e { + EnvError::PathNotFound => { + log::warn!("XDG_CONFIG_HOME does not exist, using hardcoded /etc"); + PathBuf::from("/etc") + } + _ => { + eprintln!("Failed to get XDG_CONFIG_HOME: {:?}", e); + std::process::exit(1); + } + }, + }, + Err(e) => match e { + EnvError::XdgConfigNotFound => { + log::warn!("XDG_CONFIG_HOME not found, using hardcoded /etc"); + PathBuf::from("/etc") + } + _ => { + eprintln!("Failed to get XDG_CONFIG_HOME: {:?}", e); + std::process::exit(1); + } + }, + }; + + let xdg_runtime_socket = match Self::get_env("XDG_RUNTIME_DIR") { + Ok(val) => match validate_path(&PathBuf::from(val).join("swhkd.sock")) { + Ok(val) => val, + Err(e) => match e { + EnvError::PathNotFound => { + log::warn!("XDG_RUNTIME_DIR does not exist, using hardcoded /run/user"); + PathBuf::from(format!("/run/user/{}", pkexec_id)) + } + _ => { + eprintln!("Failed to get XDG_RUNTIME_DIR: {:?}", e); + std::process::exit(1); + } + }, + }, + Err(e) => match e { + EnvError::XdgRuntimeNotFound => { + log::warn!("XDG_RUNTIME_DIR not found, using hardcoded /run/user"); + PathBuf::from(format!("/run/user/{}", pkexec_id)) + } + _ => { + eprintln!("Failed to get XDG_RUNTIME_DIR: {:?}", e); + std::process::exit(1); + } + }, + }; + + let xdg_runtime_dir = match Self::get_env("XDG_RUNTIME_DIR") { + Ok(val) => PathBuf::from(val), + Err(e) => match e { + EnvError::XdgRuntimeNotFound => { + log::warn!("XDG_RUNTIME_DIR not found, using hardcoded /run/swhkd"); + PathBuf::from("/run/swhkd") + } + _ => { + eprintln!("Failed to get XDG_RUNTIME_DIR: {:?}", e); + std::process::exit(1); + } + }, + }; + + Self { pkexec_id, xdg_config_home, xdg_runtime_dir, xdg_runtime_socket } + } + + fn get_env(name: &str) -> Result { + match std::env::var(name) { + Ok(val) => Ok(val), + Err(e) => match e { + VarError::NotPresent => match name { + "PKEXEC_UID" => Err(EnvError::PkexecNotFound), + "XDG_CONFIG_HOME" => Err(EnvError::XdgConfigNotFound), + "XDG_RUNTIME_DIR" => Err(EnvError::XdgRuntimeNotFound), + _ => Err(EnvError::GenericError(e.to_string())), + }, + VarError::NotUnicode(_) => { + Err(EnvError::GenericError("Not a valid unicode".to_string())) + } + }, + } + } + + pub fn fetch_xdg_config_path(&self) -> PathBuf { + PathBuf::from(&self.xdg_config_home).join("swhkd/swhkdrc") + } + + pub fn fetch_xdg_runtime_socket_path(&self) -> PathBuf { + PathBuf::from(&self.xdg_runtime_dir).join("swhkd.sock") + } +} + +fn validate_path(path: &Path) -> Result { + if path.exists() { + Ok(path.to_path_buf()) + } else { + Err(EnvError::PathNotFound) + } +} diff --git a/swhks/src/environ.rs b/swhks/src/environ.rs index cef57ea..97c65bf 100644 --- a/swhks/src/environ.rs +++ b/swhks/src/environ.rs @@ -20,6 +20,7 @@ pub enum EnvError { DataHomeNotSet, HomeNotSet, RuntimeDirNotSet, + PathNotFound, GenericError(String), } @@ -30,7 +31,7 @@ impl Env { let home = match Self::get_env("HOME") { Ok(val) => val, Err(_) => { - eprintln!("HOME Variable is not set, cannot fall back on hardcoded path for XDG_DATA_HOME."); + eprintln!("HOME Variable is not set/found, cannot fall back on hardcoded path for XDG_DATA_HOME."); std::process::exit(1); } }; @@ -38,7 +39,7 @@ impl Env { let data_home = match Self::get_env("XDG_DATA_HOME") { Ok(val) => val, Err(e) => match e { - EnvError::DataHomeNotSet => { + EnvError::DataHomeNotSet | EnvError::PathNotFound => { log::warn!( "XDG_DATA_HOME Variable is not set, falling back on hardcoded path." ); @@ -51,7 +52,7 @@ impl Env { let runtime_dir = match Self::get_env("XDG_RUNTIME_DIR") { Ok(val) => val, Err(e) => match e { - EnvError::RuntimeDirNotSet => { + EnvError::RuntimeDirNotSet | EnvError::PathNotFound => { log::warn!( "XDG_RUNTIME_DIR Variable is not set, falling back on hardcoded path." ); @@ -67,7 +68,10 @@ impl Env { /// Actual interface to get the environment variable. fn get_env(name: &str) -> Result { match std::env::var(name) { - Ok(val) => Ok(PathBuf::from(val)), + Ok(val) => match PathBuf::from(&val).exists() { + true => Ok(PathBuf::from(val)), + false => Err(EnvError::PathNotFound), + }, Err(e) => match e { VarError::NotPresent => match name { "XDG_DATA_HOME" => Err(EnvError::DataHomeNotSet),