diff --git a/src/main.rs b/src/main.rs index bc045e6..d06c7a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ use crate::readline::term::{LineWriter, RawModeGuard, raw_mode}; use crate::readline::{Prompt, ReadlineEvent, ShedVi}; use crate::signal::{GOT_SIGWINCH, JOB_DONE, QUIT_CODE, check_signals, sig_setup, signals_pending}; use crate::state::{ - AutoCmdKind, read_logic, read_shopts, source_rc, write_jobs, write_meta, write_shopts, + AutoCmdKind, read_logic, read_shopts, source_env, source_login, source_rc, write_jobs, write_meta, write_shopts }; use clap::Parser; use state::write_vars; @@ -128,6 +128,10 @@ fn main() -> ExitCode { unsafe { env::set_var("SHLVL", "1") }; } + if let Err(e) = source_env() { + e.print_error(); + } + if let Err(e) = if let Some(cmd) = args.command { exec_dash_c(cmd) } else if args.stdin || !isatty(STDIN_FILENO).unwrap_or(false) { @@ -217,6 +221,11 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> { let _raw_mode = raw_mode(); // sets raw mode, restores termios on drop sig_setup(args.login_shell); + if args.login_shell + && let Err(e) = source_login() { + e.print_error(); + } + if let Err(e) = source_rc() { e.print_error(); } diff --git a/src/state.rs b/src/state.rs index 690a5d9..a9c6bb9 100644 --- a/src/state.rs +++ b/src/state.rs @@ -8,7 +8,7 @@ use std::{ time::Duration, }; -use nix::unistd::{User, gethostname, getppid}; +use nix::unistd::{User, gethostname, getppid, getuid}; use regex::Regex; use crate::{ @@ -1872,19 +1872,39 @@ pub fn set_status(code: i32) { write_vars(|v| v.set_param(ShellParam::Status, &code.to_string())) } -pub fn source_rc() -> ShResult<()> { - let path = if let Ok(path) = env::var("SHED_RC") { +pub fn source_runtime_file(name: &str, env_var_name: Option<&str>) -> ShResult<()> { + let etc_path = PathBuf::from(format!("/etc/shed/{name}")); + if etc_path.is_file() + && let Err(e) = source_file(etc_path) { + e.print_error(); + } + + let path = if let Some(name) = env_var_name + && let Ok(path) = env::var(name) { PathBuf::from(&path) + } else if let Some(home) = get_home() { + home.join(format!(".{name}")) } else { - let home = env::var("HOME").unwrap(); - PathBuf::from(format!("{home}/.shedrc")) + return Err(ShErr::simple(ShErrKind::InternalErr, "could not determine home path")); }; - if !path.exists() { - return Err(ShErr::simple(ShErrKind::InternalErr, ".shedrc not found")); + if !path.is_file() { + return Ok(()) } source_file(path) } +pub fn source_rc() -> ShResult<()> { + source_runtime_file("shedrc", Some("SHED_RC")) +} + +pub fn source_login() -> ShResult<()> { + source_runtime_file("shed_profile", Some("SHED_PROFILE")) +} + +pub fn source_env() -> ShResult<()> { + source_runtime_file("shedenv", Some("SHED_ENV")) +} + pub fn source_file(path: PathBuf) -> ShResult<()> { let source_name = path.to_string_lossy().to_string(); let mut file = OpenOptions::new().read(true).open(path)?; @@ -1894,3 +1914,33 @@ pub fn source_file(path: PathBuf) -> ShResult<()> { exec_input(buf, None, false, Some(source_name))?; Ok(()) } + +#[track_caller] +pub fn get_home_unchecked() -> PathBuf { + if let Some(home) = get_home() { + home + } else { + let caller = std::panic::Location::caller(); + panic!("get_home_unchecked: could not determine home directory (called from {}:{})", caller.file(), caller.line()) + } +} + +#[track_caller] +pub fn get_home_str_unchecked() -> String { + if let Some(home) = get_home() { + home.to_string_lossy().to_string() + } else { + let caller = std::panic::Location::caller(); + panic!("get_home_str_unchecked: could not determine home directory (called from {}:{})", caller.file(), caller.line()) + } +} + +pub fn get_home() -> Option { + env::var("HOME").ok().map(PathBuf::from).or_else(|| { + User::from_uid(getuid()).ok().flatten().map(|u| u.dir) + }) +} + +pub fn get_home_str() -> Option { + get_home().map(|h| h.to_string_lossy().to_string()) +}