]> git.saurik.com Git - apple/launchd.git/blame - src/runtime.c
launchd-842.90.1.tar.gz
[apple/launchd.git] / src / runtime.c
CommitLineData
5b0a4722 1/*
ddbbfbc1 2 * Copyright (c) 1999-2008 Apple Computer, Inc. All rights reserved.
5b0a4722
A
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
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
9 *
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
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
5b0a4722 21#include "config.h"
eabd1701 22#include "runtime.h"
5b0a4722
A
23
24#include <mach/mach.h>
25#include <mach/mach_error.h>
26#include <mach/boolean.h>
27#include <mach/message.h>
28#include <mach/notify.h>
29#include <mach/mig_errors.h>
30#include <mach/mach_traps.h>
31#include <mach/mach_interface.h>
32#include <mach/host_info.h>
33#include <mach/mach_host.h>
ddbbfbc1 34#include <mach/mach_time.h>
5b0a4722
A
35#include <mach/exception.h>
36#include <sys/types.h>
37#include <sys/stat.h>
ddbbfbc1 38#include <sys/sysctl.h>
5b0a4722
A
39#include <sys/time.h>
40#include <sys/proc.h>
95379394
A
41#include <sys/proc_info.h>
42#include <libproc.h>
5b0a4722
A
43#include <sys/event.h>
44#include <sys/queue.h>
45#include <sys/socket.h>
46#include <sys/mount.h>
47#include <sys/reboot.h>
48#include <sys/fcntl.h>
ddbbfbc1 49#include <sys/kdebug.h>
5b0a4722
A
50#include <bsm/libbsm.h>
51#include <malloc/malloc.h>
52#include <unistd.h>
53#include <pthread.h>
54#include <errno.h>
55#include <string.h>
56#include <ctype.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <stdbool.h>
60#include <syslog.h>
61#include <signal.h>
62#include <dlfcn.h>
95379394 63#include <os/assumes.h>
5b0a4722 64
eabd1701
A
65#include "internalServer.h"
66#include "internal.h"
5b0a4722 67#include "notifyServer.h"
ddbbfbc1 68#include "mach_excServer.h"
5b0a4722
A
69
70/* We shouldn't be including these */
71#include "launch.h"
72#include "launchd.h"
eabd1701 73#include "core.h"
ddbbfbc1
A
74#include "vproc.h"
75#include "vproc_priv.h"
ef398931 76#include "vproc_internal.h"
eabd1701
A
77#include "jobServer.h"
78#include "job_reply.h"
5b0a4722 79
eabd1701 80#include <xpc/launchd.h>
dcace88f 81
5b0a4722
A
82static mach_port_t ipc_port_set;
83static mach_port_t demand_port_set;
84static mach_port_t launchd_internal_port;
85static int mainkq;
86
87#define BULK_KEV_MAX 100
88static struct kevent *bulk_kev;
89static int bulk_kev_i;
90static int bulk_kev_cnt;
91
92static pthread_t kqueue_demand_thread;
5b0a4722 93
ddbbfbc1
A
94static void mportset_callback(void);
95static kq_callback kqmportset_callback = (kq_callback)mportset_callback;
5b0a4722 96static void *kqueue_demand_loop(void *arg);
5b0a4722 97
ddbbfbc1 98boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
eabd1701 99static void launchd_runtime2(mach_msg_size_t msg_size);
5b0a4722
A
100static mach_msg_size_t max_msg_size;
101static mig_callback *mig_cb_table;
102static size_t mig_cb_table_sz;
103static timeout_callback runtime_idle_callback;
104static mach_msg_timeout_t runtime_idle_timeout;
ddbbfbc1 105static struct ldcred ldc;
95379394 106static audit_token_t ldc_token;
ddbbfbc1 107static size_t runtime_standby_cnt;
5b0a4722 108
ddbbfbc1
A
109static void do_file_init(void) __attribute__((constructor));
110static mach_timebase_info_data_t tbi;
111static uint64_t tbi_safe_math_max;
112static uint64_t time_of_mach_msg_return;
113static double tbi_float_val;
5b0a4722
A
114
115static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM, SIGTERM,
116 SIGURG, SIGTSTP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, SIGIO, SIGXCPU,
117 SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2
118};
119static sigset_t sigign_set;
ddbbfbc1 120bool pid1_magic;
eabd1701
A
121bool launchd_apple_internal;
122bool launchd_flat_mach_namespace = true;
123bool launchd_malloc_log_stacks = false;
124bool launchd_use_gmalloc = false;
125bool launchd_log_per_user_shutdown = false;
ddbbfbc1 126#if !TARGET_OS_EMBEDDED
eabd1701 127bool launchd_log_shutdown = true;
ddbbfbc1 128#else
eabd1701 129bool launchd_log_shutdown = false;
ddbbfbc1 130#endif
eabd1701
A
131bool launchd_log_perf = false;
132bool launchd_log_debug = false;
133bool launchd_trap_sigkill_bugs = false;
95379394 134bool launchd_no_jetsam_perm_check = false;
eabd1701
A
135bool launchd_osinstaller = false;
136bool launchd_allow_global_dyld_envvars = false;
95379394
A
137#if TARGET_OS_EMBEDDED
138bool launchd_appletv = false;
139#endif
eabd1701 140pid_t launchd_wsp = 0;
587e987e 141size_t runtime_busy_cnt;
5b0a4722 142
eabd1701
A
143#if TARGET_OS_EMBEDDED
144#define LAUNCHD_CONFIG_PREFIX "/"
145#else
146#define LAUNCHD_CONFIG_PREFIX "/private/var/db/"
147#endif
148
149#define config_check(s, sb) (stat(LAUNCHD_CONFIG_PREFIX s, &sb) == 0)
150
fe044cc9
A
151mach_port_t
152runtime_get_kernel_port(void)
153{
154 return launchd_internal_port;
155}
156
eabd1701
A
157union vproc_mig_max_sz {
158 union __RequestUnion__job_mig_job_subsystem req;
159 union __ReplyUnion__job_mig_job_subsystem rep;
160};
ddbbfbc1 161
eabd1701
A
162union internal_max_sz {
163 union __RequestUnion__x_internal_subsystem req;
164 union __ReplyUnion__internal_subsystem rep;
165};
ddbbfbc1 166
eabd1701
A
167union xpc_domain_max_sz {
168 union __RequestUnion__xpc_domain_xpc_domain_subsystem req;
169 union __ReplyUnion__xpc_domain_xpc_domain_subsystem rep;
170};
171
172union mach_exc_max_sz {
173 union __RequestUnion__catch_mach_exc_subsystem req;
174 union __ReplyUnion__catch_mach_exc_subsystem rep;
175};
176
177union do_notify_max_sz {
178 union __RequestUnion__do_notify_subsystem req;
179 union __ReplyUnion__do_notify_subsystem rep;
180};
ddbbfbc1 181
5b0a4722
A
182void
183launchd_runtime_init(void)
184{
ddbbfbc1 185 pid_t p = getpid();
5b0a4722 186
eabd1701 187 (void)posix_assert_zero((mainkq = kqueue()));
5b0a4722 188
95379394
A
189 os_assert_zero(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &demand_port_set));
190 os_assert_zero(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ipc_port_set));
eabd1701 191 posix_assert_zero(kevent_mod(demand_port_set, EVFILT_MACHPORT, EV_ADD, 0, 0, &kqmportset_callback));
5b0a4722 192
95379394
A
193 os_assert_zero(launchd_mport_create_recv(&launchd_internal_port));
194 os_assert_zero(launchd_mport_make_send(launchd_internal_port));
ddbbfbc1 195
eabd1701
A
196 max_msg_size = sizeof(union vproc_mig_max_sz);
197 if (sizeof(union xpc_domain_max_sz) > max_msg_size) {
198 max_msg_size = sizeof(union xpc_domain_max_sz);
5b0a4722
A
199 }
200
95379394
A
201 os_assert_zero(runtime_add_mport(launchd_internal_port, launchd_internal_demux));
202 os_assert_zero(pthread_create(&kqueue_demand_thread, NULL, kqueue_demand_loop, NULL));
203 os_assert_zero(pthread_detach(kqueue_demand_thread));
5b0a4722 204
eabd1701 205 (void)posix_assumes_zero(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)));
5b0a4722
A
206}
207
208void
209launchd_runtime_init2(void)
210{
211 size_t i;
212
95379394 213 __OS_COMPILETIME_ASSERT__(SIG_ERR == (typeof(SIG_ERR))-1);
5b0a4722
A
214 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
215 sigaddset(&sigign_set, sigigns[i]);
eabd1701 216 (void)posix_assumes_zero(signal(sigigns[i], SIG_IGN));
5b0a4722
A
217 }
218}
219
5b0a4722 220#define FLAGIF(f) if (flags & f) { flags_off += sprintf(flags_off, #f); flags &= ~f; }
5b0a4722
A
221const char *
222reboot_flags_to_C_names(unsigned int flags)
223{
ddbbfbc1 224#define MAX_RB_STR "RB_ASKNAME|RB_SINGLE|RB_NOSYNC|RB_HALT|RB_INITNAME|RB_DFLTROOT|RB_ALTBOOT|RB_UNIPROC|RB_SAFEBOOT|RB_UPSDELAY|0xdeadbeeffeedface"
5b0a4722
A
225 static char flags_buf[sizeof(MAX_RB_STR)];
226 char *flags_off = NULL;
227
fe044cc9
A
228 if (flags == 0) {
229 return "RB_AUTOBOOT";
230 }
231
232 while (flags) {
5b0a4722
A
233 if (flags_off) {
234 *flags_off = '|';
235 flags_off++;
236 *flags_off = '\0';
237 } else {
238 flags_off = flags_buf;
239 }
240
241 FLAGIF(RB_ASKNAME)
242 else FLAGIF(RB_SINGLE)
243 else FLAGIF(RB_NOSYNC)
5b0a4722
A
244 else FLAGIF(RB_HALT)
245 else FLAGIF(RB_INITNAME)
246 else FLAGIF(RB_DFLTROOT)
247 else FLAGIF(RB_ALTBOOT)
248 else FLAGIF(RB_UNIPROC)
249 else FLAGIF(RB_SAFEBOOT)
250 else FLAGIF(RB_UPSDELAY)
251 else {
252 flags_off += sprintf(flags_off, "0x%x", flags);
253 flags = 0;
254 }
5b0a4722 255 }
fe044cc9
A
256
257 return flags_buf;
5b0a4722
A
258}
259
260const char *
261signal_to_C_name(unsigned int sig)
262{
263 static char unknown[25];
264
265#define SIG2CASE(sg) case sg: return #sg
266
267 switch (sig) {
268 SIG2CASE(SIGHUP);
269 SIG2CASE(SIGINT);
270 SIG2CASE(SIGQUIT);
271 SIG2CASE(SIGILL);
272 SIG2CASE(SIGTRAP);
273 SIG2CASE(SIGABRT);
274 SIG2CASE(SIGFPE);
275 SIG2CASE(SIGKILL);
276 SIG2CASE(SIGBUS);
277 SIG2CASE(SIGSEGV);
278 SIG2CASE(SIGSYS);
279 SIG2CASE(SIGPIPE);
280 SIG2CASE(SIGALRM);
281 SIG2CASE(SIGTERM);
282 SIG2CASE(SIGURG);
283 SIG2CASE(SIGSTOP);
284 SIG2CASE(SIGTSTP);
285 SIG2CASE(SIGCONT);
286 SIG2CASE(SIGCHLD);
287 SIG2CASE(SIGTTIN);
288 SIG2CASE(SIGTTOU);
289 SIG2CASE(SIGIO);
290 SIG2CASE(SIGXCPU);
291 SIG2CASE(SIGXFSZ);
292 SIG2CASE(SIGVTALRM);
293 SIG2CASE(SIGPROF);
294 SIG2CASE(SIGWINCH);
295 SIG2CASE(SIGINFO);
296 SIG2CASE(SIGUSR1);
297 SIG2CASE(SIGUSR2);
298 default:
299 snprintf(unknown, sizeof(unknown), "%u", sig);
300 return unknown;
301 }
302}
303
304void
ddbbfbc1 305log_kevent_struct(int level, struct kevent *kev_base, int indx)
5b0a4722 306{
ddbbfbc1 307 struct kevent *kev = &kev_base[indx];
5b0a4722
A
308 const char *filter_str;
309 char ident_buf[100];
310 char filter_buf[100];
311 char fflags_buf[1000];
312 char flags_buf[1000] = "0x0";
313 char *flags_off = NULL;
314 char *fflags_off = NULL;
315 unsigned short flags = kev->flags;
316 unsigned int fflags = kev->fflags;
317
eabd1701 318 if (likely(!(LOG_MASK(level & ~LOG_CONSOLE) & LOG_DEBUG))) {
ddbbfbc1
A
319 return;
320 }
321
5b0a4722
A
322 if (flags) while (flags) {
323 if (flags_off) {
324 *flags_off = '|';
325 flags_off++;
326 *flags_off = '\0';
327 } else {
328 flags_off = flags_buf;
329 }
330
331 FLAGIF(EV_ADD)
332 else FLAGIF(EV_RECEIPT)
333 else FLAGIF(EV_DELETE)
334 else FLAGIF(EV_ENABLE)
335 else FLAGIF(EV_DISABLE)
336 else FLAGIF(EV_CLEAR)
337 else FLAGIF(EV_EOF)
338 else FLAGIF(EV_ONESHOT)
339 else FLAGIF(EV_ERROR)
340 else {
ddbbfbc1 341 flags_off += sprintf(flags_off, "0x%hx", flags);
5b0a4722
A
342 flags = 0;
343 }
344 }
345
346 snprintf(ident_buf, sizeof(ident_buf), "%ld", kev->ident);
347 snprintf(fflags_buf, sizeof(fflags_buf), "0x%x", fflags);
348
349 switch (kev->filter) {
350 case EVFILT_READ:
351 filter_str = "EVFILT_READ";
352 break;
353 case EVFILT_WRITE:
354 filter_str = "EVFILT_WRITE";
355 break;
356 case EVFILT_AIO:
357 filter_str = "EVFILT_AIO";
358 break;
359 case EVFILT_VNODE:
360 filter_str = "EVFILT_VNODE";
361 if (fflags) while (fflags) {
362 if (fflags_off) {
363 *fflags_off = '|';
364 fflags_off++;
365 *fflags_off = '\0';
366 } else {
367 fflags_off = fflags_buf;
368 }
369
370#define FFLAGIF(ff) if (fflags & ff) { fflags_off += sprintf(fflags_off, #ff); fflags &= ~ff; }
371
372 FFLAGIF(NOTE_DELETE)
373 else FFLAGIF(NOTE_WRITE)
374 else FFLAGIF(NOTE_EXTEND)
375 else FFLAGIF(NOTE_ATTRIB)
376 else FFLAGIF(NOTE_LINK)
377 else FFLAGIF(NOTE_RENAME)
378 else FFLAGIF(NOTE_REVOKE)
379 else {
380 fflags_off += sprintf(fflags_off, "0x%x", fflags);
381 fflags = 0;
382 }
383 }
384 break;
385 case EVFILT_PROC:
386 filter_str = "EVFILT_PROC";
387 if (fflags) while (fflags) {
388 if (fflags_off) {
389 *fflags_off = '|';
390 fflags_off++;
391 *fflags_off = '\0';
392 } else {
393 fflags_off = fflags_buf;
394 }
395
396 FFLAGIF(NOTE_EXIT)
397 else FFLAGIF(NOTE_REAP)
398 else FFLAGIF(NOTE_FORK)
399 else FFLAGIF(NOTE_EXEC)
400 else FFLAGIF(NOTE_SIGNAL)
401 else FFLAGIF(NOTE_TRACK)
402 else FFLAGIF(NOTE_TRACKERR)
403 else FFLAGIF(NOTE_CHILD)
404 else {
405 fflags_off += sprintf(fflags_off, "0x%x", fflags);
406 fflags = 0;
407 }
408 }
409 break;
410 case EVFILT_SIGNAL:
411 filter_str = "EVFILT_SIGNAL";
412 strcpy(ident_buf, signal_to_C_name(kev->ident));
413 break;
414 case EVFILT_TIMER:
415 filter_str = "EVFILT_TIMER";
416 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
417 if (fflags) while (fflags) {
418 if (fflags_off) {
419 *fflags_off = '|';
420 fflags_off++;
421 *fflags_off = '\0';
422 } else {
423 fflags_off = fflags_buf;
424 }
425
426 FFLAGIF(NOTE_SECONDS)
427 else FFLAGIF(NOTE_USECONDS)
428 else FFLAGIF(NOTE_NSECONDS)
429 else FFLAGIF(NOTE_ABSOLUTE)
430 else {
431 fflags_off += sprintf(fflags_off, "0x%x", fflags);
432 fflags = 0;
433 }
434 }
435 break;
436 case EVFILT_MACHPORT:
437 filter_str = "EVFILT_MACHPORT";
438 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
439 break;
440 case EVFILT_FS:
441 filter_str = "EVFILT_FS";
442 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
443 if (fflags) while (fflags) {
444 if (fflags_off) {
445 *fflags_off = '|';
446 fflags_off++;
447 *fflags_off = '\0';
448 } else {
449 fflags_off = fflags_buf;
450 }
451
452 FFLAGIF(VQ_NOTRESP)
453 else FFLAGIF(VQ_NEEDAUTH)
454 else FFLAGIF(VQ_LOWDISK)
455 else FFLAGIF(VQ_MOUNT)
456 else FFLAGIF(VQ_UNMOUNT)
457 else FFLAGIF(VQ_DEAD)
458 else FFLAGIF(VQ_ASSIST)
459 else FFLAGIF(VQ_NOTRESPLOCK)
460 else FFLAGIF(VQ_UPDATE)
461 else {
462 fflags_off += sprintf(fflags_off, "0x%x", fflags);
463 fflags = 0;
464 }
465 }
466 break;
467 default:
ddbbfbc1 468 snprintf(filter_buf, sizeof(filter_buf), "%hd", kev->filter);
5b0a4722
A
469 filter_str = filter_buf;
470 break;
471 }
472
eabd1701 473 launchd_syslog(level, "KEVENT[%d]: udata = %p data = 0x%lx ident = %s filter = %s flags = %s fflags = %s",
5b0a4722
A
474 indx, kev->udata, kev->data, ident_buf, filter_str, flags_buf, fflags_buf);
475}
476
ddbbfbc1
A
477void
478mportset_callback(void)
5b0a4722
A
479{
480 mach_port_name_array_t members;
481 mach_msg_type_number_t membersCnt;
482 mach_port_status_t status;
483 mach_msg_type_number_t statusCnt;
484 struct kevent kev;
485 unsigned int i;
486
95379394 487 if (os_assumes_zero(mach_port_get_set_status(mach_task_self(), demand_port_set, &members, &membersCnt)) != 0) {
ddbbfbc1 488 return;
5b0a4722
A
489 }
490
491 for (i = 0; i < membersCnt; i++) {
492 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
493 if (mach_port_get_attributes(mach_task_self(), members[i], MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status,
494 &statusCnt) != KERN_SUCCESS) {
495 continue;
496 }
497 if (status.mps_msgcount) {
498 EV_SET(&kev, members[i], EVFILT_MACHPORT, 0, 0, 0, job_find_by_service_port(members[i]));
499#if 0
eabd1701 500 if (kev.udata != NULL) {
5b0a4722 501#endif
587e987e 502 log_kevent_struct(LOG_DEBUG, &kev, 0);
5b0a4722
A
503 (*((kq_callback *)kev.udata))(kev.udata, &kev);
504#if 0
505 } else {
587e987e 506 log_kevent_struct(LOG_ERR, &kev, 0);
5b0a4722
A
507 }
508#endif
509 /* the callback may have tainted our ability to continue this for loop */
510 break;
511 }
512 }
513
95379394 514 (void)os_assumes_zero(vm_deallocate(mach_task_self(), (vm_address_t)members, (vm_size_t) membersCnt * sizeof(mach_port_name_t)));
5b0a4722
A
515}
516
517void *
518kqueue_demand_loop(void *arg __attribute__((unused)))
519{
520 fd_set rfds;
521
522 /*
523 * Yes, at first glance, calling select() on a kqueue seems silly.
524 *
525 * This avoids a race condition between the main thread and this helper
526 * thread by ensuring that we drain kqueue events on the same thread
527 * that manipulates the kqueue.
528 */
529
530 for (;;) {
531 FD_ZERO(&rfds);
532 FD_SET(mainkq, &rfds);
eabd1701
A
533 int r = select(mainkq + 1, &rfds, NULL, NULL, NULL);
534 if (r == 1) {
95379394 535 (void)os_assumes_zero(handle_kqueue(launchd_internal_port, mainkq));
eabd1701 536 } else if (posix_assumes_zero(r) != -1) {
95379394 537 (void)os_assumes_zero(r);
5b0a4722
A
538 }
539 }
540
541 return NULL;
542}
543
544kern_return_t
545x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
546{
547 struct timespec ts = { 0, 0 };
ddbbfbc1 548 struct kevent *kevi, kev[BULK_KEV_MAX];
5b0a4722
A
549 int i;
550
551 bulk_kev = kev;
552
eabd1701 553 if ((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1) {
dcace88f 554#if 0
5b0a4722 555 for (i = 0; i < bulk_kev_cnt; i++) {
587e987e 556 log_kevent_struct(LOG_DEBUG, &kev[0], i);
5b0a4722 557 }
dcace88f 558#endif
5b0a4722
A
559 for (i = 0; i < bulk_kev_cnt; i++) {
560 bulk_kev_i = i;
ddbbfbc1
A
561 kevi = &kev[i];
562
563 if (kevi->filter) {
eabd1701 564 launchd_syslog(LOG_DEBUG, "Dispatching kevent (ident/filter): %lu/%hd", kevi->ident, kevi->filter);
ddbbfbc1 565 log_kevent_struct(LOG_DEBUG, kev, i);
eabd1701 566
5c88273d
A
567 struct job_check_s {
568 kq_callback kqc;
569 };
570
571 struct job_check_s *check = kevi->udata;
572 if (check && check->kqc) {
573 runtime_ktrace(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_START, kevi->ident, kevi->filter, kevi->fflags);
574 (*((kq_callback *)kevi->udata))(kevi->udata, kevi);
575 runtime_ktrace0(RTKT_LAUNCHD_BSD_KEVENT|DBG_FUNC_END);
576 } else {
eabd1701 577 launchd_syslog(LOG_ERR, "The following kevent had invalid context data. Please file a bug with the following information:");
5c88273d
A
578 log_kevent_struct(LOG_EMERG, &kev[0], i);
579 }
eabd1701 580 launchd_syslog(LOG_DEBUG, "Handled kevent.");
5b0a4722
A
581 }
582 }
eabd1701 583 } else {
95379394 584 (void)os_assumes_zero(errno);
5b0a4722
A
585 }
586
587 bulk_kev = NULL;
588
589 return 0;
590}
591
5b0a4722
A
592void
593launchd_runtime(void)
594{
eabd1701
A
595 launchd_runtime2(max_msg_size);
596 dispatch_main();
5b0a4722
A
597}
598
599kern_return_t
600launchd_set_bport(mach_port_t name)
601{
602 return errno = task_set_bootstrap_port(mach_task_self(), name);
603}
604
605kern_return_t
606launchd_get_bport(mach_port_t *name)
607{
608 return errno = task_get_bootstrap_port(mach_task_self(), name);
609}
610
611kern_return_t
612launchd_mport_notify_req(mach_port_t name, mach_msg_id_t which)
613{
fe044cc9 614 mach_port_mscount_t msgc = (which == MACH_NOTIFY_PORT_DESTROYED) ? 0 : 1;
5b0a4722
A
615 mach_port_t previous, where = (which == MACH_NOTIFY_NO_SENDERS) ? name : launchd_internal_port;
616
617 if (which == MACH_NOTIFY_NO_SENDERS) {
eabd1701
A
618 /* Always make sure the send count is zero, in case a receive right is
619 * reused
620 */
5b0a4722 621 errno = mach_port_set_mscount(mach_task_self(), name, 0);
ddbbfbc1 622 if (unlikely(errno != KERN_SUCCESS)) {
5b0a4722
A
623 return errno;
624 }
625 }
626
eabd1701 627 errno = mach_port_request_notification(mach_task_self(), name, which, msgc, where, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
5b0a4722 628
ddbbfbc1 629 if (likely(errno == 0) && previous != MACH_PORT_NULL) {
95379394 630 (void)os_assumes_zero(launchd_mport_deallocate(previous));
5b0a4722
A
631 }
632
633 return errno;
634}
635
636pid_t
637runtime_fork(mach_port_t bsport)
638{
639 sigset_t emptyset, oset;
640 pid_t r = -1;
641 int saved_errno;
642 size_t i;
643
644 sigemptyset(&emptyset);
645
95379394
A
646 (void)os_assumes_zero(launchd_mport_make_send(bsport));
647 (void)os_assumes_zero(launchd_set_bport(bsport));
648 (void)os_assumes_zero(launchd_mport_deallocate(bsport));
5b0a4722 649
95379394 650 __OS_COMPILETIME_ASSERT__(SIG_ERR == (typeof(SIG_ERR))-1);
eabd1701 651 (void)posix_assumes_zero(sigprocmask(SIG_BLOCK, &sigign_set, &oset));
5b0a4722 652 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
eabd1701 653 (void)posix_assumes_zero(signal(sigigns[i], SIG_DFL));
5b0a4722
A
654 }
655
656 r = fork();
657 saved_errno = errno;
658
659 if (r != 0) {
660 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
eabd1701 661 (void)posix_assumes_zero(signal(sigigns[i], SIG_IGN));
5b0a4722 662 }
eabd1701 663 (void)posix_assumes_zero(sigprocmask(SIG_SETMASK, &oset, NULL));
95379394 664 (void)os_assumes_zero(launchd_set_bport(MACH_PORT_NULL));
5b0a4722 665 } else {
ddbbfbc1 666 pid_t p = -getpid();
eabd1701
A
667 (void)posix_assumes_zero(sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &p, sizeof(p)));
668 (void)posix_assumes_zero(sigprocmask(SIG_SETMASK, &emptyset, NULL));
5b0a4722
A
669 }
670
671 errno = saved_errno;
672
673 return r;
674}
675
676
677void
678runtime_set_timeout(timeout_callback to_cb, unsigned int sec)
679{
680 if (sec == 0 || to_cb == NULL) {
681 runtime_idle_callback = NULL;
682 runtime_idle_timeout = 0;
683 }
684
685 runtime_idle_callback = to_cb;
686 runtime_idle_timeout = sec * 1000;
687}
688
689kern_return_t
eabd1701 690runtime_add_mport(mach_port_t name, mig_callback demux)
5b0a4722
A
691{
692 size_t needed_table_sz = (MACH_PORT_INDEX(name) + 1) * sizeof(mig_callback);
693 mach_port_t target_set = demux ? ipc_port_set : demand_port_set;
694
ddbbfbc1 695 if (unlikely(needed_table_sz > mig_cb_table_sz)) {
5b0a4722
A
696 needed_table_sz *= 2; /* Let's try and avoid realloc'ing for a while */
697 mig_callback *new_table = malloc(needed_table_sz);
698
eabd1701 699 if (!new_table) {
5b0a4722
A
700 return KERN_RESOURCE_SHORTAGE;
701 }
702
ddbbfbc1 703 if (likely(mig_cb_table)) {
5b0a4722
A
704 memcpy(new_table, mig_cb_table, mig_cb_table_sz);
705 free(mig_cb_table);
706 }
707
708 mig_cb_table_sz = needed_table_sz;
709 mig_cb_table = new_table;
710 }
711
712 mig_cb_table[MACH_PORT_INDEX(name)] = demux;
713
5b0a4722
A
714 return errno = mach_port_move_member(mach_task_self(), name, target_set);
715}
716
717kern_return_t
718runtime_remove_mport(mach_port_t name)
719{
720 mig_cb_table[MACH_PORT_INDEX(name)] = NULL;
721
722 return errno = mach_port_move_member(mach_task_self(), name, MACH_PORT_NULL);
723}
724
725kern_return_t
726launchd_mport_make_send(mach_port_t name)
727{
728 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_MAKE_SEND);
729}
730
ddbbfbc1
A
731kern_return_t
732launchd_mport_copy_send(mach_port_t name)
733{
734 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_COPY_SEND);
735}
736
dcace88f
A
737kern_return_t
738launchd_mport_make_send_once(mach_port_t name, mach_port_t *so)
739{
740 mach_msg_type_name_t right = 0;
741 return errno = mach_port_extract_right(mach_task_self(), name, MACH_MSG_TYPE_MAKE_SEND_ONCE, so, &right);
742}
743
5b0a4722
A
744kern_return_t
745launchd_mport_close_recv(mach_port_t name)
746{
747 return errno = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE, -1);
748}
749
750kern_return_t
751launchd_mport_create_recv(mach_port_t *name)
752{
753 return errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, name);
754}
755
756kern_return_t
757launchd_mport_deallocate(mach_port_t name)
758{
759 return errno = mach_port_deallocate(mach_task_self(), name);
760}
761
762int
763kevent_bulk_mod(struct kevent *kev, size_t kev_cnt)
764{
765 size_t i;
766
767 for (i = 0; i < kev_cnt; i++) {
768 kev[i].flags |= EV_CLEAR|EV_RECEIPT;
769 }
770
771 return kevent(mainkq, kev, kev_cnt, kev, kev_cnt, NULL);
772}
773
774int
775kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata)
776{
777 struct kevent kev;
778 int r;
779
780 switch (filter) {
781 case EVFILT_READ:
782 case EVFILT_WRITE:
783 break;
ddbbfbc1
A
784 case EVFILT_TIMER:
785 /* Workaround 5225889 */
786 if (flags & EV_ADD) {
eabd1701 787 (void)kevent_mod(ident, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
ddbbfbc1
A
788 }
789 /* fall through */
5b0a4722
A
790 default:
791 flags |= EV_CLEAR;
792 break;
793 }
794
795 flags |= EV_RECEIPT;
796
eabd1701 797 if (flags & EV_ADD && !udata) {
5b0a4722
A
798 errno = EINVAL;
799 return -1;
dcace88f 800 } else if ((flags & EV_DELETE) && bulk_kev) {
ddbbfbc1 801 int i = 0;
dcace88f
A
802 for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
803 if (bulk_kev[i].filter == filter && bulk_kev[i].ident == ident) {
eabd1701 804 launchd_syslog(LOG_DEBUG, "Pruning the following kevent:");
587e987e 805 log_kevent_struct(LOG_DEBUG, &bulk_kev[0], i);
ddbbfbc1
A
806 bulk_kev[i].filter = (short)0;
807 }
808 }
5b0a4722
A
809 }
810
811 EV_SET(&kev, ident, filter, flags, fflags, data, udata);
812
813 r = kevent(mainkq, &kev, 1, &kev, 1, NULL);
814
eabd1701 815 if (r != 1) {
5b0a4722
A
816 return -1;
817 }
818
eabd1701 819 if (kev.flags & EV_ERROR) {
5b0a4722 820 if ((flags & EV_ADD) && kev.data) {
eabd1701 821 launchd_syslog(LOG_DEBUG, "%s(): See the next line...", __func__);
5b0a4722
A
822 log_kevent_struct(LOG_DEBUG, &kev, 0);
823 errno = kev.data;
824 return -1;
825 }
eabd1701 826 } else {
95379394 827 (void)os_assert_zero(kev.flags);
5b0a4722
A
828 }
829
830 return r;
831}
832
833boolean_t
834launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply)
835{
eabd1701
A
836 if (internal_server_routine(Request)) {
837 return internal_server(Request, Reply);
fe044cc9
A
838 } else if (notify_server_routine(Request)) {
839 return notify_server(Request, Reply);
840 } else {
ddbbfbc1 841 return mach_exc_server(Request, Reply);
5b0a4722 842 }
5b0a4722
A
843}
844
845kern_return_t
ddbbfbc1 846do_mach_notify_port_destroyed(mach_port_t notify __attribute__((unused)), mach_port_t rights)
5b0a4722
A
847{
848 /* This message is sent to us when a receive right is returned to us. */
eabd1701 849 if (!job_ack_port_destruction(rights)) {
95379394 850 (void)os_assumes_zero(launchd_mport_close_recv(rights));
5b0a4722
A
851 }
852
853 return KERN_SUCCESS;
854}
855
856kern_return_t
ddbbfbc1 857do_mach_notify_port_deleted(mach_port_t notify __attribute__((unused)), mach_port_name_t name __attribute__((unused)))
5b0a4722
A
858{
859 /* If we deallocate/destroy/mod_ref away a port with a pending
860 * notification, the original notification message is replaced with
861 * this message. To quote a Mach kernel expert, "the kernel has a
862 * send-once right that has to be used somehow."
863 */
864 return KERN_SUCCESS;
865}
866
867kern_return_t
ddbbfbc1 868do_mach_notify_no_senders(mach_port_t notify, mach_port_mscount_t mscount __attribute__((unused)))
5b0a4722
A
869{
870 job_t j = job_mig_intran(notify);
871
eabd1701
A
872 /* This message is sent to us when the last customer of one of our objects
873 * goes away.
5b0a4722
A
874 */
875
eabd1701 876 if (!j) {
5b0a4722
A
877 return KERN_FAILURE;
878 }
879
880 job_ack_no_senders(j);
881
882 return KERN_SUCCESS;
883}
884
885kern_return_t
ef398931 886do_mach_notify_send_once(mach_port_t notify __attribute__((unused)))
5b0a4722 887{
ddbbfbc1 888 /*
eabd1701
A
889 * This message is sent for each send-once right that is deallocated without
890 * being used.
5b0a4722
A
891 */
892
893 return KERN_SUCCESS;
894}
895
896kern_return_t
ddbbfbc1 897do_mach_notify_dead_name(mach_port_t notify __attribute__((unused)), mach_port_name_t name)
5b0a4722 898{
eabd1701
A
899 /* This message is sent to us when one of our send rights no longer has a
900 * receiver somewhere else on the system.
5b0a4722 901 */
eabd1701 902 if (name == launchd_drain_reply_port) {
95379394 903 (void)os_assumes_zero(launchd_mport_deallocate(name));
eabd1701 904 launchd_drain_reply_port = MACH_PORT_NULL;
5b0a4722
A
905 }
906
eabd1701 907 if (root_jobmgr) {
5b0a4722
A
908 root_jobmgr = jobmgr_delete_anything_with_port(root_jobmgr, name);
909 }
910
eabd1701
A
911 /* A dead-name notification about a port appears to increment the rights on
912 * said port. Let's deallocate it so that we don't leak dead-name ports.
5b0a4722 913 */
95379394 914 (void)os_assumes_zero(launchd_mport_deallocate(name));
5b0a4722
A
915
916 return KERN_SUCCESS;
917}
918
ddbbfbc1
A
919mach_msg_return_t
920launchd_exc_runtime_once(mach_port_t port, mach_msg_size_t rcv_msg_size, mach_msg_size_t send_msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply, mach_msg_timeout_t to)
921{
922 mach_msg_return_t mr = ~MACH_MSG_SUCCESS;
eabd1701
A
923 mach_msg_option_t rcv_options = MACH_RCV_MSG
924 | MACH_RCV_TIMEOUT
925 | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
926 | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
927
ddbbfbc1
A
928 do {
929 mr = mach_msg(&bufRequest->Head, rcv_options, 0, rcv_msg_size, port, to, MACH_PORT_NULL);
dcace88f 930 switch (mr) {
eabd1701
A
931 case MACH_RCV_TIMED_OUT:
932 launchd_syslog(LOG_DEBUG, "Message queue is empty.");
933 break;
934 case MACH_RCV_TOO_LARGE:
935 launchd_syslog(LOG_INFO, "Message is larger than %u bytes.", rcv_msg_size);
936 break;
937 default:
95379394 938 (void)os_assumes_zero(mr);
ddbbfbc1 939 }
eabd1701 940
dcace88f 941 if (mr == MACH_MSG_SUCCESS) {
eabd1701
A
942 if (!mach_exc_server(&bufRequest->Head, &bufReply->Head)) {
943 launchd_syslog(LOG_WARNING, "Exception server routine failed.");
ddbbfbc1
A
944 break;
945 }
eabd1701 946
ddbbfbc1 947 mach_msg_return_t smr = ~MACH_MSG_SUCCESS;
eabd1701
A
948 mach_msg_option_t send_options = MACH_SEND_MSG | MACH_SEND_TIMEOUT;
949
95379394 950 (void)os_assumes(bufReply->Head.msgh_size <= send_msg_size);
ddbbfbc1 951 smr = mach_msg(&bufReply->Head, send_options, bufReply->Head.msgh_size, 0, MACH_PORT_NULL, to + 100, MACH_PORT_NULL);
dcace88f 952 switch (smr) {
eabd1701
A
953 case MACH_SEND_TIMED_OUT:
954 launchd_syslog(LOG_WARNING, "Timed out while trying to send reply to exception message.");
955 break;
956 case MACH_SEND_INVALID_DEST:
957 launchd_syslog(LOG_WARNING, "Tried sending a message to a port that we don't possess a send right to.");
958 break;
959 default:
960 if (smr) {
961 launchd_syslog(LOG_WARNING, "Couldn't deliver exception reply: 0x%x", smr);
962 }
963 break;
ddbbfbc1
A
964 }
965 }
dcace88f 966 } while (0);
eabd1701 967
ddbbfbc1 968 return mr;
5b0a4722
A
969}
970
971void
eabd1701 972runtime_record_caller_creds(audit_token_t *token)
5b0a4722 973{
95379394 974 (void)memcpy(&ldc_token, token, sizeof(*token));
eabd1701
A
975 audit_token_to_au32(*token, NULL, &ldc.euid,&ldc.egid, &ldc.uid, &ldc.gid,
976 &ldc.pid, &ldc.asid, NULL);
977}
5b0a4722 978
eabd1701
A
979struct ldcred *
980runtime_get_caller_creds(void)
981{
982 return &ldc;
983}
5b0a4722 984
95379394
A
985audit_token_t *
986runtime_get_caller_token(void)
987{
988 return &ldc_token;
989}
990
eabd1701
A
991static boolean_t
992launchd_mig_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
993{
994 boolean_t result = false;
5b0a4722 995
eabd1701
A
996 time_of_mach_msg_return = runtime_get_opaque_time();
997 launchd_syslog(LOG_DEBUG, "MIG callout: %u", request->msgh_id);
998 mig_callback the_demux = mig_cb_table[MACH_PORT_INDEX(request->msgh_local_port)];
999 mach_msg_audit_trailer_t *tp = (mach_msg_audit_trailer_t *)((vm_offset_t)request + round_msg(request->msgh_size));
1000 runtime_record_caller_creds(&tp->msgh_audit);
5b0a4722 1001
eabd1701
A
1002 result = the_demux(request, reply);
1003 if (!result) {
1004 launchd_syslog(LOG_DEBUG, "Demux failed. Trying other subsystems...");
1005 if (request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
1006 launchd_syslog(LOG_DEBUG, "MACH_NOTIFY_NO_SENDERS");
1007 result = notify_server(request, reply);
1008 } else if (the_demux == job_server) {
1009 launchd_syslog(LOG_DEBUG, "Trying domain subsystem...");
1010 result = xpc_domain_server(request, reply);
1011 } else {
1012 launchd_syslog(LOG_ERR, "Cannot handle MIG request with ID: 0x%x", request->msgh_id);
5b0a4722 1013 }
eabd1701
A
1014 } else {
1015 launchd_syslog(LOG_DEBUG, "MIG demux succeeded.");
1016 }
5b0a4722 1017
eabd1701
A
1018 return result;
1019}
5b0a4722 1020
eabd1701
A
1021void
1022launchd_runtime2(mach_msg_size_t msg_size)
1023{
1024 for (;;) {
1025 launchd_log_push();
1026
1027 mach_port_t recvp = MACH_PORT_NULL;
1028 xpc_object_t request = NULL;
1029 int result = xpc_pipe_try_receive(ipc_port_set, &request, &recvp, launchd_mig_demux, msg_size, 0);
1030 if (result == 0 && request) {
95379394 1031 boolean_t handled = false;
eabd1701
A
1032 time_of_mach_msg_return = runtime_get_opaque_time();
1033 launchd_syslog(LOG_DEBUG, "XPC request.");
1034
1035 xpc_object_t reply = NULL;
95379394
A
1036 if (xpc_event_demux(recvp, request, &reply)) {
1037 handled = true;
1038 } else if (xpc_process_demux(recvp, request, &reply)) {
1039 handled = true;
1040 }
1041
1042 if (!handled) {
eabd1701
A
1043 launchd_syslog(LOG_DEBUG, "XPC routine could not be handled.");
1044 xpc_release(request);
1045 continue;
ddbbfbc1 1046 }
5b0a4722 1047
eabd1701
A
1048 launchd_syslog(LOG_DEBUG, "XPC routine was handled.");
1049 if (reply) {
1050 launchd_syslog(LOG_DEBUG, "Sending reply.");
1051 result = xpc_pipe_routine_reply(reply);
1052 if (result == 0) {
1053 launchd_syslog(LOG_DEBUG, "Reply sent successfully.");
1054 } else if (result != EPIPE) {
1055 launchd_syslog(LOG_ERR, "Failed to send reply message: 0x%x", result);
dcace88f 1056 }
5b0a4722 1057
eabd1701 1058 xpc_release(reply);
5b0a4722 1059 }
5b0a4722 1060
eabd1701
A
1061 xpc_release(request);
1062 } else if (result == 0) {
1063 launchd_syslog(LOG_DEBUG, "MIG request.");
1064 } else if (result == EINVAL) {
1065 launchd_syslog(LOG_ERR, "Rejected invalid request message.");
5b0a4722
A
1066 }
1067 }
1068}
1069
1070int
1071runtime_close(int fd)
1072{
1073 int i;
1074
1075 if (bulk_kev) for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
1076 switch (bulk_kev[i].filter) {
1077 case EVFILT_VNODE:
1078 case EVFILT_WRITE:
1079 case EVFILT_READ:
ddbbfbc1 1080 if (unlikely((int)bulk_kev[i].ident == fd)) {
eabd1701 1081 launchd_syslog(LOG_DEBUG, "Skipping kevent index: %d", i);
5b0a4722
A
1082 bulk_kev[i].filter = 0;
1083 }
1084 default:
1085 break;
1086 }
1087 }
1088
1089 return close(fd);
1090}
1091
5b0a4722
A
1092int
1093runtime_fsync(int fd)
1094{
ddbbfbc1 1095#if 0
eabd1701 1096 if (launchd_apple_internal) {
5b0a4722
A
1097 return fcntl(fd, F_FULLFSYNC, NULL);
1098 } else {
1099 return fsync(fd);
1100 }
ddbbfbc1
A
1101#else
1102 return fsync(fd);
1103#endif
5b0a4722
A
1104}
1105
5b0a4722
A
1106/*
1107 * We should break this into two reference counts.
1108 *
1109 * One for hard references that would prevent exiting.
1110 * One for soft references that would only prevent idle exiting.
1111 *
1112 * In the long run, reference counting should completely automate when a
1113 * process can and should exit.
1114 */
1115void
1116runtime_add_ref(void)
1117{
ddbbfbc1 1118 if (!pid1_magic) {
eabd1701
A
1119#if !TARGET_OS_EMBEDDED
1120 vproc_transaction_begin(NULL);
1121#endif
ddbbfbc1 1122 }
eabd1701 1123
5b0a4722 1124 runtime_busy_cnt++;
eabd1701 1125 launchd_syslog(LOG_PERF, "Incremented busy count. Now: %lu", runtime_busy_cnt);
587e987e 1126 runtime_remove_timer();
5b0a4722
A
1127}
1128
1129void
1130runtime_del_ref(void)
1131{
ddbbfbc1 1132 if (!pid1_magic) {
eabd1701 1133#if !TARGET_OS_EMBEDDED
dcace88f 1134 if (_vproc_transaction_count() == 0) {
eabd1701 1135 launchd_syslog(LOG_PERF, "Exiting cleanly.");
ddbbfbc1 1136 }
eabd1701
A
1137
1138 vproc_transaction_end(NULL, NULL);
1139#endif
ddbbfbc1 1140 }
eabd1701 1141
5b0a4722 1142 runtime_busy_cnt--;
eabd1701 1143 launchd_syslog(LOG_PERF, "Decremented busy count. Now: %lu", runtime_busy_cnt);
587e987e 1144 runtime_install_timer();
5b0a4722 1145}
fe044cc9 1146
ddbbfbc1
A
1147void
1148runtime_add_weak_ref(void)
1149{
1150 if (!pid1_magic) {
eabd1701 1151#if !TARGET_OS_EMBEDDED
ddbbfbc1 1152 _vproc_standby_begin();
eabd1701 1153#endif
ddbbfbc1
A
1154 }
1155 runtime_standby_cnt++;
1156}
1157
1158void
1159runtime_del_weak_ref(void)
1160{
1161 if (!pid1_magic) {
eabd1701 1162#if !TARGET_OS_EMBEDDED
ddbbfbc1 1163 _vproc_standby_end();
eabd1701 1164#endif
ddbbfbc1
A
1165 }
1166 runtime_standby_cnt--;
1167}
1168
587e987e
A
1169void
1170runtime_install_timer(void)
1171{
dcace88f 1172 if (!pid1_magic && runtime_busy_cnt == 0) {
eabd1701
A
1173 launchd_syslog(LOG_PERF, "Gone idle. Installing idle-exit timer.");
1174 (void)posix_assumes_zero(kevent_mod((uintptr_t)&launchd_runtime_busy_time, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 10, root_jobmgr));
587e987e
A
1175 }
1176}
1177
1178void
1179runtime_remove_timer(void)
1180{
dcace88f 1181 if (!pid1_magic && runtime_busy_cnt > 0) {
eabd1701
A
1182 if (runtime_busy_cnt == 1) {
1183 launchd_syslog(LOG_PERF, "No longer idle. Removing idle-exit timer.");
1184 }
1185 (void)posix_assumes_zero(kevent_mod((uintptr_t)&launchd_runtime_busy_time, EVFILT_TIMER, EV_DELETE, 0, 0, NULL));
587e987e
A
1186 }
1187}
1188
fe044cc9 1189kern_return_t
ddbbfbc1
A
1190catch_mach_exception_raise(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
1191 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt)
fe044cc9 1192{
ddbbfbc1 1193 pid_t p4t = -1;
fe044cc9 1194
95379394 1195 (void)os_assumes_zero(pid_for_task(task, &p4t));
eabd1701
A
1196
1197 launchd_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
ddbbfbc1 1198 __func__, p4t, thread, exception, code, codeCnt);
eabd1701 1199
95379394
A
1200 (void)os_assumes_zero(launchd_mport_deallocate(thread));
1201 (void)os_assumes_zero(launchd_mport_deallocate(task));
fe044cc9 1202
ddbbfbc1 1203 return KERN_SUCCESS;
fe044cc9
A
1204}
1205
1206kern_return_t
ddbbfbc1
A
1207catch_mach_exception_raise_state(mach_port_t exception_port __attribute__((unused)),
1208 exception_type_t exception, const mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1209 int *flavor, const thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1210 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
fe044cc9 1211{
eabd1701 1212 launchd_syslog(LOG_NOTICE, "%s(): type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
fe044cc9 1213 __func__, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
eabd1701 1214
fe044cc9
A
1215 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1216 *new_stateCnt = old_stateCnt;
1217
ddbbfbc1 1218 return KERN_SUCCESS;
fe044cc9
A
1219}
1220
1221kern_return_t
ddbbfbc1
A
1222catch_mach_exception_raise_state_identity(mach_port_t exception_port __attribute__((unused)), mach_port_t thread, mach_port_t task,
1223 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1224 int *flavor, thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1225 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
fe044cc9 1226{
ddbbfbc1
A
1227 pid_t p4t = -1;
1228
95379394 1229 (void)os_assumes_zero(pid_for_task(task, &p4t));
fe044cc9 1230
eabd1701 1231 launchd_syslog(LOG_NOTICE, "%s(): PID: %u thread: 0x%x type: 0x%x code: %p codeCnt: 0x%x flavor: %p old_state: %p old_stateCnt: 0x%x new_state: %p new_stateCnt: %p",
ddbbfbc1 1232 __func__, p4t, thread, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
eabd1701 1233
fe044cc9
A
1234 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1235 *new_stateCnt = old_stateCnt;
1236
95379394
A
1237 (void)os_assumes_zero(launchd_mport_deallocate(thread));
1238 (void)os_assumes_zero(launchd_mport_deallocate(task));
fe044cc9 1239
ddbbfbc1
A
1240 return KERN_SUCCESS;
1241}
1242
95379394
A
1243// FIXME: should this be thread safe? With dispatch_once?
1244uint64_t
1245runtime_get_uniqueid(void)
1246{
1247 static bool once;
1248 static uint64_t uniqueid;
1249 if (unlikely(!once)) {
1250 once = true;
1251
1252 struct proc_uniqidentifierinfo info;
1253 int size;
1254 size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 0, &info, sizeof(info));
1255 if (size == PROC_PIDUNIQIDENTIFIERINFO_SIZE) {
1256 uniqueid = info.p_uniqueid;
1257 }
1258 }
1259 return uniqueid;
1260}
1261
ddbbfbc1
A
1262void
1263launchd_log_vm_stats(void)
1264{
1265 static struct vm_statistics orig_stats;
1266 static bool did_first_pass;
1267 unsigned int count = HOST_VM_INFO_COUNT;
1268 struct vm_statistics stats, *statsp;
1269 mach_port_t mhs = mach_host_self();
1270
1271 statsp = did_first_pass ? &stats : &orig_stats;
1272
95379394 1273 if (os_assumes_zero(host_statistics(mhs, HOST_VM_INFO, (host_info_t)statsp, &count)) != KERN_SUCCESS) {
ddbbfbc1
A
1274 return;
1275 }
1276
eabd1701 1277 if (count != HOST_VM_INFO_COUNT) {
95379394 1278 (void)os_assumes_zero(count);
eabd1701 1279 }
ddbbfbc1
A
1280
1281 if (did_first_pass) {
eabd1701 1282 launchd_syslog(LOG_DEBUG, "VM statistics (now - orig): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
ddbbfbc1
A
1283 stats.free_count - orig_stats.free_count,
1284 stats.active_count - orig_stats.active_count,
1285 stats.inactive_count - orig_stats.inactive_count,
1286 stats.reactivations - orig_stats.reactivations,
1287 stats.pageins - orig_stats.pageins,
1288 stats.pageouts - orig_stats.pageouts,
1289 stats.faults - orig_stats.faults,
1290 stats.cow_faults - orig_stats.cow_faults,
1291 stats.purgeable_count - orig_stats.purgeable_count,
1292 stats.purges - orig_stats.purges);
1293 } else {
eabd1701 1294 launchd_syslog(LOG_DEBUG, "VM statistics (now): Free: %d Active: %d Inactive: %d Reactivations: %d PageIns: %d PageOuts: %d Faults: %d COW-Faults: %d Purgeable: %d Purges: %d",
ddbbfbc1
A
1295 orig_stats.free_count,
1296 orig_stats.active_count,
1297 orig_stats.inactive_count,
1298 orig_stats.reactivations,
1299 orig_stats.pageins,
1300 orig_stats.pageouts,
1301 orig_stats.faults,
1302 orig_stats.cow_faults,
1303 orig_stats.purgeable_count,
1304 orig_stats.purges);
1305
1306 did_first_pass = true;
1307 }
1308
1309 launchd_mport_deallocate(mhs);
1310}
1311
1312int64_t
1313runtime_get_wall_time(void)
1314{
1315 struct timeval tv;
1316 int64_t r;
1317
eabd1701 1318 (void)posix_assumes_zero(gettimeofday(&tv, NULL));
ddbbfbc1
A
1319
1320 r = tv.tv_sec;
1321 r *= USEC_PER_SEC;
1322 r += tv.tv_usec;
1323
1324 return r;
1325}
1326
1327uint64_t
1328runtime_get_opaque_time(void)
1329{
1330 return mach_absolute_time();
1331}
1332
1333uint64_t
1334runtime_get_opaque_time_of_event(void)
1335{
1336 return time_of_mach_msg_return;
1337}
1338
1339uint64_t
1340runtime_get_nanoseconds_since(uint64_t o)
1341{
1342 return runtime_opaque_time_to_nano(runtime_get_opaque_time_of_event() - o);
1343}
1344
1345uint64_t
1346runtime_opaque_time_to_nano(uint64_t o)
1347{
1348#if defined(__i386__) || defined(__x86_64__)
1349 if (unlikely(tbi.numer != tbi.denom)) {
1350#elif defined(__ppc__) || defined(__ppc64__)
1351 if (likely(tbi.numer != tbi.denom)) {
1352#else
1353 if (tbi.numer != tbi.denom) {
1354#endif
1355#ifdef __LP64__
1356 __uint128_t tmp = o;
1357 tmp *= tbi.numer;
1358 tmp /= tbi.denom;
1359 o = tmp;
1360#else
1361 if (o <= tbi_safe_math_max) {
1362 o *= tbi.numer;
1363 o /= tbi.denom;
1364 } else {
1365 double d = o;
1366 d *= tbi_float_val;
1367 o = d;
1368 }
1369#endif
1370 }
1371
1372 return o;
1373}
1374
1375void
1376do_file_init(void)
1377{
1378 struct stat sb;
1379
95379394 1380 os_assert_zero(mach_timebase_info(&tbi));
ddbbfbc1
A
1381 tbi_float_val = tbi.numer;
1382 tbi_float_val /= tbi.denom;
1383 tbi_safe_math_max = UINT64_MAX / tbi.numer;
1384
eabd1701
A
1385 launchd_system_start = runtime_get_wall_time();
1386
ddbbfbc1
A
1387 if (getpid() == 1) {
1388 pid1_magic = true;
1389 }
1390
1391 if (stat("/AppleInternal", &sb) == 0 && stat("/var/db/disableAppleInternal", &sb) == -1) {
eabd1701 1392 launchd_apple_internal = true;
ddbbfbc1
A
1393 }
1394
eabd1701
A
1395 if (config_check(".launchd_use_gmalloc", sb)) {
1396 launchd_use_gmalloc = true;
ddbbfbc1 1397 }
eabd1701
A
1398
1399 if (config_check(".launchd_log_shutdown", sb)) {
1400 launchd_log_shutdown = true;
ddbbfbc1 1401 }
eabd1701
A
1402
1403 if (config_check(".launchd_log_debug", sb)) {
1404 launchd_log_debug = true;
ddbbfbc1 1405 }
dcace88f 1406
eabd1701
A
1407 if (config_check(".launchd_log_perf", sb)) {
1408 launchd_log_perf = true;
dcace88f 1409 }
eabd1701
A
1410
1411 if (config_check("/etc/rc.cdrom", sb)) {
1412 launchd_osinstaller = true;
ddbbfbc1 1413 }
eabd1701
A
1414
1415 if (!pid1_magic && config_check(".launchd_allow_global_dyld_envvars", sb)) {
1416 launchd_allow_global_dyld_envvars = true;
1417 }
1418
95379394
A
1419 char buff[1024];
1420 size_t len = sizeof(buff) - 1;
1421 int r = pid1_magic ? sysctlbyname("kern.bootargs", buff, &len, NULL, 0) : -1;
dcace88f 1422 if (r == 0) {
95379394 1423 if (strnstr(buff, "-v", len)) {
eabd1701 1424 launchd_verbose_boot = true;
dcace88f 1425 }
95379394 1426 if (strnstr(buff, "launchd_trap_sigkill_bugs", len)) {
eabd1701 1427 launchd_trap_sigkill_bugs = true;
dcace88f 1428 }
95379394
A
1429 if (strnstr(buff, "launchd_no_jetsam_perm_check", len)) {
1430 launchd_no_jetsam_perm_check = true;
1431 }
1432 }
1433
1434 len = sizeof(buff) - 1;
1435#if TARGET_OS_EMBEDDED
1436 r = sysctlbyname("hw.machine", buff, &len, NULL, 0);
1437 if (r == 0) {
1438 if (strnstr(buff, "AppleTV", len)) {
1439 launchd_appletv = true;
1440 }
ddbbfbc1 1441 }
95379394 1442#endif
eabd1701 1443
95379394 1444#if !TARGET_OS_EMBEDDED
eabd1701
A
1445 if (pid1_magic && launchd_verbose_boot && config_check(".launchd_shutdown_debugging", sb)) {
1446 launchd_shutdown_debugging = true;
ddbbfbc1 1447 }
95379394
A
1448#else
1449 if (pid1_magic && config_check(".launchd_shutdown_debugging", sb)) {
1450 launchd_shutdown_debugging = true;
1451 }
1452#endif
fe044cc9 1453}