xref: /openbsd-src/lib/libc/gen/syslog_r.c (revision 368cffecf9aefef02a0ec7561324e07b016a2de1)
1*368cffecSderaadt /*	$OpenBSD: syslog_r.c,v 1.20 2024/04/03 04:36:53 deraadt Exp $ */
223599751Sguenther /*
323599751Sguenther  * Copyright (c) 1983, 1988, 1993
423599751Sguenther  *	The Regents of the University of California.  All rights reserved.
523599751Sguenther  *
623599751Sguenther  * Redistribution and use in source and binary forms, with or without
723599751Sguenther  * modification, are permitted provided that the following conditions
823599751Sguenther  * are met:
923599751Sguenther  * 1. Redistributions of source code must retain the above copyright
1023599751Sguenther  *    notice, this list of conditions and the following disclaimer.
1123599751Sguenther  * 2. Redistributions in binary form must reproduce the above copyright
1223599751Sguenther  *    notice, this list of conditions and the following disclaimer in the
1323599751Sguenther  *    documentation and/or other materials provided with the distribution.
1423599751Sguenther  * 3. Neither the name of the University nor the names of its contributors
1523599751Sguenther  *    may be used to endorse or promote products derived from this software
1623599751Sguenther  *    without specific prior written permission.
1723599751Sguenther  *
1823599751Sguenther  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1923599751Sguenther  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2023599751Sguenther  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2123599751Sguenther  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2223599751Sguenther  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2323599751Sguenther  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2423599751Sguenther  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2523599751Sguenther  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2623599751Sguenther  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2723599751Sguenther  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2823599751Sguenther  * SUCH DAMAGE.
2923599751Sguenther  */
3023599751Sguenther 
3123599751Sguenther #include <sys/types.h>
3223599751Sguenther #include <sys/uio.h>
3323599751Sguenther #include <netdb.h>
3423599751Sguenther 
3523599751Sguenther #include <errno.h>
3623599751Sguenther #include <fcntl.h>
3723599751Sguenther #include <paths.h>
3823599751Sguenther #include <stdio.h>
39e4224292Sguenther #include <stdlib.h>
4023599751Sguenther #include <string.h>
414fb98022Sguenther #include <syslog.h>
4223599751Sguenther #include <time.h>
4323599751Sguenther #include <unistd.h>
4477f21357Sderaadt #include <limits.h>
4523599751Sguenther #include <stdarg.h>
4623599751Sguenther 
4723599751Sguenther /* Reentrant version of syslog, i.e. syslog_r() */
4823599751Sguenther void
syslog_r(int pri,struct syslog_data * data,const char * fmt,...)4923599751Sguenther syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
5023599751Sguenther {
5123599751Sguenther 	va_list ap;
5223599751Sguenther 
5323599751Sguenther 	va_start(ap, fmt);
5423599751Sguenther 	vsyslog_r(pri, data, fmt, ap);
5523599751Sguenther 	va_end(ap);
5623599751Sguenther }
574fb98022Sguenther DEF_WEAK(syslog_r);
5823599751Sguenther 
5923599751Sguenther void
vsyslog_r(int pri,struct syslog_data * data,const char * fmt,va_list ap)6023599751Sguenther vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
6123599751Sguenther {
621778bf5bSderaadt 	__vsyslog_r(pri, data, 1, fmt, ap);
6323599751Sguenther }
644fb98022Sguenther DEF_WEAK(vsyslog_r);
6523599751Sguenther 
6623599751Sguenther /*
671778bf5bSderaadt  * This is used by both syslog_r and syslog.
6823599751Sguenther  */
6923599751Sguenther void
__vsyslog_r(int pri,struct syslog_data * data,int reentrant,const char * fmt,va_list ap)7023599751Sguenther __vsyslog_r(int pri, struct syslog_data *data,
711778bf5bSderaadt     int reentrant, const char *fmt, va_list ap)
7223599751Sguenther {
7323599751Sguenther 	int cnt;
7423599751Sguenther 	char ch, *p, *t;
75*368cffecSderaadt 	int saved_errno = errno;	/* use original errno */
76e868d397Sbluhm #define	TBUF_SIZE	(LOG_MAXLINE+1)
77600aaf0eSbluhm #define	FMT_SIZE	(1024+1)
78e2b64692Sbluhm 	char *stdp = NULL, tbuf[TBUF_SIZE], fmt_cpy[FMT_SIZE];
7923599751Sguenther 	int tbuf_left, fmt_left, prlen;
8023599751Sguenther 
8123599751Sguenther #define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
8223599751Sguenther 	/* Check for invalid bits. */
8323599751Sguenther 	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
8423599751Sguenther 		syslog_r(INTERNALLOG, data,
8523599751Sguenther 		    "syslog%s: unknown facility/priority: %x",
861778bf5bSderaadt 		    reentrant ? "_r" : "", pri);
8723599751Sguenther 		pri &= LOG_PRIMASK|LOG_FACMASK;
8823599751Sguenther 	}
8923599751Sguenther 
9023599751Sguenther 	/* Check priority against setlogmask values. */
9123599751Sguenther 	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
92*368cffecSderaadt 		goto done;
9323599751Sguenther 
9423599751Sguenther 	/* Set default facility if none specified. */
9523599751Sguenther 	if ((pri & LOG_FACMASK) == 0)
9623599751Sguenther 		pri |= data->log_fac;
9723599751Sguenther 
9823599751Sguenther 	p = tbuf;
99600aaf0eSbluhm 	tbuf_left = TBUF_SIZE;
10023599751Sguenther 
10123599751Sguenther #define	DEC()	\
10223599751Sguenther 	do {					\
10323599751Sguenther 		if (prlen < 0)			\
10423599751Sguenther 			prlen = 0;		\
10523599751Sguenther 		if (prlen >= tbuf_left)		\
10623599751Sguenther 			prlen = tbuf_left - 1;	\
10723599751Sguenther 		p += prlen;			\
10823599751Sguenther 		tbuf_left -= prlen;		\
10923599751Sguenther 	} while (0)
11023599751Sguenther 
11123599751Sguenther 	prlen = snprintf(p, tbuf_left, "<%d>", pri);
11223599751Sguenther 	DEC();
11323599751Sguenther 
11423599751Sguenther 	if (data->log_stat & LOG_PERROR)
11523599751Sguenther 		stdp = p;
11623599751Sguenther 	if (data->log_tag == NULL)
11723599751Sguenther 		data->log_tag = __progname;
11823599751Sguenther 	if (data->log_tag != NULL) {
11977f21357Sderaadt 		prlen = snprintf(p, tbuf_left, "%.*s", NAME_MAX, data->log_tag);
12023599751Sguenther 		DEC();
12123599751Sguenther 	}
12223599751Sguenther 	if (data->log_stat & LOG_PID) {
12323599751Sguenther 		prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid());
12423599751Sguenther 		DEC();
12523599751Sguenther 	}
12623599751Sguenther 	if (data->log_tag != NULL) {
12723599751Sguenther 		if (tbuf_left > 1) {
12823599751Sguenther 			*p++ = ':';
12923599751Sguenther 			tbuf_left--;
13023599751Sguenther 		}
13123599751Sguenther 		if (tbuf_left > 1) {
13223599751Sguenther 			*p++ = ' ';
13323599751Sguenther 			tbuf_left--;
13423599751Sguenther 		}
13523599751Sguenther 	}
13623599751Sguenther 
137600aaf0eSbluhm 	for (t = fmt_cpy, fmt_left = FMT_SIZE;
138600aaf0eSbluhm 	    (ch = *fmt) != '\0' && fmt_left > 1;
139600aaf0eSbluhm 	    ++fmt) {
14023599751Sguenther 		if (ch == '%' && fmt[1] == 'm') {
1416ac5adf8Smillert 			char ebuf[NL_TEXTMAX];
1426ac5adf8Smillert 
14323599751Sguenther 			++fmt;
1446ac5adf8Smillert 			(void)strerror_r(saved_errno, ebuf, sizeof(ebuf));
1456ac5adf8Smillert 			prlen = snprintf(t, fmt_left, "%s", ebuf);
14623599751Sguenther 			if (prlen < 0)
14723599751Sguenther 				prlen = 0;
14823599751Sguenther 			if (prlen >= fmt_left)
14923599751Sguenther 				prlen = fmt_left - 1;
15023599751Sguenther 			t += prlen;
15123599751Sguenther 			fmt_left -= prlen;
15223599751Sguenther 		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
153600aaf0eSbluhm 			++fmt;
15423599751Sguenther 			*t++ = '%';
15523599751Sguenther 			*t++ = '%';
15623599751Sguenther 			fmt_left -= 2;
15723599751Sguenther 		} else {
15823599751Sguenther 			*t++ = ch;
15923599751Sguenther 			fmt_left--;
16023599751Sguenther 		}
16123599751Sguenther 	}
16223599751Sguenther 	*t = '\0';
16323599751Sguenther 
16423599751Sguenther 	prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
16523599751Sguenther 	DEC();
16623599751Sguenther 	cnt = p - tbuf;
167d5e51dafSbluhm 	while (cnt > 0 && p[-1] == '\n') {
168d5e51dafSbluhm 		*(--p) = '\0';
169d5e51dafSbluhm 		--cnt;
170d5e51dafSbluhm 	}
17123599751Sguenther 
17223599751Sguenther 	/* Output to stderr if requested. */
17323599751Sguenther 	if (data->log_stat & LOG_PERROR) {
17423599751Sguenther 		struct iovec iov[2];
17523599751Sguenther 
17623599751Sguenther 		iov[0].iov_base = stdp;
177d5e51dafSbluhm 		iov[0].iov_len = cnt > stdp - tbuf ? cnt - (stdp - tbuf) : 0;
17823599751Sguenther 		iov[1].iov_base = "\n";
17923599751Sguenther 		iov[1].iov_len = 1;
18023599751Sguenther 		(void)writev(STDERR_FILENO, iov, 2);
18123599751Sguenther 	}
18223599751Sguenther 
18323599751Sguenther 	/*
18446afc4a4Sbluhm 	 * If the sendsyslog() fails, it means that syslogd
185f96efd98Smillert 	 * is not running or the kernel ran out of buffers.
18623599751Sguenther 	 */
18746afc4a4Sbluhm 	sendsyslog(tbuf, cnt, data->log_stat & LOG_CONS);
188*368cffecSderaadt done:
189*368cffecSderaadt 	errno = saved_errno;
19023599751Sguenther }
19123599751Sguenther 
19223599751Sguenther void
openlog_r(const char * ident,int logstat,int logfac,struct syslog_data * data)19323599751Sguenther openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
19423599751Sguenther {
19523599751Sguenther 	if (ident != NULL)
19623599751Sguenther 		data->log_tag = ident;
19723599751Sguenther 	data->log_stat = logstat;
19823599751Sguenther 	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
19923599751Sguenther 		data->log_fac = logfac;
20023599751Sguenther }
2014fb98022Sguenther DEF_WEAK(openlog_r);
20223599751Sguenther 
20323599751Sguenther void
closelog_r(struct syslog_data * data)20423599751Sguenther closelog_r(struct syslog_data *data)
20523599751Sguenther {
20623599751Sguenther 	data->log_tag = NULL;
20723599751Sguenther }
2084fb98022Sguenther DEF_WEAK(closelog_r);
209