1 // Portions of this file are Copyright 2014 The Rust Project Developers.
2 // See http://rust-lang.org/COPYRIGHT.
3 
4 ///! Operating system signals.
5 
6 use libc;
7 use {Error, Result};
8 use errno::Errno;
9 use std::convert::TryFrom;
10 use std::mem;
11 use std::fmt;
12 use std::str::FromStr;
13 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
14 use std::os::unix::io::RawFd;
15 use std::ptr;
16 
17 #[cfg(not(target_os = "openbsd"))]
18 pub use self::sigevent::*;
19 
20 libc_enum!{
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     pub enum Signal {
27         SIGHUP,
28         SIGINT,
29         SIGQUIT,
30         SIGILL,
31         SIGTRAP,
32         SIGABRT,
33         SIGBUS,
34         SIGFPE,
35         SIGKILL,
36         SIGUSR1,
37         SIGSEGV,
38         SIGUSR2,
39         SIGPIPE,
40         SIGALRM,
41         SIGTERM,
42         #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
43                   not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
44         SIGSTKFLT,
45         SIGCHLD,
46         SIGCONT,
47         SIGSTOP,
48         SIGTSTP,
49         SIGTTIN,
50         SIGTTOU,
51         SIGURG,
52         SIGXCPU,
53         SIGXFSZ,
54         SIGVTALRM,
55         SIGPROF,
56         SIGWINCH,
57         SIGIO,
58         #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
59         SIGPWR,
60         SIGSYS,
61         #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
62         SIGEMT,
63         #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
64         SIGINFO,
65     }
66 }
67 
68 impl FromStr for Signal {
69     type Err = Error;
from_str(s: &str) -> Result<Signal>70     fn from_str(s: &str) -> Result<Signal> {
71         Ok(match s {
72             "SIGHUP" => Signal::SIGHUP,
73             "SIGINT" => Signal::SIGINT,
74             "SIGQUIT" => Signal::SIGQUIT,
75             "SIGILL" => Signal::SIGILL,
76             "SIGTRAP" => Signal::SIGTRAP,
77             "SIGABRT" => Signal::SIGABRT,
78             "SIGBUS" => Signal::SIGBUS,
79             "SIGFPE" => Signal::SIGFPE,
80             "SIGKILL" => Signal::SIGKILL,
81             "SIGUSR1" => Signal::SIGUSR1,
82             "SIGSEGV" => Signal::SIGSEGV,
83             "SIGUSR2" => Signal::SIGUSR2,
84             "SIGPIPE" => Signal::SIGPIPE,
85             "SIGALRM" => Signal::SIGALRM,
86             "SIGTERM" => Signal::SIGTERM,
87             #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
88                       not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
89             "SIGSTKFLT" => Signal::SIGSTKFLT,
90             "SIGCHLD" => Signal::SIGCHLD,
91             "SIGCONT" => Signal::SIGCONT,
92             "SIGSTOP" => Signal::SIGSTOP,
93             "SIGTSTP" => Signal::SIGTSTP,
94             "SIGTTIN" => Signal::SIGTTIN,
95             "SIGTTOU" => Signal::SIGTTOU,
96             "SIGURG" => Signal::SIGURG,
97             "SIGXCPU" => Signal::SIGXCPU,
98             "SIGXFSZ" => Signal::SIGXFSZ,
99             "SIGVTALRM" => Signal::SIGVTALRM,
100             "SIGPROF" => Signal::SIGPROF,
101             "SIGWINCH" => Signal::SIGWINCH,
102             "SIGIO" => Signal::SIGIO,
103             #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
104             "SIGPWR" => Signal::SIGPWR,
105             "SIGSYS" => Signal::SIGSYS,
106             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
107             "SIGEMT" => Signal::SIGEMT,
108             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
109             "SIGINFO" => Signal::SIGINFO,
110             _ => return Err(Error::invalid_argument()),
111         })
112     }
113 }
114 
115 impl Signal {
116     /// Returns name of signal.
117     ///
118     /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
119     /// with difference that returned string is `'static`
120     /// and not bound to `self`'s lifetime.
as_str(self) -> &'static str121     pub fn as_str(self) -> &'static str {
122         match self {
123             Signal::SIGHUP => "SIGHUP",
124             Signal::SIGINT => "SIGINT",
125             Signal::SIGQUIT => "SIGQUIT",
126             Signal::SIGILL => "SIGILL",
127             Signal::SIGTRAP => "SIGTRAP",
128             Signal::SIGABRT => "SIGABRT",
129             Signal::SIGBUS => "SIGBUS",
130             Signal::SIGFPE => "SIGFPE",
131             Signal::SIGKILL => "SIGKILL",
132             Signal::SIGUSR1 => "SIGUSR1",
133             Signal::SIGSEGV => "SIGSEGV",
134             Signal::SIGUSR2 => "SIGUSR2",
135             Signal::SIGPIPE => "SIGPIPE",
136             Signal::SIGALRM => "SIGALRM",
137             Signal::SIGTERM => "SIGTERM",
138             #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
139                       not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
140             Signal::SIGSTKFLT => "SIGSTKFLT",
141             Signal::SIGCHLD => "SIGCHLD",
142             Signal::SIGCONT => "SIGCONT",
143             Signal::SIGSTOP => "SIGSTOP",
144             Signal::SIGTSTP => "SIGTSTP",
145             Signal::SIGTTIN => "SIGTTIN",
146             Signal::SIGTTOU => "SIGTTOU",
147             Signal::SIGURG => "SIGURG",
148             Signal::SIGXCPU => "SIGXCPU",
149             Signal::SIGXFSZ => "SIGXFSZ",
150             Signal::SIGVTALRM => "SIGVTALRM",
151             Signal::SIGPROF => "SIGPROF",
152             Signal::SIGWINCH => "SIGWINCH",
153             Signal::SIGIO => "SIGIO",
154             #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
155             Signal::SIGPWR => "SIGPWR",
156             Signal::SIGSYS => "SIGSYS",
157             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
158             Signal::SIGEMT => "SIGEMT",
159             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
160             Signal::SIGINFO => "SIGINFO",
161         }
162     }
163 }
164 
165 impl AsRef<str> for Signal {
as_ref(&self) -> &str166     fn as_ref(&self) -> &str {
167         self.as_str()
168     }
169 }
170 
171 impl fmt::Display for Signal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result172     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173         f.write_str(self.as_ref())
174     }
175 }
176 
177 pub use self::Signal::*;
178 
179 #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
180 const SIGNALS: [Signal; 31] = [
181     SIGHUP,
182     SIGINT,
183     SIGQUIT,
184     SIGILL,
185     SIGTRAP,
186     SIGABRT,
187     SIGBUS,
188     SIGFPE,
189     SIGKILL,
190     SIGUSR1,
191     SIGSEGV,
192     SIGUSR2,
193     SIGPIPE,
194     SIGALRM,
195     SIGTERM,
196     SIGSTKFLT,
197     SIGCHLD,
198     SIGCONT,
199     SIGSTOP,
200     SIGTSTP,
201     SIGTTIN,
202     SIGTTOU,
203     SIGURG,
204     SIGXCPU,
205     SIGXFSZ,
206     SIGVTALRM,
207     SIGPROF,
208     SIGWINCH,
209     SIGIO,
210     SIGPWR,
211     SIGSYS];
212 #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
213 const SIGNALS: [Signal; 30] = [
214     SIGHUP,
215     SIGINT,
216     SIGQUIT,
217     SIGILL,
218     SIGTRAP,
219     SIGABRT,
220     SIGBUS,
221     SIGFPE,
222     SIGKILL,
223     SIGUSR1,
224     SIGSEGV,
225     SIGUSR2,
226     SIGPIPE,
227     SIGALRM,
228     SIGTERM,
229     SIGCHLD,
230     SIGCONT,
231     SIGSTOP,
232     SIGTSTP,
233     SIGTTIN,
234     SIGTTOU,
235     SIGURG,
236     SIGXCPU,
237     SIGXFSZ,
238     SIGVTALRM,
239     SIGPROF,
240     SIGWINCH,
241     SIGIO,
242     SIGPWR,
243     SIGSYS];
244 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
245 const SIGNALS: [Signal; 31] = [
246     SIGHUP,
247     SIGINT,
248     SIGQUIT,
249     SIGILL,
250     SIGTRAP,
251     SIGABRT,
252     SIGBUS,
253     SIGFPE,
254     SIGKILL,
255     SIGUSR1,
256     SIGSEGV,
257     SIGUSR2,
258     SIGPIPE,
259     SIGALRM,
260     SIGTERM,
261     SIGCHLD,
262     SIGCONT,
263     SIGSTOP,
264     SIGTSTP,
265     SIGTTIN,
266     SIGTTOU,
267     SIGURG,
268     SIGXCPU,
269     SIGXFSZ,
270     SIGVTALRM,
271     SIGPROF,
272     SIGWINCH,
273     SIGIO,
274     SIGSYS,
275     SIGEMT,
276     SIGINFO];
277 
278 pub const NSIG: libc::c_int = 32;
279 
280 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
281 pub struct SignalIterator {
282     next: usize,
283 }
284 
285 impl Iterator for SignalIterator {
286     type Item = Signal;
287 
next(&mut self) -> Option<Signal>288     fn next(&mut self) -> Option<Signal> {
289         if self.next < SIGNALS.len() {
290             let next_signal = SIGNALS[self.next];
291             self.next += 1;
292             Some(next_signal)
293         } else {
294             None
295         }
296     }
297 }
298 
299 impl Signal {
iterator() -> SignalIterator300     pub fn iterator() -> SignalIterator {
301         SignalIterator{next: 0}
302     }
303 }
304 
305 impl TryFrom<libc::c_int> for Signal {
306     type Error = Error;
307 
try_from(signum: libc::c_int) -> Result<Signal>308     fn try_from(signum: libc::c_int) -> Result<Signal> {
309         if 0 < signum && signum < NSIG {
310             Ok(unsafe { mem::transmute(signum) })
311         } else {
312             Err(Error::invalid_argument())
313         }
314     }
315 }
316 
317 pub const SIGIOT : Signal = SIGABRT;
318 pub const SIGPOLL : Signal = SIGIO;
319 pub const SIGUNUSED : Signal = SIGSYS;
320 
321 libc_bitflags!{
322     pub struct SaFlags: libc::c_int {
323         SA_NOCLDSTOP;
324         SA_NOCLDWAIT;
325         SA_NODEFER;
326         SA_ONSTACK;
327         SA_RESETHAND;
328         SA_RESTART;
329         SA_SIGINFO;
330     }
331 }
332 
333 libc_enum! {
334     #[repr(i32)]
335     pub enum SigmaskHow {
336         SIG_BLOCK,
337         SIG_UNBLOCK,
338         SIG_SETMASK,
339     }
340 }
341 
342 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
343 pub struct SigSet {
344     sigset: libc::sigset_t
345 }
346 
347 
348 impl SigSet {
all() -> SigSet349     pub fn all() -> SigSet {
350         let mut sigset = mem::MaybeUninit::uninit();
351         let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
352 
353         unsafe{ SigSet { sigset: sigset.assume_init() } }
354     }
355 
empty() -> SigSet356     pub fn empty() -> SigSet {
357         let mut sigset = mem::MaybeUninit::uninit();
358         let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
359 
360         unsafe{ SigSet { sigset: sigset.assume_init() } }
361     }
362 
add(&mut self, signal: Signal)363     pub fn add(&mut self, signal: Signal) {
364         unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
365     }
366 
clear(&mut self)367     pub fn clear(&mut self) {
368         unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
369     }
370 
remove(&mut self, signal: Signal)371     pub fn remove(&mut self, signal: Signal) {
372         unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
373     }
374 
contains(&self, signal: Signal) -> bool375     pub fn contains(&self, signal: Signal) -> bool {
376         let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
377 
378         match res {
379             1 => true,
380             0 => false,
381             _ => unreachable!("unexpected value from sigismember"),
382         }
383     }
384 
extend(&mut self, other: &SigSet)385     pub fn extend(&mut self, other: &SigSet) {
386         for signal in Signal::iterator() {
387             if other.contains(signal) {
388                 self.add(signal);
389             }
390         }
391     }
392 
393     /// Gets the currently blocked (masked) set of signals for the calling thread.
thread_get_mask() -> Result<SigSet>394     pub fn thread_get_mask() -> Result<SigSet> {
395         let mut oldmask = mem::MaybeUninit::uninit();
396         do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
397         Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
398     }
399 
400     /// Sets the set of signals as the signal mask for the calling thread.
thread_set_mask(&self) -> Result<()>401     pub fn thread_set_mask(&self) -> Result<()> {
402         pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
403     }
404 
405     /// Adds the set of signals to the signal mask for the calling thread.
thread_block(&self) -> Result<()>406     pub fn thread_block(&self) -> Result<()> {
407         pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
408     }
409 
410     /// Removes the set of signals from the signal mask for the calling thread.
thread_unblock(&self) -> Result<()>411     pub fn thread_unblock(&self) -> Result<()> {
412         pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
413     }
414 
415     /// Sets the set of signals as the signal mask, and returns the old mask.
thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet>416     pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
417         let mut oldmask = mem::MaybeUninit::uninit();
418         do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
419         Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
420     }
421 
422     /// Suspends execution of the calling thread until one of the signals in the
423     /// signal mask becomes pending, and returns the accepted signal.
wait(&self) -> Result<Signal>424     pub fn wait(&self) -> Result<Signal> {
425         let mut signum = mem::MaybeUninit::uninit();
426         let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
427 
428         Errno::result(res).map(|_| unsafe {
429             Signal::try_from(signum.assume_init()).unwrap()
430         })
431     }
432 }
433 
434 impl AsRef<libc::sigset_t> for SigSet {
as_ref(&self) -> &libc::sigset_t435     fn as_ref(&self) -> &libc::sigset_t {
436         &self.sigset
437     }
438 }
439 
440 /// A signal handler.
441 #[allow(unknown_lints)]
442 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
443 pub enum SigHandler {
444     /// Default signal handling.
445     SigDfl,
446     /// Request that the signal be ignored.
447     SigIgn,
448     /// Use the given signal-catching function, which takes in the signal.
449     Handler(extern fn(libc::c_int)),
450     /// Use the given signal-catching function, which takes in the signal, information about how
451     /// the signal was generated, and a pointer to the threads `ucontext_t`.
452     SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
453 }
454 
455 /// Action to take on receipt of a signal. Corresponds to `sigaction`.
456 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
457 pub struct SigAction {
458     sigaction: libc::sigaction
459 }
460 
461 impl SigAction {
462     /// Creates a new action.
463     ///
464     /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
465     /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
466     /// the signal-catching function.
new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction467     pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
468         let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
469         unsafe {
470             let p = s.as_mut_ptr();
471             (*p).sa_sigaction = match handler {
472                 SigHandler::SigDfl => libc::SIG_DFL,
473                 SigHandler::SigIgn => libc::SIG_IGN,
474                 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
475                 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
476             };
477             (*p).sa_flags = match handler {
478                 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
479                 _ => (flags - SaFlags::SA_SIGINFO).bits(),
480             };
481             (*p).sa_mask = mask.sigset;
482 
483             SigAction { sigaction: s.assume_init() }
484         }
485     }
486 
487     /// Returns the flags set on the action.
flags(&self) -> SaFlags488     pub fn flags(&self) -> SaFlags {
489         SaFlags::from_bits_truncate(self.sigaction.sa_flags)
490     }
491 
492     /// Returns the set of signals that are blocked during execution of the action's
493     /// signal-catching function.
mask(&self) -> SigSet494     pub fn mask(&self) -> SigSet {
495         SigSet { sigset: self.sigaction.sa_mask }
496     }
497 
498     /// Returns the action's handler.
handler(&self) -> SigHandler499     pub fn handler(&self) -> SigHandler {
500         match self.sigaction.sa_sigaction {
501             libc::SIG_DFL => SigHandler::SigDfl,
502             libc::SIG_IGN => SigHandler::SigIgn,
503             f if self.flags().contains(SaFlags::SA_SIGINFO) =>
504                 SigHandler::SigAction( unsafe { mem::transmute(f) } ),
505             f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
506         }
507     }
508 }
509 
510 /// Changes the action taken by a process on receipt of a specific signal.
511 ///
512 /// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
513 /// action for the given signal. If `sigaction` fails, no new signal handler is installed.
514 ///
515 /// # Safety
516 ///
517 /// Signal handlers may be called at any point during execution, which limits what is safe to do in
518 /// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
519 /// marked safe for signal handlers and only share global data using atomics.
sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction>520 pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
521     let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
522 
523     let res = libc::sigaction(signal as libc::c_int,
524                               &sigaction.sigaction as *const libc::sigaction,
525                               oldact.as_mut_ptr());
526 
527     Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
528 }
529 
530 /// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
531 ///
532 /// Installs `handler` for the given `signal`, returning the previous signal
533 /// handler. `signal` should only be used following another call to `signal` or
534 /// if the current handler is the default. The return value of `signal` is
535 /// undefined after setting the handler with [`sigaction`][SigActionFn].
536 ///
537 /// # Safety
538 ///
539 /// If the pointer to the previous signal handler is invalid, undefined
540 /// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
541 ///
542 /// # Examples
543 ///
544 /// Ignore `SIGINT`:
545 ///
546 /// ```no_run
547 /// # use nix::sys::signal::{self, Signal, SigHandler};
548 /// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
549 /// ```
550 ///
551 /// Use a signal handler to set a flag variable:
552 ///
553 /// ```no_run
554 /// # #[macro_use] extern crate lazy_static;
555 /// # extern crate libc;
556 /// # extern crate nix;
557 /// # use std::convert::TryFrom;
558 /// # use std::sync::atomic::{AtomicBool, Ordering};
559 /// # use nix::sys::signal::{self, Signal, SigHandler};
560 /// lazy_static! {
561 ///    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
562 /// }
563 ///
564 /// extern fn handle_sigint(signal: libc::c_int) {
565 ///     let signal = Signal::try_from(signal).unwrap();
566 ///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
567 /// }
568 ///
569 /// fn main() {
570 ///     let handler = SigHandler::Handler(handle_sigint);
571 ///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
572 /// }
573 /// ```
574 ///
575 /// # Errors
576 ///
577 /// Returns [`Error::UnsupportedOperation`] if `handler` is
578 /// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
579 ///
580 /// `signal` also returns any error from `libc::signal`, such as when an attempt
581 /// is made to catch a signal that cannot be caught or to ignore a signal that
582 /// cannot be ignored.
583 ///
584 /// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
585 /// [SigActionStruct]: struct.SigAction.html
586 /// [sigactionFn]: fn.sigaction.html
signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>587 pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
588     let signal = signal as libc::c_int;
589     let res = match handler {
590         SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
591         SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
592         SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
593         SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
594     };
595     Errno::result(res).map(|oldhandler| {
596         match oldhandler {
597             libc::SIG_DFL => SigHandler::SigDfl,
598             libc::SIG_IGN => SigHandler::SigIgn,
599             f => SigHandler::Handler(mem::transmute(f)),
600         }
601     })
602 }
603 
do_pthread_sigmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<*mut libc::sigset_t>) -> Result<()>604 fn do_pthread_sigmask(how: SigmaskHow,
605                        set: Option<&SigSet>,
606                        oldset: Option<*mut libc::sigset_t>) -> Result<()> {
607     if set.is_none() && oldset.is_none() {
608         return Ok(())
609     }
610 
611     let res = unsafe {
612         // if set or oldset is None, pass in null pointers instead
613         libc::pthread_sigmask(how as libc::c_int,
614                              set.map_or_else(ptr::null::<libc::sigset_t>,
615                                              |s| &s.sigset as *const libc::sigset_t),
616                              oldset.unwrap_or(ptr::null_mut())
617                              )
618     };
619 
620     Errno::result(res).map(drop)
621 }
622 
623 /// Manages the signal mask (set of blocked signals) for the calling thread.
624 ///
625 /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
626 /// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
627 /// and no modification will take place.
628 ///
629 /// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
630 ///
631 /// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
632 /// and then it will be updated with `set`.
633 ///
634 /// If both `set` and `oldset` is None, this function is a no-op.
635 ///
636 /// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
637 /// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
pthread_sigmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()>638 pub fn pthread_sigmask(how: SigmaskHow,
639                        set: Option<&SigSet>,
640                        oldset: Option<&mut SigSet>) -> Result<()>
641 {
642     do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
643 }
644 
645 /// Examine and change blocked signals.
646 ///
647 /// For more informations see the [`sigprocmask` man
648 /// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()>649 pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
650     if set.is_none() && oldset.is_none() {
651         return Ok(())
652     }
653 
654     let res = unsafe {
655         // if set or oldset is None, pass in null pointers instead
656         libc::sigprocmask(how as libc::c_int,
657                           set.map_or_else(ptr::null::<libc::sigset_t>,
658                                           |s| &s.sigset as *const libc::sigset_t),
659                           oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
660                                              |os| &mut os.sigset as *mut libc::sigset_t))
661     };
662 
663     Errno::result(res).map(drop)
664 }
665 
kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()>666 pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
667     let res = unsafe { libc::kill(pid.into(),
668                                   match signal.into() {
669                                       Some(s) => s as libc::c_int,
670                                       None => 0,
671                                   }) };
672 
673     Errno::result(res).map(drop)
674 }
675 
676 /// Send a signal to a process group [(see
677 /// killpg(3))](http://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
678 ///
679 /// If `pgrp` less then or equal 1, the behavior is platform-specific.
680 /// If `signal` is `None`, `killpg` will only preform error checking and won't
681 /// send any signal.
killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()>682 pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()> {
683     let res = unsafe { libc::killpg(pgrp.into(),
684                                   match signal.into() {
685                                       Some(s) => s as libc::c_int,
686                                       None => 0,
687                                   }) };
688 
689     Errno::result(res).map(drop)
690 }
691 
raise(signal: Signal) -> Result<()>692 pub fn raise(signal: Signal) -> Result<()> {
693     let res = unsafe { libc::raise(signal as libc::c_int) };
694 
695     Errno::result(res).map(drop)
696 }
697 
698 
699 #[cfg(target_os = "freebsd")]
700 pub type type_of_thread_id = libc::lwpid_t;
701 #[cfg(target_os = "linux")]
702 pub type type_of_thread_id = libc::pid_t;
703 
704 /// Used to request asynchronous notification of certain events, for example,
705 /// with POSIX AIO, POSIX message queues, and POSIX timers.
706 // sigval is actually a union of a int and a void*.  But it's never really used
707 // as a pointer, because neither libc nor the kernel ever dereference it.  nix
708 // therefore presents it as an intptr_t, which is how kevent uses it.
709 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
710 pub enum SigevNotify {
711     /// No notification will be delivered
712     SigevNone,
713     /// The signal given by `signal` will be delivered to the process.  The
714     /// value in `si_value` will be present in the `si_value` field of the
715     /// `siginfo_t` structure of the queued signal.
716     SigevSignal { signal: Signal, si_value: libc::intptr_t },
717     // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
718     // expose a way to set the union members needed by SIGEV_THREAD.
719     /// A new `kevent` is posted to the kqueue `kq`.  The `kevent`'s `udata`
720     /// field will contain the value in `udata`.
721     #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
722     SigevKevent { kq: RawFd, udata: libc::intptr_t },
723     /// The signal `signal` is queued to the thread whose LWP ID is given in
724     /// `thread_id`.  The value stored in `si_value` will be present in the
725     /// `si_value` of the `siginfo_t` structure of the queued signal.
726     #[cfg(any(target_os = "freebsd", target_os = "linux"))]
727     SigevThreadId { signal: Signal, thread_id: type_of_thread_id,
728                     si_value: libc::intptr_t },
729 }
730 
731 #[cfg(not(target_os = "openbsd"))]
732 mod sigevent {
733     use libc;
734     use std::mem;
735     use std::ptr;
736     use super::SigevNotify;
737     #[cfg(any(target_os = "freebsd", target_os = "linux"))]
738     use super::type_of_thread_id;
739 
740     /// Used to request asynchronous notification of the completion of certain
741     /// events, such as POSIX AIO and timers.
742     #[repr(C)]
743     #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
744     pub struct SigEvent {
745         sigevent: libc::sigevent
746     }
747 
748     impl SigEvent {
749         /// **Note:** this constructor does not allow the user to set the
750         /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
751         /// at least those flags don't do anything useful.  That field is part of a
752         /// union that shares space with the more genuinely useful fields.
753         ///
754         /// **Note:** This constructor also doesn't allow the caller to set the
755         /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
756         /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
757         /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
758         /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
759         /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
760         /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
761         /// more genuinely useful `sigev_notify_thread_id`
new(sigev_notify: SigevNotify) -> SigEvent762         pub fn new(sigev_notify: SigevNotify) -> SigEvent {
763             let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
764             sev.sigev_notify = match sigev_notify {
765                 SigevNotify::SigevNone => libc::SIGEV_NONE,
766                 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
767                 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
768                 SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
769                 #[cfg(target_os = "freebsd")]
770                 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
771                 #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
772                 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
773                 #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
774                 SigevNotify::SigevThreadId{..} => 4  // No SIGEV_THREAD_ID defined
775             };
776             sev.sigev_signo = match sigev_notify {
777                 SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
778                 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
779                 SigevNotify::SigevKevent{ kq, ..} => kq,
780                 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
781                 SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
782                 _ => 0
783             };
784             sev.sigev_value.sival_ptr = match sigev_notify {
785                 SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
786                 SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
787                 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
788                 SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
789                 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
790                 SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
791             };
792             SigEvent::set_tid(&mut sev, &sigev_notify);
793             SigEvent{sigevent: sev}
794         }
795 
796         #[cfg(any(target_os = "freebsd", target_os = "linux"))]
set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify)797         fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
798             sev.sigev_notify_thread_id = match *sigev_notify {
799                 SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
800                 _ => 0 as type_of_thread_id
801             };
802         }
803 
804         #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify)805         fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
806         }
807 
sigevent(&self) -> libc::sigevent808         pub fn sigevent(&self) -> libc::sigevent {
809             self.sigevent
810         }
811     }
812 
813     impl<'a> From<&'a libc::sigevent> for SigEvent {
from(sigevent: &libc::sigevent) -> Self814         fn from(sigevent: &libc::sigevent) -> Self {
815             SigEvent{ sigevent: *sigevent }
816         }
817     }
818 }
819 
820 #[cfg(test)]
821 mod tests {
822     use std::thread;
823     use super::*;
824 
825     #[test]
test_contains()826     fn test_contains() {
827         let mut mask = SigSet::empty();
828         mask.add(SIGUSR1);
829 
830         assert!(mask.contains(SIGUSR1));
831         assert!(!mask.contains(SIGUSR2));
832 
833         let all = SigSet::all();
834         assert!(all.contains(SIGUSR1));
835         assert!(all.contains(SIGUSR2));
836     }
837 
838     #[test]
test_clear()839     fn test_clear() {
840         let mut set = SigSet::all();
841         set.clear();
842         for signal in Signal::iterator() {
843             assert!(!set.contains(signal));
844         }
845     }
846 
847     #[test]
test_from_str_round_trips()848     fn test_from_str_round_trips() {
849         for signal in Signal::iterator() {
850             assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
851             assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
852         }
853     }
854 
855     #[test]
test_from_str_invalid_value()856     fn test_from_str_invalid_value() {
857         let errval = Err(Error::Sys(Errno::EINVAL));
858         assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
859         assert_eq!("kill".parse::<Signal>(), errval);
860         assert_eq!("9".parse::<Signal>(), errval);
861     }
862 
863     #[test]
test_extend()864     fn test_extend() {
865         let mut one_signal = SigSet::empty();
866         one_signal.add(SIGUSR1);
867 
868         let mut two_signals = SigSet::empty();
869         two_signals.add(SIGUSR2);
870         two_signals.extend(&one_signal);
871 
872         assert!(two_signals.contains(SIGUSR1));
873         assert!(two_signals.contains(SIGUSR2));
874     }
875 
876     #[test]
test_thread_signal_set_mask()877     fn test_thread_signal_set_mask() {
878         thread::spawn(|| {
879             let prev_mask = SigSet::thread_get_mask()
880                 .expect("Failed to get existing signal mask!");
881 
882             let mut test_mask = prev_mask;
883             test_mask.add(SIGUSR1);
884 
885             assert!(test_mask.thread_set_mask().is_ok());
886             let new_mask = SigSet::thread_get_mask()
887                 .expect("Failed to get new mask!");
888 
889             assert!(new_mask.contains(SIGUSR1));
890             assert!(!new_mask.contains(SIGUSR2));
891 
892             prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
893         }).join().unwrap();
894     }
895 
896     #[test]
test_thread_signal_block()897     fn test_thread_signal_block() {
898         thread::spawn(|| {
899             let mut mask = SigSet::empty();
900             mask.add(SIGUSR1);
901 
902             assert!(mask.thread_block().is_ok());
903 
904             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
905         }).join().unwrap();
906     }
907 
908     #[test]
test_thread_signal_unblock()909     fn test_thread_signal_unblock() {
910         thread::spawn(|| {
911             let mut mask = SigSet::empty();
912             mask.add(SIGUSR1);
913 
914             assert!(mask.thread_unblock().is_ok());
915 
916             assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
917         }).join().unwrap();
918     }
919 
920     #[test]
test_thread_signal_swap()921     fn test_thread_signal_swap() {
922         thread::spawn(|| {
923             let mut mask = SigSet::empty();
924             mask.add(SIGUSR1);
925             mask.thread_block().unwrap();
926 
927             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
928 
929             let mut mask2 = SigSet::empty();
930             mask2.add(SIGUSR2);
931 
932             let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
933                 .unwrap();
934 
935             assert!(oldmask.contains(SIGUSR1));
936             assert!(!oldmask.contains(SIGUSR2));
937 
938             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
939         }).join().unwrap();
940     }
941 
942     #[test]
test_sigaction()943     fn test_sigaction() {
944         use libc;
945         thread::spawn(|| {
946             extern fn test_sigaction_handler(_: libc::c_int) {}
947             extern fn test_sigaction_action(_: libc::c_int,
948                 _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
949 
950             let handler_sig = SigHandler::Handler(test_sigaction_handler);
951 
952             let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
953                         SaFlags::SA_SIGINFO;
954 
955             let mut mask = SigSet::empty();
956             mask.add(SIGUSR1);
957 
958             let action_sig = SigAction::new(handler_sig, flags, mask);
959 
960             assert_eq!(action_sig.flags(),
961                        SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
962             assert_eq!(action_sig.handler(), handler_sig);
963 
964             mask = action_sig.mask();
965             assert!(mask.contains(SIGUSR1));
966             assert!(!mask.contains(SIGUSR2));
967 
968             let handler_act = SigHandler::SigAction(test_sigaction_action);
969             let action_act = SigAction::new(handler_act, flags, mask);
970             assert_eq!(action_act.handler(), handler_act);
971 
972             let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
973             assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
974 
975             let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
976             assert_eq!(action_ign.handler(), SigHandler::SigIgn);
977         }).join().unwrap();
978     }
979 
980     #[test]
test_sigwait()981     fn test_sigwait() {
982         thread::spawn(|| {
983             let mut mask = SigSet::empty();
984             mask.add(SIGUSR1);
985             mask.add(SIGUSR2);
986             mask.thread_block().unwrap();
987 
988             raise(SIGUSR1).unwrap();
989             assert_eq!(mask.wait().unwrap(), SIGUSR1);
990         }).join().unwrap();
991     }
992 }
993