extern crate errno;
extern crate libc;
use errno::{Errno, errno};
use std::error::{self, Error};
use std::ffi::{CString, NulError};
use std::iter::{IntoIterator, Iterator};
use std::fmt;
use std::ptr;
#[derive(Debug)]
#[must_use]
pub enum ExecError {
BadArgument(NulError),
Errno(Errno),
}
impl error::Error for ExecError {
fn description(&self) -> &str {
match self {
&ExecError::BadArgument(_) => "bad argument to exec",
&ExecError::Errno(_) => "couldn't exec process",
}
}
fn cause(&self) -> Option<&error::Error> {
match self {
&ExecError::BadArgument(ref err) => Some(err),
&ExecError::Errno(_) => None,
}
}
}
impl fmt::Display for ExecError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ExecError::BadArgument(ref err) =>
write!(f, "{}: {}", self.description(), err),
&ExecError::Errno(err) =>
write!(f, "{}: {}", self.description(), err),
}
}
}
impl From<NulError> for ExecError {
fn from(err: NulError) -> ExecError {
ExecError::BadArgument(err)
}
}
macro_rules! exec_try {
( $ expr : expr ) => {
match $expr {
Ok(val) => val,
Err(err) => return From::from(err),
}
};
}
pub fn execvp<'a, S, I>(program: S, args: I) -> ExecError
where S: AsRef<str>, I: IntoIterator, I::Item: AsRef<str>
{
let program_cstring = exec_try!(CString::new(program.as_ref()));
let arg_cstrings = exec_try!(args.into_iter().map(|arg| {
CString::new(arg.as_ref())
}).collect::<Result<Vec<_>, _>>());
let mut arg_charptrs: Vec<_> = arg_cstrings.iter().map(|arg| {
arg.as_bytes_with_nul().as_ptr() as *const i8
}).collect();
arg_charptrs.push(ptr::null());
let res = unsafe {
libc::execvp(program_cstring.as_bytes_with_nul().as_ptr() as *const i8,
arg_charptrs.as_ptr())
};
if res < 0 {
ExecError::Errno(errno())
} else {
panic!("execvp returned unexpectedly")
}
}