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