about summary refs log tree commit diff
path: root/src/libnative
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnative')
-rw-r--r--src/libnative/io/process.rs212
1 files changed, 105 insertions, 107 deletions
diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs
index 591c34e9be5..28f0817670b 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<T>(prog: &str, args: &[~str], cb: |**libc::c_char| -> T) -> T {
+fn with_argv<T>(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<T>(prog: &str, args: &[~str], cb: |**libc::c_char| -> T) -> T {
 }
 
 #[cfg(unix)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: |*c_void| -> T) -> T {
+fn with_envp<T>(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<T>(env: Option<~[(~str, ~str)]>, cb: |*mut c_void| -> T) -> T {
     }
 }
 
+#[cfg(windows)]
 fn with_dirp<T>(d: Option<&Path>, cb: |*libc::c_char| -> T) -> T {
     match d {
       Some(dir) => dir.with_c_str(|buf| cb(buf)),