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

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

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