nix/sys/
signal.rs

1// Portions of this file are Copyright 2014 The Rust Project Developers.
2// See https://www.rust-lang.org/policies/licenses.
3
4//! Operating system signals.
5
6use crate::{Error, Result};
7use crate::errno::Errno;
8use crate::unistd::Pid;
9use std::mem;
10use std::fmt;
11use std::str::FromStr;
12#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
13use std::os::unix::io::RawFd;
14use std::ptr;
15
16#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
17pub use self::sigevent::*;
18
19libc_enum!{
20    /// Types of operating system signals
21    // Currently there is only one definition of c_int in libc, as well as only one
22    // type for signal constants.
23    // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
24    // this is not (yet) possible.
25    #[repr(i32)]
26    #[non_exhaustive]
27    pub enum Signal {
28        /// Hangup
29        SIGHUP,
30        /// Interrupt
31        SIGINT,
32        /// Quit
33        SIGQUIT,
34        /// Illegal instruction (not reset when caught)
35        SIGILL,
36        /// Trace trap (not reset when caught)
37        SIGTRAP,
38        /// Abort
39        SIGABRT,
40        /// Bus error
41        SIGBUS,
42        /// Floating point exception
43        SIGFPE,
44        /// Kill (cannot be caught or ignored)
45        SIGKILL,
46        /// User defined signal 1
47        SIGUSR1,
48        /// Segmentation violation
49        SIGSEGV,
50        /// User defined signal 2
51        SIGUSR2,
52        /// Write on a pipe with no one to read it
53        SIGPIPE,
54        /// Alarm clock
55        SIGALRM,
56        /// Software termination signal from kill
57        SIGTERM,
58        /// Stack fault (obsolete)
59        #[cfg(all(any(target_os = "android", target_os = "emscripten",
60                      target_os = "fuchsia", target_os = "linux"),
61                  not(any(target_arch = "mips", target_arch = "mips64",
62                          target_arch = "sparc64"))))]
63        SIGSTKFLT,
64        /// To parent on child stop or exit
65        SIGCHLD,
66        /// Continue a stopped process
67        SIGCONT,
68        /// Sendable stop signal not from tty
69        SIGSTOP,
70        /// Stop signal from tty
71        SIGTSTP,
72        /// To readers pgrp upon background tty read
73        SIGTTIN,
74        /// Like TTIN if (tp->t_local&LTOSTOP)
75        SIGTTOU,
76        /// Urgent condition on IO channel
77        SIGURG,
78        /// Exceeded CPU time limit
79        SIGXCPU,
80        /// Exceeded file size limit
81        SIGXFSZ,
82        /// Virtual time alarm
83        SIGVTALRM,
84        /// Profiling time alarm
85        SIGPROF,
86        /// Window size changes
87        SIGWINCH,
88        /// Input/output possible signal
89        SIGIO,
90        #[cfg(any(target_os = "android", target_os = "emscripten",
91                  target_os = "fuchsia", target_os = "linux"))]
92        /// Power failure imminent.
93        SIGPWR,
94        /// Bad system call
95        SIGSYS,
96        #[cfg(not(any(target_os = "android", target_os = "emscripten",
97                      target_os = "fuchsia", target_os = "linux",
98                      target_os = "redox")))]
99        /// Emulator trap
100        SIGEMT,
101        #[cfg(not(any(target_os = "android", target_os = "emscripten",
102                      target_os = "fuchsia", target_os = "linux",
103                      target_os = "redox")))]
104        /// Information request
105        SIGINFO,
106    }
107    impl TryFrom<i32>
108}
109
110impl FromStr for Signal {
111    type Err = Error;
112    fn from_str(s: &str) -> Result<Signal> {
113        Ok(match s {
114            "SIGHUP" => Signal::SIGHUP,
115            "SIGINT" => Signal::SIGINT,
116            "SIGQUIT" => Signal::SIGQUIT,
117            "SIGILL" => Signal::SIGILL,
118            "SIGTRAP" => Signal::SIGTRAP,
119            "SIGABRT" => Signal::SIGABRT,
120            "SIGBUS" => Signal::SIGBUS,
121            "SIGFPE" => Signal::SIGFPE,
122            "SIGKILL" => Signal::SIGKILL,
123            "SIGUSR1" => Signal::SIGUSR1,
124            "SIGSEGV" => Signal::SIGSEGV,
125            "SIGUSR2" => Signal::SIGUSR2,
126            "SIGPIPE" => Signal::SIGPIPE,
127            "SIGALRM" => Signal::SIGALRM,
128            "SIGTERM" => Signal::SIGTERM,
129            #[cfg(all(any(target_os = "android", target_os = "emscripten",
130                          target_os = "fuchsia", target_os = "linux"),
131                      not(any(target_arch = "mips", target_arch = "mips64",
132                              target_arch = "sparc64"))))]
133            "SIGSTKFLT" => Signal::SIGSTKFLT,
134            "SIGCHLD" => Signal::SIGCHLD,
135            "SIGCONT" => Signal::SIGCONT,
136            "SIGSTOP" => Signal::SIGSTOP,
137            "SIGTSTP" => Signal::SIGTSTP,
138            "SIGTTIN" => Signal::SIGTTIN,
139            "SIGTTOU" => Signal::SIGTTOU,
140            "SIGURG" => Signal::SIGURG,
141            "SIGXCPU" => Signal::SIGXCPU,
142            "SIGXFSZ" => Signal::SIGXFSZ,
143            "SIGVTALRM" => Signal::SIGVTALRM,
144            "SIGPROF" => Signal::SIGPROF,
145            "SIGWINCH" => Signal::SIGWINCH,
146            "SIGIO" => Signal::SIGIO,
147            #[cfg(any(target_os = "android", target_os = "emscripten",
148                      target_os = "fuchsia", target_os = "linux"))]
149            "SIGPWR" => Signal::SIGPWR,
150            "SIGSYS" => Signal::SIGSYS,
151            #[cfg(not(any(target_os = "android", target_os = "emscripten",
152                          target_os = "fuchsia", target_os = "linux",
153                          target_os = "redox")))]
154            "SIGEMT" => Signal::SIGEMT,
155            #[cfg(not(any(target_os = "android", target_os = "emscripten",
156                          target_os = "fuchsia", target_os = "linux",
157                          target_os = "redox")))]
158            "SIGINFO" => Signal::SIGINFO,
159            _ => return Err(Errno::EINVAL),
160        })
161    }
162}
163
164impl Signal {
165    /// Returns name of signal.
166    ///
167    /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
168    /// with difference that returned string is `'static`
169    /// and not bound to `self`'s lifetime.
170    pub const fn as_str(self) -> &'static str {
171        match self {
172            Signal::SIGHUP => "SIGHUP",
173            Signal::SIGINT => "SIGINT",
174            Signal::SIGQUIT => "SIGQUIT",
175            Signal::SIGILL => "SIGILL",
176            Signal::SIGTRAP => "SIGTRAP",
177            Signal::SIGABRT => "SIGABRT",
178            Signal::SIGBUS => "SIGBUS",
179            Signal::SIGFPE => "SIGFPE",
180            Signal::SIGKILL => "SIGKILL",
181            Signal::SIGUSR1 => "SIGUSR1",
182            Signal::SIGSEGV => "SIGSEGV",
183            Signal::SIGUSR2 => "SIGUSR2",
184            Signal::SIGPIPE => "SIGPIPE",
185            Signal::SIGALRM => "SIGALRM",
186            Signal::SIGTERM => "SIGTERM",
187            #[cfg(all(any(target_os = "android", target_os = "emscripten",
188                          target_os = "fuchsia", target_os = "linux"),
189                      not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
190            Signal::SIGSTKFLT => "SIGSTKFLT",
191            Signal::SIGCHLD => "SIGCHLD",
192            Signal::SIGCONT => "SIGCONT",
193            Signal::SIGSTOP => "SIGSTOP",
194            Signal::SIGTSTP => "SIGTSTP",
195            Signal::SIGTTIN => "SIGTTIN",
196            Signal::SIGTTOU => "SIGTTOU",
197            Signal::SIGURG => "SIGURG",
198            Signal::SIGXCPU => "SIGXCPU",
199            Signal::SIGXFSZ => "SIGXFSZ",
200            Signal::SIGVTALRM => "SIGVTALRM",
201            Signal::SIGPROF => "SIGPROF",
202            Signal::SIGWINCH => "SIGWINCH",
203            Signal::SIGIO => "SIGIO",
204            #[cfg(any(target_os = "android", target_os = "emscripten",
205                      target_os = "fuchsia", target_os = "linux"))]
206            Signal::SIGPWR => "SIGPWR",
207            Signal::SIGSYS => "SIGSYS",
208            #[cfg(not(any(target_os = "android", target_os = "emscripten",
209                          target_os = "fuchsia", target_os = "linux",
210                          target_os = "redox")))]
211            Signal::SIGEMT => "SIGEMT",
212            #[cfg(not(any(target_os = "android", target_os = "emscripten",
213                          target_os = "fuchsia", target_os = "linux",
214                          target_os = "redox")))]
215            Signal::SIGINFO => "SIGINFO",
216        }
217    }
218}
219
220impl AsRef<str> for Signal {
221    fn as_ref(&self) -> &str {
222        self.as_str()
223    }
224}
225
226impl fmt::Display for Signal {
227    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228        f.write_str(self.as_ref())
229    }
230}
231
232pub use self::Signal::*;
233
234#[cfg(target_os = "redox")]
235const SIGNALS: [Signal; 29] = [
236    SIGHUP,
237    SIGINT,
238    SIGQUIT,
239    SIGILL,
240    SIGTRAP,
241    SIGABRT,
242    SIGBUS,
243    SIGFPE,
244    SIGKILL,
245    SIGUSR1,
246    SIGSEGV,
247    SIGUSR2,
248    SIGPIPE,
249    SIGALRM,
250    SIGTERM,
251    SIGCHLD,
252    SIGCONT,
253    SIGSTOP,
254    SIGTSTP,
255    SIGTTIN,
256    SIGTTOU,
257    SIGURG,
258    SIGXCPU,
259    SIGXFSZ,
260    SIGVTALRM,
261    SIGPROF,
262    SIGWINCH,
263    SIGIO,
264    SIGSYS];
265#[cfg(all(any(target_os = "linux", target_os = "android",
266              target_os = "emscripten", target_os = "fuchsia"),
267          not(any(target_arch = "mips", target_arch = "mips64",
268                  target_arch = "sparc64"))))]
269const SIGNALS: [Signal; 31] = [
270    SIGHUP,
271    SIGINT,
272    SIGQUIT,
273    SIGILL,
274    SIGTRAP,
275    SIGABRT,
276    SIGBUS,
277    SIGFPE,
278    SIGKILL,
279    SIGUSR1,
280    SIGSEGV,
281    SIGUSR2,
282    SIGPIPE,
283    SIGALRM,
284    SIGTERM,
285    SIGSTKFLT,
286    SIGCHLD,
287    SIGCONT,
288    SIGSTOP,
289    SIGTSTP,
290    SIGTTIN,
291    SIGTTOU,
292    SIGURG,
293    SIGXCPU,
294    SIGXFSZ,
295    SIGVTALRM,
296    SIGPROF,
297    SIGWINCH,
298    SIGIO,
299    SIGPWR,
300    SIGSYS];
301#[cfg(all(any(target_os = "linux", target_os = "android",
302              target_os = "emscripten", target_os = "fuchsia"),
303          any(target_arch = "mips", target_arch = "mips64",
304              target_arch = "sparc64")))]
305const SIGNALS: [Signal; 30] = [
306    SIGHUP,
307    SIGINT,
308    SIGQUIT,
309    SIGILL,
310    SIGTRAP,
311    SIGABRT,
312    SIGBUS,
313    SIGFPE,
314    SIGKILL,
315    SIGUSR1,
316    SIGSEGV,
317    SIGUSR2,
318    SIGPIPE,
319    SIGALRM,
320    SIGTERM,
321    SIGCHLD,
322    SIGCONT,
323    SIGSTOP,
324    SIGTSTP,
325    SIGTTIN,
326    SIGTTOU,
327    SIGURG,
328    SIGXCPU,
329    SIGXFSZ,
330    SIGVTALRM,
331    SIGPROF,
332    SIGWINCH,
333    SIGIO,
334    SIGPWR,
335    SIGSYS];
336#[cfg(not(any(target_os = "linux", target_os = "android",
337              target_os = "fuchsia", target_os = "emscripten",
338              target_os = "redox")))]
339const SIGNALS: [Signal; 31] = [
340    SIGHUP,
341    SIGINT,
342    SIGQUIT,
343    SIGILL,
344    SIGTRAP,
345    SIGABRT,
346    SIGBUS,
347    SIGFPE,
348    SIGKILL,
349    SIGUSR1,
350    SIGSEGV,
351    SIGUSR2,
352    SIGPIPE,
353    SIGALRM,
354    SIGTERM,
355    SIGCHLD,
356    SIGCONT,
357    SIGSTOP,
358    SIGTSTP,
359    SIGTTIN,
360    SIGTTOU,
361    SIGURG,
362    SIGXCPU,
363    SIGXFSZ,
364    SIGVTALRM,
365    SIGPROF,
366    SIGWINCH,
367    SIGIO,
368    SIGSYS,
369    SIGEMT,
370    SIGINFO];
371
372#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
373/// Iterate through all signals defined by this operating system
374pub struct SignalIterator {
375    next: usize,
376}
377
378impl Iterator for SignalIterator {
379    type Item = Signal;
380
381    fn next(&mut self) -> Option<Signal> {
382        if self.next < SIGNALS.len() {
383            let next_signal = SIGNALS[self.next];
384            self.next += 1;
385            Some(next_signal)
386        } else {
387            None
388        }
389    }
390}
391
392impl Signal {
393    /// Iterate through all signals defined by this OS
394    pub const fn iterator() -> SignalIterator {
395        SignalIterator{next: 0}
396    }
397}
398
399/// Alias for [`SIGABRT`]
400pub const SIGIOT : Signal = SIGABRT;
401/// Alias for [`SIGIO`]
402pub const SIGPOLL : Signal = SIGIO;
403/// Alias for [`SIGSYS`]
404pub const SIGUNUSED : Signal = SIGSYS;
405
406#[cfg(not(target_os = "redox"))]
407type SaFlags_t = libc::c_int;
408#[cfg(target_os = "redox")]
409type SaFlags_t = libc::c_ulong;
410
411libc_bitflags!{
412    /// Controls the behavior of a [`SigAction`]
413    pub struct SaFlags: SaFlags_t {
414        /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
415        /// generated only when a child process exits, not when a child process
416        /// stops.
417        SA_NOCLDSTOP;
418        /// When catching a [`Signal::SIGCHLD`] signal, the system will not
419        /// create zombie processes when children of the calling process exit.
420        SA_NOCLDWAIT;
421        /// Further occurrences of the delivered signal are not masked during
422        /// the execution of the handler.
423        SA_NODEFER;
424        /// The system will deliver the signal to the process on a signal stack,
425        /// specified by each thread with sigaltstack(2).
426        SA_ONSTACK;
427        /// The handler is reset back to the default at the moment the signal is
428        /// delivered.
429        SA_RESETHAND;
430        /// Requests that certain system calls restart if interrupted by this
431        /// signal.  See the man page for complete details.
432        SA_RESTART;
433        /// This flag is controlled internally by Nix.
434        SA_SIGINFO;
435    }
436}
437
438libc_enum! {
439    /// Specifies how certain functions should manipulate a signal mask
440    #[repr(i32)]
441    #[non_exhaustive]
442    pub enum SigmaskHow {
443        /// The new mask is the union of the current mask and the specified set.
444        SIG_BLOCK,
445        /// The new mask is the intersection of the current mask and the
446        /// complement of the specified set.
447        SIG_UNBLOCK,
448        /// The current mask is replaced by the specified set.
449        SIG_SETMASK,
450    }
451}
452
453/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
454#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
455pub struct SigSet {
456    sigset: libc::sigset_t
457}
458
459
460impl SigSet {
461    /// Initialize to include all signals.
462    pub fn all() -> SigSet {
463        let mut sigset = mem::MaybeUninit::uninit();
464        let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
465
466        unsafe{ SigSet { sigset: sigset.assume_init() } }
467    }
468
469    /// Initialize to include nothing.
470    pub fn empty() -> SigSet {
471        let mut sigset = mem::MaybeUninit::uninit();
472        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
473
474        unsafe{ SigSet { sigset: sigset.assume_init() } }
475    }
476
477    /// Add the specified signal to the set.
478    pub fn add(&mut self, signal: Signal) {
479        unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
480    }
481
482    /// Remove all signals from this set.
483    pub fn clear(&mut self) {
484        unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
485    }
486
487    /// Remove the specified signal from this set.
488    pub fn remove(&mut self, signal: Signal) {
489        unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
490    }
491
492    /// Return whether this set includes the specified signal.
493    pub fn contains(&self, signal: Signal) -> bool {
494        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
495
496        match res {
497            1 => true,
498            0 => false,
499            _ => unreachable!("unexpected value from sigismember"),
500        }
501    }
502
503    /// Merge all of `other`'s signals into this set.
504    // TODO: use libc::sigorset on supported operating systems.
505    pub fn extend(&mut self, other: &SigSet) {
506        for signal in Signal::iterator() {
507            if other.contains(signal) {
508                self.add(signal);
509            }
510        }
511    }
512
513    /// Gets the currently blocked (masked) set of signals for the calling thread.
514    pub fn thread_get_mask() -> Result<SigSet> {
515        let mut oldmask = mem::MaybeUninit::uninit();
516        do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
517        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
518    }
519
520    /// Sets the set of signals as the signal mask for the calling thread.
521    pub fn thread_set_mask(&self) -> Result<()> {
522        pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
523    }
524
525    /// Adds the set of signals to the signal mask for the calling thread.
526    pub fn thread_block(&self) -> Result<()> {
527        pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
528    }
529
530    /// Removes the set of signals from the signal mask for the calling thread.
531    pub fn thread_unblock(&self) -> Result<()> {
532        pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
533    }
534
535    /// Sets the set of signals as the signal mask, and returns the old mask.
536    pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
537        let mut oldmask = mem::MaybeUninit::uninit();
538        do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
539        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
540    }
541
542    /// Suspends execution of the calling thread until one of the signals in the
543    /// signal mask becomes pending, and returns the accepted signal.
544    #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
545    pub fn wait(&self) -> Result<Signal> {
546        use std::convert::TryFrom;
547
548        let mut signum = mem::MaybeUninit::uninit();
549        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
550
551        Errno::result(res).map(|_| unsafe {
552            Signal::try_from(signum.assume_init()).unwrap()
553        })
554    }
555}
556
557impl AsRef<libc::sigset_t> for SigSet {
558    fn as_ref(&self) -> &libc::sigset_t {
559        &self.sigset
560    }
561}
562
563/// A signal handler.
564#[allow(unknown_lints)]
565#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
566pub enum SigHandler {
567    /// Default signal handling.
568    SigDfl,
569    /// Request that the signal be ignored.
570    SigIgn,
571    /// Use the given signal-catching function, which takes in the signal.
572    Handler(extern fn(libc::c_int)),
573    /// Use the given signal-catching function, which takes in the signal, information about how
574    /// the signal was generated, and a pointer to the threads `ucontext_t`.
575    #[cfg(not(target_os = "redox"))]
576    SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
577}
578
579/// Action to take on receipt of a signal. Corresponds to `sigaction`.
580#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
581pub struct SigAction {
582    sigaction: libc::sigaction
583}
584
585impl SigAction {
586    /// Creates a new action.
587    ///
588    /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
589    /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
590    /// the signal-catching function.
591    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
592        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
593            (*p).sa_sigaction = match handler {
594                SigHandler::SigDfl => libc::SIG_DFL,
595                SigHandler::SigIgn => libc::SIG_IGN,
596                SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
597                #[cfg(not(target_os = "redox"))]
598                SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
599            };
600        }
601
602        let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
603        unsafe {
604            let p = s.as_mut_ptr();
605            install_sig(p, handler);
606            (*p).sa_flags = match handler {
607                #[cfg(not(target_os = "redox"))]
608                SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
609                _ => (flags - SaFlags::SA_SIGINFO).bits(),
610            };
611            (*p).sa_mask = mask.sigset;
612
613            SigAction { sigaction: s.assume_init() }
614        }
615    }
616
617    /// Returns the flags set on the action.
618    pub fn flags(&self) -> SaFlags {
619        SaFlags::from_bits_truncate(self.sigaction.sa_flags)
620    }
621
622    /// Returns the set of signals that are blocked during execution of the action's
623    /// signal-catching function.
624    pub fn mask(&self) -> SigSet {
625        SigSet { sigset: self.sigaction.sa_mask }
626    }
627
628    /// Returns the action's handler.
629    pub fn handler(&self) -> SigHandler {
630        match self.sigaction.sa_sigaction {
631            libc::SIG_DFL => SigHandler::SigDfl,
632            libc::SIG_IGN => SigHandler::SigIgn,
633            #[cfg(not(target_os = "redox"))]
634            p if self.flags().contains(SaFlags::SA_SIGINFO) =>
635                SigHandler::SigAction(
636                // Safe for one of two reasons:
637                // * The SigHandler was created by SigHandler::new, in which
638                //   case the pointer is correct, or
639                // * The SigHandler was created by signal or sigaction, which
640                //   are unsafe functions, so the caller should've somehow
641                //   ensured that it is correctly initialized.
642                unsafe{
643                    *(&p as *const usize
644                         as *const extern fn(_, _, _))
645                }
646                as extern fn(_, _, _)),
647            p => SigHandler::Handler(
648                // Safe for one of two reasons:
649                // * The SigHandler was created by SigHandler::new, in which
650                //   case the pointer is correct, or
651                // * The SigHandler was created by signal or sigaction, which
652                //   are unsafe functions, so the caller should've somehow
653                //   ensured that it is correctly initialized.
654                unsafe{
655                    *(&p as *const usize
656                         as *const extern fn(libc::c_int))
657                }
658                as extern fn(libc::c_int)),
659        }
660    }
661}
662
663/// Changes the action taken by a process on receipt of a specific signal.
664///
665/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
666/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
667///
668/// # Safety
669///
670/// * Signal handlers may be called at any point during execution, which limits
671///   what is safe to do in the body of the signal-catching function. Be certain
672///   to only make syscalls that are explicitly marked safe for signal handlers
673///   and only share global data using atomics.
674///
675/// * There is also no guarantee that the old signal handler was installed
676///   correctly.  If it was installed by this crate, it will be.  But if it was
677///   installed by, for example, C code, then there is no guarantee its function
678///   pointer is valid.  In that case, this function effectively dereferences a
679///   raw pointer of unknown provenance.
680pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
681    let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
682
683    let res = libc::sigaction(signal as libc::c_int,
684                              &sigaction.sigaction as *const libc::sigaction,
685                              oldact.as_mut_ptr());
686
687    Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
688}
689
690/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
691///
692/// Installs `handler` for the given `signal`, returning the previous signal
693/// handler. `signal` should only be used following another call to `signal` or
694/// if the current handler is the default. The return value of `signal` is
695/// undefined after setting the handler with [`sigaction`][SigActionFn].
696///
697/// # Safety
698///
699/// If the pointer to the previous signal handler is invalid, undefined
700/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
701///
702/// # Examples
703///
704/// Ignore `SIGINT`:
705///
706/// ```no_run
707/// # use nix::sys::signal::{self, Signal, SigHandler};
708/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
709/// ```
710///
711/// Use a signal handler to set a flag variable:
712///
713/// ```no_run
714/// # #[macro_use] extern crate lazy_static;
715/// # use std::convert::TryFrom;
716/// # use std::sync::atomic::{AtomicBool, Ordering};
717/// # use nix::sys::signal::{self, Signal, SigHandler};
718/// lazy_static! {
719///    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
720/// }
721///
722/// extern fn handle_sigint(signal: libc::c_int) {
723///     let signal = Signal::try_from(signal).unwrap();
724///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
725/// }
726///
727/// fn main() {
728///     let handler = SigHandler::Handler(handle_sigint);
729///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
730/// }
731/// ```
732///
733/// # Errors
734///
735/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
736/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
737///
738/// `signal` also returns any error from `libc::signal`, such as when an attempt
739/// is made to catch a signal that cannot be caught or to ignore a signal that
740/// cannot be ignored.
741///
742/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
743/// [SigActionStruct]: struct.SigAction.html
744/// [sigactionFn]: fn.sigaction.html
745pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
746    let signal = signal as libc::c_int;
747    let res = match handler {
748        SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
749        SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
750        SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
751        #[cfg(not(target_os = "redox"))]
752        SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
753    };
754    Errno::result(res).map(|oldhandler| {
755        match oldhandler {
756            libc::SIG_DFL => SigHandler::SigDfl,
757            libc::SIG_IGN => SigHandler::SigIgn,
758            p => SigHandler::Handler(
759                *(&p as *const usize
760                     as *const extern fn(libc::c_int))
761                as extern fn(libc::c_int)),
762        }
763    })
764}
765
766fn do_pthread_sigmask(how: SigmaskHow,
767                       set: Option<&SigSet>,
768                       oldset: Option<*mut libc::sigset_t>) -> Result<()> {
769    if set.is_none() && oldset.is_none() {
770        return Ok(())
771    }
772
773    let res = unsafe {
774        // if set or oldset is None, pass in null pointers instead
775        libc::pthread_sigmask(how as libc::c_int,
776                             set.map_or_else(ptr::null::<libc::sigset_t>,
777                                             |s| &s.sigset as *const libc::sigset_t),
778                             oldset.unwrap_or(ptr::null_mut())
779                             )
780    };
781
782    Errno::result(res).map(drop)
783}
784
785/// Manages the signal mask (set of blocked signals) for the calling thread.
786///
787/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
788/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
789/// and no modification will take place.
790///
791/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
792///
793/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
794/// and then it will be updated with `set`.
795///
796/// If both `set` and `oldset` is None, this function is a no-op.
797///
798/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
799/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
800pub fn pthread_sigmask(how: SigmaskHow,
801                       set: Option<&SigSet>,
802                       oldset: Option<&mut SigSet>) -> Result<()>
803{
804    do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
805}
806
807/// Examine and change blocked signals.
808///
809/// For more informations see the [`sigprocmask` man
810/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
811pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
812    if set.is_none() && oldset.is_none() {
813        return Ok(())
814    }
815
816    let res = unsafe {
817        // if set or oldset is None, pass in null pointers instead
818        libc::sigprocmask(how as libc::c_int,
819                          set.map_or_else(ptr::null::<libc::sigset_t>,
820                                          |s| &s.sigset as *const libc::sigset_t),
821                          oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
822                                             |os| &mut os.sigset as *mut libc::sigset_t))
823    };
824
825    Errno::result(res).map(drop)
826}
827
828/// Send a signal to a process
829///
830/// # Arguments
831///
832/// * `pid` -    Specifies which processes should receive the signal.
833///   - If positive, specifies an individual process
834///   - If zero, the signal will be sent to all processes whose group
835///     ID is equal to the process group ID of the sender.  This is a
836///     variant of [`killpg`].
837///   - If `-1` and the process has super-user privileges, the signal
838///     is sent to all processes exclusing system processes.
839///   - If less than `-1`, the signal is sent to all processes whose
840///     process group ID is equal to the absolute value of `pid`.
841/// * `signal` - Signal to send. If `None`, error checking is performed
842///              but no signal is actually sent.
843///
844/// See Also
845/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
846pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
847    let res = unsafe { libc::kill(pid.into(),
848                                  match signal.into() {
849                                      Some(s) => s as libc::c_int,
850                                      None => 0,
851                                  }) };
852
853    Errno::result(res).map(drop)
854}
855
856/// Send a signal to a process group
857///
858/// # Arguments
859///
860/// * `pgrp` -   Process group to signal.  If less then or equal 1, the behavior
861///              is platform-specific.
862/// * `signal` - Signal to send. If `None`, `killpg` will only preform error
863///              checking and won't send any signal.
864///
865/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
866#[cfg(not(target_os = "fuchsia"))]
867pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
868    let res = unsafe { libc::killpg(pgrp.into(),
869                                  match signal.into() {
870                                      Some(s) => s as libc::c_int,
871                                      None => 0,
872                                  }) };
873
874    Errno::result(res).map(drop)
875}
876
877/// Send a signal to the current thread
878///
879/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
880pub fn raise(signal: Signal) -> Result<()> {
881    let res = unsafe { libc::raise(signal as libc::c_int) };
882
883    Errno::result(res).map(drop)
884}
885
886
887/// Identifies a thread for [`SigevNotify::SigevThreadId`]
888#[cfg(target_os = "freebsd")]
889pub type type_of_thread_id = libc::lwpid_t;
890/// Identifies a thread for [`SigevNotify::SigevThreadId`]
891#[cfg(target_os = "linux")]
892pub type type_of_thread_id = libc::pid_t;
893
894/// Specifies the notification method used by a [`SigEvent`]
895// sigval is actually a union of a int and a void*.  But it's never really used
896// as a pointer, because neither libc nor the kernel ever dereference it.  nix
897// therefore presents it as an intptr_t, which is how kevent uses it.
898#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
899#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
900pub enum SigevNotify {
901    /// No notification will be delivered
902    SigevNone,
903    /// Notify by delivering a signal to the process.
904    SigevSignal {
905        /// Signal to deliver
906        signal: Signal,
907        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
908        /// structure of the queued signal.
909        si_value: libc::intptr_t
910    },
911    // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
912    // expose a way to set the union members needed by SIGEV_THREAD.
913    /// Notify by delivering an event to a kqueue.
914    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
915    SigevKevent {
916        /// File descriptor of the kqueue to notify.
917        kq: RawFd,
918        /// Will be contained in the kevent's `udata` field.
919        udata: libc::intptr_t
920    },
921    /// Notify by delivering a signal to a thread.
922    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
923    SigevThreadId {
924        /// Signal to send
925        signal: Signal,
926        /// LWP ID of the thread to notify
927        thread_id: type_of_thread_id,
928        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
929        /// structure of the queued signal.
930        si_value: libc::intptr_t
931    },
932}
933
934#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
935mod sigevent {
936    use std::mem;
937    use std::ptr;
938    use super::SigevNotify;
939    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
940    use super::type_of_thread_id;
941
942    /// Used to request asynchronous notification of the completion of certain
943    /// events, such as POSIX AIO and timers.
944    #[repr(C)]
945    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
946    pub struct SigEvent {
947        sigevent: libc::sigevent
948    }
949
950    impl SigEvent {
951        /// **Note:** this constructor does not allow the user to set the
952        /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
953        /// at least those flags don't do anything useful.  That field is part of a
954        /// union that shares space with the more genuinely useful fields.
955        ///
956        /// **Note:** This constructor also doesn't allow the caller to set the
957        /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
958        /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
959        /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
960        /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
961        /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
962        /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
963        /// more genuinely useful `sigev_notify_thread_id`
964        // Allow invalid_value warning on Fuchsia only.
965        // See https://github.com/nix-rust/nix/issues/1441
966        #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
967        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
968            let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
969            sev.sigev_notify = match sigev_notify {
970                SigevNotify::SigevNone => libc::SIGEV_NONE,
971                SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
972                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
973                SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
974                #[cfg(target_os = "freebsd")]
975                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
976                #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
977                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
978                #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
979                SigevNotify::SigevThreadId{..} => 4  // No SIGEV_THREAD_ID defined
980            };
981            sev.sigev_signo = match sigev_notify {
982                SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
983                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
984                SigevNotify::SigevKevent{ kq, ..} => kq,
985                #[cfg(any(target_os = "linux", target_os = "freebsd"))]
986                SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
987                _ => 0
988            };
989            sev.sigev_value.sival_ptr = match sigev_notify {
990                SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
991                SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
992                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
993                SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
994                #[cfg(any(target_os = "freebsd", target_os = "linux"))]
995                SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
996            };
997            SigEvent::set_tid(&mut sev, &sigev_notify);
998            SigEvent{sigevent: sev}
999        }
1000
1001        #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1002        fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1003            sev.sigev_notify_thread_id = match *sigev_notify {
1004                SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1005                _ => 0 as type_of_thread_id
1006            };
1007        }
1008
1009        #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
1010        fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1011        }
1012
1013        /// Return a copy of the inner structure
1014        pub fn sigevent(&self) -> libc::sigevent {
1015            self.sigevent
1016        }
1017    }
1018
1019    impl<'a> From<&'a libc::sigevent> for SigEvent {
1020        fn from(sigevent: &libc::sigevent) -> Self {
1021            SigEvent{ sigevent: *sigevent }
1022        }
1023    }
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028    #[cfg(not(target_os = "redox"))]
1029    use std::thread;
1030    use super::*;
1031
1032    #[test]
1033    fn test_contains() {
1034        let mut mask = SigSet::empty();
1035        mask.add(SIGUSR1);
1036
1037        assert!(mask.contains(SIGUSR1));
1038        assert!(!mask.contains(SIGUSR2));
1039
1040        let all = SigSet::all();
1041        assert!(all.contains(SIGUSR1));
1042        assert!(all.contains(SIGUSR2));
1043    }
1044
1045    #[test]
1046    fn test_clear() {
1047        let mut set = SigSet::all();
1048        set.clear();
1049        for signal in Signal::iterator() {
1050            assert!(!set.contains(signal));
1051        }
1052    }
1053
1054    #[test]
1055    fn test_from_str_round_trips() {
1056        for signal in Signal::iterator() {
1057            assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1058            assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1059        }
1060    }
1061
1062    #[test]
1063    fn test_from_str_invalid_value() {
1064        let errval = Err(Errno::EINVAL);
1065        assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1066        assert_eq!("kill".parse::<Signal>(), errval);
1067        assert_eq!("9".parse::<Signal>(), errval);
1068    }
1069
1070    #[test]
1071    fn test_extend() {
1072        let mut one_signal = SigSet::empty();
1073        one_signal.add(SIGUSR1);
1074
1075        let mut two_signals = SigSet::empty();
1076        two_signals.add(SIGUSR2);
1077        two_signals.extend(&one_signal);
1078
1079        assert!(two_signals.contains(SIGUSR1));
1080        assert!(two_signals.contains(SIGUSR2));
1081    }
1082
1083    #[test]
1084    #[cfg(not(target_os = "redox"))]
1085    fn test_thread_signal_set_mask() {
1086        thread::spawn(|| {
1087            let prev_mask = SigSet::thread_get_mask()
1088                .expect("Failed to get existing signal mask!");
1089
1090            let mut test_mask = prev_mask;
1091            test_mask.add(SIGUSR1);
1092
1093            assert!(test_mask.thread_set_mask().is_ok());
1094            let new_mask = SigSet::thread_get_mask()
1095                .expect("Failed to get new mask!");
1096
1097            assert!(new_mask.contains(SIGUSR1));
1098            assert!(!new_mask.contains(SIGUSR2));
1099
1100            prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
1101        }).join().unwrap();
1102    }
1103
1104    #[test]
1105    #[cfg(not(target_os = "redox"))]
1106    fn test_thread_signal_block() {
1107        thread::spawn(|| {
1108            let mut mask = SigSet::empty();
1109            mask.add(SIGUSR1);
1110
1111            assert!(mask.thread_block().is_ok());
1112
1113            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1114        }).join().unwrap();
1115    }
1116
1117    #[test]
1118    #[cfg(not(target_os = "redox"))]
1119    fn test_thread_signal_unblock() {
1120        thread::spawn(|| {
1121            let mut mask = SigSet::empty();
1122            mask.add(SIGUSR1);
1123
1124            assert!(mask.thread_unblock().is_ok());
1125
1126            assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1127        }).join().unwrap();
1128    }
1129
1130    #[test]
1131    #[cfg(not(target_os = "redox"))]
1132    fn test_thread_signal_swap() {
1133        thread::spawn(|| {
1134            let mut mask = SigSet::empty();
1135            mask.add(SIGUSR1);
1136            mask.thread_block().unwrap();
1137
1138            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1139
1140            let mut mask2 = SigSet::empty();
1141            mask2.add(SIGUSR2);
1142
1143            let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
1144                .unwrap();
1145
1146            assert!(oldmask.contains(SIGUSR1));
1147            assert!(!oldmask.contains(SIGUSR2));
1148
1149            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1150        }).join().unwrap();
1151    }
1152
1153    #[test]
1154    #[cfg(not(target_os = "redox"))]
1155    fn test_sigaction() {
1156        thread::spawn(|| {
1157            extern fn test_sigaction_handler(_: libc::c_int) {}
1158            extern fn test_sigaction_action(_: libc::c_int,
1159                _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
1160
1161            let handler_sig = SigHandler::Handler(test_sigaction_handler);
1162
1163            let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
1164                        SaFlags::SA_SIGINFO;
1165
1166            let mut mask = SigSet::empty();
1167            mask.add(SIGUSR1);
1168
1169            let action_sig = SigAction::new(handler_sig, flags, mask);
1170
1171            assert_eq!(action_sig.flags(),
1172                       SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
1173            assert_eq!(action_sig.handler(), handler_sig);
1174
1175            mask = action_sig.mask();
1176            assert!(mask.contains(SIGUSR1));
1177            assert!(!mask.contains(SIGUSR2));
1178
1179            let handler_act = SigHandler::SigAction(test_sigaction_action);
1180            let action_act = SigAction::new(handler_act, flags, mask);
1181            assert_eq!(action_act.handler(), handler_act);
1182
1183            let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1184            assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1185
1186            let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1187            assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1188        }).join().unwrap();
1189    }
1190
1191    #[test]
1192    #[cfg(not(target_os = "redox"))]
1193    fn test_sigwait() {
1194        thread::spawn(|| {
1195            let mut mask = SigSet::empty();
1196            mask.add(SIGUSR1);
1197            mask.add(SIGUSR2);
1198            mask.thread_block().unwrap();
1199
1200            raise(SIGUSR1).unwrap();
1201            assert_eq!(mask.wait().unwrap(), SIGUSR1);
1202        }).join().unwrap();
1203    }
1204}