Deleted Added
full compact
syslog.c (22993) syslog.c (23668)
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)
35/*
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)
35/*
36static char sccsid[] = "From: @(#)syslog.c 8.4 (Berkeley) 3/18/94";
36static char sccsid[] = "@(#)syslog.c 8.5 (Berkeley) 4/29/95";
37*/
38static const char rcsid[] =
37*/
38static const char rcsid[] =
39 "$Id$";
39 "$Id: syslog.c,v 1.11 1997/02/22 14:58:18 peter Exp $";
40#endif /* LIBC_SCCS and not lint */
41
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <sys/syslog.h>
45#include <sys/uio.h>
46#include <netdb.h>
47
48#include <errno.h>
49#include <fcntl.h>
50#include <paths.h>
51#include <stdio.h>
52#include <string.h>
53#include <time.h>
54#include <unistd.h>
55
56#if __STDC__
57#include <stdarg.h>
58#else
59#include <varargs.h>
60#endif
61
62static int LogFile = -1; /* fd for log */
63static int connected; /* have done connect */
64static int opened; /* have done openlog() */
65static int LogStat = 0; /* status bits, set by openlog() */
66static const char *LogTag = NULL; /* string to tag the entry with */
67static int LogFacility = LOG_USER; /* default facility code */
68static int LogMask = 0xff; /* mask of priorities to be logged */
69extern char *__progname; /* Program name, from crt0. */
70
71static void disconnectlog __P((void)); /* disconnect from syslogd */
72static void connectlog __P((void)); /* (re)connect to syslogd */
73
74/*
75 * Format of the magic cookie passed through the stdio hook
76 */
77struct bufcookie {
78 char *base; /* start of buffer */
79 int left;
80};
81
82/*
83 * stdio write hook for writing to a static string buffer
84 * XXX: Maybe one day, dynamically allocate it so that the line length
85 * is `unlimited'.
86 */
87static
88int writehook(cookie, buf, len)
89 void *cookie; /* really [struct bufcookie *] */
90 char *buf; /* characters to copy */
91 int len; /* length to copy */
92{
93 struct bufcookie *h; /* private `handle' */
94
95 h = (struct bufcookie *)cookie;
96 if (len > h->left) {
97 /* clip in case of wraparound */
98 len = h->left;
99 }
100 if (len > 0) {
101 (void)memcpy(h->base, buf, len); /* `write' it. */
102 h->base += len;
103 h->left -= len;
104 }
105 return 0;
106}
107
108/*
109 * syslog, vsyslog --
110 * print message on log file; output is intended for syslogd(8).
111 */
112void
113#if __STDC__
114syslog(int pri, const char *fmt, ...)
115#else
116syslog(pri, fmt, va_alist)
117 int pri;
118 char *fmt;
119 va_dcl
120#endif
121{
122 va_list ap;
123
124#if __STDC__
125 va_start(ap, fmt);
126#else
127 va_start(ap);
128#endif
129 vsyslog(pri, fmt, ap);
130 va_end(ap);
131}
132
133void
134vsyslog(pri, fmt, ap)
135 int pri;
136 register const char *fmt;
137 va_list ap;
138{
139 register int cnt;
140 register char ch, *p;
141 time_t now;
142 int fd, saved_errno;
143 char *stdp, tbuf[2048], fmt_cpy[1024];
144 FILE *fp, *fmt_fp;
145 struct bufcookie tbuf_cookie;
146 struct bufcookie fmt_cookie;
147
148#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
149 /* Check for invalid bits. */
150 if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
151 syslog(INTERNALLOG,
152 "syslog: unknown facility/priority: %x", pri);
153 pri &= LOG_PRIMASK|LOG_FACMASK;
154 }
155
156 /* Check priority against setlogmask values. */
157 if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
158 return;
159
160 saved_errno = errno;
161
162 /* Set default facility if none specified. */
163 if ((pri & LOG_FACMASK) == 0)
164 pri |= LogFacility;
165
166 /* Create the primary stdio hook */
167 tbuf_cookie.base = tbuf;
168 tbuf_cookie.left = sizeof(tbuf);
169 fp = fwopen(&tbuf_cookie, writehook);
170 if (fp == NULL)
171 return;
172
173 /* Build the message. */
174 (void)time(&now);
175 (void)fprintf(fp, "<%d>", pri);
176 (void)fprintf(fp, "%.15s ", ctime(&now) + 4);
177 if (LogStat & LOG_PERROR) {
178 /* Transfer to string buffer */
179 (void)fflush(fp);
180 stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
181 }
182 if (LogTag == NULL)
183 LogTag = __progname;
184 if (LogTag != NULL)
185 (void)fprintf(fp, "%s", LogTag);
186 if (LogStat & LOG_PID)
187 (void)fprintf(fp, "[%d]", getpid());
188 if (LogTag != NULL) {
189 (void)fprintf(fp, ": ");
190 }
191
192 /* Check to see if we can skip expanding the %m */
193 if (strstr(fmt, "%m")) {
194
195 /* Create the second stdio hook */
196 fmt_cookie.base = fmt_cpy;
197 fmt_cookie.left = sizeof(fmt_cpy) - 1;
198 fmt_fp = fwopen(&fmt_cookie, writehook);
199 if (fmt_fp == NULL) {
200 fclose(fp);
201 return;
202 }
203
204 /* Substitute error message for %m. */
205 for ( ; (ch = *fmt); ++fmt)
206 if (ch == '%' && fmt[1] == 'm') {
207 ++fmt;
208 fputs(strerror(saved_errno), fmt_fp);
209 } else
210 fputc(ch, fmt_fp);
211
212 /* Null terminate if room */
213 fputc(0, fmt_fp);
214 fclose(fmt_fp);
215
216 /* Guarantee null termination */
217 fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
218
219 fmt = fmt_cpy;
220 }
221
222 (void)vfprintf(fp, fmt, ap);
223 (void)fclose(fp);
224
225 cnt = sizeof(tbuf) - tbuf_cookie.left;
226
227 /* Output to stderr if requested. */
228 if (LogStat & LOG_PERROR) {
229 struct iovec iov[2];
230 register struct iovec *v = iov;
231
232 v->iov_base = stdp;
233 v->iov_len = cnt - (stdp - tbuf);
234 ++v;
235 v->iov_base = "\n";
236 v->iov_len = 1;
237 (void)writev(STDERR_FILENO, iov, 2);
238 }
239
240 /* Get connected, output the message to the local logger. */
241 if (!opened)
242 openlog(LogTag, LogStat | LOG_NDELAY, 0);
243 connectlog();
244 if (send(LogFile, tbuf, cnt, 0) >= 0)
245 return;
246
247 /*
248 * If the send() failed, the odds are syslogd was restarted.
249 * Make one (only) attempt to reconnect to /dev/log.
250 */
251 disconnectlog();
252 connectlog();
253 if (send(LogFile, tbuf, cnt, 0) >= 0)
254 return;
255
256 /*
257 * Output the message to the console; don't worry about blocking,
258 * if console blocks everything will. Make sure the error reported
259 * is the one from the syslogd failure.
260 */
261 if (LogStat & LOG_CONS &&
262 (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) {
263 struct iovec iov[2];
264 register struct iovec *v = iov;
265
266 p = strchr(tbuf, '>') + 1;
267 v->iov_base = p;
268 v->iov_len = cnt - (p - tbuf);
269 ++v;
270 v->iov_base = "\r\n";
271 v->iov_len = 2;
272 (void)writev(fd, iov, 2);
273 (void)close(fd);
274 }
275}
276
277static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */
278
279static void
280disconnectlog()
281{
282 /*
283 * If the user closed the FD and opened another in the same slot,
284 * that's their problem. They should close it before calling on
285 * system services.
286 */
287 if (LogFile != -1) {
288 close(LogFile);
289 LogFile = -1;
290 }
291 connected = 0; /* retry connect */
292}
293
294static void
295connectlog()
296{
297 if (LogFile == -1) {
298 SyslogAddr.sa_family = AF_UNIX;
299 (void)strncpy(SyslogAddr.sa_data, _PATH_LOG,
300 sizeof(SyslogAddr.sa_data));
301 if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
302 return;
303 (void)fcntl(LogFile, F_SETFD, 1);
304 }
305 if (LogFile != -1 && !connected) {
306 if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) {
307 (void)close(LogFile);
308 LogFile = -1;
309 } else
310 connected = 1;
311 }
312}
313
314void
315openlog(ident, logstat, logfac)
316 const char *ident;
317 int logstat, logfac;
318{
319 if (ident != NULL)
320 LogTag = ident;
321 LogStat = logstat;
322 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
323 LogFacility = logfac;
324
325 if (LogStat & LOG_NDELAY) /* open immediately */
326 connectlog();
327
328 opened = 1; /* ident and facility has been set */
329}
330
331void
332closelog()
333{
334 (void)close(LogFile);
335 LogFile = -1;
336 connected = 0;
337}
338
339/* setlogmask -- set the log mask level */
340int
341setlogmask(pmask)
342 int pmask;
343{
344 int omask;
345
346 omask = LogMask;
347 if (pmask != 0)
348 LogMask = pmask;
349 return (omask);
350}
40#endif /* LIBC_SCCS and not lint */
41
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <sys/syslog.h>
45#include <sys/uio.h>
46#include <netdb.h>
47
48#include <errno.h>
49#include <fcntl.h>
50#include <paths.h>
51#include <stdio.h>
52#include <string.h>
53#include <time.h>
54#include <unistd.h>
55
56#if __STDC__
57#include <stdarg.h>
58#else
59#include <varargs.h>
60#endif
61
62static int LogFile = -1; /* fd for log */
63static int connected; /* have done connect */
64static int opened; /* have done openlog() */
65static int LogStat = 0; /* status bits, set by openlog() */
66static const char *LogTag = NULL; /* string to tag the entry with */
67static int LogFacility = LOG_USER; /* default facility code */
68static int LogMask = 0xff; /* mask of priorities to be logged */
69extern char *__progname; /* Program name, from crt0. */
70
71static void disconnectlog __P((void)); /* disconnect from syslogd */
72static void connectlog __P((void)); /* (re)connect to syslogd */
73
74/*
75 * Format of the magic cookie passed through the stdio hook
76 */
77struct bufcookie {
78 char *base; /* start of buffer */
79 int left;
80};
81
82/*
83 * stdio write hook for writing to a static string buffer
84 * XXX: Maybe one day, dynamically allocate it so that the line length
85 * is `unlimited'.
86 */
87static
88int writehook(cookie, buf, len)
89 void *cookie; /* really [struct bufcookie *] */
90 char *buf; /* characters to copy */
91 int len; /* length to copy */
92{
93 struct bufcookie *h; /* private `handle' */
94
95 h = (struct bufcookie *)cookie;
96 if (len > h->left) {
97 /* clip in case of wraparound */
98 len = h->left;
99 }
100 if (len > 0) {
101 (void)memcpy(h->base, buf, len); /* `write' it. */
102 h->base += len;
103 h->left -= len;
104 }
105 return 0;
106}
107
108/*
109 * syslog, vsyslog --
110 * print message on log file; output is intended for syslogd(8).
111 */
112void
113#if __STDC__
114syslog(int pri, const char *fmt, ...)
115#else
116syslog(pri, fmt, va_alist)
117 int pri;
118 char *fmt;
119 va_dcl
120#endif
121{
122 va_list ap;
123
124#if __STDC__
125 va_start(ap, fmt);
126#else
127 va_start(ap);
128#endif
129 vsyslog(pri, fmt, ap);
130 va_end(ap);
131}
132
133void
134vsyslog(pri, fmt, ap)
135 int pri;
136 register const char *fmt;
137 va_list ap;
138{
139 register int cnt;
140 register char ch, *p;
141 time_t now;
142 int fd, saved_errno;
143 char *stdp, tbuf[2048], fmt_cpy[1024];
144 FILE *fp, *fmt_fp;
145 struct bufcookie tbuf_cookie;
146 struct bufcookie fmt_cookie;
147
148#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
149 /* Check for invalid bits. */
150 if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
151 syslog(INTERNALLOG,
152 "syslog: unknown facility/priority: %x", pri);
153 pri &= LOG_PRIMASK|LOG_FACMASK;
154 }
155
156 /* Check priority against setlogmask values. */
157 if (!(LOG_MASK(LOG_PRI(pri)) & LogMask))
158 return;
159
160 saved_errno = errno;
161
162 /* Set default facility if none specified. */
163 if ((pri & LOG_FACMASK) == 0)
164 pri |= LogFacility;
165
166 /* Create the primary stdio hook */
167 tbuf_cookie.base = tbuf;
168 tbuf_cookie.left = sizeof(tbuf);
169 fp = fwopen(&tbuf_cookie, writehook);
170 if (fp == NULL)
171 return;
172
173 /* Build the message. */
174 (void)time(&now);
175 (void)fprintf(fp, "<%d>", pri);
176 (void)fprintf(fp, "%.15s ", ctime(&now) + 4);
177 if (LogStat & LOG_PERROR) {
178 /* Transfer to string buffer */
179 (void)fflush(fp);
180 stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left);
181 }
182 if (LogTag == NULL)
183 LogTag = __progname;
184 if (LogTag != NULL)
185 (void)fprintf(fp, "%s", LogTag);
186 if (LogStat & LOG_PID)
187 (void)fprintf(fp, "[%d]", getpid());
188 if (LogTag != NULL) {
189 (void)fprintf(fp, ": ");
190 }
191
192 /* Check to see if we can skip expanding the %m */
193 if (strstr(fmt, "%m")) {
194
195 /* Create the second stdio hook */
196 fmt_cookie.base = fmt_cpy;
197 fmt_cookie.left = sizeof(fmt_cpy) - 1;
198 fmt_fp = fwopen(&fmt_cookie, writehook);
199 if (fmt_fp == NULL) {
200 fclose(fp);
201 return;
202 }
203
204 /* Substitute error message for %m. */
205 for ( ; (ch = *fmt); ++fmt)
206 if (ch == '%' && fmt[1] == 'm') {
207 ++fmt;
208 fputs(strerror(saved_errno), fmt_fp);
209 } else
210 fputc(ch, fmt_fp);
211
212 /* Null terminate if room */
213 fputc(0, fmt_fp);
214 fclose(fmt_fp);
215
216 /* Guarantee null termination */
217 fmt_cpy[sizeof(fmt_cpy) - 1] = '\0';
218
219 fmt = fmt_cpy;
220 }
221
222 (void)vfprintf(fp, fmt, ap);
223 (void)fclose(fp);
224
225 cnt = sizeof(tbuf) - tbuf_cookie.left;
226
227 /* Output to stderr if requested. */
228 if (LogStat & LOG_PERROR) {
229 struct iovec iov[2];
230 register struct iovec *v = iov;
231
232 v->iov_base = stdp;
233 v->iov_len = cnt - (stdp - tbuf);
234 ++v;
235 v->iov_base = "\n";
236 v->iov_len = 1;
237 (void)writev(STDERR_FILENO, iov, 2);
238 }
239
240 /* Get connected, output the message to the local logger. */
241 if (!opened)
242 openlog(LogTag, LogStat | LOG_NDELAY, 0);
243 connectlog();
244 if (send(LogFile, tbuf, cnt, 0) >= 0)
245 return;
246
247 /*
248 * If the send() failed, the odds are syslogd was restarted.
249 * Make one (only) attempt to reconnect to /dev/log.
250 */
251 disconnectlog();
252 connectlog();
253 if (send(LogFile, tbuf, cnt, 0) >= 0)
254 return;
255
256 /*
257 * Output the message to the console; don't worry about blocking,
258 * if console blocks everything will. Make sure the error reported
259 * is the one from the syslogd failure.
260 */
261 if (LogStat & LOG_CONS &&
262 (fd = open(_PATH_CONSOLE, O_WRONLY, 0)) >= 0) {
263 struct iovec iov[2];
264 register struct iovec *v = iov;
265
266 p = strchr(tbuf, '>') + 1;
267 v->iov_base = p;
268 v->iov_len = cnt - (p - tbuf);
269 ++v;
270 v->iov_base = "\r\n";
271 v->iov_len = 2;
272 (void)writev(fd, iov, 2);
273 (void)close(fd);
274 }
275}
276
277static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */
278
279static void
280disconnectlog()
281{
282 /*
283 * If the user closed the FD and opened another in the same slot,
284 * that's their problem. They should close it before calling on
285 * system services.
286 */
287 if (LogFile != -1) {
288 close(LogFile);
289 LogFile = -1;
290 }
291 connected = 0; /* retry connect */
292}
293
294static void
295connectlog()
296{
297 if (LogFile == -1) {
298 SyslogAddr.sa_family = AF_UNIX;
299 (void)strncpy(SyslogAddr.sa_data, _PATH_LOG,
300 sizeof(SyslogAddr.sa_data));
301 if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
302 return;
303 (void)fcntl(LogFile, F_SETFD, 1);
304 }
305 if (LogFile != -1 && !connected) {
306 if (connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) {
307 (void)close(LogFile);
308 LogFile = -1;
309 } else
310 connected = 1;
311 }
312}
313
314void
315openlog(ident, logstat, logfac)
316 const char *ident;
317 int logstat, logfac;
318{
319 if (ident != NULL)
320 LogTag = ident;
321 LogStat = logstat;
322 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
323 LogFacility = logfac;
324
325 if (LogStat & LOG_NDELAY) /* open immediately */
326 connectlog();
327
328 opened = 1; /* ident and facility has been set */
329}
330
331void
332closelog()
333{
334 (void)close(LogFile);
335 LogFile = -1;
336 connected = 0;
337}
338
339/* setlogmask -- set the log mask level */
340int
341setlogmask(pmask)
342 int pmask;
343{
344 int omask;
345
346 omask = LogMask;
347 if (pmask != 0)
348 LogMask = pmask;
349 return (omask);
350}