]>
Commit | Line | Data |
---|---|---|
e9ce8d39 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
734aad71 A |
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 | |
e9ce8d39 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
734aad71 A |
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. | |
e9ce8d39 A |
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> | |
224c7076 | 57 | #include <sys/param.h> |
e9ce8d39 A |
58 | #include <sys/socket.h> |
59 | #include <sys/syslog.h> | |
60 | #include <sys/uio.h> | |
61 | #include <sys/un.h> | |
62 | #include <netdb.h> | |
63 | ||
64 | #include <errno.h> | |
65 | #include <fcntl.h> | |
66 | #include <paths.h> | |
67 | #include <stdio.h> | |
3d9156a7 | 68 | #include <stdlib.h> |
224c7076 | 69 | #include <stdint.h> |
e9ce8d39 A |
70 | #include <string.h> |
71 | #include <time.h> | |
72 | #include <unistd.h> | |
3d9156a7 | 73 | #include <notify.h> |
224c7076 A |
74 | #include <asl.h> |
75 | #include <asl_private.h> | |
e9ce8d39 A |
76 | |
77 | #ifdef __STDC__ | |
78 | #include <stdarg.h> | |
79 | #else | |
80 | #include <varargs.h> | |
81 | #endif | |
82 | ||
83 | #include <crt_externs.h> | |
3d9156a7 A |
84 | |
85 | #define LOG_NO_NOTIFY 0x1000 | |
224c7076 | 86 | #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID |
3d9156a7 A |
87 | |
88 | #ifdef BUILDING_VARIANT | |
89 | __private_extern__ int _sl_LogFile; /* fd for log */ | |
90 | __private_extern__ int _sl_connected; /* have done connect */ | |
91 | __private_extern__ int _sl_LogStat; /* status bits, set by openlog() */ | |
92 | __private_extern__ const char *_sl_LogTag; /* string to tag the entry with */ | |
93 | __private_extern__ int _sl_LogFacility; /* default facility code */ | |
94 | __private_extern__ int _sl_LogMask; /* mask of priorities to be logged */ | |
95 | __private_extern__ int _sl_NotifyToken; /* for remote control of priority filter */ | |
96 | __private_extern__ int _sl_NotifyMaster; /* for remote control of priority filter */ | |
97 | #else /* !BUILDING_VARIANT */ | |
98 | __private_extern__ int _sl_LogFile = -1; /* fd for log */ | |
99 | __private_extern__ int _sl_connected = 0; /* have done connect */ | |
100 | __private_extern__ int _sl_LogStat = 0; /* status bits, set by openlog() */ | |
101 | __private_extern__ const char *_sl_LogTag = NULL; /* string to tag the entry with */ | |
102 | __private_extern__ int _sl_LogFacility = LOG_USER; /* default facility code */ | |
103 | __private_extern__ int _sl_LogMask = 0xff; /* mask of priorities to be logged */ | |
104 | __private_extern__ int _sl_NotifyToken = -1; /* for remote control of max logged priority */ | |
105 | __private_extern__ int _sl_NotifyMaster = -1; /* for remote control of max logged priority */ | |
106 | #endif /* BUILDING_VARIANT */ | |
107 | ||
108 | __private_extern__ void _sl_init_notify(); | |
109 | ||
110 | #define NOTIFY_SYSTEM_MASTER "com.apple.system.syslog.master" | |
111 | #define NOTIFY_PREFIX_SYSTEM "com.apple.system.syslog" | |
112 | #define NOTIFY_PREFIX_USER "user.syslog" | |
113 | #define NOTIFY_STATE_OFFSET 1000 | |
114 | ||
115 | /* notify SPI */ | |
3d9156a7 | 116 | uint32_t notify_register_plain(const char *name, int *out_token); |
224c7076 | 117 | const char *asl_syslog_faciliy_num_to_name(int); |
e9ce8d39 A |
118 | |
119 | /* | |
120 | * syslog, vsyslog -- | |
121 | * print message on log file; output is intended for syslogd(8). | |
122 | */ | |
123 | void | |
124 | #ifdef __STDC__ | |
125 | syslog(int pri, const char *fmt, ...) | |
126 | #else | |
127 | syslog(pri, fmt, va_alist) | |
128 | int pri; | |
129 | char *fmt; | |
130 | va_dcl | |
131 | #endif | |
132 | { | |
133 | va_list ap; | |
134 | ||
135 | #ifdef __STDC__ | |
136 | va_start(ap, fmt); | |
137 | #else | |
138 | va_start(ap); | |
139 | #endif | |
140 | vsyslog(pri, fmt, ap); | |
141 | va_end(ap); | |
142 | } | |
143 | ||
144 | void | |
224c7076 | 145 | vsyslog(int pri, const char *fmt, va_list ap) |
e9ce8d39 | 146 | { |
224c7076 A |
147 | int status, i, saved_errno, filter, rc_filter; |
148 | time_t tick; | |
149 | pid_t pid; | |
150 | uint32_t elen, count; | |
151 | char *p, *str, *expanded, *err_str, hname[MAXHOSTNAMELEN+1]; | |
152 | uint64_t cval; | |
153 | int fd, mask, level, facility; | |
154 | aslmsg msg; | |
155 | ||
156 | saved_errno = errno; | |
157 | ||
e9ce8d39 | 158 | /* Check for invalid bits. */ |
224c7076 | 159 | if (pri & ~(LOG_PRIMASK | LOG_FACMASK)) |
3d9156a7 A |
160 | { |
161 | syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri); | |
224c7076 | 162 | pri &= (LOG_PRIMASK | LOG_FACMASK); |
e9ce8d39 A |
163 | } |
164 | ||
224c7076 A |
165 | level = LOG_PRI(pri); |
166 | facility = pri & LOG_FACMASK; | |
167 | ||
168 | if (facility == 0) facility = _sl_LogFacility; | |
169 | ||
3d9156a7 A |
170 | /* Get remote-control priority filter */ |
171 | filter = _sl_LogMask; | |
172 | rc_filter = 0; | |
173 | ||
174 | _sl_init_notify(); | |
175 | ||
176 | if (_sl_NotifyToken >= 0) | |
177 | { | |
178 | if (notify_get_state(_sl_NotifyToken, &cval) == NOTIFY_STATUS_OK) | |
179 | { | |
180 | if (cval != 0) | |
181 | { | |
182 | filter = cval; | |
183 | rc_filter = 1; | |
184 | } | |
185 | } | |
186 | } | |
187 | ||
188 | if ((rc_filter == 0) && (_sl_NotifyMaster >= 0)) | |
189 | { | |
190 | if (notify_get_state(_sl_NotifyMaster, &cval) == NOTIFY_STATUS_OK) | |
191 | { | |
192 | if (cval != 0) | |
193 | { | |
194 | filter = cval; | |
195 | } | |
196 | } | |
197 | } | |
198 | ||
224c7076 A |
199 | mask = LOG_MASK(level); |
200 | if ((mask & filter) == 0) return; | |
e9ce8d39 A |
201 | |
202 | /* Build the message. */ | |
224c7076 | 203 | msg = asl_new(ASL_TYPE_MSG); |
e9ce8d39 | 204 | |
224c7076 A |
205 | if (_sl_LogTag == NULL) _sl_LogTag = *(*_NSGetArgv()); |
206 | if (_sl_LogTag != NULL) | |
207 | { | |
208 | asl_set(msg, ASL_KEY_SENDER, _sl_LogTag); | |
209 | } | |
e9ce8d39 | 210 | |
224c7076 A |
211 | str = (char *)asl_syslog_faciliy_num_to_name(facility); |
212 | if (str != NULL) asl_set(msg, ASL_KEY_FACILITY, str); | |
e9ce8d39 | 213 | |
224c7076 A |
214 | str = NULL; |
215 | tick = time(NULL); | |
216 | asprintf(&str, "%lu", tick); | |
217 | if (str != NULL) | |
218 | { | |
219 | asl_set(msg, ASL_KEY_TIME, str); | |
220 | free(str); | |
221 | } | |
e9ce8d39 | 222 | |
224c7076 A |
223 | str = NULL; |
224 | pid = getpid(); | |
225 | asprintf(&str, "%u", pid); | |
226 | if (str != NULL) | |
227 | { | |
228 | asl_set(msg, ASL_KEY_PID, str); | |
229 | free(str); | |
230 | } | |
3d9156a7 | 231 | |
224c7076 A |
232 | str = NULL; |
233 | asprintf(&str, "%d", getuid()); | |
234 | if (str != NULL) | |
235 | { | |
236 | asl_set(msg, ASL_KEY_UID, str); | |
237 | free(str); | |
238 | } | |
3d9156a7 | 239 | |
224c7076 A |
240 | str = NULL; |
241 | asprintf(&str, "%u", getgid()); | |
242 | if (str != NULL) | |
3d9156a7 | 243 | { |
224c7076 A |
244 | asl_set(msg, ASL_KEY_GID, str); |
245 | free(str); | |
e9ce8d39 | 246 | } |
3d9156a7 | 247 | |
224c7076 A |
248 | str = NULL; |
249 | asprintf(&str, "%u", level); | |
250 | if (str != NULL) | |
3d9156a7 | 251 | { |
224c7076 A |
252 | asl_set(msg, ASL_KEY_LEVEL, str); |
253 | free(str); | |
e9ce8d39 | 254 | } |
3d9156a7 | 255 | |
224c7076 A |
256 | status = gethostname(hname, MAXHOSTNAMELEN); |
257 | if (status < 0) asl_set(msg, ASL_KEY_HOST, "localhost"); | |
258 | else asl_set(msg, ASL_KEY_HOST, hname); | |
259 | ||
260 | /* check for %m */ | |
261 | count = 0; | |
262 | for (i = 0; fmt[i] != '\0'; i++) | |
3d9156a7 | 263 | { |
224c7076 | 264 | if ((fmt[i] == '%') && (fmt[i+1] == 'm')) count++; |
e9ce8d39 A |
265 | } |
266 | ||
224c7076 A |
267 | expanded = NULL; |
268 | elen = 0; | |
269 | err_str = NULL; | |
270 | ||
271 | /* deal with malloc failures gracefully */ | |
272 | if (count > 0) | |
3d9156a7 | 273 | { |
224c7076 A |
274 | err_str = strdup(strerror(saved_errno)); |
275 | if (err_str == NULL) count = 0; | |
276 | else | |
3d9156a7 | 277 | { |
224c7076 A |
278 | elen = strlen(err_str); |
279 | expanded = malloc(i + (count * elen)); | |
280 | if (expanded == NULL) count = 0; | |
3d9156a7 | 281 | } |
224c7076 A |
282 | } |
283 | ||
284 | if (expanded == NULL) expanded = (char *)fmt; | |
285 | if (count > 0) | |
286 | { | |
287 | p = expanded; | |
288 | ||
289 | for (i = 0; fmt[i] != '\0'; i++) | |
3d9156a7 | 290 | { |
224c7076 | 291 | if ((fmt[i] == '%') && (fmt[i+1] == 'm')) |
3d9156a7 | 292 | { |
224c7076 A |
293 | memcpy(p, err_str, elen); |
294 | p += elen; | |
295 | i++; | |
296 | } | |
297 | else | |
298 | { | |
299 | *p++ = fmt[i]; | |
e9ce8d39 A |
300 | } |
301 | } | |
224c7076 A |
302 | |
303 | *p = '\0'; | |
e9ce8d39 | 304 | } |
3d9156a7 | 305 | |
224c7076 | 306 | if (err_str != NULL) free(err_str); |
e9ce8d39 | 307 | |
224c7076 A |
308 | vasprintf(&str, expanded, ap); |
309 | if (count > 0) free(expanded); | |
e9ce8d39 | 310 | |
224c7076 | 311 | if (str != NULL) |
3d9156a7 | 312 | { |
224c7076 A |
313 | asl_set(msg, ASL_KEY_MSG, str); |
314 | ||
315 | /* Output to stderr if requested. */ | |
316 | if (_sl_LogStat & LOG_PERROR) | |
317 | { | |
318 | p = NULL; | |
319 | if (_sl_LogStat & LOG_PID) asprintf(&p, "%s[%u]: %s", (_sl_LogTag == NULL) ? "???" : _sl_LogTag, pid, str); | |
320 | else asprintf(&p, "%s: %s", (_sl_LogTag == NULL) ? "???" : _sl_LogTag, str); | |
321 | ||
322 | if (p != NULL) | |
323 | { | |
324 | struct iovec iov[2]; | |
325 | ||
326 | iov[0].iov_base = p; | |
327 | iov[0].iov_len = strlen(p); | |
328 | iov[1].iov_base = "\n"; | |
329 | iov[1].iov_len = 1; | |
330 | writev(STDERR_FILENO, iov, 2); | |
331 | free(p); | |
332 | } | |
333 | } | |
e9ce8d39 | 334 | |
224c7076 | 335 | free(str); |
e9ce8d39 A |
336 | } |
337 | ||
338 | /* Get connected, output the message to the local logger. */ | |
224c7076 A |
339 | str = asl_format_message(msg, ASL_MSG_FMT_RAW, ASL_TIME_FMT_SEC, &count); |
340 | if (str != NULL) | |
341 | { | |
342 | p = NULL; | |
343 | asprintf(&p, "%10u %s", count, str); | |
344 | free(str); | |
345 | ||
346 | if (p != NULL) | |
347 | { | |
348 | count += 12; | |
349 | if (_sl_connected == 0) openlog(_sl_LogTag, _sl_LogStat | LOG_NDELAY, 0); | |
350 | ||
351 | status = send(_sl_LogFile, p, count, 0); | |
352 | if (status< 0) | |
353 | { | |
354 | closelog(); | |
355 | openlog(_sl_LogTag, _sl_LogStat | LOG_NDELAY, 0); | |
356 | status = send(_sl_LogFile, p, count, 0); | |
357 | } | |
358 | ||
359 | if (status >= 0) | |
360 | { | |
361 | free(p); | |
362 | asl_free(msg); | |
363 | return; | |
364 | } | |
365 | ||
366 | free(p); | |
367 | } | |
368 | } | |
e9ce8d39 A |
369 | |
370 | /* | |
224c7076 | 371 | * Output the message to the console. |
e9ce8d39 | 372 | */ |
224c7076 | 373 | if (_sl_LogStat & LOG_CONS && (fd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) |
3d9156a7 | 374 | { |
224c7076 A |
375 | count = 0; |
376 | ||
377 | p = asl_format_message(msg, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, &count); | |
378 | if (p != NULL) | |
379 | { | |
380 | struct iovec iov; | |
381 | ||
382 | /* count includes trailing nul */ | |
383 | iov.iov_len = count - 1; | |
384 | iov.iov_base = p; | |
385 | writev(fd, &iov, 1); | |
386 | ||
387 | free(p); | |
388 | } | |
389 | ||
390 | close(fd); | |
e9ce8d39 | 391 | } |
224c7076 A |
392 | |
393 | asl_free(msg); | |
e9ce8d39 A |
394 | } |
395 | ||
3d9156a7 A |
396 | #ifndef BUILDING_VARIANT |
397 | ||
e9ce8d39 A |
398 | static struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ |
399 | ||
3d9156a7 A |
400 | __private_extern__ void |
401 | _sl_init_notify() | |
402 | { | |
403 | int status; | |
404 | char *notify_name; | |
405 | const char *prefix; | |
224c7076 | 406 | |
3d9156a7 A |
407 | if (_sl_LogStat & LOG_NO_NOTIFY) |
408 | { | |
409 | _sl_NotifyMaster = -2; | |
410 | _sl_NotifyToken = -2; | |
411 | return; | |
412 | } | |
224c7076 | 413 | |
3d9156a7 A |
414 | if (_sl_NotifyMaster == -1) |
415 | { | |
416 | status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_sl_NotifyMaster); | |
417 | if (status != NOTIFY_STATUS_OK) _sl_NotifyMaster = -2; | |
418 | } | |
224c7076 | 419 | |
3d9156a7 A |
420 | if (_sl_NotifyToken == -1) |
421 | { | |
422 | _sl_NotifyToken = -2; | |
224c7076 | 423 | |
3d9156a7 A |
424 | notify_name = NULL; |
425 | prefix = NOTIFY_PREFIX_USER; | |
426 | if (getuid() == 0) prefix = NOTIFY_PREFIX_SYSTEM; | |
427 | asprintf(¬ify_name, "%s.%d", prefix, getpid()); | |
224c7076 | 428 | |
3d9156a7 A |
429 | if (notify_name != NULL) |
430 | { | |
431 | status = notify_register_plain(notify_name, &_sl_NotifyToken); | |
432 | free(notify_name); | |
433 | if (status != NOTIFY_STATUS_OK) _sl_NotifyToken = -2; | |
434 | } | |
435 | } | |
436 | } | |
437 | ||
e9ce8d39 A |
438 | void |
439 | openlog(ident, logstat, logfac) | |
440 | const char *ident; | |
441 | int logstat, logfac; | |
442 | { | |
3d9156a7 A |
443 | if (ident != NULL) _sl_LogTag = ident; |
444 | ||
445 | _sl_LogStat = logstat; | |
446 | ||
447 | if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) _sl_LogFacility = logfac; | |
e9ce8d39 | 448 | |
3d9156a7 A |
449 | if (_sl_LogFile == -1) |
450 | { | |
e9ce8d39 | 451 | SyslogAddr.sun_family = AF_UNIX; |
3d9156a7 A |
452 | (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, sizeof(SyslogAddr.sun_path)); |
453 | if (_sl_LogStat & LOG_NDELAY) | |
454 | { | |
455 | if ((_sl_LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) return; | |
456 | (void)fcntl(_sl_LogFile, F_SETFD, 1); | |
e9ce8d39 A |
457 | } |
458 | } | |
3d9156a7 A |
459 | |
460 | if ((_sl_LogFile != -1) && (_sl_connected == 0)) | |
461 | { | |
462 | if (connect(_sl_LogFile, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr)) == -1) | |
463 | { | |
464 | (void)close(_sl_LogFile); | |
465 | _sl_LogFile = -1; | |
466 | } | |
467 | else | |
468 | { | |
469 | _sl_connected = 1; | |
470 | } | |
471 | } | |
472 | ||
473 | _sl_init_notify(); | |
e9ce8d39 A |
474 | } |
475 | ||
476 | void | |
477 | closelog() | |
478 | { | |
224c7076 A |
479 | if (_sl_LogFile >= 0) { |
480 | (void)close(_sl_LogFile); | |
481 | _sl_LogFile = -1; | |
482 | } | |
3d9156a7 | 483 | _sl_connected = 0; |
e9ce8d39 A |
484 | } |
485 | ||
486 | /* setlogmask -- set the log mask level */ | |
487 | int | |
488 | setlogmask(pmask) | |
489 | int pmask; | |
490 | { | |
491 | int omask; | |
492 | ||
3d9156a7 A |
493 | omask = _sl_LogMask; |
494 | if (pmask != 0) _sl_LogMask = pmask; | |
e9ce8d39 A |
495 | return (omask); |
496 | } | |
3d9156a7 A |
497 | |
498 | #endif /* !BUILDING_VARIANT */ |