Fix exec
This commit is contained in:
@@ -18,7 +18,7 @@ use path::Path;
|
||||
use sys::fd::FileDesc;
|
||||
use sys::fs::{File, OpenOptions};
|
||||
use sys::pipe::{self, AnonPipe};
|
||||
use sys::{self, cvt};
|
||||
use sys::cvt;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Command
|
||||
@@ -145,78 +145,32 @@ impl Command {
|
||||
|
||||
pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
|
||||
-> io::Result<(Process, StdioPipes)> {
|
||||
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) = sys::pipe::anon_pipe()?;
|
||||
|
||||
let pid = unsafe {
|
||||
match cvt(libc::clone(0))? {
|
||||
match cvt(libc::clone(libc::CLONE_VFORK))? {
|
||||
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);
|
||||
let _ = libc::exit((-err.raw_os_error().unwrap_or(libc::EINVAL)) as usize);
|
||||
unreachable!();
|
||||
}
|
||||
n => n as pid_t,
|
||||
}
|
||||
};
|
||||
|
||||
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")
|
||||
}
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
} else {
|
||||
Ok((Process { pid: pid, status: None }, ours))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user