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
35 #include <mach/mach.h>
36 #include <mach/mach_error.h>
37 #include <mach/boolean.h>
38 #include <mach/message.h>
39 #include <mach/notify.h>
40 #include <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>
48 #include <sys/ioctl.h>
49 #include <sys/types.h>
51 #include <sys/resource.h>
64 #include <bsm/audit.h>
65 #include <bsm/libbsm.h>
67 #include "bootstrap.h"
68 #include "bootstrap_internal.h"
72 /* Mig should produce a declaration for this, but doesn't */
73 extern boolean_t
bootstrap_server(mach_msg_header_t
*InHeadP
, mach_msg_header_t
*OutHeadP
);
75 auditinfo_t inherited_audit
;
76 mach_port_t inherited_bootstrap_port
= MACH_PORT_NULL
;
77 bool forward_ok
= false;
78 bool debugging
= false;
79 bool register_self
= false;
80 const char *register_name
= NULL
;
81 task_t bootstrap_self
= MACH_PORT_NULL
;
83 static uid_t inherited_uid
= 0;
84 static bool shutdown_in_progress
= false;
93 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
94 #define END_OF(x) (&(x)[NELEM(x)])
95 #define streq(a,b) (strcmp(a,b) == 0)
98 * Private declarations
100 static void init_ports(void);
101 static void start_server(server_t
*serverp
);
102 static void exec_server(server_t
*serverp
);
103 static char **argvize(const char *string
);
104 static void *demand_loop(void *arg
);
105 void *mach_server_loop(void *);
106 extern kern_return_t bootstrap_register
108 mach_port_t bootstrapport
,
110 mach_port_t serviceport
114 * Private ports we hold receive rights for. We also hold receive rights
115 * for all the privileged ports. Those are maintained in the server
118 mach_port_t bootstrap_port_set
;
119 mach_port_t demand_port_set
;
120 pthread_t demand_thread
;
122 mach_port_t notify_port
;
123 mach_port_t backup_port
;
126 static mach_msg_return_t
128 mach_port_name_t about
,
129 mach_msg_option_t options
)
131 mach_port_destroyed_notification_t
not;
132 mach_msg_size_t size
= sizeof(not) - sizeof(not.trailer
);
134 not.not_header
.msgh_id
= DEMAND_REQUEST
;
135 not.not_header
.msgh_remote_port
= backup_port
;
136 not.not_header
.msgh_local_port
= MACH_PORT_NULL
;
137 not.not_header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND
, 0);
138 not.not_header
.msgh_size
= size
;
139 not.not_body
.msgh_descriptor_count
= 1;
140 not.not_port
.type
= MACH_MSG_PORT_DESCRIPTOR
;
141 not.not_port
.disposition
= MACH_MSG_TYPE_PORT_NAME
;
142 not.not_port
.name
= about
;
143 return mach_msg(¬.not_header
, MACH_SEND_MSG
|options
, size
,
144 0, MACH_PORT_NULL
, MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
);
148 notify_server_loop(mach_port_name_t about
)
150 mach_msg_return_t result
;
152 result
= inform_server_loop(about
, MACH_MSG_OPTION_NONE
);
153 if (result
!= MACH_MSG_SUCCESS
)
154 syslog(LOG_ERR
, "notify_server_loop: mach_msg(): %s", mach_error_string(result
));
157 void mach_start_shutdown(__unused
int signalnum
)
159 shutdown_in_progress
= TRUE
;
160 (void) inform_server_loop(MACH_PORT_NULL
, MACH_SEND_TIMEOUT
);
163 mach_port_t
mach_init_init(void)
165 kern_return_t result
;
168 bootstrap_self
= mach_task_self();
169 inherited_uid
= getuid();
170 getaudit(&inherited_audit
);
174 result
= task_get_bootstrap_port(bootstrap_self
, &inherited_bootstrap_port
);
175 if (result
!= KERN_SUCCESS
) {
176 syslog(LOG_ALERT
, "task_get_bootstrap_port(): %s", mach_error_string(result
));
179 if (inherited_bootstrap_port
== MACH_PORT_NULL
)
182 /* We set this explicitly as we start each child */
183 task_set_bootstrap_port(bootstrap_self
, MACH_PORT_NULL
);
185 /* register "self" port with anscestor */
186 if (register_self
&& forward_ok
) {
187 result
= bootstrap_register(inherited_bootstrap_port
,
188 (char *)register_name
,
189 bootstraps
.bootstrap_port
);
190 if (result
!= KERN_SUCCESS
)
191 panic("register self(): %s", mach_error_string(result
));
194 pthread_attr_init(&attr
);
195 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
196 result
= pthread_create(&demand_thread
, &attr
, demand_loop
, NULL
);
198 panic("pthread_create(): %s", strerror(result
));
199 pthread_attr_destroy(&attr
);
201 return bootstraps
.bootstrap_port
;
207 kern_return_t result
;
210 * This task will become the bootstrap task.
212 /* Create port set that server loop listens to */
213 result
= mach_port_allocate(
215 MACH_PORT_RIGHT_PORT_SET
,
216 &bootstrap_port_set
);
217 if (result
!= KERN_SUCCESS
)
218 panic("port_set_allocate(): %s", mach_error_string(result
));
220 /* Create demand port set that second thread listens to */
221 result
= mach_port_allocate(
223 MACH_PORT_RIGHT_PORT_SET
,
225 if (result
!= KERN_SUCCESS
)
226 panic("port_set_allocate(): %s", mach_error_string(result
));
228 /* Create notify port and add to server port set */
229 result
= mach_port_allocate(
231 MACH_PORT_RIGHT_RECEIVE
,
233 if (result
!= KERN_SUCCESS
)
234 panic("mach_port_allocate(): %s", mach_error_string(result
));
236 result
= mach_port_move_member(
240 if (result
!= KERN_SUCCESS
)
241 panic("mach_port_move_member(): %s", mach_error_string(result
));
243 /* Create backup port and add to server port set */
244 result
= mach_port_allocate(
246 MACH_PORT_RIGHT_RECEIVE
,
248 if (result
!= KERN_SUCCESS
)
249 panic("mach_port_allocate(): %s", mach_error_string(result
));
251 result
= mach_port_move_member(
255 if (result
!= KERN_SUCCESS
)
256 panic("mach_port_move_member(): %s", mach_error_string(result
));
258 /* Create "self" port and add to server port set */
259 result
= mach_port_allocate(
261 MACH_PORT_RIGHT_RECEIVE
,
262 &bootstraps
.bootstrap_port
);
263 if (result
!= KERN_SUCCESS
)
264 panic("mach_port_allocate(): %s", mach_error_string(result
));
265 result
= mach_port_insert_right(
267 bootstraps
.bootstrap_port
,
268 bootstraps
.bootstrap_port
,
269 MACH_MSG_TYPE_MAKE_SEND
);
270 if (result
!= KERN_SUCCESS
)
271 panic("mach_port_insert_right(): %s", mach_error_string(result
));
273 /* keep the root bootstrap port "active" */
274 bootstraps
.requestor_port
= bootstraps
.bootstrap_port
;
276 result
= mach_port_move_member(
278 bootstraps
.bootstrap_port
,
280 if (result
!= KERN_SUCCESS
)
281 panic("mach_port_move_member(): %s", mach_error_string(result
));
285 active_bootstrap(bootstrap_info_t
*bootstrap
)
287 return (bootstrap
->requestor_port
!= MACH_PORT_NULL
);
291 useless_server(server_t
*serverp
)
293 return ( !active_bootstrap(serverp
->bootstrap
) ||
294 !lookup_service_by_server(serverp
) ||
299 active_server(server_t
*serverp
)
301 return ( serverp
->port
||
302 serverp
->task_port
|| serverp
->active_services
);
306 reap_server(server_t
*serverp
)
308 kern_return_t result
;
315 presult
= waitpid(serverp
->pid
, &wstatus
, WNOHANG
);
318 syslog(LOG_DEBUG
, "waitpid: cmd = %s: %m", serverp
->cmd
);
323 /* process must have switched mach tasks */
324 mach_port_t old_port
;
326 old_port
= serverp
->task_port
;
327 mach_port_deallocate(mach_task_self(), old_port
);
328 serverp
->task_port
= MACH_PORT_NULL
;
330 result
= task_for_pid( mach_task_self(),
332 &serverp
->task_port
);
333 if (result
!= KERN_SUCCESS
) {
334 syslog(LOG_INFO
, "race getting new server task port for pid[%d]: %s",
335 serverp
->pid
, mach_error_string(result
));
339 /* Request dead name notification to tell when new task dies */
340 result
= mach_port_request_notification(
343 MACH_NOTIFY_DEAD_NAME
,
346 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
348 if (result
!= KERN_SUCCESS
) {
349 syslog(LOG_INFO
, "race setting up notification for new server task port for pid[%d]: %s",
350 serverp
->pid
, mach_error_string(result
));
357 if (WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
)) {
358 syslog(LOG_NOTICE
, "Server %x in bootstrap %x uid %d: \"%s\"[%d]: exited with status: %d",
359 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
360 serverp
->uid
, serverp
->cmd
, serverp
->pid
, WEXITSTATUS(wstatus
));
361 } else if (WIFSIGNALED(wstatus
)) {
362 syslog(LOG_NOTICE
, "Server %x in bootstrap %x uid %d: \"%s\"[%d]: exited abnormally: %s",
363 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
364 serverp
->uid
, serverp
->cmd
, serverp
->pid
, strsignal(WTERMSIG(wstatus
)));
373 * Release the server task port reference, if we ever
374 * got it in the first place.
376 if (serverp
->task_port
!= MACH_PORT_NULL
) {
377 result
= mach_port_deallocate(
380 if (result
!= KERN_SUCCESS
)
381 syslog(LOG_ERR
, "mach_port_deallocate(): %s", mach_error_string(result
));
382 serverp
->task_port
= MACH_PORT_NULL
;
387 demand_server(server_t
*serverp
)
390 kern_return_t result
;
393 * For on-demand servers, make sure that the service ports are
394 * back in on-demand portset. Active service ports should come
395 * back through a PORT_DESTROYED notification. We only have to
396 * worry about the inactive ports that may have been previously
397 * pulled from the set but never checked-in by the server.
400 for ( servicep
= FIRST(services
)
401 ; !IS_END(servicep
, services
)
402 ; servicep
= NEXT(servicep
))
404 if (serverp
== servicep
->server
&& !servicep
->isActive
) {
405 result
= mach_port_move_member(
409 if (result
!= KERN_SUCCESS
)
410 panic("mach_port_move_member(): %s", mach_error_string(result
));
416 void dispatch_server(server_t
*serverp
)
418 if (!active_server(serverp
)) {
419 if (useless_server(serverp
) || shutdown_in_progress
)
420 delete_server(serverp
);
421 else if (serverp
->servertype
== RESTARTABLE
)
422 start_server(serverp
);
423 else if (serverp
->servertype
== DEMAND
)
424 demand_server(serverp
);
429 setup_server(server_t
*serverp
)
431 kern_return_t result
;
432 mach_port_t old_port
;
434 /* Allocate privileged port for requests from service */
435 result
= mach_port_allocate(mach_task_self(),
436 MACH_PORT_RIGHT_RECEIVE
,
438 syslog(LOG_INFO
, "Allocating port %x for server %s", serverp
->port
, serverp
->cmd
);
439 if (result
!= KERN_SUCCESS
)
440 panic("port_allocate(): %s", mach_error_string(result
));
442 /* Request no-senders notification so we can tell when server dies */
443 result
= mach_port_request_notification(mach_task_self(),
445 MACH_NOTIFY_NO_SENDERS
,
448 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
450 if (result
!= KERN_SUCCESS
)
451 panic("mach_port_request_notification(): %s", mach_error_string(result
));
453 /* Add privileged server port to bootstrap port set */
454 result
= mach_port_move_member(mach_task_self(),
457 if (result
!= KERN_SUCCESS
)
458 panic("mach_port_move_member(): %s", mach_error_string(result
));
462 fork_with_bootstrap_port(mach_port_t p
)
464 static pthread_mutex_t forklock
= PTHREAD_MUTEX_INITIALIZER
;
465 kern_return_t result
;
469 pthread_mutex_lock(&forklock
);
471 sigprocmask(SIG_BLOCK
, &blocked_signals
, NULL
);
473 result
= task_set_bootstrap_port(mach_task_self(), p
);
474 if (result
!= KERN_SUCCESS
)
475 panic("task_set_bootstrap_port(): %s", mach_error_string(result
));
477 if (launchd_bootstrap_port
!= p
) {
478 result
= mach_port_deallocate(mach_task_self(), p
);
479 if (result
!= KERN_SUCCESS
)
480 panic("mach_port_deallocate(): %s", mach_error_string(result
));
488 * We should set the bootstrap back to MACH_PORT_NULL instead
489 * of launchd_bootstrap_port. This will expose rare latent race
490 * condition bugs, given that some programs assume that the PID
491 * 1's bootstrap port is constant. This function clearly
492 * demonstrates that is no longer true.
494 * Those programs should be calling bootstrap_parent(), and not
495 * task_for_pid(1) followed by a call to get the bootstrap port
498 result
= task_set_bootstrap_port(mach_task_self(), launchd_bootstrap_port
);
499 if (result
!= KERN_SUCCESS
)
500 panic("task_set_bootstrap_port(): %s", mach_error_string(result
));
502 for (i
= 0; i
<= NSIG
; i
++) {
503 if (sigismember(&blocked_signals
, i
))
508 sigprocmask(SIG_UNBLOCK
, &blocked_signals
, NULL
);
510 pthread_mutex_unlock(&forklock
);
516 start_server(server_t
*serverp
)
518 kern_return_t result
;
519 mach_port_t old_port
;
523 * Do what's appropriate to get bootstrap port setup in server task
525 switch (serverp
->servertype
) {
534 setup_server(serverp
);
536 serverp
->activity
= 0;
538 /* Insert a send right */
539 result
= mach_port_insert_right(mach_task_self(),
542 MACH_MSG_TYPE_MAKE_SEND
);
543 if (result
!= KERN_SUCCESS
)
544 panic("mach_port_insert_right(): %s", mach_error_string(result
));
546 pid
= fork_with_bootstrap_port(serverp
->port
);
548 syslog(LOG_WARNING
, "fork(): %m");
549 } else if (pid
== 0) { /* CHILD */
550 exec_server(serverp
);
552 } else { /* PARENT */
553 syslog(LOG_INFO
, "Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
554 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
555 serverp
->uid
, serverp
->cmd
, pid
);
557 result
= task_for_pid(
560 &serverp
->task_port
);
561 if (result
!= KERN_SUCCESS
) {
562 syslog(LOG_ERR
, "getting server task port(): %s", mach_error_string(result
));
563 reap_server(serverp
);
564 dispatch_server(serverp
);
568 /* Request dead name notification to tell when task dies */
569 result
= mach_port_request_notification(
572 MACH_NOTIFY_DEAD_NAME
,
575 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
577 if (result
!= KERN_SUCCESS
) {
578 syslog(LOG_ERR
, "mach_port_request_notification(): %s", mach_error_string(result
));
579 reap_server(serverp
);
580 dispatch_server(serverp
);
588 exec_server(server_t
*serverp
)
594 * Setup environment for server, someday this should be Mach stuff
595 * rather than Unix crud
597 argv
= argvize(serverp
->cmd
);
601 * Set up the audit state for the user (if necessesary).
603 if (inherited_uid
== 0 &&
604 (serverp
->auinfo
.ai_auid
!= inherited_uid
||
605 serverp
->auinfo
.ai_asid
!= inherited_audit
.ai_asid
)) {
606 struct passwd
*pwd
= NULL
;
608 pwd
= getpwuid(serverp
->auinfo
.ai_auid
);
610 panic("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed",
611 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
612 serverp
->cmd
, serverp
->auinfo
.ai_auid
);
614 } else if (au_user_mask(pwd
->pw_name
, &serverp
->auinfo
.ai_mask
) != 0) {
615 panic("Disabled server %x bootstrap %x: \"%s\": au_user_mask(%s) failed",
616 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
617 serverp
->cmd
, pwd
->pw_name
);
618 } else if (setaudit(&serverp
->auinfo
) != 0)
619 panic("Disabled server %x bootstrap %x: \"%s\": setaudit()",
620 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
624 if (serverp
->uid
!= inherited_uid
) {
625 struct passwd
*pwd
= getpwuid(serverp
->uid
);
629 panic("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed",
630 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
631 serverp
->cmd
, serverp
->uid
);
636 if (-1 == setgroups(1, &g
)) {
637 panic("Disabled server %x bootstrap %x: \"%s\": setgroups(1, %d): %s",
638 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
639 serverp
->cmd
, g
, strerror(errno
));
642 if (-1 == setgid(g
)) {
643 panic("Disabled server %x bootstrap %x: \"%s\": setgid(%d): %s",
644 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
645 serverp
->cmd
, g
, strerror(errno
));
648 if (-1 == setuid(serverp
->uid
)) {
649 panic("Disabled server %x bootstrap %x: \"%s\": setuid(%d): %s",
650 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
651 serverp
->cmd
, serverp
->uid
, strerror(errno
));
658 * We can't keep this from happening, but we shouldn't start
659 * the server not as a process group leader. So, just fake like
660 * there was real activity, and exit the child. If needed,
661 * we'll re-launch it under another pid.
663 serverp
->activity
= 1;
664 panic("Temporary failure server %x bootstrap %x: \"%s\": setsid(): %s",
665 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
666 serverp
->cmd
, strerror(errno
));
670 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
672 setpriority(PRIO_PROCESS
, 0, 0);
673 execv(argv
[0], argv
);
674 panic("Disabled server %x bootstrap %x: \"%s\": exec(): %s",
676 serverp
->bootstrap
->bootstrap_port
,
682 argvize(const char *string
)
684 static char *argv
[100], args
[1000];
690 * Convert a command line into an argv for execv
695 for (cp
= string
; *cp
;) {
698 term
= (*cp
== '"') ? *cp
++ : '\0';
699 if (nargs
< NELEM(argv
))
700 argv
[nargs
++] = argp
;
701 while (*cp
&& (term
? *cp
!= term
: !isspace(*cp
))
702 && argp
< END_OF(args
)) {
716 demand_loop(void *arg
__attribute__((unused
)))
718 mach_msg_empty_rcv_t dummy
;
719 kern_return_t dresult
;
723 mach_port_name_array_t members
;
724 mach_msg_type_number_t membersCnt
;
725 mach_port_status_t status
;
726 mach_msg_type_number_t statusCnt
;
730 * Receive indication of message on demand service
731 * ports without actually receiving the message (we'll
732 * let the actual server do that.
736 MACH_RCV_MSG
|MACH_RCV_LARGE
,
742 if (dresult
!= MACH_RCV_TOO_LARGE
) {
743 syslog(LOG_ERR
, "demand_loop: mach_msg(): %s", mach_error_string(dresult
));
748 * Some port(s) now have messages on them, find out
749 * which ones (there is no indication of which port
750 * triggered in the MACH_RCV_TOO_LARGE indication).
752 dresult
= mach_port_get_set_status(
757 if (dresult
!= KERN_SUCCESS
) {
758 syslog(LOG_ERR
, "demand_loop: mach_port_get_set_status(): %s", mach_error_string(dresult
));
762 for (i
= 0; i
< membersCnt
; i
++) {
763 statusCnt
= MACH_PORT_RECEIVE_STATUS_COUNT
;
764 dresult
= mach_port_get_attributes(
767 MACH_PORT_RECEIVE_STATUS
,
768 (mach_port_info_t
)&status
,
770 if (dresult
!= KERN_SUCCESS
) {
771 syslog(LOG_ERR
, "demand_loop: mach_port_get_attributes(): %s", mach_error_string(dresult
));
776 * For each port with messages, take it out of the
777 * demand service portset, and inform the main thread
778 * that it might have to start the server responsible
781 if (status
.mps_msgcount
) {
782 dresult
= mach_port_move_member(
786 if (dresult
!= KERN_SUCCESS
) {
787 syslog(LOG_ERR
, "demand_loop: mach_port_move_member(): %s", mach_error_string(dresult
));
790 notify_server_loop(members
[i
]);
794 dresult
= vm_deallocate(
796 (vm_address_t
) members
,
797 (vm_size_t
) membersCnt
* sizeof(mach_port_name_t
));
798 if (dresult
!= KERN_SUCCESS
) {
799 syslog(LOG_ERR
, "demand_loop: vm_deallocate(): %s", mach_error_string(dresult
));
807 * server_demux -- processes requests off our service port
808 * Also handles notifications
813 mach_msg_header_t
*Request
,
814 mach_msg_header_t
*Reply
)
816 bootstrap_info_t
*bootstrap
;
819 kern_return_t result
;
820 mig_reply_error_t
*reply
;
822 syslog(LOG_DEBUG
, "received message on port %x", Request
->msgh_local_port
);
824 reply
= (mig_reply_error_t
*)Reply
;
827 * Pick off notification messages
829 if (Request
->msgh_local_port
== notify_port
) {
832 memset(reply
, 0, sizeof(*reply
));
833 switch (Request
->msgh_id
) {
834 case MACH_NOTIFY_DEAD_NAME
:
835 np
= ((mach_dead_name_notification_t
*)Request
)->not_port
;
836 syslog(LOG_DEBUG
, "Notified dead name %x", np
);
838 if (np
== inherited_bootstrap_port
) {
839 inherited_bootstrap_port
= MACH_PORT_NULL
;
844 * Check to see if a subset requestor port was deleted.
846 while ((bootstrap
= lookup_bootstrap_by_req_port(np
)) != NULL
) {
847 syslog(LOG_DEBUG
, "Received dead name notification for bootstrap subset %x requestor port %x",
848 bootstrap
->bootstrap_port
, bootstrap
->requestor_port
);
849 mach_port_deallocate(
851 bootstrap
->requestor_port
);
852 bootstrap
->requestor_port
= MACH_PORT_NULL
;
853 deactivate_bootstrap(bootstrap
);
857 * Check to see if a defined service has gone
860 while ((servicep
= lookup_service_by_port(np
)) != NULL
) {
862 * Port gone, registered service died.
864 syslog(LOG_DEBUG
, "Received dead name notification for service %s "
865 "on bootstrap port %x\n",
866 servicep
->name
, servicep
->bootstrap
);
867 syslog(LOG_DEBUG
, "Service %s failed - deallocate", servicep
->name
);
868 delete_service(servicep
);
872 * Check to see if a launched server task has gone
875 if ((serverp
= lookup_server_by_task_port(np
)) != NULL
) {
877 * Port gone, server died or picked up new task.
879 syslog(LOG_DEBUG
, "Received task death notification for server %s ",
881 reap_server(serverp
);
882 dispatch_server(serverp
);
885 mach_port_deallocate(mach_task_self(), np
);
886 reply
->RetCode
= KERN_SUCCESS
;
889 case MACH_NOTIFY_PORT_DELETED
:
890 np
= ((mach_port_deleted_notification_t
*)Request
)->not_port
;
891 syslog(LOG_DEBUG
, "port deleted notification on 0x%x", np
);
892 reply
->RetCode
= KERN_SUCCESS
;
895 case MACH_NOTIFY_SEND_ONCE
:
896 syslog(LOG_DEBUG
, "notification send-once right went unused");
897 reply
->RetCode
= KERN_SUCCESS
;
901 syslog(LOG_ERR
, "Unexpected notification: %d", Request
->msgh_id
);
902 reply
->RetCode
= KERN_FAILURE
;
907 else if (Request
->msgh_local_port
== backup_port
) {
910 memset(reply
, 0, sizeof(*reply
));
912 np
= ((mach_port_destroyed_notification_t
*)Request
)->not_port
.name
;
913 servicep
= lookup_service_by_port(np
);
914 if (servicep
!= NULL
) {
915 serverp
= servicep
->server
;
917 switch (Request
->msgh_id
) {
919 case MACH_NOTIFY_PORT_DESTROYED
:
921 * Port sent back to us, server died.
923 syslog(LOG_DEBUG
, "Received destroyed notification for service %s",
925 syslog(LOG_DEBUG
, "Service %x bootstrap %x backed up: %s",
926 servicep
->port
, servicep
->bootstrap
->bootstrap_port
,
928 ASSERT(canReceive(servicep
->port
));
929 servicep
->isActive
= FALSE
;
930 serverp
->active_services
--;
931 dispatch_server(serverp
);
932 reply
->RetCode
= KERN_SUCCESS
;
936 /* message reflected over from demand start thread */
937 if (!active_server(serverp
))
938 start_server(serverp
);
939 reply
->RetCode
= KERN_SUCCESS
;
943 syslog(LOG_DEBUG
, "Mysterious backup_port notification %d", Request
->msgh_id
);
944 reply
->RetCode
= KERN_FAILURE
;
948 syslog(LOG_DEBUG
, "Backup_port notification - previously deleted service");
949 reply
->RetCode
= KERN_FAILURE
;
953 else if (Request
->msgh_id
== MACH_NOTIFY_NO_SENDERS
) {
954 mach_port_t ns
= Request
->msgh_local_port
;
956 if ((serverp
= lookup_server_by_port(ns
)) != NULL_SERVER
) {
958 * A server we launched has released his bootstrap
959 * port send right. We won't re-launch him unless
960 * his services came back to roost. But we need to
961 * destroy the bootstrap port for fear of leaking.
963 syslog(LOG_DEBUG
, "server %s dropped server port", serverp
->cmd
);
964 serverp
->port
= MACH_PORT_NULL
;
965 dispatch_server(serverp
);
966 } else if ((bootstrap
= lookup_bootstrap_by_port(ns
)) != NULL
) {
968 * The last direct user of a deactivated bootstrap went away.
969 * We can finally free it.
971 syslog(LOG_DEBUG
, "Deallocating bootstrap %x: no more clients", ns
);
972 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
973 deallocate_bootstrap(bootstrap
);
976 result
= mach_port_mod_refs(
979 MACH_PORT_RIGHT_RECEIVE
,
981 if (result
!= KERN_SUCCESS
)
982 panic("mach_port_mod_refs(): %s", mach_error_string(result
));
984 memset(reply
, 0, sizeof(*reply
));
985 reply
->RetCode
= KERN_SUCCESS
;
988 else { /* must be a service request */
989 syslog(LOG_DEBUG
, "Handled request.");
990 return bootstrap_server(Request
, Reply
);
996 * server_loop -- pick requests off our service port and process them
997 * Also handles notifications
999 #define bootstrapMaxRequestSize 1024
1000 #define bootstrapMaxReplySize 1024
1003 server_demux_with_giant_lock(
1004 mach_msg_header_t
*Request
,
1005 mach_msg_header_t
*Reply
)
1009 assumes(pthread_mutex_lock(&giant_lock
) == 0);
1010 r
= server_demux(Request
, Reply
);
1011 assumes(pthread_mutex_unlock(&giant_lock
) == 0);
1017 mach_server_loop(void *arg
__attribute__((unused
)))
1019 mach_msg_return_t mresult
;
1022 mresult
= mach_msg_server(
1023 server_demux_with_giant_lock
,
1024 bootstrapMaxRequestSize
,
1026 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
)|
1027 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
));
1028 if (mresult
!= MACH_MSG_SUCCESS
)
1029 syslog(LOG_ERR
, "mach_msg_server(): %s", mach_error_string(mresult
));
1035 canReceive(mach_port_t port
)
1037 mach_port_type_t p_type
;
1038 kern_return_t result
;
1040 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1041 if (result
!= KERN_SUCCESS
) {
1042 syslog(LOG_ERR
, "port_type(): %s", mach_error_string(result
));
1045 return ((p_type
& MACH_PORT_TYPE_RECEIVE
) != 0);
1050 canSend(mach_port_t port
)
1052 mach_port_type_t p_type
;
1053 kern_return_t result
;
1055 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1056 if (result
!= KERN_SUCCESS
) {
1057 syslog(LOG_ERR
, "port_type(): %s", mach_error_string(result
));
1060 return ((p_type
& MACH_PORT_TYPE_PORT_RIGHTS
) != 0);
1063 /* Sigh... Libc's panic() call fails to abort and continues afterwards */
1065 panic(const char *msg
, ...)
1070 vfprintf(stderr
, msg
, ap
);
1073 _exit(EXIT_FAILURE
);