gaol/platform/unix/
process.rs

1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Child process management on POSIX systems.
12
13use 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}