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 * lists.c -- implementation of list handling routines
32 #include <mach/boolean.h>
33 #include <mach/mach_error.h>
39 #include <bsm/audit.h>
41 #include "bootstrap_internal.h"
47 bootstrap_info_t bootstraps
; /* head of list of all bootstrap ports */
48 server_t servers
; /* head of list of all servers */
49 service_t services
; /* head of list of all services */
50 unsigned nservices
; /* number of services in list */
59 #define NEW(type, num) ((type *)ckmalloc(sizeof(type) * num))
60 #define STREQ(a, b) (strcmp(a, b) == 0)
61 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
62 #define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
67 bootstraps
.ref_count
= 2; /* make sure we never deallocate this one */
68 bootstraps
.next
= bootstraps
.prev
= &bootstraps
;
69 bootstraps
.parent
= &bootstraps
;
70 servers
.next
= servers
.prev
= &servers
;
71 services
.next
= services
.prev
= &services
;
77 bootstrap_info_t
*bootstrap
,
80 servertype_t servertype
,
85 syslog(LOG_DEBUG
, "adding new server \"%s\" with uid %d", cmd
, uid
);
86 serverp
= NEW(server_t
, 1);
87 if (serverp
!= NULL
) {
88 /* Doubly linked list */
89 servers
.prev
->next
= serverp
;
90 serverp
->prev
= servers
.prev
;
91 serverp
->next
= &servers
;
92 servers
.prev
= serverp
;
94 bootstrap
->ref_count
++;
95 serverp
->bootstrap
= bootstrap
;
97 serverp
->pid
= NO_PID
;
98 serverp
->task_port
= MACH_PORT_NULL
;
101 serverp
->auinfo
= auinfo
;
103 serverp
->port
= MACH_PORT_NULL
;
104 serverp
->servertype
= servertype
;
105 serverp
->activity
= 0;
106 serverp
->active_services
= 0;
107 strncpy(serverp
->cmd
, cmd
, sizeof serverp
->cmd
);
108 LAST_ELEMENT(serverp
->cmd
) = '\0';
115 bootstrap_info_t
*bootstrap
,
117 mach_port_t serviceport
,
119 servicetype_t servicetype
,
124 servicep
= NEW(service_t
, 1);
125 if (servicep
!= NULL
) {
126 /* Doubly linked list */
127 services
.prev
->next
= servicep
;
128 servicep
->prev
= services
.prev
;
129 servicep
->next
= &services
;
130 services
.prev
= servicep
;
134 strncpy(servicep
->name
, name
, sizeof servicep
->name
);
135 LAST_ELEMENT(servicep
->name
) = '\0';
136 servicep
->servicetype
= servicetype
;
137 servicep
->bootstrap
= bootstrap
;
138 servicep
->port
= serviceport
;
139 servicep
->server
= serverp
;
140 servicep
->isActive
= isActive
;
147 bootstrap_info_t
*parent
,
148 mach_port_t bootstrapport
,
149 mach_port_t requestorport
)
151 bootstrap_info_t
*bootstrap
;
153 bootstrap
= NEW(bootstrap_info_t
, 1);
154 if (bootstrap
!= NULL
) {
155 /* Doubly linked list */
156 bootstraps
.prev
->next
= bootstrap
;
157 bootstrap
->prev
= bootstraps
.prev
;
158 bootstrap
->next
= &bootstraps
;
159 bootstraps
.prev
= bootstrap
;
161 bootstrap
->bootstrap_port
= bootstrapport
;
162 bootstrap
->requestor_port
= requestorport
;
164 bootstrap
->ref_count
= 1;
165 bootstrap
->parent
= parent
;
172 lookup_bootstrap_by_port(mach_port_t port
)
174 bootstrap_info_t
*bootstrap
;
175 bootstrap_info_t
*first
;
178 bootstrap
= first
= FIRST(bootstraps
);
180 if (bootstrap
->bootstrap_port
== port
)
182 bootstrap
= NEXT(bootstrap
);
183 } while (bootstrap
!= first
);
185 for ( serverp
= FIRST(servers
)
186 ; !IS_END(serverp
, servers
)
187 ; serverp
= NEXT(serverp
))
189 if (port
== serverp
->port
)
190 return serverp
->bootstrap
;
196 lookup_bootstrap_by_req_port(mach_port_t port
)
198 bootstrap_info_t
*bootstrap
;
200 for ( bootstrap
= FIRST(bootstraps
)
201 ; !IS_END(bootstrap
, bootstraps
)
202 ; bootstrap
= NEXT(bootstrap
))
204 if (bootstrap
->requestor_port
== port
)
212 lookup_service_by_name(bootstrap_info_t
*bootstrap
, name_t name
)
218 for ( servicep
= FIRST(services
)
219 ; !IS_END(servicep
, services
)
220 ; servicep
= NEXT(servicep
))
222 if (!STREQ(name
, servicep
->name
))
224 if (bootstrap
&& servicep
->bootstrap
!= bootstrap
)
228 } while (bootstrap
!= &bootstraps
&&
229 (bootstrap
= bootstrap
->parent
));
234 unlink_service(service_t
*servicep
)
236 ASSERT(servicep
->prev
->next
== servicep
);
237 ASSERT(servicep
->next
->prev
== servicep
);
238 servicep
->prev
->next
= servicep
->next
;
239 servicep
->next
->prev
= servicep
->prev
;
240 servicep
->prev
= servicep
->next
= servicep
; // idempotent
244 delete_service(service_t
*servicep
)
246 unlink_service(servicep
);
247 switch (servicep
->servicetype
) {
249 syslog(LOG_INFO
, "Registered service %s deleted", servicep
->name
);
250 mach_port_deallocate(mach_task_self(), servicep
->port
);
253 syslog(LOG_INFO
, "Declared service %s now unavailable", servicep
->name
);
254 mach_port_deallocate(mach_task_self(), servicep
->port
);
255 mach_port_mod_refs(mach_task_self(), servicep
->port
,
256 MACH_PORT_RIGHT_RECEIVE
, -1);
259 syslog(LOG_ERR
, "unknown service type %d", servicep
->servicetype
);
267 delete_bootstrap_services(bootstrap_info_t
*bootstrap
)
273 for ( servicep
= FIRST(services
)
274 ; !IS_END(servicep
, services
)
277 next
= NEXT(servicep
);
278 if (bootstrap
!= servicep
->bootstrap
)
281 if (!servicep
->isActive
|| !servicep
->server
) {
282 delete_service(servicep
);
286 serverp
= servicep
->server
;
287 delete_service(servicep
);
288 serverp
->active_services
--;
289 if (!active_server(serverp
))
290 delete_server(serverp
);
295 lookup_service_by_port(mach_port_t port
)
299 for ( servicep
= FIRST(services
)
300 ; !IS_END(servicep
, services
)
301 ; servicep
= NEXT(servicep
))
303 if (port
== servicep
->port
)
310 lookup_service_by_server(server_t
*serverp
)
314 for ( servicep
= FIRST(services
)
315 ; !IS_END(servicep
, services
)
316 ; servicep
= NEXT(servicep
))
318 if (serverp
== servicep
->server
)
325 lookup_server_by_task_port(mach_port_t port
)
329 for ( serverp
= FIRST(servers
)
330 ; !IS_END(serverp
, servers
)
331 ; serverp
= NEXT(serverp
))
333 if (port
== serverp
->task_port
)
340 lookup_server_by_port(mach_port_t port
)
344 for ( serverp
= FIRST(servers
)
345 ; !IS_END(serverp
, servers
)
346 ; serverp
= NEXT(serverp
))
348 if (port
== serverp
->port
)
355 delete_server(server_t
*serverp
)
360 syslog(LOG_INFO
, "Deleting server %s", serverp
->cmd
);
361 ASSERT(serverp
->prev
->next
== serverp
);
362 ASSERT(serverp
->next
->prev
== serverp
);
363 serverp
->prev
->next
= serverp
->next
;
364 serverp
->next
->prev
= serverp
->prev
;
366 for ( servicep
= FIRST(services
)
367 ; !IS_END(servicep
, services
)
370 next
= NEXT(servicep
);
371 if (serverp
== servicep
->server
)
372 delete_service(servicep
);
375 deallocate_bootstrap(serverp
->bootstrap
);
378 mach_port_mod_refs(mach_task_self(), serverp
->port
,
379 MACH_PORT_RIGHT_RECEIVE
, -1);
385 deactivate_bootstrap(bootstrap_info_t
*bootstrap
)
387 bootstrap_info_t
*deactivating_bootstraps
;
388 bootstrap_info_t
*query_bootstrap
;
389 bootstrap_info_t
*next_limit
;
390 bootstrap_info_t
*limit
;
393 * we need to recursively deactivate the whole subset tree below
394 * this point. But we don't want to do real recursion because
395 * we don't have a limit on the depth. So, build up a chain of
396 * active bootstraps anywhere underneath this one.
398 deactivating_bootstraps
= bootstrap
;
399 bootstrap
->deactivate
= NULL
;
400 for (next_limit
= deactivating_bootstraps
, limit
= NULL
401 ; deactivating_bootstraps
!= limit
402 ; limit
= next_limit
, next_limit
= deactivating_bootstraps
)
404 for (bootstrap
= deactivating_bootstraps
406 ; bootstrap
= bootstrap
->deactivate
)
408 for ( query_bootstrap
= FIRST(bootstraps
)
409 ; !IS_END(query_bootstrap
, bootstraps
)
410 ; query_bootstrap
= NEXT(query_bootstrap
))
412 if (query_bootstrap
->parent
== bootstrap
&&
413 query_bootstrap
->requestor_port
!= MACH_PORT_NULL
) {
414 mach_port_deallocate(
416 query_bootstrap
->requestor_port
);
417 query_bootstrap
->requestor_port
= MACH_PORT_NULL
;
418 query_bootstrap
->deactivate
= deactivating_bootstraps
;
419 deactivating_bootstraps
= query_bootstrap
;
426 * The list is ordered with the furthest away progeny being
427 * at the front, and concluding with the one we started with.
428 * This allows us to safely deactivate and remove the reference
429 * each holds on their parent without fear of the chain getting
430 * corrupted (because each active parent holds a reference on
431 * itself and that doesn't get removed until we reach its spot
435 bootstrap
= deactivating_bootstraps
;
436 deactivating_bootstraps
= bootstrap
->deactivate
;
438 syslog(LOG_INFO
, "deactivating bootstrap %x", bootstrap
->bootstrap_port
);
440 delete_bootstrap_services(bootstrap
);
442 mach_port_deallocate(mach_task_self(), bootstrap
->bootstrap_port
);
445 mach_port_t previous
;
446 mach_port_request_notification(
448 bootstrap
->bootstrap_port
,
449 MACH_NOTIFY_NO_SENDERS
,
451 bootstrap
->bootstrap_port
,
452 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
455 } while (deactivating_bootstraps
!= NULL
);
459 deallocate_bootstrap(bootstrap_info_t
*bootstrap
)
461 ASSERT(bootstrap
->prev
->next
== bootstrap
);
462 ASSERT(bootstrap
->next
->prev
== bootstrap
);
463 if (--bootstrap
->ref_count
> 0)
466 bootstrap
->prev
->next
= bootstrap
->next
;
467 bootstrap
->next
->prev
= bootstrap
->prev
;
468 deallocate_bootstrap(bootstrap
->parent
);
473 ckmalloc(unsigned nbytes
)
477 if ((cp
= malloc(nbytes
)) == NULL
) {
478 syslog(LOG_EMERG
, "malloc(): %m");