gaol/platform/unix/
process.rs1use sandbox::Command;
14
15use libc::{execve, fork, pid_t, waitpid, WEXITSTATUS, WIFEXITED, WTERMSIG};
16use std::ffi::CString;
17use std::io;
18use std::ptr;
19use std::str;
20
21pub fn exec(command: &Command) -> io::Error {
22 let mut args: Vec<_> = vec![command.module_path.as_ptr()];
23 for arg in command.args.iter() {
24 args.push(arg.as_ptr())
25 }
26 args.push(ptr::null());
27
28 let env: Vec<_> = command
29 .env
30 .iter()
31 .map(|(key, value)| {
32 let entry = format!(
33 "{}={}",
34 str::from_utf8(key.to_bytes()).unwrap(),
35 str::from_utf8(value.to_bytes()).unwrap()
36 );
37 CString::new(entry).unwrap()
38 }).collect();
39 let mut env: Vec<_> = env.iter().map(|entry| entry.as_ptr()).collect();
40 env.push(ptr::null());
41
42 unsafe {
43 execve(command.module_path.as_ptr(), args.as_ptr(), env.as_ptr());
44 }
45
46 io::Error::last_os_error()
47}
48
49pub fn spawn(command: &Command) -> io::Result<Process> {
50 unsafe {
51 match fork() {
52 0 => {
53 drop(exec(command));
54 panic!()
55 }
56 pid => Ok(Process { pid: pid }),
57 }
58 }
59}
60
61#[allow(missing_copy_implementations)]
62pub struct Process {
63 pub pid: pid_t,
64}
65
66impl Process {
67 pub fn wait(&self) -> io::Result<ExitStatus> {
68 let mut stat = 0;
69 loop {
70 let pid = unsafe { waitpid(-1, &mut stat, 0) };
71 if pid < 0 {
72 return Err(io::Error::last_os_error());
73 }
74 if pid == self.pid {
75 break;
76 }
77 }
78
79 unsafe {
80 if WIFEXITED(stat) {
81 Ok(ExitStatus::Code(WEXITSTATUS(stat) as i32))
82 } else {
83 Ok(ExitStatus::Signal(WTERMSIG(stat) as i32))
84 }
85 }
86 }
87}
88
89pub enum ExitStatus {
90 Code(i32),
91 Signal(i32),
92}
93
94impl ExitStatus {
95 #[inline]
96 pub fn success(&self) -> bool {
97 match *self {
98 ExitStatus::Code(0) => true,
99 _ => false,
100 }
101 }
102}