1use std::cmp::Ordering;
6use std::convert::TryFrom;
7use std::io;
8use std::mem;
9use std::os::unix::thread::JoinHandleExt;
10use std::ptr::null;
11use std::ptr::null_mut;
12use std::result;
13use std::thread::JoinHandle;
14use std::time::Duration;
15
16use libc::c_int;
17use libc::pthread_kill;
18use libc::pthread_sigmask;
19use libc::pthread_t;
20use libc::sigaction;
21use libc::sigaddset;
22use libc::sigemptyset;
23use libc::siginfo_t;
24use libc::sigismember;
25use libc::sigpending;
26use libc::sigset_t;
27use libc::sigtimedwait;
28use libc::sigwait;
29use libc::timespec;
30use libc::EAGAIN;
31use libc::EINTR;
32use libc::EINVAL;
33use libc::SA_RESTART;
34use libc::SIG_BLOCK;
35use libc::SIG_DFL;
36use libc::SIG_UNBLOCK;
37use remain::sorted;
38use thiserror::Error;
39
40use super::errno_result;
41use super::Error as ErrnoError;
42use super::Pid;
43use super::Result;
44use crate::handle_eintr_errno;
45use crate::handle_eintr_rc;
46use crate::unix::duration_to_timespec;
47
48#[sorted]
49#[derive(Error, Debug)]
50pub enum Error {
51 #[error("signal could not be blocked: {0}")]
53 BlockSignal(ErrnoError),
54 #[error("failed to check whether given signal is in the pending set: {0}")]
56 ClearCheckPending(ErrnoError),
57 #[error("failed to get pending signals: {0}")]
59 ClearGetPending(ErrnoError),
60 #[error("failed to wait for given signal: {0}")]
62 ClearWaitPending(ErrnoError),
63 #[error("failed to check whether requested signal is in the blocked set: {0}")]
65 CompareBlockedSignals(ErrnoError),
66 #[error("couldn't create a sigset: {0}")]
68 CreateSigset(ErrnoError),
69 #[error("failed to get session id: {0}")]
71 GetSid(ErrnoError),
72 #[error("failed to send signal: {0}")]
74 Kill(ErrnoError),
75 #[error("failed to retrieve signal mask: {}", io::Error::from_raw_os_error(*.0))]
77 RetrieveSignalMask(i32),
78 #[error("got RT signal greater than max: {0:?}")]
80 RtSignumGreaterThanMax(Signal),
81 #[error("signal {0} already blocked")]
83 SignalAlreadyBlocked(c_int),
84 #[error("timeout reached.")]
86 TimedOut,
87 #[error("signal could not be unblocked: {0}")]
89 UnblockSignal(ErrnoError),
90 #[error("unrecoginized signal number: {0}")]
92 UnrecognizedSignum(i32),
93 #[error("failed to wait for signal: {0}")]
95 WaitForSignal(ErrnoError),
96 #[error("failed to wait for process: {0}")]
98 WaitPid(ErrnoError),
99}
100
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102#[repr(i32)]
103pub enum Signal {
104 Abort = libc::SIGABRT,
105 Alarm = libc::SIGALRM,
106 Bus = libc::SIGBUS,
107 Child = libc::SIGCHLD,
108 Continue = libc::SIGCONT,
109 ExceededFileSize = libc::SIGXFSZ,
110 FloatingPointException = libc::SIGFPE,
111 HangUp = libc::SIGHUP,
112 IllegalInstruction = libc::SIGILL,
113 Interrupt = libc::SIGINT,
114 Io = libc::SIGIO,
115 Kill = libc::SIGKILL,
116 Pipe = libc::SIGPIPE,
117 Power = libc::SIGPWR,
118 Profile = libc::SIGPROF,
119 Quit = libc::SIGQUIT,
120 SegmentationViolation = libc::SIGSEGV,
121 StackFault = libc::SIGSTKFLT,
122 Stop = libc::SIGSTOP,
123 Sys = libc::SIGSYS,
124 Trap = libc::SIGTRAP,
125 Terminate = libc::SIGTERM,
126 TtyIn = libc::SIGTTIN,
127 TtyOut = libc::SIGTTOU,
128 TtyStop = libc::SIGTSTP,
129 Urgent = libc::SIGURG,
130 User1 = libc::SIGUSR1,
131 User2 = libc::SIGUSR2,
132 VtAlarm = libc::SIGVTALRM,
133 Winch = libc::SIGWINCH,
134 Xcpu = libc::SIGXCPU,
135 Rt0 = libc::SIGSYS + 1,
137 Rt1,
138 Rt2,
139 Rt3,
140 Rt4,
141 Rt5,
142 Rt6,
143 Rt7,
144 Rt8,
146 Rt9,
147 Rt10,
148 Rt11,
149 Rt12,
150 Rt13,
151 Rt14,
152 Rt15,
153 Rt16,
154 Rt17,
155 Rt18,
156 Rt19,
157 Rt20,
158 Rt21,
159 Rt22,
160 Rt23,
161 Rt24,
162 Rt25,
163 Rt26,
164 Rt27,
165 Rt28,
166 Rt29,
167 Rt30,
168 Rt31,
169}
170
171impl std::fmt::Display for Signal {
172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
173 let n = i32::from(*self);
174 let ptr = unsafe { libc::strsignal(n) };
176 if ptr.is_null() {
177 f.write_str("[null]")
178 } else {
179 let s = unsafe { std::ffi::CStr::from_ptr(ptr) }
185 .to_str()
186 .unwrap()
187 .to_string();
188 f.write_str(&s)
189 }
190 }
191}
192
193impl From<Signal> for c_int {
194 fn from(signal: Signal) -> c_int {
195 let num = signal as libc::c_int;
196 if num >= Signal::Rt0 as libc::c_int {
197 return num - (Signal::Rt0 as libc::c_int) + SIGRTMIN();
198 }
199 num
200 }
201}
202
203impl TryFrom<c_int> for Signal {
204 type Error = Error;
205
206 fn try_from(value: c_int) -> result::Result<Self, Self::Error> {
207 use Signal::*;
208
209 Ok(match value {
210 libc::SIGABRT => Abort,
211 libc::SIGALRM => Alarm,
212 libc::SIGBUS => Bus,
213 libc::SIGCHLD => Child,
214 libc::SIGCONT => Continue,
215 libc::SIGXFSZ => ExceededFileSize,
216 libc::SIGFPE => FloatingPointException,
217 libc::SIGHUP => HangUp,
218 libc::SIGILL => IllegalInstruction,
219 libc::SIGINT => Interrupt,
220 libc::SIGIO => Io,
221 libc::SIGKILL => Kill,
222 libc::SIGPIPE => Pipe,
223 libc::SIGPWR => Power,
224 libc::SIGPROF => Profile,
225 libc::SIGQUIT => Quit,
226 libc::SIGSEGV => SegmentationViolation,
227 libc::SIGSTKFLT => StackFault,
228 libc::SIGSTOP => Stop,
229 libc::SIGSYS => Sys,
230 libc::SIGTRAP => Trap,
231 libc::SIGTERM => Terminate,
232 libc::SIGTTIN => TtyIn,
233 libc::SIGTTOU => TtyOut,
234 libc::SIGTSTP => TtyStop,
235 libc::SIGURG => Urgent,
236 libc::SIGUSR1 => User1,
237 libc::SIGUSR2 => User2,
238 libc::SIGVTALRM => VtAlarm,
239 libc::SIGWINCH => Winch,
240 libc::SIGXCPU => Xcpu,
241 _ => {
242 if value < SIGRTMIN() {
243 return Err(Error::UnrecognizedSignum(value));
244 }
245 let signal = match value - SIGRTMIN() {
246 0 => Rt0,
247 1 => Rt1,
248 2 => Rt2,
249 3 => Rt3,
250 4 => Rt4,
251 5 => Rt5,
252 6 => Rt6,
253 7 => Rt7,
254 8 => Rt8,
255 9 => Rt9,
256 10 => Rt10,
257 11 => Rt11,
258 12 => Rt12,
259 13 => Rt13,
260 14 => Rt14,
261 15 => Rt15,
262 16 => Rt16,
263 17 => Rt17,
264 18 => Rt18,
265 19 => Rt19,
266 20 => Rt20,
267 21 => Rt21,
268 22 => Rt22,
269 23 => Rt23,
270 24 => Rt24,
271 25 => Rt25,
272 26 => Rt26,
273 27 => Rt27,
274 28 => Rt28,
275 29 => Rt29,
276 30 => Rt30,
277 31 => Rt31,
278 _ => {
279 return Err(Error::UnrecognizedSignum(value));
280 }
281 };
282 if value > SIGRTMAX() {
283 return Err(Error::RtSignumGreaterThanMax(signal));
284 }
285 signal
286 }
287 })
288 }
289}
290
291pub type SignalResult<T> = result::Result<T, Error>;
292
293#[link(name = "c")]
294extern "C" {
295 fn __libc_current_sigrtmin() -> c_int;
296 fn __libc_current_sigrtmax() -> c_int;
297}
298
299#[allow(non_snake_case)]
301pub fn SIGRTMIN() -> c_int {
302 unsafe { __libc_current_sigrtmin() }
304}
305
306#[allow(non_snake_case)]
308pub fn SIGRTMAX() -> c_int {
309 unsafe { __libc_current_sigrtmax() }
311}
312
313fn valid_rt_signal_num(num: c_int) -> bool {
314 num >= SIGRTMIN() && num <= SIGRTMAX()
315}
316
317pub unsafe fn register_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()> {
324 let mut sigact: sigaction = mem::zeroed();
325 sigact.sa_flags = SA_RESTART;
326 sigact.sa_sigaction = handler as *const () as usize;
327
328 let ret = sigaction(num, &sigact, null_mut());
329 if ret < 0 {
330 return errno_result();
331 }
332
333 Ok(())
334}
335
336pub fn clear_signal_handler(num: c_int) -> Result<()> {
338 let mut sigact: sigaction = unsafe { mem::zeroed() };
341 sigact.sa_flags = SA_RESTART;
342 sigact.sa_sigaction = SIG_DFL;
343
344 let ret = unsafe { sigaction(num, &sigact, null_mut()) };
347 if ret < 0 {
348 return errno_result();
349 }
350
351 Ok(())
352}
353
354pub unsafe fn register_rt_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()> {
363 if !valid_rt_signal_num(num) {
364 return Err(ErrnoError::new(EINVAL));
365 }
366
367 register_signal_handler(num, handler)
368}
369
370pub fn create_sigset(signals: &[c_int]) -> Result<sigset_t> {
374 let mut sigset: sigset_t = unsafe { mem::zeroed() };
377
378 let ret = unsafe { sigemptyset(&mut sigset) };
381 if ret < 0 {
382 return errno_result();
383 }
384
385 for signal in signals {
386 let ret = unsafe { sigaddset(&mut sigset, *signal) };
389 if ret < 0 {
390 return errno_result();
391 }
392 }
393
394 Ok(sigset)
395}
396
397pub fn wait_for_signal(signals: &[c_int], timeout: Option<Duration>) -> Result<c_int> {
400 let sigset = create_sigset(signals)?;
401
402 match timeout {
403 Some(timeout) => {
404 let ts = duration_to_timespec(timeout);
405 let ret = handle_eintr_errno!(unsafe { sigtimedwait(&sigset, null_mut(), &ts) });
408 if ret < 0 {
409 errno_result()
410 } else {
411 Ok(ret)
412 }
413 }
414 None => {
415 let mut ret: c_int = 0;
416 let err = handle_eintr_rc!(unsafe { sigwait(&sigset, &mut ret as *mut c_int) });
418 if err != 0 {
419 Err(ErrnoError::new(err))
420 } else {
421 Ok(ret)
422 }
423 }
424 }
425}
426
427pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
429 let mut mask = Vec::new();
430
431 unsafe {
434 let mut old_sigset: sigset_t = mem::zeroed();
435 let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
436 if ret < 0 {
437 return Err(Error::RetrieveSignalMask(ret));
438 }
439
440 for num in 0..=SIGRTMAX() {
441 if sigismember(&old_sigset, num) > 0 {
442 mask.push(num);
443 }
444 }
445 }
446
447 Ok(mask)
448}
449
450pub fn block_signal(num: c_int) -> SignalResult<()> {
455 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
456
457 unsafe {
460 let mut old_sigset: sigset_t = mem::zeroed();
461 let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
462 if ret < 0 {
463 return Err(Error::BlockSignal(ErrnoError::last()));
464 }
465 let ret = sigismember(&old_sigset, num);
466 match ret.cmp(&0) {
467 Ordering::Less => {
468 return Err(Error::CompareBlockedSignals(ErrnoError::last()));
469 }
470 Ordering::Greater => {
471 return Err(Error::SignalAlreadyBlocked(num));
472 }
473 _ => (),
474 };
475 }
476 Ok(())
477}
478
479pub fn unblock_signal(num: c_int) -> SignalResult<()> {
481 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
482
483 let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
486 if ret < 0 {
487 return Err(Error::UnblockSignal(ErrnoError::last()));
488 }
489 Ok(())
490}
491
492pub fn clear_signal(num: c_int) -> SignalResult<()> {
494 let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
495
496 while {
497 unsafe {
501 let mut siginfo: siginfo_t = mem::zeroed();
502 let ts = timespec {
503 tv_sec: 0,
504 tv_nsec: 0,
505 };
506 let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
509 if ret < 0 {
510 let e = ErrnoError::last();
511 match e.errno() {
512 EAGAIN | EINTR => {}
513 _ => {
514 return Err(Error::ClearWaitPending(ErrnoError::last()));
515 }
516 }
517 }
518
519 let mut chkset: sigset_t = mem::zeroed();
521 let ret = sigpending(&mut chkset);
523 if ret < 0 {
524 return Err(Error::ClearGetPending(ErrnoError::last()));
525 }
526
527 let ret = sigismember(&chkset, num);
528 if ret < 0 {
529 return Err(Error::ClearCheckPending(ErrnoError::last()));
530 }
531
532 ret != 0
534 }
535 } {}
536
537 Ok(())
538}
539
540pub unsafe fn kill(pid: Pid, signum: c_int) -> Result<()> {
545 let ret = libc::kill(pid, signum);
546
547 if ret != 0 {
548 errno_result()
549 } else {
550 Ok(())
551 }
552}
553
554pub unsafe trait Killable {
563 fn pthread_handle(&self) -> pthread_t;
564
565 fn kill(&self, num: c_int) -> Result<()> {
569 if !valid_rt_signal_num(num) {
570 return Err(ErrnoError::new(EINVAL));
571 }
572
573 let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
577 if ret < 0 {
578 return errno_result();
579 }
580 Ok(())
581 }
582}
583
584unsafe impl<T> Killable for JoinHandle<T> {
587 fn pthread_handle(&self) -> pthread_t {
588 self.as_pthread_t() as _
589 }
590}
591
592pub struct BlockedSignal {
594 signal_num: c_int,
595}
596
597impl BlockedSignal {
598 pub fn new(signal_num: c_int) -> Option<BlockedSignal> {
600 if block_signal(signal_num).is_ok() {
601 Some(BlockedSignal { signal_num })
602 } else {
603 None
604 }
605 }
606}
607
608impl Drop for BlockedSignal {
609 fn drop(&mut self) {
610 unblock_signal(self.signal_num).expect("failed to restore signal mask");
611 }
612}