]> git.saurik.com Git - apple/launchd.git/blame - launchd/src/launchd_runtime.c
launchd-258.1.tar.gz
[apple/launchd.git] / launchd / src / launchd_runtime.c
CommitLineData
5b0a4722
A
1/*
2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
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
fe044cc9 21static const char *const __rcs_file_version__ = "$Revision: 23459 $";
5b0a4722
A
22
23#include "config.h"
24#include "launchd_runtime.h"
25
26#include <mach/mach.h>
27#include <mach/mach_error.h>
28#include <mach/boolean.h>
29#include <mach/message.h>
30#include <mach/notify.h>
31#include <mach/mig_errors.h>
32#include <mach/mach_traps.h>
33#include <mach/mach_interface.h>
34#include <mach/host_info.h>
35#include <mach/mach_host.h>
36#include <mach/exception.h>
37#include <sys/types.h>
38#include <sys/stat.h>
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>
47#include <bsm/libbsm.h>
48#include <malloc/malloc.h>
49#include <unistd.h>
50#include <pthread.h>
51#include <errno.h>
52#include <string.h>
53#include <ctype.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <stdbool.h>
57#include <syslog.h>
58#include <signal.h>
59#include <dlfcn.h>
60
61#include "launchd_internalServer.h"
62#include "launchd_internal.h"
63#include "notifyServer.h"
fe044cc9 64#include "mach_excServer.h"
5b0a4722
A
65
66/* We shouldn't be including these */
67#include "launch.h"
68#include "launchd.h"
69#include "launchd_core_logic.h"
70#include "libvproc_internal.h"
71#include "job_reply.h"
72
73static mach_port_t ipc_port_set;
74static mach_port_t demand_port_set;
75static mach_port_t launchd_internal_port;
76static int mainkq;
77
78#define BULK_KEV_MAX 100
79static struct kevent *bulk_kev;
80static int bulk_kev_i;
81static int bulk_kev_cnt;
82
83static pthread_t kqueue_demand_thread;
84static pthread_t demand_thread;
85
86static void *mport_demand_loop(void *arg);
87static void *kqueue_demand_loop(void *arg);
88static void log_kevent_struct(int level, struct kevent *kev, int indx);
89
fe044cc9 90static boolean_t launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply);
5b0a4722
A
91static void record_caller_creds(mach_msg_header_t *mh);
92static void launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply);
93static mach_msg_size_t max_msg_size;
94static mig_callback *mig_cb_table;
95static size_t mig_cb_table_sz;
96static timeout_callback runtime_idle_callback;
97static mach_msg_timeout_t runtime_idle_timeout;
98static audit_token_t *au_tok;
99static size_t runtime_busy_cnt;
100
101
102static STAILQ_HEAD(, logmsg_s) logmsg_queue = STAILQ_HEAD_INITIALIZER(logmsg_queue);
103static size_t logmsg_queue_sz;
104static size_t logmsg_queue_cnt;
105static mach_port_t drain_reply_port;
106static void runtime_log_uncork_pending_drain(void);
107static kern_return_t runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt);
108static void runtime_log_push(void);
109
110static bool logmsg_add(struct runtime_syslog_attr *attr, int err_num, const char *msg);
111static void logmsg_remove(struct logmsg_s *lm);
112
113
114static const int sigigns[] = { SIGHUP, SIGINT, SIGPIPE, SIGALRM, SIGTERM,
115 SIGURG, SIGTSTP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU, SIGIO, SIGXCPU,
116 SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2
117};
118static sigset_t sigign_set;
119
fe044cc9
A
120mach_port_t
121runtime_get_kernel_port(void)
122{
123 return launchd_internal_port;
124}
125
5b0a4722
A
126void
127launchd_runtime_init(void)
128{
129 mach_msg_size_t mxmsgsz;
130 pthread_attr_t attr;
131
132 launchd_assert((mainkq = kqueue()) != -1);
133
134 launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &demand_port_set)) == KERN_SUCCESS);
135 launchd_assert((errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &ipc_port_set)) == KERN_SUCCESS);
136
137 launchd_assert(launchd_mport_create_recv(&launchd_internal_port) == KERN_SUCCESS);
138 launchd_assert(launchd_mport_make_send(launchd_internal_port) == KERN_SUCCESS);
139
140 /* Sigh... at the moment, MIG has maxsize == sizeof(reply union) */
141 mxmsgsz = sizeof(union __RequestUnion__x_launchd_internal_subsystem);
142 if (x_launchd_internal_subsystem.maxsize > mxmsgsz) {
143 mxmsgsz = x_launchd_internal_subsystem.maxsize;
144 }
145
146 launchd_assert(runtime_add_mport(launchd_internal_port, launchd_internal_demux, mxmsgsz) == KERN_SUCCESS);
147
148 pthread_attr_init(&attr);
149 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
150 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
151 launchd_assert(pthread_create(&kqueue_demand_thread, &attr, kqueue_demand_loop, NULL) == 0);
152 pthread_attr_destroy(&attr);
153
154 pthread_attr_init(&attr);
155 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
156 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
157 launchd_assert(pthread_create(&demand_thread, &attr, mport_demand_loop, NULL) == 0);
158 pthread_attr_destroy(&attr);
159}
160
161void
162launchd_runtime_init2(void)
163{
164 size_t i;
165
166 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
167 sigaddset(&sigign_set, sigigns[i]);
168 launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
169 }
170}
171
172void *
173mport_demand_loop(void *arg __attribute__((unused)))
174{
175 mach_msg_empty_rcv_t dummy;
176 kern_return_t kr;
177
178 for (;;) {
179 kr = mach_msg(&dummy.header, MACH_RCV_MSG|MACH_RCV_LARGE, 0, 0, demand_port_set, 0, MACH_PORT_NULL);
180 if (kr == MACH_RCV_PORT_CHANGED) {
181 break;
182 } else if (!launchd_assumes(kr == MACH_RCV_TOO_LARGE)) {
183 continue;
184 }
185 launchd_assumes(handle_mport(launchd_internal_port) == 0);
186 }
187
188 return NULL;
189}
190
191const char *
192proc_flags_to_C_names(unsigned int flags)
193{
194#define MAX_PFLAG_STR "P_ADVLOCK|P_CONTROLT|P_LP64|P_NOCLDSTOP|P_PPWAIT|P_PROFIL|P_SELECT|P_CONTINUED|P_SUGID|P_SYSTEM|P_TIMEOUT|P_TRACED|P_RESV3|P_WEXIT|P_EXEC|P_OWEUPC|P_AFFINITY|P_TRANSLATED|P_RESV5|P_CHECKOPENEVT|P_DEPENDENCY_CAPABLE|P_REBOOT|P_TBE|P_RESV7|P_THCWD|P_RESV9|P_RESV10|P_RESV11|P_NOSHLIB|P_FORCEQUOTA|P_NOCLDWAIT|P_NOREMOTEHANG|0xdeadbeeffeedface"
195
196 static char flags_buf[sizeof(MAX_PFLAG_STR)];
197 char *flags_off = NULL;
198
199 if (!flags) {
200 return "";
201 }
202
203 while (flags) {
204 if (flags_off) {
205 *flags_off = '|';
206 flags_off++;
207 *flags_off = '\0';
208 } else {
209 flags_off = flags_buf;
210 }
211
212#define FLAGIF(f) if (flags & f) { flags_off += sprintf(flags_off, #f); flags &= ~f; }
213
214 FLAGIF(P_ADVLOCK)
215 else FLAGIF(P_CONTROLT)
216 else FLAGIF(P_LP64)
217 else FLAGIF(P_NOCLDSTOP)
218 else FLAGIF(P_PPWAIT)
219 else FLAGIF(P_PROFIL)
220 else FLAGIF(P_SELECT)
221 else FLAGIF(P_CONTINUED)
222 else FLAGIF(P_SUGID)
223 else FLAGIF(P_SYSTEM)
224 else FLAGIF(P_TIMEOUT)
225 else FLAGIF(P_TRACED)
226 else FLAGIF(P_RESV3)
227 else FLAGIF(P_WEXIT)
228 else FLAGIF(P_EXEC)
229 else FLAGIF(P_OWEUPC)
230 else FLAGIF(P_AFFINITY)
231 else FLAGIF(P_TRANSLATED)
232 else FLAGIF(P_RESV5)
233 else FLAGIF(P_CHECKOPENEVT)
234 else FLAGIF(P_DEPENDENCY_CAPABLE)
235 else FLAGIF(P_REBOOT)
236 else FLAGIF(P_TBE)
237 else FLAGIF(P_RESV7)
238 else FLAGIF(P_THCWD)
239 else FLAGIF(P_RESV9)
240 else FLAGIF(P_RESV10)
241 else FLAGIF(P_RESV11)
242 else FLAGIF(P_NOSHLIB)
243 else FLAGIF(P_FORCEQUOTA)
244 else FLAGIF(P_NOCLDWAIT)
245 else FLAGIF(P_NOREMOTEHANG)
246 else {
247 flags_off += sprintf(flags_off, "0x%x", flags);
248 flags = 0;
249 }
250 }
251
252 return flags_buf;
253}
254
255const char *
256reboot_flags_to_C_names(unsigned int flags)
257{
258#define MAX_RB_STR "RB_ASKNAME|RB_SINGLE|RB_NOSYNC|RB_KDB|RB_HALT|RB_INITNAME|RB_DFLTROOT|RB_ALTBOOT|RB_UNIPROC|RB_SAFEBOOT|RB_UPSDELAY|0xdeadbeeffeedface"
259 static char flags_buf[sizeof(MAX_RB_STR)];
260 char *flags_off = NULL;
261
fe044cc9
A
262 if (flags == 0) {
263 return "RB_AUTOBOOT";
264 }
265
266 while (flags) {
5b0a4722
A
267 if (flags_off) {
268 *flags_off = '|';
269 flags_off++;
270 *flags_off = '\0';
271 } else {
272 flags_off = flags_buf;
273 }
274
275 FLAGIF(RB_ASKNAME)
276 else FLAGIF(RB_SINGLE)
277 else FLAGIF(RB_NOSYNC)
278 else FLAGIF(RB_KDB)
279 else FLAGIF(RB_HALT)
280 else FLAGIF(RB_INITNAME)
281 else FLAGIF(RB_DFLTROOT)
282 else FLAGIF(RB_ALTBOOT)
283 else FLAGIF(RB_UNIPROC)
284 else FLAGIF(RB_SAFEBOOT)
285 else FLAGIF(RB_UPSDELAY)
286 else {
287 flags_off += sprintf(flags_off, "0x%x", flags);
288 flags = 0;
289 }
5b0a4722 290 }
fe044cc9
A
291
292 return flags_buf;
5b0a4722
A
293}
294
295const char *
296signal_to_C_name(unsigned int sig)
297{
298 static char unknown[25];
299
300#define SIG2CASE(sg) case sg: return #sg
301
302 switch (sig) {
303 SIG2CASE(SIGHUP);
304 SIG2CASE(SIGINT);
305 SIG2CASE(SIGQUIT);
306 SIG2CASE(SIGILL);
307 SIG2CASE(SIGTRAP);
308 SIG2CASE(SIGABRT);
309 SIG2CASE(SIGFPE);
310 SIG2CASE(SIGKILL);
311 SIG2CASE(SIGBUS);
312 SIG2CASE(SIGSEGV);
313 SIG2CASE(SIGSYS);
314 SIG2CASE(SIGPIPE);
315 SIG2CASE(SIGALRM);
316 SIG2CASE(SIGTERM);
317 SIG2CASE(SIGURG);
318 SIG2CASE(SIGSTOP);
319 SIG2CASE(SIGTSTP);
320 SIG2CASE(SIGCONT);
321 SIG2CASE(SIGCHLD);
322 SIG2CASE(SIGTTIN);
323 SIG2CASE(SIGTTOU);
324 SIG2CASE(SIGIO);
325 SIG2CASE(SIGXCPU);
326 SIG2CASE(SIGXFSZ);
327 SIG2CASE(SIGVTALRM);
328 SIG2CASE(SIGPROF);
329 SIG2CASE(SIGWINCH);
330 SIG2CASE(SIGINFO);
331 SIG2CASE(SIGUSR1);
332 SIG2CASE(SIGUSR2);
333 default:
334 snprintf(unknown, sizeof(unknown), "%u", sig);
335 return unknown;
336 }
337}
338
339void
340log_kevent_struct(int level, struct kevent *kev, int indx)
341{
342 const char *filter_str;
343 char ident_buf[100];
344 char filter_buf[100];
345 char fflags_buf[1000];
346 char flags_buf[1000] = "0x0";
347 char *flags_off = NULL;
348 char *fflags_off = NULL;
349 unsigned short flags = kev->flags;
350 unsigned int fflags = kev->fflags;
351
352 if (flags) while (flags) {
353 if (flags_off) {
354 *flags_off = '|';
355 flags_off++;
356 *flags_off = '\0';
357 } else {
358 flags_off = flags_buf;
359 }
360
361 FLAGIF(EV_ADD)
362 else FLAGIF(EV_RECEIPT)
363 else FLAGIF(EV_DELETE)
364 else FLAGIF(EV_ENABLE)
365 else FLAGIF(EV_DISABLE)
366 else FLAGIF(EV_CLEAR)
367 else FLAGIF(EV_EOF)
368 else FLAGIF(EV_ONESHOT)
369 else FLAGIF(EV_ERROR)
370 else {
371 flags_off += sprintf(flags_off, "0x%x", flags);
372 flags = 0;
373 }
374 }
375
376 snprintf(ident_buf, sizeof(ident_buf), "%ld", kev->ident);
377 snprintf(fflags_buf, sizeof(fflags_buf), "0x%x", fflags);
378
379 switch (kev->filter) {
380 case EVFILT_READ:
381 filter_str = "EVFILT_READ";
382 break;
383 case EVFILT_WRITE:
384 filter_str = "EVFILT_WRITE";
385 break;
386 case EVFILT_AIO:
387 filter_str = "EVFILT_AIO";
388 break;
389 case EVFILT_VNODE:
390 filter_str = "EVFILT_VNODE";
391 if (fflags) while (fflags) {
392 if (fflags_off) {
393 *fflags_off = '|';
394 fflags_off++;
395 *fflags_off = '\0';
396 } else {
397 fflags_off = fflags_buf;
398 }
399
400#define FFLAGIF(ff) if (fflags & ff) { fflags_off += sprintf(fflags_off, #ff); fflags &= ~ff; }
401
402 FFLAGIF(NOTE_DELETE)
403 else FFLAGIF(NOTE_WRITE)
404 else FFLAGIF(NOTE_EXTEND)
405 else FFLAGIF(NOTE_ATTRIB)
406 else FFLAGIF(NOTE_LINK)
407 else FFLAGIF(NOTE_RENAME)
408 else FFLAGIF(NOTE_REVOKE)
409 else {
410 fflags_off += sprintf(fflags_off, "0x%x", fflags);
411 fflags = 0;
412 }
413 }
414 break;
415 case EVFILT_PROC:
416 filter_str = "EVFILT_PROC";
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_EXIT)
427 else FFLAGIF(NOTE_REAP)
428 else FFLAGIF(NOTE_FORK)
429 else FFLAGIF(NOTE_EXEC)
430 else FFLAGIF(NOTE_SIGNAL)
431 else FFLAGIF(NOTE_TRACK)
432 else FFLAGIF(NOTE_TRACKERR)
433 else FFLAGIF(NOTE_CHILD)
434 else {
435 fflags_off += sprintf(fflags_off, "0x%x", fflags);
436 fflags = 0;
437 }
438 }
439 break;
440 case EVFILT_SIGNAL:
441 filter_str = "EVFILT_SIGNAL";
442 strcpy(ident_buf, signal_to_C_name(kev->ident));
443 break;
444 case EVFILT_TIMER:
445 filter_str = "EVFILT_TIMER";
446 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
447 if (fflags) while (fflags) {
448 if (fflags_off) {
449 *fflags_off = '|';
450 fflags_off++;
451 *fflags_off = '\0';
452 } else {
453 fflags_off = fflags_buf;
454 }
455
456 FFLAGIF(NOTE_SECONDS)
457 else FFLAGIF(NOTE_USECONDS)
458 else FFLAGIF(NOTE_NSECONDS)
459 else FFLAGIF(NOTE_ABSOLUTE)
460 else {
461 fflags_off += sprintf(fflags_off, "0x%x", fflags);
462 fflags = 0;
463 }
464 }
465 break;
466 case EVFILT_MACHPORT:
467 filter_str = "EVFILT_MACHPORT";
468 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
469 break;
470 case EVFILT_FS:
471 filter_str = "EVFILT_FS";
472 snprintf(ident_buf, sizeof(ident_buf), "0x%lx", kev->ident);
473 if (fflags) while (fflags) {
474 if (fflags_off) {
475 *fflags_off = '|';
476 fflags_off++;
477 *fflags_off = '\0';
478 } else {
479 fflags_off = fflags_buf;
480 }
481
482 FFLAGIF(VQ_NOTRESP)
483 else FFLAGIF(VQ_NEEDAUTH)
484 else FFLAGIF(VQ_LOWDISK)
485 else FFLAGIF(VQ_MOUNT)
486 else FFLAGIF(VQ_UNMOUNT)
487 else FFLAGIF(VQ_DEAD)
488 else FFLAGIF(VQ_ASSIST)
489 else FFLAGIF(VQ_NOTRESPLOCK)
490 else FFLAGIF(VQ_UPDATE)
491 else {
492 fflags_off += sprintf(fflags_off, "0x%x", fflags);
493 fflags = 0;
494 }
495 }
496 break;
497 default:
498 snprintf(filter_buf, sizeof(filter_buf), "%d", kev->filter);
499 filter_str = filter_buf;
500 break;
501 }
502
503 runtime_syslog(level, "KEVENT[%d]: udata = %p data = 0x%lx ident = %s filter = %s flags = %s fflags = %s",
504 indx, kev->udata, kev->data, ident_buf, filter_str, flags_buf, fflags_buf);
505}
506
507kern_return_t
508x_handle_mport(mach_port_t junk __attribute__((unused)))
509{
510 mach_port_name_array_t members;
511 mach_msg_type_number_t membersCnt;
512 mach_port_status_t status;
513 mach_msg_type_number_t statusCnt;
514 struct kevent kev;
515 unsigned int i;
516
517 if (!launchd_assumes((errno = mach_port_get_set_status(mach_task_self(), demand_port_set, &members, &membersCnt)) == KERN_SUCCESS)) {
518 return 1;
519 }
520
521 for (i = 0; i < membersCnt; i++) {
522 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
523 if (mach_port_get_attributes(mach_task_self(), members[i], MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status,
524 &statusCnt) != KERN_SUCCESS) {
525 continue;
526 }
527 if (status.mps_msgcount) {
528 EV_SET(&kev, members[i], EVFILT_MACHPORT, 0, 0, 0, job_find_by_service_port(members[i]));
529#if 0
530 if (launchd_assumes(kev.udata != NULL)) {
531#endif
532 log_kevent_struct(LOG_DEBUG, &kev, 0);
533 (*((kq_callback *)kev.udata))(kev.udata, &kev);
534#if 0
535 } else {
536 log_kevent_struct(LOG_ERR, &kev);
537 }
538#endif
539 /* the callback may have tainted our ability to continue this for loop */
540 break;
541 }
542 }
543
544 launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)members,
545 (vm_size_t) membersCnt * sizeof(mach_port_name_t)) == KERN_SUCCESS);
546
547 return 0;
548}
549
550void *
551kqueue_demand_loop(void *arg __attribute__((unused)))
552{
553 fd_set rfds;
554
555 /*
556 * Yes, at first glance, calling select() on a kqueue seems silly.
557 *
558 * This avoids a race condition between the main thread and this helper
559 * thread by ensuring that we drain kqueue events on the same thread
560 * that manipulates the kqueue.
561 */
562
563 for (;;) {
564 FD_ZERO(&rfds);
565 FD_SET(mainkq, &rfds);
566 if (launchd_assumes(select(mainkq + 1, &rfds, NULL, NULL, NULL) == 1)) {
567 launchd_assumes(handle_kqueue(launchd_internal_port, mainkq) == 0);
568 }
569 }
570
571 return NULL;
572}
573
574kern_return_t
575x_handle_kqueue(mach_port_t junk __attribute__((unused)), integer_t fd)
576{
577 struct timespec ts = { 0, 0 };
578 struct kevent kev[BULK_KEV_MAX];
579 int i;
580
581 bulk_kev = kev;
582
583 launchd_assumes((bulk_kev_cnt = kevent(fd, NULL, 0, kev, BULK_KEV_MAX, &ts)) != -1);
584
585 if (bulk_kev_cnt > 0) {
586#if 0
587 Dl_info dli;
588
589 if (launchd_assumes(malloc_size(kev.udata) || dladdr(kev.udata, &dli))) {
590#endif
591 for (i = 0; i < bulk_kev_cnt; i++) {
592 log_kevent_struct(LOG_DEBUG, &kev[i], i);
593 }
594 for (i = 0; i < bulk_kev_cnt; i++) {
595 bulk_kev_i = i;
596 if (kev[i].filter) {
597 (*((kq_callback *)kev[i].udata))(kev[i].udata, &kev[i]);
598 }
599 }
600#if 0
601 } else {
602 log_kevent_struct(LOG_ERR, &kev);
603 }
604#endif
605 }
606
607 bulk_kev = NULL;
608
609 return 0;
610}
611
612
613
614void
615launchd_runtime(void)
616{
617 mig_reply_error_t *req = NULL, *resp = NULL;
618 mach_msg_size_t mz = max_msg_size;
619 int flags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE;
620
621 for (;;) {
622 if (req) {
623 launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)req, mz) == KERN_SUCCESS);
624 req = NULL;
625 }
626 if (resp) {
627 launchd_assumes(vm_deallocate(mach_task_self(), (vm_address_t)resp, mz) == KERN_SUCCESS);
628 resp = NULL;
629 }
630
631 mz = max_msg_size;
632
633 if (!launchd_assumes(vm_allocate(mach_task_self(), (vm_address_t *)&req, mz, flags) == KERN_SUCCESS)) {
634 continue;
635 }
636 if (!launchd_assumes(vm_allocate(mach_task_self(), (vm_address_t *)&resp, mz, flags) == KERN_SUCCESS)) {
637 continue;
638 }
639
640 launchd_runtime2(mz, req, resp);
641
642 /* If we get here, max_msg_size probably changed... */
643 }
644}
645
646kern_return_t
647launchd_set_bport(mach_port_t name)
648{
649 return errno = task_set_bootstrap_port(mach_task_self(), name);
650}
651
652kern_return_t
653launchd_get_bport(mach_port_t *name)
654{
655 return errno = task_get_bootstrap_port(mach_task_self(), name);
656}
657
658kern_return_t
659launchd_mport_notify_req(mach_port_t name, mach_msg_id_t which)
660{
fe044cc9 661 mach_port_mscount_t msgc = (which == MACH_NOTIFY_PORT_DESTROYED) ? 0 : 1;
5b0a4722
A
662 mach_port_t previous, where = (which == MACH_NOTIFY_NO_SENDERS) ? name : launchd_internal_port;
663
664 if (which == MACH_NOTIFY_NO_SENDERS) {
665 /* Always make sure the send count is zero, in case a receive right is reused */
666 errno = mach_port_set_mscount(mach_task_self(), name, 0);
667 if (errno != KERN_SUCCESS) {
668 return errno;
669 }
670 }
671
672 errno = mach_port_request_notification(mach_task_self(), name, which, msgc, where,
673 MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
674
675 if (errno == 0 && previous != MACH_PORT_NULL) {
676 launchd_assumes(launchd_mport_deallocate(previous) == KERN_SUCCESS);
677 }
678
679 return errno;
680}
681
682pid_t
683runtime_fork(mach_port_t bsport)
684{
685 sigset_t emptyset, oset;
686 pid_t r = -1;
687 int saved_errno;
688 size_t i;
689
690 sigemptyset(&emptyset);
691
692 launchd_assumes(launchd_mport_make_send(bsport) == KERN_SUCCESS);
693 launchd_assumes(launchd_set_bport(bsport) == KERN_SUCCESS);
694 launchd_assumes(launchd_mport_deallocate(bsport) == KERN_SUCCESS);
695
696 launchd_assumes(sigprocmask(SIG_BLOCK, &sigign_set, &oset) != -1);
697 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
698 launchd_assumes(signal(sigigns[i], SIG_DFL) != SIG_ERR);
699 }
700
701 r = fork();
702 saved_errno = errno;
703
704 if (r != 0) {
705 for (i = 0; i < (sizeof(sigigns) / sizeof(int)); i++) {
706 launchd_assumes(signal(sigigns[i], SIG_IGN) != SIG_ERR);
707 }
708 launchd_assumes(sigprocmask(SIG_SETMASK, &oset, NULL) != -1);
709 launchd_assumes(launchd_set_bport(MACH_PORT_NULL) == KERN_SUCCESS);
710 } else {
711 launchd_assumes(sigprocmask(SIG_SETMASK, &emptyset, NULL) != -1);
712 }
713
714 errno = saved_errno;
715
716 return r;
717}
718
719
720void
721runtime_set_timeout(timeout_callback to_cb, unsigned int sec)
722{
723 if (sec == 0 || to_cb == NULL) {
724 runtime_idle_callback = NULL;
725 runtime_idle_timeout = 0;
726 }
727
728 runtime_idle_callback = to_cb;
729 runtime_idle_timeout = sec * 1000;
730}
731
732kern_return_t
733runtime_add_mport(mach_port_t name, mig_callback demux, mach_msg_size_t msg_size)
734{
735 size_t needed_table_sz = (MACH_PORT_INDEX(name) + 1) * sizeof(mig_callback);
736 mach_port_t target_set = demux ? ipc_port_set : demand_port_set;
737
738 msg_size = round_page(msg_size + MAX_TRAILER_SIZE);
739
740 if (needed_table_sz > mig_cb_table_sz) {
741 needed_table_sz *= 2; /* Let's try and avoid realloc'ing for a while */
742 mig_callback *new_table = malloc(needed_table_sz);
743
744 if (!launchd_assumes(new_table != NULL)) {
745 return KERN_RESOURCE_SHORTAGE;
746 }
747
748 if (mig_cb_table) {
749 memcpy(new_table, mig_cb_table, mig_cb_table_sz);
750 free(mig_cb_table);
751 }
752
753 mig_cb_table_sz = needed_table_sz;
754 mig_cb_table = new_table;
755 }
756
757 mig_cb_table[MACH_PORT_INDEX(name)] = demux;
758
759 if (msg_size > max_msg_size) {
760 max_msg_size = msg_size;
761 }
762
763 return errno = mach_port_move_member(mach_task_self(), name, target_set);
764}
765
766kern_return_t
767runtime_remove_mport(mach_port_t name)
768{
769 mig_cb_table[MACH_PORT_INDEX(name)] = NULL;
770
771 return errno = mach_port_move_member(mach_task_self(), name, MACH_PORT_NULL);
772}
773
774kern_return_t
775launchd_mport_make_send(mach_port_t name)
776{
777 return errno = mach_port_insert_right(mach_task_self(), name, name, MACH_MSG_TYPE_MAKE_SEND);
778}
779
780kern_return_t
781launchd_mport_close_recv(mach_port_t name)
782{
783 return errno = mach_port_mod_refs(mach_task_self(), name, MACH_PORT_RIGHT_RECEIVE, -1);
784}
785
786kern_return_t
787launchd_mport_create_recv(mach_port_t *name)
788{
789 return errno = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, name);
790}
791
792kern_return_t
793launchd_mport_deallocate(mach_port_t name)
794{
795 return errno = mach_port_deallocate(mach_task_self(), name);
796}
797
798int
799kevent_bulk_mod(struct kevent *kev, size_t kev_cnt)
800{
801 size_t i;
802
803 for (i = 0; i < kev_cnt; i++) {
804 kev[i].flags |= EV_CLEAR|EV_RECEIPT;
805 }
806
807 return kevent(mainkq, kev, kev_cnt, kev, kev_cnt, NULL);
808}
809
810int
811kevent_mod(uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata)
812{
813 struct kevent kev;
814 int r;
815
816 switch (filter) {
817 case EVFILT_READ:
818 case EVFILT_WRITE:
819 break;
820 default:
821 flags |= EV_CLEAR;
822 break;
823 }
824
825 flags |= EV_RECEIPT;
826
827 if (flags & EV_ADD && !launchd_assumes(udata != NULL)) {
828 errno = EINVAL;
829 return -1;
830 }
831
832 EV_SET(&kev, ident, filter, flags, fflags, data, udata);
833
834 r = kevent(mainkq, &kev, 1, &kev, 1, NULL);
835
836 if (!launchd_assumes(r == 1)) {
837 return -1;
838 }
839
840 if (launchd_assumes(kev.flags & EV_ERROR)) {
841 if ((flags & EV_ADD) && kev.data) {
842 runtime_syslog(LOG_DEBUG, "%s(): See the next line...", __func__);
843 log_kevent_struct(LOG_DEBUG, &kev, 0);
844 errno = kev.data;
845 return -1;
846 }
847 }
848
849 return r;
850}
851
852boolean_t
853launchd_internal_demux(mach_msg_header_t *Request, mach_msg_header_t *Reply)
854{
855 if (launchd_internal_server_routine(Request)) {
856 return launchd_internal_server(Request, Reply);
fe044cc9
A
857 } else if (notify_server_routine(Request)) {
858 return notify_server(Request, Reply);
859 } else {
860 return mach_exc_server(Request, Reply);
5b0a4722 861 }
5b0a4722
A
862}
863
864kern_return_t
865do_mach_notify_port_destroyed(mach_port_t notify, mach_port_t rights)
866{
867 /* This message is sent to us when a receive right is returned to us. */
868
869 if (!launchd_assumes(job_ack_port_destruction(rights))) {
870 launchd_assumes(launchd_mport_close_recv(rights) == KERN_SUCCESS);
871 }
872
873 return KERN_SUCCESS;
874}
875
876kern_return_t
877do_mach_notify_port_deleted(mach_port_t notify, mach_port_name_t name)
878{
879 /* If we deallocate/destroy/mod_ref away a port with a pending
880 * notification, the original notification message is replaced with
881 * this message. To quote a Mach kernel expert, "the kernel has a
882 * send-once right that has to be used somehow."
883 */
884 return KERN_SUCCESS;
885}
886
887kern_return_t
888do_mach_notify_no_senders(mach_port_t notify, mach_port_mscount_t mscount)
889{
890 job_t j = job_mig_intran(notify);
891
892 /* This message is sent to us when the last customer of one of our
893 * objects goes away.
894 */
895
896 if (!launchd_assumes(j != NULL)) {
897 return KERN_FAILURE;
898 }
899
900 job_ack_no_senders(j);
901
902 return KERN_SUCCESS;
903}
904
905kern_return_t
906do_mach_notify_send_once(mach_port_t notify)
907{
908 /* This message is sent to us every time we close a port that we have
909 * outstanding Mach notification requests on. We can safely ignore this
910 * message.
911 */
912
913 return KERN_SUCCESS;
914}
915
916kern_return_t
917do_mach_notify_dead_name(mach_port_t notify, mach_port_name_t name)
918{
919 /* This message is sent to us when one of our send rights no longer has
920 * a receiver somewhere else on the system.
921 */
922
923 if (name == drain_reply_port) {
924 launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
925 drain_reply_port = MACH_PORT_NULL;
926 }
927
928 if (launchd_assumes(root_jobmgr != NULL)) {
929 root_jobmgr = jobmgr_delete_anything_with_port(root_jobmgr, name);
930 }
931
932 /* A dead-name notification about a port appears to increment the
933 * rights on said port. Let's deallocate it so that we don't leak
934 * dead-name ports.
935 */
936 launchd_assumes(launchd_mport_deallocate(name) == KERN_SUCCESS);
937
938 return KERN_SUCCESS;
939}
940
941void
942record_caller_creds(mach_msg_header_t *mh)
943{
944 mach_msg_max_trailer_t *tp;
945 size_t trailer_size;
946
947 tp = (mach_msg_max_trailer_t *)((vm_offset_t)mh + round_msg(mh->msgh_size));
948
949 trailer_size = tp->msgh_trailer_size - (mach_msg_size_t)(sizeof(mach_msg_trailer_type_t) - sizeof(mach_msg_trailer_size_t));
950
951 if (trailer_size < (mach_msg_size_t)sizeof(audit_token_t)) {
952 au_tok = NULL;
953 return;
954 }
955
956 au_tok = &tp->msgh_audit;
957}
958
959bool
960runtime_get_caller_creds(struct ldcred *ldc)
961{
962 if (!au_tok) {
963 return false;
964 }
965
966 audit_token_to_au32(*au_tok, /* audit UID */ NULL, &ldc->euid,
967 &ldc->egid, &ldc->uid, &ldc->gid, &ldc->pid,
968 &ldc->asid, /* au_tid_t */ NULL);
969
970 return true;
971}
972
973void
974launchd_runtime2(mach_msg_size_t msg_size, mig_reply_error_t *bufRequest, mig_reply_error_t *bufReply)
975{
976 mach_msg_options_t options, tmp_options;
977 mig_reply_error_t *bufTemp;
978 mig_callback the_demux;
979 mach_msg_timeout_t to;
980 mach_msg_return_t mr;
981
982 options = MACH_RCV_MSG|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
983 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
984
985 tmp_options = options;
986
987 for (;;) {
988 to = MACH_MSG_TIMEOUT_NONE;
989
990 if (msg_size != max_msg_size) {
991 /* The buffer isn't big enougth to receive messages anymore... */
992 tmp_options &= ~MACH_RCV_MSG;
993 options &= ~MACH_RCV_MSG;
994 if (!(tmp_options & MACH_SEND_MSG)) {
995 return;
996 }
997 }
998
999 if ((tmp_options & MACH_RCV_MSG) && (runtime_idle_callback || (runtime_busy_cnt == 0))) {
1000 tmp_options |= MACH_RCV_TIMEOUT;
1001
1002 if (!(tmp_options & MACH_SEND_TIMEOUT)) {
1003 to = runtime_busy_cnt ? runtime_idle_timeout : (RUNTIME_ADVISABLE_IDLE_TIMEOUT * 1000);
1004 }
1005 }
1006
1007 runtime_log_push();
1008
1009 mr = mach_msg(&bufReply->Head, tmp_options, bufReply->Head.msgh_size,
1010 msg_size, ipc_port_set, to, MACH_PORT_NULL);
1011
1012 tmp_options = options;
1013
1014 if (mr == MACH_SEND_INVALID_DEST || mr == MACH_SEND_TIMED_OUT) {
1015 /* We need to clean up and start over. */
1016 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1017 mach_msg_destroy(&bufReply->Head);
1018 }
1019 continue;
1020 } else if (mr == MACH_RCV_TIMED_OUT) {
1021 if (to != MACH_MSG_TIMEOUT_NONE) {
1022 if (runtime_busy_cnt == 0) {
1023 launchd_shutdown();
1024 } else if (runtime_idle_callback) {
1025 runtime_idle_callback();
1026 }
1027 }
1028 continue;
1029 } else if (!launchd_assumes(mr == MACH_MSG_SUCCESS)) {
1030 continue;
1031 }
1032
1033 bufTemp = bufRequest;
1034 bufRequest = bufReply;
1035 bufReply = bufTemp;
1036
1037 if (!(tmp_options & MACH_RCV_MSG)) {
1038 continue;
1039 }
1040
1041 /* we have another request message */
1042
1043 if (!launchd_assumes(mig_cb_table != NULL)) {
1044 break;
1045 }
1046
1047 the_demux = mig_cb_table[MACH_PORT_INDEX(bufRequest->Head.msgh_local_port)];
1048
1049 if (!launchd_assumes(the_demux != NULL)) {
1050 break;
1051 }
1052
1053 record_caller_creds(&bufRequest->Head);
1054
1055 /*
1056 * This is a total hack. We really need a bit in the kernel's proc
1057 * struct to declare our intent.
1058 */
1059 static int no_hang_fd = -1;
1060 if (no_hang_fd == -1) {
1061 no_hang_fd = _fd(open("/dev/autofs_nowait", 0));
1062 }
1063
1064 if (the_demux(&bufRequest->Head, &bufReply->Head) == FALSE) {
1065 /* XXX - also gross */
1066 if (bufRequest->Head.msgh_id == MACH_NOTIFY_NO_SENDERS) {
1067 notify_server(&bufRequest->Head, &bufReply->Head);
1068 }
1069 }
1070
1071 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
1072 if (bufReply->RetCode == MIG_NO_REPLY) {
1073 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
1074 } else if ((bufReply->RetCode != KERN_SUCCESS) && (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
1075 /* destroy the request - but not the reply port */
1076 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
1077 mach_msg_destroy(&bufRequest->Head);
1078 }
1079 }
1080
1081 if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
1082 tmp_options |= MACH_SEND_MSG;
1083
1084 if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1085 tmp_options |= MACH_SEND_TIMEOUT;
1086 }
1087 }
1088 }
1089}
1090
1091int
1092runtime_close(int fd)
1093{
1094 int i;
1095
1096 if (bulk_kev) for (i = bulk_kev_i + 1; i < bulk_kev_cnt; i++) {
1097 switch (bulk_kev[i].filter) {
1098 case EVFILT_VNODE:
1099 case EVFILT_WRITE:
1100 case EVFILT_READ:
1101 if ((int)bulk_kev[i].ident == fd) {
1102 runtime_syslog(LOG_DEBUG, "Skipping kevent index: %d", i);
1103 bulk_kev[i].filter = 0;
1104 }
1105 default:
1106 break;
1107 }
1108 }
1109
1110 return close(fd);
1111}
1112
1113static FILE *ourlogfile;
1114
1115void
1116runtime_closelog(void)
1117{
1118 if (ourlogfile) {
1119 launchd_assumes(fflush(ourlogfile) == 0);
1120 launchd_assumes(runtime_fsync(fileno(ourlogfile)) != -1);
1121 }
1122}
1123
1124int
1125runtime_fsync(int fd)
1126{
1127 if (debug_shutdown_hangs) {
1128 return fcntl(fd, F_FULLFSYNC, NULL);
1129 } else {
1130 return fsync(fd);
1131 }
1132}
1133
1134static int internal_mask_pri = LOG_UPTO(LOG_NOTICE);
1135//static int internal_mask_pri = LOG_UPTO(LOG_DEBUG);
1136
1137int
1138runtime_setlogmask(int maskpri)
1139{
1140 internal_mask_pri = maskpri;
1141
1142 return internal_mask_pri;
1143}
1144
1145void
1146runtime_syslog(int pri, const char *message, ...)
1147{
1148 struct runtime_syslog_attr attr = {
1149 "com.apple.launchd", "com.apple.launchd",
1150 getpid() == 1 ? "System" : "Background",
1151 pri, getuid(), getpid(), getpid()
1152 };
1153 va_list ap;
1154
1155 va_start(ap, message);
1156
1157 runtime_vsyslog(&attr, message, ap);
1158
1159 va_end(ap);
1160}
1161
1162void
1163runtime_vsyslog(struct runtime_syslog_attr *attr, const char *message, va_list args)
1164{
1165 static pthread_mutex_t ourlock = PTHREAD_MUTEX_INITIALIZER;
1166 static struct timeval shutdown_start;
1167 static struct timeval prev_msg;
1168 static int apple_internal_logging = 1;
1169 struct timeval tvnow, tvd_total, tvd_msg_delta = { 0, 0 };
1170 struct stat sb;
1171 int saved_errno = errno;
1172 char newmsg[10000];
1173 size_t i, j;
1174
1175 if (!(LOG_MASK(attr->priority) & internal_mask_pri)) {
1176 goto out;
1177 }
1178
1179 if (apple_internal_logging == 1) {
1180 apple_internal_logging = stat("/AppleInternal", &sb);
1181 }
1182
1183
1184 if (!(debug_shutdown_hangs && getpid() == 1)) {
1185 if (attr->priority == LOG_APPLEONLY) {
1186 if (apple_internal_logging == -1) {
1187 goto out;
1188 }
1189 attr->priority = LOG_NOTICE;
1190 }
1191 vsnprintf(newmsg, sizeof(newmsg), message, args);
1192 logmsg_add(attr, saved_errno, newmsg);
1193 goto out;
1194 }
1195
1196 if (shutdown_start.tv_sec == 0) {
1197 gettimeofday(&shutdown_start, NULL);
1198 }
1199
1200 if (gettimeofday(&tvnow, NULL) == -1) {
1201 tvnow.tv_sec = 0;
1202 tvnow.tv_usec = 0;
1203 }
1204
1205 pthread_mutex_lock(&ourlock);
1206
1207 if (ourlogfile == NULL) {
1208 rename("/var/log/launchd-shutdown.log", "/var/log/launchd-shutdown.log.1");
1209 ourlogfile = fopen("/var/log/launchd-shutdown.log", "a");
1210 }
1211
1212 pthread_mutex_unlock(&ourlock);
1213
1214 if (ourlogfile == NULL) {
1215 goto out;
1216 }
1217
1218 if (message == NULL) {
1219 goto out;
1220 }
1221
1222 timersub(&tvnow, &shutdown_start, &tvd_total);
1223
1224 if (prev_msg.tv_sec != 0) {
1225 timersub(&tvnow, &prev_msg, &tvd_msg_delta);
1226 }
1227
1228 prev_msg = tvnow;
1229
1230 snprintf(newmsg, sizeof(newmsg), "%3ld.%06d%4ld.%06d%6u %-40s%6u %-40s ",
1231 tvd_total.tv_sec, tvd_total.tv_usec,
1232 tvd_msg_delta.tv_sec, tvd_msg_delta.tv_usec,
1233 attr->from_pid, attr->from_name,
1234 attr->about_pid, attr->about_name);
1235
1236 for (i = 0, j = strlen(newmsg); message[i];) {
1237 if (message[i] == '%' && message[i + 1] == 'm') {
1238 char *errs = strerror(saved_errno);
1239 strcpy(newmsg + j, errs ? errs : "unknown error");
1240 j += strlen(newmsg + j);
1241 i += 2;
1242 } else {
1243 newmsg[j] = message[i];
1244 j++;
1245 i++;
1246 }
1247 }
1248
1249 strcpy(newmsg + j, "\n");
1250
1251 vfprintf(ourlogfile, newmsg, args);
1252
1253out:
1254 runtime_log_uncork_pending_drain();
1255}
1256
1257bool
1258logmsg_add(struct runtime_syslog_attr *attr, int err_num, const char *msg)
1259{
1260 size_t lm_sz = sizeof(struct logmsg_s) + strlen(msg) + strlen(attr->from_name) + strlen(attr->about_name) + strlen(attr->session_name) + 4;
1261 char *data_off;
1262 struct logmsg_s *lm;
1263
1264#define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7)
1265
1266 /* we do this to make the unpacking for the log_drain cause unalignment faults */
1267 lm_sz = ROUND_TO_64BIT_WORD_SIZE(lm_sz);
1268
1269 if (!(lm = calloc(1, lm_sz))) {
1270 return false;
1271 }
1272
1273 data_off = lm->data;
1274
1275 launchd_assumes(gettimeofday(&lm->when, NULL) != -1);
1276 lm->from_pid = attr->from_pid;
1277 lm->about_pid = attr->about_pid;
1278 lm->err_num = err_num;
1279 lm->pri = attr->priority;
1280 lm->obj_sz = lm_sz;
1281 lm->msg = data_off;
1282 data_off += sprintf(data_off, "%s", msg) + 1;
1283 lm->from_name = data_off;
1284 data_off += sprintf(data_off, "%s", attr->from_name) + 1;
1285 lm->about_name = data_off;
1286 data_off += sprintf(data_off, "%s", attr->about_name) + 1;
1287 lm->session_name = data_off;
1288 data_off += sprintf(data_off, "%s", attr->session_name) + 1;
1289
1290 STAILQ_INSERT_TAIL(&logmsg_queue, lm, sqe);
1291 logmsg_queue_sz += lm_sz;
1292 logmsg_queue_cnt++;
1293
1294 return true;
1295}
1296
1297void
1298logmsg_remove(struct logmsg_s *lm)
1299{
1300 STAILQ_REMOVE(&logmsg_queue, lm, logmsg_s, sqe);
1301 logmsg_queue_sz -= lm->obj_sz;
1302 logmsg_queue_cnt--;
1303
1304 free(lm);
1305}
1306
1307kern_return_t
1308runtime_log_pack(vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
1309{
1310 struct logmsg_s *lm;
1311 void *offset;
1312
1313 *outvalCnt = logmsg_queue_sz;
1314
1315 mig_allocate(outval, *outvalCnt);
1316
1317 if (*outval == 0) {
1318 return 1;
1319 }
1320
1321 offset = (void *)*outval;
1322
1323 while ((lm = STAILQ_FIRST(&logmsg_queue))) {
1324 lm->from_name -= (size_t)lm;
1325 lm->about_name -= (size_t)lm;
1326 lm->msg -= (size_t)lm;
1327 lm->session_name -= (size_t)lm;
1328
1329 memcpy(offset, lm, lm->obj_sz);
1330
1331 offset += lm->obj_sz;
1332
1333 logmsg_remove(lm);
1334 }
1335
1336 return 0;
1337}
1338
1339void
1340runtime_log_uncork_pending_drain(void)
1341{
1342 mach_msg_type_number_t outvalCnt;
1343 mach_port_t tmp_port;
1344 vm_offset_t outval;
1345
1346 if (!drain_reply_port) {
1347 return;
1348 }
1349
1350 if (logmsg_queue_cnt == 0) {
1351 return;
1352 }
1353
1354 if (runtime_log_pack(&outval, &outvalCnt) != 0) {
1355 return;
1356 }
1357
1358 tmp_port = drain_reply_port;
1359 drain_reply_port = MACH_PORT_NULL;
1360
1361 if ((errno = job_mig_log_drain_reply(tmp_port, 0, outval, outvalCnt))) {
1362 launchd_assumes(errno == MACH_SEND_INVALID_DEST);
1363 launchd_assumes(launchd_mport_deallocate(tmp_port) == KERN_SUCCESS);
1364 }
1365
1366 mig_deallocate(outval, outvalCnt);
1367}
1368
1369void
1370runtime_log_push(void)
1371{
1372 mach_msg_type_number_t outvalCnt;
1373 vm_offset_t outval;
1374
1375 if (logmsg_queue_cnt == 0) {
1376 launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
1377 return;
1378 } else if (getpid() == 1) {
1379 return;
1380 }
1381
1382 if (runtime_log_pack(&outval, &outvalCnt) != 0) {
1383 return;
1384 }
1385
1386 launchd_assumes(_vprocmgr_log_forward(inherited_bootstrap_port, (void *)outval, outvalCnt) == NULL);
1387
1388 mig_deallocate(outval, outvalCnt);
1389}
1390
1391kern_return_t
1392runtime_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, mach_msg_type_number_t invalCnt)
1393{
1394 struct logmsg_s *lm, *lm_walk;
1395 mach_msg_type_number_t data_left = invalCnt;
1396
1397 if (inval == 0) {
1398 return 0;
1399 }
1400
1401 for (lm_walk = (struct logmsg_s *)inval; (data_left > 0) && (lm_walk->obj_sz <= data_left); lm_walk = ((void *)lm_walk + lm_walk->obj_sz)) {
1402 if (!launchd_assumes(lm = malloc(lm_walk->obj_sz))) {
1403 continue;
1404 }
1405
1406 memcpy(lm, lm_walk, lm_walk->obj_sz);
1407 lm->sender_uid = forward_uid;
1408 lm->sender_gid = forward_gid;
1409
1410 lm->from_name += (size_t)lm;
1411 lm->about_name += (size_t)lm;
1412 lm->msg += (size_t)lm;
1413 lm->session_name += (size_t)lm;
1414
1415 STAILQ_INSERT_TAIL(&logmsg_queue, lm, sqe);
1416 logmsg_queue_sz += lm->obj_sz;
1417 logmsg_queue_cnt++;
1418
1419 data_left -= lm->obj_sz;
1420 }
1421
1422 mig_deallocate(inval, invalCnt);
1423
1424 return 0;
1425}
1426
1427kern_return_t
1428runtime_log_drain(mach_port_t srp, vm_offset_t *outval, mach_msg_type_number_t *outvalCnt)
1429{
1430 if (logmsg_queue_cnt == 0) {
1431 launchd_assumes(STAILQ_EMPTY(&logmsg_queue));
1432 launchd_assumes(drain_reply_port == 0);
1433
1434 drain_reply_port = srp;
1435 launchd_assumes(launchd_mport_notify_req(drain_reply_port, MACH_NOTIFY_DEAD_NAME) == KERN_SUCCESS);
1436
1437 return MIG_NO_REPLY;
1438 }
1439
1440 return runtime_log_pack(outval, outvalCnt);
1441}
1442
1443/*
1444 * We should break this into two reference counts.
1445 *
1446 * One for hard references that would prevent exiting.
1447 * One for soft references that would only prevent idle exiting.
1448 *
1449 * In the long run, reference counting should completely automate when a
1450 * process can and should exit.
1451 */
1452void
1453runtime_add_ref(void)
1454{
1455 runtime_busy_cnt++;
1456}
1457
1458void
1459runtime_del_ref(void)
1460{
1461 runtime_busy_cnt--;
1462}
fe044cc9
A
1463
1464kern_return_t
1465catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, mach_port_t task,
1466 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt)
1467{
1468 runtime_syslog(LOG_NOTICE, "%s(): thread: 0x%x task: 0x%x type: 0x%x code: %p codeCnt: 0x%x",
1469 __func__, thread, task, exception, code, codeCnt);
1470
1471 launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
1472 launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
1473
1474 return 0;
1475}
1476
1477kern_return_t
1478catch_mach_exception_raise_state(mach_port_t exception_port,
1479 exception_type_t exception, const mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1480 int *flavor, const thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1481 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
1482{
1483 runtime_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",
1484 __func__, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
1485
1486 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1487 *new_stateCnt = old_stateCnt;
1488
1489 return 0;
1490}
1491
1492kern_return_t
1493catch_mach_exception_raise_state_identity(mach_port_t exception_port, mach_port_t thread, mach_port_t task,
1494 exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t codeCnt,
1495 int *flavor, thread_state_t old_state, mach_msg_type_number_t old_stateCnt,
1496 thread_state_t new_state, mach_msg_type_number_t *new_stateCnt)
1497{
1498 runtime_syslog(LOG_NOTICE, "%s(): thread: 0x%x task: 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",
1499 __func__, thread, task, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt);
1500
1501 memcpy(new_state, old_state, old_stateCnt * sizeof(old_state[0]));
1502 *new_stateCnt = old_stateCnt;
1503
1504 launchd_assumes(launchd_mport_deallocate(thread) == KERN_SUCCESS);
1505 launchd_assumes(launchd_mport_deallocate(task) == KERN_SUCCESS);
1506
1507 return 0;
1508}