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,
Seccomp = 9,
SeccompFilterIoctl = 10,
SeccompFilterAppendOnly = 11,
SeccompFilterKptr = 12,
SeccompSendFd = 13,
SeccompWaitFd = 14,
SetDumpable = 15,
SetSid = 16,
SetPty = 17,
DupPty = 18,
SetPgrp = 19,
SetTSC = 20,
}
#[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),
Seccomp(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),
Seccomp(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",
Seccomp(_) => "error in seccomp filter load",
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()),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_1() {
assert_eq!(Error::UnknownError.raw_os_error(), None);
}
#[test]
fn test_error_2() {
assert_eq!(Error::Exec(1).raw_os_error(), Some(1));
}
#[test]
fn test_error_3() {
assert_eq!(Error::CapSet(2).raw_os_error(), Some(2));
}
#[test]
fn test_error_4() {
assert_eq!(Error::Seccomp(22).raw_os_error(), Some(22));
}
#[test]
fn test_error_5() {
let err = Error::BeforeUnfreeze(Box::new(std::io::Error::from(
std::io::ErrorKind::PermissionDenied,
)));
assert_eq!(err.raw_os_error(), None);
}
#[test]
fn test_error_6() {
let s = Error::Exec(libc::ENOENT).to_string();
assert!(s.contains("executing"));
}
#[test]
fn test_error_7() {
let s = Error::UnknownError.to_string();
assert!(!s.is_empty());
}
#[test]
fn test_error_8() {
let s = Error::Seccomp(libc::EINVAL).to_string();
assert!(s.contains("seccomp"));
}
#[test]
fn test_error_9() {
assert_eq!(ErrorCode::Exec as i32, 1);
assert_eq!(ErrorCode::CapSet as i32, 2);
assert_eq!(ErrorCode::Seccomp as i32, 9);
}
}