2004-11-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>

	* log.h: Remove several unused fields from struct zlog.  Add comments
	  for other fields, and add one new field syslog_options that is
	  used in the new syslog_sigsafe implementation.
	* log.c: (syslog_sigsafe) New function to send syslog messages in
	  an async-signal safe way that can be used inside a signal handler.
	  (syslog_connect) New function to connect to syslog daemon inside a
	  signal handler.  This function supports only systems where /dev/log
	  is a unix datagram socket (e.g. not Solaris).
	  (zlog_signal) Call syslog_sigsafe if syslog logging is enabled.
	  (zlog_backtrace_sigsafe) Call syslog_sigsafe if syslog logging is
	  enabled.
	  (openzlog) Save syslog_options for use in syslog_sigsafe.
	  (num_append) Fix bug: handle 0 properly.
	  (hex_append) New function to print a u_long in hex format.
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 74862d2..8dde0eb 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,20 @@
+2004-11-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
+
+	* log.h: Remove several unused fields from struct zlog.  Add comments
+	  for other fields, and add one new field syslog_options that is
+	  used in the new syslog_sigsafe implementation.
+	* log.c: (syslog_sigsafe) New function to send syslog messages in
+	  an async-signal safe way that can be used inside a signal handler.
+	  (syslog_connect) New function to connect to syslog daemon inside a
+	  signal handler.  This function supports only systems where /dev/log
+	  is a unix datagram socket (e.g. not Solaris).
+	  (zlog_signal) Call syslog_sigsafe if syslog logging is enabled.
+	  (zlog_backtrace_sigsafe) Call syslog_sigsafe if syslog logging is
+	  enabled.
+	  (openzlog) Save syslog_options for use in syslog_sigsafe.
+	  (num_append) Fix bug: handle 0 properly.
+	  (hex_append) New function to print a u_long in hex format.
+
 2004-11-28 Hasso Tepper <hasso at quagga.net>
 
 	* command.h: DEFUN_DEPRECATED passes attribute to DEFUN as well.
diff --git a/lib/log.c b/lib/log.c
index 86e3833..d3106cb 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -24,6 +24,9 @@
 #include "log.h"
 #include "memory.h"
 #include "command.h"
+#ifndef SUNOS_5
+#include <sys/un.h>
+#endif
 
 struct zlog *zlog_default = NULL;
 
@@ -175,9 +178,11 @@
 num_append(char *s, int len, u_long x)
 {
   char buf[30];
-  char *t = &buf[29];
+  char *t;
 
-  *t = '\0';
+  if (!x)
+    return str_append(s,len,"0");
+  *(t = &buf[sizeof(buf)-1]) = '\0';
   while (x && (t > buf))
     {
       *--t = '0'+(x % 10);
@@ -186,14 +191,93 @@
   return str_append(s,len,t);
 }
 
-/* Note: the goal here is to use only async-signal-safe functions.
-   Needs to be enhanced to support syslog logging. */
+static char *
+hex_append(char *s, int len, u_long x)
+{
+  char buf[30];
+  char *t;
+
+  if (!x)
+    return str_append(s,len,"0");
+  *(t = &buf[sizeof(buf)-1]) = '\0';
+  while (x && (t > buf))
+    {
+      u_int cc = (x % 16);
+      *--t = ((cc < 10) ? ('0'+cc) : ('a'+cc-10));
+      x /= 16;
+    }
+  return str_append(s,len,t);
+}
+
+static int syslog_fd = -1;
+
+/* Needs to be enhanced to support Solaris. */
+static int
+syslog_connect(void)
+{
+#ifdef SUNOS_5
+  return -1;
+#else
+  int fd;
+  char *s;
+  struct sockaddr_un addr;
+
+  if ((fd = socket(AF_UNIX,SOCK_DGRAM,0)) < 0)
+    return -1;
+  addr.sun_family = AF_UNIX;
+#ifdef _PATH_LOG
+#define SYSLOG_SOCKET_PATH _PATH_LOG
+#else
+#define SYSLOG_SOCKET_PATH "/dev/log"
+#endif
+  s = str_append(addr.sun_path,sizeof(addr.sun_path),SYSLOG_SOCKET_PATH);
+#undef SYSLOG_SOCKET_PATH
+  *s = '\0';
+  if (connect(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
+    {
+      close(fd);
+      return -1;
+    }
+  return fd;
+#endif
+}
+
+static void
+syslog_sigsafe(int priority, const char *msg, size_t msglen)
+{
+  char buf[sizeof("<1234567890>ripngd[1234567890]: ")+msglen+50];
+  char *s;
+
+  if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0))
+    return;
+
+#define LOC s,buf+sizeof(buf)-s
+  s = buf;
+  s = str_append(LOC,"<");
+  s = num_append(LOC,priority);
+  s = str_append(LOC,">");
+  /* forget about the timestamp, too difficult in a signal handler */
+  s = str_append(LOC,zlog_default->ident);
+  if (zlog_default->syslog_options & LOG_PID)
+    {
+      s = str_append(LOC,"[");
+      s = num_append(LOC,getpid());
+      s = str_append(LOC,"]");
+    }
+  s = str_append(LOC,": ");
+  s = str_append(LOC,msg);
+  write(syslog_fd,buf,s-buf);
+#undef LOC
+}
+
+/* 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;
+  char *msgstart = buf;
 #define LOC s,buf+sizeof(buf)-s
 
   time(&now);
@@ -202,6 +286,7 @@
       s = str_append(LOC,zlog_proto_names[zlog_default->protocol]);
       *s++ = ':';
       *s++ = ' ';
+      msgstart = s;
     }
   s = str_append(LOC,"Received signal ");
   s = num_append(LOC,signo);
@@ -209,7 +294,8 @@
   s = num_append(LOC,now);
   s = str_append(LOC,"; ");
   s = str_append(LOC,action);
-  *s++ = '\n';
+  if (s < buf+sizeof(buf))
+    *s++ = '\n';
 
 #define DUMP(FP) write(fileno(FP),buf,s-buf);
   if (!zlog_default)
@@ -222,7 +308,11 @@
         DUMP(stdout)
       if (zlog_default->flags & ZLOG_STDERR)
         DUMP(stderr)
-      /* Is there a signal-safe way to send a syslog message? */
+      if (zlog_default->flags & ZLOG_SYSLOG)
+        {
+	  *--s = '\0';
+	  syslog_sigsafe(LOG_ERR|zlog_default->facility,msgstart,s-msgstart);
+	}
     }
 #undef DUMP
 
@@ -269,7 +359,23 @@
 	DUMP(stdout)
       if (zlog_default->flags & ZLOG_STDERR)
 	DUMP(stderr)
-      /* Is there a signal-safe way to send a syslog message? */
+      if (zlog_default->flags & ZLOG_SYSLOG)
+        {
+	  int i;
+	  *--s = '\0';
+	  syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
+	  /* Just print the function addresses. */
+	  for (i = 0; i < size; i++)
+	    {
+	      s = buf;
+	      s = str_append(LOC,"[bt ");
+	      s = num_append(LOC,i);
+	      s = str_append(LOC,"] 0x");
+	      s = hex_append(LOC,(u_long)(array[i]));
+	      *s = '\0';
+	      syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
+	    }
+        }
     }
 #undef DUMP
 #undef LOC
@@ -391,6 +497,7 @@
   zl->facility = syslog_facility;
   zl->maskpri = LOG_DEBUG;
   zl->record_priority = 0;
+  zl->syslog_options = syslog_flags;
 
   openlog (progname, syslog_flags, zl->facility);
   
diff --git a/lib/log.h b/lib/log.h
index 17b24cd..54cc2a6 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -46,18 +46,16 @@
 
 struct zlog 
 {
-  const char *ident;
+  const char *ident;	/* daemon name (first arg to openlog) */
   zlog_proto_t protocol;
-  int flags;
+  int flags;		/* mask indicating which destinations to log to */
   FILE *fp;
   char *filename;
-  int syslog;
-  int stat;
-  int connected;
-  int maskpri;		/* as per syslog setlogmask */
-  int priority;		/* as per syslog priority */
+  int maskpri;		/* discard messages with priority > maskpri */
   int facility;		/* as per syslog facility */
-  int record_priority;
+  int record_priority;	/* should messages logged through stdio include the
+  			   priority of the message? */
+  int syslog_options;	/* 2nd arg to openlog */
 };
 
 /* Message structure. */