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 if (setuid(serverp
->uid
) < 0)
626 panic("Disabled server %x bootstrap %x: \"%s\": setuid(%d): %s",
627 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
628 serverp
->cmd
, serverp
->uid
, strerror(errno
));
632 * We can't keep this from happening, but we shouldn't start
633 * the server not as a process group leader. So, just fake like
634 * there was real activity, and exit the child. If needed,
635 * we'll re-launch it under another pid.
637 serverp
->activity
= 1;
638 panic("Temporary failure server %x bootstrap %x: \"%s\": setsid(): %s",
639 serverp
->port
, serverp
->bootstrap
->bootstrap_port
,
640 serverp
->cmd
, strerror(errno
));
644 (void) sigprocmask(SIG_SETMASK
, &mask
, (sigset_t
*)NULL
);
646 setpriority(PRIO_PROCESS
, 0, 0);
647 execv(argv
[0], argv
);
648 panic("Disabled server %x bootstrap %x: \"%s\": exec(): %s",
650 serverp
->bootstrap
->bootstrap_port
,
656 argvize(const char *string
)
658 static char *argv
[100], args
[1000];
664 * Convert a command line into an argv for execv
669 for (cp
= string
; *cp
;) {
672 term
= (*cp
== '"') ? *cp
++ : '\0';
673 if (nargs
< NELEM(argv
))
674 argv
[nargs
++] = argp
;
675 while (*cp
&& (term
? *cp
!= term
: !isspace(*cp
))
676 && argp
< END_OF(args
)) {
690 demand_loop(void *arg
__attribute__((unused
)))
692 mach_msg_empty_rcv_t dummy
;
693 kern_return_t dresult
;
697 mach_port_name_array_t members
;
698 mach_msg_type_number_t membersCnt
;
699 mach_port_status_t status
;
700 mach_msg_type_number_t statusCnt
;
704 * Receive indication of message on demand service
705 * ports without actually receiving the message (we'll
706 * let the actual server do that.
710 MACH_RCV_MSG
|MACH_RCV_LARGE
,
716 if (dresult
!= MACH_RCV_TOO_LARGE
) {
717 syslog(LOG_ERR
, "demand_loop: mach_msg(): %s", mach_error_string(dresult
));
722 * Some port(s) now have messages on them, find out
723 * which ones (there is no indication of which port
724 * triggered in the MACH_RCV_TOO_LARGE indication).
726 dresult
= mach_port_get_set_status(
731 if (dresult
!= KERN_SUCCESS
) {
732 syslog(LOG_ERR
, "demand_loop: mach_port_get_set_status(): %s", mach_error_string(dresult
));
736 for (i
= 0; i
< membersCnt
; i
++) {
737 statusCnt
= MACH_PORT_RECEIVE_STATUS_COUNT
;
738 dresult
= mach_port_get_attributes(
741 MACH_PORT_RECEIVE_STATUS
,
742 (mach_port_info_t
)&status
,
744 if (dresult
!= KERN_SUCCESS
) {
745 syslog(LOG_ERR
, "demand_loop: mach_port_get_attributes(): %s", mach_error_string(dresult
));
750 * For each port with messages, take it out of the
751 * demand service portset, and inform the main thread
752 * that it might have to start the server responsible
755 if (status
.mps_msgcount
) {
756 dresult
= mach_port_move_member(
760 if (dresult
!= KERN_SUCCESS
) {
761 syslog(LOG_ERR
, "demand_loop: mach_port_move_member(): %s", mach_error_string(dresult
));
764 notify_server_loop(members
[i
]);
768 dresult
= vm_deallocate(
770 (vm_address_t
) members
,
771 (vm_size_t
) membersCnt
* sizeof(mach_port_name_t
));
772 if (dresult
!= KERN_SUCCESS
) {
773 syslog(LOG_ERR
, "demand_loop: vm_deallocate(): %s", mach_error_string(dresult
));
781 * server_demux -- processes requests off our service port
782 * Also handles notifications
787 mach_msg_header_t
*Request
,
788 mach_msg_header_t
*Reply
)
790 bootstrap_info_t
*bootstrap
;
793 kern_return_t result
;
794 mig_reply_error_t
*reply
;
796 syslog(LOG_DEBUG
, "received message on port %x", Request
->msgh_local_port
);
798 reply
= (mig_reply_error_t
*)Reply
;
801 * Pick off notification messages
803 if (Request
->msgh_local_port
== notify_port
) {
806 memset(reply
, 0, sizeof(*reply
));
807 switch (Request
->msgh_id
) {
808 case MACH_NOTIFY_DEAD_NAME
:
809 np
= ((mach_dead_name_notification_t
*)Request
)->not_port
;
810 syslog(LOG_DEBUG
, "Notified dead name %x", np
);
812 if (np
== inherited_bootstrap_port
) {
813 inherited_bootstrap_port
= MACH_PORT_NULL
;
818 * Check to see if a subset requestor port was deleted.
820 while ((bootstrap
= lookup_bootstrap_by_req_port(np
)) != NULL
) {
821 syslog(LOG_DEBUG
, "Received dead name notification for bootstrap subset %x requestor port %x",
822 bootstrap
->bootstrap_port
, bootstrap
->requestor_port
);
823 mach_port_deallocate(
825 bootstrap
->requestor_port
);
826 bootstrap
->requestor_port
= MACH_PORT_NULL
;
827 deactivate_bootstrap(bootstrap
);
831 * Check to see if a defined service has gone
834 while ((servicep
= lookup_service_by_port(np
)) != NULL
) {
836 * Port gone, registered service died.
838 syslog(LOG_DEBUG
, "Received dead name notification for service %s "
839 "on bootstrap port %x\n",
840 servicep
->name
, servicep
->bootstrap
);
841 syslog(LOG_DEBUG
, "Service %s failed - deallocate", servicep
->name
);
842 delete_service(servicep
);
846 * Check to see if a launched server task has gone
849 if ((serverp
= lookup_server_by_task_port(np
)) != NULL
) {
851 * Port gone, server died or picked up new task.
853 syslog(LOG_DEBUG
, "Received task death notification for server %s ",
855 reap_server(serverp
);
856 dispatch_server(serverp
);
859 mach_port_deallocate(mach_task_self(), np
);
860 reply
->RetCode
= KERN_SUCCESS
;
863 case MACH_NOTIFY_PORT_DELETED
:
864 np
= ((mach_port_deleted_notification_t
*)Request
)->not_port
;
865 syslog(LOG_DEBUG
, "port deleted notification on 0x%x", np
);
866 reply
->RetCode
= KERN_SUCCESS
;
869 case MACH_NOTIFY_SEND_ONCE
:
870 syslog(LOG_DEBUG
, "notification send-once right went unused");
871 reply
->RetCode
= KERN_SUCCESS
;
875 syslog(LOG_ERR
, "Unexpected notification: %d", Request
->msgh_id
);
876 reply
->RetCode
= KERN_FAILURE
;
881 else if (Request
->msgh_local_port
== backup_port
) {
884 memset(reply
, 0, sizeof(*reply
));
886 np
= ((mach_port_destroyed_notification_t
*)Request
)->not_port
.name
;
887 servicep
= lookup_service_by_port(np
);
888 if (servicep
!= NULL
) {
889 serverp
= servicep
->server
;
891 switch (Request
->msgh_id
) {
893 case MACH_NOTIFY_PORT_DESTROYED
:
895 * Port sent back to us, server died.
897 syslog(LOG_DEBUG
, "Received destroyed notification for service %s",
899 syslog(LOG_DEBUG
, "Service %x bootstrap %x backed up: %s",
900 servicep
->port
, servicep
->bootstrap
->bootstrap_port
,
902 ASSERT(canReceive(servicep
->port
));
903 servicep
->isActive
= FALSE
;
904 serverp
->active_services
--;
905 dispatch_server(serverp
);
906 reply
->RetCode
= KERN_SUCCESS
;
910 /* message reflected over from demand start thread */
911 if (!active_server(serverp
))
912 start_server(serverp
);
913 reply
->RetCode
= KERN_SUCCESS
;
917 syslog(LOG_DEBUG
, "Mysterious backup_port notification %d", Request
->msgh_id
);
918 reply
->RetCode
= KERN_FAILURE
;
922 syslog(LOG_DEBUG
, "Backup_port notification - previously deleted service");
923 reply
->RetCode
= KERN_FAILURE
;
927 else if (Request
->msgh_id
== MACH_NOTIFY_NO_SENDERS
) {
928 mach_port_t ns
= Request
->msgh_local_port
;
930 if ((serverp
= lookup_server_by_port(ns
)) != NULL_SERVER
) {
932 * A server we launched has released his bootstrap
933 * port send right. We won't re-launch him unless
934 * his services came back to roost. But we need to
935 * destroy the bootstrap port for fear of leaking.
937 syslog(LOG_DEBUG
, "server %s dropped server port", serverp
->cmd
);
938 serverp
->port
= MACH_PORT_NULL
;
939 dispatch_server(serverp
);
940 } else if ((bootstrap
= lookup_bootstrap_by_port(ns
)) != NULL
) {
942 * The last direct user of a deactivated bootstrap went away.
943 * We can finally free it.
945 syslog(LOG_DEBUG
, "Deallocating bootstrap %x: no more clients", ns
);
946 bootstrap
->bootstrap_port
= MACH_PORT_NULL
;
947 deallocate_bootstrap(bootstrap
);
950 result
= mach_port_mod_refs(
953 MACH_PORT_RIGHT_RECEIVE
,
955 if (result
!= KERN_SUCCESS
)
956 panic("mach_port_mod_refs(): %s", mach_error_string(result
));
958 memset(reply
, 0, sizeof(*reply
));
959 reply
->RetCode
= KERN_SUCCESS
;
962 else { /* must be a service request */
963 syslog(LOG_DEBUG
, "Handled request.");
964 return bootstrap_server(Request
, Reply
);
970 * server_loop -- pick requests off our service port and process them
971 * Also handles notifications
973 #define bootstrapMaxRequestSize 1024
974 #define bootstrapMaxReplySize 1024
977 mach_server_loop(void *arg
__attribute__((unused
)))
979 mach_msg_return_t mresult
;
982 mresult
= mach_msg_server(
984 bootstrapMaxRequestSize
,
986 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
)|
987 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
));
988 if (mresult
!= MACH_MSG_SUCCESS
)
989 syslog(LOG_ERR
, "mach_msg_server(): %s", mach_error_string(mresult
));
995 canReceive(mach_port_t port
)
997 mach_port_type_t p_type
;
998 kern_return_t result
;
1000 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1001 if (result
!= KERN_SUCCESS
) {
1002 syslog(LOG_ERR
, "port_type(): %s", mach_error_string(result
));
1005 return ((p_type
& MACH_PORT_TYPE_RECEIVE
) != 0);
1010 canSend(mach_port_t port
)
1012 mach_port_type_t p_type
;
1013 kern_return_t result
;
1015 result
= mach_port_type(mach_task_self(), port
, &p_type
);
1016 if (result
!= KERN_SUCCESS
) {
1017 syslog(LOG_ERR
, "port_type(): %s", mach_error_string(result
));
1020 return ((p_type
& MACH_PORT_TYPE_PORT_RIGHTS
) != 0);