]>
Commit | Line | Data |
---|---|---|
790aa1f2 UD |
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 | * 4. Neither the name of the University nor the names of its contributors | |
14 | * may be used to endorse or promote products derived from this software | |
15 | * without specific prior written permission. | |
16 | * | |
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 | * SUCH DAMAGE. | |
28 | */ | |
29 | ||
30 | #if defined(LIBC_SCCS) && !defined(lint) | |
31 | static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94"; | |
32 | #endif /* LIBC_SCCS and not lint */ | |
33 | ||
0cc15f45 | 34 | #include <libio/libioP.h> |
790aa1f2 | 35 | #include <paths.h> |
0cc15f45 AZ |
36 | #include <stdarg.h> |
37 | #include <stdlib.h> | |
790aa1f2 UD |
38 | #include <stdio.h> |
39 | #include <stdio_ext.h> | |
0cc15f45 AZ |
40 | #include <sys/socket.h> |
41 | #include <sys/uio.h> | |
42 | #include <sys/un.h> | |
43 | #include <syslog.h> | |
37233df9 | 44 | |
0cc15f45 AZ |
45 | static int LogType = SOCK_DGRAM; /* type of socket connection */ |
46 | static int LogFile = -1; /* fd for log */ | |
47 | static bool connected; /* have done connect */ | |
48 | static int LogStat; /* status bits, set by openlog() */ | |
790aa1f2 | 49 | static const char *LogTag; /* string to tag the entry with */ |
0cc15f45 AZ |
50 | static int LogFacility = LOG_USER; /* default facility code */ |
51 | static int LogMask = 0xff; /* mask of priorities to be logged */ | |
52 | extern char *__progname; /* Program name, from crt0. */ | |
790aa1f2 UD |
53 | |
54 | /* Define the lock. */ | |
55 | __libc_lock_define_initialized (static, syslog_lock) | |
0cc15f45 AZ |
56 | static void openlog_internal (const char *, int, int); |
57 | static void closelog_internal (void); | |
790aa1f2 UD |
58 | |
59 | struct cleanup_arg | |
60 | { | |
61 | void *buf; | |
62 | struct sigaction *oldaction; | |
63 | }; | |
64 | ||
65 | static void | |
66 | cancel_handler (void *ptr) | |
67 | { | |
790aa1f2 UD |
68 | /* Restore the old signal handler. */ |
69 | struct cleanup_arg *clarg = (struct cleanup_arg *) ptr; | |
70 | ||
c4e4b2e1 | 71 | if (clarg != NULL) |
ded3cef3 AZ |
72 | /* Free the memstream buffer, */ |
73 | free (clarg->buf); | |
c4e4b2e1 | 74 | |
790aa1f2 UD |
75 | /* Free the lock. */ |
76 | __libc_lock_unlock (syslog_lock); | |
77 | } | |
78 | ||
79 | ||
80 | /* | |
81 | * syslog, vsyslog -- | |
82 | * print message on log file; output is intended for syslogd(8). | |
83 | */ | |
84 | void | |
0cc15f45 | 85 | __syslog (int pri, const char *fmt, ...) |
790aa1f2 | 86 | { |
0cc15f45 | 87 | va_list ap; |
790aa1f2 | 88 | |
0cc15f45 AZ |
89 | va_start (ap, fmt); |
90 | __vsyslog_internal (pri, fmt, ap, 0); | |
91 | va_end (ap); | |
790aa1f2 | 92 | } |
c6251f03 RM |
93 | ldbl_hidden_def (__syslog, syslog) |
94 | ldbl_strong_alias (__syslog, syslog) | |
790aa1f2 | 95 | |
124fc732 | 96 | void |
0cc15f45 | 97 | __vsyslog (int pri, const char *fmt, va_list ap) |
124fc732 | 98 | { |
0cc15f45 | 99 | __vsyslog_internal (pri, fmt, ap, 0); |
124fc732 ZW |
100 | } |
101 | ldbl_weak_alias (__vsyslog, vsyslog) | |
102 | ||
790aa1f2 | 103 | void |
ba745eff | 104 | ___syslog_chk (int pri, int flag, const char *fmt, ...) |
29c21e49 | 105 | { |
0cc15f45 | 106 | va_list ap; |
29c21e49 | 107 | |
0cc15f45 AZ |
108 | va_start (ap, fmt); |
109 | __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0); | |
110 | va_end (ap); | |
29c21e49 | 111 | } |
ba745eff FB |
112 | ldbl_hidden_def (___syslog_chk, __syslog_chk) |
113 | ldbl_strong_alias (___syslog_chk, __syslog_chk) | |
29c21e49 UD |
114 | |
115 | void | |
0cc15f45 | 116 | __vsyslog_chk (int pri, int flag, const char *fmt, va_list ap) |
124fc732 | 117 | { |
0cc15f45 | 118 | __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0); |
124fc732 ZW |
119 | } |
120 | ||
121 | void | |
0cc15f45 AZ |
122 | __vsyslog_internal (int pri, const char *fmt, va_list ap, |
123 | unsigned int mode_flags) | |
790aa1f2 | 124 | { |
a583b6ad AZ |
125 | /* Try to use a static buffer as an optimization. */ |
126 | char bufs[1024]; | |
6bd0e4ef AS |
127 | char *buf = bufs; |
128 | size_t bufsize; | |
129 | ||
f9f5c70e | 130 | int msgoff; |
0cc15f45 | 131 | int saved_errno = errno; |
0cc15f45 AZ |
132 | |
133 | #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID | |
134 | /* Check for invalid bits. */ | |
135 | if (pri & ~(LOG_PRIMASK | LOG_FACMASK)) | |
136 | { | |
137 | syslog (INTERNALLOG, "syslog: unknown facility/priority: %x", pri); | |
138 | pri &= LOG_PRIMASK | LOG_FACMASK; | |
139 | } | |
140 | ||
141 | /* Prepare for multiple users. We have to take care: most syscalls we are | |
142 | using are cancellation points. */ | |
f9f5c70e | 143 | struct cleanup_arg clarg = { NULL, NULL }; |
0cc15f45 AZ |
144 | __libc_cleanup_push (cancel_handler, &clarg); |
145 | __libc_lock_lock (syslog_lock); | |
146 | ||
147 | /* Check priority against setlogmask values. */ | |
148 | if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0) | |
149 | goto out; | |
150 | ||
151 | /* Set default facility if none specified. */ | |
152 | if ((pri & LOG_FACMASK) == 0) | |
153 | pri |= LogFacility; | |
154 | ||
a583b6ad AZ |
155 | pid_t pid = LogStat & LOG_PID ? __getpid () : 0; |
156 | ||
157 | /* "%b %e %H:%M:%S " */ | |
158 | char timestamp[sizeof "MMM DD hh:mm:ss "]; | |
ac0d208b | 159 | __time64_t now = time64_now (); |
a583b6ad | 160 | struct tm now_tm; |
ac0d208b AZ |
161 | struct tm *now_tmp = __localtime64_r (&now, &now_tm); |
162 | bool has_ts = now_tmp != NULL; | |
163 | ||
164 | /* In the unlikely case of localtime_r failure (tm_year out of int range) | |
165 | skip the hostname so the message is handled as valid PRI but without | |
166 | TIMESTAMP or invalid TIMESTAMP (which should force the relay to add the | |
167 | timestamp itself). */ | |
168 | if (has_ts) | |
169 | __strftime_l (timestamp, sizeof timestamp, "%h %e %T ", now_tmp, | |
170 | _nl_C_locobj_ptr); | |
a583b6ad AZ |
171 | |
172 | #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \ | |
45459476 | 173 | "<%d>%s%n%s%s%.0d%s: ", \ |
a583b6ad AZ |
174 | __pri, __timestamp, __msgoff, \ |
175 | LogTag == NULL ? __progname : LogTag, \ | |
176 | "[" + (pid == 0), pid, "]" + (pid == 0) | |
177 | ||
ac0d208b AZ |
178 | #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \ |
179 | "<%d>: %n", __pri, __msgoff | |
180 | ||
6bd0e4ef | 181 | int l, vl; |
ac0d208b AZ |
182 | if (has_ts) |
183 | l = __snprintf (bufs, sizeof bufs, | |
184 | SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); | |
185 | else | |
186 | l = __snprintf (bufs, sizeof bufs, | |
187 | SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); | |
6bd0e4ef AS |
188 | |
189 | char *pos; | |
190 | size_t len; | |
191 | ||
a583b6ad | 192 | if (0 <= l && l < sizeof bufs) |
0cc15f45 | 193 | { |
6bd0e4ef AS |
194 | /* At this point, there is still a chance that we can print the |
195 | remaining part of the log into bufs and use that. */ | |
196 | pos = bufs + l; | |
197 | len = sizeof (bufs) - l; | |
198 | } | |
199 | else | |
200 | { | |
201 | buf = NULL; | |
202 | /* We already know that bufs is too small to use for this log message. | |
203 | The next vsnprintf into bufs is used only to calculate the total | |
204 | required buffer length. We will discard bufs contents and allocate | |
205 | an appropriately sized buffer later instead. */ | |
206 | pos = bufs; | |
207 | len = sizeof (bufs); | |
208 | } | |
a583b6ad | 209 | |
6bd0e4ef AS |
210 | { |
211 | va_list apc; | |
212 | va_copy (apc, ap); | |
0cc15f45 | 213 | |
6bd0e4ef AS |
214 | /* Restore errno for %m format. */ |
215 | __set_errno (saved_errno); | |
0cc15f45 | 216 | |
6bd0e4ef AS |
217 | vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); |
218 | ||
219 | if (!(0 <= vl && vl < len)) | |
220 | buf = NULL; | |
221 | ||
222 | bufsize = l + vl; | |
223 | va_end (apc); | |
224 | } | |
a583b6ad AZ |
225 | |
226 | if (buf == NULL) | |
f9f5c70e | 227 | { |
52a5be0d | 228 | buf = malloc ((bufsize + 1) * sizeof (char)); |
a583b6ad AZ |
229 | if (buf != NULL) |
230 | { | |
231 | /* Tell the cancellation handler to free this buffer. */ | |
232 | clarg.buf = buf; | |
233 | ||
ac0d208b | 234 | if (has_ts) |
52a5be0d | 235 | __snprintf (buf, l + 1, |
ac0d208b AZ |
236 | SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); |
237 | else | |
52a5be0d | 238 | __snprintf (buf, l + 1, |
ac0d208b | 239 | SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); |
52a5be0d AZ |
240 | |
241 | va_list apc; | |
242 | va_copy (apc, ap); | |
243 | __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, | |
244 | mode_flags); | |
245 | va_end (apc); | |
a583b6ad AZ |
246 | } |
247 | else | |
248 | { | |
249 | /* Nothing much to do but emit an error message. */ | |
250 | bufsize = __snprintf (bufs, sizeof bufs, | |
251 | "out of memory[%d]", __getpid ()); | |
252 | buf = bufs; | |
253 | } | |
f9f5c70e | 254 | } |
0cc15f45 AZ |
255 | |
256 | /* Output to stderr if requested. */ | |
257 | if (LogStat & LOG_PERROR) | |
f9f5c70e AZ |
258 | __dprintf (STDERR_FILENO, "%s%s", buf + msgoff, |
259 | "\n" + (buf[bufsize - 1] == '\n')); | |
0cc15f45 AZ |
260 | |
261 | /* Get connected, output the message to the local logger. */ | |
262 | if (!connected) | |
263 | openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility); | |
264 | ||
265 | /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record | |
266 | terminator. */ | |
267 | if (LogType == SOCK_STREAM) | |
268 | ++bufsize; | |
269 | ||
270 | if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0) | |
271 | { | |
272 | if (connected) | |
273 | { | |
274 | /* Try to reopen the syslog connection. Maybe it went down. */ | |
275 | closelog_internal (); | |
276 | openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility); | |
790aa1f2 UD |
277 | } |
278 | ||
0cc15f45 AZ |
279 | if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0) |
280 | { | |
281 | closelog_internal (); /* attempt re-open next time */ | |
282 | /* | |
283 | * Output the message to the console; don't worry | |
284 | * about blocking, if console blocks everything will. | |
285 | * Make sure the error reported is the one from the | |
286 | * syslogd failure. | |
287 | */ | |
f9f5c70e | 288 | int fd; |
0cc15f45 AZ |
289 | if (LogStat & LOG_CONS && |
290 | (fd = __open (_PATH_CONSOLE, O_WRONLY | O_NOCTTY | |
291 | | O_CLOEXEC, 0)) >= 0) | |
292 | { | |
293 | __dprintf (fd, "%s\r\n", buf + msgoff); | |
294 | __close (fd); | |
295 | } | |
296 | } | |
297 | } | |
298 | ||
299 | out: | |
300 | /* End of critical section. */ | |
301 | __libc_cleanup_pop (0); | |
302 | __libc_lock_unlock (syslog_lock); | |
303 | ||
a583b6ad | 304 | if (buf != bufs) |
0cc15f45 | 305 | free (buf); |
790aa1f2 | 306 | } |
790aa1f2 | 307 | |
5ad1a81c AZ |
308 | /* AF_UNIX address of local logger */ |
309 | static const struct sockaddr_un SyslogAddr = | |
310 | { | |
311 | .sun_family = AF_UNIX, | |
312 | .sun_path = _PATH_LOG | |
313 | }; | |
790aa1f2 UD |
314 | |
315 | static void | |
0cc15f45 | 316 | openlog_internal (const char *ident, int logstat, int logfac) |
790aa1f2 | 317 | { |
0cc15f45 AZ |
318 | if (ident != NULL) |
319 | LogTag = ident; | |
320 | LogStat = logstat; | |
321 | if ((logfac & ~LOG_FACMASK) == 0) | |
322 | LogFacility = logfac; | |
323 | ||
324 | int retry = 0; | |
325 | while (retry < 2) | |
326 | { | |
327 | if (LogFile == -1) | |
328 | { | |
329 | if (LogStat & LOG_NDELAY) | |
330 | { | |
331 | LogFile = __socket (AF_UNIX, LogType | SOCK_CLOEXEC, 0); | |
332 | if (LogFile == -1) | |
333 | return; | |
334 | } | |
335 | } | |
336 | if (LogFile != -1 && !connected) | |
337 | { | |
338 | int old_errno = errno; | |
339 | if (__connect (LogFile, &SyslogAddr, sizeof (SyslogAddr)) == -1) | |
340 | { | |
341 | int saved_errno = errno; | |
342 | int fd = LogFile; | |
343 | LogFile = -1; | |
344 | __close (fd); | |
345 | __set_errno (old_errno); | |
346 | if (saved_errno == EPROTOTYPE) | |
790aa1f2 | 347 | { |
0cc15f45 AZ |
348 | /* retry with the other type: */ |
349 | LogType = LogType == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM; | |
350 | ++retry; | |
351 | continue; | |
790aa1f2 | 352 | } |
0cc15f45 AZ |
353 | } |
354 | else | |
355 | connected = true; | |
790aa1f2 | 356 | } |
0cc15f45 AZ |
357 | break; |
358 | } | |
790aa1f2 UD |
359 | } |
360 | ||
361 | void | |
362 | openlog (const char *ident, int logstat, int logfac) | |
363 | { | |
364 | /* Protect against multiple users and cancellation. */ | |
365 | __libc_cleanup_push (cancel_handler, NULL); | |
366 | __libc_lock_lock (syslog_lock); | |
367 | ||
368 | openlog_internal (ident, logstat, logfac); | |
369 | ||
370 | __libc_cleanup_pop (1); | |
371 | } | |
372 | ||
790aa1f2 | 373 | static void |
60d2f8f3 | 374 | closelog_internal (void) |
790aa1f2 UD |
375 | { |
376 | if (!connected) | |
377 | return; | |
378 | ||
379 | __close (LogFile); | |
380 | LogFile = -1; | |
7cb10381 | 381 | connected = false; |
790aa1f2 UD |
382 | } |
383 | ||
384 | void | |
60d2f8f3 | 385 | closelog (void) |
790aa1f2 UD |
386 | { |
387 | /* Protect against multiple users and cancellation. */ | |
388 | __libc_cleanup_push (cancel_handler, NULL); | |
389 | __libc_lock_lock (syslog_lock); | |
390 | ||
391 | closelog_internal (); | |
392 | LogTag = NULL; | |
393 | LogType = SOCK_DGRAM; /* this is the default */ | |
394 | ||
395 | /* Free the lock. */ | |
396 | __libc_cleanup_pop (1); | |
397 | } | |
398 | ||
399 | /* setlogmask -- set the log mask level */ | |
400 | int | |
9d46370c | 401 | setlogmask (int pmask) |
790aa1f2 | 402 | { |
0cc15f45 | 403 | int omask; |
790aa1f2 | 404 | |
0cc15f45 AZ |
405 | /* Protect against multiple users. */ |
406 | __libc_lock_lock (syslog_lock); | |
c4e4b2e1 | 407 | |
0cc15f45 AZ |
408 | omask = LogMask; |
409 | if (pmask != 0) | |
410 | LogMask = pmask; | |
c4e4b2e1 | 411 | |
0cc15f45 | 412 | __libc_lock_unlock (syslog_lock); |
c4e4b2e1 | 413 | |
0cc15f45 | 414 | return (omask); |
790aa1f2 | 415 | } |