]> git.saurik.com Git - apple/launchd.git/blob - launchd/src/bootstrap.c
launchd-106.20.tar.gz
[apple/launchd.git] / launchd / src / bootstrap.c
1 /*
2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * bootstrap -- fundamental service initiator and port server
26 * Mike DeMoney, NeXT, Inc.
27 * Copyright, 1990. All rights reserved.
28 *
29 * bootstrap.c -- implementation of bootstrap main service loop
30 */
31
32 /*
33 * Imports
34 */
35 #include <mach/mach.h>
36 #include <mach/mach_error.h>
37 #include <mach/boolean.h>
38 #include <mach/message.h>
39 #include <mach/notify.h>
40 #include <mach/mig_errors.h>
41 #include <mach/mach_traps.h>
42 #include <mach/mach_interface.h>
43 #include <mach/bootstrap.h>
44 #include <mach/host_info.h>
45 #include <mach/mach_host.h>
46 #include <mach/exception.h>
47
48 #include <sys/ioctl.h>
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #include <sys/wait.h>
53 #include <pthread.h>
54 #include <errno.h>
55 #include <string.h>
56 #include <ctype.h>
57 #include <stdio.h>
58 #include <stdbool.h>
59 #include <libc.h>
60 #include <paths.h>
61 #include <syslog.h>
62 #include <pwd.h>
63
64 #include <bsm/audit.h>
65 #include <bsm/libbsm.h>
66
67 #include "bootstrap.h"
68 #include "bootstrap_internal.h"
69 #include "lists.h"
70 #include "launchd.h"
71
72 /* Mig should produce a declaration for this, but doesn't */
73 extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
74
75 auditinfo_t inherited_audit;
76 mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
77 bool forward_ok = false;
78 bool debugging = false;
79 bool register_self = false;
80 const char *register_name = NULL;
81 task_t bootstrap_self = MACH_PORT_NULL;
82
83 static uid_t inherited_uid = 0;
84 static bool shutdown_in_progress = false;
85
86 #ifndef ASSERT
87 #define ASSERT(p)
88 #endif
89
90 /*
91 * Private macros
92 */
93 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
94 #define END_OF(x) (&(x)[NELEM(x)])
95 #define streq(a,b) (strcmp(a,b) == 0)
96
97 /*
98 * Private declarations
99 */
100 static void init_ports(void);
101 static void start_server(server_t *serverp);
102 static void exec_server(server_t *serverp);
103 static char **argvize(const char *string);
104 static void *demand_loop(void *arg);
105 void *mach_server_loop(void *);
106 extern kern_return_t bootstrap_register
107 (
108 mach_port_t bootstrapport,
109 name_t servicename,
110 mach_port_t serviceport
111 );
112
113 /*
114 * Private ports we hold receive rights for. We also hold receive rights
115 * for all the privileged ports. Those are maintained in the server
116 * structs.
117 */
118 mach_port_t bootstrap_port_set;
119 mach_port_t demand_port_set;
120 pthread_t demand_thread;
121
122 mach_port_t notify_port;
123 mach_port_t backup_port;
124
125
126 static mach_msg_return_t
127 inform_server_loop(
128 mach_port_name_t about,
129 mach_msg_option_t options)
130 {
131 mach_port_destroyed_notification_t not;
132 mach_msg_size_t size = sizeof(not) - sizeof(not.trailer);
133
134 not.not_header.msgh_id = DEMAND_REQUEST;
135 not.not_header.msgh_remote_port = backup_port;
136 not.not_header.msgh_local_port = MACH_PORT_NULL;
137 not.not_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
138 not.not_header.msgh_size = size;
139 not.not_body.msgh_descriptor_count = 1;
140 not.not_port.type = MACH_MSG_PORT_DESCRIPTOR;
141 not.not_port.disposition = MACH_MSG_TYPE_PORT_NAME;
142 not.not_port.name = about;
143 return mach_msg(&not.not_header, MACH_SEND_MSG|options, size,
144 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
145 }
146
147 static void
148 notify_server_loop(mach_port_name_t about)
149 {
150 mach_msg_return_t result;
151
152 result = inform_server_loop(about, MACH_MSG_OPTION_NONE);
153 if (result != MACH_MSG_SUCCESS)
154 syslog(LOG_ERR, "notify_server_loop: mach_msg(): %s", mach_error_string(result));
155 }
156
157 void mach_start_shutdown(__unused int signalnum)
158 {
159 shutdown_in_progress = TRUE;
160 (void) inform_server_loop(MACH_PORT_NULL, MACH_SEND_TIMEOUT);
161 }
162
163 mach_port_t mach_init_init(void)
164 {
165 kern_return_t result;
166 pthread_attr_t attr;
167
168 bootstrap_self = mach_task_self();
169 inherited_uid = getuid();
170 getaudit(&inherited_audit);
171 init_lists();
172 init_ports();
173
174 result = task_get_bootstrap_port(bootstrap_self, &inherited_bootstrap_port);
175 if (result != KERN_SUCCESS) {
176 syslog(LOG_ALERT, "task_get_bootstrap_port(): %s", mach_error_string(result));
177 exit(EXIT_FAILURE);
178 }
179 if (inherited_bootstrap_port == MACH_PORT_NULL)
180 forward_ok = FALSE;
181
182 /* We set this explicitly as we start each child */
183 task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
184
185 /* register "self" port with anscestor */
186 if (register_self && forward_ok) {
187 result = bootstrap_register(inherited_bootstrap_port,
188 (char *)register_name,
189 bootstraps.bootstrap_port);
190 if (result != KERN_SUCCESS)
191 panic("register self(): %s", mach_error_string(result));
192 }
193
194 pthread_attr_init(&attr);
195 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
196 result = pthread_create(&demand_thread, &attr, demand_loop, NULL);
197 if (result)
198 panic("pthread_create(): %s", strerror(result));
199 pthread_attr_destroy(&attr);
200
201 return bootstraps.bootstrap_port;
202 }
203
204 static void
205 init_ports(void)
206 {
207 kern_return_t result;
208
209 /*
210 * This task will become the bootstrap task.
211 */
212 /* Create port set that server loop listens to */
213 result = mach_port_allocate(
214 bootstrap_self,
215 MACH_PORT_RIGHT_PORT_SET,
216 &bootstrap_port_set);
217 if (result != KERN_SUCCESS)
218 panic("port_set_allocate(): %s", mach_error_string(result));
219
220 /* Create demand port set that second thread listens to */
221 result = mach_port_allocate(
222 bootstrap_self,
223 MACH_PORT_RIGHT_PORT_SET,
224 &demand_port_set);
225 if (result != KERN_SUCCESS)
226 panic("port_set_allocate(): %s", mach_error_string(result));
227
228 /* Create notify port and add to server port set */
229 result = mach_port_allocate(
230 bootstrap_self,
231 MACH_PORT_RIGHT_RECEIVE,
232 &notify_port);
233 if (result != KERN_SUCCESS)
234 panic("mach_port_allocate(): %s", mach_error_string(result));
235
236 result = mach_port_move_member(
237 bootstrap_self,
238 notify_port,
239 bootstrap_port_set);
240 if (result != KERN_SUCCESS)
241 panic("mach_port_move_member(): %s", mach_error_string(result));
242
243 /* Create backup port and add to server port set */
244 result = mach_port_allocate(
245 bootstrap_self,
246 MACH_PORT_RIGHT_RECEIVE,
247 &backup_port);
248 if (result != KERN_SUCCESS)
249 panic("mach_port_allocate(): %s", mach_error_string(result));
250
251 result = mach_port_move_member(
252 bootstrap_self,
253 backup_port,
254 bootstrap_port_set);
255 if (result != KERN_SUCCESS)
256 panic("mach_port_move_member(): %s", mach_error_string(result));
257
258 /* Create "self" port and add to server port set */
259 result = mach_port_allocate(
260 bootstrap_self,
261 MACH_PORT_RIGHT_RECEIVE,
262 &bootstraps.bootstrap_port);
263 if (result != KERN_SUCCESS)
264 panic("mach_port_allocate(): %s", mach_error_string(result));
265 result = mach_port_insert_right(
266 bootstrap_self,
267 bootstraps.bootstrap_port,
268 bootstraps.bootstrap_port,
269 MACH_MSG_TYPE_MAKE_SEND);
270 if (result != KERN_SUCCESS)
271 panic("mach_port_insert_right(): %s", mach_error_string(result));
272
273 /* keep the root bootstrap port "active" */
274 bootstraps.requestor_port = bootstraps.bootstrap_port;
275
276 result = mach_port_move_member(
277 bootstrap_self,
278 bootstraps.bootstrap_port,
279 bootstrap_port_set);
280 if (result != KERN_SUCCESS)
281 panic("mach_port_move_member(): %s", mach_error_string(result));
282 }
283
284 boolean_t
285 active_bootstrap(bootstrap_info_t *bootstrap)
286 {
287 return (bootstrap->requestor_port != MACH_PORT_NULL);
288 }
289
290 boolean_t
291 useless_server(server_t *serverp)
292 {
293 return ( !active_bootstrap(serverp->bootstrap) ||
294 !lookup_service_by_server(serverp) ||
295 !serverp->activity);
296 }
297
298 boolean_t
299 active_server(server_t *serverp)
300 {
301 return ( serverp->port ||
302 serverp->task_port || serverp->active_services);
303 }
304
305 static void
306 reap_server(server_t *serverp)
307 {
308 kern_return_t result;
309 pid_t presult;
310 int wstatus;
311
312 /*
313 * Reap our children.
314 */
315 presult = waitpid(serverp->pid, &wstatus, WNOHANG);
316 switch (presult) {
317 case -1:
318 syslog(LOG_DEBUG, "waitpid: cmd = %s: %m", serverp->cmd);
319 break;
320
321 case 0:
322 {
323 /* process must have switched mach tasks */
324 mach_port_t old_port;
325
326 old_port = serverp->task_port;
327 mach_port_deallocate(mach_task_self(), old_port);
328 serverp->task_port = MACH_PORT_NULL;
329
330 result = task_for_pid( mach_task_self(),
331 serverp->pid,
332 &serverp->task_port);
333 if (result != KERN_SUCCESS) {
334 syslog(LOG_INFO, "race getting new server task port for pid[%d]: %s",
335 serverp->pid, mach_error_string(result));
336 break;
337 }
338
339 /* Request dead name notification to tell when new task dies */
340 result = mach_port_request_notification(
341 mach_task_self(),
342 serverp->task_port,
343 MACH_NOTIFY_DEAD_NAME,
344 0,
345 notify_port,
346 MACH_MSG_TYPE_MAKE_SEND_ONCE,
347 &old_port);
348 if (result != KERN_SUCCESS) {
349 syslog(LOG_INFO, "race setting up notification for new server task port for pid[%d]: %s",
350 serverp->pid, mach_error_string(result));
351 break;
352 }
353 return;
354 }
355
356 default:
357 if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) {
358 syslog(LOG_NOTICE, "Server %x in bootstrap %x uid %d: \"%s\"[%d]: exited with status: %d",
359 serverp->port, serverp->bootstrap->bootstrap_port,
360 serverp->uid, serverp->cmd, serverp->pid, WEXITSTATUS(wstatus));
361 } else if (WIFSIGNALED(wstatus)) {
362 syslog(LOG_NOTICE, "Server %x in bootstrap %x uid %d: \"%s\"[%d]: exited abnormally: %s",
363 serverp->port, serverp->bootstrap->bootstrap_port,
364 serverp->uid, serverp->cmd, serverp->pid, strsignal(WTERMSIG(wstatus)));
365 }
366 break;
367 }
368
369
370 serverp->pid = 0;
371
372 /*
373 * Release the server task port reference, if we ever
374 * got it in the first place.
375 */
376 if (serverp->task_port != MACH_PORT_NULL) {
377 result = mach_port_deallocate(
378 mach_task_self(),
379 serverp->task_port);
380 if (result != KERN_SUCCESS)
381 syslog(LOG_ERR, "mach_port_deallocate(): %s", mach_error_string(result));
382 serverp->task_port = MACH_PORT_NULL;
383 }
384 }
385
386 static void
387 demand_server(server_t *serverp)
388 {
389 service_t *servicep;
390 kern_return_t result;
391
392 /*
393 * For on-demand servers, make sure that the service ports are
394 * back in on-demand portset. Active service ports should come
395 * back through a PORT_DESTROYED notification. We only have to
396 * worry about the inactive ports that may have been previously
397 * pulled from the set but never checked-in by the server.
398 */
399
400 for ( servicep = FIRST(services)
401 ; !IS_END(servicep, services)
402 ; servicep = NEXT(servicep))
403 {
404 if (serverp == servicep->server && !servicep->isActive) {
405 result = mach_port_move_member(
406 mach_task_self(),
407 servicep->port,
408 demand_port_set);
409 if (result != KERN_SUCCESS)
410 panic("mach_port_move_member(): %s", mach_error_string(result));
411 }
412 }
413 }
414
415 static
416 void dispatch_server(server_t *serverp)
417 {
418 if (!active_server(serverp)) {
419 if (useless_server(serverp) || shutdown_in_progress)
420 delete_server(serverp);
421 else if (serverp->servertype == RESTARTABLE)
422 start_server(serverp);
423 else if (serverp->servertype == DEMAND)
424 demand_server(serverp);
425 }
426 }
427
428 void
429 setup_server(server_t *serverp)
430 {
431 kern_return_t result;
432 mach_port_t old_port;
433
434 /* Allocate privileged port for requests from service */
435 result = mach_port_allocate(mach_task_self(),
436 MACH_PORT_RIGHT_RECEIVE ,
437 &serverp->port);
438 syslog(LOG_INFO, "Allocating port %x for server %s", serverp->port, serverp->cmd);
439 if (result != KERN_SUCCESS)
440 panic("port_allocate(): %s", mach_error_string(result));
441
442 /* Request no-senders notification so we can tell when server dies */
443 result = mach_port_request_notification(mach_task_self(),
444 serverp->port,
445 MACH_NOTIFY_NO_SENDERS,
446 1,
447 serverp->port,
448 MACH_MSG_TYPE_MAKE_SEND_ONCE,
449 &old_port);
450 if (result != KERN_SUCCESS)
451 panic("mach_port_request_notification(): %s", mach_error_string(result));
452
453 /* Add privileged server port to bootstrap port set */
454 result = mach_port_move_member(mach_task_self(),
455 serverp->port,
456 bootstrap_port_set);
457 if (result != KERN_SUCCESS)
458 panic("mach_port_move_member(): %s", mach_error_string(result));
459 }
460
461 pid_t
462 fork_with_bootstrap_port(mach_port_t p)
463 {
464 static pthread_mutex_t forklock = PTHREAD_MUTEX_INITIALIZER;
465 kern_return_t result;
466 pid_t r;
467 size_t i;
468
469 pthread_mutex_lock(&forklock);
470
471 sigprocmask(SIG_BLOCK, &blocked_signals, NULL);
472
473 result = task_set_bootstrap_port(mach_task_self(), p);
474 if (result != KERN_SUCCESS)
475 panic("task_set_bootstrap_port(): %s", mach_error_string(result));
476
477 if (launchd_bootstrap_port != p) {
478 result = mach_port_deallocate(mach_task_self(), p);
479 if (result != KERN_SUCCESS)
480 panic("mach_port_deallocate(): %s", mach_error_string(result));
481 }
482
483 r = fork();
484
485 if (r > 0) {
486 /* Post Tiger:
487 *
488 * We should set the bootstrap back to MACH_PORT_NULL instead
489 * of launchd_bootstrap_port. This will expose rare latent race
490 * condition bugs, given that some programs assume that the PID
491 * 1's bootstrap port is constant. This function clearly
492 * demonstrates that is no longer true.
493 *
494 * Those programs should be calling bootstrap_parent(), and not
495 * task_for_pid(1) followed by a call to get the bootstrap port
496 * on the task.
497 */
498 result = task_set_bootstrap_port(mach_task_self(), launchd_bootstrap_port);
499 if (result != KERN_SUCCESS)
500 panic("task_set_bootstrap_port(): %s", mach_error_string(result));
501 } else {
502 for (i = 0; i <= NSIG; i++) {
503 if (sigismember(&blocked_signals, i))
504 signal(i, SIG_DFL);
505 }
506 }
507
508 sigprocmask(SIG_UNBLOCK, &blocked_signals, NULL);
509
510 pthread_mutex_unlock(&forklock);
511
512 return r;
513 }
514
515 static void
516 start_server(server_t *serverp)
517 {
518 kern_return_t result;
519 mach_port_t old_port;
520 int pid;
521
522 /*
523 * Do what's appropriate to get bootstrap port setup in server task
524 */
525 switch (serverp->servertype) {
526
527 case MACHINIT:
528 break;
529
530 case SERVER:
531 case DEMAND:
532 case RESTARTABLE:
533 if (!serverp->port)
534 setup_server(serverp);
535
536 serverp->activity = 0;
537
538 /* Insert a send right */
539 result = mach_port_insert_right(mach_task_self(),
540 serverp->port,
541 serverp->port,
542 MACH_MSG_TYPE_MAKE_SEND);
543 if (result != KERN_SUCCESS)
544 panic("mach_port_insert_right(): %s", mach_error_string(result));
545
546 pid = fork_with_bootstrap_port(serverp->port);
547 if (pid < 0) {
548 syslog(LOG_WARNING, "fork(): %m");
549 } else if (pid == 0) { /* CHILD */
550 exec_server(serverp);
551 _exit(EXIT_FAILURE);
552 } else { /* PARENT */
553 syslog(LOG_INFO, "Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
554 serverp->port, serverp->bootstrap->bootstrap_port,
555 serverp->uid, serverp->cmd, pid);
556 serverp->pid = pid;
557 result = task_for_pid(
558 mach_task_self(),
559 pid,
560 &serverp->task_port);
561 if (result != KERN_SUCCESS) {
562 syslog(LOG_ERR, "getting server task port(): %s", mach_error_string(result));
563 reap_server(serverp);
564 dispatch_server(serverp);
565 break;
566 }
567
568 /* Request dead name notification to tell when task dies */
569 result = mach_port_request_notification(
570 mach_task_self(),
571 serverp->task_port,
572 MACH_NOTIFY_DEAD_NAME,
573 0,
574 notify_port,
575 MACH_MSG_TYPE_MAKE_SEND_ONCE,
576 &old_port);
577 if (result != KERN_SUCCESS) {
578 syslog(LOG_ERR, "mach_port_request_notification(): %s", mach_error_string(result));
579 reap_server(serverp);
580 dispatch_server(serverp);
581 }
582 }
583 break;
584 }
585 }
586
587 static void
588 exec_server(server_t *serverp)
589 {
590 char **argv;
591 sigset_t mask;
592
593 /*
594 * Setup environment for server, someday this should be Mach stuff
595 * rather than Unix crud
596 */
597 argv = argvize(serverp->cmd);
598 closelog();
599
600 /*
601 * Set up the audit state for the user (if necessesary).
602 */
603 if (inherited_uid == 0 &&
604 (serverp->auinfo.ai_auid != inherited_uid ||
605 serverp->auinfo.ai_asid != inherited_audit.ai_asid)) {
606 struct passwd *pwd = NULL;
607
608 pwd = getpwuid(serverp->auinfo.ai_auid);
609 if (pwd == NULL) {
610 panic("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed",
611 serverp->port, serverp->bootstrap->bootstrap_port,
612 serverp->cmd, serverp->auinfo.ai_auid);
613
614 } else if (au_user_mask(pwd->pw_name, &serverp->auinfo.ai_mask) != 0) {
615 panic("Disabled server %x bootstrap %x: \"%s\": au_user_mask(%s) failed",
616 serverp->port, serverp->bootstrap->bootstrap_port,
617 serverp->cmd, pwd->pw_name);
618 } else if (setaudit(&serverp->auinfo) != 0)
619 panic("Disabled server %x bootstrap %x: \"%s\": setaudit()",
620 serverp->port, serverp->bootstrap->bootstrap_port,
621 serverp->cmd);
622 }
623
624 if (serverp->uid != inherited_uid) {
625 struct passwd *pwd = getpwuid(serverp->uid);
626 gid_t g;
627
628 if (NULL == pwd) {
629 panic("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed",
630 serverp->port, serverp->bootstrap->bootstrap_port,
631 serverp->cmd, serverp->uid);
632 }
633
634 g = pwd->pw_gid;
635
636 if (-1 == setgroups(1, &g)) {
637 panic("Disabled server %x bootstrap %x: \"%s\": setgroups(1, %d): %s",
638 serverp->port, serverp->bootstrap->bootstrap_port,
639 serverp->cmd, g, strerror(errno));
640 }
641
642 if (-1 == setgid(g)) {
643 panic("Disabled server %x bootstrap %x: \"%s\": setgid(%d): %s",
644 serverp->port, serverp->bootstrap->bootstrap_port,
645 serverp->cmd, g, strerror(errno));
646 }
647
648 if (-1 == setuid(serverp->uid)) {
649 panic("Disabled server %x bootstrap %x: \"%s\": setuid(%d): %s",
650 serverp->port, serverp->bootstrap->bootstrap_port,
651 serverp->cmd, serverp->uid, strerror(errno));
652 }
653 }
654
655
656 if (setsid() < 0) {
657 /*
658 * We can't keep this from happening, but we shouldn't start
659 * the server not as a process group leader. So, just fake like
660 * there was real activity, and exit the child. If needed,
661 * we'll re-launch it under another pid.
662 */
663 serverp->activity = 1;
664 panic("Temporary failure server %x bootstrap %x: \"%s\": setsid(): %s",
665 serverp->port, serverp->bootstrap->bootstrap_port,
666 serverp->cmd, strerror(errno));
667 }
668
669 sigemptyset(&mask);
670 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
671
672 setpriority(PRIO_PROCESS, 0, 0);
673 execv(argv[0], argv);
674 panic("Disabled server %x bootstrap %x: \"%s\": exec(): %s",
675 serverp->port,
676 serverp->bootstrap->bootstrap_port,
677 serverp->cmd,
678 strerror(errno));
679 }
680
681 static char **
682 argvize(const char *string)
683 {
684 static char *argv[100], args[1000];
685 const char *cp;
686 char *argp, term;
687 unsigned int nargs;
688
689 /*
690 * Convert a command line into an argv for execv
691 */
692 nargs = 0;
693 argp = args;
694
695 for (cp = string; *cp;) {
696 while (isspace(*cp))
697 cp++;
698 term = (*cp == '"') ? *cp++ : '\0';
699 if (nargs < NELEM(argv))
700 argv[nargs++] = argp;
701 while (*cp && (term ? *cp != term : !isspace(*cp))
702 && argp < END_OF(args)) {
703 if (*cp == '\\')
704 cp++;
705 *argp++ = *cp;
706 if (*cp)
707 cp++;
708 }
709 *argp++ = '\0';
710 }
711 argv[nargs] = NULL;
712 return argv;
713 }
714
715 static void *
716 demand_loop(void *arg __attribute__((unused)))
717 {
718 mach_msg_empty_rcv_t dummy;
719 kern_return_t dresult;
720
721
722 for(;;) {
723 mach_port_name_array_t members;
724 mach_msg_type_number_t membersCnt;
725 mach_port_status_t status;
726 mach_msg_type_number_t statusCnt;
727 unsigned int i;
728
729 /*
730 * Receive indication of message on demand service
731 * ports without actually receiving the message (we'll
732 * let the actual server do that.
733 */
734 dresult = mach_msg(
735 &dummy.header,
736 MACH_RCV_MSG|MACH_RCV_LARGE,
737 0,
738 0,
739 demand_port_set,
740 0,
741 MACH_PORT_NULL);
742 if (dresult != MACH_RCV_TOO_LARGE) {
743 syslog(LOG_ERR, "demand_loop: mach_msg(): %s", mach_error_string(dresult));
744 continue;
745 }
746
747 /*
748 * Some port(s) now have messages on them, find out
749 * which ones (there is no indication of which port
750 * triggered in the MACH_RCV_TOO_LARGE indication).
751 */
752 dresult = mach_port_get_set_status(
753 mach_task_self(),
754 demand_port_set,
755 &members,
756 &membersCnt);
757 if (dresult != KERN_SUCCESS) {
758 syslog(LOG_ERR, "demand_loop: mach_port_get_set_status(): %s", mach_error_string(dresult));
759 continue;
760 }
761
762 for (i = 0; i < membersCnt; i++) {
763 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
764 dresult = mach_port_get_attributes(
765 mach_task_self(),
766 members[i],
767 MACH_PORT_RECEIVE_STATUS,
768 (mach_port_info_t)&status,
769 &statusCnt);
770 if (dresult != KERN_SUCCESS) {
771 syslog(LOG_ERR, "demand_loop: mach_port_get_attributes(): %s", mach_error_string(dresult));
772 continue;
773 }
774
775 /*
776 * For each port with messages, take it out of the
777 * demand service portset, and inform the main thread
778 * that it might have to start the server responsible
779 * for it.
780 */
781 if (status.mps_msgcount) {
782 dresult = mach_port_move_member(
783 mach_task_self(),
784 members[i],
785 MACH_PORT_NULL);
786 if (dresult != KERN_SUCCESS) {
787 syslog(LOG_ERR, "demand_loop: mach_port_move_member(): %s", mach_error_string(dresult));
788 continue;
789 }
790 notify_server_loop(members[i]);
791 }
792 }
793
794 dresult = vm_deallocate(
795 mach_task_self(),
796 (vm_address_t) members,
797 (vm_size_t) membersCnt * sizeof(mach_port_name_t));
798 if (dresult != KERN_SUCCESS) {
799 syslog(LOG_ERR, "demand_loop: vm_deallocate(): %s", mach_error_string(dresult));
800 continue;
801 }
802 }
803 return NULL;
804 }
805
806 /*
807 * server_demux -- processes requests off our service port
808 * Also handles notifications
809 */
810
811 static boolean_t
812 server_demux(
813 mach_msg_header_t *Request,
814 mach_msg_header_t *Reply)
815 {
816 bootstrap_info_t *bootstrap;
817 service_t *servicep;
818 server_t *serverp;
819 kern_return_t result;
820 mig_reply_error_t *reply;
821
822 syslog(LOG_DEBUG, "received message on port %x", Request->msgh_local_port);
823
824 reply = (mig_reply_error_t *)Reply;
825
826 /*
827 * Pick off notification messages
828 */
829 if (Request->msgh_local_port == notify_port) {
830 mach_port_name_t np;
831
832 memset(reply, 0, sizeof(*reply));
833 switch (Request->msgh_id) {
834 case MACH_NOTIFY_DEAD_NAME:
835 np = ((mach_dead_name_notification_t *)Request)->not_port;
836 syslog(LOG_DEBUG, "Notified dead name %x", np);
837
838 if (np == inherited_bootstrap_port) {
839 inherited_bootstrap_port = MACH_PORT_NULL;
840 forward_ok = FALSE;
841 }
842
843 /*
844 * Check to see if a subset requestor port was deleted.
845 */
846 while ((bootstrap = lookup_bootstrap_by_req_port(np)) != NULL) {
847 syslog(LOG_DEBUG, "Received dead name notification for bootstrap subset %x requestor port %x",
848 bootstrap->bootstrap_port, bootstrap->requestor_port);
849 mach_port_deallocate(
850 mach_task_self(),
851 bootstrap->requestor_port);
852 bootstrap->requestor_port = MACH_PORT_NULL;
853 deactivate_bootstrap(bootstrap);
854 }
855
856 /*
857 * Check to see if a defined service has gone
858 * away.
859 */
860 while ((servicep = lookup_service_by_port(np)) != NULL) {
861 /*
862 * Port gone, registered service died.
863 */
864 syslog(LOG_DEBUG, "Received dead name notification for service %s "
865 "on bootstrap port %x\n",
866 servicep->name, servicep->bootstrap);
867 syslog(LOG_DEBUG, "Service %s failed - deallocate", servicep->name);
868 delete_service(servicep);
869 }
870
871 /*
872 * Check to see if a launched server task has gone
873 * away.
874 */
875 if ((serverp = lookup_server_by_task_port(np)) != NULL) {
876 /*
877 * Port gone, server died or picked up new task.
878 */
879 syslog(LOG_DEBUG, "Received task death notification for server %s ",
880 serverp->cmd);
881 reap_server(serverp);
882 dispatch_server(serverp);
883 }
884
885 mach_port_deallocate(mach_task_self(), np);
886 reply->RetCode = KERN_SUCCESS;
887 break;
888
889 case MACH_NOTIFY_PORT_DELETED:
890 np = ((mach_port_deleted_notification_t *)Request)->not_port;
891 syslog(LOG_DEBUG, "port deleted notification on 0x%x", np);
892 reply->RetCode = KERN_SUCCESS;
893 break;
894
895 case MACH_NOTIFY_SEND_ONCE:
896 syslog(LOG_DEBUG, "notification send-once right went unused");
897 reply->RetCode = KERN_SUCCESS;
898 break;
899
900 default:
901 syslog(LOG_ERR, "Unexpected notification: %d", Request->msgh_id);
902 reply->RetCode = KERN_FAILURE;
903 break;
904 }
905 }
906
907 else if (Request->msgh_local_port == backup_port) {
908 mach_port_name_t np;
909
910 memset(reply, 0, sizeof(*reply));
911
912 np = ((mach_port_destroyed_notification_t *)Request)->not_port.name;
913 servicep = lookup_service_by_port(np);
914 if (servicep != NULL) {
915 serverp = servicep->server;
916
917 switch (Request->msgh_id) {
918
919 case MACH_NOTIFY_PORT_DESTROYED:
920 /*
921 * Port sent back to us, server died.
922 */
923 syslog(LOG_DEBUG, "Received destroyed notification for service %s",
924 servicep->name);
925 syslog(LOG_DEBUG, "Service %x bootstrap %x backed up: %s",
926 servicep->port, servicep->bootstrap->bootstrap_port,
927 servicep->name);
928 ASSERT(canReceive(servicep->port));
929 servicep->isActive = FALSE;
930 serverp->active_services--;
931 dispatch_server(serverp);
932 reply->RetCode = KERN_SUCCESS;
933 break;
934
935 case DEMAND_REQUEST:
936 /* message reflected over from demand start thread */
937 if (!active_server(serverp))
938 start_server(serverp);
939 reply->RetCode = KERN_SUCCESS;
940 break;
941
942 default:
943 syslog(LOG_DEBUG, "Mysterious backup_port notification %d", Request->msgh_id);
944 reply->RetCode = KERN_FAILURE;
945 break;
946 }
947 } else {
948 syslog(LOG_DEBUG, "Backup_port notification - previously deleted service");
949 reply->RetCode = KERN_FAILURE;
950 }
951 }
952
953 else if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
954 mach_port_t ns = Request->msgh_local_port;
955
956 if ((serverp = lookup_server_by_port(ns)) != NULL_SERVER) {
957 /*
958 * A server we launched has released his bootstrap
959 * port send right. We won't re-launch him unless
960 * his services came back to roost. But we need to
961 * destroy the bootstrap port for fear of leaking.
962 */
963 syslog(LOG_DEBUG, "server %s dropped server port", serverp->cmd);
964 serverp->port = MACH_PORT_NULL;
965 dispatch_server(serverp);
966 } else if ((bootstrap = lookup_bootstrap_by_port(ns)) != NULL) {
967 /*
968 * The last direct user of a deactivated bootstrap went away.
969 * We can finally free it.
970 */
971 syslog(LOG_DEBUG, "Deallocating bootstrap %x: no more clients", ns);
972 bootstrap->bootstrap_port = MACH_PORT_NULL;
973 deallocate_bootstrap(bootstrap);
974 }
975
976 result = mach_port_mod_refs(
977 mach_task_self(),
978 ns,
979 MACH_PORT_RIGHT_RECEIVE,
980 -1);
981 if (result != KERN_SUCCESS)
982 panic("mach_port_mod_refs(): %s", mach_error_string(result));
983
984 memset(reply, 0, sizeof(*reply));
985 reply->RetCode = KERN_SUCCESS;
986 }
987
988 else { /* must be a service request */
989 syslog(LOG_DEBUG, "Handled request.");
990 return bootstrap_server(Request, Reply);
991 }
992 return TRUE;
993 }
994
995 /*
996 * server_loop -- pick requests off our service port and process them
997 * Also handles notifications
998 */
999 #define bootstrapMaxRequestSize 1024
1000 #define bootstrapMaxReplySize 1024
1001
1002 static boolean_t
1003 server_demux_with_giant_lock(
1004 mach_msg_header_t *Request,
1005 mach_msg_header_t *Reply)
1006 {
1007 boolean_t r;
1008
1009 assumes(pthread_mutex_lock(&giant_lock) == 0);
1010 r = server_demux(Request, Reply);
1011 assumes(pthread_mutex_unlock(&giant_lock) == 0);
1012
1013 return r;
1014 }
1015
1016 void *
1017 mach_server_loop(void *arg __attribute__((unused)))
1018 {
1019 mach_msg_return_t mresult;
1020
1021 for (;;) {
1022 mresult = mach_msg_server(
1023 server_demux_with_giant_lock,
1024 bootstrapMaxRequestSize,
1025 bootstrap_port_set,
1026 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)|
1027 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
1028 if (mresult != MACH_MSG_SUCCESS)
1029 syslog(LOG_ERR, "mach_msg_server(): %s", mach_error_string(mresult));
1030 }
1031 return NULL;
1032 }
1033
1034 bool
1035 canReceive(mach_port_t port)
1036 {
1037 mach_port_type_t p_type;
1038 kern_return_t result;
1039
1040 result = mach_port_type(mach_task_self(), port, &p_type);
1041 if (result != KERN_SUCCESS) {
1042 syslog(LOG_ERR, "port_type(): %s", mach_error_string(result));
1043 return FALSE;
1044 }
1045 return ((p_type & MACH_PORT_TYPE_RECEIVE) != 0);
1046 }
1047
1048
1049 bool
1050 canSend(mach_port_t port)
1051 {
1052 mach_port_type_t p_type;
1053 kern_return_t result;
1054
1055 result = mach_port_type(mach_task_self(), port, &p_type);
1056 if (result != KERN_SUCCESS) {
1057 syslog(LOG_ERR, "port_type(): %s", mach_error_string(result));
1058 return FALSE;
1059 }
1060 return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0);
1061 }
1062
1063 /* Sigh... Libc's panic() call fails to abort and continues afterwards */
1064 void
1065 panic(const char *msg, ...)
1066 {
1067 va_list ap;
1068
1069 va_start(ap, msg);
1070 vfprintf(stderr, msg, ap);
1071 va_end(ap);
1072
1073 _exit(EXIT_FAILURE);
1074 }