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.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index f768088..10092d1 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.
diff --git a/lib/log.c b/lib/log.c
index 205b7c0..c55bfcb 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -163,6 +163,104 @@
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, ...)
{
diff --git a/lib/log.h b/lib/log.h
index e043760..1fd4fe0 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -122,4 +122,7 @@
/* 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 937180c..53503a7 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -37,7 +37,7 @@
/* Generic signal handler
* Schedules signal event thread
*/
-void
+static void
quagga_signal_handler (int signo)
{
int i;
@@ -125,7 +125,7 @@
/* Initialization of signal handles. */
/* Signale wrapper. */
-int
+static int
signal_set (int signo)
{
int ret;
@@ -152,6 +152,93 @@
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 @@
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)
{