2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
25 * bootstrap -- fundamental service initiator and port server
26 * Mike DeMoney, NeXT, Inc.
27 * Copyright, 1990. All rights reserved.
29 * bootstrap.c -- implementation of bootstrap main service loop
36 #import <mach/boolean.h>
37 #import <mach/message.h>
38 #import <mach/notify.h>
39 #import <mach/mig_errors.h>
40 #include <mach/mach_traps.h>
41 #include <mach/mach_interface.h>
42 #include <mach/bootstrap.h>
43 #include <mach/host_info.h>
44 #include <mach/mach_host.h>
45 #include <mach/exception.h>
50 #import <sys/resource.h>
61 #import "bootstrap_internal.h"
65 /* Mig should produce a declaration for this, but doesn't */
66 extern boolean_t
bootstrap_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
71 const char *program_name
; /* our name for error messages */
74 #define INIT_PATH "/sbin/init" /* default init path */
78 mach_port_t inherited_bootstrap_port
= MACH_PORT_NULL
;
79 boolean_t forward_ok
= FALSE
;
80 boolean_t shutdown_in_progress
= FALSE
;
81 boolean_t debugging
= FALSE
;
82 boolean_t register_self
= FALSE
;
83 boolean_t force_fork
= FALSE
;
84 const char *register_name
;
85 task_t bootstrap_self
;
94 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
95 #define END_OF(x) (&(x)[NELEM(x)])
96 #define streq(a,b) (strcmp(a,b) == 0)
99 * Private declarations
101 static void wait_for_go(mach_port_t init_notify_port
);
102 static void init_ports(void);
103 static void start_server(server_t
*serverp
);
104 static void unblock_init(mach_port_t init_notify_port
, mach_port_t newBootstrap
);
105 static void exec_server(server_t
*serverp
);
106 static char **argvize(const char *string
);
107 static void *demand_loop(void *arg
);
108 static void server_loop(void);
109 extern kern_return_t bootstrap_register
111 mach_port_t bootstrap_port
,
113 mach_port_t service_port
117 * Private ports we hold receive rights for. We also hold receive rights
118 * for all the privileged ports. Those are maintained in the server
121 mach_port_t bootstrap_port_set
;
122 mach_port_t demand_port_set
;
123 pthread_t demand_thread
;
125 mach_port_t notify_port
;
126 mach_port_t backup_port
;
130 enablecoredumps(boolean_t enabled
)
132 struct rlimit rlimit
;
134 getrlimit(RLIMIT_CORE
, &rlimit
);
135 rlimit
.rlim_cur
= (enabled
) ? rlimit
.rlim_max
: 0;
136 setrlimit(RLIMIT_CORE
, &rlimit
);
140 toggle_debug(int signal
)
143 debugging
= (debugging
) ? FALSE
: TRUE
;
144 enablecoredumps(debugging
);
147 static mach_msg_return_t
149 mach_port_name_t about
,
150 mach_msg_option_t options
)
152 mach_port_destroyed_notification_t
not;
153 mach_msg_size_t size
= sizeof(not) - sizeof(not.trailer
);
155 not.not_header
.msgh_id
= DEMAND_REQUEST
;
156 not.not_header
.msgh_remote_port
= backup_port
;
157 not.not_header
.msgh_local_port
= MACH_PORT_NULL
;
158 not.not_header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
159 not.not_header
.msgh_size
= size
;
160 not.not_body
.msgh_descriptor_count
= 1;
161 not.not_port
.type
= MACH_MSG_PORT_DESCRIPTOR
;
162 not.not_port
.disposition
= MACH_MSG_TYPE_PORT_NAME
;
163 not.not_port
.name
= about
;
164 return mach_msg(¬.not_header
, MACH_SEND_MSG
|options
, size
,
165 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
169 notify_server_loop(mach_port_name_t about
)
171 mach_msg_return_t result
;
173 result
= inform_server_loop(about
, MACH_MSG_OPTION_NONE
);
174 if (result
!= MACH_MSG_SUCCESS
)
175 kern_error(result
, "notify_server_loop: mach_msg()");
178 void start_shutdown(int signal
)
180 shutdown_in_progress
= TRUE
;
181 (void) inform_server_loop(MACH_PORT_NULL
, MACH_SEND_TIMEOUT
);
185 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
);
249 info("Execing init");
254 fd
= open("/dev/tty", O_RDONLY
);
256 ioctl(fd
, TIOCNOTTY
, 0);
260 /* pass our arguments on to init */
262 execv(argv
[0], argv
);
263 exit(1); /* will likely trigger a panic */
268 * Child - will continue along as mach_init. Construct
269 * a very basic environment - as much as if we were
270 * actually forked from init (instead of the other way
273 * Set up the PATH to be approriate for the root user.
274 * Create an initial session.
275 * Establish an initial user.
276 * Disbale core dumps.
278 setenv("PATH", _PATH_STDPATH
, 1);
281 enablecoredumps(FALSE
);
283 init_notify_port
= MACH_PORT_NULL
;
285 /* Initialize error handling */
286 program_name
= rindex(*argv
, '/');
290 program_name
= *argv
;
293 /* Parse command line args */
294 while (argc
> 0 && **argv
== '-') {
295 argp
= *argv
++ + 1; argc
--;
297 switch (c
= *argp
++) {
300 enablecoredumps(TRUE
);
304 enablecoredumps(FALSE
);
310 register_self
= forward_ok
= TRUE
;
312 register_name
= *argv
++; argc
--;
314 fatal("-r requires name");
324 * If we must fork, do it now before we get Mach ports in use
330 else if (pid
!= 0) /* PARENT: just exit */
334 /* block all but SIGHUP and SIGTERM and mark us as an init process */
337 sigdelset(&mask
, SIGHUP
);
338 signal(SIGHUP
, toggle_debug
);
339 sigdelset(&mask
, SIGTERM
);
340 signal(SIGTERM
, start_shutdown
);
341 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
343 init_errlog(pid
== 0); /* are we a daemon? */
347 * This task will become the bootstrap task, so go ahead and
348 * initialize the ports now.
350 bootstrap_self
= mach_task_self();
351 inherited_uid
= getuid();
354 log("Started with uid=%d%s%s%s",
356 (register_self
) ? " registered-as=" : "",
357 (register_self
) ? register_name
: "",
358 (debugging
) ? " in debug-mode" : "");
362 * If we are supposed to coordinate with init, we have to
363 * get that port again, because we only have a (probably wrong)
364 * name in memory, not a proper right.
366 if (init_notify_port
!= MACH_PORT_NULL
) {
367 result
= task_get_bootstrap_port(
370 if (result
!= KERN_SUCCESS
)
371 kern_fatal(result
, "task_get_bootstrap_port");
373 unblock_init(init_notify_port
, bootstraps
.bootstrap_port
);
375 result
= task_set_bootstrap_port(
378 if (result
!= KERN_SUCCESS
)
379 kern_fatal(result
, "task_set_bootstrap_port");
381 result
= mach_port_deallocate(
384 if (result
!= KERN_SUCCESS
)
385 kern_fatal(result
, "mach_port_deallocate");
388 inherited_bootstrap_port
= MACH_PORT_NULL
;
392 /* get inherited bootstrap port */
393 result
= task_get_bootstrap_port(
395 &inherited_bootstrap_port
);
396 if (result
!= KERN_SUCCESS
)
397 kern_fatal(result
, "task_get_bootstrap_port");
399 /* We set this explicitly as we start each child */
400 task_set_bootstrap_port(bootstrap_self
, MACH_PORT_NULL
);
401 if (inherited_bootstrap_port
== MACH_PORT_NULL
)
404 /* register "self" port with anscestor */
405 if (register_self
&& forward_ok
) {
406 result
= bootstrap_register(
407 inherited_bootstrap_port
,
408 (char *)register_name
,
409 bootstraps
.bootstrap_port
);
410 if (result
!= KERN_SUCCESS
)
411 kern_fatal(result
, "register self");
416 /* Kick off all continuously running server processes */
417 for ( serverp
= FIRST(servers
)
418 ; !IS_END(serverp
, servers
)
419 ; serverp
= NEXT(serverp
))
420 if (serverp
->servertype
!= DEMAND
)
421 start_server(serverp
);
423 pthread_attr_init (&attr
);
424 pthread_attr_setdetachstate ( &attr
, PTHREAD_CREATE_DETACHED
);
425 result
= pthread_create(
431 unix_error("pthread_create()");
435 /* Process bootstrap service requests */
436 server_loop(); /* Should never return */
441 wait_for_go(mach_port_t init_notify_port
)
444 mach_msg_header_t hdr
;
445 mach_msg_trailer_t trailer
;
447 kern_return_t result
;
450 * For now, we just blindly wait until we receive a message or
451 * timeout. We don't expect any notifications, and if we get one,
452 * it probably means something dire has happened; so we might as
453 * well give a shot at letting init run.
456 &init_go_msg
.hdr
, MACH_RCV_MSG
,
457 0, sizeof(init_go_msg
), init_notify_port
,
458 MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
459 if (result
!= KERN_SUCCESS
) {
460 kern_error(result
, "mach_msg(receive) failed in wait_for_go");
462 result
= task_set_bootstrap_port(
464 init_go_msg
.hdr
.msgh_remote_port
);
465 if (result
!= KERN_SUCCESS
) {
466 kern_error(result
, "task_get_bootstrap_port()");
472 unblock_init(mach_port_t init_notify_port
,
473 mach_port_t newBootstrap
)
475 mach_msg_header_t init_go_msg
;
476 kern_return_t result
;
479 * Proc 1 is blocked in a msg_receive on its notify port, this lets
480 * it continue, and we hand off its new bootstrap port
482 init_go_msg
.msgh_remote_port
= init_notify_port
;
483 init_go_msg
.msgh_local_port
= newBootstrap
;
484 init_go_msg
.msgh_bits
= MACH_MSGH_BITS(
485 MACH_MSG_TYPE_COPY_SEND
,
486 MACH_MSG_TYPE_MAKE_SEND
);
487 init_go_msg
.msgh_size
= sizeof(init_go_msg
);
488 result
= mach_msg_send(&init_go_msg
);
489 if (result
!= KERN_SUCCESS
)
490 kern_fatal(result
, "unblock_init mach_msg_send() failed");
491 debug("sent go message");
498 kern_return_t result
;
502 * This task will become the bootstrap task.
504 /* Create port set that server loop listens to */
505 result
= mach_port_allocate(
507 MACH_PORT_RIGHT_PORT_SET
,
508 &bootstrap_port_set
);
509 if (result
!= KERN_SUCCESS
)
510 kern_fatal(result
, "port_set_allocate");
512 /* Create demand port set that second thread listens to */
513 result
= mach_port_allocate(
515 MACH_PORT_RIGHT_PORT_SET
,
517 if (result
!= KERN_SUCCESS
)
518 kern_fatal(result
, "port_set_allocate");
520 /* Create notify port and add to server port set */
521 result
= mach_port_allocate(
523 MACH_PORT_RIGHT_RECEIVE
,
525 if (result
!= KERN_SUCCESS
)
526 kern_fatal(result
, "mach_port_allocate");
528 result
= mach_port_move_member(
532 if (result
!= KERN_SUCCESS
)
533 kern_fatal(result
, "mach_port_move_member");
535 /* Create backup port and add to server port set */
536 result
= mach_port_allocate(
538 MACH_PORT_RIGHT_RECEIVE
,
540 if (result
!= KERN_SUCCESS
)
541 kern_fatal(result
, "mach_port_allocate");
543 result
= mach_port_move_member(
547 if (result
!= KERN_SUCCESS
)
548 kern_fatal(result
, "mach_port_move_member");
550 /* Create "self" port and add to server port set */
551 result
= mach_port_allocate(
553 MACH_PORT_RIGHT_RECEIVE
,
554 &bootstraps
.bootstrap_port
);
555 if (result
!= KERN_SUCCESS
)
556 kern_fatal(result
, "mach_port_allocate");
557 result
= mach_port_insert_right(
559 bootstraps
.bootstrap_port
,
560 bootstraps
.bootstrap_port
,
561 MACH_MSG_TYPE_MAKE_SEND
);
562 if (result
!= KERN_SUCCESS
)
563 kern_fatal(result
, "mach_port_insert_right");
565 /* keep the root bootstrap port "active" */
566 bootstraps
.requestor_port
= bootstraps
.bootstrap_port
;
568 result
= mach_port_move_member(
570 bootstraps
.bootstrap_port
,
572 if (result
!= KERN_SUCCESS
)
573 kern_fatal(result
, "mach_port_move_member");
576 * Allocate service ports for declared services.
578 for ( servicep
= FIRST(services
)
579 ; ! IS_END(servicep
, services
)
580 ; servicep
= NEXT(servicep
))
582 switch (servicep
->servicetype
) {
584 result
= mach_port_allocate(
586 MACH_PORT_RIGHT_RECEIVE
,
588 if (result
!= KERN_SUCCESS
)
589 kern_fatal(result
, "mach_port_allocate");
591 result
= mach_port_insert_right(
595 MACH_MSG_TYPE_MAKE_SEND
);
596 if (result
!= KERN_SUCCESS
)
597 kern_fatal(result
, "mach_port_insert_right");
598 info("Declared port %x for service %s",
602 if (servicep
->server
!= NULL_SERVER
&&
603 servicep
->server
->servertype
== DEMAND
) {
604 result
= mach_port_move_member(
608 if (result
!= KERN_SUCCESS
)
609 kern_fatal(result
, "mach_port_move_member");
614 servicep
->port
= bootstraps
.bootstrap_port
;
615 servicep
->server
= new_server(&bootstraps
,
619 info("Set port %x for self port",
620 bootstraps
.bootstrap_port
);
624 fatal("Can't allocate REGISTERED port!?!");
631 active_bootstrap(bootstrap_info_t
*bootstrap
)
633 return (bootstrap
->requestor_port
!= MACH_PORT_NULL
);
637 useless_server(server_t
*serverp
)
639 return ( !active_bootstrap(serverp
->bootstrap
) ||
640 !lookup_service_by_server(serverp
) ||
645 active_server(server_t
*serverp
)
647 return ( serverp
->port
||
648 serverp
->task_port
|| serverp
->active_services
);
652 reap_server(server_t
*serverp
)
654 kern_return_t result
;
661 presult
= waitpid(serverp
->pid
, &wstatus
, WNOHANG
);
662 if (presult
!= serverp
->pid
) {
663 unix_error("waitpid: cmd = %s", serverp
->cmd
);
664 } else if (wstatus
) {
665 log("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
666 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
667 serverp
->uid
, serverp
->cmd
,
668 ((WIFEXITED(wstatus
)) ?
669 "exited with non-zero status" :
670 "exited as a result of signal"),
671 ((WIFEXITED(wstatus
)) ? WEXITSTATUS(wstatus
) : WTERMSIG(wstatus
)),
677 * Release the server task port reference, if we ever
678 * got it in the first place.
680 if (serverp
->task_port
!= MACH_PORT_NULL
) {
681 result
= mach_port_deallocate(
684 if (result
!= KERN_SUCCESS
)
685 kern_error(result
, "mach_port_deallocate");
686 serverp
->task_port
= MACH_PORT_NULL
;
691 demand_server(server_t
*serverp
)
694 kern_return_t result
;
697 * For on-demand servers, make sure that the service ports are
698 * back in on-demand portset. Active service ports should come
699 * back through a PORT_DESTROYED notification. We only have to
700 * worry about the inactive ports that may have been previously
701 * pulled from the set but never checked-in by the server.
704 for ( servicep
= FIRST(services
)
705 ; !IS_END(servicep
, services
)
706 ; servicep
= NEXT(servicep
))
708 if (serverp
== servicep
->server
&& !servicep
->isActive
) {
709 result
= mach_port_move_member(
713 if (result
!= KERN_SUCCESS
)
714 kern_fatal(result
, "mach_port_move_member");
720 void dispatch_server(server_t
*serverp
)
722 if (!active_server(serverp
)) {
723 if (useless_server(serverp
))
724 delete_server(serverp
);
725 else if (serverp
->servertype
== RESTARTABLE
)
726 start_server(serverp
);
727 else if (serverp
->servertype
== DEMAND
)
728 demand_server(serverp
);
733 setup_server(server_t
*serverp
)
735 kern_return_t result
;
736 mach_port_t old_port
;
738 /* Allocate privileged port for requests from service */
739 result
= mach_port_allocate(mach_task_self(),
740 MACH_PORT_RIGHT_RECEIVE
,
742 info("Allocating port %x for server %s", serverp
->port
, serverp
->cmd
);
743 if (result
!= KERN_SUCCESS
)
744 kern_fatal(result
, "port_allocate");
746 /* Request no-senders notification so we can tell when server dies */
747 result
= mach_port_request_notification(mach_task_self(),
749 MACH_NOTIFY_NO_SENDERS
,
752 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
754 if (result
!= KERN_SUCCESS
)
755 kern_fatal(result
, "mach_port_request_notification");
757 /* Add privileged server port to bootstrap port set */
758 result
= mach_port_move_member(mach_task_self(),
761 if (result
!= KERN_SUCCESS
)
762 kern_fatal(result
, "mach_port_move_member");
766 start_server(server_t
*serverp
)
768 kern_return_t result
;
769 mach_port_t old_port
;
773 * Do what's appropriate to get bootstrap port setup in server task
775 switch (serverp
->servertype
) {
784 setup_server(serverp
);
786 serverp
->activity
= 0;
788 /* Insert a send right */
789 result
= mach_port_insert_right(mach_task_self(),
792 MACH_MSG_TYPE_MAKE_SEND
);
793 if (result
!= KERN_SUCCESS
)
794 kern_fatal(result
, "mach_port_insert_right");
796 /* Give trusted service a unique bootstrap port */
797 result
= task_set_bootstrap_port(mach_task_self(),
799 if (result
!= KERN_SUCCESS
)
800 kern_fatal(result
, "task_set_bootstrap_port");
802 result
= mach_port_deallocate(mach_task_self(),
804 if (result
!= KERN_SUCCESS
)
805 kern_fatal(result
, "mach_port_deallocate");
810 } else if (pid
== 0) { /* CHILD */
811 exec_server(serverp
);
813 } else { /* PARENT */
815 result
= task_set_bootstrap_port(
818 if (result
!= KERN_SUCCESS
)
819 kern_fatal(result
, "task_set_bootstrap_port");
821 info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
822 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
823 serverp
->uid
, serverp
->cmd
, pid
);
825 result
= task_for_pid(
828 &serverp
->task_port
);
829 if (result
!= KERN_SUCCESS
) {
830 kern_error(result
, "getting server task port");
831 reap_server(serverp
);
832 dispatch_server(serverp
);
836 /* Request dead name notification to tell when task dies */
837 result
= mach_port_request_notification(
840 MACH_NOTIFY_DEAD_NAME
,
843 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
845 if (result
!= KERN_SUCCESS
) {
846 kern_error(result
, "mach_port_request_notification");
847 reap_server(serverp
);
848 dispatch_server(serverp
);
856 exec_server(server_t
*serverp
)
862 * Setup environment for server, someday this should be Mach stuff
863 * rather than Unix crud
865 argv
= argvize(serverp
->cmd
);
868 if (serverp
->uid
!= inherited_uid
)
869 if (setuid(serverp
->uid
) < 0)
870 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
871 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
872 serverp
->cmd
, serverp
->uid
);
876 * We can't keep this from happening, but we shouldn't start
877 * the server not as a process group leader. So, just fake like
878 * there was real activity, and exit the child. If needed,
879 * we'll re-launch it under another pid.
881 serverp
->activity
= 1;
882 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
883 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
888 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
890 execv(argv
[0], argv
);
891 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
893 serverp
->bootstrap
->bootstrap_port
,
898 argvize(const char *string
)
900 static char *argv
[100], args
[1000];
906 * Convert a command line into an argv for execv
911 for (cp
= string
; *cp
;) {
914 term
= (*cp
== '"') ? *cp
++ : '\0';
915 if (nargs
< NELEM(argv
))
916 argv
[nargs
++] = argp
;
917 while (*cp
&& (term
? *cp
!= term
: !isspace(*cp
))
918 && argp
< END_OF(args
)) {
932 demand_loop(void *arg
)
934 mach_msg_empty_rcv_t dummy
;
935 kern_return_t dresult
;
939 mach_port_name_array_t members
;
940 mach_msg_type_number_t membersCnt
;
941 mach_port_status_t status
;
942 mach_msg_type_number_t statusCnt
;
946 * Receive indication of message on demand service
947 * ports without actually receiving the message (we'll
948 * let the actual server do that.
952 MACH_RCV_MSG
|MACH_RCV_LARGE
,
958 if (dresult
!= MACH_RCV_TOO_LARGE
) {
959 kern_error(dresult
, "demand_loop: mach_msg()");
964 * If we are shutting down, there is no use processing
965 * any more of these messages.
967 if (shutdown_in_progress
== TRUE
)
971 * Some port(s) now have messages on them, find out
972 * which ones (there is no indication of which port
973 * triggered in the MACH_RCV_TOO_LARGE indication).
975 dresult
= mach_port_get_set_status(
980 if (dresult
!= KERN_SUCCESS
) {
981 kern_error(dresult
, "demand_loop: mach_port_get_set_status()");
985 for (i
= 0; i
< membersCnt
; i
++) {
986 statusCnt
= MACH_PORT_RECEIVE_STATUS_COUNT
;
987 dresult
= mach_port_get_attributes(
990 MACH_PORT_RECEIVE_STATUS
,
991 (mach_port_info_t
)&status
,
993 if (dresult
!= KERN_SUCCESS
) {
994 kern_error(dresult
, "demand_loop: mach_port_get_attributes()");
999 * For each port with messages, take it out of the
1000 * demand service portset, and inform the main thread
1001 * that it might have to start the server responsible
1004 if (status
.mps_msgcount
) {
1005 dresult
= mach_port_move_member(
1009 if (dresult
!= KERN_SUCCESS
) {
1010 kern_error(dresult
, "demand_loop: mach_port_move_member()");
1013 notify_server_loop(members
[i
]);
1017 dresult
= vm_deallocate(
1019 (vm_address_t
) members
,
1020 (vm_size_t
) membersCnt
* sizeof(mach_port_name_t
));
1021 if (dresult
!= KERN_SUCCESS
) {
1022 kern_error(dresult
, "demand_loop: vm_deallocate()");
1030 * server_demux -- processes requests off our service port
1031 * Also handles notifications
1036 mach_msg_header_t
*Request
,
1037 mach_msg_header_t
*Reply
)
1039 bootstrap_info_t
*bootstrap
;
1040 service_t
*servicep
;
1042 kern_return_t result
;
1043 mig_reply_error_t
*reply
;
1045 debug("received message on port %x\n", Request
->msgh_local_port
);
1048 * Do minimal cleanup and then exit.
1050 if (shutdown_in_progress
== TRUE
) {
1051 log("Shutting down. Deactivating root bootstrap (%x) ...",
1052 bootstraps
.bootstrap_port
);
1053 deactivate_bootstrap(&bootstraps
);
1058 reply
= (mig_reply_error_t
*)Reply
;
1061 * Pick off notification messages
1063 if (Request
->msgh_local_port
== notify_port
) {
1064 mach_port_name_t np
;
1066 memset(reply
, 0, sizeof(*reply
));
1067 switch (Request
->msgh_id
) {
1068 case MACH_NOTIFY_DEAD_NAME
:
1069 np
= ((mach_dead_name_notification_t
*)Request
)->not_port
;
1070 debug("Notified dead name %x", np
);
1072 if (np
== inherited_bootstrap_port
) {
1073 inherited_bootstrap_port
= MACH_PORT_NULL
;
1078 * Check to see if a subset requestor port was deleted.
1080 while (bootstrap
= lookup_bootstrap_by_req_port(np
)) {
1081 debug("Received dead name notification for bootstrap subset %x requestor port %x",
1082 bootstrap
->bootstrap_port
, bootstrap
->requestor_port
);
1083 mach_port_deallocate(
1085 bootstrap
->requestor_port
);
1086 bootstrap
->requestor_port
= MACH_PORT_NULL
;
1087 deactivate_bootstrap(bootstrap
);
1091 * Check to see if a defined service has gone
1094 while (servicep
= lookup_service_by_port(np
)) {
1096 * Port gone, registered service died.
1098 debug("Received dead name notification for service %s "
1099 "on bootstrap port %x\n",
1100 servicep
->name
, servicep
->bootstrap
);
1101 debug("Service %s failed - deallocate", servicep
->name
);
1102 delete_service(servicep
);
1106 * Check to see if a launched server task has gone
1109 if (serverp
= lookup_server_by_task_port(np
)) {
1111 * Port gone, server died.
1113 debug("Received task death notification for server %s ",
1115 reap_server(serverp
);
1116 dispatch_server(serverp
);
1119 mach_port_deallocate(mach_task_self(), np
);
1120 reply
->RetCode
= KERN_SUCCESS
;
1123 case MACH_NOTIFY_PORT_DELETED
:
1124 np
= ((mach_port_deleted_notification_t
*)Request
)->not_port
;
1125 debug("port deleted notification on 0x%x\n", np
);
1126 reply
->RetCode
= KERN_SUCCESS
;
1129 case MACH_NOTIFY_SEND_ONCE
:
1130 debug("notification send-once right went unused\n");
1131 reply
->RetCode
= KERN_SUCCESS
;
1135 error("Unexpected notification: %d", Request
->msgh_id
);
1136 reply
->RetCode
= KERN_FAILURE
;
1141 else if (Request
->msgh_local_port
== backup_port
) {
1142 mach_port_name_t np
;
1144 memset(reply
, 0, sizeof(*reply
));
1146 np
= ((mach_port_destroyed_notification_t
*)Request
)->not_port
.name
;
1147 servicep
= lookup_service_by_port(np
);
1148 if (servicep
!= NULL
) {
1149 server_t
*serverp
= servicep
->server
;
1151 switch (Request
->msgh_id
) {
1153 case MACH_NOTIFY_PORT_DESTROYED
:
1155 * Port sent back to us, server died.
1157 debug("Received destroyed notification for service %s",
1159 debug("Service %x bootstrap %x backed up: %s",
1160 servicep
->port
, servicep
->bootstrap
->bootstrap_port
,
1162 ASSERT(canReceive(servicep
->port
));
1163 servicep
->isActive
= FALSE
;
1164 serverp
->active_services
--;
1165 dispatch_server(serverp
);
1166 reply
->RetCode
= KERN_SUCCESS
;
1169 case DEMAND_REQUEST
:
1170 /* message reflected over from demand start thread */
1171 if (!active_server(serverp
))
1172 start_server(serverp
);
1173 reply
->RetCode
= KERN_SUCCESS
;
1177 debug("Mysterious backup_port notification %d", Request
->msgh_id
);
1178 reply
->RetCode
= KERN_FAILURE
;
1182 debug("Backup_port notification - previously deleted service");
1183 reply
->RetCode
= KERN_FAILURE
;
1187 else if (Request
->msgh_id
== MACH_NOTIFY_NO_SENDERS
) {
1188 mach_port_t ns
= Request
->msgh_local_port
;
1190 if ((serverp
= lookup_server_by_port(ns
)) != NULL_SERVER
) {
1192 * A server we launched has released his bootstrap
1193 * port send right. We won't re-launch him unless
1194 * his services came back to roost. But we need to
1195 * destroy the bootstrap port for fear of leaking.
1197 debug("server %s dropped server port", serverp
->cmd
);
1198 serverp
->port
= MACH_PORT_NULL
;
1199 dispatch_server(serverp
);
1200 } else if (bootstrap
= lookup_bootstrap_by_port(ns
)) {
1202 * The last direct user of a deactivated bootstrap went away.
1203 * We can finally free it.
1205 debug("Deallocating bootstrap %x: no more clients", ns
);
1206 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
1207 deallocate_bootstrap(bootstrap
);
1210 result
= mach_port_mod_refs(
1213 MACH_PORT_RIGHT_RECEIVE
,
1215 if (result
!= KERN_SUCCESS
)
1216 kern_fatal(result
, "mach_port_mod_refs");
1218 memset(reply
, 0, sizeof(*reply
));
1219 reply
->RetCode
= KERN_SUCCESS
;
1222 else { /* must be a service request */
1223 debug("Handled request.");
1224 return bootstrap_server(Request
, Reply
);
1230 * server_loop -- pick requests off our service port and process them
1231 * Also handles notifications
1233 #define bootstrapMaxRequestSize 1024
1234 #define bootstrapMaxReplySize 1024
1239 mach_msg_return_t mresult
;
1242 mresult
= mach_msg_server(
1244 bootstrapMaxRequestSize
,
1246 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
)|
1247 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
));
1248 if (mresult
!= MACH_MSG_SUCCESS
)
1249 kern_error(mresult
, "mach_msg_server");
1254 canReceive(mach_port_t port
)
1256 mach_port_type_t p_type
;
1257 kern_return_t result
;
1259 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1260 if (result
!= KERN_SUCCESS
) {
1261 kern_error(result
, "port_type");
1264 return ((p_type
& MACH_PORT_TYPE_RECEIVE
) != 0);
1269 canSend(mach_port_t port
)
1271 mach_port_type_t p_type
;
1272 kern_return_t result
;
1274 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1275 if (result
!= KERN_SUCCESS
) {
1276 kern_error(result
, "port_type");
1279 return ((p_type
& MACH_PORT_TYPE_PORT_RIGHTS
) != 0);