use num_derive::{FromPrimitive, ToPrimitive};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SigInfo {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub si_addr: Option<String>,
pub si_code: libc::c_int,
pub si_code_human_readable: SiCodes,
pub si_signo: libc::c_int,
pub si_signo_human_readable: SignalNames,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[allow(clippy::upper_case_acronyms, non_camel_case_types)]
#[repr(C)]
pub enum SignalNames {
SIGHUP,
SIGINT,
SIGQUIT,
SIGILL,
SIGTRAP,
SIGABRT,
SIGBUS,
SIGFPE,
SIGKILL,
SIGUSR1,
SIGSEGV,
SIGUSR2,
SIGPIPE,
SIGALRM,
SIGTERM,
SIGCHLD,
SIGCONT,
SIGSTOP,
SIGTSTP,
SIGTTIN,
SIGTTOU,
SIGURG,
SIGXCPU,
SIGXFSZ,
SIGVTALRM,
SIGPROF,
SIGWINCH,
SIGIO,
SIGSYS,
SIGEMT,
SIGINFO,
UNKNOWN,
}
#[cfg(unix)]
pub use unix::*;
#[cfg(unix)]
mod unix {
use super::*;
impl From<libc::c_int> for SignalNames {
fn from(value: libc::c_int) -> Self {
match value {
libc::SIGHUP => SignalNames::SIGHUP,
libc::SIGINT => SignalNames::SIGINT,
libc::SIGQUIT => SignalNames::SIGQUIT,
libc::SIGILL => SignalNames::SIGILL,
libc::SIGTRAP => SignalNames::SIGTRAP,
libc::SIGABRT => SignalNames::SIGABRT,
libc::SIGBUS => SignalNames::SIGBUS,
libc::SIGFPE => SignalNames::SIGFPE,
libc::SIGKILL => SignalNames::SIGKILL,
libc::SIGUSR1 => SignalNames::SIGUSR1,
libc::SIGSEGV => SignalNames::SIGSEGV,
libc::SIGUSR2 => SignalNames::SIGUSR2,
libc::SIGPIPE => SignalNames::SIGPIPE,
libc::SIGALRM => SignalNames::SIGALRM,
libc::SIGTERM => SignalNames::SIGTERM,
libc::SIGCHLD => SignalNames::SIGCHLD,
libc::SIGCONT => SignalNames::SIGCONT,
libc::SIGSTOP => SignalNames::SIGSTOP,
libc::SIGTSTP => SignalNames::SIGTSTP,
libc::SIGTTIN => SignalNames::SIGTTIN,
libc::SIGTTOU => SignalNames::SIGTTOU,
libc::SIGURG => SignalNames::SIGURG,
libc::SIGXCPU => SignalNames::SIGXCPU,
libc::SIGXFSZ => SignalNames::SIGXFSZ,
libc::SIGVTALRM => SignalNames::SIGVTALRM,
libc::SIGPROF => SignalNames::SIGPROF,
libc::SIGWINCH => SignalNames::SIGWINCH,
libc::SIGIO => SignalNames::SIGIO,
libc::SIGSYS => SignalNames::SIGSYS,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
libc::SIGEMT => SignalNames::SIGEMT,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku",
target_os = "aix"
)))]
libc::SIGINFO => SignalNames::SIGINFO,
_ => SignalNames::UNKNOWN,
}
}
}
extern "C" {
fn translate_si_code_impl(signum: libc::c_int, si_code: libc::c_int) -> libc::c_int;
}
pub fn translate_si_code(signum: libc::c_int, si_code: libc::c_int) -> SiCodes {
use num_traits::FromPrimitive;
let translated = unsafe { translate_si_code_impl(signum, si_code) };
SiCodes::from_i32(translated).unwrap_or(SiCodes::UNKNOWN)
}
#[cfg(test)]
#[cfg_attr(miri, ignore)]
#[test]
fn test_si_code() {
assert_eq!(translate_si_code(libc::SIGSEGV, 2), SiCodes::SEGV_ACCERR);
assert_eq!(translate_si_code(libc::SIGSEGV, 42), SiCodes::UNKNOWN);
}
impl From<nix::sys::signal::Signal> for SignalNames {
fn from(value: nix::sys::signal::Signal) -> Self {
match value {
nix::sys::signal::Signal::SIGHUP => SignalNames::SIGHUP,
nix::sys::signal::Signal::SIGINT => SignalNames::SIGINT,
nix::sys::signal::Signal::SIGQUIT => SignalNames::SIGQUIT,
nix::sys::signal::Signal::SIGILL => SignalNames::SIGILL,
nix::sys::signal::Signal::SIGTRAP => SignalNames::SIGTRAP,
nix::sys::signal::Signal::SIGABRT => SignalNames::SIGABRT,
nix::sys::signal::Signal::SIGBUS => SignalNames::SIGBUS,
nix::sys::signal::Signal::SIGFPE => SignalNames::SIGFPE,
nix::sys::signal::Signal::SIGKILL => SignalNames::SIGKILL,
nix::sys::signal::Signal::SIGUSR1 => SignalNames::SIGUSR1,
nix::sys::signal::Signal::SIGSEGV => SignalNames::SIGSEGV,
nix::sys::signal::Signal::SIGUSR2 => SignalNames::SIGUSR2,
nix::sys::signal::Signal::SIGPIPE => SignalNames::SIGPIPE,
nix::sys::signal::Signal::SIGALRM => SignalNames::SIGALRM,
nix::sys::signal::Signal::SIGTERM => SignalNames::SIGTERM,
nix::sys::signal::Signal::SIGCHLD => SignalNames::SIGCHLD,
nix::sys::signal::Signal::SIGCONT => SignalNames::SIGCONT,
nix::sys::signal::Signal::SIGSTOP => SignalNames::SIGSTOP,
nix::sys::signal::Signal::SIGTSTP => SignalNames::SIGTSTP,
nix::sys::signal::Signal::SIGTTIN => SignalNames::SIGTTIN,
nix::sys::signal::Signal::SIGTTOU => SignalNames::SIGTTOU,
nix::sys::signal::Signal::SIGURG => SignalNames::SIGURG,
nix::sys::signal::Signal::SIGXCPU => SignalNames::SIGXCPU,
nix::sys::signal::Signal::SIGXFSZ => SignalNames::SIGXFSZ,
nix::sys::signal::Signal::SIGVTALRM => SignalNames::SIGVTALRM,
nix::sys::signal::Signal::SIGPROF => SignalNames::SIGPROF,
nix::sys::signal::Signal::SIGWINCH => SignalNames::SIGWINCH,
nix::sys::signal::Signal::SIGIO => SignalNames::SIGIO,
nix::sys::signal::Signal::SIGSYS => SignalNames::SIGSYS,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
nix::sys::signal::Signal::SIGEMT => SignalNames::SIGEMT,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku",
target_os = "aix"
)))]
nix::sys::signal::Signal::SIGINFO => SignalNames::SIGINFO,
_ => SignalNames::UNKNOWN,
}
}
}
pub fn signal_from_signum(value: libc::c_int) -> anyhow::Result<nix::sys::signal::Signal> {
let rval = match value {
libc::SIGHUP => nix::sys::signal::Signal::SIGHUP,
libc::SIGINT => nix::sys::signal::Signal::SIGINT,
libc::SIGQUIT => nix::sys::signal::Signal::SIGQUIT,
libc::SIGILL => nix::sys::signal::Signal::SIGILL,
libc::SIGTRAP => nix::sys::signal::Signal::SIGTRAP,
libc::SIGABRT => nix::sys::signal::Signal::SIGABRT,
libc::SIGBUS => nix::sys::signal::Signal::SIGBUS,
libc::SIGFPE => nix::sys::signal::Signal::SIGFPE,
libc::SIGKILL => nix::sys::signal::Signal::SIGKILL,
libc::SIGUSR1 => nix::sys::signal::Signal::SIGUSR1,
libc::SIGSEGV => nix::sys::signal::Signal::SIGSEGV,
libc::SIGUSR2 => nix::sys::signal::Signal::SIGUSR2,
libc::SIGPIPE => nix::sys::signal::Signal::SIGPIPE,
libc::SIGALRM => nix::sys::signal::Signal::SIGALRM,
libc::SIGTERM => nix::sys::signal::Signal::SIGTERM,
libc::SIGCHLD => nix::sys::signal::Signal::SIGCHLD,
libc::SIGCONT => nix::sys::signal::Signal::SIGCONT,
libc::SIGSTOP => nix::sys::signal::Signal::SIGSTOP,
libc::SIGTSTP => nix::sys::signal::Signal::SIGTSTP,
libc::SIGTTIN => nix::sys::signal::Signal::SIGTTIN,
libc::SIGTTOU => nix::sys::signal::Signal::SIGTTOU,
libc::SIGURG => nix::sys::signal::Signal::SIGURG,
libc::SIGXCPU => nix::sys::signal::Signal::SIGXCPU,
libc::SIGXFSZ => nix::sys::signal::Signal::SIGXFSZ,
libc::SIGVTALRM => nix::sys::signal::Signal::SIGVTALRM,
libc::SIGPROF => nix::sys::signal::Signal::SIGPROF,
libc::SIGWINCH => nix::sys::signal::Signal::SIGWINCH,
libc::SIGIO => nix::sys::signal::Signal::SIGIO,
libc::SIGSYS => nix::sys::signal::Signal::SIGSYS,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
libc::SIGEMT => nix::sys::signal::Signal::SIGEMT,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku",
target_os = "aix"
)))]
libc::SIGINFO => nix::sys::signal::Signal::SIGINFO,
_ => anyhow::bail!("Unexpected signal number {value}"),
};
Ok(rval)
}
}
#[derive(
Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, FromPrimitive, ToPrimitive,
)]
#[allow(clippy::upper_case_acronyms, non_camel_case_types)]
#[repr(C)]
pub enum SiCodes {
BUS_ADRALN,
BUS_ADRERR,
BUS_MCEERR_AO,
BUS_MCEERR_AR,
BUS_OBJERR,
ILL_BADSTK,
ILL_COPROC,
ILL_ILLADR,
ILL_ILLOPC,
ILL_ILLOPN,
ILL_ILLTRP,
ILL_PRVOPC,
ILL_PRVREG,
SEGV_ACCERR,
SEGV_BNDERR,
SEGV_MAPERR,
SEGV_PKUERR,
SI_ASYNCIO,
SI_KERNEL,
SI_MESGQ,
SI_QUEUE,
SI_SIGIO,
SI_TIMER,
SI_TKILL,
SI_USER,
SYS_SECCOMP,
UNKNOWN,
}
#[cfg(test)]
impl SigInfo {
pub fn test_instance(_seed: u64) -> Self {
Self {
si_addr: Some("0x0000000000001234".to_string()),
si_code: 1,
si_code_human_readable: SiCodes::SEGV_BNDERR,
si_signo: 11,
si_signo_human_readable: SignalNames::SIGSEGV,
}
}
}