2 * Copyright (c) 1999-2004 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>
60 #include <bsm/audit.h>
61 #include <bsm/libbsm.h>
65 #import "bootstrap_internal.h"
69 /* Mig should produce a declaration for this, but doesn't */
70 extern boolean_t
bootstrap_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
75 const char *program_name
; /* our name for error messages */
78 #define INIT_PATH "/sbin/init" /* default init path */
81 uid_t inherited_uid
= 0;
82 auditinfo_t inherited_audit
;
83 mach_port_t inherited_bootstrap_port
= MACH_PORT_NULL
;
84 boolean_t forward_ok
= FALSE
;
85 boolean_t shutdown_in_progress
= FALSE
;
86 boolean_t debugging
= FALSE
;
87 boolean_t register_self
= FALSE
;
88 boolean_t force_fork
= FALSE
;
89 const char *register_name
;
90 task_t bootstrap_self
;
99 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
100 #define END_OF(x) (&(x)[NELEM(x)])
101 #define streq(a,b) (strcmp(a,b) == 0)
104 * Private declarations
106 static void wait_for_go(mach_port_t init_notify_port
);
107 static void init_ports(void);
108 static void start_server(server_t
*serverp
);
109 static void unblock_init(mach_port_t init_notify_port
, mach_port_t newBootstrap
);
110 static void exec_server(server_t
*serverp
);
111 static char **argvize(const char *string
);
112 static void *demand_loop(void *arg
);
113 static void server_loop(void);
114 extern kern_return_t bootstrap_register
116 mach_port_t bootstrap_port
,
118 mach_port_t service_port
122 * Private ports we hold receive rights for. We also hold receive rights
123 * for all the privileged ports. Those are maintained in the server
126 mach_port_t bootstrap_port_set
;
127 mach_port_t demand_port_set
;
128 pthread_t demand_thread
;
130 mach_port_t notify_port
;
131 mach_port_t backup_port
;
135 enablecoredumps(boolean_t enabled
)
137 struct rlimit rlimit
;
139 getrlimit(RLIMIT_CORE
, &rlimit
);
140 rlimit
.rlim_cur
= (enabled
) ? rlimit
.rlim_max
: 0;
141 setrlimit(RLIMIT_CORE
, &rlimit
);
145 toggle_debug(int signal
)
148 debugging
= (debugging
) ? FALSE
: TRUE
;
149 enablecoredumps(debugging
);
152 static mach_msg_return_t
154 mach_port_name_t about
,
155 mach_msg_option_t options
)
157 mach_port_destroyed_notification_t
not;
158 mach_msg_size_t size
= sizeof(not) - sizeof(not.trailer
);
160 not.not_header
.msgh_id
= DEMAND_REQUEST
;
161 not.not_header
.msgh_remote_port
= backup_port
;
162 not.not_header
.msgh_local_port
= MACH_PORT_NULL
;
163 not.not_header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
164 not.not_header
.msgh_size
= size
;
165 not.not_body
.msgh_descriptor_count
= 1;
166 not.not_port
.type
= MACH_MSG_PORT_DESCRIPTOR
;
167 not.not_port
.disposition
= MACH_MSG_TYPE_PORT_NAME
;
168 not.not_port
.name
= about
;
169 return mach_msg(¬.not_header
, MACH_SEND_MSG
|options
, size
,
170 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
174 notify_server_loop(mach_port_name_t about
)
176 mach_msg_return_t result
;
178 result
= inform_server_loop(about
, MACH_MSG_OPTION_NONE
);
179 if (result
!= MACH_MSG_SUCCESS
)
180 kern_error(result
, "notify_server_loop: mach_msg()");
183 void start_shutdown(int signal
)
185 shutdown_in_progress
= TRUE
;
186 (void) inform_server_loop(MACH_PORT_NULL
, MACH_SEND_TIMEOUT
);
190 main(int argc
, char * argv
[])
194 kern_return_t result
;
195 mach_port_t init_notify_port
;
201 * If we are pid one, we have to exec init. Before doing so, we'll
202 * fork a child, and that will become the true mach_init. But we have
203 * to be very careful about ports. They aren't inherited across fork,
204 * so we have to avoid storing port names in memory before the fork that
205 * might not be valid after.
210 result
= mach_port_allocate(
212 MACH_PORT_RIGHT_RECEIVE
,
214 if (result
!= KERN_SUCCESS
)
215 kern_fatal(result
, "mach_port_allocate");
217 result
= mach_port_insert_right(
221 MACH_MSG_TYPE_MAKE_SEND
);
222 if (result
!= KERN_SUCCESS
)
223 kern_fatal(result
, "mach_port_insert_right");
225 result
= task_set_bootstrap_port(
228 if (result
!= KERN_SUCCESS
)
229 kern_fatal(result
, "task_set_bootstrap_port");
236 else if (pid
!= 0) { /* PARENT - will become init when ready */
240 * Wait for mach_init ot give us a real bootstrap port
242 wait_for_go(init_notify_port
);
247 fd
= open("/dev/tty", O_RDONLY
);
249 ioctl(fd
, TIOCNOTTY
, 0);
253 /* pass our arguments on to init */
255 execv(argv
[0], argv
);
256 exit(1); /* will likely trigger a panic */
261 * Child - will continue along as mach_init. Save off
262 * the init_notify_port and put back a NULL bootstrap
263 * port for ourselves.
265 init_notify_port
= bootstrap_port
;
266 bootstrap_port
= MACH_PORT_NULL
;
267 (void)task_set_bootstrap_port(
270 if (result
!= KERN_SUCCESS
)
271 kern_fatal(result
, "task_get_bootstrap_port");
274 open("/dev/null", O_RDONLY
, 0);
276 open("/dev/null", O_WRONLY
, 0);
278 open("/dev/null", O_WRONLY
, 0);
281 init_notify_port
= MACH_PORT_NULL
;
283 /* Initialize error handling */
284 program_name
= rindex(*argv
, '/');
288 program_name
= *argv
;
291 /* Parse command line args */
292 while (argc
> 0 && **argv
== '-') {
293 argp
= *argv
++ + 1; argc
--;
295 switch (c
= *argp
++) {
303 if (init_notify_port
!= MACH_PORT_NULL
)
307 register_self
= forward_ok
= TRUE
;
309 register_name
= *argv
++; argc
--;
311 fatal("-r requires name");
321 * If we must fork, do it now before we get Mach ports in use
327 else if (pid
!= 0) /* PARENT: just exit */
332 * This task will become the bootstrap task, initialize the ports.
334 bootstrap_self
= mach_task_self();
335 inherited_uid
= getuid();
336 getaudit(&inherited_audit
);
340 if (init_notify_port
!= MACH_PORT_NULL
) {
341 /* send init a real bootstrap port to use */
342 unblock_init(init_notify_port
, bootstraps
.bootstrap_port
);
344 result
= mach_port_deallocate(
347 if (result
!= KERN_SUCCESS
)
348 kern_fatal(result
, "mach_port_deallocate");
351 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");
377 pthread_attr_init (&attr
);
378 pthread_attr_setdetachstate ( &attr
, PTHREAD_CREATE_DETACHED
);
379 result
= pthread_create(
385 unix_error("pthread_create()");
389 /* block all but SIGHUP and SIGTERM */
391 sigdelset(&mask
, SIGHUP
);
392 signal(SIGHUP
, toggle_debug
);
393 sigdelset(&mask
, SIGTERM
);
394 signal(SIGTERM
, start_shutdown
);
395 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
398 * Construct a very basic environment - as much as if we
399 * were actually forked from init (instead of the other
402 * Set up the PATH to be approriate for the root user.
403 * Create an initial session.
404 * Establish an initial user.
405 * Disbale core dumps.
409 enablecoredumps(debugging
);
410 setenv("PATH", _PATH_STDPATH
, 1);
412 init_errlog(pid
== 0); /* are we a daemon? */
413 notice("Started with uid=%d audit-uid=%d%s%s%s",
415 inherited_audit
.ai_auid
,
416 (register_self
) ? " registered-as=" : "",
417 (register_self
) ? register_name
: "",
418 (debugging
) ? " in debug-mode" : "");
420 /* Process bootstrap service requests */
421 server_loop(); /* Should never return */
426 wait_for_go(mach_port_t init_notify_port
)
429 mach_msg_header_t hdr
;
430 mach_msg_trailer_t trailer
;
432 kern_return_t result
;
435 * For now, we just blindly wait until we receive a message or
436 * timeout. We don't expect any notifications, and if we get one,
437 * it probably means something dire has happened; so we might as
438 * well give a shot at letting init run.
441 &init_go_msg
.hdr
, MACH_RCV_MSG
,
442 0, sizeof(init_go_msg
), init_notify_port
,
443 MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
444 if (result
!= KERN_SUCCESS
) {
445 kern_error(result
, "mach_msg(receive) failed in wait_for_go");
447 bootstrap_port
= init_go_msg
.hdr
.msgh_remote_port
;
448 result
= task_set_bootstrap_port(
451 if (result
!= KERN_SUCCESS
) {
452 kern_error(result
, "task_get_bootstrap_port()");
458 unblock_init(mach_port_t init_notify_port
,
459 mach_port_t newBootstrap
)
461 mach_msg_header_t init_go_msg
;
462 kern_return_t result
;
465 * Proc 1 is blocked in a msg_receive on its notify port, this lets
466 * it continue, and we hand off its new bootstrap port
468 init_go_msg
.msgh_remote_port
= init_notify_port
;
469 init_go_msg
.msgh_local_port
= newBootstrap
;
470 init_go_msg
.msgh_bits
= MACH_MSGH_BITS(
471 MACH_MSG_TYPE_COPY_SEND
,
472 MACH_MSG_TYPE_MAKE_SEND
);
473 init_go_msg
.msgh_size
= sizeof(init_go_msg
);
474 result
= mach_msg_send(&init_go_msg
);
475 if (result
!= KERN_SUCCESS
)
476 kern_fatal(result
, "unblock_init mach_msg_send() failed");
477 debug("sent go message");
484 kern_return_t result
;
487 * This task will become the bootstrap task.
489 /* Create port set that server loop listens to */
490 result
= mach_port_allocate(
492 MACH_PORT_RIGHT_PORT_SET
,
493 &bootstrap_port_set
);
494 if (result
!= KERN_SUCCESS
)
495 kern_fatal(result
, "port_set_allocate");
497 /* Create demand port set that second thread listens to */
498 result
= mach_port_allocate(
500 MACH_PORT_RIGHT_PORT_SET
,
502 if (result
!= KERN_SUCCESS
)
503 kern_fatal(result
, "port_set_allocate");
505 /* Create notify port and add to server port set */
506 result
= mach_port_allocate(
508 MACH_PORT_RIGHT_RECEIVE
,
510 if (result
!= KERN_SUCCESS
)
511 kern_fatal(result
, "mach_port_allocate");
513 result
= mach_port_move_member(
517 if (result
!= KERN_SUCCESS
)
518 kern_fatal(result
, "mach_port_move_member");
520 /* Create backup 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 "self" port and add to server port set */
536 result
= mach_port_allocate(
538 MACH_PORT_RIGHT_RECEIVE
,
539 &bootstraps
.bootstrap_port
);
540 if (result
!= KERN_SUCCESS
)
541 kern_fatal(result
, "mach_port_allocate");
542 result
= mach_port_insert_right(
544 bootstraps
.bootstrap_port
,
545 bootstraps
.bootstrap_port
,
546 MACH_MSG_TYPE_MAKE_SEND
);
547 if (result
!= KERN_SUCCESS
)
548 kern_fatal(result
, "mach_port_insert_right");
550 /* keep the root bootstrap port "active" */
551 bootstraps
.requestor_port
= bootstraps
.bootstrap_port
;
553 result
= mach_port_move_member(
555 bootstraps
.bootstrap_port
,
557 if (result
!= KERN_SUCCESS
)
558 kern_fatal(result
, "mach_port_move_member");
562 active_bootstrap(bootstrap_info_t
*bootstrap
)
564 return (bootstrap
->requestor_port
!= MACH_PORT_NULL
);
568 useless_server(server_t
*serverp
)
570 return ( !active_bootstrap(serverp
->bootstrap
) ||
571 !lookup_service_by_server(serverp
) ||
576 active_server(server_t
*serverp
)
578 return ( serverp
->port
||
579 serverp
->task_port
|| serverp
->active_services
);
583 reap_server(server_t
*serverp
)
585 kern_return_t result
;
592 presult
= waitpid(serverp
->pid
, &wstatus
, WNOHANG
);
593 if (presult
!= serverp
->pid
) {
594 unix_error("waitpid: cmd = %s", serverp
->cmd
);
595 } else if (wstatus
) {
596 notice("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
597 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
598 serverp
->uid
, serverp
->cmd
,
599 ((WIFEXITED(wstatus
)) ?
600 "exited with non-zero status" :
601 "exited as a result of signal"),
602 ((WIFEXITED(wstatus
)) ? WEXITSTATUS(wstatus
) : WTERMSIG(wstatus
)),
608 * Release the server task port reference, if we ever
609 * got it in the first place.
611 if (serverp
->task_port
!= MACH_PORT_NULL
) {
612 result
= mach_port_deallocate(
615 if (result
!= KERN_SUCCESS
)
616 kern_error(result
, "mach_port_deallocate");
617 serverp
->task_port
= MACH_PORT_NULL
;
622 demand_server(server_t
*serverp
)
625 kern_return_t result
;
628 * For on-demand servers, make sure that the service ports are
629 * back in on-demand portset. Active service ports should come
630 * back through a PORT_DESTROYED notification. We only have to
631 * worry about the inactive ports that may have been previously
632 * pulled from the set but never checked-in by the server.
635 for ( servicep
= FIRST(services
)
636 ; !IS_END(servicep
, services
)
637 ; servicep
= NEXT(servicep
))
639 if (serverp
== servicep
->server
&& !servicep
->isActive
) {
640 result
= mach_port_move_member(
644 if (result
!= KERN_SUCCESS
)
645 kern_fatal(result
, "mach_port_move_member");
651 void dispatch_server(server_t
*serverp
)
653 if (!active_server(serverp
)) {
654 if (useless_server(serverp
))
655 delete_server(serverp
);
656 else if (serverp
->servertype
== RESTARTABLE
)
657 start_server(serverp
);
658 else if (serverp
->servertype
== DEMAND
)
659 demand_server(serverp
);
664 setup_server(server_t
*serverp
)
666 kern_return_t result
;
667 mach_port_t old_port
;
669 /* Allocate privileged port for requests from service */
670 result
= mach_port_allocate(mach_task_self(),
671 MACH_PORT_RIGHT_RECEIVE
,
673 info("Allocating port %x for server %s", serverp
->port
, serverp
->cmd
);
674 if (result
!= KERN_SUCCESS
)
675 kern_fatal(result
, "port_allocate");
677 /* Request no-senders notification so we can tell when server dies */
678 result
= mach_port_request_notification(mach_task_self(),
680 MACH_NOTIFY_NO_SENDERS
,
683 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
685 if (result
!= KERN_SUCCESS
)
686 kern_fatal(result
, "mach_port_request_notification");
688 /* Add privileged server port to bootstrap port set */
689 result
= mach_port_move_member(mach_task_self(),
692 if (result
!= KERN_SUCCESS
)
693 kern_fatal(result
, "mach_port_move_member");
697 start_server(server_t
*serverp
)
699 kern_return_t result
;
700 mach_port_t old_port
;
704 * Do what's appropriate to get bootstrap port setup in server task
706 switch (serverp
->servertype
) {
715 setup_server(serverp
);
717 serverp
->activity
= 0;
719 /* Insert a send right */
720 result
= mach_port_insert_right(mach_task_self(),
723 MACH_MSG_TYPE_MAKE_SEND
);
724 if (result
!= KERN_SUCCESS
)
725 kern_fatal(result
, "mach_port_insert_right");
727 /* Give trusted service a unique bootstrap port */
728 result
= task_set_bootstrap_port(mach_task_self(),
730 if (result
!= KERN_SUCCESS
)
731 kern_fatal(result
, "task_set_bootstrap_port");
733 result
= mach_port_deallocate(mach_task_self(),
735 if (result
!= KERN_SUCCESS
)
736 kern_fatal(result
, "mach_port_deallocate");
741 } else if (pid
== 0) { /* CHILD */
742 exec_server(serverp
);
744 } else { /* PARENT */
746 result
= task_set_bootstrap_port(
749 if (result
!= KERN_SUCCESS
)
750 kern_fatal(result
, "task_set_bootstrap_port");
752 info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
753 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
754 serverp
->uid
, serverp
->cmd
, pid
);
756 result
= task_for_pid(
759 &serverp
->task_port
);
760 if (result
!= KERN_SUCCESS
) {
761 kern_error(result
, "getting server task port");
762 reap_server(serverp
);
763 dispatch_server(serverp
);
767 /* Request dead name notification to tell when task dies */
768 result
= mach_port_request_notification(
771 MACH_NOTIFY_DEAD_NAME
,
774 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
776 if (result
!= KERN_SUCCESS
) {
777 kern_error(result
, "mach_port_request_notification");
778 reap_server(serverp
);
779 dispatch_server(serverp
);
787 exec_server(server_t
*serverp
)
793 * Setup environment for server, someday this should be Mach stuff
794 * rather than Unix crud
796 argv
= argvize(serverp
->cmd
);
800 * Set up the audit state for the user (if necessesary).
802 if (inherited_uid
== 0 &&
803 (serverp
->auinfo
.ai_auid
!= inherited_uid
||
804 serverp
->auinfo
.ai_asid
!= inherited_audit
.ai_asid
)) {
805 struct passwd
*pwd
= NULL
;
807 pwd
= getpwuid(serverp
->auinfo
.ai_auid
);
809 unix_fatal("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed",
810 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
811 serverp
->cmd
, serverp
->auinfo
.ai_auid
);
813 } else if (au_user_mask(pwd
->pw_name
, &serverp
->auinfo
.ai_mask
) != 0) {
814 unix_fatal("Disabled server %x bootstrap %x: \"%s\": au_user_mask(%s) failed",
815 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
816 serverp
->cmd
, pwd
->pw_name
);
817 } else if (setaudit(&serverp
->auinfo
) != 0)
818 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setaudit()",
819 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
823 if (serverp
->uid
!= inherited_uid
)
824 if (setuid(serverp
->uid
) < 0)
825 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
826 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
827 serverp
->cmd
, serverp
->uid
);
831 * We can't keep this from happening, but we shouldn't start
832 * the server not as a process group leader. So, just fake like
833 * there was real activity, and exit the child. If needed,
834 * we'll re-launch it under another pid.
836 serverp
->activity
= 1;
837 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
838 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
843 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
845 execv(argv
[0], argv
);
846 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
848 serverp
->bootstrap
->bootstrap_port
,
853 argvize(const char *string
)
855 static char *argv
[100], args
[1000];
861 * Convert a command line into an argv for execv
866 for (cp
= string
; *cp
;) {
869 term
= (*cp
== '"') ? *cp
++ : '\0';
870 if (nargs
< NELEM(argv
))
871 argv
[nargs
++] = argp
;
872 while (*cp
&& (term
? *cp
!= term
: !isspace(*cp
))
873 && argp
< END_OF(args
)) {
887 demand_loop(void *arg
)
889 mach_msg_empty_rcv_t dummy
;
890 kern_return_t dresult
;
894 mach_port_name_array_t members
;
895 mach_msg_type_number_t membersCnt
;
896 mach_port_status_t status
;
897 mach_msg_type_number_t statusCnt
;
901 * Receive indication of message on demand service
902 * ports without actually receiving the message (we'll
903 * let the actual server do that.
907 MACH_RCV_MSG
|MACH_RCV_LARGE
,
913 if (dresult
!= MACH_RCV_TOO_LARGE
) {
914 kern_error(dresult
, "demand_loop: mach_msg()");
919 * If we are shutting down, there is no use processing
920 * any more of these messages.
922 if (shutdown_in_progress
== TRUE
)
926 * Some port(s) now have messages on them, find out
927 * which ones (there is no indication of which port
928 * triggered in the MACH_RCV_TOO_LARGE indication).
930 dresult
= mach_port_get_set_status(
935 if (dresult
!= KERN_SUCCESS
) {
936 kern_error(dresult
, "demand_loop: mach_port_get_set_status()");
940 for (i
= 0; i
< membersCnt
; i
++) {
941 statusCnt
= MACH_PORT_RECEIVE_STATUS_COUNT
;
942 dresult
= mach_port_get_attributes(
945 MACH_PORT_RECEIVE_STATUS
,
946 (mach_port_info_t
)&status
,
948 if (dresult
!= KERN_SUCCESS
) {
949 kern_error(dresult
, "demand_loop: mach_port_get_attributes()");
954 * For each port with messages, take it out of the
955 * demand service portset, and inform the main thread
956 * that it might have to start the server responsible
959 if (status
.mps_msgcount
) {
960 dresult
= mach_port_move_member(
964 if (dresult
!= KERN_SUCCESS
) {
965 kern_error(dresult
, "demand_loop: mach_port_move_member()");
968 notify_server_loop(members
[i
]);
972 dresult
= vm_deallocate(
974 (vm_address_t
) members
,
975 (vm_size_t
) membersCnt
* sizeof(mach_port_name_t
));
976 if (dresult
!= KERN_SUCCESS
) {
977 kern_error(dresult
, "demand_loop: vm_deallocate()");
985 * server_demux -- processes requests off our service port
986 * Also handles notifications
991 mach_msg_header_t
*Request
,
992 mach_msg_header_t
*Reply
)
994 bootstrap_info_t
*bootstrap
;
997 kern_return_t result
;
998 mig_reply_error_t
*reply
;
1000 debug("received message on port %x\n", Request
->msgh_local_port
);
1003 * Do minimal cleanup and then exit.
1005 if (shutdown_in_progress
== TRUE
) {
1006 notice("Shutting down. Deactivating root bootstrap (%x) ...",
1007 bootstraps
.bootstrap_port
);
1008 deactivate_bootstrap(&bootstraps
);
1013 reply
= (mig_reply_error_t
*)Reply
;
1016 * Pick off notification messages
1018 if (Request
->msgh_local_port
== notify_port
) {
1019 mach_port_name_t np
;
1021 memset(reply
, 0, sizeof(*reply
));
1022 switch (Request
->msgh_id
) {
1023 case MACH_NOTIFY_DEAD_NAME
:
1024 np
= ((mach_dead_name_notification_t
*)Request
)->not_port
;
1025 debug("Notified dead name %x", np
);
1027 if (np
== inherited_bootstrap_port
) {
1028 inherited_bootstrap_port
= MACH_PORT_NULL
;
1033 * Check to see if a subset requestor port was deleted.
1035 while (bootstrap
= lookup_bootstrap_by_req_port(np
)) {
1036 debug("Received dead name notification for bootstrap subset %x requestor port %x",
1037 bootstrap
->bootstrap_port
, bootstrap
->requestor_port
);
1038 mach_port_deallocate(
1040 bootstrap
->requestor_port
);
1041 bootstrap
->requestor_port
= MACH_PORT_NULL
;
1042 deactivate_bootstrap(bootstrap
);
1046 * Check to see if a defined service has gone
1049 while (servicep
= lookup_service_by_port(np
)) {
1051 * Port gone, registered service died.
1053 debug("Received dead name notification for service %s "
1054 "on bootstrap port %x\n",
1055 servicep
->name
, servicep
->bootstrap
);
1056 debug("Service %s failed - deallocate", servicep
->name
);
1057 delete_service(servicep
);
1061 * Check to see if a launched server task has gone
1064 if (serverp
= lookup_server_by_task_port(np
)) {
1066 * Port gone, server died.
1068 debug("Received task death notification for server %s ",
1070 reap_server(serverp
);
1071 dispatch_server(serverp
);
1074 mach_port_deallocate(mach_task_self(), np
);
1075 reply
->RetCode
= KERN_SUCCESS
;
1078 case MACH_NOTIFY_PORT_DELETED
:
1079 np
= ((mach_port_deleted_notification_t
*)Request
)->not_port
;
1080 debug("port deleted notification on 0x%x\n", np
);
1081 reply
->RetCode
= KERN_SUCCESS
;
1084 case MACH_NOTIFY_SEND_ONCE
:
1085 debug("notification send-once right went unused\n");
1086 reply
->RetCode
= KERN_SUCCESS
;
1090 error("Unexpected notification: %d", Request
->msgh_id
);
1091 reply
->RetCode
= KERN_FAILURE
;
1096 else if (Request
->msgh_local_port
== backup_port
) {
1097 mach_port_name_t np
;
1099 memset(reply
, 0, sizeof(*reply
));
1101 np
= ((mach_port_destroyed_notification_t
*)Request
)->not_port
.name
;
1102 servicep
= lookup_service_by_port(np
);
1103 if (servicep
!= NULL
) {
1104 server_t
*serverp
= servicep
->server
;
1106 switch (Request
->msgh_id
) {
1108 case MACH_NOTIFY_PORT_DESTROYED
:
1110 * Port sent back to us, server died.
1112 debug("Received destroyed notification for service %s",
1114 debug("Service %x bootstrap %x backed up: %s",
1115 servicep
->port
, servicep
->bootstrap
->bootstrap_port
,
1117 ASSERT(canReceive(servicep
->port
));
1118 servicep
->isActive
= FALSE
;
1119 serverp
->active_services
--;
1120 dispatch_server(serverp
);
1121 reply
->RetCode
= KERN_SUCCESS
;
1124 case DEMAND_REQUEST
:
1125 /* message reflected over from demand start thread */
1126 if (!active_server(serverp
))
1127 start_server(serverp
);
1128 reply
->RetCode
= KERN_SUCCESS
;
1132 debug("Mysterious backup_port notification %d", Request
->msgh_id
);
1133 reply
->RetCode
= KERN_FAILURE
;
1137 debug("Backup_port notification - previously deleted service");
1138 reply
->RetCode
= KERN_FAILURE
;
1142 else if (Request
->msgh_id
== MACH_NOTIFY_NO_SENDERS
) {
1143 mach_port_t ns
= Request
->msgh_local_port
;
1145 if ((serverp
= lookup_server_by_port(ns
)) != NULL_SERVER
) {
1147 * A server we launched has released his bootstrap
1148 * port send right. We won't re-launch him unless
1149 * his services came back to roost. But we need to
1150 * destroy the bootstrap port for fear of leaking.
1152 debug("server %s dropped server port", serverp
->cmd
);
1153 serverp
->port
= MACH_PORT_NULL
;
1154 dispatch_server(serverp
);
1155 } else if (bootstrap
= lookup_bootstrap_by_port(ns
)) {
1157 * The last direct user of a deactivated bootstrap went away.
1158 * We can finally free it.
1160 debug("Deallocating bootstrap %x: no more clients", ns
);
1161 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
1162 deallocate_bootstrap(bootstrap
);
1165 result
= mach_port_mod_refs(
1168 MACH_PORT_RIGHT_RECEIVE
,
1170 if (result
!= KERN_SUCCESS
)
1171 kern_fatal(result
, "mach_port_mod_refs");
1173 memset(reply
, 0, sizeof(*reply
));
1174 reply
->RetCode
= KERN_SUCCESS
;
1177 else { /* must be a service request */
1178 debug("Handled request.");
1179 return bootstrap_server(Request
, Reply
);
1185 * server_loop -- pick requests off our service port and process them
1186 * Also handles notifications
1188 #define bootstrapMaxRequestSize 1024
1189 #define bootstrapMaxReplySize 1024
1194 mach_msg_return_t mresult
;
1197 mresult
= mach_msg_server(
1199 bootstrapMaxRequestSize
,
1201 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
)|
1202 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
));
1203 if (mresult
!= MACH_MSG_SUCCESS
)
1204 kern_error(mresult
, "mach_msg_server");
1209 canReceive(mach_port_t port
)
1211 mach_port_type_t p_type
;
1212 kern_return_t result
;
1214 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1215 if (result
!= KERN_SUCCESS
) {
1216 kern_error(result
, "port_type");
1219 return ((p_type
& MACH_PORT_TYPE_RECEIVE
) != 0);
1224 canSend(mach_port_t port
)
1226 mach_port_type_t p_type
;
1227 kern_return_t result
;
1229 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1230 if (result
!= KERN_SUCCESS
) {
1231 kern_error(result
, "port_type");
1234 return ((p_type
& MACH_PORT_TYPE_PORT_RIGHTS
) != 0);