Module Name:    src
Committed By:   christos
Date:           Thu Jan 12 00:38:01 UTC 2017

Modified Files:
        src/lib/libc/gen: Makefile.inc syslog.c
Added Files:
        src/lib/libc/gen: syslog_private.h syslog_ss.c xsyslog.c

Log Message:
Split syslog.c to:

- syslog_ss.c *_ss api functions (don't use stdio, time)
- syslog.c: *syslog* non _ss api functions (use stdio, time)
- xsyslog.c> common guts.

The motivation for this is not to drag in stdio/locale/floating point/time
for every binary, since syslog_ss() is used in __stack_check_fail() for SSP.


To generate a diff of this commit:
cvs rdiff -u -r1.196 -r1.197 src/lib/libc/gen/Makefile.inc
cvs rdiff -u -r1.55 -r1.56 src/lib/libc/gen/syslog.c
cvs rdiff -u -r0 -r1.1 src/lib/libc/gen/syslog_private.h \
    src/lib/libc/gen/syslog_ss.c src/lib/libc/gen/xsyslog.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/gen/Makefile.inc
diff -u src/lib/libc/gen/Makefile.inc:1.196 src/lib/libc/gen/Makefile.inc:1.197
--- src/lib/libc/gen/Makefile.inc:1.196	Tue Oct  4 05:41:41 2016
+++ src/lib/libc/gen/Makefile.inc	Wed Jan 11 19:38:01 2017
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile.inc,v 1.196 2016/10/04 09:41:41 kamil Exp $
+#	$NetBSD: Makefile.inc,v 1.197 2017/01/12 00:38:01 christos Exp $
 #	from: @(#)Makefile.inc	8.6 (Berkeley) 5/4/95
 
 # gen sources
@@ -32,12 +32,12 @@ SRCS+=	alarm.c alphasort.c arc4random.c 
 	siglist.c signal.c signame.c sigrelse.c \
 	sigset.c sigsetops.c sleep.c \
 	stringlist.c sysconf.c sysctl.c sysctlbyname.c sysctlgetmibinfo.c \
-	sysctlnametomib.c syslog.c telldir.c time.c timespec_get.c \
+	sysctlnametomib.c syslog.c syslog_ss.c telldir.c time.c timespec_get.c \
 	times.c toascii.c tolower_.c ttyname.c ttyslot.c toupper_.c ualarm.c \
 	ulimit.c uname.c unvis.c usleep.c utime.c utimens.c utmp.c \
 	utmpx.c valloc.c vis.c wait.c wait3.c waitid.c waitpid.c warn.c \
-	warnx.c warnc.c vwarn.c vwarnx.c vwarnc.c verr.c verrx.c verrc.c \
-	wordexp.c
+	warnx.c warnc.c wordexp.c xsyslog.c \
+	vwarn.c vwarnx.c vwarnc.c verr.c verrx.c verrc.c
 
 # uses alloca
 COPTS.execvp.c = -Wno-stack-protector

Index: src/lib/libc/gen/syslog.c
diff -u src/lib/libc/gen/syslog.c:1.55 src/lib/libc/gen/syslog.c:1.56
--- src/lib/libc/gen/syslog.c:1.55	Mon Oct 26 07:44:30 2015
+++ src/lib/libc/gen/syslog.c	Wed Jan 11 19:38:01 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: syslog.c,v 1.55 2015/10/26 11:44:30 roy Exp $	*/
+/*	$NetBSD: syslog.c,v 1.56 2017/01/12 00:38:01 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1988, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)syslog.c	8.5 (Berkeley) 4/29/95";
 #else
-__RCSID("$NetBSD: syslog.c,v 1.55 2015/10/26 11:44:30 roy Exp $");
+__RCSID("$NetBSD: syslog.c,v 1.56 2017/01/12 00:38:01 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -48,6 +48,7 @@ __RCSID("$NetBSD: syslog.c,v 1.55 2015/1
 #include <netdb.h>
 
 #include <errno.h>
+#include <stdio.h>
 #include <fcntl.h>
 #include <paths.h>
 #include <stdarg.h>
@@ -56,32 +57,61 @@ __RCSID("$NetBSD: syslog.c,v 1.55 2015/1
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+
+#include "syslog_private.h"
 #include "reentrant.h"
 #include "extern.h"
 
 #ifdef __weak_alias
-__weak_alias(closelog,_closelog)
-__weak_alias(openlog,_openlog)
-__weak_alias(setlogmask,_setlogmask)
 __weak_alias(syslog,_syslog)
 __weak_alias(vsyslog,_vsyslog)
 __weak_alias(syslogp,_syslogp)
 __weak_alias(vsyslogp,_vsyslogp)
 #endif
 
-static struct syslog_data sdata = SYSLOG_DATA_INIT;
-
-static void	openlog_unlocked_r(const char *, int, int,
-    struct syslog_data *);
-static void	disconnectlog_r(struct syslog_data *);
-static void	connectlog_r(struct syslog_data *);
-
-#define LOG_SIGNAL_SAFE	(int)0x80000000
-
+static size_t
+timefun(char *p, size_t tbuf_left)
+{
+	struct timeval tv;
+	time_t now;
+	struct tm tmnow;
+	size_t prlen;
+	char *op = p;
 
-#ifdef _REENTRANT
-static mutex_t	syslog_mutex = MUTEX_INITIALIZER;
+	if (gettimeofday(&tv, NULL) == -1)
+		return snprintf_ss(p, tbuf_left, "-");
+	
+	/* strftime() implies tzset(), localtime_r() doesn't. */
+	tzset();
+	now = (time_t) tv.tv_sec;
+	localtime_r(&now, &tmnow);
+
+	prlen = strftime(p, tbuf_left, "%FT%T", &tmnow);
+	DEC();
+	prlen = snprintf(p, tbuf_left, ".%06ld", (long)tv.tv_usec);
+	DEC();
+	prlen = strftime(p, tbuf_left-1, "%z", &tmnow);
+	/* strftime gives eg. "+0200", but we need "+02:00" */
+	if (prlen == 5) {
+		p[prlen+1] = p[prlen];
+		p[prlen]   = p[prlen-1];
+		p[prlen-1] = p[prlen-2];
+		p[prlen-2] = ':';
+		prlen += 1;
+	}
+	DEC();
+	return (size_t)(p - op);
+}
+
+static struct syslog_fun _syslog_fun = {
+	timefun,
+	strerror_r,
+#ifndef __lint__
+	_vsnprintf,
+#else
+	vsnprintf,
 #endif
+};
 
 /*
  * syslog, vsyslog --
@@ -93,14 +123,14 @@ syslog(int pri, const char *fmt, ...)
 	va_list ap;
 
 	va_start(ap, fmt);
-	vsyslog(pri, fmt, ap);
+	_vxsyslogp_r(pri, &_syslog_fun, &_syslog_data, NULL, NULL, fmt, ap);
 	va_end(ap);
 }
 
 void
 vsyslog(int pri, const char *fmt, va_list ap)
 {
-	vsyslog_r(pri, &sdata, fmt, ap);
+	_vxsyslogp_r(pri, &_syslog_fun, &_syslog_data, NULL, NULL, fmt, ap);
 }
 
 /*
@@ -113,44 +143,33 @@ syslogp(int pri, const char *msgid, cons
 	va_list ap;
 
 	va_start(ap, msgfmt);
-	vsyslogp(pri, msgid, sdfmt, msgfmt, ap);
+	_vxsyslogp_r(pri, &_syslog_fun, &_syslog_data,
+	    msgid, sdfmt, msgfmt, ap);
 	va_end(ap);
 }
 
 void
-vsyslogp(int pri, const char *msgid, const char *sdfmt, const char *msgfmt, va_list ap)
+vsyslogp(int pri, const char *msgid, const char *sdfmt, const char *msgfmt,
+    va_list ap)
 {
-	vsyslogp_r(pri, &sdata, msgid, sdfmt, msgfmt, ap);
+	_vxsyslogp_r(pri, &_syslog_fun, &_syslog_data,
+	    msgid, sdfmt, msgfmt, 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)
+vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
+    const char *sdfmt, const char *msgfmt, va_list ap)
 {
-	return setlogmask_r(pmask, &sdata);
+	_vxsyslogp_r(pri, &_syslog_fun, data, msgid, sdfmt, msgfmt, ap);
 }
 
-/* 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);
+	_vxsyslogp_r(pri, &_syslog_fun, data, NULL, NULL, fmt, ap);
 	va_end(ap);
 }
 
@@ -161,409 +180,12 @@ syslogp_r(int pri, struct syslog_data *d
 	va_list ap;
 
 	va_start(ap, msgfmt);
-	vsyslogp_r(pri, data, msgid, sdfmt, msgfmt, ap);
-	va_end(ap);
-}
-
-void
-syslog_ss(int pri, struct syslog_data *data, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vsyslog_r(pri | LOG_SIGNAL_SAFE, data, fmt, ap);
-	va_end(ap);
-}
-
-void
-syslogp_ss(int pri, struct syslog_data *data, const char *msgid,
-	const char *sdfmt, const char *msgfmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, msgfmt);
-	vsyslogp_r(pri | LOG_SIGNAL_SAFE, data, msgid, sdfmt, msgfmt, ap);
+	_vxsyslogp_r(pri, &_syslog_fun, data, msgid, sdfmt, msgfmt, ap);
 	va_end(ap);
 }
 
 void
-vsyslog_ss(int pri, struct syslog_data *data, const char *fmt, va_list ap)
-{
-	vsyslog_r(pri | LOG_SIGNAL_SAFE, data, fmt, ap);
-}
-
-void
-vsyslogp_ss(int pri, struct syslog_data *data, const char *msgid,
-	const char *sdfmt, const char *msgfmt, va_list ap)
-{
-	vsyslogp_r(pri | LOG_SIGNAL_SAFE, data, msgid, sdfmt, msgfmt, ap);
-}
-
-
-void
 vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
 {
-	vsyslogp_r(pri, data, NULL, NULL, fmt, ap);
-}
-
-void
-vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
-	const char *sdfmt, const char *msgfmt, va_list ap)
-{
-	static const char BRCOSP[] = "]: ";
-	static const char CRLF[] = "\r\n";
-	size_t cnt, prlen, tries;
-	char ch, *p, *t;
-	struct timeval tv;
-	struct tm tmnow;
-	time_t now;
-	int fd, saved_errno;
-#define TBUF_LEN	2048
-#define FMT_LEN		1024
-#define MAXTRIES	10
-	char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN], fmt_cat[FMT_LEN] = "";
-	size_t tbuf_left, fmt_left, msgsdlen;
-	char *fmt = fmt_cat;
-	int signal_safe = pri & LOG_SIGNAL_SAFE;
-	struct iovec iov[7];	/* prog + [ + pid + ]: + fmt + crlf */
-	int opened, iovcnt;
-
-	pri &= ~LOG_SIGNAL_SAFE;
-
-#define INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
-	/* Check for invalid bits. */
-	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
-		syslog_r(INTERNALLOG | signal_safe, data,
-		    "syslog_r: unknown facility/priority: %x", pri);
-		pri &= LOG_PRIMASK|LOG_FACMASK;
-	}
-
-	/* Check priority against setlogmask values. */
-	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 |= data->log_fac;
-
-	/* Build the message. */
-	p = tbuf;
-	tbuf_left = TBUF_LEN;
-
-#define DEC()							\
-	do {							\
-		if (prlen >= tbuf_left)				\
-			prlen = tbuf_left - 1;			\
-		p += prlen;					\
-		tbuf_left -= prlen;				\
-	} while (/*CONSTCOND*/0)
-
-	prlen = snprintf_ss(p, tbuf_left, "<%d>1 ", pri);
-	DEC();
-
-	if (!signal_safe && (gettimeofday(&tv, NULL) != -1)) {
-		/* strftime() implies tzset(), localtime_r() doesn't. */
-		tzset();
-		now = (time_t) tv.tv_sec;
-		localtime_r(&now, &tmnow);
-
-		prlen = strftime(p, tbuf_left, "%FT%T", &tmnow);
-		DEC();
-		prlen = snprintf(p, tbuf_left, ".%06ld", (long)tv.tv_usec);
-		DEC();
-		prlen = strftime(p, tbuf_left-1, "%z", &tmnow);
-		/* strftime gives eg. "+0200", but we need "+02:00" */
-		if (prlen == 5) {
-			p[prlen+1] = p[prlen];
-			p[prlen]   = p[prlen-1];
-			p[prlen-1] = p[prlen-2];
-			p[prlen-2] = ':';
-			prlen += 1;
-		}
-	} else {
-		prlen = snprintf_ss(p, tbuf_left, "-");
-#if 0
-		/*
-		 * if gmtime_r() was signal-safe we could output
-		 * the UTC-time:
-		 */
-		gmtime_r(&now, &tmnow);
-		prlen = strftime(p, tbuf_left, "%FT%TZ", &tmnow);
-#endif
-	}
-
-	if (data == &sdata)
-		mutex_lock(&syslog_mutex);
-
-	if (data->log_hostname[0] == '\0' && gethostname(data->log_hostname,
-	    sizeof(data->log_hostname)) == -1) {
-		/* can this really happen? */
-		data->log_hostname[0] = '-';
-		data->log_hostname[1] = '\0';
-	}
-
-	DEC();
-	prlen = snprintf_ss(p, tbuf_left, " %s ", data->log_hostname);
-
-	if (data->log_tag == NULL)
-		data->log_tag = getprogname();
-
-	DEC();
-	prlen = snprintf_ss(p, tbuf_left, "%s ",
-	    data->log_tag ? data->log_tag : "-");
-
-	if (data == &sdata)
-		mutex_unlock(&syslog_mutex);
-
-	if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
-		iovcnt = 0;
-		iov[iovcnt].iov_base = p;
-		iov[iovcnt].iov_len = prlen - 1;
-		iovcnt++;
-	}
-	DEC();
-
-	if (data->log_stat & LOG_PID) {
-		prlen = snprintf_ss(p, tbuf_left, "%d ", getpid());
-		if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
-			iov[iovcnt].iov_base = __UNCONST("[");
-			iov[iovcnt].iov_len = 1;
-			iovcnt++;
-			iov[iovcnt].iov_base = p;
-			iov[iovcnt].iov_len = prlen - 1;
-			iovcnt++;
-			iov[iovcnt].iov_base = __UNCONST(BRCOSP);
-			iov[iovcnt].iov_len = 3;
-			iovcnt++;
-		}
-	} else {
-		prlen = snprintf_ss(p, tbuf_left, "- ");
-		if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
-			iov[iovcnt].iov_base = __UNCONST(BRCOSP + 1);
-			iov[iovcnt].iov_len = 2;
-			iovcnt++;
-		}
-	}
-	DEC();
-
-	/*
-	 * concat the format strings, then use one vsnprintf()
-	 */
-	if (msgid != NULL && *msgid != '\0') {
-		strlcat(fmt_cat, msgid, FMT_LEN);
-		strlcat(fmt_cat, " ", FMT_LEN);
-	} else
-		strlcat(fmt_cat, "- ", FMT_LEN);
-
-	if (sdfmt != NULL && *sdfmt != '\0') {
-		strlcat(fmt_cat, sdfmt, FMT_LEN);
-	} else
-		strlcat(fmt_cat, "-", FMT_LEN);
-
-	if (data->log_stat & (LOG_PERROR|LOG_CONS))
-		msgsdlen = strlen(fmt_cat) + 1;
-	else
-		msgsdlen = 0;	/* XXX: GCC */
-
-	if (msgfmt != NULL && *msgfmt != '\0') {
-		strlcat(fmt_cat, " ", FMT_LEN);
-		strlcat(fmt_cat, msgfmt, FMT_LEN);
-	}
-
-	/*
-	 * We wouldn't need this mess if printf handled %m, or if
-	 * strerror() had been invented before syslog().
-	 */
-	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt) != '\0'; ++fmt) {
-		if (ch == '%' && fmt[1] == 'm') {
-			const char *s;
-
-			if (signal_safe || (s = strerror(saved_errno)) == NULL)
-				prlen = snprintf_ss(t, fmt_left, "Error %d",
-				    saved_errno);
-			else
-				prlen = strlcpy(t, s, fmt_left);
-			if (prlen >= fmt_left)
-				prlen = fmt_left - 1;
-			t += prlen;
-			fmt++;
-			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--;
-			}
-		}
-	}
-	*t = '\0';
-
-	if (signal_safe)
-		prlen = vsnprintf_ss(p, tbuf_left, fmt_cpy, ap);
-	else
-		prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
-
-	if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
-		iov[iovcnt].iov_base = p + msgsdlen;
-		iov[iovcnt].iov_len = prlen - msgsdlen;
-		iovcnt++;
-	}
-
-	DEC();
-	cnt = p - tbuf;
-
-	/* Output to stderr if requested. */
-	if (data->log_stat & LOG_PERROR) {
-		iov[iovcnt].iov_base = __UNCONST(CRLF + 1);
-		iov[iovcnt].iov_len = 1;
-		(void)writev(STDERR_FILENO, iov, iovcnt + 1);
-	}
-
-	/* Get connected, output the message to the local logger. */
-	if (data == &sdata)
-		mutex_lock(&syslog_mutex);
-	opened = !data->log_opened;
-	if (opened)
-		openlog_unlocked_r(data->log_tag, data->log_stat, 0, data);
-	connectlog_r(data);
-
-	/*
-	 * If the send() failed, there are two likely scenarios:
-	 *  1) syslogd was restarted
-	 *  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.
-	 */
-	for (tries = 0; tries < MAXTRIES; tries++) {
-		if (send(data->log_file, tbuf, cnt, 0) != -1)
-			break;
-		if (errno != ENOBUFS) {
-			disconnectlog_r(data);
-			connectlog_r(data);
-		} else
-			(void)usleep(1);
-	}
-
-	/*
-	 * Output the message to the console; try not to block
-	 * as a blocking console should not stop other processes.
-	 * Make sure the error reported is the one from the syslogd failure.
-	 */
-	if (tries == MAXTRIES && (data->log_stat & LOG_CONS) &&
-	    (fd = open(_PATH_CONSOLE,
-		O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0)) >= 0) {
-		iov[iovcnt].iov_base = __UNCONST(CRLF);
-		iov[iovcnt].iov_len = 2;
-		(void)writev(fd, iov, iovcnt + 1);
-		(void)close(fd);
-	}
-
-	if (data == &sdata)
-		mutex_unlock(&syslog_mutex);
-
-	if (data != &sdata && opened) {
-		/* preserve log tag */
-		const char *ident = data->log_tag;
-		closelog_r(data);
-		data->log_tag = ident;
-	}
-}
-
-static 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 (data->log_file != -1) {
-		(void)close(data->log_file);
-		data->log_file = -1;
-	}
-	data->log_connected = 0;		/* retry connect */
-}
-
-static void
-connectlog_r(struct syslog_data *data)
-{
-	/* AF_UNIX address of local logger */
-	static const struct sockaddr_un sun = {
-		.sun_family = AF_LOCAL,
-		.sun_len = sizeof(sun),
-		.sun_path = _PATH_LOG,
-	};
-
-	if (data->log_file == -1 || fcntl(data->log_file, F_GETFL, 0) == -1) {
-		if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
-		    0)) == -1)
-			return;
-		data->log_connected = 0;
-	}
-	if (!data->log_connected) {
-		if (connect(data->log_file,
-		    (const struct sockaddr *)(const void *)&sun,
-		    (socklen_t)sizeof(sun)) == -1) {
-			(void)close(data->log_file);
-			data->log_file = -1;
-		} else
-			data->log_connected = 1;
-	}
-}
-
-static void
-openlog_unlocked_r(const char *ident, int logstat, int logfac,
-    struct syslog_data *data)
-{
-	if (ident != NULL)
-		data->log_tag = ident;
-	data->log_stat = logstat;
-	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
-		data->log_fac = logfac;
-
-	if (data->log_stat & LOG_NDELAY)	/* open immediately */
-		connectlog_r(data);
-
-	data->log_opened = 1;
-}
-
-void
-openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
-{
-	if (data == &sdata)
-		mutex_lock(&syslog_mutex);
-	openlog_unlocked_r(ident, logstat, logfac, data);
-	if (data == &sdata)
-		mutex_unlock(&syslog_mutex);
-}
-
-void
-closelog_r(struct syslog_data *data)
-{
-	if (data == &sdata)
-		mutex_lock(&syslog_mutex);
-	(void)close(data->log_file);
-	data->log_file = -1;
-	data->log_connected = 0;
-	data->log_tag = NULL;
-	if (data == &sdata)
-		mutex_unlock(&syslog_mutex);
-}
-
-int
-setlogmask_r(int pmask, struct syslog_data *data)
-{
-	int omask;
-
-	omask = data->log_mask;
-	if (pmask != 0)
-		data->log_mask = pmask;
-	return omask;
+	_vxsyslogp_r(pri, &_syslog_fun, data, NULL, NULL, fmt, ap);
 }

Added files:

Index: src/lib/libc/gen/syslog_private.h
diff -u /dev/null src/lib/libc/gen/syslog_private.h:1.1
--- /dev/null	Wed Jan 11 19:38:01 2017
+++ src/lib/libc/gen/syslog_private.h	Wed Jan 11 19:38:01 2017
@@ -0,0 +1,50 @@
+/*	$NetBSD: syslog_private.h,v 1.1 2017/01/12 00:38:01 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEC()							\
+	do {							\
+		if (prlen >= tbuf_left)				\
+			prlen = tbuf_left - 1;			\
+		p += prlen;					\
+		tbuf_left -= prlen;				\
+	} while (/*CONSTCOND*/0)
+
+struct syslog_fun {
+	size_t (*timefun)(char *, size_t);
+	int  (*errfun)(int, char *, size_t);
+	int __printflike(3, 0) (*prfun)(char *, size_t, const char *, va_list);
+};
+
+void _vxsyslogp_r(int , struct syslog_fun *, struct syslog_data *,
+    const char *, const char *, const char *, va_list);
+
+extern struct syslog_data _syslog_data;
+extern struct syslog_fun _syslog_ss_fun;
Index: src/lib/libc/gen/syslog_ss.c
diff -u /dev/null src/lib/libc/gen/syslog_ss.c:1.1
--- /dev/null	Wed Jan 11 19:38:01 2017
+++ src/lib/libc/gen/syslog_ss.c	Wed Jan 11 19:38:01 2017
@@ -0,0 +1,95 @@
+/*	$NetBSD: syslog_ss.c,v 1.1 2017/01/12 00:38:01 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: syslog_ss.c,v 1.1 2017/01/12 00:38:01 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <stdio.h>
+#include "extern.h"
+#include "syslog_private.h"
+
+
+static size_t
+timefun_ss(char *p, size_t tbuf_left)
+{
+	return snprintf_ss(p, tbuf_left, "-");
+#if 0
+	/*
+	 * if gmtime_r() was signal-safe we could output
+	 * the UTC-time:
+	 */
+	gmtime_r(&now, &tmnow);
+	prlen = strftime(p, tbuf_left, "%FT%TZ", &tmnow);
+	return prlen;
+#endif
+}
+
+struct syslog_fun _syslog_ss_fun = {
+	timefun_ss,
+	strerror_r_ss,
+	vsnprintf_ss,
+};
+
+void
+syslog_ss(int pri, struct syslog_data *data, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	_vxsyslogp_r(pri, NULL, data, NULL, NULL, fmt, ap);
+	va_end(ap);
+}
+
+void
+syslogp_ss(int pri, struct syslog_data *data, const char *msgid,
+	const char *sdfmt, const char *msgfmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, msgfmt);
+	_vxsyslogp_r(pri, NULL, data, msgid, sdfmt, msgfmt, ap);
+	va_end(ap);
+}
+
+void
+vsyslog_ss(int pri, struct syslog_data *data, const char *fmt, va_list ap)
+{
+	_vxsyslogp_r(pri, NULL, data, NULL, NULL, fmt, ap);
+}
+
+void
+vsyslogp_ss(int pri, struct syslog_data *data, const char *msgid,
+	const char *sdfmt, const char *msgfmt, va_list ap)
+{
+	_vxsyslogp_r(pri, NULL, data, msgid, sdfmt, msgfmt, ap);
+}
Index: src/lib/libc/gen/xsyslog.c
diff -u /dev/null src/lib/libc/gen/xsyslog.c:1.1
--- /dev/null	Wed Jan 11 19:38:01 2017
+++ src/lib/libc/gen/xsyslog.c	Wed Jan 11 19:38:01 2017
@@ -0,0 +1,422 @@
+/*	$NetBSD: xsyslog.c,v 1.1 2017/01/12 00:38:01 christos Exp $	*/
+
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)syslog.c	8.5 (Berkeley) 4/29/95";
+#else
+__RCSID("$NetBSD: xsyslog.c,v 1.1 2017/01/12 00:38:01 christos Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <paths.h>
+#include "syslog_private.h"
+#include "reentrant.h"
+#include "extern.h"
+
+#ifdef __weak_alias
+__weak_alias(closelog,_closelog)
+__weak_alias(openlog,_openlog)
+__weak_alias(setlogmask,_setlogmask)
+#endif
+
+struct syslog_data _syslog_data = SYSLOG_DATA_INIT;
+
+static void	openlog_unlocked_r(const char *, int, int,
+    struct syslog_data *);
+static void	disconnectlog_r(struct syslog_data *);
+static void	connectlog_r(struct syslog_data *);
+
+#ifdef _REENTRANT
+static mutex_t	syslog_mutex = MUTEX_INITIALIZER;
+#endif
+
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+	openlog_r(ident, logstat, logfac, &_syslog_data);
+}
+
+void
+closelog(void)
+{
+	closelog_r(&_syslog_data);
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask(int pmask)
+{
+	return setlogmask_r(pmask, &_syslog_data);
+}
+
+static void
+_xsyslogp_r(int pri, struct syslog_fun *fun,
+    struct syslog_data *data, const char *msgid,
+    const char *sdfmt, const char *msgfmt, ...)
+{
+	va_list ap;
+	va_start(ap, msgfmt);
+	_vxsyslogp_r(pri, fun, data, msgid, sdfmt, msgfmt, ap);
+	va_end(ap);
+}
+
+void
+_vxsyslogp_r(int pri, struct syslog_fun *fun,
+    struct syslog_data *data, const char *msgid,
+    const char *sdfmt, const char *msgfmt, va_list ap)
+{
+	static const char BRCOSP[] = "]: ";
+	static const char CRLF[] = "\r\n";
+	size_t cnt, prlen, tries;
+	char ch, *p, *t;
+	int fd, saved_errno;
+#define TBUF_LEN	2048
+#define FMT_LEN		1024
+#define MAXTRIES	10
+	char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN], fmt_cat[FMT_LEN] = "";
+	size_t tbuf_left, fmt_left, msgsdlen;
+	char *fmt = fmt_cat;
+	struct iovec iov[7];	/* prog + [ + pid + ]: + fmt + crlf */
+	int opened, iovcnt;
+
+#define INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
+	/* Check for invalid bits. */
+	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
+		_xsyslogp_r(INTERNALLOG, &_syslog_ss_fun, data, NULL, NULL,
+		    "%s: unknown facility/priority: %x", pri);
+		pri &= LOG_PRIMASK|LOG_FACMASK;
+	}
+
+	/* Check priority against setlogmask values. */
+	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 |= data->log_fac;
+
+	/* Build the message. */
+	p = tbuf;
+	tbuf_left = TBUF_LEN;
+
+	prlen = snprintf_ss(p, tbuf_left, "<%d>1 ", pri);
+	DEC();
+
+	prlen = (*fun->timefun)(p, tbuf_left);
+
+	if (data == &_syslog_data)
+		mutex_lock(&syslog_mutex);
+
+	if (data->log_hostname[0] == '\0' && gethostname(data->log_hostname,
+	    sizeof(data->log_hostname)) == -1) {
+		/* can this really happen? */
+		data->log_hostname[0] = '-';
+		data->log_hostname[1] = '\0';
+	}
+
+	DEC();
+	prlen = snprintf_ss(p, tbuf_left, " %s ", data->log_hostname);
+
+	if (data->log_tag == NULL)
+		data->log_tag = getprogname();
+
+	DEC();
+	prlen = snprintf_ss(p, tbuf_left, "%s ",
+	    data->log_tag ? data->log_tag : "-");
+
+	if (data == &_syslog_data)
+		mutex_unlock(&syslog_mutex);
+
+	if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
+		iovcnt = 0;
+		iov[iovcnt].iov_base = p;
+		iov[iovcnt].iov_len = prlen - 1;
+		iovcnt++;
+	}
+	DEC();
+
+	if (data->log_stat & LOG_PID) {
+		prlen = snprintf_ss(p, tbuf_left, "%d ", getpid());
+		if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
+			iov[iovcnt].iov_base = __UNCONST("[");
+			iov[iovcnt].iov_len = 1;
+			iovcnt++;
+			iov[iovcnt].iov_base = p;
+			iov[iovcnt].iov_len = prlen - 1;
+			iovcnt++;
+			iov[iovcnt].iov_base = __UNCONST(BRCOSP);
+			iov[iovcnt].iov_len = 3;
+			iovcnt++;
+		}
+	} else {
+		prlen = snprintf_ss(p, tbuf_left, "- ");
+		if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
+			iov[iovcnt].iov_base = __UNCONST(BRCOSP + 1);
+			iov[iovcnt].iov_len = 2;
+			iovcnt++;
+		}
+	}
+	DEC();
+
+	/*
+	 * concat the format strings, then use one vsnprintf()
+	 */
+	if (msgid != NULL && *msgid != '\0') {
+		strlcat(fmt_cat, msgid, FMT_LEN);
+		strlcat(fmt_cat, " ", FMT_LEN);
+	} else
+		strlcat(fmt_cat, "- ", FMT_LEN);
+
+	if (sdfmt != NULL && *sdfmt != '\0') {
+		strlcat(fmt_cat, sdfmt, FMT_LEN);
+	} else
+		strlcat(fmt_cat, "-", FMT_LEN);
+
+	if (data->log_stat & (LOG_PERROR|LOG_CONS))
+		msgsdlen = strlen(fmt_cat) + 1;
+	else
+		msgsdlen = 0;	/* XXX: GCC */
+
+	if (msgfmt != NULL && *msgfmt != '\0') {
+		strlcat(fmt_cat, " ", FMT_LEN);
+		strlcat(fmt_cat, msgfmt, FMT_LEN);
+	}
+
+	/*
+	 * We wouldn't need this mess if printf handled %m, or if
+	 * strerror() had been invented before syslog().
+	 */
+	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt) != '\0'; ++fmt) {
+		if (ch == '%' && fmt[1] == 'm') {
+			char buf[256];
+
+			if ((*fun->errfun)(saved_errno, buf, sizeof(buf)) != 0)
+				prlen = snprintf_ss(t, fmt_left, "Error %d",
+				    saved_errno);
+			else
+				prlen = strlcpy(t, buf, fmt_left);
+			if (prlen >= fmt_left)
+				prlen = fmt_left - 1;
+			t += prlen;
+			fmt++;
+			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--;
+			}
+		}
+	}
+	*t = '\0';
+
+	prlen = (*fun->prfun)(p, tbuf_left, fmt_cpy, ap);
+	if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
+		iov[iovcnt].iov_base = p + msgsdlen;
+		iov[iovcnt].iov_len = prlen - msgsdlen;
+		iovcnt++;
+	}
+
+	DEC();
+	cnt = p - tbuf;
+
+	/* Output to stderr if requested. */
+	if (data->log_stat & LOG_PERROR) {
+		iov[iovcnt].iov_base = __UNCONST(CRLF + 1);
+		iov[iovcnt].iov_len = 1;
+		(void)writev(STDERR_FILENO, iov, iovcnt + 1);
+	}
+
+	/* Get connected, output the message to the local logger. */
+	if (data == &_syslog_data)
+		mutex_lock(&syslog_mutex);
+	opened = !data->log_opened;
+	if (opened)
+		openlog_unlocked_r(data->log_tag, data->log_stat, 0, data);
+	connectlog_r(data);
+
+	/*
+	 * If the send() failed, there are two likely scenarios:
+	 *  1) syslogd was restarted
+	 *  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.
+	 */
+	for (tries = 0; tries < MAXTRIES; tries++) {
+		if (send(data->log_file, tbuf, cnt, 0) != -1)
+			break;
+		if (errno != ENOBUFS) {
+			disconnectlog_r(data);
+			connectlog_r(data);
+		} else
+			(void)usleep(1);
+	}
+
+	/*
+	 * Output the message to the console; try not to block
+	 * as a blocking console should not stop other processes.
+	 * Make sure the error reported is the one from the syslogd failure.
+	 */
+	if (tries == MAXTRIES && (data->log_stat & LOG_CONS) &&
+	    (fd = open(_PATH_CONSOLE,
+		O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0)) >= 0) {
+		iov[iovcnt].iov_base = __UNCONST(CRLF);
+		iov[iovcnt].iov_len = 2;
+		(void)writev(fd, iov, iovcnt + 1);
+		(void)close(fd);
+	}
+
+	if (data == &_syslog_data)
+		mutex_unlock(&syslog_mutex);
+
+	if (data != &_syslog_data && opened) {
+		/* preserve log tag */
+		const char *ident = data->log_tag;
+		closelog_r(data);
+		data->log_tag = ident;
+	}
+}
+
+static 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 (data->log_file != -1) {
+		(void)close(data->log_file);
+		data->log_file = -1;
+	}
+	data->log_connected = 0;		/* retry connect */
+}
+
+static void
+connectlog_r(struct syslog_data *data)
+{
+	/* AF_UNIX address of local logger */
+	static const struct sockaddr_un sun = {
+		.sun_family = AF_LOCAL,
+		.sun_len = sizeof(sun),
+		.sun_path = _PATH_LOG,
+	};
+
+	if (data->log_file == -1 || fcntl(data->log_file, F_GETFL, 0) == -1) {
+		if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
+		    0)) == -1)
+			return;
+		data->log_connected = 0;
+	}
+	if (!data->log_connected) {
+		if (connect(data->log_file,
+		    (const struct sockaddr *)(const void *)&sun,
+		    (socklen_t)sizeof(sun)) == -1) {
+			(void)close(data->log_file);
+			data->log_file = -1;
+		} else
+			data->log_connected = 1;
+	}
+}
+
+static void
+openlog_unlocked_r(const char *ident, int logstat, int logfac,
+    struct syslog_data *data)
+{
+	if (ident != NULL)
+		data->log_tag = ident;
+	data->log_stat = logstat;
+	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+		data->log_fac = logfac;
+
+	if (data->log_stat & LOG_NDELAY)	/* open immediately */
+		connectlog_r(data);
+
+	data->log_opened = 1;
+}
+
+void
+openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
+{
+	if (data == &_syslog_data)
+		mutex_lock(&syslog_mutex);
+	openlog_unlocked_r(ident, logstat, logfac, data);
+	if (data == &_syslog_data)
+		mutex_unlock(&syslog_mutex);
+}
+
+void
+closelog_r(struct syslog_data *data)
+{
+	if (data == &_syslog_data)
+		mutex_lock(&syslog_mutex);
+	(void)close(data->log_file);
+	data->log_file = -1;
+	data->log_connected = 0;
+	data->log_tag = NULL;
+	if (data == &_syslog_data)
+		mutex_unlock(&syslog_mutex);
+}
+
+int
+setlogmask_r(int pmask, struct syslog_data *data)
+{
+	int omask;
+
+	omask = data->log_mask;
+	if (pmask != 0)
+		data->log_mask = pmask;
+	return omask;
+}

Reply via email to