1/* POSIX compatible signal blocking.
2   Copyright (C) 2008-2012 Free Software Foundation, Inc.
3   Written by Eric Blake <ebb9@byu.net>, 2008.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#include <config.h>
19
20/* Specification.  */
21#include <signal.h>
22
23#include <errno.h>
24#include <stdint.h>
25#include <stdlib.h>
26
27/* This implementation of sigaction is tailored to native Windows behavior:
28   signal() has SysV semantics (ie. the handler is uninstalled before
29   it is invoked).  This is an inherent data race if an asynchronous
30   signal is sent twice in a row before we can reinstall our handler,
31   but there's nothing we can do about it.  Meanwhile, sigprocmask()
32   is not present, and while we can use the gnulib replacement to
33   provide critical sections, it too suffers from potential data races
34   in the face of an ill-timed asynchronous signal.  And we compound
35   the situation by reading static storage in a signal handler, which
36   POSIX warns is not generically async-signal-safe.  Oh well.
37
38   Additionally:
39     - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
40       is not defined.
41     - We don't implement SA_ONSTACK, because sigaltstack() is not present.
42     - We ignore SA_RESTART, because blocking native Windows API calls are
43       not interrupted anyway when an asynchronous signal occurs, and the
44       MSVCRT runtime never sets errno to EINTR.
45     - We don't implement SA_SIGINFO because it is impossible to do so
46       portably.
47
48   POSIX states that an application should not mix signal() and
49   sigaction().  We support the use of signal() within the gnulib
50   sigprocmask() substitute, but all other application code linked
51   with this module should stick with only sigaction().  */
52
53/* Check some of our assumptions.  */
54#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
55# error "Revisit the assumptions made in the sigaction module"
56#endif
57
58/* Out-of-range substitutes make a good fallback for uncatchable
59   signals.  */
60#ifndef SIGKILL
61# define SIGKILL (-1)
62#endif
63#ifndef SIGSTOP
64# define SIGSTOP (-1)
65#endif
66
67/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
68   for the signal SIGABRT.  Only one signal handler is stored for both
69   SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
70#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
71# undef SIGABRT_COMPAT
72# define SIGABRT_COMPAT 6
73#endif
74
75/* A signal handler.  */
76typedef void (*handler_t) (int signal);
77
78/* Set of current actions.  If sa_handler for an entry is NULL, then
79   that signal is not currently handled by the sigaction handler.  */
80static struct sigaction volatile action_array[NSIG] /* = 0 */;
81
82/* Signal handler that is installed for signals.  */
83static void
84sigaction_handler (int sig)
85{
86  handler_t handler;
87  sigset_t mask;
88  sigset_t oldmask;
89  int saved_errno = errno;
90  if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
91    {
92      /* Unexpected situation; be careful to avoid recursive abort.  */
93      if (sig == SIGABRT)
94        signal (SIGABRT, SIG_DFL);
95      abort ();
96    }
97
98  /* Reinstall the signal handler when required; otherwise update the
99     bookkeeping so that the user's handler may call sigaction and get
100     accurate results.  We know the signal isn't currently blocked, or
101     we wouldn't be in its handler, therefore we know that we are not
102     interrupting a sigaction() call.  There is a race where any
103     asynchronous instance of the same signal occurring before we
104     reinstall the handler will trigger the default handler; oh
105     well.  */
106  handler = action_array[sig].sa_handler;
107  if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
108    signal (sig, sigaction_handler);
109  else
110    action_array[sig].sa_handler = NULL;
111
112  /* Block appropriate signals.  */
113  mask = action_array[sig].sa_mask;
114  if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
115    sigaddset (&mask, sig);
116  sigprocmask (SIG_BLOCK, &mask, &oldmask);
117
118  /* Invoke the user's handler, then restore prior mask.  */
119  errno = saved_errno;
120  handler (sig);
121  saved_errno = errno;
122  sigprocmask (SIG_SETMASK, &oldmask, NULL);
123  errno = saved_errno;
124}
125
126/* Change and/or query the action that will be taken on delivery of
127   signal SIG.  If not NULL, ACT describes the new behavior.  If not
128   NULL, OACT is set to the prior behavior.  Return 0 on success, or
129   set errno and return -1 on failure.  */
130int
131sigaction (int sig, const struct sigaction *restrict act,
132           struct sigaction *restrict oact)
133{
134  sigset_t mask;
135  sigset_t oldmask;
136  int saved_errno;
137
138  if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
139      || (act && act->sa_handler == SIG_ERR))
140    {
141      errno = EINVAL;
142      return -1;
143    }
144
145#ifdef SIGABRT_COMPAT
146  if (sig == SIGABRT_COMPAT)
147    sig = SIGABRT;
148#endif
149
150  /* POSIX requires sigaction() to be async-signal-safe.  In other
151     words, if an asynchronous signal can occur while we are anywhere
152     inside this function, the user's handler could then call
153     sigaction() recursively and expect consistent results.  We meet
154     this rule by using sigprocmask to block all signals before
155     modifying any data structure that could be read from a signal
156     handler; this works since we know that the gnulib sigprocmask
157     replacement does not try to use sigaction() from its handler.  */
158  if (!act && !oact)
159    return 0;
160  sigfillset (&mask);
161  sigprocmask (SIG_BLOCK, &mask, &oldmask);
162  if (oact)
163    {
164      if (action_array[sig].sa_handler)
165        *oact = action_array[sig];
166      else
167        {
168          /* Safe to change the handler at will here, since all
169             signals are currently blocked.  */
170          oact->sa_handler = signal (sig, SIG_DFL);
171          if (oact->sa_handler == SIG_ERR)
172            goto failure;
173          signal (sig, oact->sa_handler);
174          oact->sa_flags = SA_RESETHAND | SA_NODEFER;
175          sigemptyset (&oact->sa_mask);
176        }
177    }
178
179  if (act)
180    {
181      /* Safe to install the handler before updating action_array,
182         since all signals are currently blocked.  */
183      if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
184        {
185          if (signal (sig, act->sa_handler) == SIG_ERR)
186            goto failure;
187          action_array[sig].sa_handler = NULL;
188        }
189      else
190        {
191          if (signal (sig, sigaction_handler) == SIG_ERR)
192            goto failure;
193          action_array[sig] = *act;
194        }
195    }
196  sigprocmask (SIG_SETMASK, &oldmask, NULL);
197  return 0;
198
199 failure:
200  saved_errno = errno;
201  sigprocmask (SIG_SETMASK, &oldmask, NULL);
202  errno = saved_errno;
203  return -1;
204}
205