1#![forbid(unsafe_code)]
11
12use std::{
13 array::TryFromSliceError,
14 env::VarError,
15 error::Error,
16 fmt, io,
17 net::AddrParseError,
18 num::{ParseIntError, TryFromIntError},
19 str::Utf8Error,
20 thread::JoinHandle,
21};
22
23use btoi::ParseIntegerError;
24#[cfg(feature = "oci")]
25use libcgroups::common::AnyManagerError;
26#[cfg(feature = "oci")]
27use libcgroups::common::CreateCgroupSetupError;
28#[cfg(feature = "oci")]
29use libcontainer::error::LibcontainerError;
30#[cfg(feature = "oci")]
31use libcontainer::signal::SignalError;
32#[cfg(feature = "oci")]
33use libcontainer::utils::PathBufExtError;
34use libseccomp::error::SeccompError;
35use nix::errno::Errno;
36use procfs_core::ProcError;
37use shellexpand::LookupError;
38#[cfg(feature = "oci")]
39use tracing::subscriber::SetGlobalDefaultError;
40
41use crate::{caps::errors::CapsError, elf::ElfError, landlock::RulesetError, sandbox::Capability};
42
43pub type SydResult<T> = std::result::Result<T, SydError>;
45
46pub type SydJoinHandle<T> = JoinHandle<SydResult<T>>;
48
49#[macro_export]
51macro_rules! lasterrno {
52 () => {
53 SydError::Nix(nix::errno::Errno::last())
54 };
55}
56
57pub enum SydError {
59 Addr(AddrParseError),
61 Args(lexopt::Error),
63 Caps(CapsError),
65 Elf(ElfError),
67 Env(LookupError<VarError>),
69 Nix(Errno),
71 Json(serde_json::Error),
73 ParseInt(ParseIntError),
75 ParseInteger(ParseIntegerError),
77 TryInt(TryFromIntError),
79 TrySlice(TryFromSliceError),
81 ParseSize(parse_size::Error),
83 ParseShell(shell_words::ParseError),
85 Proc(ProcError),
87 Scmp(SeccompError),
89 Utf8(Utf8Error),
91 Var(VarError),
93 #[cfg(feature = "oci")]
94 CgSetup(CreateCgroupSetupError),
96 #[cfg(feature = "oci")]
97 CgMisc(AnyManagerError),
99 #[cfg(feature = "oci")]
100 Cont(LibcontainerError),
102 #[cfg(feature = "oci")]
103 Pext(PathBufExtError),
105 #[cfg(feature = "oci")]
106 SetTracing(SetGlobalDefaultError),
108 #[cfg(feature = "oci")]
109 Signal(SignalError<String>),
111 #[cfg(feature = "oci")]
112 Spec(oci_spec::OciSpecError),
114}
115
116impl SydError {
117 pub fn errno(&self) -> Option<Errno> {
119 match self {
120 Self::Nix(errno) => Some(*errno),
121 Self::Proc(error) => proc_error_to_errno(error),
122 Self::Scmp(error) => scmp2no(error),
123 Self::ParseInt(_)
124 | Self::ParseInteger(_)
125 | Self::ParseSize(_)
126 | Self::ParseShell(_)
127 | Self::Var(_) => Some(Errno::EINVAL),
128 _ => None,
129 }
130 }
131}
132
133impl fmt::Debug for SydError {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 Self::Addr(error) => write!(f, "AddrParseError: {error:?}"),
137 Self::Args(error) => write!(f, "ArgsParseError: {error:?}"),
138 Self::Caps(error) => write!(f, "CapsError: {error:?}"),
139 Self::Elf(error) => write!(f, "ElfError: {error:?}"),
140 Self::Env(error) => write!(f, "LookupError<VarError>: {error:?}"),
141 Self::Nix(errno) => write!(f, "LinuxError: {errno:?}"),
142 Self::Json(error) => write!(f, "JsonError: {error:?}"),
143 Self::ParseInt(error) => write!(f, "ParseIntError: {error:?}"),
144 Self::ParseInteger(error) => write!(f, "ParseIntegerError: {error:?}"),
145 Self::Scmp(error) => write!(f, "SeccompError: {error:?}"),
146 Self::TryInt(error) => write!(f, "TryFromIntError: {error:?}"),
147 Self::TrySlice(error) => write!(f, "TryFromSliceError: {error:?}"),
148 Self::ParseSize(error) => write!(f, "ParseSizeError: {error:?}"),
149 Self::ParseShell(error) => write!(f, "ParseShellError: {error:?}"),
150 Self::Proc(error) => write!(f, "ProcError: {error:?}"),
151 Self::Utf8(error) => write!(f, "Utf8Error: {error:?}"),
152 Self::Var(error) => write!(f, "VarError: {error:?}"),
153 #[cfg(feature = "oci")]
154 Self::CgSetup(error) => write!(f, "CgroupSetupError: {error:?}"),
155 #[cfg(feature = "oci")]
156 Self::CgMisc(error) => write!(f, "AnyManagerError: {error:?}"),
157 #[cfg(feature = "oci")]
158 Self::Cont(error) => write!(f, "ContainerError: {error:?}"),
159 #[cfg(feature = "oci")]
160 Self::Pext(error) => write!(f, "PathBufExtError: {error:?}"),
161 #[cfg(feature = "oci")]
162 Self::SetTracing(error) => write!(f, "SetGlobalDefaultError: {error:?}"),
163 #[cfg(feature = "oci")]
164 Self::Signal(error) => write!(f, "SignalError: {error:?}"),
165 #[cfg(feature = "oci")]
166 Self::Spec(error) => write!(f, "OciSpecError: {error:?}"),
167 }
168 }
169}
170
171impl fmt::Display for SydError {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 match self {
174 Self::Addr(error) => write!(f, "AddrParseError: {error}"),
175 Self::Args(error) => write!(f, "ArgsParseError: {error}"),
176 Self::Caps(error) => write!(f, "CapsError: {error}"),
177 Self::Elf(error) => write!(f, "ElfError: {error}"),
178 Self::Env(error) => write!(f, "LookupError<VarError>: {error}"),
179 Self::Nix(errno) => write!(f, "LinuxError: {errno}"),
180 Self::Json(error) => write!(f, "JsonError: {error}"),
181 Self::ParseInt(error) => write!(f, "ParseIntError: {error}"),
182 Self::ParseInteger(error) => write!(f, "ParseIntegerError: {error}"),
183 Self::Scmp(error) => write!(f, "SeccompError: {error}"),
184 Self::TryInt(error) => write!(f, "TryFromIntError: {error}"),
185 Self::TrySlice(error) => write!(f, "TryFromSliceError: {error}"),
186 Self::ParseSize(error) => write!(f, "ParseSizeError: {error}"),
187 Self::ParseShell(error) => write!(f, "ParseShellError: {error}"),
188 Self::Proc(error) => write!(f, "ProcError: {error}"),
189 Self::Utf8(error) => write!(f, "Utf8Error: {error}"),
190 Self::Var(error) => write!(f, "VarError: {error}"),
191 #[cfg(feature = "oci")]
192 Self::CgSetup(error) => write!(f, "CgroupSetupError: {error}"),
193 #[cfg(feature = "oci")]
194 Self::CgMisc(error) => write!(f, "AnyManagerError: {error}"),
195 #[cfg(feature = "oci")]
196 Self::Cont(error) => write!(f, "ContainerError: {error}"),
197 #[cfg(feature = "oci")]
198 Self::Pext(error) => write!(f, "PathBufExtError: {error}"),
199 #[cfg(feature = "oci")]
200 Self::SetTracing(error) => write!(f, "SetGlobalDefaultError: {error}"),
201 #[cfg(feature = "oci")]
202 Self::Signal(error) => write!(f, "SignalError: {error}"),
203 #[cfg(feature = "oci")]
204 Self::Spec(error) => write!(f, "OciSpecError: {error}"),
205 }
206 }
207}
208
209impl std::error::Error for SydError {
210 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
211 match self {
212 Self::Addr(error) => Some(error),
213 Self::Args(error) => Some(error),
214 Self::Nix(errno) => Some(errno),
215 Self::ParseInt(error) => Some(error),
216 Self::ParseInteger(error) => Some(error),
217 Self::TryInt(error) => Some(error),
218 Self::TrySlice(error) => Some(error),
219 Self::ParseSize(error) => Some(error),
220 Self::ParseShell(error) => Some(error),
221 Self::Proc(error) => Some(error),
222 Self::Utf8(error) => Some(error),
223 Self::Var(error) => Some(error),
224 #[cfg(feature = "oci")]
225 Self::CgSetup(error) => Some(error),
226 #[cfg(feature = "oci")]
227 Self::CgMisc(error) => Some(error),
228 #[cfg(feature = "oci")]
229 Self::Cont(error) => Some(error),
230 #[cfg(feature = "oci")]
231 Self::Pext(error) => Some(error),
232 #[cfg(feature = "oci")]
233 Self::SetTracing(error) => Some(error),
234 #[cfg(feature = "oci")]
235 Self::Signal(error) => Some(error),
236 #[cfg(feature = "oci")]
237 Self::Spec(error) => Some(error),
238 _ => None,
239 }
240 }
241}
242
243impl From<io::Error> for SydError {
245 fn from(err: io::Error) -> SydError {
246 SydError::Nix(err2no(&err))
247 }
248}
249
250impl From<SydError> for io::Error {
252 fn from(err: SydError) -> io::Error {
253 match err.errno() {
254 Some(errno) => io::Error::from_raw_os_error(errno as i32),
255 None => io::Error::other(err),
256 }
257 }
258}
259
260impl From<AddrParseError> for SydError {
262 fn from(err: AddrParseError) -> SydError {
263 SydError::Addr(err)
264 }
265}
266
267impl From<Utf8Error> for SydError {
269 fn from(err: Utf8Error) -> SydError {
270 Self::Utf8(err)
271 }
272}
273
274impl From<ProcError> for SydError {
276 fn from(err: ProcError) -> SydError {
277 Self::Proc(err)
278 }
279}
280
281impl From<lexopt::Error> for SydError {
283 fn from(err: lexopt::Error) -> SydError {
284 Self::Args(err)
285 }
286}
287
288impl From<CapsError> for SydError {
290 fn from(err: CapsError) -> SydError {
291 Self::Caps(err)
292 }
293}
294
295impl From<ElfError> for SydError {
297 fn from(err: ElfError) -> SydError {
298 Self::Elf(err)
299 }
300}
301
302impl From<LookupError<VarError>> for SydError {
304 fn from(err: LookupError<VarError>) -> SydError {
305 Self::Env(err)
306 }
307}
308
309impl From<VarError> for SydError {
311 fn from(err: VarError) -> SydError {
312 Self::Var(err)
313 }
314}
315
316impl From<Errno> for SydError {
318 fn from(err: Errno) -> SydError {
319 Self::Nix(err)
320 }
321}
322
323impl From<serde_json::Error> for SydError {
325 fn from(err: serde_json::Error) -> SydError {
326 Self::Json(err)
327 }
328}
329
330#[cfg(feature = "oci")]
332impl From<AnyManagerError> for SydError {
333 fn from(err: AnyManagerError) -> SydError {
334 Self::CgMisc(err)
335 }
336}
337
338#[cfg(feature = "oci")]
340impl From<CreateCgroupSetupError> for SydError {
341 fn from(err: CreateCgroupSetupError) -> SydError {
342 Self::CgSetup(err)
343 }
344}
345
346#[cfg(feature = "oci")]
348impl From<LibcontainerError> for SydError {
349 fn from(err: LibcontainerError) -> SydError {
350 Self::Cont(err)
351 }
352}
353
354#[cfg(feature = "oci")]
356impl From<PathBufExtError> for SydError {
357 fn from(err: PathBufExtError) -> SydError {
358 Self::Pext(err)
359 }
360}
361
362#[cfg(feature = "oci")]
364impl From<SetGlobalDefaultError> for SydError {
365 fn from(err: SetGlobalDefaultError) -> SydError {
366 Self::SetTracing(err)
367 }
368}
369
370#[cfg(feature = "oci")]
372impl From<SignalError<String>> for SydError {
373 fn from(err: SignalError<String>) -> SydError {
374 Self::Signal(err)
375 }
376}
377
378#[cfg(feature = "oci")]
380impl From<oci_spec::OciSpecError> for SydError {
381 fn from(err: oci_spec::OciSpecError) -> SydError {
382 Self::Spec(err)
383 }
384}
385
386impl From<ParseIntError> for SydError {
388 fn from(err: ParseIntError) -> SydError {
389 Self::ParseInt(err)
390 }
391}
392
393impl From<ParseIntegerError> for SydError {
395 fn from(err: ParseIntegerError) -> SydError {
396 Self::ParseInteger(err)
397 }
398}
399
400impl From<TryFromIntError> for SydError {
402 fn from(err: TryFromIntError) -> SydError {
403 Self::TryInt(err)
404 }
405}
406
407impl From<TryFromSliceError> for SydError {
409 fn from(err: TryFromSliceError) -> SydError {
410 Self::TrySlice(err)
411 }
412}
413
414impl From<parse_size::Error> for SydError {
416 fn from(err: parse_size::Error) -> SydError {
417 Self::ParseSize(err)
418 }
419}
420
421impl From<shell_words::ParseError> for SydError {
423 fn from(err: shell_words::ParseError) -> SydError {
424 Self::ParseShell(err)
425 }
426}
427
428impl From<SeccompError> for SydError {
430 fn from(err: SeccompError) -> SydError {
431 Self::Scmp(err)
432 }
433}
434
435pub fn err2no(err: &std::io::Error) -> Errno {
437 err.raw_os_error()
438 .map(Errno::from_raw)
439 .unwrap_or(Errno::ENOSYS)
440}
441
442pub fn err2set(err: &RulesetError) -> Errno {
444 err.source()
445 .and_then(|s| s.downcast_ref::<std::io::Error>())
446 .map(err2no)
447 .unwrap_or(Errno::EINVAL)
448}
449
450pub fn scmp2no(err: &SeccompError) -> Option<Errno> {
452 err.sysrawrc().map(|errno| errno.abs()).map(Errno::from_raw)
453}
454
455pub fn proc_error_to_errno(error: &ProcError) -> Option<Errno> {
457 match error {
458 ProcError::PermissionDenied(_) => Some(Errno::EACCES),
459 ProcError::NotFound(_) => Some(Errno::ESRCH),
460 ProcError::Io(error, _) => Some(err2no(error)),
461 ProcError::Other(_) => None,
462 ProcError::Incomplete(_) => None,
463 ProcError::InternalError(_) => None,
464 }
465}
466
467pub fn cap2no(cap: Capability) -> Errno {
469 if cap.intersects(Capability::CAP_WALK | Capability::CAP_STAT) {
470 Errno::ENOENT
471 } else {
472 Errno::EACCES
473 }
474}