1extern crate errno;
16extern crate libc;
17
18use errno::Errno;
19use errno::errno;
20use std::convert::From;
21use std::default::Default;
22use std::env;
23use std::io;
24use std::marker::PhantomData;
25use std::os::unix::process::ExitStatusExt;
26use std::process::ExitStatus;
27
28#[derive(Debug)]
29pub enum ShellError {
30 Status(String, ExitStatus),
31 IoError(io::Error),
32 VarError(env::VarError),
33 Errno(&'static str, Errno),
34 NoSuchProcess,
35}
36
37impl ShellError {
38 pub fn from_signal(command: String, signal: u8) -> Self {
39 ShellError::Status(command, ExitStatus::from_raw(128 + signal as i32))
40 }
41}
42
43impl From<io::Error> for ShellError {
44 fn from(error: io::Error) -> ShellError {
45 ShellError::IoError(error)
46 }
47}
48
49impl From<env::VarError> for ShellError {
50 fn from(error: env::VarError) -> ShellError {
51 ShellError::VarError(error)
52 }
53}
54
55pub struct SuccessfulExit(PhantomData<SuccessfulExit>);
56
57impl Default for SuccessfulExit {
58 fn default() -> Self {
59 SuccessfulExit(PhantomData::default())
60 }
61}
62
63pub type ShellResult = Result<SuccessfulExit, ShellError>;
64
65pub fn check_errno(name: &'static str,
66 result: libc::c_int) -> Result<libc::c_int, ShellError> {
67 if result != -1 {
68 Ok(result)
69 } else {
70 Err(ShellError::Errno(name, errno()))
71 }
72}
73
74pub fn ok() -> ShellResult {
76 Ok(SuccessfulExit(PhantomData::default()))
77}
78
79pub trait ShellResultExt {
80 fn from_status(command: String, status: ExitStatus) -> Self;
81 fn status(self) -> Result<ExitStatus, ShellError>;
82 fn code(&self) -> u8;
83}
84
85impl ShellResultExt for ShellResult {
86 fn from_status(command: String, status: ExitStatus)
87 -> Self {
88 if status.success() {
89 Ok(SuccessfulExit(PhantomData::default()))
90 } else {
91 Err(ShellError::Status(command, status))
92 }
93 }
94
95 fn status(self) -> Result<ExitStatus, ShellError> {
96 match self {
97 Ok(_) => Ok(ExitStatus::from_raw(0)),
98 Err(ShellError::Status(_, status)) => Ok(status),
99 Err(error) => Err(error)
100 }
101 }
102
103 fn code(&self) -> u8 {
104 match self {
105 &Ok(_) => 0,
106 &Err(ShellError::Status(_, ref status)) => {
107 status.code().unwrap_or(1) as u8
108 },
109 &Err(_) => 1
110 }
111 }
112}
113
114#[test]
115fn test_from_raw() {
116 let s = ExitStatus::from_raw(128 + 15);
117 assert_eq!(s.signal().unwrap(), 15);
118}