2 * Copyright (c) 1983, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
33 * @(#)syslog.c 8.5 (Berkeley) 4/29/95
34 * $FreeBSD: src/lib/libc/gen/syslog.c,v 1.21.2.3 2002/11/18 11:49:55 ru Exp $
35 * $DragonFly: src/lib/libc/gen/syslog.c,v 1.9 2005/11/19 22:32:53 swildner Exp $
38 #include "namespace.h"
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/syslog.h>
54 #include "un-namespace.h"
58 static int LogFile
= -1; /* fd for log */
59 static int connected
; /* have done connect */
60 static int opened
; /* have done openlog() */
61 static int LogStat
= 0; /* status bits, set by openlog() */
62 static const char *LogTag
= NULL
; /* string to tag the entry with */
63 static int LogFacility
= LOG_USER
; /* default facility code */
64 static int LogMask
= 0xff; /* mask of priorities to be logged */
66 static void disconnectlog (void); /* disconnect from syslogd */
67 static void connectlog (void); /* (re)connect to syslogd */
70 * Format of the magic cookie passed through the stdio hook
73 char *base
; /* start of buffer */
78 * stdio write hook for writing to a static string buffer
79 * XXX: Maybe one day, dynamically allocate it so that the line length
83 writehook(void *cookie
, const char *buf
, int len
)
85 struct bufcookie
*h
; /* private `handle' */
87 h
= (struct bufcookie
*)cookie
;
89 /* clip in case of wraparound */
93 memcpy(h
->base
, buf
, len
); /* `write' it. */
102 * print message on log file; output is intended for syslogd(8).
105 syslog(int pri
, const char *fmt
, ...)
110 vsyslog(pri
, fmt
, ap
);
115 vsyslog(int pri
, const char *fmt
, va_list ap
)
121 char *stdp
, tbuf
[2048], fmt_cpy
[1024], timbuf
[26];
123 struct bufcookie tbuf_cookie
;
124 struct bufcookie fmt_cookie
;
128 #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
129 /* Check for invalid bits. */
130 if (pri
& ~(LOG_PRIMASK
|LOG_FACMASK
)) {
132 "syslog: unknown facility/priority: %x", pri
);
133 pri
&= LOG_PRIMASK
|LOG_FACMASK
;
136 /* Check priority against setlogmask values. */
137 if (!(LOG_MASK(LOG_PRI(pri
)) & LogMask
))
142 /* Set default facility if none specified. */
143 if ((pri
& LOG_FACMASK
) == 0)
146 /* Create the primary stdio hook */
147 tbuf_cookie
.base
= tbuf
;
148 tbuf_cookie
.left
= sizeof(tbuf
);
149 fp
= fwopen(&tbuf_cookie
, writehook
);
153 /* Build the message. */
155 fprintf(fp
, "<%d>", pri
);
156 fprintf(fp
, "%.15s ", ctime_r(&now
, timbuf
) + 4);
157 if (LogStat
& LOG_PERROR
) {
158 /* Transfer to string buffer */
160 stdp
= tbuf
+ (sizeof(tbuf
) - tbuf_cookie
.left
);
163 LogTag
= getprogname();
165 fprintf(fp
, "%s", LogTag
);
166 if (LogStat
& LOG_PID
)
167 fprintf(fp
, "[%d]", getpid());
168 if (LogTag
!= NULL
) {
172 /* Check to see if we can skip expanding the %m */
173 if (strstr(fmt
, "%m")) {
175 /* Create the second stdio hook */
176 fmt_cookie
.base
= fmt_cpy
;
177 fmt_cookie
.left
= sizeof(fmt_cpy
) - 1;
178 fmt_fp
= fwopen(&fmt_cookie
, writehook
);
179 if (fmt_fp
== NULL
) {
184 /* Substitute error message for %m. */
185 for ( ; (ch
= *fmt
); ++fmt
)
186 if (ch
== '%' && fmt
[1] == 'm') {
188 fputs(strerror(saved_errno
), fmt_fp
);
192 /* Null terminate if room */
196 /* Guarantee null termination */
197 fmt_cpy
[sizeof(fmt_cpy
) - 1] = '\0';
202 vfprintf(fp
, fmt
, ap
);
205 cnt
= sizeof(tbuf
) - tbuf_cookie
.left
;
207 /* Output to stderr if requested. */
208 if (LogStat
& LOG_PERROR
) {
210 struct iovec
*v
= iov
;
213 v
->iov_len
= cnt
- (stdp
- tbuf
);
217 _writev(STDERR_FILENO
, iov
, 2);
220 /* Get connected, output the message to the local logger. */
222 openlog(LogTag
, LogStat
| LOG_NDELAY
, 0);
224 if (send(LogFile
, tbuf
, cnt
, 0) >= 0)
228 * If the send() failed, the odds are syslogd was restarted.
229 * Make one (only) attempt to reconnect to /dev/log.
233 if (send(LogFile
, tbuf
, cnt
, 0) >= 0)
237 * Output the message to the console; try not to block
238 * as a blocking console should not stop other processes.
239 * Make sure the error reported is the one from the syslogd failure.
241 if (LogStat
& LOG_CONS
&&
242 (fd
= _open(_PATH_CONSOLE
, O_WRONLY
|O_NONBLOCK
, 0)) >= 0) {
244 struct iovec
*v
= iov
;
246 p
= strchr(tbuf
, '>') + 1;
248 v
->iov_len
= cnt
- (p
- tbuf
);
250 v
->iov_base
= "\r\n";
260 * If the user closed the FD and opened another in the same slot,
261 * that's their problem. They should close it before calling on
268 connected
= 0; /* retry connect */
274 struct sockaddr_un SyslogAddr
; /* AF_UNIX address of local logger */
277 if ((LogFile
= _socket(AF_UNIX
, SOCK_DGRAM
, 0)) == -1)
279 _fcntl(LogFile
, F_SETFD
, 1);
281 if (LogFile
!= -1 && !connected
) {
282 SyslogAddr
.sun_len
= sizeof(SyslogAddr
);
283 SyslogAddr
.sun_family
= AF_UNIX
;
284 strncpy(SyslogAddr
.sun_path
, _PATH_LOG
,
285 sizeof SyslogAddr
.sun_path
);
286 connected
= _connect(LogFile
, (struct sockaddr
*)&SyslogAddr
,
287 sizeof(SyslogAddr
)) != -1;
291 * Try the old "/dev/log" path, for backward
294 strncpy(SyslogAddr
.sun_path
, _PATH_OLDLOG
,
295 sizeof SyslogAddr
.sun_path
);
296 connected
= _connect(LogFile
,
297 (struct sockaddr
*)&SyslogAddr
,
298 sizeof(SyslogAddr
)) != -1;
309 openlog(const char *ident
, int logstat
, int logfac
)
314 if (logfac
!= 0 && (logfac
&~ LOG_FACMASK
) == 0)
315 LogFacility
= logfac
;
317 if (LogStat
& LOG_NDELAY
) /* open immediately */
320 opened
= 1; /* ident and facility has been set */
332 /* setlogmask -- set the log mask level */
334 setlogmask(int pmask
)