2 * Copyright (c) 1999-2003 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>
51 #import <sys/resource.h>
62 #import "bootstrap_internal.h"
66 /* Mig should produce a declaration for this, but doesn't */
67 extern boolean_t
bootstrap_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
72 const char *program_name
; /* our name for error messages */
75 #define INIT_PATH "/sbin/init" /* default init path */
79 mach_port_t inherited_bootstrap_port
= MACH_PORT_NULL
;
80 boolean_t forward_ok
= FALSE
;
81 boolean_t shutdown_in_progress
= FALSE
;
82 boolean_t debugging
= FALSE
;
83 boolean_t register_self
= FALSE
;
84 boolean_t force_fork
= FALSE
;
85 const char *register_name
;
86 task_t bootstrap_self
;
95 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
96 #define END_OF(x) (&(x)[NELEM(x)])
97 #define streq(a,b) (strcmp(a,b) == 0)
100 * Private declarations
102 static void wait_for_go(mach_port_t init_notify_port
);
103 static void init_ports(void);
104 static void start_server(server_t
*serverp
);
105 static void unblock_init(mach_port_t init_notify_port
, mach_port_t newBootstrap
);
106 static void exec_server(server_t
*serverp
);
107 static char **argvize(const char *string
);
108 static void *demand_loop(void *arg
);
109 static void server_loop(void);
110 extern kern_return_t bootstrap_register
112 mach_port_t bootstrap_port
,
114 mach_port_t service_port
118 * Private ports we hold receive rights for. We also hold receive rights
119 * for all the privileged ports. Those are maintained in the server
122 mach_port_t bootstrap_port_set
;
123 mach_port_t demand_port_set
;
124 pthread_t demand_thread
;
126 mach_port_t notify_port
;
127 mach_port_t backup_port
;
131 enablecoredumps(boolean_t enabled
)
133 struct rlimit rlimit
;
135 getrlimit(RLIMIT_CORE
, &rlimit
);
136 rlimit
.rlim_cur
= (enabled
) ? rlimit
.rlim_max
: 0;
137 setrlimit(RLIMIT_CORE
, &rlimit
);
141 toggle_debug(int signal
)
144 debugging
= (debugging
) ? FALSE
: TRUE
;
145 enablecoredumps(debugging
);
148 static mach_msg_return_t
150 mach_port_name_t about
,
151 mach_msg_option_t options
)
153 mach_port_destroyed_notification_t
not;
154 mach_msg_size_t size
= sizeof(not) - sizeof(not.trailer
);
156 not.not_header
.msgh_id
= DEMAND_REQUEST
;
157 not.not_header
.msgh_remote_port
= backup_port
;
158 not.not_header
.msgh_local_port
= MACH_PORT_NULL
;
159 not.not_header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
160 not.not_header
.msgh_size
= size
;
161 not.not_body
.msgh_descriptor_count
= 1;
162 not.not_port
.type
= MACH_MSG_PORT_DESCRIPTOR
;
163 not.not_port
.disposition
= MACH_MSG_TYPE_PORT_NAME
;
164 not.not_port
.name
= about
;
165 return mach_msg(¬.not_header
, MACH_SEND_MSG
|options
, size
,
166 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
170 notify_server_loop(mach_port_name_t about
)
172 mach_msg_return_t result
;
174 result
= inform_server_loop(about
, MACH_MSG_OPTION_NONE
);
175 if (result
!= MACH_MSG_SUCCESS
)
176 kern_error(result
, "notify_server_loop: mach_msg()");
179 void start_shutdown(int signal
)
181 shutdown_in_progress
= TRUE
;
182 (void) inform_server_loop(MACH_PORT_NULL
, MACH_SEND_TIMEOUT
);
186 main(int argc
, char * argv
[])
190 kern_return_t result
;
191 mach_port_t init_notify_port
;
197 * If we are pid one, we have to exec init. Before doing so, we'll
198 * fork a child, and that will become the true mach_init. But we have
199 * to be very careful about ports. They aren't inherited across fork,
200 * so we have to avoid storing port names in memory before the fork that
201 * might not be valid after.
207 freopen("/dev/console", "r", stdin
);
210 freopen("/dev/console", "w", stdout
);
211 setbuf(stdout
, NULL
);
213 freopen("/dev/console", "w", stderr
);
214 setbuf(stderr
, NULL
);
216 result
= mach_port_allocate(
218 MACH_PORT_RIGHT_RECEIVE
,
220 if (result
!= KERN_SUCCESS
)
221 kern_fatal(result
, "mach_port_allocate");
223 result
= mach_port_insert_right(
227 MACH_MSG_TYPE_MAKE_SEND
);
228 if (result
!= KERN_SUCCESS
)
229 kern_fatal(result
, "mach_port_insert_right");
231 result
= task_set_bootstrap_port(
234 if (result
!= KERN_SUCCESS
)
235 kern_fatal(result
, "task_set_bootstrap_port");
242 else if (pid
!= 0) { /* PARENT - will become init when ready */
246 * Wait for mach_init ot give us a real bootstrap port
248 wait_for_go(init_notify_port
);
253 fd
= open("/dev/tty", O_RDONLY
);
255 ioctl(fd
, TIOCNOTTY
, 0);
259 /* pass our arguments on to init */
261 execv(argv
[0], argv
);
262 exit(1); /* will likely trigger a panic */
267 * Child - will continue along as mach_init. Save off
268 * the init_notify_port and put back a NULL bootstrap
269 * port for ourselves.
271 init_notify_port
= bootstrap_port
;
272 bootstrap_port
= MACH_PORT_NULL
;
273 (void)task_set_bootstrap_port(
276 if (result
!= KERN_SUCCESS
)
277 kern_fatal(result
, "task_get_bootstrap_port");
279 init_notify_port
= MACH_PORT_NULL
;
281 /* Initialize error handling */
282 program_name
= rindex(*argv
, '/');
286 program_name
= *argv
;
289 /* Parse command line args */
290 while (argc
> 0 && **argv
== '-') {
291 argp
= *argv
++ + 1; argc
--;
293 switch (c
= *argp
++) {
301 if (init_notify_port
!= MACH_PORT_NULL
)
305 register_self
= forward_ok
= TRUE
;
307 register_name
= *argv
++; argc
--;
309 fatal("-r requires name");
319 * If we must fork, do it now before we get Mach ports in use
325 else if (pid
!= 0) /* PARENT: just exit */
330 * This task will become the bootstrap task, initialize the ports.
332 bootstrap_self
= mach_task_self();
333 inherited_uid
= getuid();
337 if (init_notify_port
!= MACH_PORT_NULL
) {
338 /* send init a real bootstrap port to use */
339 unblock_init(init_notify_port
, bootstraps
.bootstrap_port
);
341 result
= mach_port_deallocate(
344 if (result
!= KERN_SUCCESS
)
345 kern_fatal(result
, "mach_port_deallocate");
348 inherited_bootstrap_port
= MACH_PORT_NULL
;
351 /* get inherited bootstrap port */
352 result
= task_get_bootstrap_port(
354 &inherited_bootstrap_port
);
355 if (result
!= KERN_SUCCESS
)
356 kern_fatal(result
, "task_get_bootstrap_port");
358 /* We set this explicitly as we start each child */
359 task_set_bootstrap_port(bootstrap_self
, MACH_PORT_NULL
);
360 if (inherited_bootstrap_port
== MACH_PORT_NULL
)
363 /* register "self" port with anscestor */
364 if (register_self
&& forward_ok
) {
365 result
= bootstrap_register(
366 inherited_bootstrap_port
,
367 (char *)register_name
,
368 bootstraps
.bootstrap_port
);
369 if (result
!= KERN_SUCCESS
)
370 kern_fatal(result
, "register self");
374 pthread_attr_init (&attr
);
375 pthread_attr_setdetachstate ( &attr
, PTHREAD_CREATE_DETACHED
);
376 result
= pthread_create(
382 unix_error("pthread_create()");
386 /* block all but SIGHUP and SIGTERM */
388 sigdelset(&mask
, SIGHUP
);
389 signal(SIGHUP
, toggle_debug
);
390 sigdelset(&mask
, SIGTERM
);
391 signal(SIGTERM
, start_shutdown
);
392 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
395 * Construct a very basic environment - as much as if we
396 * were actually forked from init (instead of the other
399 * Set up the PATH to be approriate for the root user.
400 * Create an initial session.
401 * Establish an initial user.
402 * Disbale core dumps.
406 enablecoredumps(debugging
);
407 setenv("PATH", _PATH_STDPATH
, 1);
409 init_errlog(pid
== 0); /* are we a daemon? */
410 notice("Started with uid=%d%s%s%s",
412 (register_self
) ? " registered-as=" : "",
413 (register_self
) ? register_name
: "",
414 (debugging
) ? " in debug-mode" : "");
416 /* Process bootstrap service requests */
417 server_loop(); /* Should never return */
422 wait_for_go(mach_port_t init_notify_port
)
425 mach_msg_header_t hdr
;
426 mach_msg_trailer_t trailer
;
428 kern_return_t result
;
431 * For now, we just blindly wait until we receive a message or
432 * timeout. We don't expect any notifications, and if we get one,
433 * it probably means something dire has happened; so we might as
434 * well give a shot at letting init run.
437 &init_go_msg
.hdr
, MACH_RCV_MSG
,
438 0, sizeof(init_go_msg
), init_notify_port
,
439 MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
440 if (result
!= KERN_SUCCESS
) {
441 kern_error(result
, "mach_msg(receive) failed in wait_for_go");
443 bootstrap_port
= init_go_msg
.hdr
.msgh_remote_port
;
444 result
= task_set_bootstrap_port(
447 if (result
!= KERN_SUCCESS
) {
448 kern_error(result
, "task_get_bootstrap_port()");
454 unblock_init(mach_port_t init_notify_port
,
455 mach_port_t newBootstrap
)
457 mach_msg_header_t init_go_msg
;
458 kern_return_t result
;
461 * Proc 1 is blocked in a msg_receive on its notify port, this lets
462 * it continue, and we hand off its new bootstrap port
464 init_go_msg
.msgh_remote_port
= init_notify_port
;
465 init_go_msg
.msgh_local_port
= newBootstrap
;
466 init_go_msg
.msgh_bits
= MACH_MSGH_BITS(
467 MACH_MSG_TYPE_COPY_SEND
,
468 MACH_MSG_TYPE_MAKE_SEND
);
469 init_go_msg
.msgh_size
= sizeof(init_go_msg
);
470 result
= mach_msg_send(&init_go_msg
);
471 if (result
!= KERN_SUCCESS
)
472 kern_fatal(result
, "unblock_init mach_msg_send() failed");
473 debug("sent go message");
480 kern_return_t result
;
483 * This task will become the bootstrap task.
485 /* Create port set that server loop listens to */
486 result
= mach_port_allocate(
488 MACH_PORT_RIGHT_PORT_SET
,
489 &bootstrap_port_set
);
490 if (result
!= KERN_SUCCESS
)
491 kern_fatal(result
, "port_set_allocate");
493 /* Create demand port set that second thread listens to */
494 result
= mach_port_allocate(
496 MACH_PORT_RIGHT_PORT_SET
,
498 if (result
!= KERN_SUCCESS
)
499 kern_fatal(result
, "port_set_allocate");
501 /* Create notify port and add to server port set */
502 result
= mach_port_allocate(
504 MACH_PORT_RIGHT_RECEIVE
,
506 if (result
!= KERN_SUCCESS
)
507 kern_fatal(result
, "mach_port_allocate");
509 result
= mach_port_move_member(
513 if (result
!= KERN_SUCCESS
)
514 kern_fatal(result
, "mach_port_move_member");
516 /* Create backup port and add to server port set */
517 result
= mach_port_allocate(
519 MACH_PORT_RIGHT_RECEIVE
,
521 if (result
!= KERN_SUCCESS
)
522 kern_fatal(result
, "mach_port_allocate");
524 result
= mach_port_move_member(
528 if (result
!= KERN_SUCCESS
)
529 kern_fatal(result
, "mach_port_move_member");
531 /* Create "self" port and add to server port set */
532 result
= mach_port_allocate(
534 MACH_PORT_RIGHT_RECEIVE
,
535 &bootstraps
.bootstrap_port
);
536 if (result
!= KERN_SUCCESS
)
537 kern_fatal(result
, "mach_port_allocate");
538 result
= mach_port_insert_right(
540 bootstraps
.bootstrap_port
,
541 bootstraps
.bootstrap_port
,
542 MACH_MSG_TYPE_MAKE_SEND
);
543 if (result
!= KERN_SUCCESS
)
544 kern_fatal(result
, "mach_port_insert_right");
546 /* keep the root bootstrap port "active" */
547 bootstraps
.requestor_port
= bootstraps
.bootstrap_port
;
549 result
= mach_port_move_member(
551 bootstraps
.bootstrap_port
,
553 if (result
!= KERN_SUCCESS
)
554 kern_fatal(result
, "mach_port_move_member");
558 active_bootstrap(bootstrap_info_t
*bootstrap
)
560 return (bootstrap
->requestor_port
!= MACH_PORT_NULL
);
564 useless_server(server_t
*serverp
)
566 return ( !active_bootstrap(serverp
->bootstrap
) ||
567 !lookup_service_by_server(serverp
) ||
572 active_server(server_t
*serverp
)
574 return ( serverp
->port
||
575 serverp
->task_port
|| serverp
->active_services
);
579 reap_server(server_t
*serverp
)
581 kern_return_t result
;
588 presult
= waitpid(serverp
->pid
, &wstatus
, WNOHANG
);
589 if (presult
!= serverp
->pid
) {
590 unix_error("waitpid: cmd = %s", serverp
->cmd
);
591 } else if (wstatus
) {
592 notice("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
593 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
594 serverp
->uid
, serverp
->cmd
,
595 ((WIFEXITED(wstatus
)) ?
596 "exited with non-zero status" :
597 "exited as a result of signal"),
598 ((WIFEXITED(wstatus
)) ? WEXITSTATUS(wstatus
) : WTERMSIG(wstatus
)),
604 * Release the server task port reference, if we ever
605 * got it in the first place.
607 if (serverp
->task_port
!= MACH_PORT_NULL
) {
608 result
= mach_port_deallocate(
611 if (result
!= KERN_SUCCESS
)
612 kern_error(result
, "mach_port_deallocate");
613 serverp
->task_port
= MACH_PORT_NULL
;
618 demand_server(server_t
*serverp
)
621 kern_return_t result
;
624 * For on-demand servers, make sure that the service ports are
625 * back in on-demand portset. Active service ports should come
626 * back through a PORT_DESTROYED notification. We only have to
627 * worry about the inactive ports that may have been previously
628 * pulled from the set but never checked-in by the server.
631 for ( servicep
= FIRST(services
)
632 ; !IS_END(servicep
, services
)
633 ; servicep
= NEXT(servicep
))
635 if (serverp
== servicep
->server
&& !servicep
->isActive
) {
636 result
= mach_port_move_member(
640 if (result
!= KERN_SUCCESS
)
641 kern_fatal(result
, "mach_port_move_member");
647 void dispatch_server(server_t
*serverp
)
649 if (!active_server(serverp
)) {
650 if (useless_server(serverp
))
651 delete_server(serverp
);
652 else if (serverp
->servertype
== RESTARTABLE
)
653 start_server(serverp
);
654 else if (serverp
->servertype
== DEMAND
)
655 demand_server(serverp
);
660 setup_server(server_t
*serverp
)
662 kern_return_t result
;
663 mach_port_t old_port
;
665 /* Allocate privileged port for requests from service */
666 result
= mach_port_allocate(mach_task_self(),
667 MACH_PORT_RIGHT_RECEIVE
,
669 info("Allocating port %x for server %s", serverp
->port
, serverp
->cmd
);
670 if (result
!= KERN_SUCCESS
)
671 kern_fatal(result
, "port_allocate");
673 /* Request no-senders notification so we can tell when server dies */
674 result
= mach_port_request_notification(mach_task_self(),
676 MACH_NOTIFY_NO_SENDERS
,
679 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
681 if (result
!= KERN_SUCCESS
)
682 kern_fatal(result
, "mach_port_request_notification");
684 /* Add privileged server port to bootstrap port set */
685 result
= mach_port_move_member(mach_task_self(),
688 if (result
!= KERN_SUCCESS
)
689 kern_fatal(result
, "mach_port_move_member");
693 start_server(server_t
*serverp
)
695 kern_return_t result
;
696 mach_port_t old_port
;
700 * Do what's appropriate to get bootstrap port setup in server task
702 switch (serverp
->servertype
) {
711 setup_server(serverp
);
713 serverp
->activity
= 0;
715 /* Insert a send right */
716 result
= mach_port_insert_right(mach_task_self(),
719 MACH_MSG_TYPE_MAKE_SEND
);
720 if (result
!= KERN_SUCCESS
)
721 kern_fatal(result
, "mach_port_insert_right");
723 /* Give trusted service a unique bootstrap port */
724 result
= task_set_bootstrap_port(mach_task_self(),
726 if (result
!= KERN_SUCCESS
)
727 kern_fatal(result
, "task_set_bootstrap_port");
729 result
= mach_port_deallocate(mach_task_self(),
731 if (result
!= KERN_SUCCESS
)
732 kern_fatal(result
, "mach_port_deallocate");
737 } else if (pid
== 0) { /* CHILD */
738 exec_server(serverp
);
740 } else { /* PARENT */
742 result
= task_set_bootstrap_port(
745 if (result
!= KERN_SUCCESS
)
746 kern_fatal(result
, "task_set_bootstrap_port");
748 info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
749 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
750 serverp
->uid
, serverp
->cmd
, pid
);
752 result
= task_for_pid(
755 &serverp
->task_port
);
756 if (result
!= KERN_SUCCESS
) {
757 kern_error(result
, "getting server task port");
758 reap_server(serverp
);
759 dispatch_server(serverp
);
763 /* Request dead name notification to tell when task dies */
764 result
= mach_port_request_notification(
767 MACH_NOTIFY_DEAD_NAME
,
770 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
772 if (result
!= KERN_SUCCESS
) {
773 kern_error(result
, "mach_port_request_notification");
774 reap_server(serverp
);
775 dispatch_server(serverp
);
783 exec_server(server_t
*serverp
)
789 * Setup environment for server, someday this should be Mach stuff
790 * rather than Unix crud
792 argv
= argvize(serverp
->cmd
);
795 if (serverp
->uid
!= inherited_uid
)
796 if (setuid(serverp
->uid
) < 0)
797 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
798 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
799 serverp
->cmd
, serverp
->uid
);
803 * We can't keep this from happening, but we shouldn't start
804 * the server not as a process group leader. So, just fake like
805 * there was real activity, and exit the child. If needed,
806 * we'll re-launch it under another pid.
808 serverp
->activity
= 1;
809 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
810 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
815 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
817 execv(argv
[0], argv
);
818 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
820 serverp
->bootstrap
->bootstrap_port
,
825 argvize(const char *string
)
827 static char *argv
[100], args
[1000];
833 * Convert a command line into an argv for execv
838 for (cp
= string
; *cp
;) {
841 term
= (*cp
== '"') ? *cp
++ : '\0';
842 if (nargs
< NELEM(argv
))
843 argv
[nargs
++] = argp
;
844 while (*cp
&& (term
? *cp
!= term
: !isspace(*cp
))
845 && argp
< END_OF(args
)) {
859 demand_loop(void *arg
)
861 mach_msg_empty_rcv_t dummy
;
862 kern_return_t dresult
;
866 mach_port_name_array_t members
;
867 mach_msg_type_number_t membersCnt
;
868 mach_port_status_t status
;
869 mach_msg_type_number_t statusCnt
;
873 * Receive indication of message on demand service
874 * ports without actually receiving the message (we'll
875 * let the actual server do that.
879 MACH_RCV_MSG
|MACH_RCV_LARGE
,
885 if (dresult
!= MACH_RCV_TOO_LARGE
) {
886 kern_error(dresult
, "demand_loop: mach_msg()");
891 * If we are shutting down, there is no use processing
892 * any more of these messages.
894 if (shutdown_in_progress
== TRUE
)
898 * Some port(s) now have messages on them, find out
899 * which ones (there is no indication of which port
900 * triggered in the MACH_RCV_TOO_LARGE indication).
902 dresult
= mach_port_get_set_status(
907 if (dresult
!= KERN_SUCCESS
) {
908 kern_error(dresult
, "demand_loop: mach_port_get_set_status()");
912 for (i
= 0; i
< membersCnt
; i
++) {
913 statusCnt
= MACH_PORT_RECEIVE_STATUS_COUNT
;
914 dresult
= mach_port_get_attributes(
917 MACH_PORT_RECEIVE_STATUS
,
918 (mach_port_info_t
)&status
,
920 if (dresult
!= KERN_SUCCESS
) {
921 kern_error(dresult
, "demand_loop: mach_port_get_attributes()");
926 * For each port with messages, take it out of the
927 * demand service portset, and inform the main thread
928 * that it might have to start the server responsible
931 if (status
.mps_msgcount
) {
932 dresult
= mach_port_move_member(
936 if (dresult
!= KERN_SUCCESS
) {
937 kern_error(dresult
, "demand_loop: mach_port_move_member()");
940 notify_server_loop(members
[i
]);
944 dresult
= vm_deallocate(
946 (vm_address_t
) members
,
947 (vm_size_t
) membersCnt
* sizeof(mach_port_name_t
));
948 if (dresult
!= KERN_SUCCESS
) {
949 kern_error(dresult
, "demand_loop: vm_deallocate()");
957 * server_demux -- processes requests off our service port
958 * Also handles notifications
963 mach_msg_header_t
*Request
,
964 mach_msg_header_t
*Reply
)
966 bootstrap_info_t
*bootstrap
;
969 kern_return_t result
;
970 mig_reply_error_t
*reply
;
972 debug("received message on port %x\n", Request
->msgh_local_port
);
975 * Do minimal cleanup and then exit.
977 if (shutdown_in_progress
== TRUE
) {
978 notice("Shutting down. Deactivating root bootstrap (%x) ...",
979 bootstraps
.bootstrap_port
);
980 deactivate_bootstrap(&bootstraps
);
985 reply
= (mig_reply_error_t
*)Reply
;
988 * Pick off notification messages
990 if (Request
->msgh_local_port
== notify_port
) {
993 memset(reply
, 0, sizeof(*reply
));
994 switch (Request
->msgh_id
) {
995 case MACH_NOTIFY_DEAD_NAME
:
996 np
= ((mach_dead_name_notification_t
*)Request
)->not_port
;
997 debug("Notified dead name %x", np
);
999 if (np
== inherited_bootstrap_port
) {
1000 inherited_bootstrap_port
= MACH_PORT_NULL
;
1005 * Check to see if a subset requestor port was deleted.
1007 while (bootstrap
= lookup_bootstrap_by_req_port(np
)) {
1008 debug("Received dead name notification for bootstrap subset %x requestor port %x",
1009 bootstrap
->bootstrap_port
, bootstrap
->requestor_port
);
1010 mach_port_deallocate(
1012 bootstrap
->requestor_port
);
1013 bootstrap
->requestor_port
= MACH_PORT_NULL
;
1014 deactivate_bootstrap(bootstrap
);
1018 * Check to see if a defined service has gone
1021 while (servicep
= lookup_service_by_port(np
)) {
1023 * Port gone, registered service died.
1025 debug("Received dead name notification for service %s "
1026 "on bootstrap port %x\n",
1027 servicep
->name
, servicep
->bootstrap
);
1028 debug("Service %s failed - deallocate", servicep
->name
);
1029 delete_service(servicep
);
1033 * Check to see if a launched server task has gone
1036 if (serverp
= lookup_server_by_task_port(np
)) {
1038 * Port gone, server died.
1040 debug("Received task death notification for server %s ",
1042 reap_server(serverp
);
1043 dispatch_server(serverp
);
1046 mach_port_deallocate(mach_task_self(), np
);
1047 reply
->RetCode
= KERN_SUCCESS
;
1050 case MACH_NOTIFY_PORT_DELETED
:
1051 np
= ((mach_port_deleted_notification_t
*)Request
)->not_port
;
1052 debug("port deleted notification on 0x%x\n", np
);
1053 reply
->RetCode
= KERN_SUCCESS
;
1056 case MACH_NOTIFY_SEND_ONCE
:
1057 debug("notification send-once right went unused\n");
1058 reply
->RetCode
= KERN_SUCCESS
;
1062 error("Unexpected notification: %d", Request
->msgh_id
);
1063 reply
->RetCode
= KERN_FAILURE
;
1068 else if (Request
->msgh_local_port
== backup_port
) {
1069 mach_port_name_t np
;
1071 memset(reply
, 0, sizeof(*reply
));
1073 np
= ((mach_port_destroyed_notification_t
*)Request
)->not_port
.name
;
1074 servicep
= lookup_service_by_port(np
);
1075 if (servicep
!= NULL
) {
1076 server_t
*serverp
= servicep
->server
;
1078 switch (Request
->msgh_id
) {
1080 case MACH_NOTIFY_PORT_DESTROYED
:
1082 * Port sent back to us, server died.
1084 debug("Received destroyed notification for service %s",
1086 debug("Service %x bootstrap %x backed up: %s",
1087 servicep
->port
, servicep
->bootstrap
->bootstrap_port
,
1089 ASSERT(canReceive(servicep
->port
));
1090 servicep
->isActive
= FALSE
;
1091 serverp
->active_services
--;
1092 dispatch_server(serverp
);
1093 reply
->RetCode
= KERN_SUCCESS
;
1096 case DEMAND_REQUEST
:
1097 /* message reflected over from demand start thread */
1098 if (!active_server(serverp
))
1099 start_server(serverp
);
1100 reply
->RetCode
= KERN_SUCCESS
;
1104 debug("Mysterious backup_port notification %d", Request
->msgh_id
);
1105 reply
->RetCode
= KERN_FAILURE
;
1109 debug("Backup_port notification - previously deleted service");
1110 reply
->RetCode
= KERN_FAILURE
;
1114 else if (Request
->msgh_id
== MACH_NOTIFY_NO_SENDERS
) {
1115 mach_port_t ns
= Request
->msgh_local_port
;
1117 if ((serverp
= lookup_server_by_port(ns
)) != NULL_SERVER
) {
1119 * A server we launched has released his bootstrap
1120 * port send right. We won't re-launch him unless
1121 * his services came back to roost. But we need to
1122 * destroy the bootstrap port for fear of leaking.
1124 debug("server %s dropped server port", serverp
->cmd
);
1125 serverp
->port
= MACH_PORT_NULL
;
1126 dispatch_server(serverp
);
1127 } else if (bootstrap
= lookup_bootstrap_by_port(ns
)) {
1129 * The last direct user of a deactivated bootstrap went away.
1130 * We can finally free it.
1132 debug("Deallocating bootstrap %x: no more clients", ns
);
1133 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
1134 deallocate_bootstrap(bootstrap
);
1137 result
= mach_port_mod_refs(
1140 MACH_PORT_RIGHT_RECEIVE
,
1142 if (result
!= KERN_SUCCESS
)
1143 kern_fatal(result
, "mach_port_mod_refs");
1145 memset(reply
, 0, sizeof(*reply
));
1146 reply
->RetCode
= KERN_SUCCESS
;
1149 else { /* must be a service request */
1150 debug("Handled request.");
1151 return bootstrap_server(Request
, Reply
);
1157 * server_loop -- pick requests off our service port and process them
1158 * Also handles notifications
1160 #define bootstrapMaxRequestSize 1024
1161 #define bootstrapMaxReplySize 1024
1166 mach_msg_return_t mresult
;
1169 mresult
= mach_msg_server(
1171 bootstrapMaxRequestSize
,
1173 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
)|
1174 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
));
1175 if (mresult
!= MACH_MSG_SUCCESS
)
1176 kern_error(mresult
, "mach_msg_server");
1181 canReceive(mach_port_t port
)
1183 mach_port_type_t p_type
;
1184 kern_return_t result
;
1186 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1187 if (result
!= KERN_SUCCESS
) {
1188 kern_error(result
, "port_type");
1191 return ((p_type
& MACH_PORT_TYPE_RECEIVE
) != 0);
1196 canSend(mach_port_t port
)
1198 mach_port_type_t p_type
;
1199 kern_return_t result
;
1201 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1202 if (result
!= KERN_SUCCESS
) {
1203 kern_error(result
, "port_type");
1206 return ((p_type
& MACH_PORT_TYPE_PORT_RIGHTS
) != 0);