Annotation of embedaddon/quagga/lib/sigevent.c, revision 1.1.1.2

1.1       misho       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>
1.1.1.2 ! misho      25: #include <memory.h>
1.1       misho      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: quagga_signal_handler (int signo)
                     56: {
                     57:   int i;
                     58:   struct quagga_signal_t *sig;
                     59:   
                     60:   for (i = 0; i < sigmaster.sigc; i++)
                     61:     {
                     62:       sig = &(sigmaster.signals[i]);
                     63:       
                     64:       if (sig->signal == signo)
                     65:         sig->caught = 1;
                     66:     }
                     67:   
                     68:   sigmaster.caught = 1;
                     69: } 
                     70: 
                     71: /* check if signals have been caught and run appropriate handlers */
                     72: int
                     73: 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:   if (sigmaster.caught > 0)
                     98:     {
                     99:       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:       for (i = 0; i < sigmaster.sigc; i++)
                    105:         {
                    106:           sig = &(sigmaster.signals[i]);
                    107: 
                    108:           if (sig->caught > 0)
                    109:             {
                    110:               sig->caught = 0;
                    111:               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:   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: signal_set (int signo)
                    144: {
                    145:   int ret;
                    146:   struct sigaction sig;
                    147:   struct sigaction osig;
                    148: 
                    149:   sig.sa_handler = &quagga_signal_handler;
                    150:   sigfillset (&sig.sa_mask);
                    151:   sig.sa_flags = 0;
                    152:   if (signo == SIGALRM) {
                    153: #ifdef SA_INTERRUPT
                    154:       sig.sa_flags |= SA_INTERRUPT; /* SunOS */
                    155: #endif
                    156:   } else {
                    157: #ifdef SA_RESTART
                    158:       sig.sa_flags |= SA_RESTART;
                    159: #endif /* SA_RESTART */
                    160:   }
                    161: 
                    162:   ret = sigaction (signo, &sig, &osig);
                    163:   if (ret < 0) 
                    164:     return ret;
                    165:   else
                    166:     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: 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:   return NULL;
                    185: }
                    186: 
                    187: #endif /* SA_SIGINFO */
                    188: 
                    189: static void __attribute__ ((noreturn))
                    190: exit_handler(int signo
                    191: #ifdef SA_SIGINFO
                    192:             , siginfo_t *siginfo, void *context
                    193: #endif
                    194:            )
                    195: {
                    196:   zlog_signal(signo, "exiting..."
                    197: #ifdef SA_SIGINFO
                    198:              , siginfo, program_counter(context)
                    199: #endif
                    200:             );
                    201:   _exit(128+signo);
                    202: }
                    203: 
                    204: static void __attribute__ ((noreturn))
                    205: core_handler(int signo
                    206: #ifdef SA_SIGINFO
                    207:             , siginfo_t *siginfo, void *context
                    208: #endif
                    209:            )
                    210: {
                    211:   zlog_signal(signo, "aborting..."
                    212: #ifdef SA_SIGINFO
                    213:              , siginfo, program_counter(context)
                    214: #endif
                    215:             );
                    216:   abort();
                    217: }
                    218: 
                    219: static void
                    220: 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[] = {
1.1.1.2 ! misho     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},
1.1       misho     273:   };
                    274:   u_int i;
                    275: 
1.1.1.2 ! misho     276:   for (i = 0; i < array_size(sigmap); i++)
1.1       misho     277:     {
                    278:       u_int j;
                    279: 
                    280:       for (j = 0; j < sigmap[i].nsigs; j++)
                    281:         {
                    282:          struct sigaction oact;
                    283:          if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
                    284:              (oact.sa_handler == SIG_DFL))
                    285:            {
                    286:              struct sigaction act;
                    287:              sigfillset (&act.sa_mask);
                    288:              if (sigmap[i].handler == NULL)
                    289:                {
                    290:                  act.sa_handler = SIG_IGN;
                    291:                  act.sa_flags = 0;
                    292:                }
                    293:              else
                    294:                {
                    295: #ifdef SA_SIGINFO
                    296:                  /* Request extra arguments to signal handler. */
                    297:                  act.sa_sigaction = sigmap[i].handler;
                    298:                  act.sa_flags = SA_SIGINFO;
                    299: #else
                    300:                  act.sa_handler = sigmap[i].handler;
                    301:                  act.sa_flags = 0;
                    302: #endif
                    303:                }
                    304:              if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
                    305:                zlog_warn("Unable to set signal handler for signal %d: %s",
                    306:                          sigmap[i].sigs[j],safe_strerror(errno));
                    307: 
                    308:            }
                    309:         }
                    310:     }
                    311: }
                    312: 
                    313: void 
                    314: signal_init (struct thread_master *m, int sigc, 
                    315:              struct quagga_signal_t signals[])
                    316: {
                    317: 
                    318:   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:   trap_default_signals();
                    324:   
                    325:   while (i < sigc)
                    326:     {
                    327:       sig = &signals[i];
                    328:       if ( signal_set (sig->signal) < 0 )
                    329:         exit (-1);
                    330:       i++;
                    331:     }
                    332: 
                    333:   sigmaster.sigc = sigc;
                    334:   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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>