xref: /freebsd/lib/libc/gen/syslog.c (revision 2ce3ef55035093cac7839e71e9ff91f5562ebc29)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
458f0484fSRodney W. Grimes  * Copyright (c) 1983, 1988, 1993
558f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
658f0484fSRodney W. Grimes  *
758f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
858f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
958f0484fSRodney W. Grimes  * are met:
1058f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
1158f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1258f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1358f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1458f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1658f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
1758f0484fSRodney W. Grimes  *    without specific prior written permission.
1858f0484fSRodney W. Grimes  *
1958f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2058f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2158f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2258f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2358f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2458f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2558f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2658f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2758f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2858f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2958f0484fSRodney W. Grimes  * SUCH DAMAGE.
3058f0484fSRodney W. Grimes  */
3158f0484fSRodney W. Grimes 
32b231cb39SDavid E. O'Brien #include <sys/cdefs.h>
33c1920558SJohn Baldwin __SCCSID("@(#)syslog.c	8.5 (Berkeley) 4/29/95");
34b231cb39SDavid E. O'Brien __FBSDID("$FreeBSD$");
3558f0484fSRodney W. Grimes 
36d201fe46SDaniel Eischen #include "namespace.h"
378129693eSEd Schouten #include <sys/param.h>
3858f0484fSRodney W. Grimes #include <sys/socket.h>
3958f0484fSRodney W. Grimes #include <sys/syslog.h>
408129693eSEd Schouten #include <sys/time.h>
4158f0484fSRodney W. Grimes #include <sys/uio.h>
42d584948eSBrian Somers #include <sys/un.h>
4358f0484fSRodney W. Grimes #include <netdb.h>
4458f0484fSRodney W. Grimes 
4558f0484fSRodney W. Grimes #include <errno.h>
4658f0484fSRodney W. Grimes #include <fcntl.h>
4758f0484fSRodney W. Grimes #include <paths.h>
4896575206SGleb Smirnoff #include <pthread.h>
49ddc68905SGleb Smirnoff #include <stdbool.h>
5058f0484fSRodney W. Grimes #include <stdio.h>
514cd01193SMark Murray #include <stdlib.h>
5258f0484fSRodney W. Grimes #include <string.h>
5358f0484fSRodney W. Grimes #include <time.h>
5458f0484fSRodney W. Grimes #include <unistd.h>
5558f0484fSRodney W. Grimes 
5658f0484fSRodney W. Grimes #include <stdarg.h>
57d201fe46SDaniel Eischen #include "un-namespace.h"
5858f0484fSRodney W. Grimes 
594cd01193SMark Murray #include "libc_private.h"
604cd01193SMark Murray 
6188105995SDmitry Wagin /* Maximum number of characters of syslog message */
6288105995SDmitry Wagin #define	MAXLINE		8192
6388105995SDmitry Wagin 
6458f0484fSRodney W. Grimes static int	LogFile = -1;		/* fd for log */
65ddc68905SGleb Smirnoff static bool	connected;		/* have done connect */
667e6ace85SPeter Wemm static int	opened;			/* have done openlog() */
6758f0484fSRodney W. Grimes static int	LogStat = 0;		/* status bits, set by openlog() */
68e9ae9fa9SEugene Grosbein static pid_t	LogPid = -1;		/* process id to tag the entry with */
6958f0484fSRodney W. Grimes static const char *LogTag = NULL;	/* string to tag the entry with */
70e9ae9fa9SEugene Grosbein static int	LogTagLength = -1;	/* usable part of LogTag */
7158f0484fSRodney W. Grimes static int	LogFacility = LOG_USER;	/* default facility code */
7258f0484fSRodney W. Grimes static int	LogMask = 0xff;		/* mask of priorities to be logged */
7396575206SGleb Smirnoff static pthread_mutex_t	syslog_mutex = PTHREAD_MUTEX_INITIALIZER;
7496575206SGleb Smirnoff 
7596575206SGleb Smirnoff #define	THREAD_LOCK()							\
7696575206SGleb Smirnoff 	do { 								\
7796575206SGleb Smirnoff 		if (__isthreaded) _pthread_mutex_lock(&syslog_mutex);	\
7896575206SGleb Smirnoff 	} while(0)
7996575206SGleb Smirnoff #define	THREAD_UNLOCK()							\
8096575206SGleb Smirnoff 	do {								\
8196575206SGleb Smirnoff 		if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex);	\
8296575206SGleb Smirnoff 	} while(0)
8358f0484fSRodney W. Grimes 
842933cd31SBryan Drewery /* RFC5424 defined value. */
852933cd31SBryan Drewery #define NILVALUE "-"
862933cd31SBryan Drewery 
87b231cb39SDavid E. O'Brien static void	disconnectlog(void); /* disconnect from syslogd */
88b231cb39SDavid E. O'Brien static void	connectlog(void);	/* (re)connect to syslogd */
8996575206SGleb Smirnoff static void	openlog_unlocked(const char *, int, int);
90e9ae9fa9SEugene Grosbein static void	parse_tag(void);	/* parse ident[NNN] if needed */
917e6ace85SPeter Wemm 
9258f0484fSRodney W. Grimes /*
937c8e2aa4SPeter Wemm  * Format of the magic cookie passed through the stdio hook
947c8e2aa4SPeter Wemm  */
957c8e2aa4SPeter Wemm struct bufcookie {
967c8e2aa4SPeter Wemm 	char	*base;	/* start of buffer */
977c8e2aa4SPeter Wemm 	int	left;
987c8e2aa4SPeter Wemm };
997c8e2aa4SPeter Wemm 
1007c8e2aa4SPeter Wemm /*
1017c8e2aa4SPeter Wemm  * stdio write hook for writing to a static string buffer
1027c8e2aa4SPeter Wemm  * XXX: Maybe one day, dynamically allocate it so that the line length
1037c8e2aa4SPeter Wemm  *      is `unlimited'.
1047c8e2aa4SPeter Wemm  */
105fd42c4d8SStefan Farfeleder static int
106fd42c4d8SStefan Farfeleder writehook(void *cookie, const char *buf, int len)
1077c8e2aa4SPeter Wemm {
1087c8e2aa4SPeter Wemm 	struct bufcookie *h;	/* private `handle' */
1097c8e2aa4SPeter Wemm 
1107c8e2aa4SPeter Wemm 	h = (struct bufcookie *)cookie;
1117c8e2aa4SPeter Wemm 	if (len > h->left) {
1127c8e2aa4SPeter Wemm 		/* clip in case of wraparound */
1137c8e2aa4SPeter Wemm 		len = h->left;
1147c8e2aa4SPeter Wemm 	}
1157c8e2aa4SPeter Wemm 	if (len > 0) {
1167c8e2aa4SPeter Wemm 		(void)memcpy(h->base, buf, len); /* `write' it. */
1177c8e2aa4SPeter Wemm 		h->base += len;
1187c8e2aa4SPeter Wemm 		h->left -= len;
1197c8e2aa4SPeter Wemm 	}
1205b1deb3cSPoul-Henning Kamp 	return len;
1217c8e2aa4SPeter Wemm }
1227c8e2aa4SPeter Wemm 
1237c8e2aa4SPeter Wemm /*
12458f0484fSRodney W. Grimes  * syslog, vsyslog --
12558f0484fSRodney W. Grimes  *	print message on log file; output is intended for syslogd(8).
12658f0484fSRodney W. Grimes  */
12758f0484fSRodney W. Grimes void
12858f0484fSRodney W. Grimes syslog(int pri, const char *fmt, ...)
12958f0484fSRodney W. Grimes {
13058f0484fSRodney W. Grimes 	va_list ap;
13158f0484fSRodney W. Grimes 
13258f0484fSRodney W. Grimes 	va_start(ap, fmt);
13358f0484fSRodney W. Grimes 	vsyslog(pri, fmt, ap);
13458f0484fSRodney W. Grimes 	va_end(ap);
13558f0484fSRodney W. Grimes }
13658f0484fSRodney W. Grimes 
137f3990417SKonstantin Belousov static void
138f3990417SKonstantin Belousov vsyslog1(int pri, const char *fmt, va_list ap)
13958f0484fSRodney W. Grimes {
1408129693eSEd Schouten 	struct timeval now;
1418129693eSEd Schouten 	struct tm tm;
142b231cb39SDavid E. O'Brien 	char ch, *p;
1438129693eSEd Schouten 	long tz_offset;
1448129693eSEd Schouten 	int cnt, fd, saved_errno;
14588105995SDmitry Wagin 	char hostname[MAXHOSTNAMELEN], *stdp, tbuf[MAXLINE], fmt_cpy[MAXLINE],
1468129693eSEd Schouten 	    errstr[64], tz_sign;
1477c8e2aa4SPeter Wemm 	FILE *fp, *fmt_fp;
1487c8e2aa4SPeter Wemm 	struct bufcookie tbuf_cookie;
1497c8e2aa4SPeter Wemm 	struct bufcookie fmt_cookie;
15058f0484fSRodney W. Grimes 
15158f0484fSRodney W. Grimes #define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
15258f0484fSRodney W. Grimes 	/* Check for invalid bits. */
15358f0484fSRodney W. Grimes 	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
15458f0484fSRodney W. Grimes 		syslog(INTERNALLOG,
15558f0484fSRodney W. Grimes 		    "syslog: unknown facility/priority: %x", pri);
15658f0484fSRodney W. Grimes 		pri &= LOG_PRIMASK|LOG_FACMASK;
15758f0484fSRodney W. Grimes 	}
15858f0484fSRodney W. Grimes 
1593a31b448SDavid Xu 	saved_errno = errno;
1603a31b448SDavid Xu 
16158f0484fSRodney W. Grimes 	/* Check priority against setlogmask values. */
162f3990417SKonstantin Belousov 	if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
16358f0484fSRodney W. Grimes 		return;
16458f0484fSRodney W. Grimes 
16558f0484fSRodney W. Grimes 	/* Set default facility if none specified. */
16658f0484fSRodney W. Grimes 	if ((pri & LOG_FACMASK) == 0)
16758f0484fSRodney W. Grimes 		pri |= LogFacility;
16858f0484fSRodney W. Grimes 
1697c8e2aa4SPeter Wemm 	/* Create the primary stdio hook */
1707c8e2aa4SPeter Wemm 	tbuf_cookie.base = tbuf;
1717c8e2aa4SPeter Wemm 	tbuf_cookie.left = sizeof(tbuf);
1727c8e2aa4SPeter Wemm 	fp = fwopen(&tbuf_cookie, writehook);
173f3990417SKonstantin Belousov 	if (fp == NULL)
1747c8e2aa4SPeter Wemm 		return;
1757c8e2aa4SPeter Wemm 
1768129693eSEd Schouten 	/* Build the message according to RFC 5424. Tag and version. */
1778129693eSEd Schouten 	(void)fprintf(fp, "<%d>1 ", pri);
1788129693eSEd Schouten 	/* Timestamp similar to RFC 3339. */
1798129693eSEd Schouten 	if (gettimeofday(&now, NULL) == 0 &&
1808129693eSEd Schouten 	    localtime_r(&now.tv_sec, &tm) != NULL) {
1818129693eSEd Schouten 		if (tm.tm_gmtoff < 0) {
1828129693eSEd Schouten 			tz_sign = '-';
1838129693eSEd Schouten 			tz_offset = -tm.tm_gmtoff;
1848129693eSEd Schouten 		} else {
1858129693eSEd Schouten 			tz_sign = '+';
1868129693eSEd Schouten 			tz_offset = tm.tm_gmtoff;
1878129693eSEd Schouten 		}
1888129693eSEd Schouten 
1898129693eSEd Schouten 		(void)fprintf(fp,
1908129693eSEd Schouten 		    "%04d-%02d-%02d"		/* Date. */
1918129693eSEd Schouten 		    "T%02d:%02d:%02d.%06ld"	/* Time. */
1928129693eSEd Schouten 		    "%c%02ld:%02ld ",		/* Time zone offset. */
1938129693eSEd Schouten 		    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
1948129693eSEd Schouten 		    tm.tm_hour, tm.tm_min, tm.tm_sec, now.tv_usec,
1958129693eSEd Schouten 		    tz_sign, tz_offset / 3600, (tz_offset % 3600) / 60);
1968129693eSEd Schouten 	} else
1972933cd31SBryan Drewery 		(void)fputs(NILVALUE " ", fp);
1988129693eSEd Schouten 	/* Hostname. */
1998129693eSEd Schouten 	(void)gethostname(hostname, sizeof(hostname));
2002933cd31SBryan Drewery 	(void)fprintf(fp, "%s ",
2012933cd31SBryan Drewery 	    hostname[0] == '\0' ? NILVALUE : hostname);
2027c8e2aa4SPeter Wemm 	if (LogStat & LOG_PERROR) {
2037c8e2aa4SPeter Wemm 		/* Transfer to string buffer */
2047c8e2aa4SPeter Wemm 		(void)fflush(fp);
2057c8e2aa4SPeter Wemm 		stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
2067c8e2aa4SPeter Wemm 	}
2072933cd31SBryan Drewery 	/* Application name. */
2082933cd31SBryan Drewery 	if (LogTag == NULL)
2092933cd31SBryan Drewery 		LogTag = _getprogname();
210e9ae9fa9SEugene Grosbein 	else if (LogTagLength == -1)
211e9ae9fa9SEugene Grosbein 		parse_tag();
212e9ae9fa9SEugene Grosbein 	if (LogTagLength > 0)
213e9ae9fa9SEugene Grosbein 		(void)fprintf(fp, "%.*s ", LogTagLength, LogTag);
214e9ae9fa9SEugene Grosbein 	else
2152933cd31SBryan Drewery 		(void)fprintf(fp, "%s ", LogTag == NULL ? NILVALUE : LogTag);
2168129693eSEd Schouten 	/*
2178129693eSEd Schouten 	 * Provide the process ID regardless of whether LOG_PID has been
2188129693eSEd Schouten 	 * specified, as it provides valuable information. Many
2198129693eSEd Schouten 	 * applications tend not to use this, even though they should.
2208129693eSEd Schouten 	 */
221*2ce3ef55SEugene Grosbein 	if (LogTagLength <= 0)
222e9ae9fa9SEugene Grosbein 		LogPid = getpid();
223e9ae9fa9SEugene Grosbein 	(void)fprintf(fp, "%d ", (int)LogPid);
2242933cd31SBryan Drewery 	/* Message ID. */
2252933cd31SBryan Drewery 	(void)fputs(NILVALUE " ", fp);
2262933cd31SBryan Drewery 	/* Structured data. */
2272933cd31SBryan Drewery 	(void)fputs(NILVALUE " ", fp);
2287c8e2aa4SPeter Wemm 
2297c8e2aa4SPeter Wemm 	/* Check to see if we can skip expanding the %m */
2307c8e2aa4SPeter Wemm 	if (strstr(fmt, "%m")) {
2317c8e2aa4SPeter Wemm 
2327c8e2aa4SPeter Wemm 		/* Create the second stdio hook */
2337c8e2aa4SPeter Wemm 		fmt_cookie.base = fmt_cpy;
2347c8e2aa4SPeter Wemm 		fmt_cookie.left = sizeof(fmt_cpy) - 1;
2357c8e2aa4SPeter Wemm 		fmt_fp = fwopen(&fmt_cookie, writehook);
2367c8e2aa4SPeter Wemm 		if (fmt_fp == NULL) {
2377c8e2aa4SPeter Wemm 			fclose(fp);
2387c8e2aa4SPeter Wemm 			return;
23958f0484fSRodney W. Grimes 		}
24058f0484fSRodney W. Grimes 
241e6cfb1ccSAlfred Perlstein 		/*
242e6cfb1ccSAlfred Perlstein 		 * Substitute error message for %m.  Be careful not to
243e6cfb1ccSAlfred Perlstein 		 * molest an escaped percent "%%m".  We want to pass it
244e6cfb1ccSAlfred Perlstein 		 * on untouched as the format is later parsed by vfprintf.
245e6cfb1ccSAlfred Perlstein 		 */
246e6cfb1ccSAlfred Perlstein 		for ( ; (ch = *fmt); ++fmt) {
24758f0484fSRodney W. Grimes 			if (ch == '%' && fmt[1] == 'm') {
24858f0484fSRodney W. Grimes 				++fmt;
24996575206SGleb Smirnoff 				strerror_r(saved_errno, errstr, sizeof(errstr));
25096575206SGleb Smirnoff 				fputs(errstr, fmt_fp);
251e6cfb1ccSAlfred Perlstein 			} else if (ch == '%' && fmt[1] == '%') {
252e6cfb1ccSAlfred Perlstein 				++fmt;
2537c8e2aa4SPeter Wemm 				fputc(ch, fmt_fp);
254e6cfb1ccSAlfred Perlstein 				fputc(ch, fmt_fp);
255e6cfb1ccSAlfred Perlstein 			} else {
256e6cfb1ccSAlfred Perlstein 				fputc(ch, fmt_fp);
257e6cfb1ccSAlfred Perlstein 			}
258e6cfb1ccSAlfred Perlstein 		}
25958f0484fSRodney W. Grimes 
2607c8e2aa4SPeter Wemm 		/* Null terminate if room */
2617c8e2aa4SPeter Wemm 		fputc(0, fmt_fp);
2627c8e2aa4SPeter Wemm 		fclose(fmt_fp);
2637c8e2aa4SPeter Wemm 
2647c8e2aa4SPeter Wemm 		/* Guarantee null termination */
2657c8e2aa4SPeter Wemm 		fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
2667c8e2aa4SPeter Wemm 
2677c8e2aa4SPeter Wemm 		fmt = fmt_cpy;
2687c8e2aa4SPeter Wemm 	}
2697c8e2aa4SPeter Wemm 
2702933cd31SBryan Drewery 	/* Message. */
2717c8e2aa4SPeter Wemm 	(void)vfprintf(fp, fmt, ap);
2727c8e2aa4SPeter Wemm 	(void)fclose(fp);
2737c8e2aa4SPeter Wemm 
2747c8e2aa4SPeter Wemm 	cnt = sizeof(tbuf) - tbuf_cookie.left;
27558f0484fSRodney W. Grimes 
276857b57eaSDiomidis Spinellis 	/* Remove a trailing newline */
277857b57eaSDiomidis Spinellis 	if (tbuf[cnt - 1] == '\n')
278857b57eaSDiomidis Spinellis 		cnt--;
279857b57eaSDiomidis Spinellis 
28058f0484fSRodney W. Grimes 	/* Output to stderr if requested. */
28158f0484fSRodney W. Grimes 	if (LogStat & LOG_PERROR) {
28258f0484fSRodney W. Grimes 		struct iovec iov[2];
283b231cb39SDavid E. O'Brien 		struct iovec *v = iov;
28458f0484fSRodney W. Grimes 
28558f0484fSRodney W. Grimes 		v->iov_base = stdp;
28658f0484fSRodney W. Grimes 		v->iov_len = cnt - (stdp - tbuf);
28758f0484fSRodney W. Grimes 		++v;
28858f0484fSRodney W. Grimes 		v->iov_base = "\n";
28958f0484fSRodney W. Grimes 		v->iov_len = 1;
290d201fe46SDaniel Eischen 		(void)_writev(STDERR_FILENO, iov, 2);
29158f0484fSRodney W. Grimes 	}
29258f0484fSRodney W. Grimes 
29358f0484fSRodney W. Grimes 	/* Get connected, output the message to the local logger. */
2947e6ace85SPeter Wemm 	if (!opened)
29596575206SGleb Smirnoff 		openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0);
2967e6ace85SPeter Wemm 	connectlog();
2977e6ace85SPeter Wemm 
2987e6ace85SPeter Wemm 	/*
299ddc68905SGleb Smirnoff 	 * If the send() failed, there are two likely scenarios:
300ddc68905SGleb Smirnoff 	 * 1) syslogd was restarted.  In this case make one (only) attempt
301ddc68905SGleb Smirnoff 	 *    to reconnect.
302ddc68905SGleb Smirnoff 	 * 2) We filled our buffer due to syslogd not being able to read
303ddc68905SGleb Smirnoff 	 *    as fast as we write.  In this case prefer to lose the current
304ddc68905SGleb Smirnoff 	 *    message rather than whole buffer of previously logged data.
3057e6ace85SPeter Wemm 	 */
3062e89951bSGleb Smirnoff 	if (send(LogFile, tbuf, cnt, 0) < 0) {
3072e89951bSGleb Smirnoff 		if (errno != ENOBUFS) {
3087e6ace85SPeter Wemm 			disconnectlog();
3097e6ace85SPeter Wemm 			connectlog();
310f3990417SKonstantin Belousov 			if (send(LogFile, tbuf, cnt, 0) >= 0)
31152e05d9aSXin LI 				return;
31296575206SGleb Smirnoff 		}
313f3990417SKonstantin Belousov 	} else
3148ba85e77SGleb Smirnoff 		return;
31558f0484fSRodney W. Grimes 
31658f0484fSRodney W. Grimes 	/*
31794998878SDavid Malone 	 * Output the message to the console; try not to block
31894998878SDavid Malone 	 * as a blocking console should not stop other processes.
31994998878SDavid Malone 	 * Make sure the error reported is the one from the syslogd failure.
32058f0484fSRodney W. Grimes 	 */
32158f0484fSRodney W. Grimes 	if (LogStat & LOG_CONS &&
32205eb11cbSJilles Tjoelker 	    (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0)) >=
32305eb11cbSJilles Tjoelker 	    0) {
32411e67a9fSPeter Wemm 		struct iovec iov[2];
325b231cb39SDavid E. O'Brien 		struct iovec *v = iov;
32611e67a9fSPeter Wemm 
3278129693eSEd Schouten 		p = strchr(tbuf, '>') + 3;
32811e67a9fSPeter Wemm 		v->iov_base = p;
32911e67a9fSPeter Wemm 		v->iov_len = cnt - (p - tbuf);
33011e67a9fSPeter Wemm 		++v;
33111e67a9fSPeter Wemm 		v->iov_base = "\r\n";
33211e67a9fSPeter Wemm 		v->iov_len = 2;
333d201fe46SDaniel Eischen 		(void)_writev(fd, iov, 2);
3349233c4d9SJason Evans 		(void)_close(fd);
33558f0484fSRodney W. Grimes 	}
336f3990417SKonstantin Belousov }
337f3990417SKonstantin Belousov 
338f3990417SKonstantin Belousov static void
339f3990417SKonstantin Belousov syslog_cancel_cleanup(void *arg __unused)
340f3990417SKonstantin Belousov {
34196575206SGleb Smirnoff 
34296575206SGleb Smirnoff 	THREAD_UNLOCK();
34358f0484fSRodney W. Grimes }
34496575206SGleb Smirnoff 
345f3990417SKonstantin Belousov void
346f3990417SKonstantin Belousov vsyslog(int pri, const char *fmt, va_list ap)
347f3990417SKonstantin Belousov {
348f3990417SKonstantin Belousov 
349f3990417SKonstantin Belousov 	THREAD_LOCK();
350f3990417SKonstantin Belousov 	pthread_cleanup_push(syslog_cancel_cleanup, NULL);
351f3990417SKonstantin Belousov 	vsyslog1(pri, fmt, ap);
352f3990417SKonstantin Belousov 	pthread_cleanup_pop(1);
353f3990417SKonstantin Belousov }
354f3990417SKonstantin Belousov 
35596575206SGleb Smirnoff /* Should be called with mutex acquired */
3567e6ace85SPeter Wemm static void
357fd42c4d8SStefan Farfeleder disconnectlog(void)
3587e6ace85SPeter Wemm {
3597e6ace85SPeter Wemm 	/*
3607e6ace85SPeter Wemm 	 * If the user closed the FD and opened another in the same slot,
3617e6ace85SPeter Wemm 	 * that's their problem.  They should close it before calling on
3627e6ace85SPeter Wemm 	 * system services.
3637e6ace85SPeter Wemm 	 */
3647e6ace85SPeter Wemm 	if (LogFile != -1) {
3659233c4d9SJason Evans 		_close(LogFile);
3667e6ace85SPeter Wemm 		LogFile = -1;
3677e6ace85SPeter Wemm 	}
368ddc68905SGleb Smirnoff 	connected = false;			/* retry connect */
3697e6ace85SPeter Wemm }
3707e6ace85SPeter Wemm 
37196575206SGleb Smirnoff /* Should be called with mutex acquired */
3727e6ace85SPeter Wemm static void
373fd42c4d8SStefan Farfeleder connectlog(void)
3747e6ace85SPeter Wemm {
375d584948eSBrian Somers 	struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
376cf49f439SJohn Polstra 
3777e6ace85SPeter Wemm 	if (LogFile == -1) {
37888105995SDmitry Wagin 		socklen_t len;
37988105995SDmitry Wagin 
3800b89df4aSJilles Tjoelker 		if ((LogFile = _socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
3810b89df4aSJilles Tjoelker 		    0)) == -1)
3827e6ace85SPeter Wemm 			return;
38388105995SDmitry Wagin 		if (_getsockopt(LogFile, SOL_SOCKET, SO_SNDBUF, &len,
38488105995SDmitry Wagin 		    &(socklen_t){sizeof(len)}) == 0) {
38588105995SDmitry Wagin 			if (len < MAXLINE) {
38688105995SDmitry Wagin 				len = MAXLINE;
38788105995SDmitry Wagin 				(void)_setsockopt(LogFile, SOL_SOCKET, SO_SNDBUF,
38888105995SDmitry Wagin 				    &len, sizeof(len));
38988105995SDmitry Wagin 			}
39088105995SDmitry Wagin 		}
3917e6ace85SPeter Wemm 	}
392ddc68905SGleb Smirnoff 	if (!connected) {
393d584948eSBrian Somers 		SyslogAddr.sun_len = sizeof(SyslogAddr);
394d584948eSBrian Somers 		SyslogAddr.sun_family = AF_UNIX;
395240d5a9bSGleb Smirnoff 
396d584948eSBrian Somers 		(void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
3970b3b961eSBrian Somers 		    sizeof SyslogAddr.sun_path);
398240d5a9bSGleb Smirnoff 		if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
399240d5a9bSGleb Smirnoff 		    sizeof(SyslogAddr)) != -1)
400ddc68905SGleb Smirnoff 			connected = true;
401ddc68905SGleb Smirnoff 		else {
4029233c4d9SJason Evans 			(void)_close(LogFile);
4037e6ace85SPeter Wemm 			LogFile = -1;
404cf49f439SJohn Polstra 		}
4057e6ace85SPeter Wemm 	}
4067e6ace85SPeter Wemm }
4077e6ace85SPeter Wemm 
40896575206SGleb Smirnoff static void
409fd42c4d8SStefan Farfeleder openlog_unlocked(const char *ident, int logstat, int logfac)
41058f0484fSRodney W. Grimes {
411e9ae9fa9SEugene Grosbein 	if (ident != NULL) {
41258f0484fSRodney W. Grimes 		LogTag = ident;
413e9ae9fa9SEugene Grosbein 		LogTagLength = -1;
414e9ae9fa9SEugene Grosbein 	}
41558f0484fSRodney W. Grimes 	LogStat = logstat;
416e9ae9fa9SEugene Grosbein 	parse_tag();
41758f0484fSRodney W. Grimes 	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
41858f0484fSRodney W. Grimes 		LogFacility = logfac;
41958f0484fSRodney W. Grimes 
4207e6ace85SPeter Wemm 	if (LogStat & LOG_NDELAY)	/* open immediately */
4217e6ace85SPeter Wemm 		connectlog();
4227e6ace85SPeter Wemm 
4237e6ace85SPeter Wemm 	opened = 1;	/* ident and facility has been set */
42458f0484fSRodney W. Grimes }
42558f0484fSRodney W. Grimes 
42658f0484fSRodney W. Grimes void
427fd42c4d8SStefan Farfeleder openlog(const char *ident, int logstat, int logfac)
42896575206SGleb Smirnoff {
429f3990417SKonstantin Belousov 
43096575206SGleb Smirnoff 	THREAD_LOCK();
431f3990417SKonstantin Belousov 	pthread_cleanup_push(syslog_cancel_cleanup, NULL);
43296575206SGleb Smirnoff 	openlog_unlocked(ident, logstat, logfac);
433f3990417SKonstantin Belousov 	pthread_cleanup_pop(1);
43496575206SGleb Smirnoff }
43596575206SGleb Smirnoff 
43696575206SGleb Smirnoff 
43796575206SGleb Smirnoff void
438fd42c4d8SStefan Farfeleder closelog(void)
43958f0484fSRodney W. Grimes {
44096575206SGleb Smirnoff 	THREAD_LOCK();
441bf36cf8eSEitan Adler 	if (LogFile != -1) {
4429233c4d9SJason Evans 		(void)_close(LogFile);
44358f0484fSRodney W. Grimes 		LogFile = -1;
444bf36cf8eSEitan Adler 	}
445bedff4e8SRuslan Ermilov 	LogTag = NULL;
446e9ae9fa9SEugene Grosbein 	LogTagLength = -1;
447ddc68905SGleb Smirnoff 	connected = false;
44896575206SGleb Smirnoff 	THREAD_UNLOCK();
44958f0484fSRodney W. Grimes }
45058f0484fSRodney W. Grimes 
45158f0484fSRodney W. Grimes /* setlogmask -- set the log mask level */
45258f0484fSRodney W. Grimes int
453fd42c4d8SStefan Farfeleder setlogmask(int pmask)
45458f0484fSRodney W. Grimes {
45558f0484fSRodney W. Grimes 	int omask;
45658f0484fSRodney W. Grimes 
45796575206SGleb Smirnoff 	THREAD_LOCK();
45858f0484fSRodney W. Grimes 	omask = LogMask;
45958f0484fSRodney W. Grimes 	if (pmask != 0)
46058f0484fSRodney W. Grimes 		LogMask = pmask;
46196575206SGleb Smirnoff 	THREAD_UNLOCK();
46258f0484fSRodney W. Grimes 	return (omask);
46358f0484fSRodney W. Grimes }
464e9ae9fa9SEugene Grosbein 
465e9ae9fa9SEugene Grosbein /*
4666ab555cfSEugene Grosbein  * Obtain LogPid from LogTag formatted as per RFC 3164,
4676ab555cfSEugene Grosbein  * Section 5.3 Originating Process Information:
4686ab555cfSEugene Grosbein  *
4696ab555cfSEugene Grosbein  * ident[NNN]
470e9ae9fa9SEugene Grosbein  */
471e9ae9fa9SEugene Grosbein static void
472e9ae9fa9SEugene Grosbein parse_tag(void)
473e9ae9fa9SEugene Grosbein {
474e9ae9fa9SEugene Grosbein 	char *begin, *end, *p;
475e9ae9fa9SEugene Grosbein 	pid_t pid;
476e9ae9fa9SEugene Grosbein 
477e9ae9fa9SEugene Grosbein 	if (LogTag == NULL || (LogStat & LOG_PID) != 0)
478e9ae9fa9SEugene Grosbein 		return;
479e9ae9fa9SEugene Grosbein 	/*
480e9ae9fa9SEugene Grosbein 	 * LogTagLength is -1 if LogTag was not parsed yet.
481e9ae9fa9SEugene Grosbein 	 * Avoid multiple passes over same LogTag.
482e9ae9fa9SEugene Grosbein 	 */
483e9ae9fa9SEugene Grosbein 	LogTagLength = 0;
484e9ae9fa9SEugene Grosbein 
485e9ae9fa9SEugene Grosbein 	/* Check for presence of opening [ and non-empty ident. */
486e9ae9fa9SEugene Grosbein 	if ((begin = strchr(LogTag, '[')) == NULL || begin == LogTag)
487e9ae9fa9SEugene Grosbein 		return;
488e9ae9fa9SEugene Grosbein 	/* Check for presence of closing ] at the very end and non-empty pid. */
489e9ae9fa9SEugene Grosbein 	if ((end = strchr(begin + 1, ']')) == NULL || end[1] != 0 ||
490e9ae9fa9SEugene Grosbein 	    (end - begin) < 2)
491e9ae9fa9SEugene Grosbein 		return;
492e9ae9fa9SEugene Grosbein 
493e9ae9fa9SEugene Grosbein 	/* Check for pid to contain digits only. */
494e9ae9fa9SEugene Grosbein 	pid = (pid_t)strtol(begin + 1, &p, 10);
495e9ae9fa9SEugene Grosbein 	if (p != end)
496e9ae9fa9SEugene Grosbein 		return;
497e9ae9fa9SEugene Grosbein 
498e9ae9fa9SEugene Grosbein 	LogPid = pid;
499e9ae9fa9SEugene Grosbein 	LogTagLength = begin - LogTag;
500e9ae9fa9SEugene Grosbein }
501