]> git.puffer.fish Git - mirror/frr.git/commitdiff
2004-11-23 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
authorajs <ajs>
Tue, 23 Nov 2004 18:19:14 +0000 (18:19 +0000)
committerajs <ajs>
Tue, 23 Nov 2004 18:19:14 +0000 (18:19 +0000)
* 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.

lib/ChangeLog
lib/log.c
lib/log.h
lib/sigevent.c

index f768088c043d78f454c212dbbfd806a72c45b6d7..10092d1c5ac4ccf1ba11daea3747f84bb0645857 100644 (file)
@@ -1,3 +1,18 @@
+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
index 205b7c0d379750084cdbcf8ec3f42794195e3422..c55bfcb18d0da4d378f0ac1112a37375f39be918 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -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, ...)
 {
index e04376034840fb72c14e42c9b49daaa3c686e333..1fd4fe0c73a6f45b0b7cc6120f3b9f17e3a2c1a3 100644 (file)
--- a/lib/log.h
+++ b/lib/log.h
@@ -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 */
index 937180c9528b514830d24f89b095c333eb05bedd..53503a7a9898388d8a275d37aa54db523af069a6 100644 (file)
@@ -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)
     {