2005-02-03 Andrew J. Schorr <ajschorr@alumni.princeton.edu>

	* log.c: (syslog_sigsafe) Reduce scope of syslog_fd: it is accessed
	  inside this function only.
	  (open_crashlog) New function to open /var/tmp/quagga.<daemon>.crashlog
	  with flags O_WRONLY|O_CREAT|O_EXCL to save some crash info.
	  (zlog_signal,_zlog_assert_failed) Increase logging priority from
	  LOG_ERR to LOG_CRIT.  If no file logging is configured, try to use
	  open_crashlog to create a crash logfile.
	  (zlog_backtrace_sigsafe) If a crashlog file descriptor is open,
	  dump a backtrace to that file.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index a69abc5..6f9c39a 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,15 @@
+2005-02-03 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
+
+	* log.c: (syslog_sigsafe) Reduce scope of syslog_fd: it is accessed
+	  inside this function only.
+	  (open_crashlog) New function to open /var/tmp/quagga.<daemon>.crashlog
+	  with flags O_WRONLY|O_CREAT|O_EXCL to save some crash info.
+	  (zlog_signal,_zlog_assert_failed) Increase logging priority from
+	  LOG_ERR to LOG_CRIT.  If no file logging is configured, try to use
+	  open_crashlog to create a crash logfile.
+	  (zlog_backtrace_sigsafe) If a crashlog file descriptor is open,
+	  dump a backtrace to that file.
+
 2005-02-02 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
 
 	* if.h: Declare if_flag_dump.
diff --git a/lib/log.c b/lib/log.c
index 2efc30f..dbd378f 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1,5 +1,5 @@
 /*
- * $Id: log.c,v 1.23 2005/01/18 22:18:59 ajs Exp $
+ * $Id: log.c,v 1.24 2005/02/03 16:42:40 ajs Exp $
  *
  * Logging of zebra
  * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
@@ -31,6 +31,9 @@
 #include <sys/un.h>
 #endif
 
+static int crashlog_fd = -1;   /* Used for last-resort crash logfile when a
+				  signal is caught. */
+
 struct zlog *zlog_default = NULL;
 
 const char *zlog_proto_names[] = 
@@ -197,8 +200,6 @@
 }
 #endif
 
-static int syslog_fd = -1;
-
 /* Needs to be enhanced to support Solaris. */
 static int
 syslog_connect(void)
@@ -233,6 +234,7 @@
 static void
 syslog_sigsafe(int priority, const char *msg, size_t msglen)
 {
+  static int syslog_fd = -1;
   char buf[sizeof("<1234567890>ripngd[1234567890]: ")+msglen+50];
   char *s;
 
@@ -258,6 +260,38 @@
 #undef LOC
 }
 
+static int
+open_crashlog(void)
+{
+#define CRASHLOG_PREFIX "/var/tmp/quagga."
+#define CRASHLOG_SUFFIX "crashlog"
+  if (zlog_default && zlog_default->ident)
+    {
+      /* Avoid strlen since it is not async-signal-safe. */
+      const char *p;
+      size_t ilen;
+
+      for (p = zlog_default->ident, ilen = 0; *p; p++)
+	ilen++;
+      {
+	char buf[sizeof(CRASHLOG_PREFIX)+ilen+sizeof(CRASHLOG_SUFFIX)+3];
+	char *s = buf;
+#define LOC s,buf+sizeof(buf)-s
+	s = str_append(LOC, CRASHLOG_PREFIX);
+	s = str_append(LOC, zlog_default->ident);
+	s = str_append(LOC, ".");
+	s = str_append(LOC, CRASHLOG_SUFFIX);
+#undef LOC
+	*s = '\0';
+	return open(buf, O_WRONLY|O_CREAT|O_EXCL, LOGFILE_MASK);
+      }
+    }
+  return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX, O_WRONLY|O_CREAT|O_EXCL,
+	      LOGFILE_MASK);
+#undef CRASHLOG_SUFFIX
+#undef CRASHLOG_PREFIX
+}
+
 /* Note: the goal here is to use only async-signal-safe functions. */
 void
 zlog_signal(int signo, const char *action
@@ -301,17 +335,21 @@
     *s++ = '\n';
 
   /* N.B. implicit priority is most severe */
-#define PRI LOG_ERR
+#define PRI LOG_CRIT
 
-#define DUMP(FP) write(fileno(FP),buf,s-buf);
+#define DUMP(FD) write(FD, buf, s-buf);
+  /* If no file logging configured, try to write to fallback log file. */
+  if ((!zlog_default || !zlog_default->fp) &&
+      ((crashlog_fd = open_crashlog()) >= 0))
+    DUMP(crashlog_fd)
   if (!zlog_default)
-    DUMP(stderr)
+    DUMP(fileno(stderr))
   else
     {
       if ((PRI <= zlog_default->maxlvl[ZLOG_DEST_FILE]) && zlog_default->fp)
-        DUMP(zlog_default->fp)
+        DUMP(fileno(zlog_default->fp))
       if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
-        DUMP(stdout)
+        DUMP(fileno(stdout))
       /* Remove trailing '\n' for monitor and syslog */
       *--s = '\0';
       if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
@@ -353,25 +391,27 @@
   s = num_append(LOC,size);
   s = str_append(LOC," stack frames:\n");
 
-#define DUMP(FP) { \
+#define DUMP(FD) { \
   if (program_counter) \
     { \
-      write(fileno(FP),pclabel,sizeof(pclabel)-1); \
-      backtrace_symbols_fd(&program_counter, 1, fileno(FP)); \
+      write(FD, pclabel, sizeof(pclabel)-1); \
+      backtrace_symbols_fd(&program_counter, 1, FD); \
     } \
-  write(fileno(FP),buf,s-buf);	\
-  backtrace_symbols_fd(array, size, fileno(FP)); \
+  write(FD, buf, s-buf);	\
+  backtrace_symbols_fd(array, size, FD); \
 }
 
+  if (crashlog_fd >= 0)
+    DUMP(crashlog_fd)
   if (!zlog_default)
-    DUMP(stderr)
+    DUMP(fileno(stderr))
   else
     {
       if ((priority <= zlog_default->maxlvl[ZLOG_DEST_FILE]) &&
 	  zlog_default->fp)
-	DUMP(zlog_default->fp)
+	DUMP(fileno(zlog_default->fp))
       if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
-	DUMP(stdout)
+	DUMP(fileno(stdout))
       /* Remove trailing '\n' for monitor and syslog */
       *--s = '\0';
       if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
@@ -493,9 +533,21 @@
 _zlog_assert_failed (const char *assertion, const char *file,
 		     unsigned int line, const char *function)
 {
-  zlog_err("Assertion `%s' failed in file %s, line %u, function %s",
-	   assertion,file,line,(function ? function : "?"));
-  zlog_backtrace(LOG_ERR);
+  if (zlog_default && !zlog_default->fp)
+    {
+      /* Force fallback file logging. */
+      int fd;
+      FILE *fp;
+
+      if (((fd = open_crashlog()) >= 0) && ((fp = fdopen(fd, "w")) != NULL))
+	{
+	  zlog_default->fp = fp;
+	  zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR;
+        }
+    }
+  zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
+       assertion,file,line,(function ? function : "?"));
+  zlog_backtrace(LOG_CRIT);
   abort();
 }