syslog.c revision 11192
1/*
2 * Copyright (c) 1983, 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)syslog.c	8.4 (Berkeley) 3/18/94";
36#endif /* LIBC_SCCS and not lint */
37
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <sys/syslog.h>
41#include <sys/uio.h>
42#include <netdb.h>
43
44#include <errno.h>
45#include <fcntl.h>
46#include <paths.h>
47#include <stdio.h>
48#include <string.h>
49#include <time.h>
50#include <unistd.h>
51
52#if __STDC__
53#include <stdarg.h>
54#else
55#include <varargs.h>
56#endif
57
58static int	LogFile = -1;		/* fd for log */
59static int	connected;		/* have done connect */
60static int	LogStat = 0;		/* status bits, set by openlog() */
61static const char *LogTag = NULL;	/* string to tag the entry with */
62static int	LogFacility = LOG_USER;	/* default facility code */
63static int	LogMask = 0xff;		/* mask of priorities to be logged */
64extern char	*__progname;		/* Program name, from crt0. */
65
66/*
67 * Format of the magic cookie passed through the stdio hook
68 */
69struct bufcookie {
70	char	*base;	/* start of buffer */
71	int	left;
72};
73
74/*
75 * stdio write hook for writing to a static string buffer
76 * XXX: Maybe one day, dynamically allocate it so that the line length
77 *      is `unlimited'.
78 */
79static writehook(cookie, buf, len)
80	void	*cookie;	/* really [struct bufcookie *] */
81	char	*buf;		/* characters to copy */
82	int	len;		/* length to copy */
83{
84	struct bufcookie *h;	/* private `handle' */
85
86	h = (struct bufcookie *)cookie;
87	if (len > h->left) {
88		/* clip in case of wraparound */
89		len = h->left;
90	}
91	if (len > 0) {
92		(void)memcpy(h->base, buf, len); /* `write' it. */
93		h->base += len;
94		h->left -= len;
95	}
96	return 0;
97}
98
99/*
100 * syslog, vsyslog --
101 *	print message on log file; output is intended for syslogd(8).
102 */
103void
104#if __STDC__
105syslog(int pri, const char *fmt, ...)
106#else
107syslog(pri, fmt, va_alist)
108	int pri;
109	char *fmt;
110	va_dcl
111#endif
112{
113	va_list ap;
114
115#if __STDC__
116	va_start(ap, fmt);
117#else
118	va_start(ap);
119#endif
120	vsyslog(pri, fmt, ap);
121	va_end(ap);
122}
123
124void
125vsyslog(pri, fmt, ap)
126	int pri;
127	register const char *fmt;
128	va_list ap;
129{
130	register int cnt;
131	register char ch, *p, *t;
132	time_t now;
133	int fd, saved_errno;
134	char *stdp, tbuf[2048], fmt_cpy[1024];
135	FILE *fp, *fmt_fp;
136	struct bufcookie tbuf_cookie;
137	struct bufcookie fmt_cookie;
138
139#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
140	/* Check for invalid bits. */
141	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
142		syslog(INTERNALLOG,
143		    "syslog: unknown facility/priority: %x", pri);
144		pri &= LOG_PRIMASK|LOG_FACMASK;
145	}
146
147	/* Check priority against setlogmask values. */
148	if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
149		return;
150
151	saved_errno = errno;
152
153	/* Set default facility if none specified. */
154	if ((pri & LOG_FACMASK) == 0)
155		pri |= LogFacility;
156
157	/* Create the primary stdio hook */
158	tbuf_cookie.base = tbuf;
159	tbuf_cookie.left = sizeof(tbuf);
160	fp = fwopen(&tbuf_cookie, writehook);
161	if (fp == NULL)
162		return;
163
164	/* Build the message. */
165	(void)time(&now);
166	(void)fprintf(fp, "<%d>", pri);
167	(void)fprintf(fp, "%.15s ", ctime(&now) + 4);
168	if (LogStat & LOG_PERROR) {
169		/* Transfer to string buffer */
170		(void)fflush(fp);
171		stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
172	}
173	if (LogTag == NULL)
174		LogTag = __progname;
175	if (LogTag != NULL)
176		(void)fprintf(fp, "%s", LogTag);
177	if (LogStat & LOG_PID)
178		(void)fprintf(fp, "[%d]", getpid());
179	if (LogTag != NULL) {
180		(void)fprintf(fp, ": ");
181	}
182
183	/* Check to see if we can skip expanding the %m */
184	if (strstr(fmt, "%m")) {
185
186		/* Create the second stdio hook */
187		fmt_cookie.base = fmt_cpy;
188		fmt_cookie.left = sizeof(fmt_cpy) - 1;
189		fmt_fp = fwopen(&fmt_cookie, writehook);
190		if (fmt_fp == NULL) {
191			fclose(fp);
192			return;
193		}
194
195		/* Substitute error message for %m. */
196		for ( ; ch = *fmt; ++fmt)
197			if (ch == '%' && fmt[1] == 'm') {
198				++fmt;
199				fputs(strerror(saved_errno), fmt_fp);
200			} else
201				fputc(ch, fmt_fp);
202
203		/* Null terminate if room */
204		fputc(0, fmt_fp);
205		fclose(fmt_fp);
206
207		/* Guarantee null termination */
208		fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
209
210		fmt = fmt_cpy;
211	}
212
213	(void)vfprintf(fp, fmt, ap);
214	(void)fclose(fp);
215
216	cnt = sizeof(tbuf) - tbuf_cookie.left;
217
218	/* Output to stderr if requested. */
219	if (LogStat & LOG_PERROR) {
220		struct iovec iov[2];
221		register struct iovec *v = iov;
222
223		v->iov_base = stdp;
224		v->iov_len = cnt - (stdp - tbuf);
225		++v;
226		v->iov_base = "\n";
227		v->iov_len = 1;
228		(void)writev(STDERR_FILENO, iov, 2);
229	}
230
231	/* Get connected, output the message to the local logger. */
232	if (!connected)
233		openlog(LogTag, LogStat | LOG_NDELAY, 0);
234	if (send(LogFile, tbuf, cnt, 0) >= 0)
235		return;
236
237	/*
238	 * Output the message to the console; don't worry about blocking,
239	 * if console blocks everything will.  Make sure the error reported
240	 * is the one from the syslogd failure.
241	 */
242	if (LogStat & LOG_CONS &&
243	    (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) {
244		struct iovec iov[2];
245		register struct iovec *v = iov;
246
247		p = strchr(tbuf, '>') + 1;
248		v->iov_base = p;
249		v->iov_len = cnt - (p - tbuf);
250		++v;
251		v->iov_base = "\r\n";
252		v->iov_len = 2;
253		(void)writev(fd, iov, 2);
254		(void)close(fd);
255	}
256}
257
258static struct sockaddr SyslogAddr;	/* AF_UNIX address of local logger */
259
260void
261openlog(ident, logstat, logfac)
262	const char *ident;
263	int logstat, logfac;
264{
265	if (ident != NULL)
266		LogTag = ident;
267	LogStat = logstat;
268	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
269		LogFacility = logfac;
270
271	if (LogFile == -1) {
272		SyslogAddr.sa_family = AF_UNIX;
273		(void)strncpy(SyslogAddr.sa_data, _PATH_LOG,
274		    sizeof(SyslogAddr.sa_data));
275		if (LogStat & LOG_NDELAY) {
276			if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
277				return;
278			(void)fcntl(LogFile, F_SETFD, 1);
279		}
280	}
281	if (LogFile != -1 && !connected)
282		if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) {
283			(void)close(LogFile);
284			LogFile = -1;
285		} else
286			connected = 1;
287}
288
289void
290closelog()
291{
292	(void)close(LogFile);
293	LogFile = -1;
294	connected = 0;
295}
296
297/* setlogmask -- set the log mask level */
298int
299setlogmask(pmask)
300	int pmask;
301{
302	int omask;
303
304	omask = LogMask;
305	if (pmask != 0)
306		LogMask = pmask;
307	return (omask);
308}
309