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