2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * bootstrap -- fundamental service initiator and port server
27 * Mike DeMoney, NeXT, Inc.
28 * Copyright, 1990. All rights reserved.
30 * bootstrap.c -- implementation of bootstrap main service loop
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>
59 #import "bootstrap_internal.h"
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
);
69 const char *program_name
; /* our name for error messages */
72 #define INIT_PATH "/sbin/init" /* default init path */
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
;
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)
97 * Private declarations
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
109 mach_port_t bootstrap_port
,
111 mach_port_t service_port
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
119 mach_port_t bootstrap_port_set
;
120 mach_port_t demand_port_set
;
121 pthread_t demand_thread
;
123 mach_port_t notify_port
;
124 mach_port_t backup_port
;
127 notify_server_loop(mach_port_name_t about
)
129 mach_port_destroyed_notification_t
not;
130 mach_msg_return_t nresult
;
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_header
);
142 if (nresult
!= MACH_MSG_SUCCESS
) {
143 kern_error(nresult
, "notify_server: mach_msg_send()");
147 void _myExit(int arg
)
152 void toggle_debug(int signal
)
154 debugging
= (debugging
) ? FALSE
: TRUE
;
157 void start_shutdown(int signal
)
159 debug("received SIGTERM");
160 shutdown_in_progress
= TRUE
;
161 notify_server_loop(MACH_PORT_DEAD
);
165 main(int argc
, char * argv
[])
170 kern_return_t result
;
171 mach_port_t init_notify_port
;
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.
187 freopen("/dev/console", "r", stdin
);
190 freopen("/dev/console", "w", stdout
);
191 setbuf(stdout
, NULL
);
193 freopen("/dev/console", "w", stderr
);
194 setbuf(stderr
, NULL
);
196 result
= mach_port_allocate(
198 MACH_PORT_RIGHT_RECEIVE
,
200 if (result
!= KERN_SUCCESS
)
201 kern_fatal(result
, "mach_port_allocate");
203 result
= mach_port_insert_right(
207 MACH_MSG_TYPE_MAKE_SEND
);
208 if (result
!= KERN_SUCCESS
)
209 kern_fatal(result
, "mach_port_insert_right");
211 result
= task_set_bootstrap_port(
214 if (result
!= KERN_SUCCESS
)
215 kern_fatal(result
, "task_set_bootstrap_port");
222 else if (pid
!= 0) { /* PARENT - will become init when ready */
226 * Wait for mach_init ot give us a real bootstrap port
228 wait_for_go(init_notify_port
);
229 info("Execing init");
234 fd
= open("/dev/tty", O_RDONLY
);
236 ioctl(fd
, TIOCNOTTY
, 0);
240 /* pass our arguments on to init */
242 execv(argv
[0], argv
);
243 exit(1); /* will likely trigger a panic */
247 init_notify_port
= MACH_PORT_NULL
;
249 /* Initialize error handling */
250 program_name
= rindex(*argv
, '/');
254 program_name
= *argv
;
257 /* Parse command line args */
258 while (argc
> 0 && **argv
== '-') {
259 argp
= *argv
++ + 1; argc
--;
261 switch (c
= *argp
++) {
272 register_self
= forward_ok
= TRUE
;
274 register_name
= *argv
++; argc
--;
276 fatal("-r requires name");
286 * If we must fork, do it now before we get Mach ports in use
292 else if (pid
!= 0) /* PARENT: just exit */
296 /* block all but SIGHUP and SIGTERM and mark us as an init process */
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
);
305 init_errlog(pid
== 0); /* are we a daemon? */
309 * This task will become the bootstrap task, so go ahead and
310 * initialize the ports now.
312 bootstrap_self
= mach_task_self();
313 inherited_uid
= getuid();
316 log("Started with uid=%d%s%s%s",
318 (register_self
) ? " registered-as=" : "",
319 (register_self
) ? register_name
: "",
320 (debugging
) ? " in debug-mode" : "");
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.
328 if (init_notify_port
!= MACH_PORT_NULL
) {
329 result
= task_get_bootstrap_port(
332 if (result
!= KERN_SUCCESS
)
333 kern_fatal(result
, "task_get_bootstrap_port");
335 unblock_init(init_notify_port
, bootstraps
.bootstrap_port
);
337 result
= task_set_bootstrap_port(
340 if (result
!= KERN_SUCCESS
)
341 kern_fatal(result
, "task_set_bootstrap_port");
343 result
= mach_port_deallocate(
346 if (result
!= KERN_SUCCESS
)
347 kern_fatal(result
, "mach_port_deallocate");
350 inherited_bootstrap_port
= MACH_PORT_NULL
;
354 /* get inherited bootstrap port */
355 result
= task_get_bootstrap_port(
357 &inherited_bootstrap_port
);
358 if (result
!= KERN_SUCCESS
)
359 kern_fatal(result
, "task_get_bootstrap_port");
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
)
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");
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
);
385 pthread_attr_init (&attr
);
386 pthread_attr_setdetachstate ( &attr
, PTHREAD_CREATE_DETACHED
);
387 result
= pthread_create(
393 unix_error("pthread_create()");
397 /* Process bootstrap service requests */
398 server_loop(); /* Should never return */
403 wait_for_go(mach_port_t init_notify_port
)
406 mach_msg_header_t hdr
;
407 mach_msg_trailer_t trailer
;
409 kern_return_t result
;
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.
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");
424 result
= task_set_bootstrap_port(
426 init_go_msg
.hdr
.msgh_remote_port
);
427 if (result
!= KERN_SUCCESS
) {
428 kern_error(result
, "task_get_bootstrap_port()");
434 unblock_init(mach_port_t init_notify_port
,
435 mach_port_t newBootstrap
)
437 mach_msg_header_t init_go_msg
;
438 kern_return_t result
;
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
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");
460 kern_return_t result
;
464 * This task will become the bootstrap task.
466 /* Create port set that server loop listens to */
467 result
= mach_port_allocate(
469 MACH_PORT_RIGHT_PORT_SET
,
470 &bootstrap_port_set
);
471 if (result
!= KERN_SUCCESS
)
472 kern_fatal(result
, "port_set_allocate");
474 /* Create demand port set that second thread listens to */
475 result
= mach_port_allocate(
477 MACH_PORT_RIGHT_PORT_SET
,
479 if (result
!= KERN_SUCCESS
)
480 kern_fatal(result
, "port_set_allocate");
482 /* Create notify port and add to server port set */
483 result
= mach_port_allocate(
485 MACH_PORT_RIGHT_RECEIVE
,
487 if (result
!= KERN_SUCCESS
)
488 kern_fatal(result
, "mach_port_allocate");
490 result
= mach_port_move_member(
494 if (result
!= KERN_SUCCESS
)
495 kern_fatal(result
, "mach_port_move_member");
497 /* Create backup port and add to server port set */
498 result
= mach_port_allocate(
500 MACH_PORT_RIGHT_RECEIVE
,
502 if (result
!= KERN_SUCCESS
)
503 kern_fatal(result
, "mach_port_allocate");
505 result
= mach_port_move_member(
509 if (result
!= KERN_SUCCESS
)
510 kern_fatal(result
, "mach_port_move_member");
512 /* Create "self" port and add to server port set */
513 result
= mach_port_allocate(
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(
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");
527 /* keep the root bootstrap port "active" */
528 bootstraps
.requestor_port
= bootstraps
.bootstrap_port
;
530 result
= mach_port_move_member(
532 bootstraps
.bootstrap_port
,
534 if (result
!= KERN_SUCCESS
)
535 kern_fatal(result
, "mach_port_move_member");
538 * Allocate service ports for declared services.
540 for ( servicep
= FIRST(services
)
541 ; ! IS_END(servicep
, services
)
542 ; servicep
= NEXT(servicep
))
544 switch (servicep
->servicetype
) {
546 result
= mach_port_allocate(
548 MACH_PORT_RIGHT_RECEIVE
,
550 if (result
!= KERN_SUCCESS
)
551 kern_fatal(result
, "mach_port_allocate");
553 result
= mach_port_insert_right(
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",
564 if (servicep
->server
!= NULL_SERVER
&&
565 servicep
->server
->servertype
== DEMAND
) {
566 result
= mach_port_move_member(
570 if (result
!= KERN_SUCCESS
)
571 kern_fatal(result
, "mach_port_move_member");
576 servicep
->port
= bootstraps
.bootstrap_port
;
577 servicep
->server
= new_server(&bootstraps
,
581 info("Set port %x for self port",
582 bootstraps
.bootstrap_port
);
586 fatal("Can't allocate REGISTERED port!?!");
593 active_bootstrap(bootstrap_info_t
*bootstrap
)
595 return (bootstrap
->requestor_port
!= MACH_PORT_NULL
);
599 useless_server(server_t
*serverp
)
601 return ( !active_bootstrap(serverp
->bootstrap
) ||
602 !lookup_service_by_server(serverp
) ||
607 active_server(server_t
*serverp
)
610 #ifdef DELAYED_BOOTSTRAP_DESTROY
613 (serverp
->port
&& serverp
->pid
== NO_PID
) ||
615 serverp
->task_port
|| serverp
->active_services
);
619 reap_server(server_t
*serverp
)
621 kern_return_t result
;
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
)),
644 * Release the server task port reference, if we ever
645 * got it in the first place.
647 if (serverp
->task_port
!= MACH_PORT_NULL
) {
648 result
= mach_port_deallocate(
651 if (result
!= KERN_SUCCESS
)
652 kern_error(result
, "mach_port_deallocate");
653 serverp
->task_port
= MACH_PORT_NULL
;
658 demand_server(server_t
*serverp
)
661 kern_return_t result
;
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.
671 for ( servicep
= FIRST(services
)
672 ; !IS_END(servicep
, services
)
673 ; servicep
= NEXT(servicep
))
675 if (serverp
== servicep
->server
&& !servicep
->isActive
) {
676 result
= mach_port_move_member(
680 if (result
!= KERN_SUCCESS
)
681 kern_fatal(result
, "mach_port_move_member");
687 void dispatch_server(server_t
*serverp
)
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
);
700 setup_server(server_t
*serverp
)
702 kern_return_t result
;
703 mach_port_t old_port
;
705 /* Allocate privileged port for requests from service */
706 result
= mach_port_allocate(mach_task_self(),
707 MACH_PORT_RIGHT_RECEIVE
,
709 info("Allocating port %x for server %s", serverp
->port
, serverp
->cmd
);
710 if (result
!= KERN_SUCCESS
)
711 kern_fatal(result
, "port_allocate");
713 /* Request no-senders notification so we can tell when server dies */
714 result
= mach_port_request_notification(mach_task_self(),
716 MACH_NOTIFY_NO_SENDERS
,
719 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
721 if (result
!= KERN_SUCCESS
)
722 kern_fatal(result
, "mach_port_request_notification");
724 /* Add privileged server port to bootstrap port set */
725 result
= mach_port_move_member(mach_task_self(),
728 if (result
!= KERN_SUCCESS
)
729 kern_fatal(result
, "mach_port_move_member");
733 start_server(server_t
*serverp
)
735 kern_return_t result
;
736 mach_port_t old_port
;
740 * Do what's appropriate to get bootstrap port setup in server task
742 switch (serverp
->servertype
) {
750 #ifdef DELAYED_BOOTSTRAP_DESTROY
753 setup_server(serverp
);
755 serverp
->activity
= 0;
757 /* Insert a send right */
758 result
= mach_port_insert_right(mach_task_self(),
761 MACH_MSG_TYPE_MAKE_SEND
);
762 if (result
!= KERN_SUCCESS
)
763 kern_fatal(result
, "mach_port_insert_right");
765 /* Give trusted service a unique bootstrap port */
766 result
= task_set_bootstrap_port(mach_task_self(),
768 if (result
!= KERN_SUCCESS
)
769 kern_fatal(result
, "task_set_bootstrap_port");
771 result
= mach_port_deallocate(mach_task_self(),
773 if (result
!= KERN_SUCCESS
)
774 kern_fatal(result
, "mach_port_deallocate");
779 } else if (pid
== 0) { /* CHILD */
780 exec_server(serverp
);
782 } else { /* PARENT */
784 result
= task_set_bootstrap_port(
787 if (result
!= KERN_SUCCESS
)
788 kern_fatal(result
, "task_set_bootstrap_port");
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
);
794 result
= task_for_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
);
805 /* Request dead name notification to tell when task dies */
806 result
= mach_port_request_notification(
809 MACH_NOTIFY_DEAD_NAME
,
812 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
814 if (result
!= KERN_SUCCESS
) {
815 kern_error(result
, "mach_port_request_notification");
816 reap_server(serverp
);
817 dispatch_server(serverp
);
825 exec_server(server_t
*serverp
)
831 * Setup environment for server, someday this should be Mach stuff
832 * rather than Unix crud
834 argv
= argvize(serverp
->cmd
);
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
);
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.
850 serverp
->activity
= 1;
851 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
852 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
857 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
859 execv(argv
[0], argv
);
860 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
862 serverp
->bootstrap
->bootstrap_port
,
867 argvize(const char *string
)
869 static char *argv
[100], args
[1000];
875 * Convert a command line into an argv for execv
880 for (cp
= string
; *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
)) {
901 demand_loop(void *arg
)
903 mach_msg_empty_rcv_t dummy
;
904 kern_return_t dresult
;
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
;
915 * Receive indication of message on demand service
916 * ports without actually receiving the message (we'll
917 * let the actual server do that.
921 MACH_RCV_MSG
|MACH_RCV_LARGE
,
927 if (dresult
!= MACH_RCV_TOO_LARGE
) {
928 kern_error(dresult
, "demand_loop: mach_msg()");
933 * If we are shutting down, there is no use processing
934 * any more of these messages.
936 if (shutdown_in_progress
== TRUE
)
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).
944 dresult
= mach_port_get_set_status(
949 if (dresult
!= KERN_SUCCESS
) {
950 kern_error(dresult
, "demand_loop: mach_port_get_set_status()");
954 for (i
= 0; i
< membersCnt
; i
++) {
955 statusCnt
= MACH_PORT_RECEIVE_STATUS_COUNT
;
956 dresult
= mach_port_get_attributes(
959 MACH_PORT_RECEIVE_STATUS
,
960 (mach_port_info_t
)&status
,
962 if (dresult
!= KERN_SUCCESS
) {
963 kern_error(dresult
, "demand_loop: mach_port_get_attributes()");
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
973 if (status
.mps_msgcount
) {
974 dresult
= mach_port_move_member(
978 if (dresult
!= KERN_SUCCESS
) {
979 kern_error(dresult
, "demand_loop: mach_port_move_member()");
982 notify_server_loop(members
[i
]);
986 dresult
= vm_deallocate(
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()");
999 * server_demux -- processes requests off our service port
1000 * Also handles notifications
1005 mach_msg_header_t
*Request
,
1006 mach_msg_header_t
*Reply
)
1008 bootstrap_info_t
*bootstrap
;
1009 service_t
*servicep
;
1011 kern_return_t result
;
1012 mig_reply_error_t
*reply
;
1014 debug("received message on port %x\n", Request
->msgh_local_port
);
1017 * Do minimal cleanup and then exit.
1019 if (shutdown_in_progress
== TRUE
) {
1020 log("Shutting down. Deactivating root bootstrap (%x) ...",
1021 bootstraps
.bootstrap_port
);
1022 deactivate_bootstrap(&bootstraps
);
1027 reply
= (mig_reply_error_t
*)Reply
;
1030 * Pick off notification messages
1032 if (Request
->msgh_local_port
== notify_port
) {
1033 mach_port_name_t np
;
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
);
1041 if (np
== inherited_bootstrap_port
) {
1042 inherited_bootstrap_port
= MACH_PORT_NULL
;
1047 * Check to see if a subset requestor port was deleted.
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(
1054 bootstrap
->requestor_port
);
1055 bootstrap
->requestor_port
= MACH_PORT_NULL
;
1056 deactivate_bootstrap(bootstrap
);
1060 * Check to see if a defined service has gone
1063 while (servicep
= lookup_service_by_port(np
)) {
1065 * Port gone, registered service died.
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
);
1075 * Check to see if a launched server task has gone
1078 if (serverp
= lookup_server_by_task_port(np
)) {
1080 * Port gone, server died.
1082 debug("Received task death notification for server %s ",
1084 reap_server(serverp
);
1085 dispatch_server(serverp
);
1088 mach_port_deallocate(mach_task_self(), np
);
1089 reply
->RetCode
= KERN_SUCCESS
;
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
;
1098 case MACH_NOTIFY_SEND_ONCE
:
1099 debug("notification send-once right went unused\n");
1100 reply
->RetCode
= KERN_SUCCESS
;
1104 error("Unexpected notification: %d", Request
->msgh_id
);
1105 reply
->RetCode
= KERN_FAILURE
;
1110 else if (Request
->msgh_local_port
== backup_port
) {
1111 mach_port_name_t np
;
1113 memset(reply
, 0, sizeof(*reply
));
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
;
1120 switch (Request
->msgh_id
) {
1122 case MACH_NOTIFY_PORT_DESTROYED
:
1124 * Port sent back to us, server died.
1126 debug("Received destroyed notification for service %s",
1128 debug("Service %x bootstrap %x backed up: %s",
1129 servicep
->port
, servicep
->bootstrap
->bootstrap_port
,
1131 ASSERT(canReceive(servicep
->port
));
1132 servicep
->isActive
= FALSE
;
1133 serverp
->active_services
--;
1134 dispatch_server(serverp
);
1135 reply
->RetCode
= KERN_SUCCESS
;
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
;
1146 debug("Mysterious backup_port notification %d", Request
->msgh_id
);
1147 reply
->RetCode
= KERN_FAILURE
;
1151 debug("Backup_port notification - previously deleted service");
1152 reply
->RetCode
= KERN_FAILURE
;
1156 else if (Request
->msgh_id
== MACH_NOTIFY_NO_SENDERS
) {
1157 mach_port_t ns
= Request
->msgh_local_port
;
1159 if ((serverp
= lookup_server_by_port(ns
)) != NULL_SERVER
) {
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.
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
)) {
1171 * The last direct user of a deactivated bootstrap went away.
1172 * We can finally free it.
1174 debug("Deallocating bootstrap %x: no more clients", ns
);
1175 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
1176 deallocate_bootstrap(bootstrap
);
1179 result
= mach_port_mod_refs(
1182 MACH_PORT_RIGHT_RECEIVE
,
1184 if (result
!= KERN_SUCCESS
)
1185 kern_fatal(result
, "mach_port_mod_refs");
1187 memset(reply
, 0, sizeof(*reply
));
1188 reply
->RetCode
= KERN_SUCCESS
;
1191 else { /* must be a service request */
1192 debug("Handled request.");
1193 return bootstrap_server(Request
, Reply
);
1199 * server_loop -- pick requests off our service port and process them
1200 * Also handles notifications
1202 #define bootstrapMaxRequestSize 1024
1203 #define bootstrapMaxReplySize 1024
1208 mach_msg_return_t mresult
;
1211 mresult
= mach_msg_server(
1213 bootstrapMaxRequestSize
,
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");
1223 canReceive(mach_port_t port
)
1225 mach_port_type_t p_type
;
1226 kern_return_t result
;
1228 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1229 if (result
!= KERN_SUCCESS
) {
1230 kern_error(result
, "port_type");
1233 return ((p_type
& MACH_PORT_TYPE_RECEIVE
) != 0);
1238 canSend(mach_port_t port
)
1240 mach_port_type_t p_type
;
1241 kern_return_t result
;
1243 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1244 if (result
!= KERN_SUCCESS
) {
1245 kern_error(result
, "port_type");
1248 return ((p_type
& MACH_PORT_TYPE_PORT_RIGHTS
) != 0);