rust_shell/
result.rs

1// Copyright 2017 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15extern 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
74/// Returns `ShellResult` which is `Ok`.
75pub 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}