diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 63730eb7e2..5ae746416c 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -238,6 +238,7 @@ pub fn install(no_prompt: bool, verbose: bool, quiet: bool, mut opts: InstallOpt do_pre_install_sanity_checks()?; do_pre_install_options_sanity_checks(&opts)?; check_existence_of_rustc_or_cargo_in_path(no_prompt)?; + #[cfg(unix)] do_anti_sudo_check(no_prompt)?; let mut term = term2::stdout(); @@ -467,63 +468,33 @@ fn do_pre_install_options_sanity_checks(opts: &InstallOpts) -> Result<()> { // If the user is trying to install with sudo, on some systems this will // result in writing root-owned files to the user's home directory, because // sudo is configured not to change $HOME. Don't let that bogosity happen. -#[allow(dead_code)] +#[cfg(unix)] fn do_anti_sudo_check(no_prompt: bool) -> Result<()> { - use std::ffi::OsString; - - #[cfg(unix)] - pub fn home_mismatch() -> (bool, OsString, String) { - use std::ffi::CStr; - use std::mem::MaybeUninit; - use std::ptr; - + pub fn home_mismatch() -> (bool, PathBuf, PathBuf) { + let fallback = || (false, PathBuf::new(), PathBuf::new()); // test runner should set this, nothing else - if let Ok(true) = env::var("RUSTUP_INIT_SKIP_SUDO_CHECK").map(|s| s == "yes") { - return (false, OsString::new(), String::new()); - } - let mut buf = [0u8; 1024]; - let mut pwd = MaybeUninit::::uninit(); - let mut pwdp: *mut libc::passwd = ptr::null_mut(); - let rv = unsafe { - libc::getpwuid_r( - libc::geteuid(), - pwd.as_mut_ptr(), - buf.as_mut_ptr().cast::(), - buf.len(), - (&mut pwdp) as *mut *mut libc::passwd, - ) - }; - if rv != 0 || pwdp.is_null() { - warn!("getpwuid_r: couldn't get user data"); - return (false, OsString::new(), String::new()); + if env::var_os("RUSTUP_INIT_SKIP_SUDO_CHECK").map_or(false, |s| s == "yes") { + return fallback(); } - let pwd = unsafe { pwd.assume_init() }; - let pw_dir = unsafe { CStr::from_ptr(pwd.pw_dir) }.to_str().ok(); - let env_home = env::var_os("HOME"); - match (env_home, pw_dir) { - (None, _) | (_, None) => (false, OsString::new(), String::new()), - (Some(eh), Some(pd)) => (eh != pd, eh, String::from(pd)), - } - } - #[cfg(not(unix))] - pub fn home_mismatch() -> (bool, OsString, String) { - (false, OsString::new(), String::new()) + match (utils::home_dir_from_passwd(), env::var_os("HOME")) { + (Some(pw), Some(eh)) if eh != pw => return (true, PathBuf::from(eh), pw), + (None, _) => warn!("getpwuid_r: couldn't get user data"), + _ => {} + } + fallback() } - match (home_mismatch(), no_prompt) { - ((false, _, _), _) => (), - ((true, env_home, euid_home), false) => { + match home_mismatch() { + (false, _, _) => {} + (true, env_home, euid_home) => { err!("$HOME differs from euid-obtained home directory: you may be using sudo"); - err!("$HOME directory: {:?}", env_home); - err!("euid-obtained home directory: {}", euid_home); - err!("if this is what you want, restart the installation with `-y'"); - process::exit(1); - } - ((true, env_home, euid_home), true) => { - warn!("$HOME differs from euid-obtained home directory: you may be using sudo"); - warn!("$HOME directory: {:?}", env_home); - warn!("euid-obtained home directory: {}", euid_home); + err!("$HOME directory: {}", env_home.display()); + err!("euid-obtained home directory: {}", euid_home.display()); + if !no_prompt { + err!("if this is what you want, restart the installation with `-y'"); + process::exit(1); + } } } diff --git a/src/utils/utils.rs b/src/utils/utils.rs index b920f6e99b..14330f99c9 100644 --- a/src/utils/utils.rs +++ b/src/utils/utils.rs @@ -670,6 +670,39 @@ impl<'a> io::Read for FileReaderWithProgress<'a> { } } +// search user database to get home dir of euid user +#[cfg(unix)] +pub fn home_dir_from_passwd() -> Option { + use std::ffi::CStr; + use std::mem::MaybeUninit; + use std::os::unix::ffi::OsStringExt; + use std::ptr; + unsafe { + let init_size = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { + -1 => 1024, + n => n as usize, + }; + let mut buf = Vec::with_capacity(init_size); + let mut pwd: MaybeUninit = MaybeUninit::uninit(); + let mut pwdp = ptr::null_mut(); + match libc::getpwuid_r( + libc::geteuid(), + pwd.as_mut_ptr(), + buf.as_mut_ptr(), + buf.capacity(), + &mut pwdp, + ) { + 0 if !pwdp.is_null() => { + let pwd = pwd.assume_init(); + let bytes = CStr::from_ptr(pwd.pw_dir).to_bytes().to_vec(); + let pw_dir = OsString::from_vec(bytes); + Some(PathBuf::from(pw_dir)) + } + _ => None, + } + } +} + #[cfg(test)] mod tests { use super::*;