proc_exit/
sysexits.rs

1//! Support for [sysexits](https://www.freebsd.org/cgi/man.cgi?query=sysexits) codes
2//!
3//! Note: [FreeBSD no longer encourages these](https://reviews.freebsd.org/D27176)
4
5/// Extension for converting errors to [`Exit`][crate::Exit]
6///
7/// # Example
8///
9/// ```
10/// use proc_exit::prelude::*;
11///
12/// fn main() {
13///     // Simple but Macro-less `main`
14///     // - Fast compiles
15///     // - Composable with other features
16///     let result = run();
17///     proc_exit::exit(result);
18/// }
19///
20/// fn run() -> proc_exit::ExitResult {
21///     // Integrates directly with `std::io::Error`, returning the right exit code.
22///     let exit_status = std::process::Command::new("true")
23///          .status().to_sysexits()?;
24///     // Can pass `Command` exit codes right up, when appropriate
25///     proc_exit::Code::from_status(exit_status).ok()?;
26///
27///     proc_exit::Code::SUCCESS.ok()
28/// }
29/// ```
30pub trait ToSysexitsResultExt<T> {
31    /// Convert an Error into an [`Exit`][crate::Exit]
32    fn to_sysexits(self) -> Result<T, crate::Exit>;
33}
34
35impl<T> ToSysexitsResultExt<T> for Result<T, std::io::Error> {
36    #[inline]
37    fn to_sysexits(self) -> Result<T, crate::Exit> {
38        self.map_err(|e| {
39            let kind = e.kind();
40            let code = io_to_sysexists(kind)
41                .or_else(|| crate::bash::io_to_signal(kind))
42                .unwrap_or(IO_ERR);
43            crate::Exit::new(code).with_message(e)
44        })
45    }
46}
47
48/// Convert [`std::io::ErrorKind`] to a [`Code`][crate::Code]
49#[inline]
50pub fn io_to_sysexists(kind: std::io::ErrorKind) -> Option<crate::Code> {
51    match kind {
52        std::io::ErrorKind::NotFound => Some(OS_FILE_ERR),
53        std::io::ErrorKind::PermissionDenied => Some(NO_PERM),
54        std::io::ErrorKind::ConnectionRefused
55        | std::io::ErrorKind::ConnectionReset
56        | std::io::ErrorKind::ConnectionAborted
57        | std::io::ErrorKind::NotConnected => Some(PROTOCOL_ERR),
58        std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable => {
59            Some(SERVICE_UNAVAILABLE)
60        }
61        std::io::ErrorKind::AlreadyExists => Some(CANT_CREAT),
62        std::io::ErrorKind::InvalidInput
63        | std::io::ErrorKind::InvalidData
64        | std::io::ErrorKind::UnexpectedEof => Some(DATA_ERR),
65        std::io::ErrorKind::WriteZero => Some(NO_INPUT),
66        _ => None,
67    }
68}
69
70/// The process exited successfully.
71pub const OK: crate::Code = crate::Code::new(0);
72
73/// The command was used incorrectly, e.g. with the wrong number of
74/// arguments, a bad flag, bad syntax in a parameter, or whatever.
75pub const USAGE_ERR: crate::Code = crate::Code::new(64);
76
77/// The input data was incorrect in some way.  This should only be used for
78/// user’s data and not system files.
79pub const DATA_ERR: crate::Code = crate::Code::new(65);
80
81/// An input file (not a system file) did not exist or was not readable.
82/// This could also include errors like “No message” to a mailer (if it
83/// cared to catch it).
84pub const NO_INPUT: crate::Code = crate::Code::new(66);
85
86/// The user specified did not exist.  This might be used for mail addresses
87/// or remote logins.
88pub const NO_USER: crate::Code = crate::Code::new(67);
89
90/// The host specified did not exist.  This is used in mail addresses or
91/// network requests.
92pub const NO_HOST: crate::Code = crate::Code::new(68);
93
94/// A service is unavailable.  This can occur if a support program or file
95/// does not exist.  This can also be used as a catch-all message when
96/// something you wanted to do doesn’t work, but you don’t know why.
97pub const SERVICE_UNAVAILABLE: crate::Code = crate::Code::new(69);
98
99/// An internal software error has been detected.  This should be limited
100/// to non-operating system related errors if possible.
101pub const SOFTWARE_ERR: crate::Code = crate::Code::new(70);
102
103/// An operating system error has been detected.  This is intended to be
104/// used for such things as “cannot fork”, or “cannot create pipe”.  It
105/// includes things like [getuid(2)] returning a user that does not exist
106/// in the passwd file.
107///
108/// [getuid(2)]: https://man.openbsd.org/getuid.2
109pub const OS_ERR: crate::Code = crate::Code::new(71);
110
111/// Some system file (e.g. _/etc/passwd_, _/var/run/utmp_) does not exist,
112/// cannot be opened, or has some sort of error (e.g. syntax error).
113pub const OS_FILE_ERR: crate::Code = crate::Code::new(72);
114
115/// A (user specified) output file cannot be created.
116pub const CANT_CREAT: crate::Code = crate::Code::new(73);
117
118/// An error occurred while doing I/O on some file.
119pub const IO_ERR: crate::Code = crate::Code::new(74);
120
121/// Temporary failure, indicating something that is not really an error.
122/// For example that a mailer could not create a connection, and the
123/// request should be reattempted later.
124pub const TEMP_FAIL: crate::Code = crate::Code::new(75);
125
126/// The remote system returned something that was “not possible” during a
127/// protocol exchange.
128pub const PROTOCOL_ERR: crate::Code = crate::Code::new(76);
129
130/// You did not have sufficient permission to perform the operation.  This
131/// is not intended for file system problems, which should use `NoInput` or
132/// `CantCreat`, but rather for high level permissions.
133pub const NO_PERM: crate::Code = crate::Code::new(77);
134
135/// Something was found in an unconfigured or misconfigured state.
136pub const CONFIG_ERR: crate::Code = crate::Code::new(78);