1pub type Errno = libc::c_int;
2
3#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
5pub struct Error {
6 kind: ErrorKind,
7}
8
9#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
11pub enum ErrorKind {
12 Fork(Errno),
13 Wait(Errno),
14 DetachSession(Errno),
15 GroupNotFound,
16 GroupContainsNul,
17 SetGroup(Errno),
18 UserNotFound,
19 UserContainsNul,
20 SetUser(Errno),
21 ChangeDirectory(Errno),
22 PathContainsNul,
23 OpenPidfile(Errno),
24 GetPidfileFlags(Errno),
25 SetPidfileFlags(Errno),
26 LockPidfile(Errno),
27 ChownPidfile(Errno),
28 OpenDevnull(Errno),
29 RedirectStreams(Errno),
30 CloseDevnull(Errno),
31 TruncatePidfile(Errno),
32 WritePid(Errno),
33 WritePidUnspecifiedError,
34 Chroot(Errno),
35}
36
37impl ErrorKind {
38 fn description(&self) -> &str {
39 match self {
40 ErrorKind::Fork(_) => "unable to fork",
41 ErrorKind::Wait(_) => "wait failed",
42 ErrorKind::DetachSession(_) => "unable to create new session",
43 ErrorKind::GroupNotFound => "unable to resolve group name to group id",
44 ErrorKind::GroupContainsNul => "group option contains NUL",
45 ErrorKind::SetGroup(_) => "unable to set group",
46 ErrorKind::UserNotFound => "unable to resolve user name to user id",
47 ErrorKind::UserContainsNul => "user option contains NUL",
48 ErrorKind::SetUser(_) => "unable to set user",
49 ErrorKind::ChangeDirectory(_) => "unable to change directory",
50 ErrorKind::PathContainsNul => "pid_file option contains NUL",
51 ErrorKind::OpenPidfile(_) => "unable to open pid file",
52 ErrorKind::GetPidfileFlags(_) => "unable get pid file flags",
53 ErrorKind::SetPidfileFlags(_) => "unable set pid file flags",
54 ErrorKind::LockPidfile(_) => "unable to lock pid file",
55 ErrorKind::ChownPidfile(_) => "unable to chown pid file",
56 ErrorKind::OpenDevnull(_) => "unable to open /dev/null",
57 ErrorKind::RedirectStreams(_) => "unable to redirect standard streams to /dev/null",
58 ErrorKind::CloseDevnull(_) => "unable to close /dev/null",
59 ErrorKind::TruncatePidfile(_) => "unable to truncate pid file",
60 ErrorKind::WritePid(_) => "unable to write self pid to pid file",
61 ErrorKind::WritePidUnspecifiedError => {
62 "unable to write self pid to pid file due to unknown reason"
63 }
64 ErrorKind::Chroot(_) => "unable to chroot into directory",
65 }
66 }
67
68 fn errno(&self) -> Option<Errno> {
69 match self {
70 ErrorKind::Fork(errno) => Some(*errno),
71 ErrorKind::Wait(errno) => Some(*errno),
72 ErrorKind::DetachSession(errno) => Some(*errno),
73 ErrorKind::GroupNotFound => None,
74 ErrorKind::GroupContainsNul => None,
75 ErrorKind::SetGroup(errno) => Some(*errno),
76 ErrorKind::UserNotFound => None,
77 ErrorKind::UserContainsNul => None,
78 ErrorKind::SetUser(errno) => Some(*errno),
79 ErrorKind::ChangeDirectory(errno) => Some(*errno),
80 ErrorKind::PathContainsNul => None,
81 ErrorKind::OpenPidfile(errno) => Some(*errno),
82 ErrorKind::GetPidfileFlags(errno) => Some(*errno),
83 ErrorKind::SetPidfileFlags(errno) => Some(*errno),
84 ErrorKind::LockPidfile(errno) => Some(*errno),
85 ErrorKind::ChownPidfile(errno) => Some(*errno),
86 ErrorKind::OpenDevnull(errno) => Some(*errno),
87 ErrorKind::RedirectStreams(errno) => Some(*errno),
88 ErrorKind::CloseDevnull(errno) => Some(*errno),
89 ErrorKind::TruncatePidfile(errno) => Some(*errno),
90 ErrorKind::WritePid(errno) => Some(*errno),
91 ErrorKind::WritePidUnspecifiedError => None,
92 ErrorKind::Chroot(errno) => Some(*errno),
93 }
94 }
95}
96
97impl std::fmt::Display for ErrorKind {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.write_str(self.description())?;
100 if let Some(errno) = self.errno() {
101 write!(f, ", errno {}", errno)?
102 }
103 Ok(())
104 }
105}
106
107impl std::error::Error for ErrorKind {}
108
109impl std::fmt::Display for Error {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 write!(f, "{}", self.kind)
112 }
113}
114
115impl std::error::Error for Error {}
116
117impl From<ErrorKind> for Error {
118 fn from(kind: ErrorKind) -> Self {
119 Self { kind }
120 }
121}
122
123pub trait Num {
124 fn is_err(&self) -> bool;
125}
126
127impl Num for i8 {
128 fn is_err(&self) -> bool {
129 *self == -1
130 }
131}
132
133impl Num for i16 {
134 fn is_err(&self) -> bool {
135 *self == -1
136 }
137}
138
139impl Num for i32 {
140 fn is_err(&self) -> bool {
141 *self == -1
142 }
143}
144
145impl Num for i64 {
146 fn is_err(&self) -> bool {
147 *self == -1
148 }
149}
150
151impl Num for isize {
152 fn is_err(&self) -> bool {
153 *self == -1
154 }
155}
156
157pub fn check_err<N: Num, F: FnOnce(Errno) -> ErrorKind>(ret: N, f: F) -> Result<N, ErrorKind> {
158 if ret.is_err() {
159 Err(f(errno()))
160 } else {
161 Ok(ret)
162 }
163}
164
165pub fn errno() -> Errno {
166 std::io::Error::last_os_error()
167 .raw_os_error()
168 .expect("errno")
169}