daemonize2/
error.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//
3// This file is licensed under the MIT license or the Apache License, Version 2.0, at your choice.
4//
5// Copyright 2016 Fedor Gogolev
6// Copyright 2025 Oliver Old
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License at
11//
12//     http://www.apache.org/licenses/LICENSE-2.0
13//
14// Unless required by applicable law or agreed to in writing, software
15// distributed under the License is distributed on an "AS IS" BASIS,
16// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17// See the License for the specific language governing permissions and
18// limitations under the License.
19
20pub type Errno = libc::c_int;
21
22/// Error type returned by `Daemonize::start()`.
23#[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/// Error kind used inside `struct Error`.
37#[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}