]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/bootstrap.c
system_cmds-230.0.2.tar.gz
[apple/system_cmds.git] / mach_init.tproj / bootstrap.c
1 /*
2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * bootstrap -- fundamental service initiator and port server
27 * Mike DeMoney, NeXT, Inc.
28 * Copyright, 1990. All rights reserved.
29 *
30 * bootstrap.c -- implementation of bootstrap main service loop
31 */
32
33 /*
34 * Imports
35 */
36 #import <mach/mach.h>
37 #import <mach/boolean.h>
38 #import <mach/message.h>
39 #import <mach/notify.h>
40 #import <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 #import <sys/ioctl.h>
49 #import <sys/types.h>
50 #import <sys/wait.h>
51 #import <pthread.h>
52 #import <string.h>
53 #import <ctype.h>
54 #import <stdio.h>
55 #import <libc.h>
56
57 #import "bootstrap.h"
58
59 #import "bootstrap_internal.h"
60 #import "lists.h"
61 #import "error_log.h"
62
63 /* Mig should produce a declaration for this, but doesn't */
64 extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
65
66 /*
67 * Exports
68 */
69 const char *program_name; /* our name for error messages */
70
71 #ifndef INIT_PATH
72 #define INIT_PATH "/sbin/init" /* default init path */
73 #endif INIT_PATH
74
75 uid_t inherited_uid;
76 mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
77 boolean_t forward_ok = FALSE;
78 boolean_t shutdown_in_progress = FALSE;
79 boolean_t debugging = FALSE;
80 boolean_t register_self = FALSE;
81 boolean_t force_fork = FALSE;
82 const char *register_name;
83 task_t bootstrap_self;
84
85 #ifndef ASSERT
86 #define ASSERT(p)
87 #endif
88
89 /*
90 * Private macros
91 */
92 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
93 #define END_OF(x) (&(x)[NELEM(x)])
94 #define streq(a,b) (strcmp(a,b) == 0)
95
96 /*
97 * Private declarations
98 */
99 static void wait_for_go(mach_port_t init_notify_port);
100 static void init_ports(void);
101 static void start_server(server_t *serverp);
102 static void unblock_init(mach_port_t init_notify_port, mach_port_t newBootstrap);
103 static void exec_server(server_t *serverp);
104 static char **argvize(const char *string);
105 static void *demand_loop(void *arg);
106 static void server_loop(void);
107 extern kern_return_t bootstrap_register
108 (
109 mach_port_t bootstrap_port,
110 name_t service_name,
111 mach_port_t service_port
112 );
113
114 /*
115 * Private ports we hold receive rights for. We also hold receive rights
116 * for all the privileged ports. Those are maintained in the server
117 * structs.
118 */
119 mach_port_t bootstrap_port_set;
120 mach_port_t demand_port_set;
121 pthread_t demand_thread;
122
123 mach_port_t notify_port;
124 mach_port_t backup_port;
125
126 static void
127 notify_server_loop(mach_port_name_t about)
128 {
129 mach_port_destroyed_notification_t not;
130 mach_msg_return_t nresult;
131
132 not.not_header.msgh_id = DEMAND_REQUEST;
133 not.not_header.msgh_remote_port = backup_port;
134 not.not_header.msgh_local_port = MACH_PORT_NULL;
135 not.not_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
136 not.not_header.msgh_size = sizeof(not) - sizeof(not.trailer);
137 not.not_body.msgh_descriptor_count = 1;
138 not.not_port.type = MACH_MSG_PORT_DESCRIPTOR;
139 not.not_port.disposition = MACH_MSG_TYPE_PORT_NAME;
140 not.not_port.name = about;
141 nresult = mach_msg_send(&not.not_header);
142 if (nresult != MACH_MSG_SUCCESS) {
143 kern_error(nresult, "notify_server: mach_msg_send()");
144 }
145 }
146
147 void _myExit(int arg)
148 {
149 exit(arg);
150 }
151
152 void toggle_debug(int signal)
153 {
154 debugging = (debugging) ? FALSE : TRUE;
155 }
156
157 void start_shutdown(int signal)
158 {
159 debug("received SIGTERM");
160 shutdown_in_progress = TRUE;
161 notify_server_loop(MACH_PORT_DEAD);
162 }
163
164 int
165 main(int argc, char * argv[])
166 {
167 const char *argp;
168 char c;
169 server_t *serverp;
170 kern_return_t result;
171 mach_port_t init_notify_port;
172 pthread_attr_t attr;
173 sigset_t mask;
174 int pid;
175
176 /*
177 * If we are pid one, we have to exec init. Before doing so, we'll
178 * fork a child, and that will become the true mach_init. But we have
179 * to be very careful about ports. They aren't inherited across fork,
180 * so we have to avoid storing port names in memory before the fork that
181 * might not be valid after.
182 */
183 pid = getpid();
184 if (pid == 1)
185 {
186 close(0);
187 freopen("/dev/console", "r", stdin);
188 setbuf(stdin, NULL);
189 close(1);
190 freopen("/dev/console", "w", stdout);
191 setbuf(stdout, NULL);
192 close(2);
193 freopen("/dev/console", "w", stderr);
194 setbuf(stderr, NULL);
195
196 result = mach_port_allocate(
197 mach_task_self(),
198 MACH_PORT_RIGHT_RECEIVE,
199 &init_notify_port);
200 if (result != KERN_SUCCESS)
201 kern_fatal(result, "mach_port_allocate");
202
203 result = mach_port_insert_right(
204 mach_task_self(),
205 init_notify_port,
206 init_notify_port,
207 MACH_MSG_TYPE_MAKE_SEND);
208 if (result != KERN_SUCCESS)
209 kern_fatal(result, "mach_port_insert_right");
210
211 result = task_set_bootstrap_port(
212 mach_task_self(),
213 init_notify_port);
214 if (result != KERN_SUCCESS)
215 kern_fatal(result, "task_set_bootstrap_port");
216
217 pid = fork();
218
219 if (pid < 0)
220 unix_fatal("fork");
221
222 else if (pid != 0) { /* PARENT - will become init when ready */
223 int fd;
224
225 /*
226 * Wait for mach_init ot give us a real bootstrap port
227 */
228 wait_for_go(init_notify_port);
229 info("Execing init");
230
231 close(0);
232 close(1);
233 close(2);
234 fd = open("/dev/tty", O_RDONLY);
235 if (fd >= 0) {
236 ioctl(fd, TIOCNOTTY, 0);
237 close(fd);
238 }
239
240 /* pass our arguments on to init */
241 argv[0] = INIT_PATH;
242 execv(argv[0], argv);
243 exit(1); /* will likely trigger a panic */
244
245 }
246 } else
247 init_notify_port = MACH_PORT_NULL;
248
249 /* Initialize error handling */
250 program_name = rindex(*argv, '/');
251 if (program_name)
252 program_name++;
253 else
254 program_name = *argv;
255 argv++; argc--;
256
257 /* Parse command line args */
258 while (argc > 0 && **argv == '-') {
259 argp = *argv++ + 1; argc--;
260 while (*argp) {
261 switch (c = *argp++) {
262 case 'd':
263 debugging = TRUE;
264 break;
265 case 'D':
266 debugging = FALSE;
267 break;
268 case 'F':
269 force_fork = TRUE;
270 break;
271 case 'r':
272 register_self = forward_ok = TRUE;
273 if (argc > 0) {
274 register_name = *argv++; argc--;
275 } else
276 fatal("-r requires name");
277 break;
278 case '-':
279 default:
280 break;
281 }
282 }
283 }
284
285 /*
286 * If we must fork, do it now before we get Mach ports in use
287 */
288 if (force_fork) {
289 pid = fork();
290 if (pid < 0)
291 unix_fatal("fork");
292 else if (pid != 0) /* PARENT: just exit */
293 exit(0);
294 }
295
296 /* block all but SIGHUP and SIGTERM and mark us as an init process */
297 setsid();
298 sigfillset(&mask);
299 sigdelset(&mask, SIGHUP);
300 signal(SIGHUP, toggle_debug);
301 sigdelset(&mask, SIGTERM);
302 signal(SIGTERM, start_shutdown);
303 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
304
305 init_errlog(pid == 0); /* are we a daemon? */
306 init_lists();
307
308 /*
309 * This task will become the bootstrap task, so go ahead and
310 * initialize the ports now.
311 */
312 bootstrap_self = mach_task_self();
313 inherited_uid = getuid();
314 init_ports();
315
316 log("Started with uid=%d%s%s%s",
317 inherited_uid,
318 (register_self) ? " registered-as=" : "",
319 (register_self) ? register_name : "",
320 (debugging) ? " in debug-mode" : "");
321
322
323 /*
324 * If we are supposed to coordinate with init, we have to
325 * get that port again, because we only have a (probably wrong)
326 * name in memory, not a proper right.
327 */
328 if (init_notify_port != MACH_PORT_NULL) {
329 result = task_get_bootstrap_port(
330 bootstrap_self,
331 &init_notify_port);
332 if (result != KERN_SUCCESS)
333 kern_fatal(result, "task_get_bootstrap_port");
334
335 unblock_init(init_notify_port, bootstraps.bootstrap_port);
336
337 result = task_set_bootstrap_port(
338 bootstrap_self,
339 MACH_PORT_NULL);
340 if (result != KERN_SUCCESS)
341 kern_fatal(result, "task_set_bootstrap_port");
342
343 result = mach_port_deallocate(
344 bootstrap_self,
345 init_notify_port);
346 if (result != KERN_SUCCESS)
347 kern_fatal(result, "mach_port_deallocate");
348
349 forward_ok = FALSE;
350 inherited_bootstrap_port = MACH_PORT_NULL;
351
352 } else {
353
354 /* get inherited bootstrap port */
355 result = task_get_bootstrap_port(
356 bootstrap_self,
357 &inherited_bootstrap_port);
358 if (result != KERN_SUCCESS)
359 kern_fatal(result, "task_get_bootstrap_port");
360
361 /* We set this explicitly as we start each child */
362 task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
363 if (inherited_bootstrap_port == MACH_PORT_NULL)
364 forward_ok = FALSE;
365
366 /* register "self" port with anscestor */
367 if (register_self && forward_ok) {
368 result = bootstrap_register(
369 inherited_bootstrap_port,
370 (char *)register_name,
371 bootstraps.bootstrap_port);
372 if (result != KERN_SUCCESS)
373 kern_fatal(result, "register self");
374 }
375 }
376
377
378 /* Kick off all continuously running server processes */
379 for ( serverp = FIRST(servers)
380 ; !IS_END(serverp, servers)
381 ; serverp = NEXT(serverp))
382 if (serverp->servertype != DEMAND)
383 start_server(serverp);
384
385 pthread_attr_init (&attr);
386 pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_DETACHED );
387 result = pthread_create(
388 &demand_thread,
389 &attr,
390 demand_loop,
391 NULL);
392 if (result) {
393 unix_error("pthread_create()");
394 exit(1);
395 }
396
397 /* Process bootstrap service requests */
398 server_loop(); /* Should never return */
399 exit(1);
400 }
401
402 static void
403 wait_for_go(mach_port_t init_notify_port)
404 {
405 struct {
406 mach_msg_header_t hdr;
407 mach_msg_trailer_t trailer;
408 } init_go_msg;
409 kern_return_t result;
410
411 /*
412 * For now, we just blindly wait until we receive a message or
413 * timeout. We don't expect any notifications, and if we get one,
414 * it probably means something dire has happened; so we might as
415 * well give a shot at letting init run.
416 */
417 result = mach_msg(
418 &init_go_msg.hdr, MACH_RCV_MSG,
419 0, sizeof(init_go_msg), init_notify_port,
420 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
421 if (result != KERN_SUCCESS) {
422 kern_error(result, "mach_msg(receive) failed in wait_for_go");
423 }
424 result = task_set_bootstrap_port(
425 mach_task_self(),
426 init_go_msg.hdr.msgh_remote_port);
427 if (result != KERN_SUCCESS) {
428 kern_error(result, "task_get_bootstrap_port()");
429 }
430 }
431
432
433 static void
434 unblock_init(mach_port_t init_notify_port,
435 mach_port_t newBootstrap)
436 {
437 mach_msg_header_t init_go_msg;
438 kern_return_t result;
439
440 /*
441 * Proc 1 is blocked in a msg_receive on its notify port, this lets
442 * it continue, and we hand off its new bootstrap port
443 */
444 init_go_msg.msgh_remote_port = init_notify_port;
445 init_go_msg.msgh_local_port = newBootstrap;
446 init_go_msg.msgh_bits = MACH_MSGH_BITS(
447 MACH_MSG_TYPE_COPY_SEND,
448 MACH_MSG_TYPE_MAKE_SEND);
449 init_go_msg.msgh_size = sizeof(init_go_msg);
450 result = mach_msg_send(&init_go_msg);
451 if (result != KERN_SUCCESS)
452 kern_fatal(result, "unblock_init mach_msg_send() failed");
453 debug("sent go message");
454 }
455
456
457 static void
458 init_ports(void)
459 {
460 kern_return_t result;
461 service_t *servicep;
462
463 /*
464 * This task will become the bootstrap task.
465 */
466 /* Create port set that server loop listens to */
467 result = mach_port_allocate(
468 bootstrap_self,
469 MACH_PORT_RIGHT_PORT_SET,
470 &bootstrap_port_set);
471 if (result != KERN_SUCCESS)
472 kern_fatal(result, "port_set_allocate");
473
474 /* Create demand port set that second thread listens to */
475 result = mach_port_allocate(
476 bootstrap_self,
477 MACH_PORT_RIGHT_PORT_SET,
478 &demand_port_set);
479 if (result != KERN_SUCCESS)
480 kern_fatal(result, "port_set_allocate");
481
482 /* Create notify port and add to server port set */
483 result = mach_port_allocate(
484 bootstrap_self,
485 MACH_PORT_RIGHT_RECEIVE,
486 &notify_port);
487 if (result != KERN_SUCCESS)
488 kern_fatal(result, "mach_port_allocate");
489
490 result = mach_port_move_member(
491 bootstrap_self,
492 notify_port,
493 bootstrap_port_set);
494 if (result != KERN_SUCCESS)
495 kern_fatal(result, "mach_port_move_member");
496
497 /* Create backup port and add to server port set */
498 result = mach_port_allocate(
499 bootstrap_self,
500 MACH_PORT_RIGHT_RECEIVE,
501 &backup_port);
502 if (result != KERN_SUCCESS)
503 kern_fatal(result, "mach_port_allocate");
504
505 result = mach_port_move_member(
506 bootstrap_self,
507 backup_port,
508 bootstrap_port_set);
509 if (result != KERN_SUCCESS)
510 kern_fatal(result, "mach_port_move_member");
511
512 /* Create "self" port and add to server port set */
513 result = mach_port_allocate(
514 bootstrap_self,
515 MACH_PORT_RIGHT_RECEIVE,
516 &bootstraps.bootstrap_port);
517 if (result != KERN_SUCCESS)
518 kern_fatal(result, "mach_port_allocate");
519 result = mach_port_insert_right(
520 bootstrap_self,
521 bootstraps.bootstrap_port,
522 bootstraps.bootstrap_port,
523 MACH_MSG_TYPE_MAKE_SEND);
524 if (result != KERN_SUCCESS)
525 kern_fatal(result, "mach_port_insert_right");
526
527 /* keep the root bootstrap port "active" */
528 bootstraps.requestor_port = bootstraps.bootstrap_port;
529
530 result = mach_port_move_member(
531 bootstrap_self,
532 bootstraps.bootstrap_port,
533 bootstrap_port_set);
534 if (result != KERN_SUCCESS)
535 kern_fatal(result, "mach_port_move_member");
536
537 /*
538 * Allocate service ports for declared services.
539 */
540 for ( servicep = FIRST(services)
541 ; ! IS_END(servicep, services)
542 ; servicep = NEXT(servicep))
543 {
544 switch (servicep->servicetype) {
545 case DECLARED:
546 result = mach_port_allocate(
547 bootstrap_self,
548 MACH_PORT_RIGHT_RECEIVE,
549 &(servicep->port));
550 if (result != KERN_SUCCESS)
551 kern_fatal(result, "mach_port_allocate");
552
553 result = mach_port_insert_right(
554 bootstrap_self,
555 servicep->port,
556 servicep->port,
557 MACH_MSG_TYPE_MAKE_SEND);
558 if (result != KERN_SUCCESS)
559 kern_fatal(result, "mach_port_insert_right");
560 info("Declared port %x for service %s",
561 servicep->port,
562 servicep->name);
563
564 if (servicep->server != NULL_SERVER &&
565 servicep->server->servertype == DEMAND) {
566 result = mach_port_move_member(
567 bootstrap_self,
568 servicep->port,
569 demand_port_set);
570 if (result != KERN_SUCCESS)
571 kern_fatal(result, "mach_port_move_member");
572 }
573 break;
574
575 case SELF:
576 servicep->port = bootstraps.bootstrap_port;
577 servicep->server = new_server(&bootstraps,
578 program_name,
579 inherited_uid,
580 MACHINIT);
581 info("Set port %x for self port",
582 bootstraps.bootstrap_port);
583 break;
584
585 case REGISTERED:
586 fatal("Can't allocate REGISTERED port!?!");
587 break;
588 }
589 }
590 }
591
592 boolean_t
593 active_bootstrap(bootstrap_info_t *bootstrap)
594 {
595 return (bootstrap->requestor_port != MACH_PORT_NULL);
596 }
597
598 boolean_t
599 useless_server(server_t *serverp)
600 {
601 return ( !active_bootstrap(serverp->bootstrap) ||
602 !lookup_service_by_server(serverp) ||
603 !serverp->activity);
604 }
605
606 boolean_t
607 active_server(server_t *serverp)
608 {
609 return (
610 #ifdef DELAYED_BOOTSTRAP_DESTROY
611 serverp->port ||
612 #else
613 (serverp->port && serverp->pid == NO_PID) ||
614 #endif
615 serverp->task_port || serverp->active_services);
616 }
617
618 static void
619 reap_server(server_t *serverp)
620 {
621 kern_return_t result;
622 pid_t presult;
623 int wstatus;
624
625 /*
626 * Reap our children.
627 */
628 presult = waitpid(serverp->pid, &wstatus, WNOHANG);
629 if (presult != serverp->pid) {
630 unix_error("waitpid: cmd = %s", serverp->cmd);
631 } else if (wstatus) {
632 log("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
633 serverp->port, serverp->bootstrap->bootstrap_port,
634 serverp->uid, serverp->cmd,
635 ((WIFEXITED(wstatus)) ?
636 "exited with non-zero status" :
637 "exited as a result of signal"),
638 ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) : WTERMSIG(wstatus)),
639 serverp->pid);
640 }
641 serverp->pid = 0;
642
643 /*
644 * Release the server task port reference, if we ever
645 * got it in the first place.
646 */
647 if (serverp->task_port != MACH_PORT_NULL) {
648 result = mach_port_deallocate(
649 mach_task_self(),
650 serverp->task_port);
651 if (result != KERN_SUCCESS)
652 kern_error(result, "mach_port_deallocate");
653 serverp->task_port = MACH_PORT_NULL;
654 }
655 }
656
657 static void
658 demand_server(server_t *serverp)
659 {
660 service_t *servicep;
661 kern_return_t result;
662
663 /*
664 * For on-demand servers, make sure that the service ports are
665 * back in on-demand portset. Active service ports should come
666 * back through a PORT_DESTROYED notification. We only have to
667 * worry about the inactive ports that may have been previously
668 * pulled from the set but never checked-in by the server.
669 */
670
671 for ( servicep = FIRST(services)
672 ; !IS_END(servicep, services)
673 ; servicep = NEXT(servicep))
674 {
675 if (serverp == servicep->server && !servicep->isActive) {
676 result = mach_port_move_member(
677 mach_task_self(),
678 servicep->port,
679 demand_port_set);
680 if (result != KERN_SUCCESS)
681 kern_fatal(result, "mach_port_move_member");
682 }
683 }
684 }
685
686 static
687 void dispatch_server(server_t *serverp)
688 {
689 if (!active_server(serverp)) {
690 if (useless_server(serverp))
691 delete_server(serverp);
692 else if (serverp->servertype == RESTARTABLE)
693 start_server(serverp);
694 else if (serverp->servertype == DEMAND)
695 demand_server(serverp);
696 }
697 }
698
699 void
700 setup_server(server_t *serverp)
701 {
702 kern_return_t result;
703 mach_port_t old_port;
704
705 /* Allocate privileged port for requests from service */
706 result = mach_port_allocate(mach_task_self(),
707 MACH_PORT_RIGHT_RECEIVE ,
708 &serverp->port);
709 info("Allocating port %x for server %s", serverp->port, serverp->cmd);
710 if (result != KERN_SUCCESS)
711 kern_fatal(result, "port_allocate");
712
713 /* Request no-senders notification so we can tell when server dies */
714 result = mach_port_request_notification(mach_task_self(),
715 serverp->port,
716 MACH_NOTIFY_NO_SENDERS,
717 1,
718 serverp->port,
719 MACH_MSG_TYPE_MAKE_SEND_ONCE,
720 &old_port);
721 if (result != KERN_SUCCESS)
722 kern_fatal(result, "mach_port_request_notification");
723
724 /* Add privileged server port to bootstrap port set */
725 result = mach_port_move_member(mach_task_self(),
726 serverp->port,
727 bootstrap_port_set);
728 if (result != KERN_SUCCESS)
729 kern_fatal(result, "mach_port_move_member");
730 }
731
732 static void
733 start_server(server_t *serverp)
734 {
735 kern_return_t result;
736 mach_port_t old_port;
737 int pid;
738
739 /*
740 * Do what's appropriate to get bootstrap port setup in server task
741 */
742 switch (serverp->servertype) {
743
744 case MACHINIT:
745 break;
746
747 case SERVER:
748 case DEMAND:
749 case RESTARTABLE:
750 #ifdef DELAYED_BOOTSTRAP_DESTROY
751 if (!serverp->port)
752 #endif
753 setup_server(serverp);
754
755 serverp->activity = 0;
756
757 /* Insert a send right */
758 result = mach_port_insert_right(mach_task_self(),
759 serverp->port,
760 serverp->port,
761 MACH_MSG_TYPE_MAKE_SEND);
762 if (result != KERN_SUCCESS)
763 kern_fatal(result, "mach_port_insert_right");
764
765 /* Give trusted service a unique bootstrap port */
766 result = task_set_bootstrap_port(mach_task_self(),
767 serverp->port);
768 if (result != KERN_SUCCESS)
769 kern_fatal(result, "task_set_bootstrap_port");
770
771 result = mach_port_deallocate(mach_task_self(),
772 serverp->port);
773 if (result != KERN_SUCCESS)
774 kern_fatal(result, "mach_port_deallocate");
775
776 pid = fork();
777 if (pid < 0) {
778 unix_error("fork");
779 } else if (pid == 0) { /* CHILD */
780 exec_server(serverp);
781 exit(1);
782 } else { /* PARENT */
783
784 result = task_set_bootstrap_port(
785 mach_task_self(),
786 MACH_PORT_NULL);
787 if (result != KERN_SUCCESS)
788 kern_fatal(result, "task_set_bootstrap_port");
789
790 info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
791 serverp->port, serverp->bootstrap->bootstrap_port,
792 serverp->uid, serverp->cmd, pid);
793 serverp->pid = pid;
794 result = task_for_pid(
795 mach_task_self(),
796 pid,
797 &serverp->task_port);
798 if (result != KERN_SUCCESS) {
799 kern_error(result, "getting server task port");
800 reap_server(serverp);
801 dispatch_server(serverp);
802 break;
803 }
804
805 /* Request dead name notification to tell when task dies */
806 result = mach_port_request_notification(
807 mach_task_self(),
808 serverp->task_port,
809 MACH_NOTIFY_DEAD_NAME,
810 0,
811 notify_port,
812 MACH_MSG_TYPE_MAKE_SEND_ONCE,
813 &old_port);
814 if (result != KERN_SUCCESS) {
815 kern_error(result, "mach_port_request_notification");
816 reap_server(serverp);
817 dispatch_server(serverp);
818 }
819 }
820 break;
821 }
822 }
823
824 static void
825 exec_server(server_t *serverp)
826 {
827 char **argv;
828 sigset_t mask;
829
830 /*
831 * Setup environment for server, someday this should be Mach stuff
832 * rather than Unix crud
833 */
834 argv = argvize(serverp->cmd);
835 close_errlog();
836
837 if (serverp->uid != inherited_uid)
838 if (setuid(serverp->uid) < 0)
839 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
840 serverp->port, serverp->bootstrap->bootstrap_port,
841 serverp->cmd, serverp->uid);
842
843 if (setsid() < 0) {
844 /*
845 * We can't keep this from happening, but we shouldn't start
846 * the server not as a process group leader. So, just fake like
847 * there was real activity, and exit the child. If needed,
848 * we'll re-launch it under another pid.
849 */
850 serverp->activity = 1;
851 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
852 serverp->port, serverp->bootstrap->bootstrap_port,
853 serverp->cmd);
854 }
855
856 sigemptyset(&mask);
857 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
858
859 execv(argv[0], argv);
860 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
861 serverp->port,
862 serverp->bootstrap->bootstrap_port,
863 serverp->cmd);
864 }
865
866 static char **
867 argvize(const char *string)
868 {
869 static char *argv[100], args[1000];
870 const char *cp;
871 char *argp, term;
872 int nargs;
873
874 /*
875 * Convert a command line into an argv for execv
876 */
877 nargs = 0;
878 argp = args;
879
880 for (cp = string; *cp;) {
881 while (isspace(*cp))
882 cp++;
883 term = (*cp == '"') ? *cp++ : '\0';
884 if (nargs < NELEM(argv))
885 argv[nargs++] = argp;
886 while (*cp && (term ? *cp != term : !isspace(*cp))
887 && argp < END_OF(args)) {
888 if (*cp == '\\')
889 cp++;
890 *argp++ = *cp;
891 if (*cp)
892 cp++;
893 }
894 *argp++ = '\0';
895 }
896 argv[nargs] = NULL;
897 return argv;
898 }
899
900 static void *
901 demand_loop(void *arg)
902 {
903 mach_msg_empty_rcv_t dummy;
904 kern_return_t dresult;
905
906
907 for(;;) {
908 mach_port_name_array_t members;
909 mach_msg_type_number_t membersCnt;
910 mach_port_status_t status;
911 mach_msg_type_number_t statusCnt;
912 int i;
913
914 /*
915 * Receive indication of message on demand service
916 * ports without actually receiving the message (we'll
917 * let the actual server do that.
918 */
919 dresult = mach_msg(
920 &dummy.header,
921 MACH_RCV_MSG|MACH_RCV_LARGE,
922 0,
923 0,
924 demand_port_set,
925 0,
926 MACH_PORT_NULL);
927 if (dresult != MACH_RCV_TOO_LARGE) {
928 kern_error(dresult, "demand_loop: mach_msg()");
929 continue;
930 }
931
932 /*
933 * If we are shutting down, there is no use processing
934 * any more of these messages.
935 */
936 if (shutdown_in_progress == TRUE)
937 return arg;
938
939 /*
940 * Some port(s) now have messages on them, find out
941 * which ones (there is no indication of which port
942 * triggered in the MACH_RCV_TOO_LARGE indication).
943 */
944 dresult = mach_port_get_set_status(
945 mach_task_self(),
946 demand_port_set,
947 &members,
948 &membersCnt);
949 if (dresult != KERN_SUCCESS) {
950 kern_error(dresult, "demand_loop: mach_port_get_set_status()");
951 continue;
952 }
953
954 for (i = 0; i < membersCnt; i++) {
955 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
956 dresult = mach_port_get_attributes(
957 mach_task_self(),
958 members[i],
959 MACH_PORT_RECEIVE_STATUS,
960 (mach_port_info_t)&status,
961 &statusCnt);
962 if (dresult != KERN_SUCCESS) {
963 kern_error(dresult, "demand_loop: mach_port_get_attributes()");
964 continue;
965 }
966
967 /*
968 * For each port with messages, take it out of the
969 * demand service portset, and inform the main thread
970 * that it might have to start the server responsible
971 * for it.
972 */
973 if (status.mps_msgcount) {
974 dresult = mach_port_move_member(
975 mach_task_self(),
976 members[i],
977 MACH_PORT_NULL);
978 if (dresult != KERN_SUCCESS) {
979 kern_error(dresult, "demand_loop: mach_port_move_member()");
980 continue;
981 }
982 notify_server_loop(members[i]);
983 }
984 }
985
986 dresult = vm_deallocate(
987 mach_task_self(),
988 (vm_address_t) members,
989 (vm_size_t) membersCnt * sizeof(mach_port_name_t));
990 if (dresult != KERN_SUCCESS) {
991 kern_error(dresult, "demand_loop: vm_deallocate()");
992 continue;
993 }
994 }
995 return NULL;
996 }
997
998 /*
999 * server_demux -- processes requests off our service port
1000 * Also handles notifications
1001 */
1002
1003 static boolean_t
1004 server_demux(
1005 mach_msg_header_t *Request,
1006 mach_msg_header_t *Reply)
1007 {
1008 bootstrap_info_t *bootstrap;
1009 service_t *servicep;
1010 server_t *serverp;
1011 kern_return_t result;
1012 mig_reply_error_t *reply;
1013
1014 debug("received message on port %x\n", Request->msgh_local_port);
1015
1016 /*
1017 * Do minimal cleanup and then exit.
1018 */
1019 if (shutdown_in_progress == TRUE) {
1020 log("Shutting down. Deactivating root bootstrap (%x) ...",
1021 bootstraps.bootstrap_port);
1022 deactivate_bootstrap(&bootstraps);
1023 log("Done.");
1024 exit(0);
1025 }
1026
1027 reply = (mig_reply_error_t *)Reply;
1028
1029 /*
1030 * Pick off notification messages
1031 */
1032 if (Request->msgh_local_port == notify_port) {
1033 mach_port_name_t np;
1034
1035 memset(reply, 0, sizeof(*reply));
1036 switch (Request->msgh_id) {
1037 case MACH_NOTIFY_DEAD_NAME:
1038 np = ((mach_dead_name_notification_t *)Request)->not_port;
1039 debug("Notified dead name %x", np);
1040
1041 if (np == inherited_bootstrap_port) {
1042 inherited_bootstrap_port = MACH_PORT_NULL;
1043 forward_ok = FALSE;
1044 }
1045
1046 /*
1047 * Check to see if a subset requestor port was deleted.
1048 */
1049 while (bootstrap = lookup_bootstrap_by_req_port(np)) {
1050 debug("Received dead name notification for bootstrap subset %x requestor port %x",
1051 bootstrap->bootstrap_port, bootstrap->requestor_port);
1052 mach_port_deallocate(
1053 mach_task_self(),
1054 bootstrap->requestor_port);
1055 bootstrap->requestor_port = MACH_PORT_NULL;
1056 deactivate_bootstrap(bootstrap);
1057 }
1058
1059 /*
1060 * Check to see if a defined service has gone
1061 * away.
1062 */
1063 while (servicep = lookup_service_by_port(np)) {
1064 /*
1065 * Port gone, registered service died.
1066 */
1067 debug("Received dead name notification for service %s "
1068 "on bootstrap port %x\n",
1069 servicep->name, servicep->bootstrap);
1070 debug("Service %s failed - deallocate", servicep->name);
1071 delete_service(servicep);
1072 }
1073
1074 /*
1075 * Check to see if a launched server task has gone
1076 * away.
1077 */
1078 if (serverp = lookup_server_by_task_port(np)) {
1079 /*
1080 * Port gone, server died.
1081 */
1082 debug("Received task death notification for server %s ",
1083 serverp->cmd);
1084 reap_server(serverp);
1085 dispatch_server(serverp);
1086 }
1087
1088 mach_port_deallocate(mach_task_self(), np);
1089 reply->RetCode = KERN_SUCCESS;
1090 break;
1091
1092 case MACH_NOTIFY_PORT_DELETED:
1093 np = ((mach_port_deleted_notification_t *)Request)->not_port;
1094 debug("port deleted notification on 0x%x\n", np);
1095 reply->RetCode = KERN_SUCCESS;
1096 break;
1097
1098 case MACH_NOTIFY_SEND_ONCE:
1099 debug("notification send-once right went unused\n");
1100 reply->RetCode = KERN_SUCCESS;
1101 break;
1102
1103 default:
1104 error("Unexpected notification: %d", Request->msgh_id);
1105 reply->RetCode = KERN_FAILURE;
1106 break;
1107 }
1108 }
1109
1110 else if (Request->msgh_local_port == backup_port) {
1111 mach_port_name_t np;
1112
1113 memset(reply, 0, sizeof(*reply));
1114
1115 np = ((mach_port_destroyed_notification_t *)Request)->not_port.name;
1116 servicep = lookup_service_by_port(np);
1117 if (servicep != NULL) {
1118 server_t *serverp = servicep->server;
1119
1120 switch (Request->msgh_id) {
1121
1122 case MACH_NOTIFY_PORT_DESTROYED:
1123 /*
1124 * Port sent back to us, server died.
1125 */
1126 debug("Received destroyed notification for service %s",
1127 servicep->name);
1128 debug("Service %x bootstrap %x backed up: %s",
1129 servicep->port, servicep->bootstrap->bootstrap_port,
1130 servicep->name);
1131 ASSERT(canReceive(servicep->port));
1132 servicep->isActive = FALSE;
1133 serverp->active_services--;
1134 dispatch_server(serverp);
1135 reply->RetCode = KERN_SUCCESS;
1136 break;
1137
1138 case DEMAND_REQUEST:
1139 /* message reflected over from demand start thread */
1140 if (!active_server(serverp))
1141 start_server(serverp);
1142 reply->RetCode = KERN_SUCCESS;
1143 break;
1144
1145 default:
1146 debug("Mysterious backup_port notification %d", Request->msgh_id);
1147 reply->RetCode = KERN_FAILURE;
1148 break;
1149 }
1150 } else {
1151 debug("Backup_port notification - previously deleted service");
1152 reply->RetCode = KERN_FAILURE;
1153 }
1154 }
1155
1156 else if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
1157 mach_port_t ns = Request->msgh_local_port;
1158
1159 if ((serverp = lookup_server_by_port(ns)) != NULL_SERVER) {
1160 /*
1161 * A server we launched has released his bootstrap
1162 * port send right. We won't re-launch him unless
1163 * his services came back to roost. But we need to
1164 * destroy the bootstrap port for fear of leaking.
1165 */
1166 debug("server %s dropped server port", serverp->cmd);
1167 serverp->port = MACH_PORT_NULL;
1168 dispatch_server(serverp);
1169 } else if (bootstrap = lookup_bootstrap_by_port(ns)) {
1170 /*
1171 * The last direct user of a deactivated bootstrap went away.
1172 * We can finally free it.
1173 */
1174 debug("Deallocating bootstrap %x: no more clients", ns);
1175 bootstrap->bootstrap_port = MACH_PORT_NULL;
1176 deallocate_bootstrap(bootstrap);
1177 }
1178
1179 result = mach_port_mod_refs(
1180 mach_task_self(),
1181 ns,
1182 MACH_PORT_RIGHT_RECEIVE,
1183 -1);
1184 if (result != KERN_SUCCESS)
1185 kern_fatal(result, "mach_port_mod_refs");
1186
1187 memset(reply, 0, sizeof(*reply));
1188 reply->RetCode = KERN_SUCCESS;
1189 }
1190
1191 else { /* must be a service request */
1192 debug("Handled request.");
1193 return bootstrap_server(Request, Reply);
1194 }
1195 return TRUE;
1196 }
1197
1198 /*
1199 * server_loop -- pick requests off our service port and process them
1200 * Also handles notifications
1201 */
1202 #define bootstrapMaxRequestSize 1024
1203 #define bootstrapMaxReplySize 1024
1204
1205 static void
1206 server_loop(void)
1207 {
1208 mach_msg_return_t mresult;
1209
1210 for (;;) {
1211 mresult = mach_msg_server(
1212 server_demux,
1213 bootstrapMaxRequestSize,
1214 bootstrap_port_set,
1215 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)|
1216 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
1217 if (mresult != MACH_MSG_SUCCESS)
1218 kern_error(mresult, "mach_msg_server");
1219 }
1220 }
1221
1222 boolean_t
1223 canReceive(mach_port_t port)
1224 {
1225 mach_port_type_t p_type;
1226 kern_return_t result;
1227
1228 result = mach_port_type(mach_task_self(), port, &p_type);
1229 if (result != KERN_SUCCESS) {
1230 kern_error(result, "port_type");
1231 return FALSE;
1232 }
1233 return ((p_type & MACH_PORT_TYPE_RECEIVE) != 0);
1234 }
1235
1236
1237 boolean_t
1238 canSend(mach_port_t port)
1239 {
1240 mach_port_type_t p_type;
1241 kern_return_t result;
1242
1243 result = mach_port_type(mach_task_self(), port, &p_type);
1244 if (result != KERN_SUCCESS) {
1245 kern_error(result, "port_type");
1246 return FALSE;
1247 }
1248 return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0);
1249 }