// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use env;
-use ffi::CString;
use io::{self, Error, ErrorKind};
use libc::{self, c_int, gid_t, pid_t, uid_t};
use ptr;
return Ok((ret, ours))
}
- let possible_paths = self.compute_possible_paths(envp.as_ref());
-
let (input, output) = sys::pipe::anon_pipe()?;
let pid = unsafe {
match cvt(libc::fork())? {
0 => {
drop(input);
- let err = self.do_exec(theirs, envp.as_ref(), possible_paths);
+ let err = self.do_exec(theirs, envp.as_ref());
let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
let bytes = [
(errno >> 24) as u8,
"nul byte found in provided data")
}
- let possible_paths = self.compute_possible_paths(envp.as_ref());
match self.setup_io(default, true) {
- Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref(), possible_paths) },
+ Ok((_, theirs)) => unsafe { self.do_exec(theirs, envp.as_ref()) },
Err(e) => e,
}
}
- fn compute_possible_paths(&self, maybe_envp: Option<&CStringArray>) -> Option<Vec<CString>> {
- let program = self.get_program().as_bytes();
- if program.contains(&b'/') {
- return None;
- }
- // Outside the match so we can borrow it for the lifetime of the function.
- let parent_path = env::var("PATH").ok();
- let paths = match maybe_envp {
- Some(envp) => {
- match envp.get_items().iter().find(|var| var.as_bytes().starts_with(b"PATH=")) {
- Some(p) => &p.as_bytes()[5..],
- None => return None,
- }
- },
- // maybe_envp is None if the process isn't changing the parent's env at all.
- None => {
- match parent_path.as_ref() {
- Some(p) => p.as_bytes(),
- None => return None,
- }
- },
- };
-
- let mut possible_paths = vec![];
- for path in paths.split(|p| *p == b':') {
- let mut binary_path = Vec::with_capacity(program.len() + path.len() + 1);
- binary_path.extend_from_slice(path);
- binary_path.push(b'/');
- binary_path.extend_from_slice(program);
- let c_binary_path = CString::new(binary_path).unwrap();
- possible_paths.push(c_binary_path);
- }
- return Some(possible_paths);
- }
-
// And at this point we've reached a special time in the life of the
// child. The child must now be considered hamstrung and unable to
// do anything other than syscalls really. Consider the following
unsafe fn do_exec(
&mut self,
stdio: ChildPipes,
- maybe_envp: Option<&CStringArray>,
- maybe_possible_paths: Option<Vec<CString>>,
+ maybe_envp: Option<&CStringArray>
) -> io::Error {
use sys::{self, cvt_r};
if let Some(ref cwd) = *self.get_cwd() {
t!(cvt(libc::chdir(cwd.as_ptr())));
}
+ if let Some(envp) = maybe_envp {
+ *sys::os::environ() = envp.as_ptr();
+ }
// emscripten has no signal support.
#[cfg(not(any(target_os = "emscripten")))]
t!(callback());
}
- // If the program isn't an absolute path, and our environment contains a PATH var, then we
- // implement the PATH traversal ourselves so that it honors the child's PATH instead of the
- // parent's. This mirrors the logic that exists in glibc's execvpe, except using the
- // child's env to fetch PATH.
- match maybe_possible_paths {
- Some(possible_paths) => {
- let mut pending_error = None;
- for path in possible_paths {
- libc::execve(
- path.as_ptr(),
- self.get_argv().as_ptr(),
- maybe_envp.map(|envp| envp.as_ptr()).unwrap_or_else(|| *sys::os::environ())
- );
- let err = io::Error::last_os_error();
- match err.kind() {
- io::ErrorKind::PermissionDenied => {
- // If we saw a PermissionDenied, and none of the other entries in
- // $PATH are successful, then we'll return the first EACCESS we see.
- if pending_error.is_none() {
- pending_error = Some(err);
- }
- },
- // Errors which indicate we failed to find a file are ignored and we try
- // the next entry in the path.
- io::ErrorKind::NotFound | io::ErrorKind::TimedOut => {
- continue
- },
- // Any other error means we found a file and couldn't execute it.
- _ => {
- return err;
- }
- }
- }
- if let Some(err) = pending_error {
- return err;
- }
- return io::Error::from_raw_os_error(libc::ENOENT);
- },
- _ => {
- libc::execve(
- self.get_argv()[0],
- self.get_argv().as_ptr(),
- maybe_envp.map(|envp| envp.as_ptr()).unwrap_or_else(|| *sys::os::environ())
- );
- return io::Error::last_os_error()
- }
- }
+ libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
+ io::Error::last_os_error()
}
#[cfg(not(any(target_os = "macos", target_os = "freebsd",