diff --git a/src/rustup-cli/setup_mode.rs b/src/rustup-cli/setup_mode.rs index 26191f257c..b822b684e6 100644 --- a/src/rustup-cli/setup_mode.rs +++ b/src/rustup-cli/setup_mode.rs @@ -1,10 +1,49 @@ use std::env; +use std::process; use self_update::{self, InstallOpts}; use errors::*; use clap::{App, Arg, AppSettings}; use rustup_dist::dist::TargetTriple; use common; +mod sys_check { + #[cfg(unix)] + pub fn home_mismatch() -> bool { + extern crate libc as c; + + use std::env; + use std::ffi::CStr; + use std::mem; + use std::ops::Deref; + use std::ptr; + + // test runner should set this, nothing else + if env::var("RUSTUP_INIT_SKIP_SUDO_CHECK").as_ref().map(Deref::deref).ok() == Some("yes") { + return false; + } + let mut pwd = unsafe { mem::uninitialized::() }; + let mut pwdp: *mut c::passwd = ptr::null_mut(); + let mut buf = [0u8; 1024]; + let rv = unsafe { c::getpwuid_r(c::geteuid(), &mut pwd, mem::transmute(&mut buf), buf.len(), &mut pwdp) }; + if rv != 0 || pwdp == ptr::null_mut() { + warn!("getpwuid_r: couldn't get user data"); + return false; + } + let pw_dir = unsafe { CStr::from_ptr(pwd.pw_dir) }.to_str().ok(); + let env_home = env::var_os("HOME"); + let env_home = env_home.as_ref().map(Deref::deref); + match (env_home, pw_dir) { + (None, _) | (_, None) => false, + (Some(ref eh), Some(ref pd)) => eh != pd + } + } + + #[cfg(not(unix))] + pub fn home_mismatch() -> bool { + false + } +} + pub fn main() -> Result<()> { let args: Vec<_> = env::args().collect(); let arg1 = args.get(1).map(|a| &**a); @@ -39,6 +78,17 @@ pub fn main() -> Result<()> { let matches = cli.get_matches(); let no_prompt = matches.is_present("no-prompt"); + match (self::sys_check::home_mismatch(), no_prompt) { + (false, _) => (), + (true, false) => { + err!("$HOME differs from euid-obtained home directory: you may be using sudo"); + err!("if this is what you want, restart the installation with `-y'"); + process::exit(1); + }, + (true, true) => { + warn!("$HOME differs from euid-obtained home directory: you may be using sudo"); + } + } let verbose = matches.is_present("verbose"); let default_host = matches.value_of("default-host").map(|s| s.to_owned()).unwrap_or_else(|| { TargetTriple::from_host_or_build().to_string() diff --git a/src/rustup-mock/src/clitools.rs b/src/rustup-mock/src/clitools.rs index 83ff319d2a..3074db01dd 100644 --- a/src/rustup-mock/src/clitools.rs +++ b/src/rustup-mock/src/clitools.rs @@ -242,6 +242,9 @@ pub fn env(config: &Config, cmd: &mut Command) { // This is only used for some installation tests on unix where CARGO_HOME // above is unset cmd.env("HOME", config.homedir.to_string_lossy().to_string()); + + // Setting HOME will confuse the sudo check for rustup-init. Override it + cmd.env("RUSTUP_INIT_SKIP_SUDO_CHECK", "yes"); } pub fn run(config: &Config, name: &str, args: &[&str], env: &[(&str, &str)]) -> SanitizedOutput {