2 * Copyright (c) 1999 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 * rpc_services.c -- implementation of bootstrap rpc services
35 #import "bootstrap_internal.h"
45 #define NULL ((void *)0)
48 /* extern port_all_t backup_port; */
52 * bootstrap_check_in(mach_port_t bootstrap_port,
53 * name_t service_name,
54 * mach_port_t *service_portp)
56 * Returns receive rights to service_port of service named by service_name.
58 * Errors: Returns appropriate kernel errors on rpc failure.
59 * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
60 * Returns BOOTSTRAP_SERVICE_NOT_DECLARED, if service not declared
61 * in /etc/bootstrap.conf.
62 * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been
63 * registered or checked-in.
67 mach_port_t bootstrap_port
,
69 mach_port_t
*service_portp
)
74 bootstrap_info_t
*bootstrap
;
76 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
77 serverp
= lookup_server_by_port(bootstrap_port
);
78 if (serverp
== NULL
) {
79 debug("bootstrap_check_in service %s has no server",
81 return BOOTSTRAP_NOT_PRIVILEGED
;
83 servicep
= lookup_service_by_name(bootstrap
, service_name
);
84 if (servicep
== NULL
|| servicep
->port
== MACH_PORT_NULL
) {
85 debug("bootstrap_check_in service %s unknown%s", service_name
,
86 forward_ok
? " forwarding" : "");
87 result
= BOOTSTRAP_UNKNOWN_SERVICE
;
90 if (servicep
->server
!= NULL
&& servicep
->server
!= serverp
) {
91 debug("bootstrap_check_in service %s not privileged",
93 return BOOTSTRAP_NOT_PRIVILEGED
;
95 if (servicep
->servicetype
== SELF
|| !canReceive(servicep
->port
)) {
96 ASSERT(servicep
->isActive
);
97 debug("bootstrap_check_in service %s already active",
99 return BOOTSTRAP_SERVICE_ACTIVE
;
101 log("Checkin service %s", service_name
);
102 ASSERT(servicep
->isActive
== FALSE
);
103 servicep
->isActive
= TRUE
;
104 *service_portp
= servicep
->port
;
105 info("Check-in port %d for service %s\n",
106 servicep
->port
, servicep
->name
);
107 return BOOTSTRAP_SUCCESS
;
110 ? bootstrap_check_in(inherited_bootstrap_port
,
118 * bootstrap_register(mach_port_t bootstrap_port,
119 * name_t service_name,
120 * mach_port_t service_port)
122 * Registers send rights for the port service_port for the service named by
123 * service_name. Registering a declared service or registering a service for
124 * which bootstrap has receive rights via a port backup notification is
126 * The previous service port will be deallocated. Restarting services wishing
127 * to resume service for previous clients must first attempt to checkin to the
130 * Errors: Returns appropriate kernel errors on rpc failure.
131 * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to
132 * unprivileged bootstrap port.
133 * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been
134 * register or checked-in.
137 x_bootstrap_register(
138 mach_port_t bootstrap_port
,
140 mach_port_t service_port
)
144 bootstrap_info_t
*bootstrap
;
145 mach_port_t old_port
;
147 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
148 ASSERT(canSend(service_port
));
149 debug("Register attempt for service %s port %d",
150 service_name
, service_port
);
153 * If this bootstrap port is for a server, or it's an unprivileged
154 * bootstrap can't register the port.
156 serverp
= lookup_server_by_port(bootstrap_port
);
157 servicep
= lookup_service_by_name(bootstrap
, service_name
);
158 if (servicep
&& servicep
->server
&& servicep
->server
!= serverp
)
159 return BOOTSTRAP_NOT_PRIVILEGED
;
162 bootstrap_port
= bootstrap
->bootstrap_port
;
163 else if (bootstrap_port
!= bootstrap
->bootstrap_port
)
164 return BOOTSTRAP_NOT_PRIVILEGED
;
166 if (servicep
== NULL
|| servicep
->bootstrap
!= bootstrap
) {
167 servicep
= new_service(bootstrap
,
173 debug("Registered new service %s", service_name
);
175 if (servicep
->isActive
) {
176 debug("Register: service %s already active, port %d",
177 servicep
->name
, servicep
->port
);
178 ASSERT(!canReceive(servicep
->port
));
179 return BOOTSTRAP_SERVICE_ACTIVE
;
181 old_port
= servicep
->port
;
182 servicep
->port
= service_port
;
183 msg_destroy_port(old_port
);
184 servicep
->isActive
= TRUE
;
185 log("Re-registered inactive service %s", service_name
);
187 debug("Registering port %d for service %s\n",
190 return BOOTSTRAP_SUCCESS
;
195 * bootstrap_look_up(mach_port_t bootstrap_port,
196 * name_t service_name,
197 * mach_port_t *service_portp)
199 * Returns send rights for the service port of the service named by
200 * service_name in *service_portp. Service is not guaranteed to be active.
202 * Errors: Returns appropriate kernel errors on rpc failure.
203 * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
207 mach_port_t bootstrap_port
,
209 mach_port_t
*service_portp
)
212 bootstrap_info_t
*bootstrap
;
214 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
215 servicep
= lookup_service_by_name(bootstrap
, service_name
);
216 if (servicep
== NULL
|| servicep
->port
== MACH_PORT_NULL
) {
219 debug("bootstrap_look_up service %s forwarding",
222 return bootstrap_look_up(inherited_bootstrap_port
,
227 debug("bootstrap_look_up service %s unknown",
230 return BOOTSTRAP_UNKNOWN_SERVICE
;
233 if (!canSend(servicep
->port
)) {
234 error("Mysterious loss of send rights on port %d, "
235 "deleting service %s",
238 delete_service(servicep
);
239 return BOOTSTRAP_UNKNOWN_SERVICE
;
241 *service_portp
= servicep
->port
;
243 debug("Lookup returns port %d for service %s\n",
247 return BOOTSTRAP_SUCCESS
;
252 * bootstrap_look_up_array(mach_port_t bootstrap_port,
253 * name_array_t service_names,
254 * int service_names_cnt,
255 * mach_port_array_t *service_ports,
256 * int *service_ports_cnt,
257 * boolean_t *all_services_known)
259 * Returns port send rights in corresponding entries of the array service_ports
260 * for all services named in the array service_names. Service_ports_cnt is
261 * returned and will always equal service_names_cnt (assuming service_names_cnt
262 * is greater than or equal to zero).
264 * Errors: Returns appropriate kernel errors on rpc failure.
265 * Returns BOOTSTRAP_NO_MEMORY, if server couldn't obtain memory
267 * Unknown service names have the corresponding service
268 * port set to MACH_PORT_NULL.
269 * If all services are known, all_services_known is true on
271 * if any service is unknown, it's false.
274 x_bootstrap_look_up_array(
275 mach_port_t bootstrap_port
,
276 name_array_t service_names
,
277 unsigned int service_names_cnt
,
278 mach_port_array_t
*service_portsp
,
279 unsigned int *service_ports_cnt
,
280 boolean_t
*all_services_known
)
283 static mach_port_t service_ports
[BOOTSTRAP_MAX_LOOKUP_COUNT
];
285 if (service_names_cnt
> BOOTSTRAP_MAX_LOOKUP_COUNT
)
286 return BOOTSTRAP_BAD_COUNT
;
287 *service_ports_cnt
= service_names_cnt
;
288 *all_services_known
= TRUE
;
289 for (i
= 0; i
< service_names_cnt
; i
++) {
290 if ( x_bootstrap_look_up(bootstrap_port
,
293 != BOOTSTRAP_SUCCESS
)
295 *all_services_known
= FALSE
;
296 service_ports
[i
] = MACH_PORT_NULL
;
300 debug("bootstrap_look_up_array returns %d ports", service_names_cnt
);
302 *service_portsp
= service_ports
;
303 return BOOTSTRAP_SUCCESS
;
308 * bootstrap_status(mach_port_t bootstrap_port,
309 * name_t service_name,
310 * boolean_t *service_active);
312 * Returns: service_active is true if service is available.
314 * Errors: Returns appropriate kernel errors on rpc failure.
315 * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
319 mach_port_t bootstrap_port
,
321 boolean_t
*service_active
)
324 bootstrap_info_t
*bootstrap
;
326 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
327 servicep
= lookup_service_by_name(bootstrap
, service_name
);
328 if (servicep
== NULL
) {
330 debug("bootstrap_status forwarding status, server %s",
332 return bootstrap_status(inherited_bootstrap_port
,
337 debug("bootstrap_status service %s unknown",
340 return BOOTSTRAP_UNKNOWN_SERVICE
;
343 *service_active
= servicep
->isActive
;
345 debug("bootstrap_status server %s %sactive", service_name
,
346 servicep
->isActive
? "" : "in");
348 return BOOTSTRAP_SUCCESS
;
353 * bootstrap_info(mach_port_t bootstrap_port,
354 * name_array_t *service_names,
355 * int *service_names_cnt,
356 * name_array_t *server_names,
357 * int *server_names_cnt,
358 * bool_array_t *service_actives,
359 * int *service_active_cnt);
361 * Returns bootstrap status for all known services.
363 * Errors: Returns appropriate kernel errors on rpc failure.
367 mach_port_t bootstrap_port
,
368 name_array_t
*service_namesp
,
369 unsigned int *service_names_cnt
,
370 name_array_t
*server_namesp
,
371 unsigned int *server_names_cnt
,
372 bool_array_t
*service_activesp
,
373 unsigned int *service_actives_cnt
)
375 kern_return_t result
;
379 bootstrap_info_t
*bootstrap
;
380 name_array_t service_names
;
381 name_array_t server_names
;
382 bool_array_t service_actives
;
384 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
386 for ( cnt
= i
= 0, servicep
= services
.next
388 ; servicep
= servicep
->next
, i
++)
390 if (lookup_service_by_name(bootstrap
, servicep
->name
) == servicep
)
395 result
= vm_allocate(mach_task_self(),
396 (vm_address_t
*)&service_names
,
397 cnt
* sizeof(service_names
[0]),
399 if (result
!= KERN_SUCCESS
)
400 return BOOTSTRAP_NO_MEMORY
;
402 result
= vm_allocate(mach_task_self(),
403 (vm_address_t
*)&server_names
,
404 cnt
* sizeof(server_names
[0]),
406 if (result
!= KERN_SUCCESS
) {
407 (void)vm_deallocate(mach_task_self(),
408 (vm_address_t
)service_names
,
409 cnt
* sizeof(service_names
[0]));
410 return BOOTSTRAP_NO_MEMORY
;
412 result
= vm_allocate(mach_task_self(),
413 (vm_address_t
*)&service_actives
,
414 cnt
* sizeof(service_actives
[0]),
416 if (result
!= KERN_SUCCESS
) {
417 (void)vm_deallocate(mach_task_self(),
418 (vm_address_t
)service_names
,
419 cnt
* sizeof(service_names
[0]));
420 (void)vm_deallocate(mach_task_self(),
421 (vm_address_t
)server_names
,
422 cnt
* sizeof(server_names
[0]));
423 return BOOTSTRAP_NO_MEMORY
;
426 for ( i
= 0, servicep
= services
.next
428 ; servicep
= servicep
->next
)
430 if ( lookup_service_by_name(bootstrap
, servicep
->name
)
433 strncpy(service_names
[i
],
435 sizeof(service_names
[0]));
436 service_names
[i
][sizeof(service_names
[0]) - 1] = '\0';
437 if (servicep
->server
) {
438 serverp
= servicep
->server
;
439 strncpy(server_names
[i
],
441 sizeof(server_names
[0]));
442 server_names
[i
][sizeof(server_names
[0]) - 1] = '\0';
443 debug("bootstrap info service %s server %s %sactive",
445 serverp
->cmd
, servicep
->isActive
? "" : "in");
447 server_names
[i
][0] = '\0';
448 debug("bootstrap info service %s %sactive",
449 servicep
->name
, servicep
->isActive
? "" : "in");
451 service_actives
[i
] = servicep
->isActive
;
454 *service_namesp
= service_names
;
455 *server_namesp
= server_names
;
456 *service_activesp
= service_actives
;
457 *service_names_cnt
= *server_names_cnt
=
458 *service_actives_cnt
= cnt
;
460 return BOOTSTRAP_SUCCESS
;
465 * bootstrap_subset(mach_port_t bootstrap_port,
466 * mach_port_t requestor_port,
467 * mach_port_t *subset_port);
469 * Returns a new port to use as a bootstrap port. This port behaves
470 * exactly like the previous bootstrap_port, except that ports dynamically
471 * registered via bootstrap_register() are available only to users of this
472 * specific subset_port. Lookups on the subset_port will return ports
473 * registered with this port specifically, and ports registered with
474 * ancestors of this subset_port. Duplications of services already
475 * registered with an ancestor port may be registered with the subset port
476 * are allowed. Services already advertised may then be effectively removed
477 * by registering MACH_PORT_NULL for the service.
478 * When it is detected that the requestor_port is destroied the subset
479 * port and all services advertized by it are destroied as well.
481 * Errors: Returns appropriate kernel errors on rpc failure.
485 mach_port_t bootstrap_port
,
486 mach_port_t requestor_port
,
487 mach_port_t
*subset_port
)
489 kern_return_t result
;
490 bootstrap_info_t
*bootstrap
;
491 bootstrap_info_t
*subset
;
492 mach_port_t new_bootstrap_port
;
494 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
496 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &new_bootstrap_port
);
497 if (result
!= KERN_SUCCESS
)
498 kern_fatal(result
, "mach_port_allocate");
499 result
= mach_port_insert_right(mach_task_self(), new_bootstrap_port
, new_bootstrap_port
, MACH_MSG_TYPE_MAKE_SEND
);
500 if (result
!= KERN_SUCCESS
)
501 kern_fatal(result
, "failed to insert send right");
503 result
= mach_port_move_member(mach_task_self(), new_bootstrap_port
, bootstrap_port_set
);
504 if (result
!= KERN_SUCCESS
)
505 kern_fatal(result
, "port_set_add");
507 subset
= new_bootstrap(bootstrap
, new_bootstrap_port
, requestor_port
);
508 *subset_port
= new_bootstrap_port
;
509 debug("bootstrap_subset new bootstrap %d", new_bootstrap_port
);
510 return BOOTSTRAP_SUCCESS
;
515 * bootstrap_create_service(mach_port_t bootstrap_port,
516 * name_t service_name,
517 * mach_port_t *service_port)
519 * Creates a service named "service_name" and returns send rights to that
520 * port in "service_port." The port may later be checked in as if this
521 * port were configured in the bootstrap configuration file.
523 * Errors: Returns appropriate kernel errors on rpc failure.
524 * Returns BOOTSTRAP_NAME_IN_USE, if service already exists.
527 x_bootstrap_create_service(
528 mach_port_t bootstrap_port
,
530 mach_port_t
*service_port
)
533 bootstrap_info_t
*bootstrap
;
534 kern_return_t result
;
535 mach_port_t previous
;
537 bootstrap
= lookup_bootstrap_by_port(bootstrap_port
);
539 debug("Service creation attempt for service %s", service_name
);
541 servicep
= lookup_service_by_name(bootstrap
, service_name
);
543 debug("Service creation attempt for service %s failed, "
544 "service already exists", service_name
);
545 return BOOTSTRAP_NAME_IN_USE
;
548 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, service_port
);
549 if (result
!= KERN_SUCCESS
)
550 kern_fatal(result
, "port_allocate");
551 result
= mach_port_insert_right(mach_task_self(), *service_port
, *service_port
, MACH_MSG_TYPE_MAKE_SEND
);
552 if (result
!= KERN_SUCCESS
)
553 kern_fatal(result
, "failed to insert send right");
555 result
= port_set_backup(mach_task_self(), *service_port
, backup_port
,
557 if (result
!= KERN_SUCCESS
)
558 kern_fatal(result
, "port_set_backup");
559 info("Declared port %d for service %s", *service_port
,
563 servicep
= new_service(bootstrap
,
570 log("Created new service %s", service_name
);
572 return BOOTSTRAP_SUCCESS
;