]> git.saurik.com Git - apple/launchd.git/blame - src/launchd.c
launchd-842.92.1.tar.gz
[apple/launchd.git] / 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
5b0a4722
A
21#include "config.h"
22#include "launchd.h"
ed34e3c3 23
e91b9f68
A
24#include <sys/types.h>
25#include <sys/queue.h>
26#include <sys/event.h>
27#include <sys/stat.h>
28#include <sys/ucred.h>
29#include <sys/fcntl.h>
30#include <sys/un.h>
31#include <sys/wait.h>
32#include <sys/sysctl.h>
33#include <sys/sockio.h>
34#include <sys/time.h>
35#include <sys/resource.h>
36#include <sys/ioctl.h>
37#include <sys/mount.h>
ed34e3c3 38#include <sys/kern_event.h>
5b0a4722 39#include <sys/reboot.h>
ddbbfbc1
A
40#include <sys/socket.h>
41#include <sys/syscall.h>
e91b9f68
A
42#include <net/if.h>
43#include <netinet/in.h>
44#include <netinet/in_var.h>
45#include <netinet6/nd6.h>
ed34e3c3 46#include <ifaddrs.h>
e91b9f68
A
47#include <unistd.h>
48#include <signal.h>
49#include <errno.h>
e91b9f68
A
50#include <libgen.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <stdarg.h>
54#include <stdbool.h>
e91b9f68
A
55#include <paths.h>
56#include <pwd.h>
57#include <grp.h>
ed34e3c3 58#include <ttyent.h>
e91b9f68
A
59#include <dlfcn.h>
60#include <dirent.h>
ed34e3c3 61#include <string.h>
5b0a4722
A
62#include <setjmp.h>
63#include <spawn.h>
64#include <sched.h>
ef398931 65#include <pthread.h>
ddbbfbc1 66#include <util.h>
95379394 67#include <os/assumes.h>
ddbbfbc1
A
68
69#if HAVE_LIBAUDITD
70#include <bsm/auditd_lib.h>
dcace88f 71#include <bsm/audit_session.h>
ef398931 72#endif
e91b9f68 73
ef398931
A
74#include "bootstrap.h"
75#include "vproc.h"
ddbbfbc1 76#include "vproc_priv.h"
ef398931
A
77#include "vproc_internal.h"
78#include "launch.h"
ddbbfbc1 79#include "launch_internal.h"
5b0a4722 80
eabd1701
A
81#include "runtime.h"
82#include "core.h"
83#include "ipc.h"
ed34e3c3 84
e91b9f68 85#define LAUNCHD_CONF ".launchd.conf"
e91b9f68
A
86
87extern char **environ;
88
ed34e3c3 89static void pfsystem_callback(void *, struct kevent *);
e91b9f68 90
ed34e3c3
A
91static kq_callback kqpfsystem_callback = pfsystem_callback;
92
5b0a4722 93static void pid1_magic_init(void);
e91b9f68 94
aa59983a 95static void testfd_or_openfd(int fd, const char *path, int flags);
ed34e3c3
A
96static bool get_network_state(void);
97static void monitor_networking_state(void);
5b0a4722
A
98static void fatal_signal_handler(int sig, siginfo_t *si, void *uap);
99static void handle_pid1_crashes_separately(void);
dcace88f 100static void do_pid1_crash_diagnosis_mode(const char *msg);
ddbbfbc1 101static int basic_fork(void);
dcace88f 102static bool do_pid1_crash_diagnosis_mode2(const char *msg);
ed34e3c3 103
ef398931 104static void *update_thread(void *nothing);
ef398931 105
5b0a4722
A
106static void *crash_addr;
107static pid_t crash_pid;
ed34e3c3 108
eabd1701
A
109char *_launchd_database_dir;
110char *_launchd_log_dir;
111
112bool launchd_shutting_down;
ddbbfbc1 113bool network_up;
eabd1701
A
114uid_t launchd_uid;
115FILE *launchd_console = NULL;
116int32_t launchd_sync_frequency = 30;
e91b9f68 117
ed34e3c3
A
118int
119main(int argc, char *const *argv)
e91b9f68 120{
5b0a4722
A
121 bool sflag = false;
122 int ch;
fc89531e 123
eabd1701
A
124 /* This needs to be cleaned up. Currently, we risk tripping assumes() macros
125 * before we've properly set things like launchd's log database paths, the
126 * global launchd label for syslog messages and the like. Luckily, these are
127 * operations that will probably never fail, like test_of_openfd(), the
128 * stuff in launchd_runtime_init() and the stuff in
129 * handle_pid1_crashes_separately().
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
eabd1701 135 if (launchd_use_gmalloc) {
ddbbfbc1
A
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 }
eabd1701 144 } else if (launchd_malloc_log_stacks) {
dcace88f
A
145 if (!getenv("MallocStackLogging")) {
146 setenv("MallocStackLogging", "1", 1);
147 execv(argv[0], argv);
148 } else {
149 unsetenv("MallocStackLogging");
150 }
ddbbfbc1
A
151 }
152
5b0a4722 153 while ((ch = getopt(argc, argv, "s")) != -1) {
e91b9f68 154 switch (ch) {
5b0a4722 155 case 's': sflag = true; break; /* single user */
ed34e3c3 156 case '?': /* we should do something with the global optopt variable here */
e91b9f68 157 default:
5b0a4722 158 fprintf(stderr, "%s: ignoring unknown arguments\n", getprogname());
e91b9f68
A
159 break;
160 }
161 }
e91b9f68 162
5b0a4722
A
163 if (getpid() != 1 && getppid() != 1) {
164 fprintf(stderr, "%s: This program is not meant to be run directly.\n", getprogname());
165 exit(EXIT_FAILURE);
e91b9f68
A
166 }
167
5b0a4722 168 launchd_runtime_init();
e91b9f68 169
eabd1701
A
170 if (NULL == getenv("PATH")) {
171 setenv("PATH", _PATH_STDPATH, 1);
172 }
173
dcace88f 174 if (pid1_magic) {
eabd1701
A
175 pid1_magic_init();
176
ddbbfbc1 177 int cfd = -1;
eabd1701 178 if ((cfd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) != -1) {
ddbbfbc1 179 _fd(cfd);
eabd1701
A
180 if (!(launchd_console = fdopen(cfd, "w"))) {
181 (void)close(cfd);
ddbbfbc1
A
182 }
183 }
ddbbfbc1 184
eabd1701
A
185 char *extra = "";
186 if (launchd_osinstaller) {
187 extra = " in the OS Installer";
188 } else if (sflag) {
189 extra = " in single-user mode";
190 }
aa59983a 191
eabd1701
A
192 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** launchd[1] has started up%s. ***", extra);
193 if (launchd_use_gmalloc) {
194 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Using libgmalloc. ***");
ddbbfbc1
A
195 }
196
eabd1701
A
197 if (launchd_verbose_boot) {
198 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Verbose boot, will log to /dev/console. ***");
ddbbfbc1 199 }
aa59983a 200
eabd1701
A
201 if (launchd_shutdown_debugging) {
202 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown debugging is enabled. ***");
dcace88f 203 }
eabd1701
A
204
205 if (launchd_log_shutdown) {
206 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Shutdown logging is enabled. ***");
ddbbfbc1
A
207 }
208
eabd1701
A
209 if (launchd_log_perf) {
210 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Performance logging is enabled. ***");
ddbbfbc1
A
211 }
212
eabd1701
A
213 if (launchd_log_debug) {
214 launchd_syslog(LOG_NOTICE | LOG_CONSOLE, "*** Debug logging is enabled. ***");
ddbbfbc1
A
215 }
216
eabd1701
A
217 handle_pid1_crashes_separately();
218
219 /* Start the update thread.
220 *
221 * <rdar://problem/5039559&6153301>
222 */
223 pthread_t t = NULL;
95379394
A
224 (void)os_assumes_zero(pthread_create(&t, NULL, update_thread, NULL));
225 (void)os_assumes_zero(pthread_detach(t));
eabd1701 226
ddbbfbc1 227 /* PID 1 doesn't have a flat namespace. */
eabd1701
A
228 launchd_flat_mach_namespace = false;
229 fflush(launchd_console);
dcace88f 230 } else {
eabd1701
A
231 launchd_uid = getuid();
232 launchd_var_available = true;
233 if (asprintf(&launchd_label, "com.apple.launchd.peruser.%u", launchd_uid) == 0) {
234 launchd_label = "com.apple.launchd.peruser.unknown";
dcace88f 235 }
ddbbfbc1 236
eabd1701
A
237 struct passwd *pwent = getpwuid(launchd_uid);
238 if (pwent) {
239 launchd_username = strdup(pwent->pw_name);
240 } else {
241 launchd_username = "(unknown)";
242 }
e91b9f68 243
eabd1701
A
244 if (asprintf(&_launchd_database_dir, LAUNCHD_DB_PREFIX "/com.apple.launchd.peruser.%u", launchd_uid) == 0) {
245 _launchd_database_dir = "";
246 }
e91b9f68 247
eabd1701
A
248 if (asprintf(&_launchd_log_dir, LAUNCHD_LOG_PREFIX "/com.apple.launchd.peruser.%u", launchd_uid) == 0) {
249 _launchd_log_dir = "";
250 }
251
252 if (launchd_allow_global_dyld_envvars) {
253 launchd_syslog(LOG_WARNING, "Per-user launchd will allow DYLD_* environment variables in the global environment.");
254 }
255
256 ipc_server_init();
257 launchd_log_push();
258
259 auditinfo_addr_t auinfo;
260 if (posix_assumes_zero(getaudit_addr(&auinfo, sizeof(auinfo))) != -1) {
261 launchd_audit_session = auinfo.ai_asid;
262 launchd_syslog(LOG_DEBUG, "Our audit session ID is %i", launchd_audit_session);
263 }
264
265 launchd_audit_port = _audit_session_self();
266
267 vproc_transaction_begin(NULL);
268 vproc_transaction_end(NULL, NULL);
269
270 launchd_syslog(LOG_DEBUG, "Per-user launchd started (UID/username): %u/%s.", launchd_uid, launchd_username);
ddbbfbc1 271 }
e91b9f68 272
eabd1701 273 monitor_networking_state();
ddbbfbc1 274 jobmgr_init(sflag);
e91b9f68 275
eabd1701 276 launchd_runtime_init2();
5b0a4722 277 launchd_runtime();
e91b9f68 278}
e91b9f68 279
5b0a4722
A
280void
281handle_pid1_crashes_separately(void)
e91b9f68 282{
5b0a4722 283 struct sigaction fsa;
ab36757d 284
5b0a4722
A
285 fsa.sa_sigaction = fatal_signal_handler;
286 fsa.sa_flags = SA_SIGINFO;
287 sigemptyset(&fsa.sa_mask);
e91b9f68 288
eabd1701
A
289 (void)posix_assumes_zero(sigaction(SIGILL, &fsa, NULL));
290 (void)posix_assumes_zero(sigaction(SIGFPE, &fsa, NULL));
291 (void)posix_assumes_zero(sigaction(SIGBUS, &fsa, NULL));
292 (void)posix_assumes_zero(sigaction(SIGTRAP, &fsa, NULL));
293 (void)posix_assumes_zero(sigaction(SIGABRT, &fsa, NULL));
294 (void)posix_assumes_zero(sigaction(SIGSEGV, &fsa, NULL));
e91b9f68
A
295}
296
eabd1701
A
297void *
298update_thread(void *nothing __attribute__((unused)))
ddbbfbc1 299{
eabd1701
A
300 (void)posix_assumes_zero(setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, IOPOL_THROTTLE));
301
302 while (launchd_sync_frequency) {
ddbbfbc1 303 sync();
eabd1701 304 sleep(launchd_sync_frequency);
ddbbfbc1 305 }
eabd1701
A
306
307 launchd_syslog(LOG_DEBUG, "Update thread exiting.");
ddbbfbc1
A
308 return NULL;
309}
310
5b0a4722 311#define PID1_CRASH_LOGFILE "/var/log/launchd-pid1.crash"
e91b9f68 312
5b0a4722
A
313/* This hack forces the dynamic linker to resolve these symbols ASAP */
314static __attribute__((unused)) typeof(sync) *__junk_dyld_trick1 = sync;
315static __attribute__((unused)) typeof(sleep) *__junk_dyld_trick2 = sleep;
316static __attribute__((unused)) typeof(reboot) *__junk_dyld_trick3 = reboot;
ab36757d 317
ddbbfbc1 318void
dcace88f 319do_pid1_crash_diagnosis_mode(const char *msg)
ddbbfbc1 320{
eabd1701
A
321 if (launchd_wsp) {
322 kill(launchd_wsp, SIGKILL);
ddbbfbc1 323 sleep(3);
eabd1701 324 launchd_wsp = 0;
ddbbfbc1
A
325 }
326
eabd1701 327 while (launchd_shutdown_debugging && !do_pid1_crash_diagnosis_mode2(msg)) {
ddbbfbc1
A
328 sleep(1);
329 }
330}
331
332int
333basic_fork(void)
334{
335 int wstatus = 0;
336 pid_t p;
eabd1701 337
ddbbfbc1 338 switch ((p = fork())) {
dcace88f 339 case -1:
eabd1701 340 launchd_syslog(LOG_ERR | LOG_CONSOLE, "Can't fork PID 1 copy for crash debugging: %m");
dcace88f
A
341 return p;
342 case 0:
343 return p;
344 default:
345 do {
346 (void)waitpid(p, &wstatus, 0);
347 } while(!WIFEXITED(wstatus));
348
349 fprintf(stdout, "PID 1 copy: exit status: %d\n", WEXITSTATUS(wstatus));
350
351 return 1;
ddbbfbc1 352 }
eabd1701 353
ddbbfbc1
A
354 return -1;
355}
356
357bool
dcace88f 358do_pid1_crash_diagnosis_mode2(const char *msg)
ddbbfbc1 359{
dcace88f 360 if (basic_fork() == 0) {
eabd1701
A
361 /* Neuter our bootstrap port so that the shell doesn't try talking to us
362 * while we're blocked waiting on it.
ddbbfbc1 363 */
eabd1701
A
364 if (launchd_console) {
365 fflush(launchd_console);
ddbbfbc1 366 }
eabd1701 367
ddbbfbc1 368 task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL);
dcace88f 369 if (basic_fork() != 0) {
eabd1701
A
370 if (launchd_console) {
371 fflush(launchd_console);
ddbbfbc1 372 }
eabd1701 373
ddbbfbc1
A
374 return true;
375 }
376 } else {
377 return true;
378 }
eabd1701 379
ddbbfbc1
A
380 int fd;
381 revoke(_PATH_CONSOLE);
382 if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) {
383 _exit(2);
384 }
385 if (login_tty(fd) == -1) {
386 _exit(3);
387 }
eabd1701 388
ddbbfbc1
A
389 setenv("TERM", "vt100", 1);
390 fprintf(stdout, "\n");
391 fprintf(stdout, "Entering launchd PID 1 debugging mode...\n");
dcace88f
A
392 fprintf(stdout, "The PID 1 launchd has crashed %s.\n", msg);
393 fprintf(stdout, "It has fork(2)ed itself for debugging.\n");
394 fprintf(stdout, "To debug the crashing thread of PID 1:\n");
ddbbfbc1
A
395 fprintf(stdout, " gdb attach %d\n", getppid());
396 fprintf(stdout, "To exit this shell and shut down:\n");
397 fprintf(stdout, " kill -9 1\n");
398 fprintf(stdout, "A sample of PID 1 has been written to %s\n", PID1_CRASH_LOGFILE);
399 fprintf(stdout, "\n");
400 fflush(stdout);
eabd1701 401
ddbbfbc1
A
402 execl(_PATH_BSHELL, "-sh", NULL);
403 syslog(LOG_ERR, "can't exec %s for PID 1 crash debugging: %m", _PATH_BSHELL);
404 _exit(EXIT_FAILURE);
405}
406
5b0a4722 407void
ef398931 408fatal_signal_handler(int sig, siginfo_t *si, void *uap __attribute__((unused)))
5b0a4722
A
409{
410 const char *doom_why = "at instruction";
dcace88f 411 char msg[128];
95379394 412#if 0
5b0a4722
A
413 char *sample_args[] = { "/usr/bin/sample", "1", "1", "-file", PID1_CRASH_LOGFILE, NULL };
414 pid_t sample_p;
415 int wstatus;
95379394 416#endif
e91b9f68 417
5b0a4722
A
418 crash_addr = si->si_addr;
419 crash_pid = si->si_pid;
95379394 420#if 0
eabd1701 421 setenv("XPC_SERVICES_UNAVAILABLE", "1", 0);
5b0a4722 422 unlink(PID1_CRASH_LOGFILE);
e91b9f68 423
5b0a4722
A
424 switch ((sample_p = vfork())) {
425 case 0:
426 execve(sample_args[0], sample_args, environ);
427 _exit(EXIT_FAILURE);
428 break;
429 default:
430 waitpid(sample_p, &wstatus, 0);
431 break;
432 case -1:
433 break;
e91b9f68 434 }
95379394 435#endif
5b0a4722
A
436 switch (sig) {
437 default:
438 case 0:
439 break;
440 case SIGBUS:
441 case SIGSEGV:
442 doom_why = "trying to read/write";
443 case SIGILL:
444 case SIGFPE:
95379394 445 case SIGTRAP:
dcace88f 446 snprintf(msg, sizeof(msg), "%s: %p (%s sent by PID %u)", doom_why, crash_addr, strsignal(sig), crash_pid);
5b0a4722 447 sync();
dcace88f 448 do_pid1_crash_diagnosis_mode(msg);
5b0a4722
A
449 sleep(3);
450 reboot(0);
451 break;
e91b9f68 452 }
ed34e3c3 453}
e91b9f68 454
ed34e3c3 455void
5b0a4722 456pid1_magic_init(void)
ed34e3c3 457{
eabd1701
A
458 launchd_label = "com.apple.launchd";
459 launchd_username = "system";
460
461 _launchd_database_dir = LAUNCHD_DB_PREFIX "/com.apple.launchd";
462 _launchd_log_dir = LAUNCHD_LOG_PREFIX "/com.apple.launchd";
463
464 (void)posix_assumes_zero(setsid());
465 (void)posix_assumes_zero(chdir("/"));
466 (void)posix_assumes_zero(setlogin("root"));
ddbbfbc1 467
dcace88f 468#if !TARGET_OS_EMBEDDED
ddbbfbc1 469 auditinfo_addr_t auinfo = {
eabd1701
A
470 .ai_termid = {
471 .at_type = AU_IPv4
472 },
ddbbfbc1
A
473 .ai_asid = AU_ASSIGN_ASID,
474 .ai_auid = AU_DEFAUDITID,
dcace88f 475 .ai_flags = AU_SESSION_FLAG_IS_INITIAL,
ddbbfbc1 476 };
eabd1701
A
477
478 if (setaudit_addr(&auinfo, sizeof(auinfo)) == -1) {
479 launchd_syslog(LOG_WARNING | LOG_CONSOLE, "Could not set audit session: %d: %s.", errno, strerror(errno));
ddbbfbc1
A
480 _exit(EXIT_FAILURE);
481 }
482
eabd1701
A
483 launchd_audit_session = auinfo.ai_asid;
484 launchd_syslog(LOG_DEBUG, "Audit Session ID: %i", launchd_audit_session);
ddbbfbc1 485
eabd1701 486 launchd_audit_port = _audit_session_self();
5c88273d 487#endif // !TARGET_OS_EMBEDDED
e91b9f68
A
488}
489
ddbbfbc1 490char *
eabd1701 491launchd_copy_persistent_store(int type, const char *file)
ddbbfbc1 492{
eabd1701
A
493 char *result = NULL;
494 if (!file) {
495 file = "";
ddbbfbc1 496 }
eabd1701
A
497
498 switch (type) {
499 case LAUNCHD_PERSISTENT_STORE_DB:
500 (void)asprintf(&result, "%s/%s", _launchd_database_dir, file);
501 break;
502 case LAUNCHD_PERSISTENT_STORE_LOGS:
503 (void)asprintf(&result, "%s/%s", _launchd_log_dir, file);
504 break;
505 default:
506 break;
ddbbfbc1 507 }
eabd1701 508
ddbbfbc1
A
509 return result;
510}
e91b9f68 511
ed34e3c3
A
512int
513_fd(int fd)
e91b9f68 514{
5b0a4722 515 if (fd >= 0) {
eabd1701 516 (void)posix_assumes_zero(fcntl(fd, F_SETFD, 1));
5b0a4722 517 }
ed34e3c3
A
518 return fd;
519}
fc89531e 520
ed34e3c3
A
521void
522launchd_shutdown(void)
e91b9f68 523{
ddbbfbc1 524 int64_t now;
5b0a4722 525
eabd1701 526 if (launchd_shutting_down) {
5b0a4722
A
527 return;
528 }
ed34e3c3 529
ddbbfbc1
A
530 runtime_ktrace0(RTKT_LAUNCHD_EXITING);
531
eabd1701
A
532 launchd_shutting_down = true;
533 launchd_log_push();
ddbbfbc1
A
534
535 now = runtime_get_wall_time();
536
537 char *term_who = pid1_magic ? "System shutdown" : "Per-user launchd termination for ";
eabd1701 538 launchd_syslog(LOG_INFO, "%s%s began", term_who, pid1_magic ? "" : launchd_username);
ddbbfbc1 539
95379394 540 os_assert(jobmgr_shutdown(root_jobmgr) != NULL);
ddbbfbc1
A
541
542#if HAVE_LIBAUDITD
dcace88f 543 if (pid1_magic) {
95379394 544 (void)os_assumes_zero(audit_quick_stop());
ddbbfbc1
A
545 }
546#endif
e91b9f68
A
547}
548
ed34e3c3
A
549void
550launchd_SessionCreate(void)
e91b9f68 551{
dcace88f
A
552#if !TARGET_OS_EMBEDDED
553 auditinfo_addr_t auinfo = {
554 .ai_termid = { .at_type = AU_IPv4 },
555 .ai_asid = AU_ASSIGN_ASID,
556 .ai_auid = getuid(),
557 .ai_flags = 0,
558 };
eabd1701 559 if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
dcace88f
A
560 char session[16];
561 snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
562 setenv("SECURITYSESSIONID", session, 1);
563 } else {
eabd1701 564 launchd_syslog(LOG_WARNING, "Could not set audit session: %d: %s.", errno, strerror(errno));
e91b9f68 565 }
5c88273d 566#endif // !TARGET_OS_EMBEDDED
e91b9f68
A
567}
568
ed34e3c3
A
569void
570testfd_or_openfd(int fd, const char *path, int flags)
e91b9f68 571{
ed34e3c3 572 int tmpfd;
e91b9f68 573
ed34e3c3 574 if (-1 != (tmpfd = dup(fd))) {
eabd1701 575 (void)posix_assumes_zero(runtime_close(tmpfd));
ed34e3c3 576 } else {
5b0a4722 577 if (-1 == (tmpfd = open(path, flags | O_NOCTTY, DEFFILEMODE))) {
eabd1701 578 launchd_syslog(LOG_ERR, "open(\"%s\", ...): %m", path);
ed34e3c3 579 } else if (tmpfd != fd) {
eabd1701
A
580 (void)posix_assumes_zero(dup2(tmpfd, fd));
581 (void)posix_assumes_zero(runtime_close(tmpfd));
e91b9f68 582 }
e91b9f68
A
583 }
584}
585
ed34e3c3
A
586bool
587get_network_state(void)
588{
589 struct ifaddrs *ifa, *ifai;
590 bool up = false;
5b0a4722
A
591 int r;
592
593 /* Workaround 4978696: getifaddrs() reports false ENOMEM */
594 while ((r = getifaddrs(&ifa)) == -1 && errno == ENOMEM) {
eabd1701
A
595 launchd_syslog(LOG_DEBUG, "Worked around bug: 4978696");
596 (void)posix_assumes_zero(sched_yield());
5b0a4722 597 }
ed34e3c3 598
eabd1701 599 if (posix_assumes_zero(r) == -1) {
ed34e3c3 600 return network_up;
5b0a4722 601 }
ed34e3c3
A
602
603 for (ifai = ifa; ifai; ifai = ifai->ifa_next) {
5b0a4722 604 if (!(ifai->ifa_flags & IFF_UP)) {
ed34e3c3 605 continue;
5b0a4722
A
606 }
607 if (ifai->ifa_flags & IFF_LOOPBACK) {
ed34e3c3 608 continue;
5b0a4722
A
609 }
610 if (ifai->ifa_addr->sa_family != AF_INET && ifai->ifa_addr->sa_family != AF_INET6) {
ed34e3c3 611 continue;
5b0a4722 612 }
ed34e3c3 613 up = true;
e91b9f68
A
614 break;
615 }
ed34e3c3
A
616
617 freeifaddrs(ifa);
618
619 return up;
e91b9f68
A
620}
621
ed34e3c3
A
622void
623monitor_networking_state(void)
e91b9f68 624{
ed34e3c3
A
625 int pfs = _fd(socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT));
626 struct kev_request kev_req;
e91b9f68 627
ed34e3c3 628 network_up = get_network_state();
e91b9f68 629
eabd1701 630 if (pfs == -1) {
95379394 631 (void)os_assumes_zero(errno);
ed34e3c3 632 return;
5b0a4722 633 }
e91b9f68 634
ed34e3c3
A
635 memset(&kev_req, 0, sizeof(kev_req));
636 kev_req.vendor_code = KEV_VENDOR_APPLE;
637 kev_req.kev_class = KEV_NETWORK_CLASS;
e91b9f68 638
eabd1701 639 if (posix_assumes_zero(ioctl(pfs, SIOCSKEVFILT, &kev_req)) == -1) {
5b0a4722 640 runtime_close(pfs);
e91b9f68 641 return;
e91b9f68
A
642 }
643
eabd1701 644 (void)posix_assumes_zero(kevent_mod(pfs, EVFILT_READ, EV_ADD, 0, 0, &kqpfsystem_callback));
e91b9f68
A
645}
646
ed34e3c3 647void
ef398931 648pfsystem_callback(void *obj __attribute__((unused)), struct kevent *kev)
e91b9f68 649{
ed34e3c3
A
650 bool new_networking_state;
651 char buf[1024];
e91b9f68 652
eabd1701 653 (void)posix_assumes_zero(read((int)kev->ident, &buf, sizeof(buf)));
e91b9f68 654
ed34e3c3 655 new_networking_state = get_network_state();
e91b9f68 656
ed34e3c3
A
657 if (new_networking_state != network_up) {
658 network_up = new_networking_state;
5b0a4722 659 jobmgr_dispatch_all_semaphores(root_jobmgr);
2a27bb34 660 }
e91b9f68 661}