diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 21da0104c2f8d70eb2539791fde4d2b22a7c681a..e3e6ae425266e586265c3e2866390bd8c83c4420 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -305,6 +305,25 @@ fn spawn_process_os(cfg: ProcessConfig, }) } + // To have the spawning semantics of unix/windows stay the same, we need to + // read the *child's* PATH if one is provided. See #15149 for more details. + let program = cfg.env.and_then(|env| { + for &(ref key, ref v) in env.iter() { + if b"PATH" != key.as_bytes_no_nul() { continue } + + // Split the value and test each path to see if the program exists. + for path in os::split_paths(v.as_bytes_no_nul()).move_iter() { + let path = path.join(cfg.program.as_bytes_no_nul()) + .with_extension(os::consts::EXE_EXTENSION); + if path.exists() { + return Some(path.to_c_str()) + } + } + break + } + None + }); + unsafe { let mut si = zeroed_startupinfo(); si.cb = mem::size_of::() as DWORD; @@ -362,7 +381,8 @@ fn spawn_process_os(cfg: ProcessConfig, try!(set_fd(&out_fd, &mut si.hStdOutput, false)); try!(set_fd(&err_fd, &mut si.hStdError, false)); - let cmd_str = make_command_line(cfg.program, cfg.args); + let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program), + cfg.args); let mut pi = zeroed_process_information(); let mut create_err = None; diff --git a/src/test/run-pass/issue-15149.rs b/src/test/run-pass/issue-15149.rs new file mode 100644 index 0000000000000000000000000000000000000000..d76a7109ced8e7d87a192cc263432a7cede1116f --- /dev/null +++ b/src/test/run-pass/issue-15149.rs @@ -0,0 +1,56 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(phase)] +extern crate native; +#[phase(plugin)] +extern crate green; + +use native::NativeTaskBuilder; +use std::io::{TempDir, Command, fs}; +use std::os; +use std::task::TaskBuilder; + +// FIXME(#15149) libgreen still needs to be update. There is an open PR for it +// but it is not yet merged. +// green_start!(main) + +fn main() { + // If we're the child, make sure we were invoked correctly + let args = os::args(); + if args.len() > 1 && args.get(1).as_slice() == "child" { + return assert_eq!(args.get(0).as_slice(), "mytest"); + } + + test(); + let (tx, rx) = channel(); + TaskBuilder::new().native().spawn(proc() { + tx.send(test()); + }); + rx.recv(); +} + +fn test() { + // If we're the parent, copy our own binary to a tempr directory, and then + // make it executable. + let dir = TempDir::new("mytest").unwrap(); + let me = os::self_exe_name().unwrap(); + let dest = dir.path().join(format!("mytest{}", os::consts::EXE_SUFFIX)); + fs::copy(&me, &dest).unwrap(); + + // Append the temp directory to our own PATH. + let mut path = os::split_paths(os::getenv("PATH").unwrap_or(String::new())); + path.push(dir.path().clone()); + let path = os::join_paths(path.as_slice()).unwrap(); + + Command::new("mytest").env("PATH", path.as_slice()) + .arg("child") + .spawn().unwrap(); +}