about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorJeremy Soller <jackpot51@gmail.com>2016-11-17 10:22:07 -0700
committerJeremy Soller <jackpot51@gmail.com>2016-11-17 10:22:07 -0700
commitf01add1a3bc3d86ee62f5819fa6ed9f79d453665 (patch)
tree492992a6c6e0510b55681a242fa111b08e61db27 /src/libstd
parent267bc54fbd2cfeadde7a87fc2aa3fb975ff58b6c (diff)
downloadrust-f01add1a3bc3d86ee62f5819fa6ed9f79d453665.tar.gz
rust-f01add1a3bc3d86ee62f5819fa6ed9f79d453665.zip
Add signal support, better exec error handling
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/sys/redox/process.rs114
1 files changed, 80 insertions, 34 deletions
diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs
index 934cf20bf07..92694e4b222 100644
--- a/src/libstd/sys/redox/process.rs
+++ b/src/libstd/sys/redox/process.rs
@@ -13,7 +13,7 @@ use env;
 use ffi::OsStr;
 use fmt;
 use io::{self, Error, ErrorKind};
-use libc::{self, pid_t, c_int, gid_t, uid_t};
+use libc::{self, pid_t, gid_t, uid_t};
 use path::Path;
 use sys::fd::FileDesc;
 use sys::fs::{File, OpenOptions};
@@ -145,33 +145,79 @@ impl Command {
 
     pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
                  -> io::Result<(Process, StdioPipes)> {
-        if self.saw_nul {
-            return Err(io::Error::new(ErrorKind::InvalidInput,
-                                      "nul byte found in provided data"));
-        }
-
-        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
-
-        let pid = unsafe {
-            match cvt(libc::clone(libc::CLONE_VFORK))? {
-                0 => {
-                    let err = self.do_exec(theirs);
-                    let _ = libc::exit((-err.raw_os_error().unwrap_or(libc::EINVAL)) as usize);
-                    unreachable!();
-                }
-                n => n as pid_t,
-            }
-        };
-
-        let mut status_mux = 0;
-        if cvt(libc::waitpid(pid, &mut status_mux, libc::WNOHANG))? == pid {
-            match libc::Error::demux(status_mux) {
-                Ok(status) => Ok((Process { pid: pid, status: Some(ExitStatus::from(status as c_int)) }, ours)),
-                Err(err) => Err(io::Error::from_raw_os_error(err.errno)),
-            }
-        } else {
-            Ok((Process { pid: pid, status: None }, ours))
-        }
+         const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
+
+         if self.saw_nul {
+             return Err(io::Error::new(ErrorKind::InvalidInput,
+                                       "nul byte found in provided data"));
+         }
+
+         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+         let (input, output) = pipe::anon_pipe()?;
+
+         let pid = unsafe {
+             match cvt(libc::clone(0))? {
+                 0 => {
+                     drop(input);
+                     let err = self.do_exec(theirs);
+                     let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
+                     let bytes = [
+                         (errno >> 24) as u8,
+                         (errno >> 16) as u8,
+                         (errno >>  8) as u8,
+                         (errno >>  0) as u8,
+                         CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
+                         CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
+                     ];
+                     // pipe I/O up to PIPE_BUF bytes should be atomic, and then
+                     // we want to be sure we *don't* run at_exit destructors as
+                     // we're being torn down regardless
+                     assert!(output.write(&bytes).is_ok());
+                     let _ = libc::exit(1);
+                     panic!("failed to exit");
+                 }
+                 n => n,
+             }
+         };
+
+         let mut p = Process { pid: pid, status: None };
+         drop(output);
+         let mut bytes = [0; 8];
+
+         // loop to handle EINTR
+         loop {
+             match input.read(&mut bytes) {
+                 Ok(0) => return Ok((p, ours)),
+                 Ok(8) => {
+                     assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
+                             "Validation on the CLOEXEC pipe failed: {:?}", bytes);
+                     let errno = combine(&bytes[0.. 4]);
+                     assert!(p.wait().is_ok(),
+                             "wait() should either return Ok or panic");
+                     return Err(Error::from_raw_os_error(errno))
+                 }
+                 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                 Err(e) => {
+                     assert!(p.wait().is_ok(),
+                             "wait() should either return Ok or panic");
+                     panic!("the CLOEXEC pipe failed: {:?}", e)
+                 },
+                 Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
+                     assert!(p.wait().is_ok(),
+                             "wait() should either return Ok or panic");
+                     panic!("short read on the CLOEXEC pipe")
+                 }
+             }
+         }
+
+         fn combine(arr: &[u8]) -> i32 {
+             let a = arr[0] as u32;
+             let b = arr[1] as u32;
+             let c = arr[2] as u32;
+             let d = arr[3] as u32;
+
+             ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
+         }
     }
 
     pub fn exec(&mut self, default: Stdio) -> io::Error {
@@ -378,11 +424,11 @@ impl fmt::Debug for Command {
 
 /// Unix exit statuses
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatus(c_int);
+pub struct ExitStatus(i32);
 
 impl ExitStatus {
     fn exited(&self) -> bool {
-        true
+        self.0 & 0x7F == 0
     }
 
     pub fn success(&self) -> bool {
@@ -391,7 +437,7 @@ impl ExitStatus {
 
     pub fn code(&self) -> Option<i32> {
         if self.exited() {
-            Some(self.0)
+            Some((self.0 >> 8) & 0xFF)
         } else {
             None
         }
@@ -399,15 +445,15 @@ impl ExitStatus {
 
     pub fn signal(&self) -> Option<i32> {
         if !self.exited() {
-            Some(self.0)
+            Some(self.0 & 0x7F)
         } else {
             None
         }
     }
 }
 
-impl From<c_int> for ExitStatus {
-    fn from(a: c_int) -> ExitStatus {
+impl From<i32> for ExitStatus {
+    fn from(a: i32) -> ExitStatus {
         ExitStatus(a)
     }
 }