]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/syslogd.c
syslog-14.2.tar.gz
[apple/syslog.git] / syslogd.tproj / syslogd.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/fcntl.h>
33 #include <sys/queue.h>
34 #include <sys/time.h>
35 #include <dirent.h>
36 #include <dlfcn.h>
37 #include <libgen.h>
38 #include <notify.h>
39 #include "daemon.h"
40
41 #define DEFAULT_MARK_SEC 0
42 #define DEFAULT_PRUNE_DAYS 7
43 #define PRUNE_AFTER_START_DELAY 300
44
45 #define NOTIFY_DELAY 1
46
47 #define streq(A,B) (strcmp(A,B)==0)
48 #define forever for(;;)
49
50 static int debug = 0;
51 static int reset = 0;
52
53 static TAILQ_HEAD(ml, module_list) Moduleq;
54
55 /* global */
56 int asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
57 int prune = 0;
58
59 extern int __notify_78945668_info__;
60
61 /* kernel log fd */
62 extern int kfd;
63
64 /* Static Modules */
65 int asl_in_init();
66 int asl_in_reset();
67 int asl_in_close();
68 static int activate_asl_in = 1;
69
70 int asl_action_init();
71 int asl_action_reset();
72 int asl_action_close();
73 static int activate_asl_action = 1;
74
75 int klog_in_init();
76 int klog_in_reset();
77 int klog_in_close();
78 static int activate_klog_in = 1;
79
80 int bsd_in_init();
81 int bsd_in_reset();
82 int bsd_in_close();
83 static int activate_bsd_in = 1;
84
85 int bsd_out_init();
86 int bsd_out_reset();
87 int bsd_out_close();
88 static int activate_bsd_out = 1;
89
90 int udp_in_init();
91 int udp_in_reset();
92 int udp_in_close();
93 static int activate_udp_in = 0;
94
95 /*
96 * Module approach: only one type of module. This module may implement
97 * the set of functions necessary for any of the functions (input, output,
98 * etc.) Prior to using the modules, dlsym() is consulted to see what it
99 * implements.
100 */
101
102 static int
103 static_modules()
104 {
105 struct module_list *tmp;
106
107 if (activate_asl_in != 0)
108 {
109 tmp = calloc(1, sizeof(struct module_list));
110 if (tmp == NULL) return 1;
111 tmp->name = strdup("asl_in");
112 tmp->module = NULL;
113 tmp->init = asl_in_init;
114 tmp->reset = asl_in_reset;
115 tmp->close = asl_in_close;
116 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
117 }
118
119 if (activate_asl_action != 0)
120 {
121 tmp = calloc(1, sizeof(struct module_list));
122 if (tmp == NULL) return 1;
123 tmp->name = strdup("asl_action");
124 tmp->module = NULL;
125 tmp->init = asl_action_init;
126 tmp->reset = asl_action_reset;
127 tmp->close = asl_action_close;
128 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
129 }
130
131 if (activate_klog_in != 0)
132 {
133 tmp = calloc(1, sizeof(struct module_list));
134 if (tmp == NULL) return 1;
135 tmp->name = strdup("klog_in");
136 tmp->module = NULL;
137 tmp->init = klog_in_init;
138 tmp->reset = klog_in_reset;
139 tmp->close = klog_in_close;
140 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
141 }
142
143 if (activate_bsd_in != 0)
144 {
145 tmp = calloc(1, sizeof(struct module_list));
146 if (tmp == NULL) return 1;
147 tmp->name = strdup("bsd_in");
148 tmp->module = NULL;
149 tmp->init = bsd_in_init;
150 tmp->reset = bsd_in_reset;
151 tmp->close = bsd_in_close;
152 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
153 }
154
155 if (activate_bsd_out != 0)
156 {
157 tmp = calloc(1, sizeof(struct module_list));
158 if (tmp == NULL) return 1;
159 tmp->name = strdup("bsd_out");
160 tmp->module = NULL;
161 tmp->init = bsd_out_init;
162 tmp->reset = bsd_out_reset;
163 tmp->close = bsd_out_close;
164 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
165 }
166
167 if (activate_udp_in != 0)
168 {
169 tmp = calloc(1, sizeof(struct module_list));
170 if (tmp == NULL) return 1;
171 tmp->name = strdup("udp_in");
172 tmp->module = NULL;
173 tmp->init = udp_in_init;
174 tmp->reset = udp_in_reset;
175 tmp->close = udp_in_close;
176 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
177 }
178
179 return 0;
180 }
181
182 /*
183 * Loads all the modules. This DOES NOT call the modules initializer
184 * functions. It simply scans the modules directory looking for modules
185 * and loads them. This does not mean the module will be used.
186 */
187 static int
188 load_modules(char *mp)
189 {
190 DIR *d;
191 struct dirent *de;
192 struct module_list *tmp;
193 void *c, *bn;
194 char *modulepath = NULL;
195
196 d = opendir(mp);
197 if (d == NULL) return -1;
198
199 while (NULL != (de = readdir(d)))
200 {
201 if (de->d_name[0] == '.') continue;
202
203 /* Must have ".so" in the name" */
204 if (!strstr(de->d_name, ".so")) continue;
205
206 asprintf(&modulepath, "%s/%s", mp, de->d_name);
207 if (!modulepath) continue;
208
209 c = dlopen(modulepath, RTLD_LOCAL);
210 if (c == NULL)
211 {
212 free(modulepath);
213 continue;
214 }
215
216 tmp = calloc(1, sizeof(struct module_list));
217 if (tmp == NULL)
218 {
219 free(modulepath);
220 dlclose(c);
221 continue;
222 }
223
224 bn = basename(modulepath);
225 tmp->name = strdup(bn);
226 tmp->module = c;
227 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
228
229 tmp->init = dlsym(tmp->module, "aslmod_init");
230 tmp->reset = dlsym(tmp->module, "aslmod_reset");
231 tmp->close = dlsym(tmp->module, "aslmod_close");
232
233 free(modulepath);
234 }
235
236 closedir(d);
237
238 return 0;
239 }
240
241 static void
242 writepid(void)
243 {
244 FILE *fp;
245
246 fp = fopen(_PATH_PIDFILE, "w");
247 if (fp != NULL)
248 {
249 fprintf(fp, "%d\n", getpid());
250 fclose(fp);
251 }
252 }
253
254 static void
255 closeall(void)
256 {
257 int i;
258
259 for (i = getdtablesize() - 1; i >= 0; i--) close(i);
260
261 open("/dev/null", O_RDWR, 0);
262 dup(0);
263 dup(0);
264 }
265
266 static void
267 detach(void)
268 {
269 signal(SIGINT, SIG_IGN);
270 signal(SIGPIPE, SIG_IGN);
271 setsid();
272 }
273
274 static void
275 catch_sighup(int x)
276 {
277 reset = 1;
278 }
279
280 static void
281 catch_sigwinch(int x)
282 {
283 prune = 1;
284 }
285
286 static void
287 send_reset(void)
288 {
289 struct module_list *mod;
290
291 for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
292 {
293 if (mod->reset != NULL) mod->reset();
294 }
295 }
296
297 int
298 main(int argc, char *argv[])
299 {
300 struct module_list *mod;
301 fd_set rd, wr, ex, kern;
302 int fd, i, max, status, pdays, daemonize;
303 time_t lastmark, msec, ssec, tick, delta, ptime, notify_time;
304 char *mp, *str;
305 struct timeval timeout, *pto, zto;
306 asl_msg_t *pq;
307
308 mp = _PATH_MODULE_LIB;
309 msec = DEFAULT_MARK_SEC;
310 pdays = DEFAULT_PRUNE_DAYS;
311 daemonize = 0;
312 __notify_78945668_info__ = -1;
313 kfd = -1;
314 zto.tv_sec = 0;
315 zto.tv_usec = 0;
316 FD_ZERO(&kern);
317
318 for (i = 1; i < argc; i++)
319 {
320 if (streq(argv[i], "-d"))
321 {
322 debug = 1;
323 }
324 if (streq(argv[i], "-D"))
325 {
326 daemonize = 1;
327 }
328 if (streq(argv[i], "-u"))
329 {
330 activate_udp_in = 1;
331 }
332 else if (streq(argv[i], "-m"))
333 {
334 if ((i + 1) < argc) msec = 60 * atoi(argv[++i]);
335 }
336 else if (streq(argv[i], "-p"))
337 {
338 if ((i + 1) < argc) pdays = atoi(argv[++i]);
339 }
340 else if (streq(argv[i], "-l"))
341 {
342 if ((i + 1) < argc) mp = argv[++i];
343 }
344 else if (streq(argv[i], "-c"))
345 {
346 if ((i + 1) < argc)
347 {
348 i++;
349 if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(argv[i]));
350 }
351 }
352 else if (streq(argv[i], "-asl_in"))
353 {
354 if ((i + 1) < argc) activate_asl_in = atoi(argv[++i]);
355 }
356 else if (streq(argv[i], "-asl_action"))
357 {
358 if ((i + 1) < argc) activate_asl_action = atoi(argv[++i]);
359 }
360 else if (streq(argv[i], "-klog_in"))
361 {
362 if ((i + 1) < argc) activate_klog_in = atoi(argv[++i]);
363 }
364 else if (streq(argv[i], "-bsd_in"))
365 {
366 if ((i + 1) < argc) activate_bsd_in = atoi(argv[++i]);
367 }
368 else if (streq(argv[i], "-bsd_out"))
369 {
370 if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]);
371 }
372 else if (streq(argv[i], "-udp_in"))
373 {
374 if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
375 }
376 }
377
378 TAILQ_INIT(&Moduleq);
379 static_modules();
380 load_modules(mp);
381 aslevent_init();
382
383 if (debug == 0)
384 {
385 if (daemonize != 0)
386 {
387 if (fork() != 0) exit(0);
388
389 detach();
390 closeall();
391 }
392
393 writepid();
394 }
395
396 signal(SIGHUP, catch_sighup);
397 signal(SIGWINCH, catch_sigwinch);
398
399 FD_ZERO(&rd);
400 FD_ZERO(&wr);
401 FD_ZERO(&ex);
402
403 for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
404 {
405 fd = mod->init();
406 if (fd < 0) continue;
407 }
408
409 lastmark = time(NULL);
410 notify_time = lastmark;
411 memset(&timeout, 0, sizeof(struct timeval));
412 pto = NULL;
413
414 ssec = msec;
415 if (ssec > 0)
416 {
417 timeout.tv_sec = ssec;
418 pto = &timeout;
419 }
420
421 ptime = 0;
422 if (pdays > 0) ptime = lastmark + PRUNE_AFTER_START_DELAY;
423
424 if (kfd >= 0) FD_SET(kfd, &kern);
425
426 /*
427 * drain /dev/klog first
428 */
429 if (kfd >= 0)
430 {
431 max = kfd + 1;
432 while (select(max, &kern, NULL, NULL, &zto) > 0)
433 {
434 aslevent_handleevent(kern, wr, ex, NULL);
435 }
436 }
437
438 forever
439 {
440 if (pto != NULL) pto->tv_sec = ssec;
441 max = aslevent_fdsets(&rd, &wr, &ex) + 1;
442
443 status = select(max, &rd, &wr, &ex, pto);
444 if ((kfd >= 0) && FD_ISSET(kfd, &rd))
445 {
446 /*
447 * drain /dev/klog
448 */
449 max = kfd + 1;
450
451 while (select(max, &kern, NULL, NULL, &zto) > 0)
452 {
453 aslevent_handleevent(kern, wr, ex, NULL);
454 }
455 }
456
457 if (reset != 0)
458 {
459 send_reset();
460 reset = 0;
461 }
462
463 if (pto != NULL)
464 {
465 tick = time(NULL);
466 delta = tick - lastmark;
467 if (delta >= msec)
468 {
469 lastmark = tick;
470 aslmark();
471 }
472 }
473
474 if (prune != 0)
475 {
476 asl_prune(NULL);
477 prune = 0;
478 ptime = 0;
479 }
480 else if (ptime != 0)
481 {
482 tick = time(NULL);
483 if (tick >= ptime)
484 {
485 pq = asl_new(ASL_TYPE_QUERY);
486 str = NULL;
487 asprintf(&str, "-%dd", pdays);
488 asl_set_query(pq, ASL_KEY_TIME, str, ASL_QUERY_OP_LESS);
489 if (str != NULL) free(str);
490
491 /* asl_prune frees the query */
492 asl_prune(pq);
493 ptime = 0;
494 }
495 }
496
497 if (__notify_78945668_info__ < 0)
498 {
499 tick = time(NULL);
500 if (tick >= notify_time)
501 {
502 if (notify_post("com.apple.system.syslogd") == NOTIFY_STATUS_OK) __notify_78945668_info__ = 0;
503 else notify_time = tick + NOTIFY_DELAY;
504 }
505 }
506
507 if (status != 0) aslevent_handleevent(rd, wr, ex, NULL);
508 }
509 }
510
511 int
512 asldebug(const char *str, ...)
513 {
514 va_list v;
515
516 if (debug == 0) return 0;
517
518 va_start(v, str);
519 return vprintf(str, v);
520 }