use std::{fmt, io};
use nix::errno::Errno;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCode {
Exec = 1,
CapSet = 2,
ParentDeathSignal = 3,
PreExec = 4,
ProcessStop = 5,
ResetSignal = 6,
SetResourceLimits = 7,
LandlockFilterScopedSignals = 8,
#[cfg(libseccomp_v2_6)]
SeccompComp = 9,
SeccompLoad = 10,
SeccompFilterIoctl = 11,
SeccompFilterAppendOnly = 12,
SeccompFilterKptr = 13,
SeccompSendFd = 14,
SeccompWaitFd = 15,
SetDumpable = 16,
SetSid = 17,
SetPty = 18,
DupPty = 19,
SetPgrp = 20,
SetTSC = 21,
}
#[derive(Debug)]
pub enum Error {
NixError(i32), UnknownError,
CapSet(i32),
Exec(i32),
ParentDeathSignal(i32),
BeforeUnfreeze(Box<dyn ::std::error::Error + Send + Sync + 'static>),
PreExec(i32),
ProcessStop(i32),
ResetSignal(i32),
SetResourceLimits(i32),
LandlockFilterScopedSignals(i32),
#[cfg(libseccomp_v2_6)]
SeccompComp(i32),
SeccompLoad(i32),
SeccompFilterIoctl(i32),
SeccompFilterAppendOnly(i32),
SeccompFilterKptr(i32),
SeccompSendFd(i32),
SeccompWaitFd(i32),
SetDumpable(i32),
SetSid(i32),
SetPty(i32),
DupPty(i32),
SetPgrp(i32),
SetTSC(i32),
}
impl std::error::Error for Error {}
impl Error {
pub fn raw_os_error(&self) -> Option<i32> {
use self::Error::*;
match *self {
UnknownError => None,
NixError(x) => Some(x),
CapSet(x) => Some(x),
Exec(x) => Some(x),
ParentDeathSignal(x) => Some(x),
BeforeUnfreeze(..) => None,
PreExec(x) => Some(x),
ProcessStop(x) => Some(x),
ResetSignal(x) => Some(x),
SetResourceLimits(x) => Some(x),
LandlockFilterScopedSignals(x) => Some(x),
#[cfg(libseccomp_v2_6)]
SeccompComp(x) => Some(x),
SeccompLoad(x) => Some(x),
SeccompFilterIoctl(x) => Some(x),
SeccompFilterAppendOnly(x) => Some(x),
SeccompFilterKptr(x) => Some(x),
SeccompSendFd(x) => Some(x),
SeccompWaitFd(x) => Some(x),
SetDumpable(x) => Some(x),
SetSid(x) => Some(x),
SetPty(x) => Some(x),
DupPty(x) => Some(x),
SetPgrp(x) => Some(x),
SetTSC(x) => Some(x),
}
}
}
impl Error {
fn title(&self) -> &'static str {
use self::Error::*;
match *self {
UnknownError => "unexpected value received via signal pipe",
NixError(_) => "some unknown nix error",
CapSet(_) => "error when setting capabilities",
Exec(_) => "error when executing",
ParentDeathSignal(_) => "error when death signal",
BeforeUnfreeze(_) => "error in before_unfreeze callback",
PreExec(_) => "error in pre_exec callback",
ProcessStop(_) => "error stopping process",
ResetSignal(_) => "error resetting signals",
SetResourceLimits(_) => "error setting resource limits",
LandlockFilterScopedSignals(_) => "error scoping signals with landlock",
#[cfg(libseccomp_v2_6)]
SeccompComp(_) => "error precomputing seccomp filter",
SeccompLoad(_) => "error loading seccomp filter",
SeccompFilterIoctl(_) => "error filtering ioctl requests with seccomp",
SeccompFilterAppendOnly(_) => "error filtering pwritev2 requests with seccomp",
SeccompFilterKptr(_) => {
"error filtering kernel pointers in syscall arguments with seccomp"
}
SeccompSendFd(_) => "error sending seccomp file descriptor",
SeccompWaitFd(_) => "error waiting for parent to receive the seccomp file descriptor",
SetDumpable(_) => "error resetting process dumpable attribute",
SetSid(_) => "error calling setsid",
SetPty(_) => "error setting pty as controlling terminal",
DupPty(_) => "error duplicating pty onto stdio fds",
SetPgrp(_) => "error setting foreground process group",
SetTSC(_) => "error setting timestamp counter prctl",
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use crate::unshare::Error::*;
if let Some(code) = self.raw_os_error() {
let errno = Errno::from_raw(code);
if let nix::errno::Errno::UnknownErrno = errno {
write!(
fmt,
"{}: {}",
self.title(),
io::Error::from_raw_os_error(code)
)
} else {
write!(
fmt,
"{}: {} (os error {})",
self.title(),
errno.desc(),
code
)
}
} else {
match self {
BeforeUnfreeze(err) => {
write!(fmt, "{}: {}", self.title(), err)
}
_ => write!(fmt, "{}", self.title()),
}
}
}
}