aboutsummaryrefslogtreecommitdiff
path: root/src/command.rs
blob: ddfa26997ad83b13f9c7bd985813cec5ba11a2b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! Command execution module.
//!
use std::ffi::OsStr;
use std::process::{Command,Child};
use std::io::{Result, Error, ErrorKind};

use libc::c_int;
use libc::types::os::arch::posix88::pid_t;

const WNOHANG: c_int = 0x00000001;

extern {
    /// wait for a child process to stop or terminate.
    pub fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t;
}

/// Extension to the Child struct that allows to check the status without block the
/// current thread.
pub trait ChildExt {
    fn wait_nohang(&mut self) -> Result<bool>;
}

impl ChildExt for Child {
    /// Checks if the calling child is a zombie and try to kill it, returning
    /// if it was killed or not.
    fn wait_nohang(&mut self) -> Result<bool> {
        let mut stat = 0i32;
        let pid = unsafe { waitpid(self.id() as i32, &mut stat, WNOHANG) };
        if pid < 0 {
            Err(Error::new(ErrorKind::NotFound, format!("pid not found {}", pid)))
        } else {
            if pid > 0 {
                Ok(self.wait()
                    .map(|x| {
                        x.success()
                    }).unwrap_or(false))
            } else {
                Ok(false)
            }
        }
    }
}

/// Executes the given command.
pub fn exec_cmd<S: AsRef<OsStr>>(program: S, args: &[S]) -> Result<Child> {
    Command::new(program).args(args).spawn()
}