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