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)
     {