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