xref: /minix3/lib/libc/gen/syslog.c (revision 27852ebe53d5bf221cf5058cb7e858fa8fa8895e)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: syslog.c,v 1.54 2014/09/18 13:58:20 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
42fe8fb19SBen Gras  * Copyright (c) 1983, 1988, 1993
52fe8fb19SBen Gras  *	The Regents of the University of California.  All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
82fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
92fe8fb19SBen Gras  * are met:
102fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
112fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
122fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
132fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
142fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
152fe8fb19SBen Gras  * 3. Neither the name of the University nor the names of its contributors
162fe8fb19SBen Gras  *    may be used to endorse or promote products derived from this software
172fe8fb19SBen Gras  *    without specific prior written permission.
182fe8fb19SBen Gras  *
192fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
202fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212fe8fb19SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222fe8fb19SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
232fe8fb19SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
242fe8fb19SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
252fe8fb19SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
262fe8fb19SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272fe8fb19SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
282fe8fb19SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
292fe8fb19SBen Gras  * SUCH DAMAGE.
302fe8fb19SBen Gras  */
312fe8fb19SBen Gras 
322fe8fb19SBen Gras #include <sys/cdefs.h>
332fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
342fe8fb19SBen Gras #if 0
352fe8fb19SBen Gras static char sccsid[] = "@(#)syslog.c	8.5 (Berkeley) 4/29/95";
362fe8fb19SBen Gras #else
37*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: syslog.c,v 1.54 2014/09/18 13:58:20 christos Exp $");
382fe8fb19SBen Gras #endif
392fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
402fe8fb19SBen Gras 
412fe8fb19SBen Gras #include "namespace.h"
422fe8fb19SBen Gras #include <sys/types.h>
432fe8fb19SBen Gras #include <sys/param.h>
442fe8fb19SBen Gras #include <sys/socket.h>
452fe8fb19SBen Gras #include <sys/syslog.h>
462fe8fb19SBen Gras #include <sys/uio.h>
472fe8fb19SBen Gras #include <sys/un.h>
482fe8fb19SBen Gras #include <netdb.h>
492fe8fb19SBen Gras 
502fe8fb19SBen Gras #include <errno.h>
512fe8fb19SBen Gras #include <fcntl.h>
522fe8fb19SBen Gras #include <paths.h>
532fe8fb19SBen Gras #include <stdarg.h>
542fe8fb19SBen Gras #include <stdio.h>
552fe8fb19SBen Gras #include <stdlib.h>
562fe8fb19SBen Gras #include <string.h>
572fe8fb19SBen Gras #include <time.h>
582fe8fb19SBen Gras #include <unistd.h>
592fe8fb19SBen Gras #include "reentrant.h"
602fe8fb19SBen Gras #include "extern.h"
612fe8fb19SBen Gras 
622fe8fb19SBen Gras #ifdef __weak_alias
632fe8fb19SBen Gras __weak_alias(closelog,_closelog)
642fe8fb19SBen Gras __weak_alias(openlog,_openlog)
652fe8fb19SBen Gras __weak_alias(setlogmask,_setlogmask)
662fe8fb19SBen Gras __weak_alias(syslog,_syslog)
672fe8fb19SBen Gras __weak_alias(vsyslog,_vsyslog)
682fe8fb19SBen Gras __weak_alias(syslogp,_syslogp)
692fe8fb19SBen Gras __weak_alias(vsyslogp,_vsyslogp)
702fe8fb19SBen Gras #endif
712fe8fb19SBen Gras 
722fe8fb19SBen Gras static struct syslog_data sdata = SYSLOG_DATA_INIT;
732fe8fb19SBen Gras 
742fe8fb19SBen Gras static void	openlog_unlocked_r(const char *, int, int,
752fe8fb19SBen Gras     struct syslog_data *);
762fe8fb19SBen Gras static void	disconnectlog_r(struct syslog_data *);
772fe8fb19SBen Gras static void	connectlog_r(struct syslog_data *);
782fe8fb19SBen Gras 
792fe8fb19SBen Gras #define LOG_SIGNAL_SAFE	(int)0x80000000
802fe8fb19SBen Gras 
812fe8fb19SBen Gras 
822fe8fb19SBen Gras #ifdef _REENTRANT
832fe8fb19SBen Gras static mutex_t	syslog_mutex = MUTEX_INITIALIZER;
842fe8fb19SBen Gras #endif
852fe8fb19SBen Gras 
862fe8fb19SBen Gras /*
872fe8fb19SBen Gras  * syslog, vsyslog --
882fe8fb19SBen Gras  *	print message on log file; output is intended for syslogd(8).
892fe8fb19SBen Gras  */
902fe8fb19SBen Gras void
syslog(int pri,const char * fmt,...)912fe8fb19SBen Gras syslog(int pri, const char *fmt, ...)
922fe8fb19SBen Gras {
932fe8fb19SBen Gras 	va_list ap;
942fe8fb19SBen Gras 
952fe8fb19SBen Gras 	va_start(ap, fmt);
962fe8fb19SBen Gras 	vsyslog(pri, fmt, ap);
972fe8fb19SBen Gras 	va_end(ap);
982fe8fb19SBen Gras }
992fe8fb19SBen Gras 
1002fe8fb19SBen Gras void
vsyslog(int pri,const char * fmt,va_list ap)1012fe8fb19SBen Gras vsyslog(int pri, const char *fmt, va_list ap)
1022fe8fb19SBen Gras {
1032fe8fb19SBen Gras 	vsyslog_r(pri, &sdata, fmt, ap);
1042fe8fb19SBen Gras }
1052fe8fb19SBen Gras 
1062fe8fb19SBen Gras /*
1072fe8fb19SBen Gras  * syslogp, vsyslogp --
1082fe8fb19SBen Gras  *	like syslog but take additional arguments for MSGID and SD
1092fe8fb19SBen Gras  */
1102fe8fb19SBen Gras void
syslogp(int pri,const char * msgid,const char * sdfmt,const char * msgfmt,...)1112fe8fb19SBen Gras syslogp(int pri, const char *msgid, const char *sdfmt, const char *msgfmt, ...)
1122fe8fb19SBen Gras {
1132fe8fb19SBen Gras 	va_list ap;
1142fe8fb19SBen Gras 
1152fe8fb19SBen Gras 	va_start(ap, msgfmt);
1162fe8fb19SBen Gras 	vsyslogp(pri, msgid, sdfmt, msgfmt, ap);
1172fe8fb19SBen Gras 	va_end(ap);
1182fe8fb19SBen Gras }
1192fe8fb19SBen Gras 
1202fe8fb19SBen Gras void
vsyslogp(int pri,const char * msgid,const char * sdfmt,const char * msgfmt,va_list ap)1212fe8fb19SBen Gras vsyslogp(int pri, const char *msgid, const char *sdfmt, const char *msgfmt, va_list ap)
1222fe8fb19SBen Gras {
1232fe8fb19SBen Gras 	vsyslogp_r(pri, &sdata, msgid, sdfmt, msgfmt, ap);
1242fe8fb19SBen Gras }
1252fe8fb19SBen Gras 
1262fe8fb19SBen Gras void
openlog(const char * ident,int logstat,int logfac)1272fe8fb19SBen Gras openlog(const char *ident, int logstat, int logfac)
1282fe8fb19SBen Gras {
1292fe8fb19SBen Gras 	openlog_r(ident, logstat, logfac, &sdata);
1302fe8fb19SBen Gras }
1312fe8fb19SBen Gras 
1322fe8fb19SBen Gras void
closelog(void)1332fe8fb19SBen Gras closelog(void)
1342fe8fb19SBen Gras {
1352fe8fb19SBen Gras 	closelog_r(&sdata);
1362fe8fb19SBen Gras }
1372fe8fb19SBen Gras 
1382fe8fb19SBen Gras /* setlogmask -- set the log mask level */
1392fe8fb19SBen Gras int
setlogmask(int pmask)1402fe8fb19SBen Gras setlogmask(int pmask)
1412fe8fb19SBen Gras {
1422fe8fb19SBen Gras 	return setlogmask_r(pmask, &sdata);
1432fe8fb19SBen Gras }
1442fe8fb19SBen Gras 
1452fe8fb19SBen Gras /* Reentrant version of syslog, i.e. syslog_r() */
1462fe8fb19SBen Gras 
1472fe8fb19SBen Gras void
syslog_r(int pri,struct syslog_data * data,const char * fmt,...)1482fe8fb19SBen Gras syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
1492fe8fb19SBen Gras {
1502fe8fb19SBen Gras 	va_list ap;
1512fe8fb19SBen Gras 
1522fe8fb19SBen Gras 	va_start(ap, fmt);
1532fe8fb19SBen Gras 	vsyslog_r(pri, data, fmt, ap);
1542fe8fb19SBen Gras 	va_end(ap);
1552fe8fb19SBen Gras }
1562fe8fb19SBen Gras 
1572fe8fb19SBen Gras void
syslogp_r(int pri,struct syslog_data * data,const char * msgid,const char * sdfmt,const char * msgfmt,...)1582fe8fb19SBen Gras syslogp_r(int pri, struct syslog_data *data, const char *msgid,
1592fe8fb19SBen Gras 	const char *sdfmt, const char *msgfmt, ...)
1602fe8fb19SBen Gras {
1612fe8fb19SBen Gras 	va_list ap;
1622fe8fb19SBen Gras 
1632fe8fb19SBen Gras 	va_start(ap, msgfmt);
1642fe8fb19SBen Gras 	vsyslogp_r(pri, data, msgid, sdfmt, msgfmt, ap);
1652fe8fb19SBen Gras 	va_end(ap);
1662fe8fb19SBen Gras }
1672fe8fb19SBen Gras 
1682fe8fb19SBen Gras void
syslog_ss(int pri,struct syslog_data * data,const char * fmt,...)1692fe8fb19SBen Gras syslog_ss(int pri, struct syslog_data *data, const char *fmt, ...)
1702fe8fb19SBen Gras {
1712fe8fb19SBen Gras 	va_list ap;
1722fe8fb19SBen Gras 
1732fe8fb19SBen Gras 	va_start(ap, fmt);
1742fe8fb19SBen Gras 	vsyslog_r(pri | LOG_SIGNAL_SAFE, data, fmt, ap);
1752fe8fb19SBen Gras 	va_end(ap);
1762fe8fb19SBen Gras }
1772fe8fb19SBen Gras 
1782fe8fb19SBen Gras void
syslogp_ss(int pri,struct syslog_data * data,const char * msgid,const char * sdfmt,const char * msgfmt,...)1792fe8fb19SBen Gras syslogp_ss(int pri, struct syslog_data *data, const char *msgid,
1802fe8fb19SBen Gras 	const char *sdfmt, const char *msgfmt, ...)
1812fe8fb19SBen Gras {
1822fe8fb19SBen Gras 	va_list ap;
1832fe8fb19SBen Gras 
1842fe8fb19SBen Gras 	va_start(ap, msgfmt);
1852fe8fb19SBen Gras 	vsyslogp_r(pri | LOG_SIGNAL_SAFE, data, msgid, sdfmt, msgfmt, ap);
1862fe8fb19SBen Gras 	va_end(ap);
1872fe8fb19SBen Gras }
1882fe8fb19SBen Gras 
1892fe8fb19SBen Gras void
vsyslog_ss(int pri,struct syslog_data * data,const char * fmt,va_list ap)1902fe8fb19SBen Gras vsyslog_ss(int pri, struct syslog_data *data, const char *fmt, va_list ap)
1912fe8fb19SBen Gras {
1922fe8fb19SBen Gras 	vsyslog_r(pri | LOG_SIGNAL_SAFE, data, fmt, ap);
1932fe8fb19SBen Gras }
1942fe8fb19SBen Gras 
1952fe8fb19SBen Gras void
vsyslogp_ss(int pri,struct syslog_data * data,const char * msgid,const char * sdfmt,const char * msgfmt,va_list ap)1962fe8fb19SBen Gras vsyslogp_ss(int pri, struct syslog_data *data, const char *msgid,
1972fe8fb19SBen Gras 	const char *sdfmt, const char *msgfmt, va_list ap)
1982fe8fb19SBen Gras {
1992fe8fb19SBen Gras 	vsyslogp_r(pri | LOG_SIGNAL_SAFE, data, msgid, sdfmt, msgfmt, ap);
2002fe8fb19SBen Gras }
2012fe8fb19SBen Gras 
2022fe8fb19SBen Gras 
2032fe8fb19SBen Gras void
vsyslog_r(int pri,struct syslog_data * data,const char * fmt,va_list ap)2042fe8fb19SBen Gras vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
2052fe8fb19SBen Gras {
2062fe8fb19SBen Gras 	vsyslogp_r(pri, data, NULL, NULL, fmt, ap);
2072fe8fb19SBen Gras }
2082fe8fb19SBen Gras 
2092fe8fb19SBen Gras void
vsyslogp_r(int pri,struct syslog_data * data,const char * msgid,const char * sdfmt,const char * msgfmt,va_list ap)2102fe8fb19SBen Gras vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
2112fe8fb19SBen Gras 	const char *sdfmt, const char *msgfmt, va_list ap)
2122fe8fb19SBen Gras {
2132fe8fb19SBen Gras 	static const char BRCOSP[] = "]: ";
2142fe8fb19SBen Gras 	static const char CRLF[] = "\r\n";
2152fe8fb19SBen Gras 	size_t cnt, prlen, tries;
2162fe8fb19SBen Gras 	char ch, *p, *t;
2172fe8fb19SBen Gras 	struct timeval tv;
2182fe8fb19SBen Gras 	struct tm tmnow;
2192fe8fb19SBen Gras 	time_t now;
2202fe8fb19SBen Gras 	int fd, saved_errno;
2212fe8fb19SBen Gras #define TBUF_LEN	2048
2222fe8fb19SBen Gras #define FMT_LEN		1024
2232fe8fb19SBen Gras #define MAXTRIES	10
2242fe8fb19SBen Gras 	char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN], fmt_cat[FMT_LEN] = "";
2252fe8fb19SBen Gras 	size_t tbuf_left, fmt_left, msgsdlen;
2262fe8fb19SBen Gras 	char *fmt = fmt_cat;
2272fe8fb19SBen Gras 	int signal_safe = pri & LOG_SIGNAL_SAFE;
2282fe8fb19SBen Gras 	struct iovec iov[7];	/* prog + [ + pid + ]: + fmt + crlf */
2292fe8fb19SBen Gras 	int opened, iovcnt;
2302fe8fb19SBen Gras 
2312fe8fb19SBen Gras 	pri &= ~LOG_SIGNAL_SAFE;
2322fe8fb19SBen Gras 
2332fe8fb19SBen Gras #define INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
2342fe8fb19SBen Gras 	/* Check for invalid bits. */
2352fe8fb19SBen Gras 	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
2362fe8fb19SBen Gras 		syslog_r(INTERNALLOG | signal_safe, data,
2372fe8fb19SBen Gras 		    "syslog_r: unknown facility/priority: %x", pri);
2382fe8fb19SBen Gras 		pri &= LOG_PRIMASK|LOG_FACMASK;
2392fe8fb19SBen Gras 	}
2402fe8fb19SBen Gras 
2412fe8fb19SBen Gras 	/* Check priority against setlogmask values. */
2422fe8fb19SBen Gras 	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
2432fe8fb19SBen Gras 		return;
2442fe8fb19SBen Gras 
2452fe8fb19SBen Gras 	saved_errno = errno;
2462fe8fb19SBen Gras 
2472fe8fb19SBen Gras 	/* Set default facility if none specified. */
2482fe8fb19SBen Gras 	if ((pri & LOG_FACMASK) == 0)
2492fe8fb19SBen Gras 		pri |= data->log_fac;
2502fe8fb19SBen Gras 
2512fe8fb19SBen Gras 	/* Build the message. */
2522fe8fb19SBen Gras 	p = tbuf;
2532fe8fb19SBen Gras 	tbuf_left = TBUF_LEN;
2542fe8fb19SBen Gras 
2552fe8fb19SBen Gras #define DEC()							\
2562fe8fb19SBen Gras 	do {							\
2572fe8fb19SBen Gras 		if (prlen >= tbuf_left)				\
2582fe8fb19SBen Gras 			prlen = tbuf_left - 1;			\
2592fe8fb19SBen Gras 		p += prlen;					\
2602fe8fb19SBen Gras 		tbuf_left -= prlen;				\
2612fe8fb19SBen Gras 	} while (/*CONSTCOND*/0)
2622fe8fb19SBen Gras 
2632fe8fb19SBen Gras 	prlen = snprintf_ss(p, tbuf_left, "<%d>1 ", pri);
2642fe8fb19SBen Gras 	DEC();
2652fe8fb19SBen Gras 
2662fe8fb19SBen Gras 	if (!signal_safe && (gettimeofday(&tv, NULL) != -1)) {
2672fe8fb19SBen Gras 		/* strftime() implies tzset(), localtime_r() doesn't. */
2682fe8fb19SBen Gras 		tzset();
2692fe8fb19SBen Gras 		now = (time_t) tv.tv_sec;
2702fe8fb19SBen Gras 		localtime_r(&now, &tmnow);
2712fe8fb19SBen Gras 
2722fe8fb19SBen Gras 		prlen = strftime(p, tbuf_left, "%FT%T", &tmnow);
2732fe8fb19SBen Gras 		DEC();
2742fe8fb19SBen Gras 		prlen = snprintf(p, tbuf_left, ".%06ld", (long)tv.tv_usec);
2752fe8fb19SBen Gras 		DEC();
2762fe8fb19SBen Gras 		prlen = strftime(p, tbuf_left-1, "%z", &tmnow);
2772fe8fb19SBen Gras 		/* strftime gives eg. "+0200", but we need "+02:00" */
2782fe8fb19SBen Gras 		if (prlen == 5) {
2792fe8fb19SBen Gras 			p[prlen+1] = p[prlen];
2802fe8fb19SBen Gras 			p[prlen]   = p[prlen-1];
2812fe8fb19SBen Gras 			p[prlen-1] = p[prlen-2];
2822fe8fb19SBen Gras 			p[prlen-2] = ':';
2832fe8fb19SBen Gras 			prlen += 1;
2842fe8fb19SBen Gras 		}
2852fe8fb19SBen Gras 	} else {
2862fe8fb19SBen Gras 		prlen = snprintf_ss(p, tbuf_left, "-");
287f14fb602SLionel Sambuc #if 0
288f14fb602SLionel Sambuc 		/*
289f14fb602SLionel Sambuc 		 * if gmtime_r() was signal-safe we could output
290f14fb602SLionel Sambuc 		 * the UTC-time:
291f14fb602SLionel Sambuc 		 */
2922fe8fb19SBen Gras 		gmtime_r(&now, &tmnow);
2932fe8fb19SBen Gras 		prlen = strftime(p, tbuf_left, "%FT%TZ", &tmnow);
294f14fb602SLionel Sambuc #endif
2952fe8fb19SBen Gras 	}
296f14fb602SLionel Sambuc 
29784d9c625SLionel Sambuc #if !defined(__minix)
298f14fb602SLionel Sambuc 	if (data == &sdata)
299f14fb602SLionel Sambuc 		mutex_lock(&syslog_mutex);
30084d9c625SLionel Sambuc #endif /* !defined(__minix) */
301f14fb602SLionel Sambuc 
302f14fb602SLionel Sambuc 	if (data->log_hostname[0] == '\0' && gethostname(data->log_hostname,
303f14fb602SLionel Sambuc 	    sizeof(data->log_hostname)) == -1) {
304f14fb602SLionel Sambuc 		/* can this really happen? */
305f14fb602SLionel Sambuc 		data->log_hostname[0] = '-';
306f14fb602SLionel Sambuc 		data->log_hostname[1] = '\0';
307f14fb602SLionel Sambuc 	}
308f14fb602SLionel Sambuc 
3092fe8fb19SBen Gras 	DEC();
310f14fb602SLionel Sambuc 	prlen = snprintf_ss(p, tbuf_left, " %s ", data->log_hostname);
3112fe8fb19SBen Gras 
3122fe8fb19SBen Gras 	if (data->log_tag == NULL)
3132fe8fb19SBen Gras 		data->log_tag = getprogname();
3142fe8fb19SBen Gras 
315f14fb602SLionel Sambuc 	DEC();
3162fe8fb19SBen Gras 	prlen = snprintf_ss(p, tbuf_left, "%s ",
3172fe8fb19SBen Gras 	    data->log_tag ? data->log_tag : "-");
318f14fb602SLionel Sambuc 
31984d9c625SLionel Sambuc #if !defined(__minix)
320f14fb602SLionel Sambuc 	if (data == &sdata)
321f14fb602SLionel Sambuc 		mutex_unlock(&syslog_mutex);
32284d9c625SLionel Sambuc #endif /* !defined(__minix) */
323f14fb602SLionel Sambuc 
3242fe8fb19SBen Gras 	if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
3252fe8fb19SBen Gras 		iovcnt = 0;
3262fe8fb19SBen Gras 		iov[iovcnt].iov_base = p;
3272fe8fb19SBen Gras 		iov[iovcnt].iov_len = prlen - 1;
3282fe8fb19SBen Gras 		iovcnt++;
3292fe8fb19SBen Gras 	}
3302fe8fb19SBen Gras 	DEC();
3312fe8fb19SBen Gras 
3322fe8fb19SBen Gras 	if (data->log_stat & LOG_PID) {
3332fe8fb19SBen Gras 		prlen = snprintf_ss(p, tbuf_left, "%d ", getpid());
3342fe8fb19SBen Gras 		if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
3352fe8fb19SBen Gras 			iov[iovcnt].iov_base = __UNCONST("[");
3362fe8fb19SBen Gras 			iov[iovcnt].iov_len = 1;
3372fe8fb19SBen Gras 			iovcnt++;
3382fe8fb19SBen Gras 			iov[iovcnt].iov_base = p;
3392fe8fb19SBen Gras 			iov[iovcnt].iov_len = prlen - 1;
3402fe8fb19SBen Gras 			iovcnt++;
3412fe8fb19SBen Gras 			iov[iovcnt].iov_base = __UNCONST(BRCOSP);
3422fe8fb19SBen Gras 			iov[iovcnt].iov_len = 3;
3432fe8fb19SBen Gras 			iovcnt++;
3442fe8fb19SBen Gras 		}
3452fe8fb19SBen Gras 	} else {
3462fe8fb19SBen Gras 		prlen = snprintf_ss(p, tbuf_left, "- ");
3472fe8fb19SBen Gras 		if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
3482fe8fb19SBen Gras 			iov[iovcnt].iov_base = __UNCONST(BRCOSP + 1);
3492fe8fb19SBen Gras 			iov[iovcnt].iov_len = 2;
3502fe8fb19SBen Gras 			iovcnt++;
3512fe8fb19SBen Gras 		}
3522fe8fb19SBen Gras 	}
3532fe8fb19SBen Gras 	DEC();
3542fe8fb19SBen Gras 
3552fe8fb19SBen Gras 	/*
3562fe8fb19SBen Gras 	 * concat the format strings, then use one vsnprintf()
3572fe8fb19SBen Gras 	 */
3582fe8fb19SBen Gras 	if (msgid != NULL && *msgid != '\0') {
3592fe8fb19SBen Gras 		strlcat(fmt_cat, msgid, FMT_LEN);
3602fe8fb19SBen Gras 		strlcat(fmt_cat, " ", FMT_LEN);
3612fe8fb19SBen Gras 	} else
3622fe8fb19SBen Gras 		strlcat(fmt_cat, "- ", FMT_LEN);
3632fe8fb19SBen Gras 
3642fe8fb19SBen Gras 	if (sdfmt != NULL && *sdfmt != '\0') {
3652fe8fb19SBen Gras 		strlcat(fmt_cat, sdfmt, FMT_LEN);
3662fe8fb19SBen Gras 	} else
3672fe8fb19SBen Gras 		strlcat(fmt_cat, "-", FMT_LEN);
3682fe8fb19SBen Gras 
3692fe8fb19SBen Gras 	if (data->log_stat & (LOG_PERROR|LOG_CONS))
3702fe8fb19SBen Gras 		msgsdlen = strlen(fmt_cat) + 1;
3712fe8fb19SBen Gras 	else
3722fe8fb19SBen Gras 		msgsdlen = 0;	/* XXX: GCC */
3732fe8fb19SBen Gras 
3742fe8fb19SBen Gras 	if (msgfmt != NULL && *msgfmt != '\0') {
3752fe8fb19SBen Gras 		strlcat(fmt_cat, " ", FMT_LEN);
3762fe8fb19SBen Gras 		strlcat(fmt_cat, msgfmt, FMT_LEN);
3772fe8fb19SBen Gras 	}
3782fe8fb19SBen Gras 
3792fe8fb19SBen Gras 	/*
3802fe8fb19SBen Gras 	 * We wouldn't need this mess if printf handled %m, or if
3812fe8fb19SBen Gras 	 * strerror() had been invented before syslog().
3822fe8fb19SBen Gras 	 */
3832fe8fb19SBen Gras 	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt) != '\0'; ++fmt) {
3842fe8fb19SBen Gras 		if (ch == '%' && fmt[1] == 'm') {
3852fe8fb19SBen Gras 			char ebuf[128];
3862fe8fb19SBen Gras 			++fmt;
3872fe8fb19SBen Gras 			if (signal_safe ||
3882fe8fb19SBen Gras 			    strerror_r(saved_errno, ebuf, sizeof(ebuf)))
3892fe8fb19SBen Gras 				prlen = snprintf_ss(t, fmt_left, "Error %d",
3902fe8fb19SBen Gras 				    saved_errno);
3912fe8fb19SBen Gras 			else
3922fe8fb19SBen Gras 				prlen = snprintf_ss(t, fmt_left, "%s", ebuf);
3932fe8fb19SBen Gras 			if (prlen >= fmt_left)
3942fe8fb19SBen Gras 				prlen = fmt_left - 1;
3952fe8fb19SBen Gras 			t += prlen;
3962fe8fb19SBen Gras 			fmt_left -= prlen;
3972fe8fb19SBen Gras 		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
3982fe8fb19SBen Gras 			*t++ = '%';
3992fe8fb19SBen Gras 			*t++ = '%';
4002fe8fb19SBen Gras 			fmt++;
4012fe8fb19SBen Gras 			fmt_left -= 2;
4022fe8fb19SBen Gras 		} else {
4032fe8fb19SBen Gras 			if (fmt_left > 1) {
4042fe8fb19SBen Gras 				*t++ = ch;
4052fe8fb19SBen Gras 				fmt_left--;
4062fe8fb19SBen Gras 			}
4072fe8fb19SBen Gras 		}
4082fe8fb19SBen Gras 	}
4092fe8fb19SBen Gras 	*t = '\0';
4102fe8fb19SBen Gras 
4112fe8fb19SBen Gras 	if (signal_safe)
4122fe8fb19SBen Gras 		prlen = vsnprintf_ss(p, tbuf_left, fmt_cpy, ap);
4132fe8fb19SBen Gras 	else
4142fe8fb19SBen Gras 		prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
4152fe8fb19SBen Gras 
4162fe8fb19SBen Gras 	if (data->log_stat & (LOG_PERROR|LOG_CONS)) {
4172fe8fb19SBen Gras 		iov[iovcnt].iov_base = p + msgsdlen;
4182fe8fb19SBen Gras 		iov[iovcnt].iov_len = prlen - msgsdlen;
4192fe8fb19SBen Gras 		iovcnt++;
4202fe8fb19SBen Gras 	}
4212fe8fb19SBen Gras 
4222fe8fb19SBen Gras 	DEC();
4232fe8fb19SBen Gras 	cnt = p - tbuf;
4242fe8fb19SBen Gras 
4252fe8fb19SBen Gras 	/* Output to stderr if requested. */
4262fe8fb19SBen Gras 	if (data->log_stat & LOG_PERROR) {
4272fe8fb19SBen Gras 		iov[iovcnt].iov_base = __UNCONST(CRLF + 1);
4282fe8fb19SBen Gras 		iov[iovcnt].iov_len = 1;
4292fe8fb19SBen Gras 		(void)writev(STDERR_FILENO, iov, iovcnt + 1);
4302fe8fb19SBen Gras 	}
4312fe8fb19SBen Gras 
4322fe8fb19SBen Gras 	/* Get connected, output the message to the local logger. */
43384d9c625SLionel Sambuc #if !defined(__minix)
4342fe8fb19SBen Gras 	if (data == &sdata)
4352fe8fb19SBen Gras 		mutex_lock(&syslog_mutex);
43684d9c625SLionel Sambuc #endif /* !defined(__minix) */
437f14fb602SLionel Sambuc 	opened = !data->log_opened;
4382fe8fb19SBen Gras 	if (opened)
4392fe8fb19SBen Gras 		openlog_unlocked_r(data->log_tag, data->log_stat, 0, data);
4402fe8fb19SBen Gras 	connectlog_r(data);
4412fe8fb19SBen Gras 
4422fe8fb19SBen Gras 	/*
4432fe8fb19SBen Gras 	 * If the send() failed, there are two likely scenarios:
4442fe8fb19SBen Gras 	 *  1) syslogd was restarted
4452fe8fb19SBen Gras 	 *  2) /dev/log is out of socket buffer space
4462fe8fb19SBen Gras 	 * We attempt to reconnect to /dev/log to take care of
4472fe8fb19SBen Gras 	 * case #1 and keep send()ing data to cover case #2
4482fe8fb19SBen Gras 	 * to give syslogd a chance to empty its socket buffer.
4492fe8fb19SBen Gras 	 */
4502fe8fb19SBen Gras 	for (tries = 0; tries < MAXTRIES; tries++) {
4512fe8fb19SBen Gras 		if (send(data->log_file, tbuf, cnt, 0) != -1)
4522fe8fb19SBen Gras 			break;
4532fe8fb19SBen Gras 		if (errno != ENOBUFS) {
4542fe8fb19SBen Gras 			disconnectlog_r(data);
4552fe8fb19SBen Gras 			connectlog_r(data);
4562fe8fb19SBen Gras 		} else
4572fe8fb19SBen Gras 			(void)usleep(1);
4582fe8fb19SBen Gras 	}
4592fe8fb19SBen Gras 
4602fe8fb19SBen Gras 	/*
4612fe8fb19SBen Gras 	 * Output the message to the console; try not to block
4622fe8fb19SBen Gras 	 * as a blocking console should not stop other processes.
4632fe8fb19SBen Gras 	 * Make sure the error reported is the one from the syslogd failure.
4642fe8fb19SBen Gras 	 */
4652fe8fb19SBen Gras 	if (tries == MAXTRIES && (data->log_stat & LOG_CONS) &&
466*0a6a1f1dSLionel Sambuc 	    (fd = open(_PATH_CONSOLE,
467*0a6a1f1dSLionel Sambuc 		O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0)) >= 0) {
4682fe8fb19SBen Gras 		iov[iovcnt].iov_base = __UNCONST(CRLF);
4692fe8fb19SBen Gras 		iov[iovcnt].iov_len = 2;
4702fe8fb19SBen Gras 		(void)writev(fd, iov, iovcnt + 1);
4712fe8fb19SBen Gras 		(void)close(fd);
4722fe8fb19SBen Gras 	}
4732fe8fb19SBen Gras 
47484d9c625SLionel Sambuc #if !defined(__minix)
4752fe8fb19SBen Gras 	if (data == &sdata)
4762fe8fb19SBen Gras 		mutex_unlock(&syslog_mutex);
47784d9c625SLionel Sambuc #endif /* !defined(__minix) */
4782fe8fb19SBen Gras 
4792fe8fb19SBen Gras 	if (data != &sdata && opened) {
4802fe8fb19SBen Gras 		/* preserve log tag */
4812fe8fb19SBen Gras 		const char *ident = data->log_tag;
4822fe8fb19SBen Gras 		closelog_r(data);
4832fe8fb19SBen Gras 		data->log_tag = ident;
4842fe8fb19SBen Gras 	}
4852fe8fb19SBen Gras }
4862fe8fb19SBen Gras 
4872fe8fb19SBen Gras static void
disconnectlog_r(struct syslog_data * data)4882fe8fb19SBen Gras disconnectlog_r(struct syslog_data *data)
4892fe8fb19SBen Gras {
4902fe8fb19SBen Gras 	/*
4912fe8fb19SBen Gras 	 * If the user closed the FD and opened another in the same slot,
4922fe8fb19SBen Gras 	 * that's their problem.  They should close it before calling on
4932fe8fb19SBen Gras 	 * system services.
4942fe8fb19SBen Gras 	 */
4952fe8fb19SBen Gras 	if (data->log_file != -1) {
4962fe8fb19SBen Gras 		(void)close(data->log_file);
4972fe8fb19SBen Gras 		data->log_file = -1;
4982fe8fb19SBen Gras 	}
499f14fb602SLionel Sambuc 	data->log_connected = 0;		/* retry connect */
5002fe8fb19SBen Gras }
5012fe8fb19SBen Gras 
5022fe8fb19SBen Gras static void
connectlog_r(struct syslog_data * data)5032fe8fb19SBen Gras connectlog_r(struct syslog_data *data)
5042fe8fb19SBen Gras {
5052fe8fb19SBen Gras 	/* AF_UNIX address of local logger */
5062fe8fb19SBen Gras 	static const struct sockaddr_un sun = {
5072fe8fb19SBen Gras 		.sun_family = AF_LOCAL,
5082fe8fb19SBen Gras 		.sun_len = sizeof(sun),
5092fe8fb19SBen Gras 		.sun_path = _PATH_LOG,
5102fe8fb19SBen Gras 	};
5112fe8fb19SBen Gras 
5122fe8fb19SBen Gras 	if (data->log_file == -1 || fcntl(data->log_file, F_GETFL, 0) == -1) {
513f14fb602SLionel Sambuc 		if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
514f14fb602SLionel Sambuc 		    0)) == -1)
5152fe8fb19SBen Gras 			return;
516f14fb602SLionel Sambuc 		data->log_connected = 0;
5172fe8fb19SBen Gras 	}
518f14fb602SLionel Sambuc 	if (!data->log_connected) {
5192fe8fb19SBen Gras 		if (connect(data->log_file,
5202fe8fb19SBen Gras 		    (const struct sockaddr *)(const void *)&sun,
5219178749eSBen Gras 		    (socklen_t)sizeof(sun)) == -1)
5229178749eSBen Gras 		{
5232fe8fb19SBen Gras 			(void)close(data->log_file);
5242fe8fb19SBen Gras 			data->log_file = -1;
5252fe8fb19SBen Gras 		} else
526f14fb602SLionel Sambuc 			data->log_connected = 1;
5272fe8fb19SBen Gras 	}
5282fe8fb19SBen Gras }
5292fe8fb19SBen Gras 
5302fe8fb19SBen Gras static void
openlog_unlocked_r(const char * ident,int logstat,int logfac,struct syslog_data * data)5312fe8fb19SBen Gras openlog_unlocked_r(const char *ident, int logstat, int logfac,
5322fe8fb19SBen Gras     struct syslog_data *data)
5332fe8fb19SBen Gras {
5342fe8fb19SBen Gras 	if (ident != NULL)
5352fe8fb19SBen Gras 		data->log_tag = ident;
5362fe8fb19SBen Gras 	data->log_stat = logstat;
5372fe8fb19SBen Gras 	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
5382fe8fb19SBen Gras 		data->log_fac = logfac;
5392fe8fb19SBen Gras 
5402fe8fb19SBen Gras 	if (data->log_stat & LOG_NDELAY)	/* open immediately */
5412fe8fb19SBen Gras 		connectlog_r(data);
5422fe8fb19SBen Gras 
543f14fb602SLionel Sambuc 	data->log_opened = 1;
5442fe8fb19SBen Gras }
5452fe8fb19SBen Gras 
5462fe8fb19SBen Gras void
openlog_r(const char * ident,int logstat,int logfac,struct syslog_data * data)5472fe8fb19SBen Gras openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
5482fe8fb19SBen Gras {
54984d9c625SLionel Sambuc #if !defined(__minix)
5502fe8fb19SBen Gras 	if (data == &sdata)
5512fe8fb19SBen Gras 		mutex_lock(&syslog_mutex);
55284d9c625SLionel Sambuc #endif /* !defined(__minix) */
5532fe8fb19SBen Gras 	openlog_unlocked_r(ident, logstat, logfac, data);
55484d9c625SLionel Sambuc #if !defined(__minix)
5552fe8fb19SBen Gras 	if (data == &sdata)
5562fe8fb19SBen Gras 		mutex_unlock(&syslog_mutex);
55784d9c625SLionel Sambuc #endif /* !defined(__minix) */
5582fe8fb19SBen Gras }
5592fe8fb19SBen Gras 
5602fe8fb19SBen Gras void
closelog_r(struct syslog_data * data)5612fe8fb19SBen Gras closelog_r(struct syslog_data *data)
5622fe8fb19SBen Gras {
56384d9c625SLionel Sambuc #if !defined(__minix)
5642fe8fb19SBen Gras 	if (data == &sdata)
5652fe8fb19SBen Gras 		mutex_lock(&syslog_mutex);
56684d9c625SLionel Sambuc #endif /* !defined(__minix) */
5672fe8fb19SBen Gras 	(void)close(data->log_file);
5682fe8fb19SBen Gras 	data->log_file = -1;
569f14fb602SLionel Sambuc 	data->log_connected = 0;
5702fe8fb19SBen Gras 	data->log_tag = NULL;
57184d9c625SLionel Sambuc #if !defined(__minix)
5722fe8fb19SBen Gras 	if (data == &sdata)
5732fe8fb19SBen Gras 		mutex_unlock(&syslog_mutex);
57484d9c625SLionel Sambuc #endif /* !defined(__minix) */
5752fe8fb19SBen Gras }
5762fe8fb19SBen Gras 
5772fe8fb19SBen Gras int
setlogmask_r(int pmask,struct syslog_data * data)5782fe8fb19SBen Gras setlogmask_r(int pmask, struct syslog_data *data)
5792fe8fb19SBen Gras {
5802fe8fb19SBen Gras 	int omask;
5812fe8fb19SBen Gras 
5822fe8fb19SBen Gras 	omask = data->log_mask;
5832fe8fb19SBen Gras 	if (pmask != 0)
5842fe8fb19SBen Gras 		data->log_mask = pmask;
5852fe8fb19SBen Gras 	return omask;
5862fe8fb19SBen Gras }
587