1use mio::{
6 event::{self},
7 unix::SourceFd,
8 Interest, Registry, Token,
9};
10use std::{fmt, mem, os::unix::prelude::RawFd, str::FromStr};
11
12use crate::{Error, Result};
13
14#[repr(i32)]
19#[non_exhaustive]
20#[derive(Copy, Clone, PartialEq, Eq, Debug)]
21pub enum Signal {
22 SIGHUP = libc::SIGHUP,
24 SIGINT = libc::SIGINT,
26 SIGQUIT = libc::SIGQUIT,
28 SIGILL = libc::SIGILL,
30 SIGTRAP = libc::SIGTRAP,
32 SIGABRT = libc::SIGABRT,
34 SIGBUS = libc::SIGBUS,
36 SIGFPE = libc::SIGFPE,
38 SIGKILL = libc::SIGKILL,
40 SIGUSR1 = libc::SIGUSR1,
42 SIGSEGV = libc::SIGSEGV,
44 SIGUSR2 = libc::SIGUSR2,
46 SIGPIPE = libc::SIGPIPE,
48 SIGALRM = libc::SIGALRM,
50 SIGTERM = libc::SIGTERM,
52 SIGSTKFLT = libc::SIGSTKFLT,
54 SIGCHLD = libc::SIGCHLD,
56 SIGCONT = libc::SIGCONT,
58 SIGSTOP = libc::SIGSTOP,
60 SIGTSTP = libc::SIGTSTP,
62 SIGTTIN = libc::SIGTTIN,
64 SIGTTOU = libc::SIGTTOU,
66 SIGURG = libc::SIGURG,
68 SIGXCPU = libc::SIGXCPU,
70 SIGXFSZ = libc::SIGXFSZ,
72 SIGVTALRM = libc::SIGVTALRM,
74 SIGPROF = libc::SIGPROF,
76 SIGWINCH = libc::SIGWINCH,
78 SIGIO = libc::SIGIO,
80 SIGPWR = libc::SIGPWR,
82 SIGSYS = libc::SIGSYS,
84}
85
86impl Signal {
87 pub const fn as_str(self) -> &'static str {
89 match self {
90 Signal::SIGHUP => "SIGHUP",
91 Signal::SIGINT => "SIGINT",
92 Signal::SIGQUIT => "SIGQUIT",
93 Signal::SIGILL => "SIGILL",
94 Signal::SIGTRAP => "SIGTRAP",
95 Signal::SIGABRT => "SIGABRT",
96 Signal::SIGBUS => "SIGBUS",
97 Signal::SIGFPE => "SIGFPE",
98 Signal::SIGKILL => "SIGKILL",
99 Signal::SIGUSR1 => "SIGUSR1",
100 Signal::SIGSEGV => "SIGSEGV",
101 Signal::SIGUSR2 => "SIGUSR2",
102 Signal::SIGPIPE => "SIGPIPE",
103 Signal::SIGALRM => "SIGALRM",
104 Signal::SIGTERM => "SIGTERM",
105 Signal::SIGSTKFLT => "SIGSTKFLT",
106 Signal::SIGCHLD => "SIGCHLD",
107 Signal::SIGCONT => "SIGCONT",
108 Signal::SIGSTOP => "SIGSTOP",
109 Signal::SIGTSTP => "SIGTSTP",
110 Signal::SIGTTIN => "SIGTTIN",
111 Signal::SIGTTOU => "SIGTTOU",
112 Signal::SIGURG => "SIGURG",
113 Signal::SIGXCPU => "SIGXCPU",
114 Signal::SIGXFSZ => "SIGXFSZ",
115 Signal::SIGVTALRM => "SIGVTALRM",
116 Signal::SIGPROF => "SIGPROF",
117 Signal::SIGWINCH => "SIGWINCH",
118 Signal::SIGIO => "SIGIO",
119 Signal::SIGPWR => "SIGPWR",
120 Signal::SIGSYS => "SIGSYS",
121 }
122 }
123}
124
125impl FromStr for Signal {
126 type Err = Error;
127
128 fn from_str(s: &str) -> Result<Signal> {
130 Ok(match s {
131 "SIGHUP" => Signal::SIGHUP,
132 "SIGINT" => Signal::SIGINT,
133 "SIGQUIT" => Signal::SIGQUIT,
134 "SIGILL" => Signal::SIGILL,
135 "SIGTRAP" => Signal::SIGTRAP,
136 "SIGABRT" => Signal::SIGABRT,
137 "SIGBUS" => Signal::SIGBUS,
138 "SIGFPE" => Signal::SIGFPE,
139 "SIGKILL" => Signal::SIGKILL,
140 "SIGUSR1" => Signal::SIGUSR1,
141 "SIGSEGV" => Signal::SIGSEGV,
142 "SIGUSR2" => Signal::SIGUSR2,
143 "SIGPIPE" => Signal::SIGPIPE,
144 "SIGALRM" => Signal::SIGALRM,
145 "SIGTERM" => Signal::SIGTERM,
146 "SIGSTKFLT" => Signal::SIGSTKFLT,
147 "SIGCHLD" => Signal::SIGCHLD,
148 "SIGCONT" => Signal::SIGCONT,
149 "SIGSTOP" => Signal::SIGSTOP,
150 "SIGTSTP" => Signal::SIGTSTP,
151 "SIGTTIN" => Signal::SIGTTIN,
152 "SIGTTOU" => Signal::SIGTTOU,
153 "SIGURG" => Signal::SIGURG,
154 "SIGXCPU" => Signal::SIGXCPU,
155 "SIGXFSZ" => Signal::SIGXFSZ,
156 "SIGVTALRM" => Signal::SIGVTALRM,
157 "SIGPROF" => Signal::SIGPROF,
158 "SIGWINCH" => Signal::SIGWINCH,
159 "SIGIO" => Signal::SIGIO,
160 "SIGPWR" => Signal::SIGPWR,
161 "SIGSYS" => Signal::SIGSYS,
162 _ => {
163 return Err(Error::Syscall(std::io::Error::new(
164 std::io::ErrorKind::InvalidData,
165 "invalid signal",
166 )))
167 }
168 })
169 }
170}
171
172impl TryFrom<libc::c_int> for Signal {
173 type Error = Error;
174
175 fn try_from(signum: libc::c_int) -> std::result::Result<Self, Self::Error> {
180 if 0 < signum && signum < 32 {
181 Ok(unsafe { mem::transmute(signum) })
182 } else {
183 Err(Error::Syscall(std::io::Error::new(
184 std::io::ErrorKind::InvalidData,
185 "invalid signal number",
186 )))
187 }
188 }
189}
190
191impl AsRef<str> for Signal {
192 fn as_ref(&self) -> &str {
193 self.as_str()
194 }
195}
196
197impl fmt::Display for Signal {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 f.write_str(self.as_ref())
200 }
201}
202
203#[derive(Clone, Copy, Debug, PartialEq, Eq)]
208pub struct SignalSet(libc::sigset_t);
209
210impl SignalSet {
211 pub fn fill() -> Result<SignalSet> {
213 let mut set = mem::MaybeUninit::uninit();
214
215 syscall!(sigfillset(set.as_mut_ptr()))?;
216
217 Ok(unsafe { SignalSet(set.assume_init()) })
218 }
219
220 pub fn empty() -> Result<SignalSet> {
225 let mut set = mem::MaybeUninit::uninit();
226
227 syscall!(sigemptyset(set.as_mut_ptr()))?;
228
229 Ok(unsafe { SignalSet(set.assume_init()) })
230 }
231
232 pub fn add(&mut self, signal: Signal) -> Result<()> {
234 syscall!(sigaddset(
235 &mut self.0 as *mut libc::sigset_t,
236 signal as libc::c_int
237 ))?;
238
239 Ok(())
240 }
241
242 pub fn remove(&mut self, signal: Signal) -> Result<()> {
244 syscall!(sigdelset(
245 &mut self.0 as *mut libc::sigset_t,
246 signal as libc::c_int
247 ))?;
248
249 Ok(())
250 }
251}
252
253impl AsRef<libc::sigset_t> for SignalSet {
254 fn as_ref(&self) -> &libc::sigset_t {
255 &self.0
256 }
257}
258
259impl From<&[Signal]> for SignalSet {
260 fn from(signals: &[Signal]) -> Self {
265 *signals.iter().fold(
266 &mut SignalSet::empty().expect("syscall failed"),
267 |set, sig| {
268 set.add(*sig).expect("syscall failed");
269 set
270 },
271 )
272 }
273}
274
275const SIGNALFD_NEW: libc::c_int = -1;
277
278#[derive(Debug, PartialEq, Eq)]
283pub struct SignalFd(RawFd);
284
285impl SignalFd {
286 pub fn new(signals: SignalSet) -> Result<SignalFd> {
289 let fd = syscall!(signalfd(
290 SIGNALFD_NEW,
291 signals.as_ref() as *const libc::sigset_t,
292 0
293 ))?;
294
295 Ok(SignalFd(fd))
296 }
297
298 pub fn read_signal(&mut self) -> Result<Signal> {
302 let mut siginfo = mem::MaybeUninit::<libc::signalfd_siginfo>::uninit();
303 let size = mem::size_of_val(&siginfo);
304
305 let num = syscall!(read(
306 self.0,
307 siginfo.as_mut_ptr() as *mut libc::c_void,
308 size
309 ))?;
310
311 if num as usize != size {
313 return Err(Error::Syscall(std::io::Error::new(
314 std::io::ErrorKind::InvalidData,
315 "invalid signal",
316 )));
317 }
318
319 let siginfo = unsafe { siginfo.assume_init() };
320 let signum = siginfo.ssi_signo as libc::c_int;
321
322 signum.try_into()
323 }
324}
325
326impl event::Source for SignalFd {
327 fn register(
328 &mut self,
329 registry: &Registry,
330 token: Token,
331 interests: Interest,
332 ) -> std::io::Result<()> {
333 SourceFd(&self.0).register(registry, token, interests)
334 }
335
336 fn reregister(
337 &mut self,
338 registry: &Registry,
339 token: Token,
340 interests: Interest,
341 ) -> std::io::Result<()> {
342 SourceFd(&self.0).reregister(registry, token, interests)
343 }
344
345 fn deregister(&mut self, registry: &Registry) -> std::io::Result<()> {
346 SourceFd(&self.0).deregister(registry)
347 }
348}
349
350impl Drop for SignalFd {
351 fn drop(&mut self) {
357 unsafe { libc::close(self.0) };
358
359 if std::io::Error::last_os_error().raw_os_error().unwrap_or(0) == libc::EBADF {
361 panic!("closing invalid signal fd");
362 }
363 }
364}
365
366pub fn signal_block(set: SignalSet) -> Result<SignalSet> {
372 let mut old = SignalSet::empty()?;
373
374 syscall!(sigprocmask(
375 libc::SIG_BLOCK,
376 &set.0 as *const libc::sigset_t,
377 &mut old.0 as &mut libc::sigset_t
378 ))?;
379
380 Ok(old)
381}
382
383pub fn signal_restore(set: SignalSet) -> Result<SignalSet> {
389 let mut old = SignalSet::empty()?;
390
391 syscall!(sigprocmask(
392 libc::SIG_SETMASK,
393 &set.0 as *const libc::sigset_t,
394 &mut old.0 as &mut libc::sigset_t
395 ))?;
396
397 Ok(old)
398}
399
400#[cfg(test)]
401mod tests {
402 use anyhow::Result;
403
404 use super::{signal_block, signal_restore, Signal, SignalFd, SignalSet};
405
406 #[test]
407 fn signal_set_add() -> Result<()> {
408 let mut set = SignalSet::empty()?;
409
410 set.add(Signal::SIGCHLD)?;
411 set.add(Signal::SIGPIPE)?;
412
413 assert_ne!(set, SignalSet::empty()?);
414 assert_ne!(set, SignalSet::fill()?);
415
416 Ok(())
417 }
418
419 #[test]
420 fn signal_set_remove() -> Result<()> {
421 let mut set = SignalSet::empty()?;
422
423 set.add(Signal::SIGHUP)?;
424 set.add(Signal::SIGQUIT)?;
425
426 set.remove(Signal::SIGHUP)?;
427 set.remove(Signal::SIGQUIT)?;
428
429 assert_eq!(set, SignalSet::empty()?);
430 assert_ne!(set, SignalSet::fill()?);
431
432 Ok(())
433 }
434
435 #[test]
436 fn signal_set_remove_unknown() -> Result<()> {
437 let mut set = SignalSet::empty()?;
438
439 set.remove(Signal::SIGCHLD)?;
440
441 set.add(Signal::SIGHUP)?;
442
443 set.remove(Signal::SIGCHLD)?;
444 set.remove(Signal::SIGHUP)?;
445
446 assert_eq!(set, SignalSet::empty()?);
447 assert_ne!(set, SignalSet::fill()?);
448
449 Ok(())
450 }
451
452 #[test]
453 fn signal_try_from() -> Result<()> {
454 let signum = Signal::SIGQUIT as libc::c_int;
455 let sig: Signal = signum.try_into()?;
456
457 assert_eq!(signum, libc::SIGQUIT);
458 assert_eq!(sig, Signal::SIGQUIT);
459
460 let res: std::result::Result<Signal, _> = (255 as libc::c_int).try_into();
461
462 assert_eq!(
463 format!("{:?}", res.err().unwrap()),
464 "Syscall(Custom { kind: InvalidData, error: \"invalid signal number\" })"
465 );
466
467 Ok(())
468 }
469
470 #[test]
471 fn block_signals() -> Result<()> {
472 let signals = vec![
473 Signal::SIGCHLD,
474 Signal::SIGINT,
475 Signal::SIGQUIT,
476 Signal::SIGTERM,
477 ];
478
479 let old = signal_block(signals.as_slice().into())?;
481
482 assert_eq!(old, SignalSet::empty()?);
483 assert_ne!(old, SignalSet::fill()?);
484
485 let blocked = signal_block(old)?;
487
488 assert_eq!(blocked, signals.as_slice().into());
489
490 Ok(())
491 }
492
493 #[test]
494 fn restore_signals() -> Result<()> {
495 let signals = vec![
496 Signal::SIGCHLD,
497 Signal::SIGINT,
498 Signal::SIGQUIT,
499 Signal::SIGTERM,
500 ];
501
502 let old = signal_block(signals.as_slice().into())?;
503
504 let blocked = signal_restore(old)?;
505
506 assert_eq!(blocked, signals.as_slice().into());
507
508 Ok(())
509 }
510
511 #[test]
512 fn signalfd_new() -> Result<()> {
513 let _ = SignalFd::new(SignalSet::empty()?)?;
514 Ok(())
515 }
516
517 #[test]
518 #[should_panic(expected = "closing invalid signal fd")]
519 fn signalfd_drop_invalid() {
520 let fake = SignalFd(-1);
521 drop(fake);
522 }
523}