use sandbox::Command;
use libc::{execve, fork, pid_t, waitpid, WEXITSTATUS, WIFEXITED, WTERMSIG};
use std::ffi::CString;
use std::io;
use std::ptr;
use std::str;
pub fn exec(command: &Command) -> io::Error {
let mut args: Vec<_> = vec![command.module_path.as_ptr()];
for arg in command.args.iter() {
args.push(arg.as_ptr())
}
args.push(ptr::null());
let env: Vec<_> = command
.env
.iter()
.map(|(key, value)| {
let entry = format!(
"{}={}",
str::from_utf8(key.to_bytes()).unwrap(),
str::from_utf8(value.to_bytes()).unwrap()
);
CString::new(entry).unwrap()
}).collect();
let mut env: Vec<_> = env.iter().map(|entry| entry.as_ptr()).collect();
env.push(ptr::null());
unsafe {
execve(command.module_path.as_ptr(), args.as_ptr(), env.as_ptr());
}
io::Error::last_os_error()
}
pub fn spawn(command: &Command) -> io::Result<Process> {
unsafe {
match fork() {
0 => {
drop(exec(command));
panic!()
}
pid => Ok(Process { pid: pid }),
}
}
}
#[allow(missing_copy_implementations)]
pub struct Process {
pub pid: pid_t,
}
impl Process {
pub fn wait(&self) -> io::Result<ExitStatus> {
let mut stat = 0;
loop {
let pid = unsafe { waitpid(-1, &mut stat, 0) };
if pid < 0 {
return Err(io::Error::last_os_error());
}
if pid == self.pid {
break;
}
}
unsafe {
if WIFEXITED(stat) {
Ok(ExitStatus::Code(WEXITSTATUS(stat) as i32))
} else {
Ok(ExitStatus::Signal(WTERMSIG(stat) as i32))
}
}
}
}
pub enum ExitStatus {
Code(i32),
Signal(i32),
}
impl ExitStatus {
#[inline]
pub fn success(&self) -> bool {
match *self {
ExitStatus::Code(0) => true,
_ => false,
}
}
}