LCOV - code coverage report
Current view: top level - lib - sigevent.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 46 61 75.4 %
Date: 2015-11-19 Functions: 5 8 62.5 %

          Line data    Source code
       1             : /* Quagga signal handling functions.
       2             :  * Copyright (C) 2004 Paul Jakma,
       3             :  *
       4             :  * This file is part of Quagga.
       5             :  *
       6             :  * Quagga is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * Quagga is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with Quagga; see the file COPYING.  If not, write to the Free
      18             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      19             :  * 02111-1307, USA.  
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : #include <sigevent.h>
      24             : #include <log.h>
      25             : #include <memory.h>
      26             : 
      27             : #ifdef SA_SIGINFO
      28             : #ifdef HAVE_UCONTEXT_H
      29             : #ifdef GNU_LINUX
      30             : /* get REG_EIP from ucontext.h */
      31             : #ifndef __USE_GNU
      32             : #define __USE_GNU
      33             : #endif /* __USE_GNU */
      34             : #endif /* GNU_LINUX */
      35             : #include <ucontext.h>
      36             : #endif /* HAVE_UCONTEXT_H */
      37             : #endif /* SA_SIGINFO */
      38             : 
      39             : 
      40             : /* master signals descriptor struct */
      41             : struct quagga_sigevent_master_t
      42             : {
      43             :   struct thread *t;
      44             : 
      45             :   struct quagga_signal_t *signals; 
      46             :   int sigc;
      47             :   
      48             :   volatile sig_atomic_t caught;
      49             : } sigmaster;
      50             : 
      51             : /* Generic signal handler 
      52             :  * Schedules signal event thread
      53             :  */
      54             : static void
      55          90 : quagga_signal_handler (int signo)
      56             : {
      57             :   int i;
      58             :   struct quagga_signal_t *sig;
      59             :   
      60         450 :   for (i = 0; i < sigmaster.sigc; i++)
      61             :     {
      62         360 :       sig = &(sigmaster.signals[i]);
      63             :       
      64         360 :       if (sig->signal == signo)
      65          90 :         sig->caught = 1;
      66             :     }
      67             :   
      68          90 :   sigmaster.caught = 1;
      69          90 : } 
      70             : 
      71             : /* check if signals have been caught and run appropriate handlers */
      72             : int
      73        2274 : quagga_sigevent_process (void)
      74             : {
      75             :   struct quagga_signal_t *sig;
      76             :   int i;
      77             : #ifdef SIGEVENT_BLOCK_SIGNALS
      78             :   /* shouldnt need to block signals, but potentially may be needed */
      79             :   sigset_t newmask, oldmask;
      80             : 
      81             :   /*
      82             :    * Block most signals, but be careful not to defer SIGTRAP because
      83             :    * doing so breaks gdb, at least on NetBSD 2.0.  Avoid asking to
      84             :    * block SIGKILL, just because we shouldn't be able to do so.
      85             :    */
      86             :   sigfillset (&newmask);
      87             :   sigdelset (&newmask, SIGTRAP);
      88             :   sigdelset (&newmask, SIGKILL);
      89             :    
      90             :   if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0)
      91             :     {
      92             :       zlog_err ("quagga_signal_timer: couldnt block signals!");
      93             :       return -1;
      94             :     }
      95             : #endif /* SIGEVENT_BLOCK_SIGNALS */
      96             : 
      97        2274 :   if (sigmaster.caught > 0)
      98             :     {
      99          45 :       sigmaster.caught = 0;
     100             :       /* must not read or set sigmaster.caught after here,
     101             :        * race condition with per-sig caught flags if one does
     102             :        */
     103             :       
     104         180 :       for (i = 0; i < sigmaster.sigc; i++)
     105             :         {
     106         180 :           sig = &(sigmaster.signals[i]);
     107             : 
     108         180 :           if (sig->caught > 0)
     109             :             {
     110          90 :               sig->caught = 0;
     111          90 :               sig->handler ();
     112             :             }
     113             :         }
     114             :     }
     115             : 
     116             : #ifdef SIGEVENT_BLOCK_SIGNALS
     117             :   if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 );
     118             :     return -1;
     119             : #endif /* SIGEVENT_BLOCK_SIGNALS */
     120             : 
     121        2229 :   return 0;
     122             : }
     123             : 
     124             : #ifdef SIGEVENT_SCHEDULE_THREAD
     125             : /* timer thread to check signals. Shouldnt be needed */
     126             : int
     127             : quagga_signal_timer (struct thread *t)
     128             : {
     129             :   struct quagga_sigevent_master_t *sigm;
     130             :   struct quagga_signal_t *sig;
     131             :   int i;
     132             : 
     133             :   sigm = THREAD_ARG (t);
     134             :   sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster,
     135             :                               QUAGGA_SIGNAL_TIMER_INTERVAL);
     136             :   return quagga_sigevent_process ();
     137             : }
     138             : #endif /* SIGEVENT_SCHEDULE_THREAD */
     139             : 
     140             : /* Initialization of signal handles. */
     141             : /* Signal wrapper. */
     142             : static int
     143         180 : signal_set (int signo)
     144             : {
     145             :   int ret;
     146             :   struct sigaction sig;
     147             :   struct sigaction osig;
     148             : 
     149         180 :   sig.sa_handler = &quagga_signal_handler;
     150         180 :   sigfillset (&sig.sa_mask);
     151         180 :   sig.sa_flags = 0;
     152         180 :   if (signo == SIGALRM) {
     153             : #ifdef SA_INTERRUPT
     154           0 :       sig.sa_flags |= SA_INTERRUPT; /* SunOS */
     155             : #endif
     156             :   } else {
     157             : #ifdef SA_RESTART
     158         180 :       sig.sa_flags |= SA_RESTART;
     159             : #endif /* SA_RESTART */
     160             :   }
     161             : 
     162         180 :   ret = sigaction (signo, &sig, &osig);
     163         180 :   if (ret < 0) 
     164           0 :     return ret;
     165             :   else
     166         180 :     return 0;
     167             : }
     168             : 
     169             : #ifdef SA_SIGINFO
     170             : 
     171             : /* XXX This function should be enhanced to support more platforms
     172             :        (it currently works only on Linux/x86). */
     173             : static void *
     174           0 : program_counter(void *context)
     175             : {
     176             : #ifdef HAVE_UCONTEXT_H
     177             : #ifdef GNU_LINUX
     178             : #ifdef REG_EIP
     179             :   if (context)
     180             :     return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]);
     181             : #endif /* REG_EIP */
     182             : #endif /* GNU_LINUX */
     183             : #endif /* HAVE_UCONTEXT_H */
     184           0 :   return NULL;
     185             : }
     186             : 
     187             : #endif /* SA_SIGINFO */
     188             : 
     189             : static void __attribute__ ((noreturn))
     190           0 : exit_handler(int signo
     191             : #ifdef SA_SIGINFO
     192             :              , siginfo_t *siginfo, void *context
     193             : #endif
     194             :             )
     195             : {
     196           0 :   zlog_signal(signo, "exiting..."
     197             : #ifdef SA_SIGINFO
     198             :               , siginfo, program_counter(context)
     199             : #endif
     200             :              );
     201           0 :   _exit(128+signo);
     202             : }
     203             : 
     204             : static void __attribute__ ((noreturn))
     205           0 : core_handler(int signo
     206             : #ifdef SA_SIGINFO
     207             :              , siginfo_t *siginfo, void *context
     208             : #endif
     209             :             )
     210             : {
     211           0 :   zlog_signal(signo, "aborting..."
     212             : #ifdef SA_SIGINFO
     213             :               , siginfo, program_counter(context)
     214             : #endif
     215             :              );
     216           0 :   abort();
     217             : }
     218             : 
     219             : static void
     220          45 : trap_default_signals(void)
     221             : {
     222             :   static const int core_signals[] = {
     223             :     SIGQUIT,
     224             :     SIGILL,
     225             : #ifdef SIGEMT
     226             :     SIGEMT,
     227             : #endif
     228             :     SIGFPE,
     229             :     SIGBUS,
     230             :     SIGSEGV,
     231             : #ifdef SIGSYS
     232             :     SIGSYS,
     233             : #endif
     234             : #ifdef SIGXCPU
     235             :     SIGXCPU,
     236             : #endif
     237             : #ifdef SIGXFSZ
     238             :     SIGXFSZ,
     239             : #endif
     240             :   };
     241             :   static const int exit_signals[] = {
     242             :     SIGHUP,
     243             :     SIGINT,
     244             :     SIGALRM,
     245             :     SIGTERM,
     246             :     SIGUSR1,
     247             :     SIGUSR2,
     248             : #ifdef SIGPOLL
     249             :     SIGPOLL, 
     250             : #endif
     251             : #ifdef SIGVTALRM
     252             :     SIGVTALRM,
     253             : #endif
     254             : #ifdef SIGSTKFLT
     255             :     SIGSTKFLT, 
     256             : #endif
     257             :   };
     258             :   static const int ignore_signals[] = {
     259             :     SIGPIPE,
     260             :   };
     261             :   static const struct {
     262             :     const int *sigs;
     263             :     u_int nsigs;
     264             :     void (*handler)(int signo
     265             : #ifdef SA_SIGINFO
     266             :                     , siginfo_t *info, void *context
     267             : #endif
     268             :                    );
     269             :   } sigmap[] = {
     270             :     { core_signals, array_size(core_signals), core_handler},
     271             :     { exit_signals, array_size(exit_signals), exit_handler},
     272             :     { ignore_signals, array_size(ignore_signals), NULL},
     273             :   };
     274             :   u_int i;
     275             : 
     276         180 :   for (i = 0; i < array_size(sigmap); i++)
     277             :     {
     278             :       u_int j;
     279             : 
     280         945 :       for (j = 0; j < sigmap[i].nsigs; j++)
     281             :         {
     282             :           struct sigaction oact;
     283        1620 :           if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
     284         810 :               (oact.sa_handler == SIG_DFL))
     285             :             {
     286             :               struct sigaction act;
     287         630 :               sigfillset (&act.sa_mask);
     288         630 :               if (sigmap[i].handler == NULL)
     289             :                 {
     290           0 :                   act.sa_handler = SIG_IGN;
     291           0 :                   act.sa_flags = 0;
     292             :                 }
     293             :               else
     294             :                 {
     295             : #ifdef SA_SIGINFO
     296             :                   /* Request extra arguments to signal handler. */
     297         630 :                   act.sa_sigaction = sigmap[i].handler;
     298         630 :                   act.sa_flags = SA_SIGINFO;
     299             : #else
     300             :                   act.sa_handler = sigmap[i].handler;
     301             :                   act.sa_flags = 0;
     302             : #endif
     303             :                 }
     304         630 :               if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
     305           0 :                 zlog_warn("Unable to set signal handler for signal %d: %s",
     306           0 :                           sigmap[i].sigs[j],safe_strerror(errno));
     307             : 
     308             :             }
     309             :         }
     310             :     }
     311          45 : }
     312             : 
     313             : void 
     314          45 : signal_init (struct thread_master *m, int sigc, 
     315             :              struct quagga_signal_t signals[])
     316             : {
     317             : 
     318          45 :   int i = 0;
     319             :   struct quagga_signal_t *sig;
     320             : 
     321             :   /* First establish some default handlers that can be overridden by
     322             :      the application. */
     323          45 :   trap_default_signals();
     324             :   
     325         270 :   while (i < sigc)
     326             :     {
     327         180 :       sig = &signals[i];
     328         180 :       if ( signal_set (sig->signal) < 0 )
     329           0 :         exit (-1);
     330         180 :       i++;
     331             :     }
     332             : 
     333          45 :   sigmaster.sigc = sigc;
     334          45 :   sigmaster.signals = signals;
     335             : 
     336             : #ifdef SIGEVENT_SCHEDULE_THREAD  
     337             :   sigmaster.t = 
     338             :     thread_add_timer (m, quagga_signal_timer, &sigmaster, 
     339             :                       QUAGGA_SIGNAL_TIMER_INTERVAL);
     340             : #endif /* SIGEVENT_SCHEDULE_THREAD */
     341          45 : }

Generated by: LCOV version 1.10