diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index d3e8e73afe..8634649f7c 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -306,6 +306,10 @@ fn main() { Task::ready(()) } else { app.background_executor().spawn(async { + #[cfg(unix)] + { + load_shell_from_passwd().await.log_err(); + } load_login_shell_environment().await.log_err(); }) }; @@ -678,6 +682,56 @@ fn init_stdout_logger() { }) .init(); } + +#[cfg(unix)] +async fn load_shell_from_passwd() -> Result<()> { + let buflen = match unsafe { libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) } { + n if n < 0 => 1024, + n => n as usize, + }; + let mut buffer = Vec::with_capacity(buflen); + + let mut pwd: std::mem::MaybeUninit = std::mem::MaybeUninit::uninit(); + let mut result: *mut libc::passwd = std::ptr::null_mut(); + + let uid = unsafe { libc::getuid() }; + let status = unsafe { + libc::getpwuid_r( + uid, + pwd.as_mut_ptr(), + buffer.as_mut_ptr() as *mut libc::c_char, + buflen, + &mut result, + ) + }; + let entry = unsafe { pwd.assume_init() }; + + anyhow::ensure!( + status == 0, + "call to getpwuid_r failed. uid: {}, status: {}", + uid, + status + ); + anyhow::ensure!(!result.is_null(), "passwd entry for uid {} not found", uid); + anyhow::ensure!( + entry.pw_uid == uid, + "passwd entry has different uid ({}) than getuid ({}) returned", + entry.pw_uid, + uid, + ); + + let shell = unsafe { std::ffi::CStr::from_ptr(entry.pw_shell).to_str().unwrap() }; + if env::var("SHELL").map_or(true, |shell_env| shell_env != shell) { + log::info!( + "updating SHELL environment variable to value from passwd entry: {:?}", + shell, + ); + env::set_var("SHELL", shell); + } + + Ok(()) +} + async fn load_login_shell_environment() -> Result<()> { let marker = "ZED_LOGIN_SHELL_START"; let shell = env::var("SHELL").context(