Skip to content

Commit f01add1

Browse files
committed
Add signal support, better exec error handling
1 parent 267bc54 commit f01add1

File tree

1 file changed

+80
-34
lines changed

1 file changed

+80
-34
lines changed

src/libstd/sys/redox/process.rs

Lines changed: 80 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use env;
1313
use ffi::OsStr;
1414
use fmt;
1515
use io::{self, Error, ErrorKind};
16-
use libc::{self, pid_t, c_int, gid_t, uid_t};
16+
use libc::{self, pid_t, gid_t, uid_t};
1717
use path::Path;
1818
use sys::fd::FileDesc;
1919
use sys::fs::{File, OpenOptions};
@@ -145,33 +145,79 @@ impl Command {
145145

146146
pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
147147
-> io::Result<(Process, StdioPipes)> {
148-
if self.saw_nul {
149-
return Err(io::Error::new(ErrorKind::InvalidInput,
150-
"nul byte found in provided data"));
151-
}
152-
153-
let (ours, theirs) = self.setup_io(default, needs_stdin)?;
154-
155-
let pid = unsafe {
156-
match cvt(libc::clone(libc::CLONE_VFORK))? {
157-
0 => {
158-
let err = self.do_exec(theirs);
159-
let _ = libc::exit((-err.raw_os_error().unwrap_or(libc::EINVAL)) as usize);
160-
unreachable!();
161-
}
162-
n => n as pid_t,
163-
}
164-
};
165-
166-
let mut status_mux = 0;
167-
if cvt(libc::waitpid(pid, &mut status_mux, libc::WNOHANG))? == pid {
168-
match libc::Error::demux(status_mux) {
169-
Ok(status) => Ok((Process { pid: pid, status: Some(ExitStatus::from(status as c_int)) }, ours)),
170-
Err(err) => Err(io::Error::from_raw_os_error(err.errno)),
171-
}
172-
} else {
173-
Ok((Process { pid: pid, status: None }, ours))
174-
}
148+
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
149+
150+
if self.saw_nul {
151+
return Err(io::Error::new(ErrorKind::InvalidInput,
152+
"nul byte found in provided data"));
153+
}
154+
155+
let (ours, theirs) = self.setup_io(default, needs_stdin)?;
156+
let (input, output) = pipe::anon_pipe()?;
157+
158+
let pid = unsafe {
159+
match cvt(libc::clone(0))? {
160+
0 => {
161+
drop(input);
162+
let err = self.do_exec(theirs);
163+
let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
164+
let bytes = [
165+
(errno >> 24) as u8,
166+
(errno >> 16) as u8,
167+
(errno >> 8) as u8,
168+
(errno >> 0) as u8,
169+
CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
170+
CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
171+
];
172+
// pipe I/O up to PIPE_BUF bytes should be atomic, and then
173+
// we want to be sure we *don't* run at_exit destructors as
174+
// we're being torn down regardless
175+
assert!(output.write(&bytes).is_ok());
176+
let _ = libc::exit(1);
177+
panic!("failed to exit");
178+
}
179+
n => n,
180+
}
181+
};
182+
183+
let mut p = Process { pid: pid, status: None };
184+
drop(output);
185+
let mut bytes = [0; 8];
186+
187+
// loop to handle EINTR
188+
loop {
189+
match input.read(&mut bytes) {
190+
Ok(0) => return Ok((p, ours)),
191+
Ok(8) => {
192+
assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
193+
"Validation on the CLOEXEC pipe failed: {:?}", bytes);
194+
let errno = combine(&bytes[0.. 4]);
195+
assert!(p.wait().is_ok(),
196+
"wait() should either return Ok or panic");
197+
return Err(Error::from_raw_os_error(errno))
198+
}
199+
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
200+
Err(e) => {
201+
assert!(p.wait().is_ok(),
202+
"wait() should either return Ok or panic");
203+
panic!("the CLOEXEC pipe failed: {:?}", e)
204+
},
205+
Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
206+
assert!(p.wait().is_ok(),
207+
"wait() should either return Ok or panic");
208+
panic!("short read on the CLOEXEC pipe")
209+
}
210+
}
211+
}
212+
213+
fn combine(arr: &[u8]) -> i32 {
214+
let a = arr[0] as u32;
215+
let b = arr[1] as u32;
216+
let c = arr[2] as u32;
217+
let d = arr[3] as u32;
218+
219+
((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
220+
}
175221
}
176222

177223
pub fn exec(&mut self, default: Stdio) -> io::Error {
@@ -378,11 +424,11 @@ impl fmt::Debug for Command {
378424

379425
/// Unix exit statuses
380426
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
381-
pub struct ExitStatus(c_int);
427+
pub struct ExitStatus(i32);
382428

383429
impl ExitStatus {
384430
fn exited(&self) -> bool {
385-
true
431+
self.0 & 0x7F == 0
386432
}
387433

388434
pub fn success(&self) -> bool {
@@ -391,23 +437,23 @@ impl ExitStatus {
391437

392438
pub fn code(&self) -> Option<i32> {
393439
if self.exited() {
394-
Some(self.0)
440+
Some((self.0 >> 8) & 0xFF)
395441
} else {
396442
None
397443
}
398444
}
399445

400446
pub fn signal(&self) -> Option<i32> {
401447
if !self.exited() {
402-
Some(self.0)
448+
Some(self.0 & 0x7F)
403449
} else {
404450
None
405451
}
406452
}
407453
}
408454

409-
impl From<c_int> for ExitStatus {
410-
fn from(a: c_int) -> ExitStatus {
455+
impl From<i32> for ExitStatus {
456+
fn from(a: i32) -> ExitStatus {
411457
ExitStatus(a)
412458
}
413459
}

0 commit comments

Comments
 (0)