about summary refs log tree commit diff
path: root/src/libstd/sys/unix/process2.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/unix/process2.rs')
-rw-r--r--src/libstd/sys/unix/process2.rs59
1 files changed, 36 insertions, 23 deletions
diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs
index dc6897fec8e..0b4e871454d 100644
--- a/src/libstd/sys/unix/process2.rs
+++ b/src/libstd/sys/unix/process2.rs
@@ -119,6 +119,12 @@ pub struct Process {
     pid: pid_t
 }
 
+pub enum Stdio {
+    Inherit,
+    Piped(AnonPipe),
+    None,
+}
+
 const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
 
 impl Process {
@@ -128,9 +134,9 @@ impl Process {
     }
 
     pub fn spawn(cfg: &Command,
-                 in_fd: Option<AnonPipe>,
-                 out_fd: Option<AnonPipe>,
-                 err_fd: Option<AnonPipe>) -> io::Result<Process> {
+                 in_fd: Stdio,
+                 out_fd: Stdio,
+                 err_fd: Stdio) -> io::Result<Process> {
         let dirp = cfg.cwd.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null());
 
         let (envp, _a, _b) = make_envp(cfg.env.as_ref());
@@ -224,9 +230,9 @@ impl Process {
                                argv: *const *const libc::c_char,
                                envp: *const libc::c_void,
                                dirp: *const libc::c_char,
-                               in_fd: Option<AnonPipe>,
-                               out_fd: Option<AnonPipe>,
-                               err_fd: Option<AnonPipe>) -> ! {
+                               in_fd: Stdio,
+                               out_fd: Stdio,
+                               err_fd: Stdio) -> ! {
         fn fail(output: &mut AnonPipe) -> ! {
             let errno = sys::os::errno() as u32;
             let bytes = [
@@ -244,23 +250,30 @@ impl Process {
             unsafe { libc::_exit(1) }
         }
 
-        // If a stdio file descriptor is set to be ignored, we don't
-        // actually close it, but rather open up /dev/null into that
-        // file descriptor. Otherwise, the first file descriptor opened
-        // up in the child would be numbered as one of the stdio file
-        // descriptors, which is likely to wreak havoc.
-        let setup = |src: Option<AnonPipe>, dst: c_int| {
-            src.map(|p| p.into_fd()).or_else(|| {
-                let mut opts = OpenOptions::new();
-                opts.read(dst == libc::STDIN_FILENO);
-                opts.write(dst != libc::STDIN_FILENO);
-                let devnull = CStr::from_ptr(b"/dev/null\0".as_ptr()
-                                                as *const _);
-                File::open_c(devnull, &opts).ok().map(|f| f.into_fd())
-            }).map(|fd| {
-                fd.unset_cloexec();
-                retry(|| libc::dup2(fd.raw(), dst)) != -1
-            }).unwrap_or(false)
+        let setup = |src: Stdio, dst: c_int| {
+            let fd = match src {
+                Stdio::Inherit => return true,
+                Stdio::Piped(pipe) => pipe.into_fd(),
+
+                // If a stdio file descriptor is set to be ignored, we open up
+                // /dev/null into that file descriptor. Otherwise, the first
+                // file descriptor opened up in the child would be numbered as
+                // one of the stdio file descriptors, which is likely to wreak
+                // havoc.
+                Stdio::None => {
+                    let mut opts = OpenOptions::new();
+                    opts.read(dst == libc::STDIN_FILENO);
+                    opts.write(dst != libc::STDIN_FILENO);
+                    let devnull = CStr::from_ptr(b"/dev/null\0".as_ptr()
+                                                    as *const _);
+                    if let Ok(f) = File::open_c(devnull, &opts) {
+                        f.into_fd()
+                    } else {
+                        return false
+                    }
+                }
+            };
+            retry(|| libc::dup2(fd.raw(), dst)) != -1
         };
 
         if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }