diff options
-rw-r--r-- | lib/ChangeLog | 15 | ||||
-rw-r--r-- | lib/log.c | 98 | ||||
-rw-r--r-- | lib/log.h | 3 | ||||
-rw-r--r-- | lib/sigevent.c | 95 |
4 files changed, 209 insertions, 2 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog index f768088c..10092d1c 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,5 +1,20 @@ 2004-11-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + * sigevent.c: (signal_init) Set up some default signal handlers + so that processes will issue an error message before terminating + or dumping core. + (trap_default_signals) New function to set up signal handlers + for various signals that may kill the process. + (exit_handler) Call zlog_signal, then _exit. + (core_handler) Call zlog_signal, then abort. + * log.h: Declare new function zlog_signal. + * log.c: (zlog_signal) New function to log information about + a received signal before the process dies. Try to log a + backtrace also. + (quagga_signal_handler,signal_set) Should be static. + +2004-11-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + * log.c: (vzlog) Take a single va_list argument and use va_copy as necessary for multiple traversals. (zlog) Pass only one va_list to vzlog. @@ -163,6 +163,104 @@ vzlog (struct zlog *zl, int priority, const char *format, va_list args) vty_log (zlog_proto_names[zl->protocol], format, args); } +static char * +str_append(char *dst, int len, const char *src) +{ + while ((len-- > 0) && *src) + *dst++ = *src++; + return dst; +} + +static char * +num_append(char *s, int len, u_long x) +{ + char buf[30]; + char *t = &buf[29]; + + *t = '\0'; + while (x && (t > buf)) + { + *--t = '0'+(x % 10); + x /= 10; + } + return str_append(s,len,t); +} + +/* Note: the goal here is to use only async-signal-safe functions. */ +void +zlog_signal(int signo, const char *action) +{ + time_t now; + char buf[sizeof("DEFAULT: Received signal S at T; aborting...")+60]; + char *s = buf; + +#define LOC s,buf+sizeof(buf)-s + + time(&now); + if (zlog_default) + { + s = str_append(LOC,zlog_proto_names[zlog_default->protocol]); + *s++ = ':'; + *s++ = ' '; + } + s = str_append(LOC,"Received signal "); + s = num_append(LOC,signo); + s = str_append(LOC," at "); + s = num_append(LOC,now); + s = str_append(LOC,"; "); + s = str_append(LOC,action); + *s++ = '\n'; + +#define DUMP(FP) write(fileno(FP),buf,s-buf); + if (!zlog_default) + DUMP(stderr) + else + { + if ((zlog_default->flags & ZLOG_FILE) && zlog_default->fp) + DUMP(zlog_default->fp) + if (zlog_default->flags & ZLOG_STDOUT) + DUMP(stdout) + if (zlog_default->flags & ZLOG_STDERR) + DUMP(stderr) + /* Is there a signal-safe way to send a syslog message? */ + } +#undef DUMP + + /* Now try for a backtrace. */ +#ifdef HAVE_GLIBC_BACKTRACE + { + void *array[20]; + size_t size; + + size = backtrace(array,sizeof(array)/sizeof(array[0])); + s = buf; + s = str_append(LOC,"Backtrace for "); + s = num_append(LOC,size); + s = str_append(LOC," stack frames:\n"); + +#define DUMP(FP) { \ + write(fileno(FP),buf,s-buf); \ + backtrace_symbols_fd(array, size, fileno(FP)); \ +} + + if (!zlog_default) + DUMP(stderr) + else + { + if ((zlog_default->flags & ZLOG_FILE) && zlog_default->fp) + DUMP(zlog_default->fp) + if (zlog_default->flags & ZLOG_STDOUT) + DUMP(stdout) + if (zlog_default->flags & ZLOG_STDERR) + DUMP(stderr) + /* Is there a signal-safe way to send a syslog message? */ + } +#undef DUMP + } +#endif /* HAVE_GLIBC_BACKTRACE */ +#undef LOC +} + void zlog (struct zlog *zl, int priority, const char *format, ...) { @@ -122,4 +122,7 @@ extern const char *zlog_priority[]; /* Safe version of strerror -- never returns NULL. */ extern const char *safe_strerror(int errnum); +/* To be called when a fatal signal is caught. */ +extern void zlog_signal(int signo, const char *action); + #endif /* _ZEBRA_LOG_H */ diff --git a/lib/sigevent.c b/lib/sigevent.c index 937180c9..53503a7a 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -37,7 +37,7 @@ struct quagga_sigevent_master_t /* Generic signal handler * Schedules signal event thread */ -void +static void quagga_signal_handler (int signo) { int i; @@ -125,7 +125,7 @@ quagga_signal_timer (struct thread *t) /* Initialization of signal handles. */ /* Signale wrapper. */ -int +static int signal_set (int signo) { int ret; @@ -152,6 +152,93 @@ signal_set (int signo) return 0; } +static void +exit_handler(int signo) +{ + zlog_signal(signo,"exiting..."); + _exit(128+signo); +} + +static void +core_handler(int signo) +{ + zlog_signal(signo,"aborting..."); + abort(); +} + +static void +trap_default_signals(void) +{ + static const int core_signals[] = { + SIGQUIT, + SIGILL, +#ifdef SIGEMT + SIGEMT, +#endif + SIGFPE, + SIGBUS, + SIGSEGV, +#ifdef SIGSYS + SIGSYS, +#endif +#ifdef SIGXCPU + SIGXCPU, +#endif +#ifdef SIGXFSZ + SIGXFSZ, +#endif + }; + static const int exit_signals[] = { + SIGHUP, + SIGINT, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGUSR1, + SIGUSR2, +#ifdef SIGPOLL + SIGPOLL, +#endif +#ifdef SIGVTALRM + SIGVTALRM, +#endif +#ifdef SIGSTKFLT + SIGSTKFLT, +#endif + }; + static const struct { + const int *sigs; + int nsigs; + void (*handler)(int); + } sigmap[2] = { + { core_signals, sizeof(core_signals)/sizeof(core_signals[0]),core_handler }, + { exit_signals, sizeof(exit_signals)/sizeof(exit_signals[0]),exit_handler }, + }; + int i; + + for (i = 0; i < 2; i++) + { + int j; + + 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)) + { + struct sigaction act; + act.sa_handler = sigmap[i].handler; + sigfillset (&act.sa_mask); + act.sa_flags = 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)); + + } + } + } +} + void signal_init (struct thread_master *m, int sigc, struct quagga_signal_t signals[]) @@ -159,6 +246,10 @@ signal_init (struct thread_master *m, int sigc, int i = 0; struct quagga_signal_t *sig; + + /* First establish some default handlers that can be overridden by + the application. */ + trap_default_signals(); while (i < sigc) { |