(root)/
gettext-0.22.4/
libtextstyle/
lib/
sigaction.c
       1  /* POSIX compatible signal blocking.
       2     Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3     Written by Eric Blake <ebb9@byu.net>, 2008.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file 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 Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://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 __CYGWIN__
      71  # undef SIGABRT_COMPAT
      72  # define SIGABRT_COMPAT 6
      73  #endif
      74  
      75  /* A signal handler.  */
      76  typedef 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.  */
      80  static struct sigaction volatile action_array[NSIG] /* = 0 */;
      81  
      82  /* Signal handler that is installed for signals.  */
      83  static void
      84  sigaction_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.  */
     130  int
     131  sigaction (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  }