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