diff options
Diffstat (limited to 'lib/sigevent.c')
-rw-r--r-- | lib/sigevent.c | 109 |
1 files changed, 79 insertions, 30 deletions
diff --git a/lib/sigevent.c b/lib/sigevent.c index 30e9a3d1..18fcffb0 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #include <zebra.h> @@ -41,13 +41,13 @@ struct quagga_sigevent_master_t { struct thread *t; - struct quagga_signal_t *signals; + struct quagga_signal_t *signals; int sigc; - + volatile sig_atomic_t caught; } sigmaster; -/* Generic signal handler +/* Generic signal handler * Schedules signal event thread */ static void @@ -55,24 +55,30 @@ quagga_signal_handler (int signo) { int i; struct quagga_signal_t *sig; - + for (i = 0; i < sigmaster.sigc; i++) { sig = &(sigmaster.signals[i]); - + if (sig->signal == signo) sig->caught = 1; } - + sigmaster.caught = 1; -} +} -/* check if signals have been caught and run appropriate handlers */ +/* check if signals have been caught and run appropriate handlers + * + * Returns: 0 => nothing to do + * -1 => failed + * > 0 => done this many signals + */ int quagga_sigevent_process (void) { struct quagga_signal_t *sig; int i; + int done ; #ifdef SIGEVENT_BLOCK_SIGNALS /* shouldnt need to block signals, but potentially may be needed */ sigset_t newmask, oldmask; @@ -85,7 +91,7 @@ quagga_sigevent_process (void) sigfillset (&newmask); sigdelset (&newmask, SIGTRAP); sigdelset (&newmask, SIGKILL); - + if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0) { zlog_err ("quagga_signal_timer: couldnt block signals!"); @@ -93,13 +99,14 @@ quagga_sigevent_process (void) } #endif /* SIGEVENT_BLOCK_SIGNALS */ + done = 0 ; if (sigmaster.caught > 0) { sigmaster.caught = 0; /* must not read or set sigmaster.caught after here, * race condition with per-sig caught flags if one does */ - + for (i = 0; i < sigmaster.sigc; i++) { sig = &(sigmaster.signals[i]); @@ -108,6 +115,7 @@ quagga_sigevent_process (void) { sig->caught = 0; sig->handler (); + ++done ; } } } @@ -117,7 +125,7 @@ quagga_sigevent_process (void) return -1; #endif /* SIGEVENT_BLOCK_SIGNALS */ - return 0; + return done ; } #ifdef SIGEVENT_SCHEDULE_THREAD @@ -159,7 +167,7 @@ signal_set (int signo) } ret = sigaction (signo, &sig, &osig); - if (ret < 0) + if (ret < 0) return ret; else return 0; @@ -212,18 +220,25 @@ core_handler(int signo , siginfo, program_counter(context) #endif ); - abort(); + zabort_abort(); } +/* For the signals known to Quagga, and which are in their default state, + * set a Quagga default handler. + */ static void trap_default_signals(void) { static const int core_signals[] = { SIGQUIT, SIGILL, + SIGABRT, #ifdef SIGEMT SIGEMT, #endif +#ifdef SIGIOT + SIGIOT, +#endif SIGFPE, SIGBUS, SIGSEGV, @@ -237,6 +252,7 @@ trap_default_signals(void) SIGXFSZ, #endif }; + static const int exit_signals[] = { SIGHUP, SIGINT, @@ -245,18 +261,20 @@ trap_default_signals(void) SIGUSR1, SIGUSR2, #ifdef SIGPOLL - SIGPOLL, + SIGPOLL, #endif #ifdef SIGVTALRM SIGVTALRM, #endif #ifdef SIGSTKFLT - SIGSTKFLT, + SIGSTKFLT, #endif }; + static const int ignore_signals[] = { SIGPIPE, }; + static const struct { const int *sigs; u_int nsigs; @@ -279,38 +297,49 @@ trap_default_signals(void) for (j = 0; j < sigmap[i].nsigs; j++) { struct sigaction oact; - if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) && - (oact.sa_handler == SIG_DFL)) + if (sigaction(sigmap[i].sigs[j], NULL, &oact) < 0) + zlog_warn("Unable to get signal handler for signal %d: %s", + sigmap[i].sigs[j], errtoa(errno, 0).str); + else { +#ifdef SA_SIGINFO + if (oact.sa_flags & SA_SIGINFO) + continue ; /* Don't set again */ +#endif + if (oact.sa_handler != SIG_DFL) + continue ; /* Don't set again */ + } + if ( (sigaction(sigmap[i].sigs[j], NULL, &oact) == 0) && + (oact.sa_handler == SIG_DFL) ) { struct sigaction act; sigfillset (&act.sa_mask); if (sigmap[i].handler == NULL) { act.sa_handler = SIG_IGN; - act.sa_flags = 0; + act.sa_flags = 0; } else { #ifdef SA_SIGINFO /* Request extra arguments to signal handler. */ act.sa_sigaction = sigmap[i].handler; - act.sa_flags = SA_SIGINFO; + act.sa_flags = SA_SIGINFO; #else - act.sa_handler = sigmap[i].handler; - act.sa_flags = 0; + act.sa_handler = sigmap[i].handler; + act.sa_flags = 0; #endif } - if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0) + if (sigaction(sigmap[i].sigs[j], &act, NULL) < 0) zlog_warn("Unable to set signal handler for signal %d: %s", - sigmap[i].sigs[j],safe_strerror(errno)); + sigmap[i].sigs[j], errtoa(errno, 0).str); } } } } -void -signal_init (struct thread_master *m, int sigc, +void +signal_init (struct thread_master *m, int sigc, struct quagga_signal_t signals[]) { @@ -320,7 +349,7 @@ signal_init (struct thread_master *m, int sigc, /* First establish some default handlers that can be overridden by the application. */ trap_default_signals(); - + while (i < sigc) { sig = &signals[i]; @@ -332,9 +361,29 @@ signal_init (struct thread_master *m, int sigc, sigmaster.sigc = sigc; sigmaster.signals = signals; -#ifdef SIGEVENT_SCHEDULE_THREAD - sigmaster.t = - thread_add_timer (m, quagga_signal_timer, &sigmaster, +#ifdef SIGEVENT_SCHEDULE_THREAD + sigmaster.t = + thread_add_timer (m, quagga_signal_timer, &sigmaster, QUAGGA_SIGNAL_TIMER_INTERVAL); #endif /* SIGEVENT_SCHEDULE_THREAD */ } + +/* turn off trap for SIGABRT ! */ +extern void quagga_sigabrt_no_trap(void) +{ + struct sigaction new_act ; + sigset_t set ; + + sigfillset(&set) ; + + new_act.sa_handler = SIG_DFL ; + new_act.sa_mask = set ; + new_act.sa_flags = 0 ; + sigaction(SIGABRT, &new_act, NULL) ; + + sigemptyset(&set) ; + sigaddset(&set, SIGABRT) ; + sigprocmask(SIG_UNBLOCK, &set, NULL) ; + +} ; + |