use core::{fmt, mem};
use derive_more::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
use linux_raw_sys::general::{SI_KERNEL, SS_DISABLE, SS_ONSTACK, kernel_sigset_t, siginfo_t};
pub const SI_TIMER: i32 = -2;
use strum::{EnumIter, FromRepr, IntoEnumIterator};
use crate::DefaultSignalAction;
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromRepr, EnumIter)]
pub enum Signo {
SIGHUP = 1,
SIGINT = 2,
SIGQUIT = 3,
SIGILL = 4,
SIGTRAP = 5,
SIGABRT = 6,
SIGBUS = 7,
SIGFPE = 8,
SIGKILL = 9,
SIGUSR1 = 10,
SIGSEGV = 11,
SIGUSR2 = 12,
SIGPIPE = 13,
SIGALRM = 14,
SIGTERM = 15,
SIGSTKFLT = 16,
SIGCHLD = 17,
SIGCONT = 18,
SIGSTOP = 19,
SIGTSTP = 20,
SIGTTIN = 21,
SIGTTOU = 22,
SIGURG = 23,
SIGXCPU = 24,
SIGXFSZ = 25,
SIGVTALRM = 26,
SIGPROF = 27,
SIGWINCH = 28,
SIGIO = 29,
SIGPWR = 30,
SIGSYS = 31,
SIGRTMIN = 32,
SIGRT1 = 33,
SIGRT2 = 34,
SIGRT3 = 35,
SIGRT4 = 36,
SIGRT5 = 37,
SIGRT6 = 38,
SIGRT7 = 39,
SIGRT8 = 40,
SIGRT9 = 41,
SIGRT10 = 42,
SIGRT11 = 43,
SIGRT12 = 44,
SIGRT13 = 45,
SIGRT14 = 46,
SIGRT15 = 47,
SIGRT16 = 48,
SIGRT17 = 49,
SIGRT18 = 50,
SIGRT19 = 51,
SIGRT20 = 52,
SIGRT21 = 53,
SIGRT22 = 54,
SIGRT23 = 55,
SIGRT24 = 56,
SIGRT25 = 57,
SIGRT26 = 58,
SIGRT27 = 59,
SIGRT28 = 60,
SIGRT29 = 61,
SIGRT30 = 62,
SIGRT31 = 63,
SIGRT32 = 64,
}
impl Signo {
pub fn is_realtime(&self) -> bool {
*self >= Signo::SIGRTMIN
}
pub fn default_action(&self) -> DefaultSignalAction {
match self {
Signo::SIGHUP => DefaultSignalAction::Terminate,
Signo::SIGINT => DefaultSignalAction::Terminate,
Signo::SIGQUIT => DefaultSignalAction::CoreDump,
Signo::SIGILL => DefaultSignalAction::CoreDump,
Signo::SIGTRAP => DefaultSignalAction::CoreDump,
Signo::SIGABRT => DefaultSignalAction::CoreDump,
Signo::SIGBUS => DefaultSignalAction::CoreDump,
Signo::SIGFPE => DefaultSignalAction::CoreDump,
Signo::SIGKILL => DefaultSignalAction::Terminate,
Signo::SIGUSR1 => DefaultSignalAction::Terminate,
Signo::SIGSEGV => DefaultSignalAction::CoreDump,
Signo::SIGUSR2 => DefaultSignalAction::Terminate,
Signo::SIGPIPE => DefaultSignalAction::Terminate,
Signo::SIGALRM => DefaultSignalAction::Terminate,
Signo::SIGTERM => DefaultSignalAction::Terminate,
Signo::SIGSTKFLT => DefaultSignalAction::Terminate,
Signo::SIGCHLD => DefaultSignalAction::Ignore,
Signo::SIGCONT => DefaultSignalAction::Continue,
Signo::SIGSTOP => DefaultSignalAction::Stop,
Signo::SIGTSTP => DefaultSignalAction::Stop,
Signo::SIGTTIN => DefaultSignalAction::Stop,
Signo::SIGTTOU => DefaultSignalAction::Stop,
Signo::SIGURG => DefaultSignalAction::Ignore,
Signo::SIGXCPU => DefaultSignalAction::CoreDump,
Signo::SIGXFSZ => DefaultSignalAction::CoreDump,
Signo::SIGVTALRM => DefaultSignalAction::Terminate,
Signo::SIGPROF => DefaultSignalAction::Terminate,
Signo::SIGWINCH => DefaultSignalAction::Ignore,
Signo::SIGIO => DefaultSignalAction::Terminate,
Signo::SIGPWR => DefaultSignalAction::Terminate,
Signo::SIGSYS => DefaultSignalAction::CoreDump,
_ => DefaultSignalAction::Ignore,
}
}
}
#[derive(Default, Clone, Copy, Not, BitOr, BitOrAssign, BitAnd, BitAndAssign)]
#[repr(transparent)]
pub struct SignalSet(u64);
impl SignalSet {
fn signo_bit(signo: Signo) -> u64 {
1 << (signo as u8 - 1)
}
pub fn add(&mut self, signal: Signo) -> bool {
let bit = Self::signo_bit(signal);
if self.0 & bit != 0 {
return false;
}
self.0 |= bit;
true
}
pub fn remove(&mut self, signal: Signo) -> bool {
let bit = Self::signo_bit(signal);
if self.0 & bit == 0 {
return false;
}
self.0 &= !bit;
true
}
pub fn has(&self, signal: Signo) -> bool {
(self.0 & Self::signo_bit(signal)) != 0
}
pub fn is_empty(&self) -> bool {
self.0 == 0
}
pub fn dequeue(&mut self, mask: &SignalSet) -> Option<Signo> {
let bits = self.0 & mask.0;
if bits == 0 {
None
} else {
let signal = bits.trailing_zeros();
self.0 &= !(1 << signal);
Signo::from_repr((signal + 1) as u8)
}
}
}
impl From<SignalSet> for kernel_sigset_t {
fn from(value: SignalSet) -> Self {
unsafe { mem::transmute::<u64, kernel_sigset_t>(value.0) }
}
}
impl From<kernel_sigset_t> for SignalSet {
fn from(value: kernel_sigset_t) -> Self {
Self(unsafe { mem::transmute::<kernel_sigset_t, u64>(value) })
}
}
impl fmt::Debug for SignalSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug = f.debug_set();
for signo in Signo::iter() {
if self.has(signo) {
debug.entry(&signo);
}
}
debug.finish()
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct SignalInfo(pub siginfo_t);
impl SignalInfo {
pub fn new_kernel(signo: Signo) -> Self {
let mut result: Self = unsafe { mem::zeroed() };
result.set_signo(signo);
result.set_code(SI_KERNEL as _);
result
}
pub fn new_user(signo: Signo, code: i32, pid: u32, uid: u32) -> Self {
let mut result: Self = unsafe { mem::zeroed() };
result.set_signo(signo);
result.set_code(code);
result
.0
.__bindgen_anon_1
.__bindgen_anon_1
._sifields
._sigchld
._pid = pid as _;
result
.0
.__bindgen_anon_1
.__bindgen_anon_1
._sifields
._sigchld
._uid = uid as _;
result
}
pub fn pid(&self) -> u32 {
unsafe {
self.0
.__bindgen_anon_1
.__bindgen_anon_1
._sifields
._sigchld
._pid as u32
}
}
pub fn uid(&self) -> u32 {
unsafe {
self.0
.__bindgen_anon_1
.__bindgen_anon_1
._sifields
._sigchld
._uid
}
}
pub fn new_sigchld(child_pid: u32, child_uid: u32, code: i32, status: i32) -> Self {
let mut result: Self = unsafe { mem::zeroed() };
result.set_signo(Signo::SIGCHLD);
result.set_code(code);
unsafe {
let fields = &mut result
.0
.__bindgen_anon_1
.__bindgen_anon_1
._sifields
._sigchld;
fields._pid = child_pid as _;
fields._uid = child_uid as _;
fields._status = status;
}
result
}
pub fn new_timer(signo: Signo, sigev_value: i64) -> Self {
let mut result: Self = unsafe { mem::zeroed() };
result.set_signo(signo);
result.set_code(SI_TIMER);
result
.0
.__bindgen_anon_1
.__bindgen_anon_1
._sifields
._timer
._sigval
.sival_ptr = sigev_value as *mut core::ffi::c_void;
result
}
pub fn signo(&self) -> Signo {
unsafe { Signo::from_repr(self.0.__bindgen_anon_1.__bindgen_anon_1.si_signo as _).unwrap() }
}
pub fn set_signo(&mut self, signo: Signo) {
self.0.__bindgen_anon_1.__bindgen_anon_1.si_signo = signo as _;
}
pub fn code(&self) -> i32 {
unsafe { self.0.__bindgen_anon_1.__bindgen_anon_1.si_code }
}
pub fn set_code(&mut self, code: i32) {
self.0.__bindgen_anon_1.__bindgen_anon_1.si_code = code;
}
pub fn errno(&self) -> i32 {
unsafe { self.0.__bindgen_anon_1.__bindgen_anon_1.si_errno }
}
}
unsafe impl Send for SignalInfo {}
unsafe impl Sync for SignalInfo {}
impl fmt::Debug for SignalInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SignalInfo")
.field("signo", &self.signo())
.field("code", &self.code())
.finish()
}
}
#[repr(C)]
#[derive(Clone)]
pub struct SignalStack {
pub sp: usize,
pub flags: u32,
pub size: usize,
}
impl Default for SignalStack {
fn default() -> Self {
Self {
sp: 0,
flags: SS_DISABLE,
size: 0,
}
}
}
impl SignalStack {
pub fn disabled(&self) -> bool {
self.flags & SS_DISABLE != 0
}
pub fn on_stack(mut self) -> Self {
if !self.disabled() {
self.flags |= SS_ONSTACK;
}
self
}
pub fn without_runtime_flags(mut self) -> Self {
self.flags &= !SS_ONSTACK;
self
}
}