use std::fmt::{Debug, Formatter, Result as FmtResult};
use libc::{c_int, pid_t, siginfo_t, uid_t};
use crate::low_level;
extern "C" {
fn sighook_signal_cause(info: &siginfo_t) -> ICause;
fn sighook_signal_pid(info: &siginfo_t) -> pid_t;
fn sighook_signal_uid(info: &siginfo_t) -> uid_t;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[repr(u8)]
#[allow(dead_code)]
enum ICause {
Unknown = 0,
Kernel = 1,
User = 2,
TKill = 3,
Queue = 4,
MesgQ = 5,
Exited = 6,
Killed = 7,
Dumped = 8,
Trapped = 9,
Stopped = 10,
Continued = 11,
}
impl ICause {
#[cfg(target_os = "macos")]
fn has_process(self) -> bool {
true
}
#[cfg(not(target_os = "macos"))]
fn has_process(self) -> bool {
use ICause::*;
match self {
Unknown | Kernel => false,
User | TKill | Queue | MesgQ | Exited | Killed | Dumped | Trapped | Stopped
| Continued => true,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct Process {
pub pid: pid_t,
pub uid: uid_t,
}
impl Process {
unsafe fn extract(info: &siginfo_t) -> Self {
Self {
pid: sighook_signal_pid(info),
uid: sighook_signal_uid(info),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Sent {
User,
TKill,
Queue,
MesgQ,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Chld {
Exited,
Killed,
Dumped,
Trapped,
Stopped,
Continued,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Cause {
Unknown,
Kernel,
Sent(Sent),
Chld(Chld),
}
impl From<ICause> for Cause {
fn from(c: ICause) -> Cause {
match c {
ICause::Kernel => Cause::Kernel,
ICause::User => Cause::Sent(Sent::User),
ICause::TKill => Cause::Sent(Sent::TKill),
ICause::Queue => Cause::Sent(Sent::Queue),
ICause::MesgQ => Cause::Sent(Sent::MesgQ),
ICause::Exited => Cause::Chld(Chld::Exited),
ICause::Killed => Cause::Chld(Chld::Killed),
ICause::Dumped => Cause::Chld(Chld::Dumped),
ICause::Trapped => Cause::Chld(Chld::Trapped),
ICause::Stopped => Cause::Chld(Chld::Stopped),
ICause::Continued => Cause::Chld(Chld::Continued),
_ => Cause::Unknown,
}
}
}
#[derive(Clone, Eq, PartialEq)]
#[non_exhaustive]
pub struct Origin {
pub signal: c_int,
pub process: Option<Process>,
pub cause: Cause,
}
impl Debug for Origin {
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
fn named_signal(sig: c_int) -> String {
low_level::signal_name(sig)
.map(|n| format!("{} ({})", n, sig))
.unwrap_or_else(|| sig.to_string())
}
fmt.debug_struct("Origin")
.field("signal", &named_signal(self.signal))
.field("process", &self.process)
.field("cause", &self.cause)
.finish()
}
}
impl Origin {
pub unsafe fn extract(info: &siginfo_t) -> Self {
let cause = sighook_signal_cause(info);
let process = if cause.has_process() {
let process = Process::extract(info);
if cfg!(target_os = "macos") && process.pid == 0 && process.uid == 0 {
None
} else {
Some(process)
}
} else {
None
};
let signal = info.si_signo;
Origin {
cause: cause.into(),
signal,
process,
}
}
}