1use crate::errors::{Errno, errno, error};
6use crate::sigset_t;
7use linux_uapi as uapi;
8use static_assertions::assert_eq_size;
9use std::fmt;
10use std::ops::{BitAnd, BitOr, Not};
11use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
12
13pub const UNBLOCKABLE_SIGNALS: SigSet = SigSet(SIGKILL.mask() | SIGSTOP.mask());
14
15#[derive(Debug, Copy, Clone, Eq, PartialEq)]
18pub struct UncheckedSignal(u64);
19
20impl UncheckedSignal {
21 pub fn new(value: u64) -> UncheckedSignal {
22 UncheckedSignal(value)
23 }
24
25 pub fn is_zero(self) -> bool {
26 self.0 == 0
27 }
28
29 pub fn raw(self) -> u64 {
30 self.0
31 }
32}
33impl From<Signal> for UncheckedSignal {
34 fn from(signal: Signal) -> UncheckedSignal {
35 UncheckedSignal(signal.number as u64)
36 }
37}
38impl From<u32> for UncheckedSignal {
39 fn from(value: u32) -> UncheckedSignal {
40 UncheckedSignal(value as u64)
41 }
42}
43
44#[derive(Copy, Clone, PartialEq, Eq, Hash)]
46pub struct Signal {
47 number: u32,
48}
49
50impl Signal {
51 pub fn number(&self) -> u32 {
53 self.number
54 }
55
56 pub const fn mask(&self) -> u64 {
58 1 << (self.number - 1)
59 }
60
61 pub fn is_real_time(&self) -> bool {
63 self.number >= super::SIGRTMIN
64 }
65
66 pub fn is_unblockable(&self) -> bool {
68 UNBLOCKABLE_SIGNALS.has_signal(*self)
69 }
70
71 pub fn set_ptrace_syscall_bit(&mut self) {
73 self.number |= 0x80
74 }
75
76 pub fn name(&self) -> &'static str {
77 if self.is_real_time() {
78 return "real time signal";
79 }
80 match self.number {
81 uapi::SIGHUP => "SIGHUP",
82 uapi::SIGINT => "SIGINT",
83 uapi::SIGQUIT => "SIGQUIT",
84 uapi::SIGILL => "SIGILL",
85 uapi::SIGTRAP => "SIGTRAP",
86 uapi::SIGABRT => "SIGABRT",
87 uapi::SIGBUS => "SIGBUS",
88 uapi::SIGFPE => "SIGFPE",
89 uapi::SIGKILL => "SIGKILL",
90 uapi::SIGUSR1 => "SIGUSR1",
91 uapi::SIGSEGV => "SIGSEGV",
92 uapi::SIGUSR2 => "SIGUSR2",
93 uapi::SIGPIPE => "SIGPIPE",
94 uapi::SIGALRM => "SIGALRM",
95 uapi::SIGTERM => "SIGTERM",
96 uapi::SIGSTKFLT => "SIGSTKFLT",
97 uapi::SIGCHLD => "SIGCHLD",
98 uapi::SIGCONT => "SIGCONT",
99 uapi::SIGSTOP => "SIGSTOP",
100 uapi::SIGTSTP => "SIGTSTP",
101 uapi::SIGTTIN => "SIGTTIN",
102 uapi::SIGTTOU => "SIGTTOU",
103 uapi::SIGURG => "SIGURG",
104 uapi::SIGXCPU => "SIGXCPU",
105 uapi::SIGXFSZ => "SIGXFSZ",
106 uapi::SIGVTALRM => "SIGVTALRM",
107 uapi::SIGPROF => "SIGPROF",
108 uapi::SIGWINCH => "SIGWINCH",
109 uapi::SIGIO => "SIGIO",
110 uapi::SIGPWR => "SIGPWR",
111 uapi::SIGSYS => "SIGSYS",
112 _ => "unknown signal",
113 }
114 }
115
116 pub const NUM_SIGNALS: u32 = 64;
118}
119
120pub const SIGHUP: Signal = Signal { number: uapi::SIGHUP };
121pub const SIGINT: Signal = Signal { number: uapi::SIGINT };
122pub const SIGQUIT: Signal = Signal { number: uapi::SIGQUIT };
123pub const SIGILL: Signal = Signal { number: uapi::SIGILL };
124pub const SIGTRAP: Signal = Signal { number: uapi::SIGTRAP };
125pub const SIGABRT: Signal = Signal { number: uapi::SIGABRT };
126#[allow(dead_code)]
127pub const SIGIOT: Signal = Signal { number: uapi::SIGIOT };
128pub const SIGBUS: Signal = Signal { number: uapi::SIGBUS };
129pub const SIGFPE: Signal = Signal { number: uapi::SIGFPE };
130pub const SIGKILL: Signal = Signal { number: uapi::SIGKILL };
131pub const SIGUSR1: Signal = Signal { number: uapi::SIGUSR1 };
132pub const SIGSEGV: Signal = Signal { number: uapi::SIGSEGV };
133pub const SIGUSR2: Signal = Signal { number: uapi::SIGUSR2 };
134pub const SIGPIPE: Signal = Signal { number: uapi::SIGPIPE };
135pub const SIGALRM: Signal = Signal { number: uapi::SIGALRM };
136pub const SIGTERM: Signal = Signal { number: uapi::SIGTERM };
137pub const SIGSTKFLT: Signal = Signal { number: uapi::SIGSTKFLT };
138pub const SIGCHLD: Signal = Signal { number: uapi::SIGCHLD };
139pub const SIGCONT: Signal = Signal { number: uapi::SIGCONT };
140pub const SIGSTOP: Signal = Signal { number: uapi::SIGSTOP };
141pub const SIGTSTP: Signal = Signal { number: uapi::SIGTSTP };
142pub const SIGTTIN: Signal = Signal { number: uapi::SIGTTIN };
143pub const SIGTTOU: Signal = Signal { number: uapi::SIGTTOU };
144pub const SIGURG: Signal = Signal { number: uapi::SIGURG };
145pub const SIGXCPU: Signal = Signal { number: uapi::SIGXCPU };
146pub const SIGXFSZ: Signal = Signal { number: uapi::SIGXFSZ };
147pub const SIGVTALRM: Signal = Signal { number: uapi::SIGVTALRM };
148pub const SIGPROF: Signal = Signal { number: uapi::SIGPROF };
149pub const SIGWINCH: Signal = Signal { number: uapi::SIGWINCH };
150pub const SIGIO: Signal = Signal { number: uapi::SIGIO };
151pub const SIGPWR: Signal = Signal { number: uapi::SIGPWR };
152pub const SIGSYS: Signal = Signal { number: uapi::SIGSYS };
153#[allow(dead_code)]
154pub const SIGRTMIN: Signal = Signal { number: super::SIGRTMIN };
155
156impl TryFrom<UncheckedSignal> for Signal {
157 type Error = Errno;
158
159 fn try_from(value: UncheckedSignal) -> Result<Self, Self::Error> {
160 let value = u32::try_from(value.0).map_err(|_| errno!(EINVAL))?;
161 if (1..=Signal::NUM_SIGNALS).contains(&value) {
162 Ok(Signal { number: value })
163 } else {
164 error!(EINVAL)
165 }
166 }
167}
168
169impl fmt::Debug for Signal {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 write!(f, "{self}")
172 }
173}
174
175impl fmt::Display for Signal {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 if self.is_real_time() {
178 write!(f, "SIGRTMIN+{}({})", self.number - super::SIGRTMIN, self.number)
179 } else {
180 write!(f, "{}({})", self.name(), self.number)
181 }
182 }
183}
184
185#[repr(transparent)]
199#[derive(
200 Debug, Copy, Clone, Default, IntoBytes, Eq, KnownLayout, FromBytes, Immutable, PartialEq,
201)]
202pub struct SigSet(pub std::os::raw::c_ulong);
203assert_eq_size!(SigSet, sigset_t);
204
205impl SigSet {
206 pub fn has_signal(&self, signal: Signal) -> bool {
208 (self.0 & (signal.mask() as std::os::raw::c_ulong)) != 0
209 }
210
211 pub fn intersects(&self, other: &Self) -> bool {
213 (self.0 & other.0) != 0
214 }
215}
216
217impl From<sigset_t> for SigSet {
218 fn from(value: sigset_t) -> Self {
219 #[allow(
222 clippy::undocumented_unsafe_blocks,
223 reason = "Force documented unsafe blocks in Starnix"
224 )]
225 SigSet(unsafe { std::mem::transmute(value) })
226 }
227}
228
229impl From<SigSet> for sigset_t {
230 fn from(val: SigSet) -> Self {
231 #[allow(
234 clippy::undocumented_unsafe_blocks,
235 reason = "Force documented unsafe blocks in Starnix"
236 )]
237 unsafe {
238 std::mem::transmute(val.0)
239 }
240 }
241}
242
243impl BitAnd for SigSet {
244 type Output = Self;
245
246 fn bitand(self, rhs: Self) -> Self::Output {
248 Self(self.0 & rhs.0)
249 }
250}
251
252impl BitOr for SigSet {
253 type Output = Self;
254
255 fn bitor(self, rhs: Self) -> Self::Output {
257 Self(self.0 | rhs.0)
258 }
259}
260
261impl Not for SigSet {
262 type Output = Self;
263
264 fn not(self) -> Self::Output {
265 SigSet(!self.0)
266 }
267}
268
269impl From<Signal> for SigSet {
270 fn from(value: Signal) -> Self {
272 SigSet(value.mask() as std::os::raw::c_ulong)
273 }
274}
275
276pub fn sigaltstack_contains_pointer(stack: &uapi::sigaltstack, ptr: u64) -> bool {
277 let min = stack.ss_sp.addr as u64;
278 let max = (stack.ss_sp.addr as u64).saturating_add(stack.ss_size as u64);
279 ptr >= min && ptr <= max
280}