]> git.saurik.com Git - apple/syslog.git/blob - syslogd.tproj/syslogd.c
syslog-148.7.tar.gz
[apple/syslog.git] / syslogd.tproj / syslogd.c
1 /*
2 * Copyright (c) 2004-2011 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 <notify_keys.h>
48 #include <utmpx.h>
49 #include <vproc_priv.h>
50 #include "daemon.h"
51
52 #define SERVICE_NAME "com.apple.system.logger"
53 #define SERVER_STATUS_ERROR -1
54 #define SERVER_STATUS_INACTIVE 0
55 #define SERVER_STATUS_ACTIVE 1
56 #define SERVER_STATUS_ON_DEMAND 2
57
58 #define BILLION 1000000000
59
60 #define NOTIFY_DELAY 1
61
62 #define streq(A,B) (strcmp(A,B)==0)
63 #define forever for(;;)
64
65 extern int __notify_78945668_info__;
66 extern int _malloc_no_asl_log;
67
68 /* global */
69 struct global_s global;
70
71 /* Input Modules */
72 int klog_in_init(void);
73 int klog_in_reset(void);
74 int klog_in_close(void);
75 static int activate_klog_in = 1;
76
77 int bsd_in_init(void);
78 int bsd_in_reset(void);
79 int bsd_in_close(void);
80 static int activate_bsd_in = 1;
81
82 int udp_in_init(void);
83 int udp_in_reset(void);
84 int udp_in_close(void);
85 static int activate_udp_in = 1;
86
87 /* Output Modules */
88 int bsd_out_init(void);
89 int bsd_out_reset(void);
90 int bsd_out_close(void);
91 static int activate_bsd_out = 1;
92
93 int asl_action_init(void);
94 int asl_action_reset(void);
95 int asl_action_close(void);
96 static int activate_asl_action = 1;
97
98 /* Interactive Module */
99 int remote_init(void);
100 int remote_reset(void);
101 int remote_close(void);
102 static int remote_enabled = 0;
103
104 extern void database_server();
105
106 static void
107 init_modules()
108 {
109 module_t *m_klog_in, *m_bsd_in, *m_bsd_out, *m_udp_in;
110 module_t *m_asl, *m_remote;
111
112 /* ASL module (configured by /etc/asl.conf) */
113 m_asl = (module_t *)calloc(1, sizeof(module_t));
114 if (m_asl == NULL)
115 {
116 asldebug("alloc failed (init_modules asl_action)\n");
117 exit(1);
118 }
119
120 m_asl->name = "asl_action";
121 m_asl->enabled = activate_asl_action;
122 m_asl->init = asl_action_init;
123 m_asl->reset = asl_action_reset;
124 m_asl->close = asl_action_close;
125
126 if (m_asl->enabled) m_asl->init();
127
128 /* BSD output module (configured by /etc/syslog.conf) */
129 m_bsd_out = (module_t *)calloc(1, sizeof(module_t));
130 if (m_bsd_out == NULL)
131 {
132 asldebug("alloc failed (init_modules bsd_out)\n");
133 exit(1);
134 }
135
136 m_bsd_out->name = "bsd_out";
137 m_bsd_out->enabled = activate_bsd_out;
138 m_bsd_out->init = bsd_out_init;
139 m_bsd_out->reset = bsd_out_reset;
140 m_bsd_out->close = bsd_out_close;
141
142 if (m_bsd_out->enabled)
143 {
144 m_bsd_out->init();
145 global.bsd_out_enabled = 1;
146 }
147
148 /* kernel input module */
149 m_klog_in = (module_t *)calloc(1, sizeof(module_t));
150 if (m_klog_in == NULL)
151 {
152 asldebug("alloc failed (init_modules klog_in)\n");
153 exit(1);
154 }
155
156 m_klog_in->name = "klog_in";
157 m_klog_in->enabled = activate_klog_in;
158 m_klog_in->init = klog_in_init;
159 m_klog_in->reset = klog_in_reset;
160 m_klog_in->close = klog_in_close;
161
162 if (m_klog_in->enabled) m_klog_in->init();
163
164 /* BSD (UNIX domain socket) input module */
165 m_bsd_in = (module_t *)calloc(1, sizeof(module_t));
166 if (m_bsd_in == NULL)
167 {
168 asldebug("alloc failed (init_modules bsd_in)\n");
169 exit(1);
170 }
171
172 m_bsd_in->name = "bsd_in";
173 m_bsd_in->enabled = activate_bsd_in;
174 m_bsd_in->init = bsd_in_init;
175 m_bsd_in->reset = bsd_in_reset;
176 m_bsd_in->close = bsd_in_close;
177
178 if (m_bsd_in->enabled) m_bsd_in->init();
179
180 /* network (syslog protocol) input module */
181 m_udp_in = (module_t *)calloc(1, sizeof(module_t));
182 if (m_udp_in == NULL)
183 {
184 asldebug("alloc failed (init_modules udp_in)\n");
185 exit(1);
186 }
187
188 m_udp_in->name = "udp_in";
189 m_udp_in->enabled = activate_udp_in;
190 m_udp_in->init = udp_in_init;
191 m_udp_in->reset = udp_in_reset;
192 m_udp_in->close = udp_in_close;
193
194 if (m_udp_in->enabled) m_udp_in->init();
195
196 /* remote (iOS support) module */
197 m_remote = (module_t *)calloc(1, sizeof(module_t));
198 if (m_remote == NULL)
199 {
200 asldebug("alloc failed (init_modules remote)\n");
201 exit(1);
202 }
203
204 m_remote->name = "remote";
205 m_remote->enabled = remote_enabled;
206 m_remote->init = remote_init;
207 m_remote->reset = remote_reset;
208 m_remote->close = remote_close;
209
210 if (m_remote->enabled) m_remote->init();
211
212 /* save modules in global.module array */
213 global.module_count = 6;
214 global.module = (module_t **)calloc(global.module_count, sizeof(module_t *));
215 if (global.module == NULL)
216 {
217 asldebug("alloc failed (init_modules)\n");
218 exit(1);
219 }
220
221 global.module[0] = m_asl;
222 global.module[1] = m_bsd_out;
223 global.module[2] = m_klog_in;
224 global.module[3] = m_bsd_in;
225 global.module[4] = m_udp_in;
226 global.module[5] = m_remote;
227 }
228
229 static void
230 writepid(int *first)
231 {
232 struct stat sb;
233 FILE *fp;
234 pid_t pid = getpid();
235
236 asldebug("\nsyslogd %d start\n", pid);
237
238 if (first != NULL)
239 {
240 *first = 1;
241 memset(&sb, 0, sizeof(struct stat));
242 if (stat(_PATH_PIDFILE, &sb) == 0)
243 {
244 if (S_ISREG(sb.st_mode)) *first = 0;
245 }
246 }
247
248 fp = fopen(_PATH_PIDFILE, "w");
249 if (fp != NULL)
250 {
251 fprintf(fp, "%d\n", pid);
252 fclose(fp);
253 }
254 }
255
256 void
257 launch_config()
258 {
259 launch_data_t tmp, pdict;
260 kern_return_t status;
261
262 tmp = launch_data_new_string(LAUNCH_KEY_CHECKIN);
263 global.launch_dict = launch_msg(tmp);
264 launch_data_free(tmp);
265
266 if (global.launch_dict == NULL)
267 {
268 asldebug("%d launchd checkin failed\n", getpid());
269 exit(1);
270 }
271
272 tmp = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_MACHSERVICES);
273 if (tmp == NULL)
274 {
275 asldebug("%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid());
276 exit(1);
277 }
278
279 pdict = launch_data_dict_lookup(tmp, SERVICE_NAME);
280 if (pdict == NULL)
281 {
282 asldebug("%d launchd lookup of SERVICE_NAME failed\n", getpid());
283 exit(1);
284 }
285
286 global.server_port = launch_data_get_machport(pdict);
287
288 /* port for receiving MACH_NOTIFY_DEAD_NAME notifications */
289 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(global.dead_session_port));
290 if (status != KERN_SUCCESS)
291 {
292 asldebug("mach_port_allocate dead_session_port failed: %d", status);
293 exit(1);
294 }
295
296 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &(global.listen_set));
297 if (status != KERN_SUCCESS)
298 {
299 asldebug("mach_port_allocate listen_set failed: %d", status);
300 exit(1);
301 }
302
303 status = mach_port_move_member(mach_task_self(), global.server_port, global.listen_set);
304 if (status != KERN_SUCCESS)
305 {
306 asldebug("mach_port_move_member server_port failed: %d", status);
307 exit(1);
308 }
309
310 status = mach_port_move_member(mach_task_self(), global.dead_session_port, global.listen_set);
311 if (status != KERN_SUCCESS)
312 {
313 asldebug("mach_port_move_member dead_session_port failed (%u)", status);
314 exit(1);
315 }
316 }
317
318 void
319 config_debug(int enable, const char *path)
320 {
321 OSSpinLockLock(&global.lock);
322
323 global.debug = enable;
324 free(global.debug_file);
325 global.debug_file = NULL;
326 if (path != NULL) global.debug_file = strdup(path);
327
328 OSSpinLockUnlock(&global.lock);
329 }
330
331 void
332 config_data_store(int type, uint32_t file_max, uint32_t memory_max, uint32_t mini_max)
333 {
334 pthread_mutex_lock(global.db_lock);
335
336 if (global.dbtype & DB_TYPE_FILE)
337 {
338 asl_store_close(global.file_db);
339 global.file_db = NULL;
340 }
341
342 if (global.dbtype & DB_TYPE_MEMORY)
343 {
344 asl_memory_close(global.memory_db);
345 global.memory_db = NULL;
346 }
347
348 if (global.dbtype & DB_TYPE_MINI)
349 {
350 asl_mini_memory_close(global.mini_db);
351 global.mini_db = NULL;
352 }
353
354 global.dbtype = type;
355 global.db_file_max = file_max;
356 global.db_memory_max = memory_max;
357 global.db_mini_max = mini_max;
358
359 pthread_mutex_unlock(global.db_lock);
360 }
361
362 void
363 write_boot_log(int first)
364 {
365 int mib[2] = {CTL_KERN, KERN_BOOTTIME};
366 size_t len;
367 aslmsg msg;
368 char buf[256];
369 struct utmpx utx;
370
371 if (first == 0)
372 {
373 /* syslogd restart */
374 msg = asl_new(ASL_TYPE_MSG);
375 if (msg == NULL) return;
376
377 asl_set(msg, ASL_KEY_SENDER, "syslogd");
378 asl_set(msg, ASL_KEY_FACILITY, "daemon");
379 asl_set(msg, ASL_KEY_LEVEL, "Notice");
380 asl_set(msg, ASL_KEY_UID, "0");
381 asl_set(msg, ASL_KEY_GID, "0");
382 snprintf(buf, sizeof(buf), "%u", getpid());
383 asl_set(msg, ASL_KEY_PID, buf);
384 asl_set(msg, ASL_KEY_MSG, "--- syslogd restarted ---");
385 dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
386 return;
387 }
388
389 bzero(&utx, sizeof(utx));
390 utx.ut_type = BOOT_TIME;
391 utx.ut_pid = 1;
392
393 /* get the boot time */
394 len = sizeof(struct timeval);
395 if (sysctl(mib, 2, &utx.ut_tv, &len, NULL, 0) < 0)
396 {
397 gettimeofday(&utx.ut_tv, NULL);
398 }
399
400 pututxline(&utx);
401
402 msg = asl_new(ASL_TYPE_MSG);
403 if (msg == NULL) return;
404
405 asl_set(msg, ASL_KEY_SENDER, "bootlog");
406 asl_set(msg, ASL_KEY_FACILITY, "com.apple.system.utmpx");
407 asl_set(msg, ASL_KEY_LEVEL, "Notice");
408 asl_set(msg, ASL_KEY_UID, "0");
409 asl_set(msg, ASL_KEY_GID, "0");
410 asl_set(msg, ASL_KEY_PID, "0");
411 snprintf(buf, sizeof(buf), "BOOT_TIME %lu %u", (unsigned long)utx.ut_tv.tv_sec, (unsigned int)utx.ut_tv.tv_usec);
412 asl_set(msg, ASL_KEY_MSG, buf);
413 asl_set(msg, "ut_id", "0x00 0x00 0x00 0x00");
414 asl_set(msg, "ut_pid", "1");
415 asl_set(msg, "ut_type", "2");
416 snprintf(buf, sizeof(buf), "%lu", (unsigned long)utx.ut_tv.tv_sec);
417 asl_set(msg, ASL_KEY_TIME, buf);
418 asl_set(msg, "ut_tv.tv_sec", buf);
419 snprintf(buf, sizeof(buf), "%u", (unsigned int)utx.ut_tv.tv_usec);
420 asl_set(msg, "ut_tv.tv_usec", buf);
421 snprintf(buf, sizeof(buf), "%u%s", (unsigned int)utx.ut_tv.tv_usec, (utx.ut_tv.tv_usec == 0) ? "" : "000");
422 asl_set(msg, ASL_KEY_TIME_NSEC, buf);
423
424 dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
425 }
426
427 int
428 main(int argc, const char *argv[])
429 {
430 int32_t i;
431 int network_change_token, asl_db_token;
432 char tstr[32];
433 time_t now;
434 int first_syslogd_start = 1;
435
436 /* Set I/O policy */
437 setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE);
438
439 memset(&global, 0, sizeof(struct global_s));
440
441 global.db_lock = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
442 pthread_mutex_init(global.db_lock, NULL);
443
444 /*
445 * Create work queue, but suspend until output modules are initialized.
446 */
447 global.work_queue = dispatch_queue_create("Work Queue", NULL);
448 dispatch_suspend(global.work_queue);
449
450 global.lockdown_session_fd = -1;
451
452 init_globals();
453
454 #ifdef CONFIG_IPHONE
455 remote_enabled = 1;
456 activate_bsd_out = 0;
457 #endif
458
459 /* prevent malloc from calling ASL on error */
460 _malloc_no_asl_log = 1;
461
462 /* first pass sets up default configurations */
463 for (i = 1; i < argc; i++)
464 {
465 if (streq(argv[i], "-config"))
466 {
467 if (((i + 1) < argc) && (argv[i+1][0] != '-'))
468 {
469 i++;
470 if (streq(argv[i], "mac"))
471 {
472 global.dbtype = DB_TYPE_FILE;
473 global.db_file_max = 25600000;
474 }
475 else if (streq(argv[i], "appletv"))
476 {
477 global.dbtype = DB_TYPE_FILE;
478 global.db_file_max = 10240000;
479 }
480 else if (streq(argv[i], "iphone"))
481 {
482 global.dbtype = DB_TYPE_MINI;
483 remote_enabled = 1;
484 }
485 }
486 }
487 }
488
489 for (i = 1; i < argc; i++)
490 {
491 if (streq(argv[i], "-d"))
492 {
493 global.debug = 1;
494 if (((i+1) < argc) && (argv[i+1][0] != '-')) global.debug_file = strdup(argv[++i]);
495 memset(tstr, 0, sizeof(tstr));
496 now = time(NULL);
497 ctime_r(&now, tstr);
498 tstr[19] = '\0';
499 asldebug("%s syslogd[%d]: Start\n", tstr, getpid());
500 }
501 else if (streq(argv[i], "-db"))
502 {
503 if (((i + 1) < argc) && (argv[i+1][0] != '-'))
504 {
505 i++;
506 if (streq(argv[i], "file"))
507 {
508 global.dbtype |= DB_TYPE_FILE;
509 if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_file_max = atol(argv[++i]);
510 }
511 else if (streq(argv[i], "memory"))
512 {
513 global.dbtype |= DB_TYPE_MEMORY;
514 if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_memory_max = atol(argv[++i]);
515 }
516 else if (streq(argv[i], "mini"))
517 {
518 global.dbtype |= DB_TYPE_MINI;
519 if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_mini_max = atol(argv[++i]);
520 }
521 }
522 }
523 else if (streq(argv[i], "-m"))
524 {
525 if ((i + 1) < argc) global.mark_time = 60 * atoll(argv[++i]);
526 }
527 else if (streq(argv[i], "-utmp_ttl"))
528 {
529 if ((i + 1) < argc) global.utmp_ttl = atol(argv[++i]);
530 }
531 else if (streq(argv[i], "-mps_limit"))
532 {
533 if ((i + 1) < argc) global.mps_limit = atol(argv[++i]);
534 }
535 else if (streq(argv[i], "-dup_delay"))
536 {
537 if ((i + 1) < argc) global.bsd_max_dup_time = atoll(argv[++i]);
538 }
539 else if (streq(argv[i], "-klog_in"))
540 {
541 if ((i + 1) < argc) activate_klog_in = atoi(argv[++i]);
542 }
543 else if (streq(argv[i], "-bsd_in"))
544 {
545 if ((i + 1) < argc) activate_bsd_in = atoi(argv[++i]);
546 }
547 else if (streq(argv[i], "-udp_in"))
548 {
549 if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]);
550 }
551 else if (streq(argv[i], "-bsd_out"))
552 {
553 if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]);
554 }
555 else if (streq(argv[i], "-remote"))
556 {
557 if ((i + 1) < argc) remote_enabled = atoi(argv[++i]);
558 }
559 }
560
561 if (global.dbtype == 0)
562 {
563 global.dbtype = DB_TYPE_FILE;
564 global.db_file_max = 25600000;
565 }
566
567 signal(SIGHUP, SIG_IGN);
568
569 writepid(&first_syslogd_start);
570
571 /*
572 * Log UTMPX boot time record
573 */
574 write_boot_log(first_syslogd_start);
575
576 asldebug("reading launch plist\n");
577 launch_config();
578
579 asldebug("initializing modules\n");
580 init_modules();
581 dispatch_resume(global.work_queue);
582
583 /* network change notification resets UDP and BSD modules */
584 notify_register_dispatch(kNotifySCNetworkChange, &network_change_token, global.work_queue, ^(int x){
585 if (activate_udp_in != 0) udp_in_reset();
586 if (activate_bsd_out != 0) bsd_out_reset();
587 });
588
589 /* SIGHUP resets all modules */
590 global.sig_hup_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGHUP, 0, dispatch_get_main_queue());
591 dispatch_source_set_event_handler(global.sig_hup_src, ^{
592 dispatch_async(global.work_queue, ^{
593 int i;
594
595 asldebug("SIGHUP reset\n");
596 for (i = 0; i < global.module_count; i++)
597 {
598 if (global.module[i]->enabled != 0) global.module[i]->reset();
599 }
600 });
601 });
602
603 dispatch_resume(global.sig_hup_src);
604
605 /* register for DB notification (posted by dbserver) for performance */
606 notify_register_plain(kNotifyASLDBUpdate, &asl_db_token);
607
608 /* timer for MARK facility */
609 if (global.mark_time > 0)
610 {
611 global.mark_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
612 dispatch_source_set_event_handler(global.mark_timer, ^{
613 asl_mark();
614 });
615 dispatch_source_set_timer(global.mark_timer, dispatch_walltime(NULL, global.mark_time * NSEC_PER_SEC), global.mark_time * NSEC_PER_SEC, 0);
616 dispatch_resume(global.mark_timer);
617 }
618
619 /*
620 * Start launchd service
621 * This pins a thread in _vprocmgr_log_drain. Eventually we will either
622 * remove the whole stderr/stdout -> ASL mechanism entirely, or come up
623 * with a communication channel that we can trigger with a dispatch source.
624 */
625 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
626 forever _vprocmgr_log_drain(NULL, NULL, launchd_callback);
627 });
628
629 /*
630 * Start mach server
631 * Parks a thread in database_server. In notifyd, we found that the overhead of
632 * a dispatch source for mach calls was too high, especially on iOS.
633 */
634 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
635 database_server();
636 });
637
638 dispatch_main();
639
640 /* NOTREACHED */
641 return 0;
642 }