2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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>
37 #include <sys/fcntl.h>
38 #include <sys/errno.h>
39 #include <sys/queue.h>
47 #include <notify_keys.h>
49 #include <vproc_priv.h>
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
58 #define BILLION 1000000000
60 #define NOTIFY_DELAY 1
62 #define streq(A,B) (strcmp(A,B)==0)
63 #define forever for(;;)
65 extern int __notify_78945668_info__
;
66 extern int _malloc_no_asl_log
;
69 struct global_s global
;
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;
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;
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;
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;
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;
98 /* Interactive Module */
99 int remote_init(void);
100 int remote_reset(void);
101 int remote_close(void);
102 static int remote_enabled
= 0;
104 extern void database_server();
109 module_t
*m_klog_in
, *m_bsd_in
, *m_bsd_out
, *m_udp_in
;
110 module_t
*m_asl
, *m_remote
;
112 /* ASL module (configured by /etc/asl.conf) */
113 m_asl
= (module_t
*)calloc(1, sizeof(module_t
));
116 asldebug("alloc failed (init_modules asl_action)\n");
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
;
126 if (m_asl
->enabled
) m_asl
->init();
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
)
132 asldebug("alloc failed (init_modules bsd_out)\n");
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
;
142 if (m_bsd_out
->enabled
)
145 global
.bsd_out_enabled
= 1;
148 /* kernel input module */
149 m_klog_in
= (module_t
*)calloc(1, sizeof(module_t
));
150 if (m_klog_in
== NULL
)
152 asldebug("alloc failed (init_modules klog_in)\n");
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
;
162 if (m_klog_in
->enabled
) m_klog_in
->init();
164 /* BSD (UNIX domain socket) input module */
165 m_bsd_in
= (module_t
*)calloc(1, sizeof(module_t
));
166 if (m_bsd_in
== NULL
)
168 asldebug("alloc failed (init_modules bsd_in)\n");
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
;
178 if (m_bsd_in
->enabled
) m_bsd_in
->init();
180 /* network (syslog protocol) input module */
181 m_udp_in
= (module_t
*)calloc(1, sizeof(module_t
));
182 if (m_udp_in
== NULL
)
184 asldebug("alloc failed (init_modules udp_in)\n");
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
;
194 if (m_udp_in
->enabled
) m_udp_in
->init();
196 /* remote (iOS support) module */
197 m_remote
= (module_t
*)calloc(1, sizeof(module_t
));
198 if (m_remote
== NULL
)
200 asldebug("alloc failed (init_modules remote)\n");
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
;
210 if (m_remote
->enabled
) m_remote
->init();
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
)
217 asldebug("alloc failed (init_modules)\n");
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
;
234 pid_t pid
= getpid();
236 asldebug("\nsyslogd %d start\n", pid
);
241 memset(&sb
, 0, sizeof(struct stat
));
242 if (stat(_PATH_PIDFILE
, &sb
) == 0)
244 if (S_ISREG(sb
.st_mode
)) *first
= 0;
248 fp
= fopen(_PATH_PIDFILE
, "w");
251 fprintf(fp
, "%d\n", pid
);
259 launch_data_t tmp
, pdict
;
260 kern_return_t status
;
262 tmp
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
263 global
.launch_dict
= launch_msg(tmp
);
264 launch_data_free(tmp
);
266 if (global
.launch_dict
== NULL
)
268 asldebug("%d launchd checkin failed\n", getpid());
272 tmp
= launch_data_dict_lookup(global
.launch_dict
, LAUNCH_JOBKEY_MACHSERVICES
);
275 asldebug("%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid());
279 pdict
= launch_data_dict_lookup(tmp
, SERVICE_NAME
);
282 asldebug("%d launchd lookup of SERVICE_NAME failed\n", getpid());
286 global
.server_port
= launch_data_get_machport(pdict
);
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
)
292 asldebug("mach_port_allocate dead_session_port failed: %d", status
);
296 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &(global
.listen_set
));
297 if (status
!= KERN_SUCCESS
)
299 asldebug("mach_port_allocate listen_set failed: %d", status
);
303 status
= mach_port_move_member(mach_task_self(), global
.server_port
, global
.listen_set
);
304 if (status
!= KERN_SUCCESS
)
306 asldebug("mach_port_move_member server_port failed: %d", status
);
310 status
= mach_port_move_member(mach_task_self(), global
.dead_session_port
, global
.listen_set
);
311 if (status
!= KERN_SUCCESS
)
313 asldebug("mach_port_move_member dead_session_port failed (%u)", status
);
319 config_debug(int enable
, const char *path
)
321 OSSpinLockLock(&global
.lock
);
323 global
.debug
= enable
;
324 free(global
.debug_file
);
325 global
.debug_file
= NULL
;
326 if (path
!= NULL
) global
.debug_file
= strdup(path
);
328 OSSpinLockUnlock(&global
.lock
);
332 config_data_store(int type
, uint32_t file_max
, uint32_t memory_max
, uint32_t mini_max
)
334 pthread_mutex_lock(global
.db_lock
);
336 if (global
.dbtype
& DB_TYPE_FILE
)
338 asl_store_close(global
.file_db
);
339 global
.file_db
= NULL
;
342 if (global
.dbtype
& DB_TYPE_MEMORY
)
344 asl_memory_close(global
.memory_db
);
345 global
.memory_db
= NULL
;
348 if (global
.dbtype
& DB_TYPE_MINI
)
350 asl_mini_memory_close(global
.mini_db
);
351 global
.mini_db
= NULL
;
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
;
359 pthread_mutex_unlock(global
.db_lock
);
363 write_boot_log(int first
)
365 int mib
[2] = {CTL_KERN
, KERN_BOOTTIME
};
373 /* syslogd restart */
374 msg
= asl_new(ASL_TYPE_MSG
);
375 if (msg
== NULL
) return;
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
); });
389 bzero(&utx
, sizeof(utx
));
390 utx
.ut_type
= BOOT_TIME
;
393 /* get the boot time */
394 len
= sizeof(struct timeval
);
395 if (sysctl(mib
, 2, &utx
.ut_tv
, &len
, NULL
, 0) < 0)
397 gettimeofday(&utx
.ut_tv
, NULL
);
402 msg
= asl_new(ASL_TYPE_MSG
);
403 if (msg
== NULL
) return;
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
);
424 dispatch_async(global
.work_queue
, ^{ process_message(msg
, SOURCE_INTERNAL
); });
428 main(int argc
, const char *argv
[])
431 int network_change_token
, asl_db_token
;
434 int first_syslogd_start
= 1;
437 setiopolicy_np(IOPOL_TYPE_DISK
, IOPOL_SCOPE_PROCESS
, IOPOL_PASSIVE
);
439 memset(&global
, 0, sizeof(struct global_s
));
441 global
.db_lock
= (pthread_mutex_t
*)calloc(1, sizeof(pthread_mutex_t
));
442 pthread_mutex_init(global
.db_lock
, NULL
);
445 * Create work queue, but suspend until output modules are initialized.
447 global
.work_queue
= dispatch_queue_create("Work Queue", NULL
);
448 dispatch_suspend(global
.work_queue
);
450 global
.lockdown_session_fd
= -1;
456 activate_bsd_out
= 0;
459 /* prevent malloc from calling ASL on error */
460 _malloc_no_asl_log
= 1;
462 /* first pass sets up default configurations */
463 for (i
= 1; i
< argc
; i
++)
465 if (streq(argv
[i
], "-config"))
467 if (((i
+ 1) < argc
) && (argv
[i
+1][0] != '-'))
470 if (streq(argv
[i
], "mac"))
472 global
.dbtype
= DB_TYPE_FILE
;
473 global
.db_file_max
= 25600000;
475 else if (streq(argv
[i
], "appletv"))
477 global
.dbtype
= DB_TYPE_FILE
;
478 global
.db_file_max
= 10240000;
480 else if (streq(argv
[i
], "iphone"))
482 global
.dbtype
= DB_TYPE_MINI
;
489 for (i
= 1; i
< argc
; i
++)
491 if (streq(argv
[i
], "-d"))
494 if (((i
+1) < argc
) && (argv
[i
+1][0] != '-')) global
.debug_file
= strdup(argv
[++i
]);
495 memset(tstr
, 0, sizeof(tstr
));
499 asldebug("%s syslogd[%d]: Start\n", tstr
, getpid());
501 else if (streq(argv
[i
], "-db"))
503 if (((i
+ 1) < argc
) && (argv
[i
+1][0] != '-'))
506 if (streq(argv
[i
], "file"))
508 global
.dbtype
|= DB_TYPE_FILE
;
509 if (((i
+ 1) < argc
) && (argv
[i
+1][0] != '-')) global
.db_file_max
= atol(argv
[++i
]);
511 else if (streq(argv
[i
], "memory"))
513 global
.dbtype
|= DB_TYPE_MEMORY
;
514 if (((i
+ 1) < argc
) && (argv
[i
+1][0] != '-')) global
.db_memory_max
= atol(argv
[++i
]);
516 else if (streq(argv
[i
], "mini"))
518 global
.dbtype
|= DB_TYPE_MINI
;
519 if (((i
+ 1) < argc
) && (argv
[i
+1][0] != '-')) global
.db_mini_max
= atol(argv
[++i
]);
523 else if (streq(argv
[i
], "-m"))
525 if ((i
+ 1) < argc
) global
.mark_time
= 60 * atoll(argv
[++i
]);
527 else if (streq(argv
[i
], "-utmp_ttl"))
529 if ((i
+ 1) < argc
) global
.utmp_ttl
= atol(argv
[++i
]);
531 else if (streq(argv
[i
], "-mps_limit"))
533 if ((i
+ 1) < argc
) global
.mps_limit
= atol(argv
[++i
]);
535 else if (streq(argv
[i
], "-dup_delay"))
537 if ((i
+ 1) < argc
) global
.bsd_max_dup_time
= atoll(argv
[++i
]);
539 else if (streq(argv
[i
], "-klog_in"))
541 if ((i
+ 1) < argc
) activate_klog_in
= atoi(argv
[++i
]);
543 else if (streq(argv
[i
], "-bsd_in"))
545 if ((i
+ 1) < argc
) activate_bsd_in
= atoi(argv
[++i
]);
547 else if (streq(argv
[i
], "-udp_in"))
549 if ((i
+ 1) < argc
) activate_udp_in
= atoi(argv
[++i
]);
551 else if (streq(argv
[i
], "-bsd_out"))
553 if ((i
+ 1) < argc
) activate_bsd_out
= atoi(argv
[++i
]);
555 else if (streq(argv
[i
], "-remote"))
557 if ((i
+ 1) < argc
) remote_enabled
= atoi(argv
[++i
]);
561 if (global
.dbtype
== 0)
563 global
.dbtype
= DB_TYPE_FILE
;
564 global
.db_file_max
= 25600000;
567 signal(SIGHUP
, SIG_IGN
);
569 writepid(&first_syslogd_start
);
572 * Log UTMPX boot time record
574 write_boot_log(first_syslogd_start
);
576 asldebug("reading launch plist\n");
579 asldebug("initializing modules\n");
581 dispatch_resume(global
.work_queue
);
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();
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
, ^{
595 asldebug("SIGHUP reset\n");
596 for (i
= 0; i
< global
.module_count
; i
++)
598 if (global
.module[i
]->enabled
!= 0) global
.module[i
]->reset();
603 dispatch_resume(global
.sig_hup_src
);
605 /* register for DB notification (posted by dbserver) for performance */
606 notify_register_plain(kNotifyASLDBUpdate
, &asl_db_token
);
608 /* timer for MARK facility */
609 if (global
.mark_time
> 0)
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
, ^{
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
);
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.
625 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
626 forever
_vprocmgr_log_drain(NULL
, NULL
, launchd_callback
);
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.
634 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{