File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / sigevent.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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: 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:   /* these are from GNU libc, rather than Linux, strictly speaking */
  179: # if defined(REG_EIP)
  180: #  define REG_INDEX REG_EIP
  181: # elif defined(REG_RIP)
  182: #  define REG_INDEX REG_RIP
  183: # elif defined(__powerpc__)
  184: #  define REG_INDEX 32
  185: # endif
  186: #elif defined(SUNOS_5) /* !GNU_LINUX */
  187: # define REG_INDEX REG_PC
  188: #endif /* GNU_LINUX */
  189: 
  190: #ifdef REG_INDEX
  191: # ifdef HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS
  192: #  define REGS gregs[REG_INDEX]
  193: # elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_UC_REGS)
  194: #  define REGS uc_regs->gregs[REG_INDEX]
  195: # endif /* HAVE_UCONTEXT_T_UC_MCONTEXT_GREGS */
  196: #endif /* REG_INDEX */
  197: 
  198: #ifdef REGS
  199:   if (context)
  200:     return (void *)(((ucontext_t *)context)->uc_mcontext.REGS);
  201: #elif defined(HAVE_UCONTEXT_T_UC_MCONTEXT_REGS__NIP) 
  202:   /* older Linux / struct pt_regs ? */
  203:   if (context)
  204:     return (void *)(((ucontext_t *)context)->uc_mcontext.regs->nip);
  205: #endif /* REGS */
  206: 
  207: #endif /* HAVE_UCONTEXT_H */
  208:   return NULL;
  209: }
  210: 
  211: #endif /* SA_SIGINFO */
  212: 
  213: static void __attribute__ ((noreturn))
  214: exit_handler(int signo
  215: #ifdef SA_SIGINFO
  216: 	     , siginfo_t *siginfo, void *context
  217: #endif
  218: 	    )
  219: {
  220:   zlog_signal(signo, "exiting..."
  221: #ifdef SA_SIGINFO
  222: 	      , siginfo, program_counter(context)
  223: #endif
  224: 	     );
  225:   _exit(128+signo);
  226: }
  227: 
  228: static void __attribute__ ((noreturn))
  229: core_handler(int signo
  230: #ifdef SA_SIGINFO
  231: 	     , siginfo_t *siginfo, void *context
  232: #endif
  233: 	    )
  234: {
  235:   zlog_signal(signo, "aborting..."
  236: #ifdef SA_SIGINFO
  237: 	      , siginfo, program_counter(context)
  238: #endif
  239: 	     );
  240:   abort();
  241: }
  242: 
  243: static void
  244: trap_default_signals(void)
  245: {
  246:   static const int core_signals[] = {
  247:     SIGQUIT,
  248:     SIGILL,
  249: #ifdef SIGEMT
  250:     SIGEMT,
  251: #endif
  252:     SIGFPE,
  253:     SIGBUS,
  254:     SIGSEGV,
  255: #ifdef SIGSYS
  256:     SIGSYS,
  257: #endif
  258: #ifdef SIGXCPU
  259:     SIGXCPU,
  260: #endif
  261: #ifdef SIGXFSZ
  262:     SIGXFSZ,
  263: #endif
  264:   };
  265:   static const int exit_signals[] = {
  266:     SIGHUP,
  267:     SIGINT,
  268:     SIGALRM,
  269:     SIGTERM,
  270:     SIGUSR1,
  271:     SIGUSR2,
  272: #ifdef SIGPOLL
  273:     SIGPOLL, 
  274: #endif
  275: #ifdef SIGVTALRM
  276:     SIGVTALRM,
  277: #endif
  278: #ifdef SIGSTKFLT
  279:     SIGSTKFLT, 
  280: #endif
  281:   };
  282:   static const int ignore_signals[] = {
  283:     SIGPIPE,
  284:   };
  285:   static const struct {
  286:     const int *sigs;
  287:     u_int nsigs;
  288:     void (*handler)(int signo
  289: #ifdef SA_SIGINFO
  290: 		    , siginfo_t *info, void *context
  291: #endif
  292: 		   );
  293:   } sigmap[] = {
  294:     { core_signals, array_size(core_signals), core_handler},
  295:     { exit_signals, array_size(exit_signals), exit_handler},
  296:     { ignore_signals, array_size(ignore_signals), NULL},
  297:   };
  298:   u_int i;
  299: 
  300:   for (i = 0; i < array_size(sigmap); i++)
  301:     {
  302:       u_int j;
  303: 
  304:       for (j = 0; j < sigmap[i].nsigs; j++)
  305:         {
  306: 	  struct sigaction oact;
  307: 	  if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
  308: 	      (oact.sa_handler == SIG_DFL))
  309: 	    {
  310: 	      struct sigaction act;
  311: 	      sigfillset (&act.sa_mask);
  312: 	      if (sigmap[i].handler == NULL)
  313: 	        {
  314: 		  act.sa_handler = SIG_IGN;
  315: 		  act.sa_flags = 0;
  316: 	        }
  317: 	      else
  318: 	        {
  319: #ifdef SA_SIGINFO
  320: 		  /* Request extra arguments to signal handler. */
  321: 		  act.sa_sigaction = sigmap[i].handler;
  322: 		  act.sa_flags = SA_SIGINFO;
  323: #else
  324: 		  act.sa_handler = sigmap[i].handler;
  325: 		  act.sa_flags = 0;
  326: #endif
  327: 	        }
  328: 	      if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
  329: 	        zlog_warn("Unable to set signal handler for signal %d: %s",
  330: 			  sigmap[i].sigs[j],safe_strerror(errno));
  331: 
  332: 	    }
  333:         }
  334:     }
  335: }
  336: 
  337: void 
  338: signal_init (struct thread_master *m, int sigc, 
  339:              struct quagga_signal_t signals[])
  340: {
  341: 
  342:   int i = 0;
  343:   struct quagga_signal_t *sig;
  344: 
  345:   /* First establish some default handlers that can be overridden by
  346:      the application. */
  347:   trap_default_signals();
  348:   
  349:   while (i < sigc)
  350:     {
  351:       sig = &signals[i];
  352:       if ( signal_set (sig->signal) < 0 )
  353:         exit (-1);
  354:       i++;
  355:     }
  356: 
  357:   sigmaster.sigc = sigc;
  358:   sigmaster.signals = signals;
  359: 
  360: #ifdef SIGEVENT_SCHEDULE_THREAD  
  361:   sigmaster.t = 
  362:     thread_add_timer (m, quagga_signal_timer, &sigmaster, 
  363:                       QUAGGA_SIGNAL_TIMER_INTERVAL);
  364: #endif /* SIGEVENT_SCHEDULE_THREAD */
  365: }

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