]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/syslogd.c
syslog-97.1.tar.gz
[apple/syslog.git] / syslogd.tproj / syslogd.c
1 /*
2 * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <mach/mach.h>
30 #include <mach/mach_error.h>
31 #include <mach/mach_time.h>
32 #include <servers/bootstrap.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/fcntl.h>
36 #include <sys/queue.h>
37 #include <sys/time.h>
38 #include <pthread.h>
39 #include <dirent.h>
40 #include <dlfcn.h>
41 #include <libgen.h>
42 #include <notify.h>
43 #include "daemon.h"
44
45 #define SERVICE_NAME "com.apple.system.logger"
46 #define SERVER_STATUS_ERROR -1
47 #define SERVER_STATUS_INACTIVE 0
48 #define SERVER_STATUS_ACTIVE 1
49 #define SERVER_STATUS_ON_DEMAND 2
50
51 #define DEFAULT_MARK_SEC 0
52 #define DEFAULT_UTMP_TTL_SEC 31622400
53 #define DEFAULT_FS_TTL_SEC 31622400
54 #define DEFAULT_BSD_MAX_DUP_SEC 30
55 #define DEFAULT_MPS_LIMIT 500
56 #define BILLION 1000000000
57
58 #define NOTIFY_DELAY 1
59
60 #define NETWORK_CHANGE_NOTIFICATION "com.apple.system.config.network_change"
61
62 #define streq(A,B) (strcmp(A,B)==0)
63 #define forever for(;;)
64
65 static uint64_t time_start = 0;
66 static uint64_t mark_last = 0;
67 static uint64_t ping_last = 0;
68 static uint64_t time_last = 0;
69
70 extern int __notify_78945668_info__;
71 extern int _malloc_no_asl_log;
72
73 static TAILQ_HEAD(ml, module_list) Moduleq;
74
75 /* global */
76 struct global_s global;
77
78 /* Static Modules */
79 int asl_in_init();
80 int asl_in_reset();
81 int asl_in_close();
82 static int activate_asl_in = 1;
83
84 int asl_action_init();
85 int asl_action_reset();
86 int asl_action_close();
87 static int activate_asl_action = 1;
88
89 int klog_in_init();
90 int klog_in_reset();
91 int klog_in_close();
92 static int activate_klog_in = 1;
93
94 int bsd_in_init();
95 int bsd_in_reset();
96 int bsd_in_close();
97 static int activate_bsd_in = 1;
98
99 int bsd_out_init();
100 int bsd_out_reset();
101 int bsd_out_close();
102 static int activate_bsd_out = 1;
103
104 int remote_init();
105 int remote_reset();
106 int remote_close();
107 static int activate_remote = 0;
108
109 int udp_in_init();
110 int udp_in_reset();
111 int udp_in_close();
112 static int activate_udp_in = 1;
113
114 extern void database_server();
115 extern void output_worker();
116 extern void launchd_drain();
117 extern void bsd_flush_duplicates(time_t now);
118 extern void bsd_close_idle_files(time_t now);
119
120 /*
121 * Module approach: only one type of module. This module may implement
122 * the set of functions necessary for any of the functions (input, output,
123 * etc.) Prior to using the modules, dlsym() is consulted to see what it
124 * implements.
125 */
126
127 static int
128 static_modules()
129 {
130 struct module_list *tmp;
131
132 /*
133 * The order of these initializations is important.
134 * When messages are sent to output modules, they are
135 * sent in the same order as these initializations.
136 * asl_action may add modify messages, for example to
137 * add access controls, so it must come first.
138 */
139 if (activate_asl_action != 0)
140 {
141 tmp = calloc(1, sizeof(struct module_list));
142 if (tmp == NULL) return 1;
143
144 tmp->name = strdup("asl_action");
145 if (tmp->name == NULL)
146 {
147 free(tmp);
148 return 1;
149 }
150
151 tmp->module = NULL;
152 tmp->init = asl_action_init;
153 tmp->reset = asl_action_reset;
154 tmp->close = asl_action_close;
155 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
156 }
157
158 if (activate_asl_in != 0)
159 {
160 tmp = calloc(1, sizeof(struct module_list));
161 if (tmp == NULL) return 1;
162
163 tmp->name = strdup("asl_in");
164 if (tmp->name == NULL)
165 {
166 free(tmp);
167 return 1;
168 }
169
170 tmp->module = NULL;
171 tmp->init = asl_in_init;
172 tmp->reset = asl_in_reset;
173 tmp->close = asl_in_close;
174 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
175 }
176
177 if (activate_klog_in != 0)
178 {
179 tmp = calloc(1, sizeof(struct module_list));
180 if (tmp == NULL) return 1;
181
182 tmp->name = strdup("klog_in");
183 if (tmp->name == NULL)
184 {
185 free(tmp);
186 return 1;
187 }
188
189 tmp->module = NULL;
190 tmp->init = klog_in_init;
191 tmp->reset = klog_in_reset;
192 tmp->close = klog_in_close;
193 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
194 }
195
196 if (activate_bsd_in != 0)
197 {
198 tmp = calloc(1, sizeof(struct module_list));
199 if (tmp == NULL) return 1;
200
201 tmp->name = strdup("bsd_in");
202 if (tmp->name == NULL)
203 {
204 free(tmp);
205 return 1;
206 }
207
208 tmp->module = NULL;
209 tmp->init = bsd_in_init;
210 tmp->reset = bsd_in_reset;
211 tmp->close = bsd_in_close;
212 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
213 }
214
215 if (activate_bsd_out != 0)
216 {
217 tmp = calloc(1, sizeof(struct module_list));
218 if (tmp == NULL) return 1;
219
220 tmp->name = strdup("bsd_out");
221 if (tmp->name == NULL)
222 {
223 free(tmp);
224 return 1;
225 }
226
227 tmp->module = NULL;
228 tmp->init = bsd_out_init;
229 tmp->reset = bsd_out_reset;
230 tmp->close = bsd_out_close;
231 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
232 }
233
234 if (activate_remote != 0)
235 {
236 tmp = calloc(1, sizeof(struct module_list));
237 if (tmp == NULL) return 1;
238
239 tmp->name = strdup("remote");
240 if (tmp->name == NULL)
241 {
242 free(tmp);
243 return 1;
244 }
245
246 tmp->module = NULL;
247 tmp->init = remote_init;
248 tmp->reset = remote_reset;
249 tmp->close = remote_close;
250 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
251 }
252
253 if (activate_udp_in != 0)
254 {
255 tmp = calloc(1, sizeof(struct module_list));
256 if (tmp == NULL) return 1;
257
258 tmp->name = strdup("udp_in");
259 if (tmp->name == NULL)
260 {
261 free(tmp);
262 return 1;
263 }
264
265 tmp->module = NULL;
266 tmp->init = udp_in_init;
267 tmp->reset = udp_in_reset;
268 tmp->close = udp_in_close;
269 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
270 }
271
272 return 0;
273 }
274
275 /*
276 * Loads all the modules. This DOES NOT call the modules initializer
277 * functions. It simply scans the modules directory looking for modules
278 * and loads them. This does not mean the module will be used.
279 */
280 static int
281 load_modules(const char *mp)
282 {
283 DIR *d;
284 struct dirent *de;
285 struct module_list *tmp;
286 void *c, *bn;
287 char *modulepath = NULL;
288
289 d = opendir(mp);
290 if (d == NULL) return -1;
291
292 while (NULL != (de = readdir(d)))
293 {
294 if (de->d_name[0] == '.') continue;
295
296 /* Must have ".so" in the name" */
297 if (!strstr(de->d_name, ".so")) continue;
298
299 asprintf(&modulepath, "%s/%s", mp, de->d_name);
300 if (!modulepath) continue;
301
302 c = dlopen(modulepath, RTLD_LOCAL);
303 if (c == NULL)
304 {
305 free(modulepath);
306 continue;
307 }
308
309 tmp = calloc(1, sizeof(struct module_list));
310 if (tmp == NULL)
311 {
312 free(modulepath);
313 dlclose(c);
314 continue;
315 }
316
317 bn = basename(modulepath);
318 tmp->name = strdup(bn);
319 if (tmp->name == NULL)
320 {
321 free(tmp);
322 return 1;
323 }
324
325 tmp->module = c;
326 TAILQ_INSERT_TAIL(&Moduleq, tmp, entries);
327
328 tmp->init = dlsym(tmp->module, "aslmod_init");
329 tmp->reset = dlsym(tmp->module, "aslmod_reset");
330 tmp->close = dlsym(tmp->module, "aslmod_close");
331
332 free(modulepath);
333 }
334
335 closedir(d);
336
337 return 0;
338 }
339
340 static void
341 writepid(void)
342 {
343 FILE *fp;
344
345 fp = fopen(_PATH_PIDFILE, "w");
346 if (fp != NULL)
347 {
348 fprintf(fp, "%d\n", getpid());
349 fclose(fp);
350 }
351 }
352
353 static void
354 closeall(void)
355 {
356 int i;
357
358 for (i = getdtablesize() - 1; i >= 0; i--) close(i);
359
360 open("/dev/null", O_RDWR, 0);
361 dup(0);
362 dup(0);
363 }
364
365 static void
366 detach(void)
367 {
368 signal(SIGINT, SIG_IGN);
369 signal(SIGPIPE, SIG_IGN);
370 setsid();
371 }
372
373 static void
374 catch_sighup(int x)
375 {
376 global.reset = RESET_CONFIG;
377 }
378
379 static void
380 catch_siginfo(int x)
381 {
382 global.reset = RESET_NETWORK;
383 }
384
385 static void
386 send_reset(void)
387 {
388 struct module_list *mod;
389
390 for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
391 {
392 if (mod->reset != NULL) mod->reset();
393 }
394 }
395
396 /*
397 * perform timed activities and set next run-loop timeout
398 */
399 static void
400 timed_events(struct timeval **run)
401 {
402 time_t now, delta, t;
403 static struct timeval next;
404
405 now = time(NULL);
406
407 *run = NULL;
408 next.tv_sec = 0;
409 next.tv_usec = 0;
410
411 if (time_start == 0)
412 {
413 /* startup */
414 time_start = now;
415 time_last = now;
416 mark_last = now;
417 ping_last = now;
418 }
419
420 /*
421 * At startup, we try sending a notification once a second.
422 * Once it succeeds, we set the Libc global __notify_78945668_info__ to 0
423 * which lets Libc's localtime calculations use notifyd to invalidate
424 * cached timezones. This prevents a deadlock in localtime.
425 */
426 if (__notify_78945668_info__ < 0)
427 {
428 if (notify_post("com.apple.system.syslogd") == NOTIFY_STATUS_OK) __notify_78945668_info__ = 0;
429 else next.tv_sec = 1;
430 }
431
432 if (time_last > now)
433 {
434 /*
435 * Despite Albert Einstein's assurance, time has gone backward.
436 * Reset "last" times to current time.
437 */
438 time_last = now;
439 mark_last = now;
440 ping_last = now;
441 }
442
443 /*
444 * Tickle bsd_out module to flush duplicates.
445 */
446 if (global.bsd_flush_time > 0)
447 {
448 bsd_flush_duplicates(now);
449 bsd_close_idle_files(now);
450 if (global.bsd_flush_time > 0)
451 {
452 if (next.tv_sec == 0) next.tv_sec = global.bsd_flush_time;
453 else if (global.bsd_flush_time < next.tv_sec) next.tv_sec = global.bsd_flush_time;
454 }
455 }
456
457 /*
458 * Tickle asl_store to sweep file cache
459 */
460 if (global.asl_store_ping_time > 0)
461 {
462 delta = now - ping_last;
463 if (delta >= global.asl_store_ping_time)
464 {
465 db_ping_store();
466 bsd_close_idle_files(now);
467 ping_last = now;
468 t = global.asl_store_ping_time;
469 }
470 else
471 {
472 t = global.asl_store_ping_time - delta;
473 }
474
475 if (next.tv_sec == 0) next.tv_sec = t;
476 else if (t < next.tv_sec) next.tv_sec = t;
477 }
478
479 /*
480 * Send MARK
481 */
482 if (global.mark_time > 0)
483 {
484 delta = now - mark_last;
485 if (delta >= global.mark_time)
486 {
487 asl_mark();
488 mark_last = now;
489 t = global.mark_time;
490 }
491 else
492 {
493 t = global.mark_time - delta;
494 }
495
496 if (next.tv_sec == 0) next.tv_sec = t;
497 else if (t < next.tv_sec) next.tv_sec = t;
498 }
499
500 /*
501 * set output timeout parameter if runloop needs to have a timer
502 */
503 if (next.tv_sec > 0) *run = &next;
504
505 time_last = now;
506 }
507
508 void
509 init_config()
510 {
511 launch_data_t tmp, pdict;
512 kern_return_t status;
513
514 tmp = launch_data_new_string(LAUNCH_KEY_CHECKIN);
515 global.launch_dict = launch_msg(tmp);
516 launch_data_free(tmp);
517
518 if (global.launch_dict == NULL)
519 {
520 fprintf(stderr, "%d launchd checkin failed\n", getpid());
521 exit(1);
522 }
523
524 tmp = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_MACHSERVICES);
525 if (tmp == NULL)
526 {
527 fprintf(stderr, "%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid());
528 exit(1);
529 }
530
531 pdict = launch_data_dict_lookup(tmp, SERVICE_NAME);
532 if (pdict == NULL)
533 {
534 fprintf(stderr, "%d launchd lookup of SERVICE_NAME failed\n", getpid());
535 exit(1);
536 }
537
538 global.server_port = launch_data_get_machport(pdict);
539
540 /* port for receiving internal messages */
541 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(global.self_port));
542 if (status != KERN_SUCCESS)
543 {
544 fprintf(stderr, "mach_port_allocate self_port failed: %d", status);
545 exit(1);
546 }
547
548 status = mach_port_insert_right(mach_task_self(), global.self_port, global.self_port, MACH_MSG_TYPE_MAKE_SEND);
549 if (status != KERN_SUCCESS)
550 {
551 fprintf(stderr, "Can't make send right for self_port: %d\n", status);
552 exit(1);
553 }
554
555 /* port for receiving MACH_NOTIFY_DEAD_NAME notifications */
556 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(global.dead_session_port));
557 if (status != KERN_SUCCESS)
558 {
559 fprintf(stderr, "mach_port_allocate dead_session_port failed: %d", status);
560 exit(1);
561 }
562
563 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &(global.listen_set));
564 if (status != KERN_SUCCESS)
565 {
566 fprintf(stderr, "mach_port_allocate listen_set failed: %d", status);
567 exit(1);
568 }
569
570 status = mach_port_move_member(mach_task_self(), global.server_port, global.listen_set);
571 if (status != KERN_SUCCESS)
572 {
573 fprintf(stderr, "mach_port_move_member server_port failed: %d", status);
574 exit(1);
575 }
576
577 status = mach_port_move_member(mach_task_self(), global.self_port, global.listen_set);
578 if (status != KERN_SUCCESS)
579 {
580 fprintf(stderr, "mach_port_move_member self_port failed: %d", status);
581 exit(1);
582 }
583
584 status = mach_port_move_member(mach_task_self(), global.dead_session_port, global.listen_set);
585 if (status != KERN_SUCCESS)
586 {
587 fprintf(stderr, "mach_port_move_member dead_session_port failed (%u)", status);
588 exit(1);
589 }
590 }
591
592 void
593 config_debug(int enable, const char *path)
594 {
595 OSSpinLockLock(&global.lock);
596
597 global.debug = enable;
598 if (global.debug_file != NULL) free(global.debug_file);
599 global.debug_file = strdup(path);
600
601 OSSpinLockUnlock(&global.lock);
602 }
603
604 void
605 config_data_store(int type, uint32_t file_max, uint32_t memory_max, uint32_t mini_max)
606 {
607 pthread_mutex_lock(global.db_lock);
608
609 if (global.dbtype & DB_TYPE_FILE)
610 {
611 asl_store_close(global.file_db);
612 global.file_db = NULL;
613 }
614
615 if (global.dbtype & DB_TYPE_MEMORY)
616 {
617 asl_memory_close(global.memory_db);
618 global.memory_db = NULL;
619 }
620
621 if (global.dbtype & DB_TYPE_MINI)
622 {
623 asl_mini_memory_close(global.mini_db);
624 global.mini_db = NULL;
625 }
626
627 global.dbtype = type;
628 global.db_file_max = file_max;
629 global.db_memory_max = memory_max;
630 global.db_mini_max = mini_max;
631
632 pthread_mutex_unlock(global.db_lock);
633 }
634
635 int
636 main(int argc, const char *argv[])
637 {
638 struct module_list *mod;
639 fd_set rd, wr, ex, kern;
640 int32_t fd, i, max, status, daemonize;
641 const char *mp;
642 struct timeval *runloop_timer, zto;
643 pthread_attr_t attr;
644 pthread_t t;
645 int network_change_token;
646 char tstr[32];
647 time_t now;
648
649 memset(&global, 0, sizeof(struct global_s));
650
651 global.db_lock = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
652 pthread_mutex_init(global.db_lock, NULL);
653
654 global.work_queue_lock = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
655 pthread_mutex_init(global.work_queue_lock, NULL);
656
657 pthread_cond_init(&global.work_queue_cond, NULL);
658
659 global.work_queue = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
660
661 global.asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
662 global.db_file_max = 16384000;
663 global.db_memory_max = 8192;
664 global.db_mini_max = 256;
665 global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
666 global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
667 global.fs_ttl = DEFAULT_FS_TTL_SEC;
668 global.mps_limit = DEFAULT_MPS_LIMIT;
669 global.kfd = -1;
670
671 #ifdef CONFIG_MAC
672 global.dbtype = DB_TYPE_FILE;
673 global.db_file_max = 25600000;
674 global.asl_store_ping_time = 150;
675 #endif
676
677 #ifdef CONFIG_APPLETV
678 global.dbtype = DB_TYPE_FILE;
679 global.db_file_max = 10240000;
680 global.asl_store_ping_time = 150;
681 #endif
682
683 #ifdef CONFIG_IPHONE
684 global.dbtype = DB_TYPE_MINI;
685 activate_remote = 1;
686 activate_bsd_out = 0;
687 #endif
688
689 mp = _PATH_MODULE_LIB;
690 daemonize = 0;
691 __notify_78945668_info__ = 0xf0000000;
692 zto.tv_sec = 0;
693 zto.tv_usec = 0;
694
695 /* prevent malloc from calling ASL on error */
696 _malloc_no_asl_log = 1;
697
698 /* first pass sets up default configurations */
699 for (i = 1; i < argc; i++)
700 {
701 if (streq(argv[i], "-config"))
702 {
703 if (((i + 1) < argc) && (argv[i+1][0] != '-'))
704 {
705 i++;
706 if (streq(argv[i], "mac"))
707 {
708 global.dbtype = DB_TYPE_FILE;
709 global.db_file_max = 25600000;
710 }
711 else if (streq(argv[i], "appletv"))
712 {
713 global.dbtype = DB_TYPE_FILE;
714 global.db_file_max = 10240000;
715 }
716 else if (streq(argv[i], "iphone"))
717 {
718 global.dbtype = DB_TYPE_MINI;
719 activate_remote = 1;
720 }
721 }
722 }
723 }
724
725 for (i = 1; i < argc; i++)
726 {
727 if (streq(argv[i], "-d"))
728 {
729 global.debug = 1;
730 if (((i+1) < argc) && (argv[i+1][0] != '-')) global.debug_file = strdup(argv[++i]);
731 memset(tstr, 0, sizeof(tstr));
732 now = time(NULL);
733 ctime_r(&now, tstr);
734 tstr[19] = '\0';
735 asldebug("%s syslogd[%d]: Start\n", tstr, getpid());
736 }
737 else if (streq(argv[i], "-db"))
738 {
739 if (((i + 1) < argc) && (argv[i+1][0] != '-'))
740 {
741 i++;
742 if (streq(argv[i], "file"))
743 {
744 global.dbtype |= DB_TYPE_FILE;
745 if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_file_max = atol(argv[++i]);
746 }
747 else if (streq(argv[i], "memory"))
748 {
749 global.dbtype |= DB_TYPE_MEMORY;
750 if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_memory_max = atol(argv[++i]);
751 }
752 else if (streq(argv[i], "mini"))
753 {
754 global.dbtype |= DB_TYPE_MINI;
755 if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_mini_max = atol(argv[++i]);
756 }
757 }
758 }
759 else if (streq(argv[i], "-D"))
760 {
761 daemonize = 1;
762 }
763 else if (streq(argv[i], "-m"))
764 {
765 if ((i + 1) < argc) global.mark_time = 60 * atoll(argv[++i]);
766 }
767 else if (streq(argv[i], "-utmp_ttl"))
768 {
769 if ((i + 1) < argc) global.utmp_ttl = atol(argv[++i]);
770 }
771 else if (streq(argv[i], "-fs_ttl"))
772 {
773 if ((i + 1) < argc) global.fs_ttl = atol(argv[++i]);
774 }
775 else if (streq(argv[i], "-mps_limit"))
776 {
777 if ((i + 1) < argc) global.mps_limit = atol(argv[++i]);
778 }
779 else if (streq(argv[i], "-l"))
780 {
781 if ((i + 1) < argc) mp = argv[++i];
782 }
783 else if (streq(argv[i], "-c"))
784 {
785 if ((i + 1) < argc)
786 {
787 i++;
788 if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) global.asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(argv[i]));
789 }
790 }
791 else if (streq(argv[i], "-dup_delay"))
792 {
793 if ((i + 1) < argc) global.bsd_max_dup_time = atoll(argv[++i]);
794 }
795 else if (streq(argv[i], "-asl_in"))
796 {
797 if ((i + 1) < argc) activate_asl_in = atoi(argv[++i]);
798 }
799 else if (streq(argv[i], "-asl_action"))
800 {
801 if ((i + 1) < argc) activate_asl_action = atoi(argv[++i]);
802 }
803 else if (streq(argv[i], "-klog_in"))
804 {
805 if ((i + 1) < argc) activate_klog_in = atoi(argv[++i]);
806 }
807 else if (streq(argv[i], "-bsd_in"))
808 {
809 if ((i + 1) < argc) activate_bsd_in = atoi(argv[++i]);
810 }
811 else if (streq(argv[i], "-bsd_out"))
812 {
813 if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]);
814 }
815 else if (streq(argv[i], "-remote"))
816 {
817 if ((i + 1) < argc) activate_remote = atoi(argv[++i]);
818 }
819 else if (streq(argv[i], "-udp_in"))
820 {
821 if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
822 }
823 }
824
825 if (global.dbtype == 0)
826 {
827 global.dbtype = DB_TYPE_FILE;
828 global.db_file_max = 25600000;
829 global.asl_store_ping_time = 150;
830 }
831
832 TAILQ_INIT(&Moduleq);
833 static_modules();
834 load_modules(mp);
835 aslevent_init();
836
837 if (global.debug == 0)
838 {
839 if (daemonize != 0)
840 {
841 if (fork() != 0) exit(0);
842
843 detach();
844 closeall();
845 }
846
847 writepid();
848 }
849
850 init_config();
851
852 signal(SIGHUP, catch_sighup);
853 signal(SIGINFO, catch_siginfo);
854
855 /* register for network change notifications if the udp_in module is active */
856 network_change_token = -1;
857 if (activate_udp_in != 0) notify_register_signal(NETWORK_CHANGE_NOTIFICATION, SIGINFO, &network_change_token);
858
859 for (mod = Moduleq.tqh_first; mod != NULL; mod = mod->entries.tqe_next)
860 {
861 fd = mod->init();
862 if (fd < 0) continue;
863 }
864
865 /*
866 * Start database server thread
867 */
868 pthread_attr_init(&attr);
869 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
870 pthread_create(&t, &attr, (void *(*)(void *))database_server, NULL);
871 pthread_attr_destroy(&attr);
872
873 /*
874 * Start output worker thread
875 */
876 pthread_attr_init(&attr);
877 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
878 pthread_create(&t, &attr, (void *(*)(void *))output_worker, NULL);
879 pthread_attr_destroy(&attr);
880
881 FD_ZERO(&rd);
882 FD_ZERO(&wr);
883 FD_ZERO(&ex);
884
885 /*
886 * drain /dev/klog first
887 */
888 if (global.kfd >= 0)
889 {
890 FD_ZERO(&kern);
891 FD_SET(global.kfd, &kern);
892 max = global.kfd + 1;
893 while (select(max, &kern, NULL, NULL, &zto) > 0)
894 {
895 aslevent_handleevent(&kern, &wr, &ex);
896 }
897 }
898
899 /*
900 * Start launchd drain thread
901 */
902 pthread_attr_init(&attr);
903 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
904 pthread_create(&t, &attr, (void *(*)(void *))launchd_drain, NULL);
905 pthread_attr_destroy(&attr);
906
907 runloop_timer = NULL;
908 timed_events(&runloop_timer);
909
910 forever
911 {
912 max = aslevent_fdsets(&rd, &wr, &ex) + 1;
913
914 status = select(max, &rd, &wr, &ex, runloop_timer);
915 if ((global.kfd >= 0) && FD_ISSET(global.kfd, &rd))
916 {
917 /* drain /dev/klog */
918 FD_ZERO(&kern);
919 FD_SET(global.kfd, &kern);
920 max = global.kfd + 1;
921
922 while (select(max, &kern, NULL, NULL, &zto) > 0)
923 {
924 aslevent_handleevent(&kern, &wr, &ex);
925 }
926 }
927
928 if (global.reset != RESET_NONE)
929 {
930 send_reset();
931 global.reset = RESET_NONE;
932 }
933
934 if (status != 0) aslevent_handleevent(&rd, &wr, &ex);
935
936 timed_events(&runloop_timer);
937 }
938 }