1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright (c) 1993
25 *	The Regents of the University of California.  All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 *    notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 *    notice, this list of conditions and the following disclaimer in the
34 *    documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 *    must display the following acknowledgement:
37 *	This product includes software developed by the University of
38 *	California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 *    may be used to endorse or promote products derived from this software
41 *    without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56#include <sys/types.h>
57#include <sys/socket.h>
58#include <sys/syslog.h>
59#include <sys/uio.h>
60#include <sys/un.h>
61#include <netdb.h>
62
63#include <errno.h>
64#include <fcntl.h>
65#include <paths.h>
66#include <stdio.h>
67#include <string.h>
68#include <time.h>
69#include <unistd.h>
70
71#ifdef __STDC__
72#include <stdarg.h>
73#else
74#include <varargs.h>
75#endif
76
77#include <crt_externs.h>
78
79#ifdef BUILDING_VARIANT
80__private_extern__ int	_sl_LogFile;		/* fd for log */
81__private_extern__ int	_sl_connected;		/* have done connect */
82__private_extern__ int	_sl_LogStat;		/* status bits, set by openlog() */
83__private_extern__ const char *_sl_LogTag;	/* string to tag the entry with */
84__private_extern__ int	_sl_LogFacility;	/* default facility code */
85__private_extern__ int	_sl_LogMask;		/* mask of priorities to be logged */
86#else /* !BUILDING_VARIANT */
87__private_extern__ int	_sl_LogFile = -1;		/* fd for log */
88__private_extern__ int	_sl_connected = 0;		/* have done connect */
89__private_extern__ int	_sl_LogStat = 0;		/* status bits, set by openlog() */
90__private_extern__ const char *_sl_LogTag = NULL;	/* string to tag the entry with */
91__private_extern__ int	_sl_LogFacility = LOG_USER;	/* default facility code */
92__private_extern__ int	_sl_LogMask = 0xff;		/* mask of priorities to be logged */
93#endif /* BUILDING_VARIANT */
94
95/*
96 * syslog, vsyslog --
97 *	print message on log file; output is intended for syslogd(8).
98 */
99void
100#ifdef __STDC__
101syslog(int pri, const char *fmt, ...)
102#else
103syslog(pri, fmt, va_alist)
104	int pri;
105	char *fmt;
106	va_dcl
107#endif
108{
109	va_list ap;
110
111#ifdef __STDC__
112	va_start(ap, fmt);
113#else
114	va_start(ap);
115#endif
116	vsyslog(pri, fmt, ap);
117	va_end(ap);
118}
119
120void
121vsyslog(pri, fmt, ap)
122	int pri;
123	register const char *fmt;
124	va_list ap;
125{
126	register int cnt;
127	register char ch, *p, *t;
128	time_t now;
129	int fd, saved_errno;
130#define	TBUF_LEN	2048
131#define	FMT_LEN		1024
132	char *stdp, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
133	int tbuf_left, fmt_left, prlen;
134
135#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
136	/* Check for invalid bits. */
137	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
138		syslog(INTERNALLOG,
139		    "syslog: unknown facility/priority: %x", pri);
140		pri &= LOG_PRIMASK|LOG_FACMASK;
141	}
142
143	/* Check priority against setlogmask values. */
144	if (!(LOG_MASK(LOG_PRI(pri)) & _sl_LogMask))
145		return;
146
147	saved_errno = errno;
148
149	/* Set default facility if none specified. */
150	if ((pri & LOG_FACMASK) == 0)
151		pri |= _sl_LogFacility;
152
153	/* Build the message. */
154
155	/*
156 	 * Although it's tempting, we can't ignore the possibility of
157	 * overflowing the buffer when assembling the "fixed" portion
158	 * of the message.  Strftime's "%h" directive expands to the
159	 * locale's abbreviated month name, but if the user has the
160	 * ability to construct to his own locale files, it may be
161	 * arbitrarily long.
162	 */
163	(void)time(&now);
164
165	p = tbuf;
166	tbuf_left = TBUF_LEN;
167
168#define	DEC()	\
169	do {					\
170		if (prlen >= tbuf_left)		\
171			prlen = tbuf_left - 1;	\
172		p += prlen;			\
173		tbuf_left -= prlen;		\
174	} while (0)
175
176	prlen = snprintf(p, tbuf_left, "<%d>", pri);
177	DEC();
178
179	prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
180	DEC();
181
182	if (_sl_LogStat & LOG_PERROR)
183		stdp = p;
184	if (_sl_LogTag == NULL)
185		_sl_LogTag = *(*_NSGetArgv());
186	if (_sl_LogTag != NULL) {
187		prlen = snprintf(p, tbuf_left, "%s", _sl_LogTag);
188		DEC();
189	}
190	if (_sl_LogStat & LOG_PID) {
191		prlen = snprintf(p, tbuf_left, "[%d]", getpid());
192		DEC();
193	}
194	if (_sl_LogTag != NULL) {
195		if (tbuf_left > 1) {
196			*p++ = ':';
197			tbuf_left--;
198		}
199		if (tbuf_left > 1) {
200			*p++ = ' ';
201			tbuf_left--;
202		}
203	}
204
205	/*
206	 * We wouldn't need this mess if printf handled %m, or if
207	 * strerror() had been invented before syslog().
208	 */
209	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
210		if (ch == '%' && fmt[1] == 'm') {
211			++fmt;
212			prlen = snprintf(t, fmt_left, "%s",
213			    strerror(saved_errno));
214			if (prlen >= fmt_left)
215				prlen = fmt_left - 1;
216			t += prlen;
217			fmt_left -= prlen;
218		} else {
219			if (fmt_left > 1) {
220				*t++ = ch;
221				fmt_left--;
222			}
223		}
224	}
225	*t = '\0';
226
227	prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
228	DEC();
229	cnt = p - tbuf;
230
231	/* Output to stderr if requested. */
232	if (_sl_LogStat & LOG_PERROR) {
233		struct iovec iov[2];
234
235		iov[0].iov_base = stdp;
236		iov[0].iov_len = cnt - (stdp - tbuf);
237		iov[1].iov_base = "\n";
238		iov[1].iov_len = 1;
239		(void)writev(STDERR_FILENO, iov, 2);
240	}
241
242	/* Get connected, output the message to the local logger. */
243	if (!_sl_connected)
244		openlog(_sl_LogTag, _sl_LogStat | LOG_NDELAY, 0);
245	if (send(_sl_LogFile, tbuf, cnt, 0) >= 0)
246		return;
247
248	/*
249	 * Output the message to the console; don't worry about blocking,
250	 * if console blocks everything will.  Make sure the error reported
251	 * is the one from the syslogd failure.
252	 */
253	if (_sl_LogStat & LOG_CONS &&
254	    (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) {
255		struct iovec iov[2];
256
257		p = strchr(tbuf, '>') + 1;
258		iov[0].iov_base = p;
259		iov[0].iov_len = cnt - (p - tbuf);
260		iov[1].iov_base = "\r\n";
261		iov[1].iov_len = 2;
262		(void)writev(fd, iov, 2);
263		(void)close(fd);
264	}
265}
266
267#ifndef BUILDING_VARIANT
268
269static struct sockaddr_un SyslogAddr;	/* AF_UNIX address of local logger */
270
271void
272openlog(ident, logstat, logfac)
273	const char *ident;
274	int logstat, logfac;
275{
276	if (ident != NULL)
277		_sl_LogTag = ident;
278	_sl_LogStat = logstat;
279	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
280		_sl_LogFacility = logfac;
281
282	if (_sl_LogFile == -1) {
283		SyslogAddr.sun_family = AF_UNIX;
284		(void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
285		    sizeof(SyslogAddr.sun_path));
286		if (_sl_LogStat & LOG_NDELAY) {
287			if ((_sl_LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
288				return;
289			(void)fcntl(_sl_LogFile, F_SETFD, 1);
290		}
291	}
292	if (_sl_LogFile != -1 && !_sl_connected)
293		if (connect(_sl_LogFile, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr)) == -1) {
294			(void)close(_sl_LogFile);
295			_sl_LogFile = -1;
296		} else
297			_sl_connected = 1;
298}
299
300void
301closelog()
302{
303	(void)close(_sl_LogFile);
304	_sl_LogFile = -1;
305	_sl_connected = 0;
306}
307
308/* setlogmask -- set the log mask level */
309int
310setlogmask(pmask)
311	int pmask;
312{
313	int omask;
314
315	omask = _sl_LogMask;
316	if (pmask != 0)
317		_sl_LogMask = pmask;
318	return (omask);
319}
320
321#endif /* !BUILDING_VARIANT */
322