diff --git a/swhks/src/environ.rs b/swhks/src/environ.rs new file mode 100644 index 0000000..cef57ea --- /dev/null +++ b/swhks/src/environ.rs @@ -0,0 +1,84 @@ +//! Environ.rs +//! Defines modules and structs for handling environment variables and paths. + +use std::{env::VarError, path::PathBuf}; + +use nix::unistd; + +// The main struct for handling environment variables. +// Contains the values of the environment variables in the form of PathBuffers. +pub struct Env { + pub data_home: PathBuf, + pub home: PathBuf, + pub runtime_dir: PathBuf, +} + +/// Error type for the Env struct. +/// Contains all the possible errors that can occur when trying to get an environment variable. +#[derive(Debug)] +pub enum EnvError { + DataHomeNotSet, + HomeNotSet, + RuntimeDirNotSet, + GenericError(String), +} + +impl Env { + /// Constructs a new Env struct. + /// This function is called only once and the result is stored in a static variable. + pub fn construct() -> Self { + 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."); + std::process::exit(1); + } + }; + + let data_home = match Self::get_env("XDG_DATA_HOME") { + Ok(val) => val, + Err(e) => match e { + EnvError::DataHomeNotSet => { + log::warn!( + "XDG_DATA_HOME Variable is not set, falling back on hardcoded path." + ); + home.join(".local/share") + } + _ => panic!("Unexpected error: {:#?}", e), + }, + }; + + let runtime_dir = match Self::get_env("XDG_RUNTIME_DIR") { + Ok(val) => val, + Err(e) => match e { + EnvError::RuntimeDirNotSet => { + log::warn!( + "XDG_RUNTIME_DIR Variable is not set, falling back on hardcoded path." + ); + PathBuf::from(format!("/run/user/{}", unistd::Uid::current())) + } + _ => panic!("Unexpected error: {:#?}", e), + }, + }; + + Self { data_home, home, runtime_dir } + } + + /// Actual interface to get the environment variable. + fn get_env(name: &str) -> Result { + match std::env::var(name) { + Ok(val) => Ok(PathBuf::from(val)), + Err(e) => match e { + VarError::NotPresent => match name { + "XDG_DATA_HOME" => Err(EnvError::DataHomeNotSet), + "HOME" => Err(EnvError::HomeNotSet), + "XDG_RUNTIME_DIR" => Err(EnvError::RuntimeDirNotSet), + _ => Err(EnvError::GenericError(format!("{} not set", name))), + }, + VarError::NotUnicode(_) => { + Err(EnvError::GenericError(format!("{} not unicode", name))) + } + }, + } + } +} diff --git a/swhks/src/main.rs b/swhks/src/main.rs index 77d0911..3de2eae 100644 --- a/swhks/src/main.rs +++ b/swhks/src/main.rs @@ -1,20 +1,22 @@ use clap::arg; +use environ::Env; use nix::{ sys::stat::{umask, Mode}, - unistd, unistd::daemon, }; +use std::io::Read; +use std::time::{SystemTime, UNIX_EPOCH}; use std::{ env, fs, fs::OpenOptions, - io::prelude::*, os::unix::net::UnixListener, path::Path, process::{exit, id, Command, Stdio}, - time::{SystemTime, UNIX_EPOCH}, }; use sysinfo::{ProcessExt, System, SystemExt}; +mod environ; + fn main() -> std::io::Result<()> { let app = clap::Command::new("swhks") .version(env!("CARGO_PKG_VERSION")) @@ -38,7 +40,10 @@ fn main() -> std::io::Result<()> { log::trace!("Setting process umask."); umask(Mode::S_IWGRP | Mode::S_IWOTH); - let (pid_file_path, sock_file_path) = get_file_paths(); + // This is used to initialize the environment variables only once + let environment = environ::Env::construct(); + + let (pid_file_path, sock_file_path) = get_file_paths(&environment); let log_file_name = if let Some(val) = args.value_of("log") { val.to_string() @@ -51,29 +56,7 @@ fn main() -> std::io::Result<()> { } }; - match env::var("XDG_DATA_HOME") { - Ok(val) => { - log::info!( - "XDG_DATA_HOME Variable is present, using it's value for default file path." - ); - format!("{}/swhks/swhks-{}.log", val, time) - } - Err(e) => { - log::trace!( - "XDG_DATA_HOME Variable is not set, falling back on hardcoded path.\nError: {:#?}", - e - ); - match env::var("HOME") { - Ok(val) => format!("{}/.local/share/swhks/swhks-{}.log", val, time), - Err(_) => { - log::error!( - "HOME Variable is not set, cannot fall back on hardcoded path for XDG_DATA_HOME." - ); - exit(1); - } - } - } - } + format!("{}/swhks/swhks-{}.log", environment.data_home.to_string_lossy(), time) }; let log_path = Path::new(&log_file_name); @@ -142,27 +125,11 @@ fn main() -> std::io::Result<()> { } } -fn get_file_paths() -> (String, String) { - match env::var("XDG_RUNTIME_DIR") { - Ok(val) => { - log::info!( - "XDG_RUNTIME_DIR Variable is present, using it's value as default file path." - ); - - let pid_file_path = format!("{}/swhks.pid", val); - let sock_file_path = format!("{}/swhkd.sock", val); +fn get_file_paths(env: &Env) -> (String, String) { + let pid_file_path = format!("{}/swhks.pid", env.runtime_dir.to_string_lossy()); + let sock_file_path = format!("{}/swhkd.sock", env.runtime_dir.to_string_lossy()); - (pid_file_path, sock_file_path) - } - Err(e) => { - log::trace!("XDG_RUNTIME_DIR Variable is not set, falling back on hardcoded path.\nError: {:#?}", e); - - let pid_file_path = format!("/run/user/{}/swhks.pid", unistd::Uid::current()); - let sock_file_path = format!("/run/user/{}/swhkd.sock", unistd::Uid::current()); - - (pid_file_path, sock_file_path) - } - } + (pid_file_path, sock_file_path) } fn run_system_command(command: &str, log_path: &Path) {