xref: /freebsd/lib/libc/gen/syslog.c (revision 8129693e78a67c2362bae5ad0d18e09e74eca311)
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 
3258f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint)
33adf6ad9eSPeter Wemm static char sccsid[] = "@(#)syslog.c	8.5 (Berkeley) 4/29/95";
3458f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */
35b231cb39SDavid E. O'Brien #include <sys/cdefs.h>
36b231cb39SDavid E. O'Brien __FBSDID("$FreeBSD$");
3758f0484fSRodney W. Grimes 
38d201fe46SDaniel Eischen #include "namespace.h"
39*8129693eSEd Schouten #include <sys/param.h>
4058f0484fSRodney W. Grimes #include <sys/socket.h>
4158f0484fSRodney W. Grimes #include <sys/syslog.h>
42*8129693eSEd Schouten #include <sys/time.h>
4358f0484fSRodney W. Grimes #include <sys/uio.h>
44d584948eSBrian Somers #include <sys/un.h>
4558f0484fSRodney W. Grimes #include <netdb.h>
4658f0484fSRodney W. Grimes 
4758f0484fSRodney W. Grimes #include <errno.h>
4858f0484fSRodney W. Grimes #include <fcntl.h>
4958f0484fSRodney W. Grimes #include <paths.h>
5096575206SGleb Smirnoff #include <pthread.h>
5158f0484fSRodney W. Grimes #include <stdio.h>
524cd01193SMark Murray #include <stdlib.h>
5358f0484fSRodney W. Grimes #include <string.h>
5458f0484fSRodney W. Grimes #include <time.h>
5558f0484fSRodney W. Grimes #include <unistd.h>
5658f0484fSRodney W. Grimes 
5758f0484fSRodney W. Grimes #include <stdarg.h>
58d201fe46SDaniel Eischen #include "un-namespace.h"
5958f0484fSRodney W. Grimes 
604cd01193SMark Murray #include "libc_private.h"
614cd01193SMark Murray 
6258f0484fSRodney W. Grimes static int	LogFile = -1;		/* fd for log */
63240d5a9bSGleb Smirnoff static int	status;			/* connection status */
647e6ace85SPeter Wemm static int	opened;			/* have done openlog() */
6558f0484fSRodney W. Grimes static int	LogStat = 0;		/* status bits, set by openlog() */
6658f0484fSRodney W. Grimes static const char *LogTag = NULL;	/* string to tag the entry with */
6758f0484fSRodney W. Grimes static int	LogFacility = LOG_USER;	/* default facility code */
6858f0484fSRodney W. Grimes static int	LogMask = 0xff;		/* mask of priorities to be logged */
6996575206SGleb Smirnoff static pthread_mutex_t	syslog_mutex = PTHREAD_MUTEX_INITIALIZER;
7096575206SGleb Smirnoff 
7196575206SGleb Smirnoff #define	THREAD_LOCK()							\
7296575206SGleb Smirnoff 	do { 								\
7396575206SGleb Smirnoff 		if (__isthreaded) _pthread_mutex_lock(&syslog_mutex);	\
7496575206SGleb Smirnoff 	} while(0)
7596575206SGleb Smirnoff #define	THREAD_UNLOCK()							\
7696575206SGleb Smirnoff 	do {								\
7796575206SGleb Smirnoff 		if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex);	\
7896575206SGleb Smirnoff 	} while(0)
7958f0484fSRodney W. Grimes 
80b231cb39SDavid E. O'Brien static void	disconnectlog(void); /* disconnect from syslogd */
81b231cb39SDavid E. O'Brien static void	connectlog(void);	/* (re)connect to syslogd */
8296575206SGleb Smirnoff static void	openlog_unlocked(const char *, int, int);
837e6ace85SPeter Wemm 
84240d5a9bSGleb Smirnoff enum {
85240d5a9bSGleb Smirnoff 	NOCONN = 0,
86240d5a9bSGleb Smirnoff 	CONNDEF,
87240d5a9bSGleb Smirnoff 	CONNPRIV,
88240d5a9bSGleb Smirnoff };
89240d5a9bSGleb Smirnoff 
9058f0484fSRodney W. Grimes /*
917c8e2aa4SPeter Wemm  * Format of the magic cookie passed through the stdio hook
927c8e2aa4SPeter Wemm  */
937c8e2aa4SPeter Wemm struct bufcookie {
947c8e2aa4SPeter Wemm 	char	*base;	/* start of buffer */
957c8e2aa4SPeter Wemm 	int	left;
967c8e2aa4SPeter Wemm };
977c8e2aa4SPeter Wemm 
987c8e2aa4SPeter Wemm /*
997c8e2aa4SPeter Wemm  * stdio write hook for writing to a static string buffer
1007c8e2aa4SPeter Wemm  * XXX: Maybe one day, dynamically allocate it so that the line length
1017c8e2aa4SPeter Wemm  *      is `unlimited'.
1027c8e2aa4SPeter Wemm  */
103fd42c4d8SStefan Farfeleder static int
104fd42c4d8SStefan Farfeleder writehook(void *cookie, const char *buf, int len)
1057c8e2aa4SPeter Wemm {
1067c8e2aa4SPeter Wemm 	struct bufcookie *h;	/* private `handle' */
1077c8e2aa4SPeter Wemm 
1087c8e2aa4SPeter Wemm 	h = (struct bufcookie *)cookie;
1097c8e2aa4SPeter Wemm 	if (len > h->left) {
1107c8e2aa4SPeter Wemm 		/* clip in case of wraparound */
1117c8e2aa4SPeter Wemm 		len = h->left;
1127c8e2aa4SPeter Wemm 	}
1137c8e2aa4SPeter Wemm 	if (len > 0) {
1147c8e2aa4SPeter Wemm 		(void)memcpy(h->base, buf, len); /* `write' it. */
1157c8e2aa4SPeter Wemm 		h->base += len;
1167c8e2aa4SPeter Wemm 		h->left -= len;
1177c8e2aa4SPeter Wemm 	}
1185b1deb3cSPoul-Henning Kamp 	return len;
1197c8e2aa4SPeter Wemm }
1207c8e2aa4SPeter Wemm 
1217c8e2aa4SPeter Wemm /*
12258f0484fSRodney W. Grimes  * syslog, vsyslog --
12358f0484fSRodney W. Grimes  *	print message on log file; output is intended for syslogd(8).
12458f0484fSRodney W. Grimes  */
12558f0484fSRodney W. Grimes void
12658f0484fSRodney W. Grimes syslog(int pri, const char *fmt, ...)
12758f0484fSRodney W. Grimes {
12858f0484fSRodney W. Grimes 	va_list ap;
12958f0484fSRodney W. Grimes 
13058f0484fSRodney W. Grimes 	va_start(ap, fmt);
13158f0484fSRodney W. Grimes 	vsyslog(pri, fmt, ap);
13258f0484fSRodney W. Grimes 	va_end(ap);
13358f0484fSRodney W. Grimes }
13458f0484fSRodney W. Grimes 
135f3990417SKonstantin Belousov static void
136f3990417SKonstantin Belousov vsyslog1(int pri, const char *fmt, va_list ap)
13758f0484fSRodney W. Grimes {
138*8129693eSEd Schouten 	struct timeval now;
139*8129693eSEd Schouten 	struct tm tm;
140b231cb39SDavid E. O'Brien 	char ch, *p;
141*8129693eSEd Schouten 	long tz_offset;
142*8129693eSEd Schouten 	int cnt, fd, saved_errno;
143*8129693eSEd Schouten 	char hostname[MAXHOSTNAMELEN], *stdp, tbuf[2048], fmt_cpy[1024],
144*8129693eSEd Schouten 	    errstr[64], tz_sign;
1457c8e2aa4SPeter Wemm 	FILE *fp, *fmt_fp;
1467c8e2aa4SPeter Wemm 	struct bufcookie tbuf_cookie;
1477c8e2aa4SPeter Wemm 	struct bufcookie fmt_cookie;
14858f0484fSRodney W. Grimes 
14958f0484fSRodney W. Grimes #define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
15058f0484fSRodney W. Grimes 	/* Check for invalid bits. */
15158f0484fSRodney W. Grimes 	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
15258f0484fSRodney W. Grimes 		syslog(INTERNALLOG,
15358f0484fSRodney W. Grimes 		    "syslog: unknown facility/priority: %x", pri);
15458f0484fSRodney W. Grimes 		pri &= LOG_PRIMASK|LOG_FACMASK;
15558f0484fSRodney W. Grimes 	}
15658f0484fSRodney W. Grimes 
1573a31b448SDavid Xu 	saved_errno = errno;
1583a31b448SDavid Xu 
15958f0484fSRodney W. Grimes 	/* Check priority against setlogmask values. */
160f3990417SKonstantin Belousov 	if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
16158f0484fSRodney W. Grimes 		return;
16258f0484fSRodney W. Grimes 
16358f0484fSRodney W. Grimes 	/* Set default facility if none specified. */
16458f0484fSRodney W. Grimes 	if ((pri & LOG_FACMASK) == 0)
16558f0484fSRodney W. Grimes 		pri |= LogFacility;
16658f0484fSRodney W. Grimes 
1677c8e2aa4SPeter Wemm 	/* Create the primary stdio hook */
1687c8e2aa4SPeter Wemm 	tbuf_cookie.base = tbuf;
1697c8e2aa4SPeter Wemm 	tbuf_cookie.left = sizeof(tbuf);
1707c8e2aa4SPeter Wemm 	fp = fwopen(&tbuf_cookie, writehook);
171f3990417SKonstantin Belousov 	if (fp == NULL)
1727c8e2aa4SPeter Wemm 		return;
1737c8e2aa4SPeter Wemm 
174*8129693eSEd Schouten 	/* Build the message according to RFC 5424. Tag and version. */
175*8129693eSEd Schouten 	(void)fprintf(fp, "<%d>1 ", pri);
176*8129693eSEd Schouten 	/* Timestamp similar to RFC 3339. */
177*8129693eSEd Schouten 	if (gettimeofday(&now, NULL) == 0 &&
178*8129693eSEd Schouten 	    localtime_r(&now.tv_sec, &tm) != NULL) {
179*8129693eSEd Schouten 		if (tm.tm_gmtoff < 0) {
180*8129693eSEd Schouten 			tz_sign = '-';
181*8129693eSEd Schouten 			tz_offset = -tm.tm_gmtoff;
182*8129693eSEd Schouten 		} else {
183*8129693eSEd Schouten 			tz_sign = '+';
184*8129693eSEd Schouten 			tz_offset = tm.tm_gmtoff;
185*8129693eSEd Schouten 		}
186*8129693eSEd Schouten 
187*8129693eSEd Schouten 		(void)fprintf(fp,
188*8129693eSEd Schouten 		    "%04d-%02d-%02d"		/* Date. */
189*8129693eSEd Schouten 		    "T%02d:%02d:%02d.%06ld"	/* Time. */
190*8129693eSEd Schouten 		    "%c%02ld:%02ld ",		/* Time zone offset. */
191*8129693eSEd Schouten 		    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
192*8129693eSEd Schouten 		    tm.tm_hour, tm.tm_min, tm.tm_sec, now.tv_usec,
193*8129693eSEd Schouten 		    tz_sign, tz_offset / 3600, (tz_offset % 3600) / 60);
194*8129693eSEd Schouten 	} else
195*8129693eSEd Schouten 		(void)fprintf(fp, "- ");
196*8129693eSEd Schouten 	/* Hostname. */
197*8129693eSEd Schouten 	(void)gethostname(hostname, sizeof(hostname));
198*8129693eSEd Schouten 	(void)fprintf(fp, "%s ", hostname);
1997c8e2aa4SPeter Wemm 	if (LogStat & LOG_PERROR) {
2007c8e2aa4SPeter Wemm 		/* Transfer to string buffer */
2017c8e2aa4SPeter Wemm 		(void)fflush(fp);
2027c8e2aa4SPeter Wemm 		stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
2037c8e2aa4SPeter Wemm 	}
204*8129693eSEd Schouten 	/*
205*8129693eSEd Schouten 	 * Application name, process ID, message ID and structured data.
206*8129693eSEd Schouten 	 * Provide the process ID regardless of whether LOG_PID has been
207*8129693eSEd Schouten 	 * specified, as it provides valuable information. Many
208*8129693eSEd Schouten 	 * applications tend not to use this, even though they should.
209*8129693eSEd Schouten 	 */
21058f0484fSRodney W. Grimes 	if (LogTag == NULL)
2114cd01193SMark Murray 		LogTag = _getprogname();
212*8129693eSEd Schouten 	(void)fprintf(fp, "%s %d - - ",
213*8129693eSEd Schouten 	    LogTag == NULL ? "-" : LogTag, getpid());
2147c8e2aa4SPeter Wemm 
2157c8e2aa4SPeter Wemm 	/* Check to see if we can skip expanding the %m */
2167c8e2aa4SPeter Wemm 	if (strstr(fmt, "%m")) {
2177c8e2aa4SPeter Wemm 
2187c8e2aa4SPeter Wemm 		/* Create the second stdio hook */
2197c8e2aa4SPeter Wemm 		fmt_cookie.base = fmt_cpy;
2207c8e2aa4SPeter Wemm 		fmt_cookie.left = sizeof(fmt_cpy) - 1;
2217c8e2aa4SPeter Wemm 		fmt_fp = fwopen(&fmt_cookie, writehook);
2227c8e2aa4SPeter Wemm 		if (fmt_fp == NULL) {
2237c8e2aa4SPeter Wemm 			fclose(fp);
2247c8e2aa4SPeter Wemm 			return;
22558f0484fSRodney W. Grimes 		}
22658f0484fSRodney W. Grimes 
227e6cfb1ccSAlfred Perlstein 		/*
228e6cfb1ccSAlfred Perlstein 		 * Substitute error message for %m.  Be careful not to
229e6cfb1ccSAlfred Perlstein 		 * molest an escaped percent "%%m".  We want to pass it
230e6cfb1ccSAlfred Perlstein 		 * on untouched as the format is later parsed by vfprintf.
231e6cfb1ccSAlfred Perlstein 		 */
232e6cfb1ccSAlfred Perlstein 		for ( ; (ch = *fmt); ++fmt) {
23358f0484fSRodney W. Grimes 			if (ch == '%' && fmt[1] == 'm') {
23458f0484fSRodney W. Grimes 				++fmt;
23596575206SGleb Smirnoff 				strerror_r(saved_errno, errstr, sizeof(errstr));
23696575206SGleb Smirnoff 				fputs(errstr, fmt_fp);
237e6cfb1ccSAlfred Perlstein 			} else if (ch == '%' && fmt[1] == '%') {
238e6cfb1ccSAlfred Perlstein 				++fmt;
2397c8e2aa4SPeter Wemm 				fputc(ch, fmt_fp);
240e6cfb1ccSAlfred Perlstein 				fputc(ch, fmt_fp);
241e6cfb1ccSAlfred Perlstein 			} else {
242e6cfb1ccSAlfred Perlstein 				fputc(ch, fmt_fp);
243e6cfb1ccSAlfred Perlstein 			}
244e6cfb1ccSAlfred Perlstein 		}
24558f0484fSRodney W. Grimes 
2467c8e2aa4SPeter Wemm 		/* Null terminate if room */
2477c8e2aa4SPeter Wemm 		fputc(0, fmt_fp);
2487c8e2aa4SPeter Wemm 		fclose(fmt_fp);
2497c8e2aa4SPeter Wemm 
2507c8e2aa4SPeter Wemm 		/* Guarantee null termination */
2517c8e2aa4SPeter Wemm 		fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
2527c8e2aa4SPeter Wemm 
2537c8e2aa4SPeter Wemm 		fmt = fmt_cpy;
2547c8e2aa4SPeter Wemm 	}
2557c8e2aa4SPeter Wemm 
2567c8e2aa4SPeter Wemm 	(void)vfprintf(fp, fmt, ap);
2577c8e2aa4SPeter Wemm 	(void)fclose(fp);
2587c8e2aa4SPeter Wemm 
2597c8e2aa4SPeter Wemm 	cnt = sizeof(tbuf) - tbuf_cookie.left;
26058f0484fSRodney W. Grimes 
261857b57eaSDiomidis Spinellis 	/* Remove a trailing newline */
262857b57eaSDiomidis Spinellis 	if (tbuf[cnt - 1] == '\n')
263857b57eaSDiomidis Spinellis 		cnt--;
264857b57eaSDiomidis Spinellis 
26558f0484fSRodney W. Grimes 	/* Output to stderr if requested. */
26658f0484fSRodney W. Grimes 	if (LogStat & LOG_PERROR) {
26758f0484fSRodney W. Grimes 		struct iovec iov[2];
268b231cb39SDavid E. O'Brien 		struct iovec *v = iov;
26958f0484fSRodney W. Grimes 
27058f0484fSRodney W. Grimes 		v->iov_base = stdp;
27158f0484fSRodney W. Grimes 		v->iov_len = cnt - (stdp - tbuf);
27258f0484fSRodney W. Grimes 		++v;
27358f0484fSRodney W. Grimes 		v->iov_base = "\n";
27458f0484fSRodney W. Grimes 		v->iov_len = 1;
275d201fe46SDaniel Eischen 		(void)_writev(STDERR_FILENO, iov, 2);
27658f0484fSRodney W. Grimes 	}
27758f0484fSRodney W. Grimes 
27858f0484fSRodney W. Grimes 	/* Get connected, output the message to the local logger. */
2797e6ace85SPeter Wemm 	if (!opened)
28096575206SGleb Smirnoff 		openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0);
2817e6ace85SPeter Wemm 	connectlog();
2827e6ace85SPeter Wemm 
2837e6ace85SPeter Wemm 	/*
28452e05d9aSXin LI 	 * If the send() fails, there are two likely scenarios:
2852e89951bSGleb Smirnoff 	 *  1) syslogd was restarted
286240d5a9bSGleb Smirnoff 	 *  2) /var/run/log is out of socket buffer space, which
287240d5a9bSGleb Smirnoff 	 *     in most cases means local DoS.
28852e05d9aSXin LI 	 * If the error does not indicate a full buffer, we address
28952e05d9aSXin LI 	 * case #1 by attempting to reconnect to /var/run/log[priv]
29052e05d9aSXin LI 	 * and resending the message once.
291240d5a9bSGleb Smirnoff 	 *
29252e05d9aSXin LI 	 * If we are working with a privileged socket, the retry
29352e05d9aSXin LI 	 * attempts end there, because we don't want to freeze a
294240d5a9bSGleb Smirnoff 	 * critical application like su(1) or sshd(8).
295240d5a9bSGleb Smirnoff 	 *
29652e05d9aSXin LI 	 * Otherwise, we address case #2 by repeatedly retrying the
29752e05d9aSXin LI 	 * send() to give syslogd a chance to empty its socket buffer.
2987e6ace85SPeter Wemm 	 */
2992e89951bSGleb Smirnoff 
3002e89951bSGleb Smirnoff 	if (send(LogFile, tbuf, cnt, 0) < 0) {
3012e89951bSGleb Smirnoff 		if (errno != ENOBUFS) {
30252e05d9aSXin LI 			/*
30352e05d9aSXin LI 			 * Scenario 1: syslogd was restarted
30452e05d9aSXin LI 			 * reconnect and resend once
30552e05d9aSXin LI 			 */
3067e6ace85SPeter Wemm 			disconnectlog();
3077e6ace85SPeter Wemm 			connectlog();
308f3990417SKonstantin Belousov 			if (send(LogFile, tbuf, cnt, 0) >= 0)
30952e05d9aSXin LI 				return;
31052e05d9aSXin LI 			/*
31152e05d9aSXin LI 			 * if the resend failed, fall through to
31252e05d9aSXin LI 			 * possible scenario 2
31352e05d9aSXin LI 			 */
31452e05d9aSXin LI 		}
31552e05d9aSXin LI 		while (errno == ENOBUFS) {
31652e05d9aSXin LI 			/*
31752e05d9aSXin LI 			 * Scenario 2: out of socket buffer space
31852e05d9aSXin LI 			 * possible DoS, fail fast on a privileged
31952e05d9aSXin LI 			 * socket
32052e05d9aSXin LI 			 */
32105824745SDavid E. O'Brien 			if (status == CONNPRIV)
32205824745SDavid E. O'Brien 				break;
323ed0b0abcSDaniel Eischen 			_usleep(1);
324f3990417SKonstantin Belousov 			if (send(LogFile, tbuf, cnt, 0) >= 0)
3258ba85e77SGleb Smirnoff 				return;
32696575206SGleb Smirnoff 		}
327f3990417SKonstantin Belousov 	} else
3288ba85e77SGleb Smirnoff 		return;
32958f0484fSRodney W. Grimes 
33058f0484fSRodney W. Grimes 	/*
33194998878SDavid Malone 	 * Output the message to the console; try not to block
33294998878SDavid Malone 	 * as a blocking console should not stop other processes.
33394998878SDavid Malone 	 * Make sure the error reported is the one from the syslogd failure.
33458f0484fSRodney W. Grimes 	 */
33558f0484fSRodney W. Grimes 	if (LogStat & LOG_CONS &&
33605eb11cbSJilles Tjoelker 	    (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0)) >=
33705eb11cbSJilles Tjoelker 	    0) {
33811e67a9fSPeter Wemm 		struct iovec iov[2];
339b231cb39SDavid E. O'Brien 		struct iovec *v = iov;
34011e67a9fSPeter Wemm 
341*8129693eSEd Schouten 		p = strchr(tbuf, '>') + 3;
34211e67a9fSPeter Wemm 		v->iov_base = p;
34311e67a9fSPeter Wemm 		v->iov_len = cnt - (p - tbuf);
34411e67a9fSPeter Wemm 		++v;
34511e67a9fSPeter Wemm 		v->iov_base = "\r\n";
34611e67a9fSPeter Wemm 		v->iov_len = 2;
347d201fe46SDaniel Eischen 		(void)_writev(fd, iov, 2);
3489233c4d9SJason Evans 		(void)_close(fd);
34958f0484fSRodney W. Grimes 	}
350f3990417SKonstantin Belousov }
351f3990417SKonstantin Belousov 
352f3990417SKonstantin Belousov static void
353f3990417SKonstantin Belousov syslog_cancel_cleanup(void *arg __unused)
354f3990417SKonstantin Belousov {
35596575206SGleb Smirnoff 
35696575206SGleb Smirnoff 	THREAD_UNLOCK();
35758f0484fSRodney W. Grimes }
35896575206SGleb Smirnoff 
359f3990417SKonstantin Belousov void
360f3990417SKonstantin Belousov vsyslog(int pri, const char *fmt, va_list ap)
361f3990417SKonstantin Belousov {
362f3990417SKonstantin Belousov 
363f3990417SKonstantin Belousov 	THREAD_LOCK();
364f3990417SKonstantin Belousov 	pthread_cleanup_push(syslog_cancel_cleanup, NULL);
365f3990417SKonstantin Belousov 	vsyslog1(pri, fmt, ap);
366f3990417SKonstantin Belousov 	pthread_cleanup_pop(1);
367f3990417SKonstantin Belousov }
368f3990417SKonstantin Belousov 
36996575206SGleb Smirnoff /* Should be called with mutex acquired */
3707e6ace85SPeter Wemm static void
371fd42c4d8SStefan Farfeleder disconnectlog(void)
3727e6ace85SPeter Wemm {
3737e6ace85SPeter Wemm 	/*
3747e6ace85SPeter Wemm 	 * If the user closed the FD and opened another in the same slot,
3757e6ace85SPeter Wemm 	 * that's their problem.  They should close it before calling on
3767e6ace85SPeter Wemm 	 * system services.
3777e6ace85SPeter Wemm 	 */
3787e6ace85SPeter Wemm 	if (LogFile != -1) {
3799233c4d9SJason Evans 		_close(LogFile);
3807e6ace85SPeter Wemm 		LogFile = -1;
3817e6ace85SPeter Wemm 	}
382240d5a9bSGleb Smirnoff 	status = NOCONN;			/* retry connect */
3837e6ace85SPeter Wemm }
3847e6ace85SPeter Wemm 
38596575206SGleb Smirnoff /* Should be called with mutex acquired */
3867e6ace85SPeter Wemm static void
387fd42c4d8SStefan Farfeleder connectlog(void)
3887e6ace85SPeter Wemm {
389d584948eSBrian Somers 	struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
390cf49f439SJohn Polstra 
3917e6ace85SPeter Wemm 	if (LogFile == -1) {
3920b89df4aSJilles Tjoelker 		if ((LogFile = _socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC,
3930b89df4aSJilles Tjoelker 		    0)) == -1)
3947e6ace85SPeter Wemm 			return;
3957e6ace85SPeter Wemm 	}
396240d5a9bSGleb Smirnoff 	if (LogFile != -1 && status == NOCONN) {
397d584948eSBrian Somers 		SyslogAddr.sun_len = sizeof(SyslogAddr);
398d584948eSBrian Somers 		SyslogAddr.sun_family = AF_UNIX;
399240d5a9bSGleb Smirnoff 
400240d5a9bSGleb Smirnoff 		/*
40152e05d9aSXin LI 		 * First try privileged socket. If no success,
402240d5a9bSGleb Smirnoff 		 * then try default socket.
403240d5a9bSGleb Smirnoff 		 */
404240d5a9bSGleb Smirnoff 		(void)strncpy(SyslogAddr.sun_path, _PATH_LOG_PRIV,
405240d5a9bSGleb Smirnoff 		    sizeof SyslogAddr.sun_path);
406240d5a9bSGleb Smirnoff 		if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
407240d5a9bSGleb Smirnoff 		    sizeof(SyslogAddr)) != -1)
408240d5a9bSGleb Smirnoff 			status = CONNPRIV;
409240d5a9bSGleb Smirnoff 
410240d5a9bSGleb Smirnoff 		if (status == NOCONN) {
411d584948eSBrian Somers 			(void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
4120b3b961eSBrian Somers 			    sizeof SyslogAddr.sun_path);
413240d5a9bSGleb Smirnoff 			if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
414240d5a9bSGleb Smirnoff 			    sizeof(SyslogAddr)) != -1)
415240d5a9bSGleb Smirnoff 				status = CONNDEF;
416240d5a9bSGleb Smirnoff 		}
417cf49f439SJohn Polstra 
418240d5a9bSGleb Smirnoff 		if (status == NOCONN) {
419cf49f439SJohn Polstra 			/*
420cf49f439SJohn Polstra 			 * Try the old "/dev/log" path, for backward
421cf49f439SJohn Polstra 			 * compatibility.
422cf49f439SJohn Polstra 			 */
423d584948eSBrian Somers 			(void)strncpy(SyslogAddr.sun_path, _PATH_OLDLOG,
4240b3b961eSBrian Somers 			    sizeof SyslogAddr.sun_path);
425240d5a9bSGleb Smirnoff 			if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
426240d5a9bSGleb Smirnoff 			    sizeof(SyslogAddr)) != -1)
427240d5a9bSGleb Smirnoff 				status = CONNDEF;
428cf49f439SJohn Polstra 		}
429cf49f439SJohn Polstra 
430240d5a9bSGleb Smirnoff 		if (status == NOCONN) {
4319233c4d9SJason Evans 			(void)_close(LogFile);
4327e6ace85SPeter Wemm 			LogFile = -1;
433cf49f439SJohn Polstra 		}
4347e6ace85SPeter Wemm 	}
4357e6ace85SPeter Wemm }
4367e6ace85SPeter Wemm 
43796575206SGleb Smirnoff static void
438fd42c4d8SStefan Farfeleder openlog_unlocked(const char *ident, int logstat, int logfac)
43958f0484fSRodney W. Grimes {
44058f0484fSRodney W. Grimes 	if (ident != NULL)
44158f0484fSRodney W. Grimes 		LogTag = ident;
44258f0484fSRodney W. Grimes 	LogStat = logstat;
44358f0484fSRodney W. Grimes 	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
44458f0484fSRodney W. Grimes 		LogFacility = logfac;
44558f0484fSRodney W. Grimes 
4467e6ace85SPeter Wemm 	if (LogStat & LOG_NDELAY)	/* open immediately */
4477e6ace85SPeter Wemm 		connectlog();
4487e6ace85SPeter Wemm 
4497e6ace85SPeter Wemm 	opened = 1;	/* ident and facility has been set */
45058f0484fSRodney W. Grimes }
45158f0484fSRodney W. Grimes 
45258f0484fSRodney W. Grimes void
453fd42c4d8SStefan Farfeleder openlog(const char *ident, int logstat, int logfac)
45496575206SGleb Smirnoff {
455f3990417SKonstantin Belousov 
45696575206SGleb Smirnoff 	THREAD_LOCK();
457f3990417SKonstantin Belousov 	pthread_cleanup_push(syslog_cancel_cleanup, NULL);
45896575206SGleb Smirnoff 	openlog_unlocked(ident, logstat, logfac);
459f3990417SKonstantin Belousov 	pthread_cleanup_pop(1);
46096575206SGleb Smirnoff }
46196575206SGleb Smirnoff 
46296575206SGleb Smirnoff 
46396575206SGleb Smirnoff void
464fd42c4d8SStefan Farfeleder closelog(void)
46558f0484fSRodney W. Grimes {
46696575206SGleb Smirnoff 	THREAD_LOCK();
467bf36cf8eSEitan Adler 	if (LogFile != -1) {
4689233c4d9SJason Evans 		(void)_close(LogFile);
46958f0484fSRodney W. Grimes 		LogFile = -1;
470bf36cf8eSEitan Adler 	}
471bedff4e8SRuslan Ermilov 	LogTag = NULL;
472240d5a9bSGleb Smirnoff 	status = NOCONN;
47396575206SGleb Smirnoff 	THREAD_UNLOCK();
47458f0484fSRodney W. Grimes }
47558f0484fSRodney W. Grimes 
47658f0484fSRodney W. Grimes /* setlogmask -- set the log mask level */
47758f0484fSRodney W. Grimes int
478fd42c4d8SStefan Farfeleder setlogmask(int pmask)
47958f0484fSRodney W. Grimes {
48058f0484fSRodney W. Grimes 	int omask;
48158f0484fSRodney W. Grimes 
48296575206SGleb Smirnoff 	THREAD_LOCK();
48358f0484fSRodney W. Grimes 	omask = LogMask;
48458f0484fSRodney W. Grimes 	if (pmask != 0)
48558f0484fSRodney W. Grimes 		LogMask = pmask;
48696575206SGleb Smirnoff 	THREAD_UNLOCK();
48758f0484fSRodney W. Grimes 	return (omask);
48858f0484fSRodney W. Grimes }
489