diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 591c34e9be551..28f0817670b8f 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -446,132 +446,129 @@ fn spawn_process_os(config: p::ProcessConfig, assert_eq!(ret, 0); } - let pipe = os::pipe(); - let mut input = file::FileDesc::new(pipe.input, true); - let mut output = file::FileDesc::new(pipe.out, true); + let dirp = dir.map(|p| p.to_c_str()); + let dirp = dirp.as_ref().map(|c| c.with_ref(|p| p)).unwrap_or(ptr::null()); + + with_envp(env, proc(envp) { + with_argv(config.program, config.args, proc(argv) unsafe { + let pipe = os::pipe(); + let mut input = file::FileDesc::new(pipe.input, true); + let mut output = file::FileDesc::new(pipe.out, true); + + set_cloexec(output.fd()); + + let pid = fork(); + if pid < 0 { + fail!("failure in fork: {}", os::last_os_error()); + } else if pid > 0 { + drop(output); + let mut bytes = [0, ..4]; + return match input.inner_read(bytes) { + Ok(4) => { + let errno = (bytes[0] << 24) as i32 | + (bytes[1] << 16) as i32 | + (bytes[2] << 8) as i32 | + (bytes[3] << 0) as i32; + Err(super::translate_error(errno, false)) + } + Err(e) => { + assert!(e.kind == io::BrokenPipe || + e.kind == io::EndOfFile, + "unexpected error: {}", e); + Ok(SpawnProcessResult { + pid: pid, + handle: ptr::null() + }) + } + Ok(..) => fail!("short read on the cloexec pipe"), + }; + } + drop(input); + + fn fail(output: &mut file::FileDesc) -> ! { + let errno = os::errno(); + let bytes = [ + (errno << 24) as u8, + (errno << 16) as u8, + (errno << 8) as u8, + (errno << 0) as u8, + ]; + assert!(output.inner_write(bytes).is_ok()); + unsafe { libc::_exit(1) } + } - unsafe { set_cloexec(output.fd()) }; + rustrt::rust_unset_sigprocmask(); - unsafe { - let pid = fork(); - if pid < 0 { - fail!("failure in fork: {}", os::last_os_error()); - } else if pid > 0 { - drop(output); - let mut bytes = [0, ..4]; - return match input.inner_read(bytes) { - Ok(4) => { - let errno = (bytes[0] << 24) as i32 | - (bytes[1] << 16) as i32 | - (bytes[2] << 8) as i32 | - (bytes[3] << 0) as i32; - Err(super::translate_error(errno, false)) - } - Err(e) => { - assert!(e.kind == io::BrokenPipe || - e.kind == io::EndOfFile, - "unexpected error: {}", e); - Ok(SpawnProcessResult { - pid: pid, - handle: ptr::null() - }) + if in_fd == -1 { + let _ = libc::close(libc::STDIN_FILENO); + } else if retry(|| dup2(in_fd, 0)) == -1 { + fail(&mut output); + } + if out_fd == -1 { + let _ = libc::close(libc::STDOUT_FILENO); + } else if retry(|| dup2(out_fd, 1)) == -1 { + fail(&mut output); + } + if err_fd == -1 { + let _ = libc::close(libc::STDERR_FILENO); + } else if retry(|| dup2(err_fd, 2)) == -1 { + fail(&mut output); + } + // close all other fds + for fd in range(3, getdtablesize()).rev() { + if fd != output.fd() { + let _ = close(fd as c_int); } - Ok(..) => fail!("short read on the cloexec pipe"), - }; - } - drop(input); - - fn fail(output: &mut file::FileDesc) -> ! { - let errno = os::errno(); - let bytes = [ - (errno << 24) as u8, - (errno << 16) as u8, - (errno << 8) as u8, - (errno << 0) as u8, - ]; - assert!(output.inner_write(bytes).is_ok()); - unsafe { libc::_exit(1) } - } - - rustrt::rust_unset_sigprocmask(); - - if in_fd == -1 { - let _ = libc::close(libc::STDIN_FILENO); - } else if retry(|| dup2(in_fd, 0)) == -1 { - fail(&mut output); - } - if out_fd == -1 { - let _ = libc::close(libc::STDOUT_FILENO); - } else if retry(|| dup2(out_fd, 1)) == -1 { - fail(&mut output); - } - if err_fd == -1 { - let _ = libc::close(libc::STDERR_FILENO); - } else if retry(|| dup2(err_fd, 2)) == -1 { - fail(&mut output); - } - // close all other fds - for fd in range(3, getdtablesize()).rev() { - if fd != output.fd() { - let _ = close(fd as c_int); } - } - match config.gid { - Some(u) => { - if libc::setgid(u as libc::gid_t) != 0 { - fail(&mut output); + match config.gid { + Some(u) => { + if libc::setgid(u as libc::gid_t) != 0 { + fail(&mut output); + } } + None => {} } - None => {} - } - match config.uid { - Some(u) => { - // When dropping privileges from root, the `setgroups` call will - // remove any extraneous groups. If we don't call this, then - // even though our uid has dropped, we may still have groups - // that enable us to do super-user things. This will fail if we - // aren't root, so don't bother checking the return value, this - // is just done as an optimistic privilege dropping function. - extern { - fn setgroups(ngroups: libc::c_int, - ptr: *libc::c_void) -> libc::c_int; - } - let _ = setgroups(0, 0 as *libc::c_void); + match config.uid { + Some(u) => { + // When dropping privileges from root, the `setgroups` call will + // remove any extraneous groups. If we don't call this, then + // even though our uid has dropped, we may still have groups + // that enable us to do super-user things. This will fail if we + // aren't root, so don't bother checking the return value, this + // is just done as an optimistic privilege dropping function. + extern { + fn setgroups(ngroups: libc::c_int, + ptr: *libc::c_void) -> libc::c_int; + } + let _ = setgroups(0, 0 as *libc::c_void); - if libc::setuid(u as libc::uid_t) != 0 { - fail(&mut output); + if libc::setuid(u as libc::uid_t) != 0 { + fail(&mut output); + } } + None => {} + } + if config.detach { + // Don't check the error of setsid because it fails if we're the + // process leader already. We just forked so it shouldn't return + // error, but ignore it anyway. + let _ = libc::setsid(); } - None => {} - } - if config.detach { - // Don't check the error of setsid because it fails if we're the - // process leader already. We just forked so it shouldn't return - // error, but ignore it anyway. - let _ = libc::setsid(); - } - - with_dirp(dir, |dirp| { if !dirp.is_null() && chdir(dirp) == -1 { fail(&mut output); } - }); - - with_envp(env, |envp| { if !envp.is_null() { set_environ(envp); } - with_argv(config.program, config.args, |argv| { - let _ = execvp(*argv, argv); - fail(&mut output); - }) + let _ = execvp(*argv, argv); + fail(&mut output); }) - } + }) } #[cfg(unix)] -fn with_argv(prog: &str, args: &[~str], cb: |**libc::c_char| -> T) -> T { +fn with_argv(prog: &str, args: &[~str], cb: proc:(**libc::c_char) -> T) -> T { use std::slice; // We can't directly convert `str`s into `*char`s, as someone needs to hold @@ -597,7 +594,7 @@ fn with_argv(prog: &str, args: &[~str], cb: |**libc::c_char| -> T) -> T { } #[cfg(unix)] -fn with_envp(env: Option<~[(~str, ~str)]>, cb: |*c_void| -> T) -> T { +fn with_envp(env: Option<~[(~str, ~str)]>, cb: proc:(*c_void) -> T) -> T { use std::slice; // On posixy systems we can pass a char** for envp, which is a @@ -645,6 +642,7 @@ fn with_envp(env: Option<~[(~str, ~str)]>, cb: |*mut c_void| -> T) -> T { } } +#[cfg(windows)] fn with_dirp(d: Option<&Path>, cb: |*libc::c_char| -> T) -> T { match d { Some(dir) => dir.with_c_str(|buf| cb(buf)),