]> git.saurik.com Git - apple/launchd.git/blame - launchd/src/launchd.c
launchd-329.3.tar.gz
[apple/launchd.git] / launchd / src / launchd.c
CommitLineData
e91b9f68
A
1/*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
ed34e3c3 4 * @APPLE_APACHE_LICENSE_HEADER_START@
e91b9f68 5 *
ed34e3c3
A
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
e91b9f68 9 *
ed34e3c3
A
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
e91b9f68
A
16 * limitations under the License.
17 *
ed34e3c3 18 * @APPLE_APACHE_LICENSE_HEADER_END@
e91b9f68 19 */
ed34e3c3 20
ddbbfbc1 21static const char *const __rcs_file_version__ = "$Revision: 23925 $";
5b0a4722
A
22
23#include "config.h"
24#include "launchd.h"
ed34e3c3 25
f36da725 26#if HAVE_SECURITY
e91b9f68
A
27#include <Security/Authorization.h>
28#include <Security/AuthorizationTags.h>
29#include <Security/AuthSession.h>
f36da725 30#endif
e91b9f68
A
31#include <sys/types.h>
32#include <sys/queue.h>
33#include <sys/event.h>
34#include <sys/stat.h>
35#include <sys/ucred.h>
36#include <sys/fcntl.h>
37#include <sys/un.h>
38#include <sys/wait.h>
39#include <sys/sysctl.h>
40#include <sys/sockio.h>
41#include <sys/time.h>
42#include <sys/resource.h>
43#include <sys/ioctl.h>
44#include <sys/mount.h>
ed34e3c3 45#include <sys/kern_event.h>
5b0a4722 46#include <sys/reboot.h>
ddbbfbc1
A
47#include <sys/socket.h>
48#include <sys/syscall.h>
e91b9f68
A
49#include <net/if.h>
50#include <netinet/in.h>
51#include <netinet/in_var.h>
52#include <netinet6/nd6.h>
ed34e3c3 53#include <ifaddrs.h>
e91b9f68
A
54#include <unistd.h>
55#include <signal.h>
56#include <errno.h>
e91b9f68
A
57#include <libgen.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <stdarg.h>
61#include <stdbool.h>
e91b9f68
A
62#include <paths.h>
63#include <pwd.h>
64#include <grp.h>
ed34e3c3 65#include <ttyent.h>
e91b9f68
A
66#include <dlfcn.h>
67#include <dirent.h>
ed34e3c3 68#include <string.h>
5b0a4722
A
69#include <setjmp.h>
70#include <spawn.h>
71#include <sched.h>
ef398931 72#include <pthread.h>
ddbbfbc1
A
73#include <util.h>
74
75#if HAVE_LIBAUDITD
76#include <bsm/auditd_lib.h>
ef398931 77#endif
e91b9f68 78
ef398931
A
79#include "bootstrap.h"
80#include "vproc.h"
ddbbfbc1 81#include "vproc_priv.h"
ef398931
A
82#include "vproc_internal.h"
83#include "launch.h"
ddbbfbc1 84#include "launch_internal.h"
5b0a4722
A
85
86#include "launchd_runtime.h"
ed34e3c3
A
87#include "launchd_core_logic.h"
88#include "launchd_unix_ipc.h"
89
e91b9f68 90#define LAUNCHD_CONF ".launchd.conf"
e91b9f68 91#define SECURITY_LIB "/System/Library/Frameworks/Security.framework/Versions/A/Security"
e91b9f68
A
92
93extern char **environ;
94
ed34e3c3 95static void pfsystem_callback(void *, struct kevent *);
e91b9f68 96
ed34e3c3
A
97static kq_callback kqpfsystem_callback = pfsystem_callback;
98
5b0a4722 99static void pid1_magic_init(void);
e91b9f68 100
aa59983a 101static void testfd_or_openfd(int fd, const char *path, int flags);
ed34e3c3
A
102static bool get_network_state(void);
103static void monitor_networking_state(void);
5b0a4722
A
104static void fatal_signal_handler(int sig, siginfo_t *si, void *uap);
105static void handle_pid1_crashes_separately(void);
ddbbfbc1
A
106static void do_pid1_crash_diagnosis_mode(void);
107static int basic_fork(void);
108static bool do_pid1_crash_diagnosis_mode2(void);
ed34e3c3 109
ef398931 110static void *update_thread(void *nothing);
ef398931 111
ddbbfbc1 112static bool re_exec_in_single_user_mode;
5b0a4722
A
113static void *crash_addr;
114static pid_t crash_pid;
ed34e3c3 115
ddbbfbc1
A
116bool shutdown_in_progress;
117bool fake_shutdown_in_progress;
118bool network_up;
119char g_username[128] = "__Uninitialized__";
120char g_my_label[128] = "__Uninitialized__";
121char g_launchd_database_dir[PATH_MAX];
122FILE *g_console = NULL;
123int32_t g_sync_frequency = 30;
e91b9f68 124
ed34e3c3
A
125int
126main(int argc, char *const *argv)
e91b9f68 127{
5b0a4722
A
128 bool sflag = false;
129 int ch;
fc89531e 130
5b0a4722
A
131 testfd_or_openfd(STDIN_FILENO, _PATH_DEVNULL, O_RDONLY);
132 testfd_or_openfd(STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY);
133 testfd_or_openfd(STDERR_FILENO, _PATH_DEVNULL, O_WRONLY);
e91b9f68 134
ddbbfbc1
A
135 if (pid1_magic && g_use_gmalloc) {
136 if (!getenv("DYLD_INSERT_LIBRARIES")) {
137 setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib", 1);
138 setenv("MALLOC_STRICT_SIZE", "1", 1);
139 execv(argv[0], argv);
140 } else {
141 unsetenv("DYLD_INSERT_LIBRARIES");
142 unsetenv("MALLOC_STRICT_SIZE");
143 }
144 }
145
5b0a4722 146 while ((ch = getopt(argc, argv, "s")) != -1) {
e91b9f68 147 switch (ch) {
5b0a4722 148 case 's': sflag = true; break; /* single user */
ed34e3c3 149 case '?': /* we should do something with the global optopt variable here */
e91b9f68 150 default:
5b0a4722 151 fprintf(stderr, "%s: ignoring unknown arguments\n", getprogname());
e91b9f68
A
152 break;
153 }
154 }
e91b9f68 155
5b0a4722
A
156 if (getpid() != 1 && getppid() != 1) {
157 fprintf(stderr, "%s: This program is not meant to be run directly.\n", getprogname());
158 exit(EXIT_FAILURE);
e91b9f68
A
159 }
160
5b0a4722 161 launchd_runtime_init();
e91b9f68 162
ddbbfbc1
A
163 if( pid1_magic ) {
164 int cfd = -1;
165 if( launchd_assumes((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) ) {
166 _fd(cfd);
167 if( !launchd_assumes((g_console = fdopen(cfd, "w")) != NULL) ) {
168 close(cfd);
169 }
170 }
171 }
172
5b0a4722 173 if (NULL == getenv("PATH")) {
ed34e3c3 174 setenv("PATH", _PATH_STDPATH, 1);
5b0a4722 175 }
aa59983a 176
ddbbfbc1 177 if (pid1_magic) {
5b0a4722 178 pid1_magic_init();
ed34e3c3 179 } else {
5b0a4722 180 ipc_server_init();
ddbbfbc1
A
181
182 runtime_log_push();
183
184 struct passwd *pwent = getpwuid(getuid());
185 if( pwent ) {
186 strlcpy(g_username, pwent->pw_name, sizeof(g_username) - 1);
187 }
188
189 snprintf(g_my_label, sizeof(g_my_label), "com.apple.launchd.peruser.%u", getuid());
190
191 auditinfo_addr_t auinfo;
192 if( launchd_assumes(getaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
193 g_audit_session = auinfo.ai_asid;
194 runtime_syslog(LOG_DEBUG, "Our audit session ID is %i", g_audit_session);
195 }
196
197 g_audit_session_port = _audit_session_self();
198 snprintf(g_launchd_database_dir, sizeof(g_launchd_database_dir), LAUNCHD_DB_PREFIX "/com.apple.launchd.peruser.%u", getuid());
199 runtime_syslog(LOG_DEBUG, "Per-user launchd for UID %u (%s) has begun.", getuid(), g_username);
aa59983a
A
200 }
201
ddbbfbc1
A
202 if( pid1_magic ) {
203 runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[1] has started up. ***");
204 if( g_use_gmalloc ) {
205 runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Using libgmalloc ***");
206 }
207
208 if( g_verbose_boot ) {
209 runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***");
210 }
211
212 if( g_shutdown_debugging ) {
213 runtime_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown debugging is enabled. ***");
214 }
215
216 /* PID 1 doesn't have a flat namespace. */
217 g_flat_mach_namespace = false;
ef398931 218 }
ddbbfbc1 219
ed34e3c3 220 monitor_networking_state();
e91b9f68 221
ddbbfbc1 222 if (pid1_magic) {
5b0a4722 223 handle_pid1_crashes_separately();
ddbbfbc1
A
224 } else {
225 #if !TARGET_OS_EMBEDDED
226 /* prime shared memory before the 'bootstrap_port' global is set to zero */
227 _vproc_transaction_begin();
228 _vproc_transaction_end();
229 #endif
e91b9f68
A
230 }
231
ddbbfbc1
A
232 if( pid1_magic ) {
233 /* Start the update thread -- rdar://problem/5039559&6153301 */
234 pthread_t t = NULL;
235 int err = pthread_create(&t, NULL, update_thread, NULL);
236 launchd_assumes(err == 0);
237 launchd_assumes(pthread_detach(t) == 0);
238 }
e91b9f68 239
ddbbfbc1
A
240 jobmgr_init(sflag);
241
5b0a4722 242 launchd_runtime_init2();
e91b9f68 243
5b0a4722 244 launchd_runtime();
e91b9f68 245}
e91b9f68 246
5b0a4722
A
247void
248handle_pid1_crashes_separately(void)
e91b9f68 249{
5b0a4722 250 struct sigaction fsa;
ab36757d 251
5b0a4722
A
252 fsa.sa_sigaction = fatal_signal_handler;
253 fsa.sa_flags = SA_SIGINFO;
254 sigemptyset(&fsa.sa_mask);
e91b9f68 255
5b0a4722
A
256 launchd_assumes(sigaction(SIGILL, &fsa, NULL) != -1);
257 launchd_assumes(sigaction(SIGFPE, &fsa, NULL) != -1);
258 launchd_assumes(sigaction(SIGBUS, &fsa, NULL) != -1);
259 launchd_assumes(sigaction(SIGSEGV, &fsa, NULL) != -1);
e91b9f68
A
260}
261
ddbbfbc1
A
262void *update_thread(void *nothing __attribute__((unused)))
263{
264 while( g_sync_frequency ) {
265 sync();
266 sleep(g_sync_frequency);
267 }
268
269 runtime_syslog(LOG_DEBUG, "Update thread exiting.");
270 return NULL;
271}
272
5b0a4722 273#define PID1_CRASH_LOGFILE "/var/log/launchd-pid1.crash"
e91b9f68 274
5b0a4722
A
275/* This hack forces the dynamic linker to resolve these symbols ASAP */
276static __attribute__((unused)) typeof(sync) *__junk_dyld_trick1 = sync;
277static __attribute__((unused)) typeof(sleep) *__junk_dyld_trick2 = sleep;
278static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot;
ab36757d 279
ddbbfbc1
A
280void
281do_pid1_crash_diagnosis_mode(void)
282{
283 if( g_wsp ) {
284 kill(g_wsp, SIGKILL);
285 sleep(3);
286 g_wsp = 0;
287 }
288
289 while( g_shutdown_debugging && !do_pid1_crash_diagnosis_mode2() ) {
290 sleep(1);
291 }
292}
293
294int
295basic_fork(void)
296{
297 int wstatus = 0;
298 pid_t p;
299
300 switch ((p = fork())) {
301 case -1:
302 runtime_syslog(LOG_ERR | LOG_CONSOLE, "Can't fork PID 1 copy for crash debugging: %m");
303 return p;
304 case 0:
305 return p;
306 default:
307 #if 0
308 /* If we attach with the debugger, the kernel reparenting could
309 * cause this to return prematurely.
310 */
311 waitpid(p, &wstatus, 0);
312 #else
313 sleep(UINT_MAX);
314 #endif
315 if (WIFEXITED(wstatus)) {
316 if (WEXITSTATUS(wstatus) == EXIT_SUCCESS) {
317 return 1;
318 } else {
319 fprintf(stdout, "PID 1 copy: exit status: %d\n", WEXITSTATUS(wstatus));
320 }
321 } else {
322 fprintf(stdout, "PID 1 copy: %s\n", strsignal(WTERMSIG(wstatus)));
323 }
324 return 1;
325 }
326
327 return -1;
328}
329
330bool
331do_pid1_crash_diagnosis_mode2(void)
332{
333 if( basic_fork() == 0 ) {
334 /* Neuter our bootstrap port so that the shell doesn't try talking to us while
335 * we're blocked waiting on it.
336 */
337 if( g_console ) {
338 fflush(g_console);
339 }
340 task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL);
341 if( basic_fork() != 0 ) {
342 if( g_console ) {
343 fflush(g_console);
344 }
345 return true;
346 }
347 } else {
348 return true;
349 }
350
351 int fd;
352 revoke(_PATH_CONSOLE);
353 if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) {
354 _exit(2);
355 }
356 if (login_tty(fd) == -1) {
357 _exit(3);
358 }
359 setenv("TERM", "vt100", 1);
360 fprintf(stdout, "\n");
361 fprintf(stdout, "Entering launchd PID 1 debugging mode...\n");
362 fprintf(stdout, "The PID 1 launchd has crashed. It has fork(2)ed itself for debugging.\n");
363 fprintf(stdout, "To debug the main thread of PID 1:\n");
364 fprintf(stdout, " gdb attach %d\n", getppid());
365 fprintf(stdout, "To exit this shell and shut down:\n");
366 fprintf(stdout, " kill -9 1\n");
367 fprintf(stdout, "A sample of PID 1 has been written to %s\n", PID1_CRASH_LOGFILE);
368 fprintf(stdout, "\n");
369 fflush(stdout);
370
371 execl(_PATH_BSHELL, "-sh", NULL);
372 syslog(LOG_ERR, "can't exec %s for PID 1 crash debugging: %m", _PATH_BSHELL);
373 _exit(EXIT_FAILURE);
374}
375
5b0a4722 376void
ef398931 377fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
5b0a4722
A
378{
379 const char *doom_why = "at instruction";
380 char *sample_args[] = { "/usr/bin/sample", "1", "1", "-file", PID1_CRASH_LOGFILE, NULL };
381 pid_t sample_p;
382 int wstatus;
e91b9f68 383
5b0a4722
A
384 crash_addr = si->si_addr;
385 crash_pid = si->si_pid;
ddbbfbc1 386
5b0a4722 387 unlink(PID1_CRASH_LOGFILE);
e91b9f68 388
5b0a4722
A
389 switch ((sample_p = vfork())) {
390 case 0:
391 execve(sample_args[0], sample_args, environ);
392 _exit(EXIT_FAILURE);
393 break;
394 default:
395 waitpid(sample_p, &wstatus, 0);
396 break;
397 case -1:
398 break;
e91b9f68
A
399 }
400
ddbbfbc1
A
401 do_pid1_crash_diagnosis_mode();
402
5b0a4722
A
403 switch (sig) {
404 default:
405 case 0:
406 break;
407 case SIGBUS:
408 case SIGSEGV:
409 doom_why = "trying to read/write";
410 case SIGILL:
411 case SIGFPE:
412 runtime_syslog(LOG_EMERG, "We crashed %s: %p (sent by PID %u)", doom_why, crash_addr, crash_pid);
413 sync();
414 sleep(3);
415 reboot(0);
416 break;
e91b9f68 417 }
ed34e3c3 418}
e91b9f68 419
ed34e3c3 420void
5b0a4722 421pid1_magic_init(void)
ed34e3c3
A
422{
423 launchd_assumes(setsid() != -1);
424 launchd_assumes(chdir("/") != -1);
425 launchd_assumes(setlogin("root") != -1);
ddbbfbc1
A
426
427 strcpy(g_my_label, "com.apple.launchd");
428
429#if !TARGET_OS_EMBEDDED
430 auditinfo_addr_t auinfo = {
431 .ai_termid = { .at_type = AU_IPv4 },
432 .ai_asid = AU_ASSIGN_ASID,
433 .ai_auid = AU_DEFAUDITID,
434 .ai_flags = sessionIsRoot,
435 };
436
437 if( !launchd_assumes(setaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
438 runtime_syslog(LOG_WARNING | LOG_CONSOLE, "Could not set audit session: %s.", strerror(errno));
439 _exit(EXIT_FAILURE);
440 }
441
442 if( launchd_assumes(getaudit_addr(&auinfo, sizeof(auinfo)) != -1) ) {
443 g_audit_session = auinfo.ai_asid;
444 runtime_syslog(LOG_DEBUG, "Our audit session ID is %i", g_audit_session);
445 }
446
447 g_audit_session_port = _audit_session_self();
448#endif
449
450 strcpy(g_launchd_database_dir, LAUNCHD_DB_PREFIX "/com.apple.launchd");
e91b9f68
A
451}
452
ddbbfbc1
A
453char *
454launchd_data_base_path(int db_type)
455{
456 static char result[PATH_MAX];
457 static int last_db_type = -1;
458
459 if( db_type == last_db_type ) {
460 return result;
461 }
462
463 switch( db_type ) {
464 case LAUNCHD_DB_TYPE_OVERRIDES :
465 snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "overrides.plist");
466 last_db_type = db_type;
467 break;
468 case LAUNCHD_DB_TYPE_JOBCACHE :
469 snprintf(result, sizeof(result), "%s/%s", g_launchd_database_dir, "jobcache.launchdata");
470 last_db_type = db_type;
471 break;
472 default :
473 break;
474 }
475
476 return result;
477}
e91b9f68 478
ed34e3c3
A
479int
480_fd(int fd)
e91b9f68 481{
5b0a4722 482 if (fd >= 0) {
ed34e3c3 483 launchd_assumes(fcntl(fd, F_SETFD, 1) != -1);
5b0a4722 484 }
ed34e3c3
A
485 return fd;
486}
fc89531e 487
ed34e3c3
A
488void
489launchd_shutdown(void)
e91b9f68 490{
ddbbfbc1 491 int64_t now;
5b0a4722
A
492
493 if (shutdown_in_progress) {
494 return;
495 }
ed34e3c3 496
ddbbfbc1
A
497 runtime_ktrace0(RTKT_LAUNCHD_EXITING);
498
5b0a4722 499 shutdown_in_progress = true;
fc89531e 500
ddbbfbc1 501 if( pid1_magic || g_log_per_user_shutdown ) {
5b0a4722
A
502 /*
503 * When this changes to a more sustainable API, update this:
504 * http://howto.apple.com/db.cgi?Debugging_Apps_Non-Responsive_At_Shutdown
505 */
506 runtime_setlogmask(LOG_UPTO(LOG_DEBUG));
5b0a4722 507 }
fc89531e 508
ddbbfbc1
A
509 runtime_log_push();
510
511 now = runtime_get_wall_time();
512
513 char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination for ";
514 runtime_syslog(LOG_INFO, "%s%s began", term_who, pid1_magic ? "" : g_username);
515
5b0a4722 516 launchd_assert(jobmgr_shutdown(root_jobmgr) != NULL);
ddbbfbc1
A
517
518#if HAVE_LIBAUDITD
519 if( pid1_magic ) {
520 launchd_assumes(audit_quick_stop() == 0);
521 }
522#endif
e91b9f68
A
523}
524
ed34e3c3
A
525void
526launchd_single_user(void)
e91b9f68 527{
5b0a4722 528 runtime_syslog(LOG_NOTICE, "Going to single-user mode");
fc89531e 529
ed34e3c3 530 re_exec_in_single_user_mode = true;
e91b9f68 531
5b0a4722 532 launchd_shutdown();
e91b9f68 533
5b0a4722 534 sleep(3);
e91b9f68 535
5b0a4722 536 runtime_kill(-1, SIGKILL);
e91b9f68
A
537}
538
ed34e3c3
A
539void
540launchd_SessionCreate(void)
e91b9f68 541{
f36da725 542#if HAVE_SECURITY
ed34e3c3
A
543 OSStatus (*sescr)(SessionCreationFlags flags, SessionAttributeBits attributes);
544 void *seclib;
e91b9f68 545
ed34e3c3 546 if (launchd_assumes((seclib = dlopen(SECURITY_LIB, RTLD_LAZY)) != NULL)) {
5b0a4722 547 if (launchd_assumes((sescr = dlsym(seclib, "SessionCreate")) != NULL)) {
ed34e3c3 548 launchd_assumes(sescr(0, 0) == noErr);
5b0a4722 549 }
ed34e3c3 550 launchd_assumes(dlclose(seclib) != -1);
e91b9f68 551 }
f36da725 552#endif
e91b9f68
A
553}
554
ed34e3c3
A
555void
556testfd_or_openfd(int fd, const char *path, int flags)
e91b9f68 557{
ed34e3c3 558 int tmpfd;
e91b9f68 559
ed34e3c3 560 if (-1 != (tmpfd = dup(fd))) {
5b0a4722 561 launchd_assumes(runtime_close(tmpfd) == 0);
ed34e3c3 562 } else {
5b0a4722
A
563 if (-1 == (tmpfd = open(path, flags | O_NOCTTY, DEFFILEMODE))) {
564 runtime_syslog(LOG_ERR, "open(\"%s\", ...): %m", path);
ed34e3c3
A
565 } else if (tmpfd != fd) {
566 launchd_assumes(dup2(tmpfd, fd) != -1);
5b0a4722 567 launchd_assumes(runtime_close(tmpfd) == 0);
e91b9f68 568 }
e91b9f68
A
569 }
570}
571
ed34e3c3
A
572bool
573get_network_state(void)
574{
575 struct ifaddrs *ifa, *ifai;
576 bool up = false;
5b0a4722
A
577 int r;
578
579 /* Workaround 4978696: getifaddrs() reports false ENOMEM */
580 while ((r = getifaddrs(&ifa)) == -1 && errno == ENOMEM) {
581 runtime_syslog(LOG_DEBUG, "Worked around bug: 4978696");
582 launchd_assumes(sched_yield() != -1);
583 }
ed34e3c3 584
5b0a4722 585 if (!launchd_assumes(r != -1)) {
ed34e3c3 586 return network_up;
5b0a4722 587 }
ed34e3c3
A
588
589 for (ifai = ifa; ifai; ifai = ifai->ifa_next) {
5b0a4722 590 if (!(ifai->ifa_flags & IFF_UP)) {
ed34e3c3 591 continue;
5b0a4722
A
592 }
593 if (ifai->ifa_flags & IFF_LOOPBACK) {
ed34e3c3 594 continue;
5b0a4722
A
595 }
596 if (ifai->ifa_addr->sa_family != AF_INET && ifai->ifa_addr->sa_family != AF_INET6) {
ed34e3c3 597 continue;
5b0a4722 598 }
ed34e3c3 599 up = true;
e91b9f68
A
600 break;
601 }
ed34e3c3
A
602
603 freeifaddrs(ifa);
604
605 return up;
e91b9f68
A
606}
607
ed34e3c3
A
608void
609monitor_networking_state(void)
e91b9f68 610{
ed34e3c3
A
611 int pfs = _fd(socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT));
612 struct kev_request kev_req;
e91b9f68 613
ed34e3c3 614 network_up = get_network_state();
e91b9f68 615
5b0a4722 616 if (!launchd_assumes(pfs != -1)) {
ed34e3c3 617 return;
5b0a4722 618 }
e91b9f68 619
ed34e3c3
A
620 memset(&kev_req, 0, sizeof(kev_req));
621 kev_req.vendor_code = KEV_VENDOR_APPLE;
622 kev_req.kev_class = KEV_NETWORK_CLASS;
e91b9f68 623
ed34e3c3 624 if (!launchd_assumes(ioctl(pfs, SIOCSKEVFILT, &kev_req) != -1)) {
5b0a4722 625 runtime_close(pfs);
e91b9f68 626 return;
e91b9f68
A
627 }
628
ed34e3c3 629 launchd_assumes(kevent_mod(pfs, EVFILT_READ, EV_ADD, 0, 0, &kqpfsystem_callback) != -1);
e91b9f68
A
630}
631
ed34e3c3 632void
ef398931 633pfsystem_callback(void *obj __attribute__((unused)), struct kevent *kev)
e91b9f68 634{
ed34e3c3
A
635 bool new_networking_state;
636 char buf[1024];
e91b9f68 637
ddbbfbc1 638 launchd_assumes(read((int)kev->ident, &buf, sizeof(buf)) != -1);
e91b9f68 639
ed34e3c3 640 new_networking_state = get_network_state();
e91b9f68 641
ed34e3c3
A
642 if (new_networking_state != network_up) {
643 network_up = new_networking_state;
5b0a4722 644 jobmgr_dispatch_all_semaphores(root_jobmgr);
2a27bb34 645 }
e91b9f68
A
646}
647
6a39f10b 648void
ed34e3c3 649_log_launchd_bug(const char *rcs_rev, const char *path, unsigned int line, const char *test)
6a39f10b 650{
ed34e3c3
A
651 int saved_errno = errno;
652 char buf[100];
653 const char *file = strrchr(path, '/');
654 char *rcs_rev_tmp = strchr(rcs_rev, ' ');
6a39f10b 655
ddbbfbc1
A
656 runtime_ktrace1(RTKT_LAUNCHD_BUG);
657
ed34e3c3
A
658 if (!file) {
659 file = path;
6a39f10b 660 } else {
ed34e3c3 661 file += 1;
e91b9f68 662 }
aa59983a 663
ed34e3c3
A
664 if (!rcs_rev_tmp) {
665 strlcpy(buf, rcs_rev, sizeof(buf));
aa59983a 666 } else {
ed34e3c3
A
667 strlcpy(buf, rcs_rev_tmp + 1, sizeof(buf));
668 rcs_rev_tmp = strchr(buf, ' ');
5b0a4722 669 if (rcs_rev_tmp) {
ed34e3c3 670 *rcs_rev_tmp = '\0';
2a27bb34 671 }
2a27bb34
A
672 }
673
5b0a4722 674 runtime_syslog(LOG_NOTICE, "Bug: %s:%u (%s):%u: %s", file, line, buf, saved_errno, test);
fc89531e 675}