From nobody@FreeBSD.org  Fri Feb 23 22:02:12 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 904B516A403
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 23 Feb 2007 22:02:12 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id 7399A13C4BE
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 23 Feb 2007 22:02:12 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l1NM2CDP029284
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 23 Feb 2007 22:02:12 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l1NM2Cuj029282;
	Fri, 23 Feb 2007 22:02:12 GMT
	(envelope-from nobody)
Message-Id: <200702232202.l1NM2Cuj029282@www.freebsd.org>
Date: Fri, 23 Feb 2007 22:02:12 GMT
From: Steven Kreuzer<skreuzer@f2o.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Reentrant syslog functions
X-Send-Pr-Version: www-3.0

>Number:         109478
>Category:       bin
>Synopsis:       [libc] [patch] adopt reentrant syslog functions from OpenBSD
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Fri Feb 23 22:10:05 GMT 2007
>Closed-Date:    
>Last-Modified:  Sun Apr  6 19:40:01 UTC 2014
>Originator:     Steven Kreuzer
>Release:        6.2-STABLE
>Organization:
>Environment:
FreeBSD escobar.exit2shell.com 6.2-STABLE FreeBSD 6.2-STABLE #3: Wed Feb  7 18:28:56 EST 2007     root@escobar.exit2shell.com:/usr/obj/usr/src/sys/ESCOBAR  i386
>Description:
The patch essentially takes OpenBSD's reentrant syslog functions  
(openlog_r, closelog_r, syslog_r and vsyslog_r) and makes them  
available in FreeBSD. Hopefully this will make building of packages  
such as spamd under FreeBSD easier since the source shouldn't require  
modifications.
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

Index: sys/sys/syslog.h
===================================================================
RCS file: /usr/share/cvs/freebsd/src/sys/sys/syslog.h,v
retrieving revision 1.26
diff -u -r1.26 syslog.h
--- sys/sys/syslog.h	7 Jan 2005 02:29:24 -0000	1.26
+++ sys/sys/syslog.h	7 Feb 2007 23:16:08 -0000
@@ -151,6 +151,20 @@
 };
 #endif
 
+/* Used by reentrant functions */
+
+struct syslog_data {
+        int     log_file;
+        int     connected;
+        int     opened;
+        int     log_stat;
+        const char      *log_tag;
+        int     log_fac;
+        int     log_mask;
+};
+
+#define SYSLOG_DATA_INIT {-1, 0, 0, 0, (const char *)0, LOG_USER, 0xff}
+
 #ifdef _KERNEL
 #define	LOG_PRINTF	-1	/* pseudo-priority to indicate use of printf */
 #endif
@@ -194,6 +208,12 @@
 int	setlogmask(int);
 void	syslog(int, const char *, ...) __printflike(2, 3);
 void	vsyslog(int, const char *, __va_list) __printflike(2, 0);
+void    closelog_r(struct syslog_data *);
+void    openlog_r(const char *, int, int, struct syslog_data *);
+int     setlogmask_r(int, struct syslog_data *);
+void    syslog_r(int, struct syslog_data *, const char *, ...)
+     __printflike(3, 4);
+void    vsyslog_r(int, struct syslog_data *, const char *, __va_list);
 __END_DECLS
 
 #endif /* !_KERNEL */
Index: lib/libc/gen/syslog.c
===================================================================
RCS file: /usr/share/cvs/freebsd/src/lib/libc/gen/syslog.c,v
retrieving revision 1.39
diff -u -r1.39 syslog.c
--- lib/libc/gen/syslog.c	9 Jan 2007 00:27:55 -0000	1.39
+++ lib/libc/gen/syslog.c	7 Feb 2007 23:16:43 -0000
@@ -56,14 +56,7 @@
 
 #include "libc_private.h"
 
-static int	LogFile = -1;		/* fd for log */
-static int	status;			/* connection status */
-static int	opened;			/* have done openlog() */
-static int	LogStat = 0;		/* status bits, set by openlog() */
-static const char *LogTag = NULL;	/* string to tag the entry with */
-static int	LogFacility = LOG_USER;	/* default facility code */
-static int	LogMask = 0xff;		/* mask of priorities to be logged */
-static pthread_mutex_t	syslog_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct syslog_data sdata = SYSLOG_DATA_INIT;
 
 #define	THREAD_LOCK()							\
 	do { 								\
@@ -74,9 +67,8 @@
 		if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex);	\
 	} while(0)
 
-static void	disconnectlog(void); /* disconnect from syslogd */
-static void	connectlog(void);	/* (re)connect to syslogd */
-static void	openlog_unlocked(const char *, int, int);
+static void	connectlog_r(struct syslog_data *data);
+static void	disconnectlog_r(struct syslog_data *data);
 
 enum {
 	NOCONN = 0,
@@ -93,29 +85,6 @@
 };
 
 /*
- * stdio write hook for writing to a static string buffer
- * XXX: Maybe one day, dynamically allocate it so that the line length
- *      is `unlimited'.
- */
-static int
-writehook(void *cookie, const char *buf, int len)
-{
-	struct bufcookie *h;	/* private `handle' */
-
-	h = (struct bufcookie *)cookie;
-	if (len > h->left) {
-		/* clip in case of wraparound */
-		len = h->left;
-	}
-	if (len > 0) {
-		(void)memcpy(h->base, buf, len); /* `write' it. */
-		h->base += len;
-		h->left -= len;
-	}
-	return len;
-}
-
-/*
  * syslog, vsyslog --
  *	print message on log file; output is intended for syslogd(8).
  */
@@ -132,166 +101,197 @@
 void
 vsyslog(int pri, const char *fmt, va_list ap)
 {
+	vsyslog_r(pri, &sdata, fmt, ap);
+}
+
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+        openlog_r(ident, logstat, logfac, &sdata);
+}
+
+void
+closelog(void)
+{
+        closelog_r(&sdata);
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask(int pmask)
+{
+        return setlogmask_r(pmask, &sdata);
+}
+
+/* Reentrant version of syslog, i.e. syslog_r() */
+
+void
+syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
+{
+        va_list ap;
+
+        va_start(ap, fmt);
+        vsyslog_r(pri, data, fmt, ap);
+        va_end(ap);
+}
+
+void
+vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
+{
 	int cnt;
-	char ch, *p;
+	char ch, *p, *t;
 	time_t now;
-	int fd, saved_errno;
-	char *stdp, tbuf[2048], fmt_cpy[1024], timbuf[26], errstr[64];
-	FILE *fp, *fmt_fp;
-	struct bufcookie tbuf_cookie;
-	struct bufcookie fmt_cookie;
+	int fd, saved_errno, error;
+#define	TBUF_LEN	2048
+#define	FMT_LEN		1024
+	char *stdp, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
+	int tbuf_left, fmt_left, prlen;
 
 #define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
 	/* Check for invalid bits. */
 	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
-		syslog(INTERNALLOG,
-		    "syslog: unknown facility/priority: %x", pri);
+		if (data == &sdata) {
+			syslog(INTERNALLOG,
+			    "syslog: unknown facility/priority: %x", pri);
+		} else {
+			syslog_r(INTERNALLOG, data,
+			    "syslog_r: unknown facility/priority: %x", pri);
+		}
 		pri &= LOG_PRIMASK|LOG_FACMASK;
 	}
 
-	saved_errno = errno;
-
-	THREAD_LOCK();
-
 	/* Check priority against setlogmask values. */
-	if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) {
-		THREAD_UNLOCK();
+	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
 		return;
-	}
+
+	saved_errno = errno;
 
 	/* Set default facility if none specified. */
 	if ((pri & LOG_FACMASK) == 0)
-		pri |= LogFacility;
+		pri |= data->log_fac;
 
-	/* Create the primary stdio hook */
-	tbuf_cookie.base = tbuf;
-	tbuf_cookie.left = sizeof(tbuf);
-	fp = fwopen(&tbuf_cookie, writehook);
-	if (fp == NULL) {
-		THREAD_UNLOCK();
-		return;
-	}
-
-	/* Build the message. */
-	(void)time(&now);
-	(void)fprintf(fp, "<%d>", pri);
-	(void)fprintf(fp, "%.15s ", ctime_r(&now, timbuf) + 4);
-	if (LogStat & LOG_PERROR) {
-		/* Transfer to string buffer */
-		(void)fflush(fp);
-		stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
-	}
-	if (LogTag == NULL)
-		LogTag = _getprogname();
-	if (LogTag != NULL)
-		(void)fprintf(fp, "%s", LogTag);
-	if (LogStat & LOG_PID)
-		(void)fprintf(fp, "[%d]", getpid());
-	if (LogTag != NULL) {
-		(void)fprintf(fp, ": ");
+	/* If we have been called through syslog(), no need for reentrancy. */
+	if (data == &sdata)
+		(void)time(&now);
+
+	p = tbuf;
+	tbuf_left = TBUF_LEN;
+
+#define	DEC()	\
+	do {					\
+		if (prlen < 0)			\
+			prlen = 0;		\
+		if (prlen >= tbuf_left)		\
+			prlen = tbuf_left - 1;	\
+		p += prlen;			\
+		tbuf_left -= prlen;		\
+	} while (0)
+
+	prlen = snprintf(p, tbuf_left, "<%d>", pri);
+	DEC();
+
+	/* 
+	 * syslogd will expand time automagically for reentrant case, and
+	 * for normal case, just do like before
+	 */
+	if (data == &sdata) {
+		prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
+		DEC();
+	}
+
+	if (data->log_stat & LOG_PERROR)
+		stdp = p;
+	if (data->log_tag == NULL)
+		data->log_tag = __progname;
+	if (data->log_tag != NULL) {
+		prlen = snprintf(p, tbuf_left, "%s", data->log_tag);
+		DEC();
+	}
+	if (data->log_stat & LOG_PID) {
+		prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid());
+		DEC();
+	}
+	if (data->log_tag != NULL) {
+		if (tbuf_left > 1) {
+			*p++ = ':';
+			tbuf_left--;
+		}
+		if (tbuf_left > 1) {
+			*p++ = ' ';
+			tbuf_left--;
+		}
 	}
 
-	/* Check to see if we can skip expanding the %m */
-	if (strstr(fmt, "%m")) {
-
-		/* Create the second stdio hook */
-		fmt_cookie.base = fmt_cpy;
-		fmt_cookie.left = sizeof(fmt_cpy) - 1;
-		fmt_fp = fwopen(&fmt_cookie, writehook);
-		if (fmt_fp == NULL) {
-			fclose(fp);
-			THREAD_UNLOCK();
-			return;
-		}
+	/* strerror() is not reentrant */
 
-		/*
-		 * Substitute error message for %m.  Be careful not to
-		 * molest an escaped percent "%%m".  We want to pass it
-		 * on untouched as the format is later parsed by vfprintf.
-		 */
-		for ( ; (ch = *fmt); ++fmt) {
-			if (ch == '%' && fmt[1] == 'm') {
-				++fmt;
-				strerror_r(saved_errno, errstr, sizeof(errstr));
-				fputs(errstr, fmt_fp);
-			} else if (ch == '%' && fmt[1] == '%') {
-				++fmt;
-				fputc(ch, fmt_fp);
-				fputc(ch, fmt_fp);
+	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
+		if (ch == '%' && fmt[1] == 'm') {
+			++fmt;
+			if (data == &sdata) {
+				prlen = snprintf(t, fmt_left, "%s",
+				    strerror(saved_errno)); 
 			} else {
-				fputc(ch, fmt_fp);
+				prlen = snprintf(t, fmt_left, "Error %d",
+				    saved_errno); 
+			}
+			if (prlen < 0)
+				prlen = 0;
+			if (prlen >= fmt_left)
+				prlen = fmt_left - 1;
+			t += prlen;
+			fmt_left -= prlen;
+		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
+			*t++ = '%';
+			*t++ = '%';
+			fmt++;
+			fmt_left -= 2;
+		} else {
+			if (fmt_left > 1) {
+				*t++ = ch;
+				fmt_left--;
 			}
 		}
-
-		/* Null terminate if room */
-		fputc(0, fmt_fp);
-		fclose(fmt_fp);
-
-		/* Guarantee null termination */
-		fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
-
-		fmt = fmt_cpy;
 	}
+	*t = '\0';
 
-	(void)vfprintf(fp, fmt, ap);
-	(void)fclose(fp);
-
-	cnt = sizeof(tbuf) - tbuf_cookie.left;
-
-	/* Remove a trailing newline */
-	if (tbuf[cnt - 1] == '\n')
-		cnt--;
+	prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
+	DEC();
+	cnt = p - tbuf;
 
 	/* Output to stderr if requested. */
-	if (LogStat & LOG_PERROR) {
+	if (data->log_stat & LOG_PERROR) {
 		struct iovec iov[2];
-		struct iovec *v = iov;
 
-		v->iov_base = stdp;
-		v->iov_len = cnt - (stdp - tbuf);
-		++v;
-		v->iov_base = "\n";
-		v->iov_len = 1;
+		iov[0].iov_base = stdp;
+		iov[0].iov_len = cnt - (stdp - tbuf);
+		iov[1].iov_base = "\n";
+		iov[1].iov_len = 1;
 		(void)_writev(STDERR_FILENO, iov, 2);
 	}
 
 	/* Get connected, output the message to the local logger. */
-	if (!opened)
-		openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0);
-	connectlog();
+	if (!data->opened)
+		openlog_r(data->log_tag, data->log_stat, 0, data);
+	connectlog_r(data);
 
 	/*
-	 * If the send() failed, there are two likely scenarios: 
+	 * If the send() failed, there are two likely scenarios:
 	 *  1) syslogd was restarted
-	 *  2) /var/run/log is out of socket buffer space, which
-	 *     in most cases means local DoS.
-	 * We attempt to reconnect to /var/run/log to take care of
+	 *  2) /dev/log is out of socket buffer space
+	 * We attempt to reconnect to /dev/log to take care of
 	 * case #1 and keep send()ing data to cover case #2
 	 * to give syslogd a chance to empty its socket buffer.
-	 *
-	 * If we are working with a priveleged socket, then take
-	 * only one attempt, because we don't want to freeze a
-	 * critical application like su(1) or sshd(8).
-	 *
 	 */
-
-	if (send(LogFile, tbuf, cnt, 0) < 0) {
+	if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
 		if (errno != ENOBUFS) {
-			disconnectlog();
-			connectlog();
+			disconnectlog_r(data);
+			connectlog_r(data);
 		}
 		do {
 			_usleep(1);
-			if (send(LogFile, tbuf, cnt, 0) >= 0) {
-				THREAD_UNLOCK();
-				return;
-			}
-			if (status == CONNPRIV)
+			if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
 				break;
 		} while (errno == ENOBUFS);
-	} else {
-		THREAD_UNLOCK();
-		return;
 	}
 
 	/*
@@ -299,137 +299,95 @@
 	 * as a blocking console should not stop other processes.
 	 * Make sure the error reported is the one from the syslogd failure.
 	 */
-	if (LogStat & LOG_CONS &&
+	if (error == -1 && (data->log_stat & LOG_CONS) &&
 	    (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
 		struct iovec iov[2];
-		struct iovec *v = iov;
-
+		
 		p = strchr(tbuf, '>') + 1;
-		v->iov_base = p;
-		v->iov_len = cnt - (p - tbuf);
-		++v;
-		v->iov_base = "\r\n";
-		v->iov_len = 2;
+		iov[0].iov_base = p;
+		iov[0].iov_len = cnt - (p - tbuf);
+		iov[1].iov_base = "\r\n";
+		iov[1].iov_len = 2;
 		(void)_writev(fd, iov, 2);
 		(void)_close(fd);
 	}
 
-	THREAD_UNLOCK();
+	if (data != &sdata)
+		closelog_r(data);
 }
 
-/* Should be called with mutex acquired */
 static void
-disconnectlog(void)
+disconnectlog_r(struct syslog_data *data)
 {
-	/*
-	 * If the user closed the FD and opened another in the same slot,
-	 * that's their problem.  They should close it before calling on
-	 * system services.
-	 */
-	if (LogFile != -1) {
-		_close(LogFile);
-		LogFile = -1;
-	}
-	status = NOCONN;			/* retry connect */
+        /*
+         * If the user closed the FD and opened another in the same slot,
+         * that's their problem.  They should close it before calling on
+         * system services.
+         */
+        if (data->log_file != -1) {
+                _close(data->log_file);
+                data->log_file = -1;
+        }
+        data->connected = 0;            /* retry connect */
 }
 
-/* Should be called with mutex acquired */
 static void
-connectlog(void)
+connectlog_r(struct syslog_data *data)
 {
-	struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
-
-	if (LogFile == -1) {
-		if ((LogFile = _socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
-			return;
-		(void)_fcntl(LogFile, F_SETFD, 1);
-	}
-	if (LogFile != -1 && status == NOCONN) {
-		SyslogAddr.sun_len = sizeof(SyslogAddr);
-		SyslogAddr.sun_family = AF_UNIX;
-
-		/*
-		 * First try priveleged socket. If no success,
-		 * then try default socket.
-		 */
-		(void)strncpy(SyslogAddr.sun_path, _PATH_LOG_PRIV,
-		    sizeof SyslogAddr.sun_path);
-		if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
-		    sizeof(SyslogAddr)) != -1)
-			status = CONNPRIV;
-
-		if (status == NOCONN) {
-			(void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
-			    sizeof SyslogAddr.sun_path);
-			if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
-			    sizeof(SyslogAddr)) != -1)
-				status = CONNDEF;
-		}
-
-		if (status == NOCONN) {
-			/*
-			 * Try the old "/dev/log" path, for backward
-			 * compatibility.
-			 */
-			(void)strncpy(SyslogAddr.sun_path, _PATH_OLDLOG,
-			    sizeof SyslogAddr.sun_path);
-			if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
-			    sizeof(SyslogAddr)) != -1)
-				status = CONNDEF;
-		}
+        struct sockaddr_un SyslogAddr;  /* AF_UNIX address of local logger */
 
-		if (status == NOCONN) {
-			(void)_close(LogFile);
-			LogFile = -1;
-		}
-	}
+        if (data->log_file == -1) {
+                if ((data->log_file = _socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
+                        return;
+                (void)_fcntl(data->log_file, F_SETFD, 1);
+        }
+        if (data->log_file != -1 && !data->connected) {
+                memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
+                SyslogAddr.sun_len = sizeof(SyslogAddr);
+                SyslogAddr.sun_family = AF_UNIX;
+                strlcpy(SyslogAddr.sun_path, _PATH_LOG,
+                    sizeof(SyslogAddr.sun_path));
+                if (_connect(data->log_file, (struct sockaddr *)&SyslogAddr,
+                    sizeof(SyslogAddr)) == -1) {
+                        (void)_close(data->log_file);
+                        data->log_file = -1;
+                } else
+                        data->connected = 1;
+        }
 }
 
-static void
-openlog_unlocked(const char *ident, int logstat, int logfac)
+void
+openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
 {
-	if (ident != NULL)
-		LogTag = ident;
-	LogStat = logstat;
-	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
-		LogFacility = logfac;
+        if (ident != NULL)
+                data->log_tag = ident;
+        data->log_stat = logstat;
+        if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+                data->log_fac = logfac;
 
-	if (LogStat & LOG_NDELAY)	/* open immediately */
-		connectlog();
+        if (data->log_stat & LOG_NDELAY)        /* open immediately */
+                connectlog_r(data);
 
-	opened = 1;	/* ident and facility has been set */
-}
-
-void
-openlog(const char *ident, int logstat, int logfac)
-{
-	THREAD_LOCK();
-	openlog_unlocked(ident, logstat, logfac);
-	THREAD_UNLOCK();
+        data->opened = 1;       /* ident and facility has been set */
 }
 
-
 void
-closelog(void)
+closelog_r(struct syslog_data *data)
 {
-	THREAD_LOCK();
-	(void)_close(LogFile);
-	LogFile = -1;
-	LogTag = NULL;
-	status = NOCONN;
-	THREAD_UNLOCK();
+        (void)_close(data->log_file);
+        data->log_file = -1;
+        data->connected = 0;
+        data->log_tag = NULL;
 }
 
 /* setlogmask -- set the log mask level */
 int
-setlogmask(int pmask)
+setlogmask_r(int pmask, struct syslog_data *data)
 {
-	int omask;
+        int omask;
 
-	THREAD_LOCK();
-	omask = LogMask;
-	if (pmask != 0)
-		LogMask = pmask;
-	THREAD_UNLOCK();
-	return (omask);
+        omask = data->log_mask;
+        if (pmask != 0)
+                data->log_mask = pmask;
+        return (omask);
 }

>Release-Note:
>Audit-Trail:

From: Jilles Tjoelker <jilles@stack.nl>
To: bug-followup@FreeBSD.org, skreuzer@f2o.org
Cc:  
Subject: Re: bin/109478: [libc] [patch] adopt reentrant syslog functions from
 OpenBSD
Date: Sun, 6 Apr 2014 21:32:34 +0200

 In FreeBSD PR bin/109478, you wrote:
 > The patch essentially takes OpenBSD's reentrant syslog functions
 > (openlog_r, closelog_r, syslog_r and vsyslog_r) and makes them
 > available in FreeBSD. Hopefully this will make building of packages
 > such as spamd under FreeBSD easier since the source shouldn't require
 > modifications.
 
 There may be some point in syslog functions without global data, but I
 think OpenBSD's API exposes way too much information about the
 implementation and is therefore bad for ABI stability and encapsulation.
 
 Specifically, this kind of struct seems bad (in the header file):
 > +/* Used by reentrant functions */
 > +
 > +struct syslog_data {
 > +        int     log_file;
 > +        int     connected;
 > +        int     opened;
 > +        int     log_stat;
 > +        const char      *log_tag;
 > +        int     log_fac;
 > +        int     log_mask;
 > +};
 > +
 > +#define SYSLOG_DATA_INIT {-1, 0, 0, 0, (const char *)0, LOG_USER, 0xff}
 
 A better way would be for openlog_r() to allocate something and
 closelog_r() to free it again.
 
 I don't really like the word "reentrant"; I prefer terms like
 "thread-safe" and "async-signal safe" with clear definitions. It seems
 that async-signal safe is meant here, since our syslog implementation is
 thread-safe by locking.
 
 -- 
 Jilles Tjoelker
>Unformatted:
