]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/lists.c
35b66b62733a718f614adbc88bdba2a087e5c38d
[apple/system_cmds.git] / mach_init.tproj / lists.c
1 /*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * bootstrap -- fundamental service initiator and port server
27 * Mike DeMoney, NeXT, Inc.
28 * Copyright, 1990. All rights reserved.
29 *
30 * lists.c -- implementation of list handling routines
31 */
32
33 #import <mach/boolean.h>
34 #import <mach/mach_error.h>
35
36 #import <stdlib.h>
37 #import <string.h>
38
39 #import "bootstrap_internal.h"
40 #import "lists.h"
41 #import "error_log.h"
42
43 /*
44 * Exports
45 */
46 bootstrap_info_t bootstraps; /* head of list of all bootstrap ports */
47 server_t servers; /* head of list of all servers */
48 service_t services; /* head of list of all services */
49 unsigned nservices; /* number of services in list */
50
51 #ifndef ASSERT
52 #define ASSERT(p)
53 #endif
54
55 /*
56 * Private macros
57 */
58 #define NEW(type, num) ((type *)ckmalloc(sizeof(type) * num))
59 #define STREQ(a, b) (strcmp(a, b) == 0)
60 #define NELEM(x) (sizeof(x)/sizeof((x)[0]))
61 #define LAST_ELEMENT(x) ((x)[NELEM(x)-1])
62
63 void
64 init_lists(void)
65 {
66 bootstraps.ref_count = 2; /* make sure we never deallocate this one */
67 bootstraps.next = bootstraps.prev = &bootstraps;
68 bootstraps.parent = &bootstraps;
69 servers.next = servers.prev = &servers;
70 services.next = services.prev = &services;
71 nservices = 0;
72 }
73
74 server_t *
75 new_server(
76 bootstrap_info_t *bootstrap,
77 const char *cmd,
78 int uid,
79 servertype_t servertype)
80 {
81 server_t *serverp;
82
83 debug("adding new server \"%s\" with uid %d\n", cmd, uid);
84 serverp = NEW(server_t, 1);
85 if (serverp != NULL) {
86 /* Doubly linked list */
87 servers.prev->next = serverp;
88 serverp->prev = servers.prev;
89 serverp->next = &servers;
90 servers.prev = serverp;
91
92 bootstrap->ref_count++;
93 serverp->bootstrap = bootstrap;
94
95 serverp->pid = NO_PID;
96 serverp->task_port = MACH_PORT_NULL;
97 serverp->uid = uid;
98
99 serverp->port = MACH_PORT_NULL;
100 serverp->servertype = servertype;
101 serverp->activity = 0;
102 serverp->active_services = 0;
103 strncpy(serverp->cmd, cmd, sizeof serverp->cmd);
104 LAST_ELEMENT(serverp->cmd) = '\0';
105 }
106 return serverp;
107 }
108
109 service_t *
110 new_service(
111 bootstrap_info_t *bootstrap,
112 const char *name,
113 mach_port_t service_port,
114 boolean_t isActive,
115 servicetype_t servicetype,
116 server_t *serverp)
117 {
118 service_t *servicep;
119
120 servicep = NEW(service_t, 1);
121 if (servicep != NULL) {
122 /* Doubly linked list */
123 services.prev->next = servicep;
124 servicep->prev = services.prev;
125 servicep->next = &services;
126 services.prev = servicep;
127
128 nservices += 1;
129
130 strncpy(servicep->name, name, sizeof servicep->name);
131 LAST_ELEMENT(servicep->name) = '\0';
132 servicep->servicetype = servicetype;
133 servicep->bootstrap = bootstrap;
134 servicep->port = service_port;
135 servicep->server = serverp;
136 servicep->isActive = isActive;
137 }
138 return servicep;
139 }
140
141 bootstrap_info_t *
142 new_bootstrap(
143 bootstrap_info_t *parent,
144 mach_port_t bootstrap_port,
145 mach_port_t requestor_port)
146 {
147 bootstrap_info_t *bootstrap;
148
149 bootstrap = NEW(bootstrap_info_t, 1);
150 if (bootstrap != NULL) {
151 /* Doubly linked list */
152 bootstraps.prev->next = bootstrap;
153 bootstrap->prev = bootstraps.prev;
154 bootstrap->next = &bootstraps;
155 bootstraps.prev = bootstrap;
156
157 bootstrap->bootstrap_port = bootstrap_port;
158 bootstrap->requestor_port = requestor_port;
159
160 bootstrap->ref_count = 1;
161 bootstrap->parent = parent;
162 parent->ref_count++;
163 }
164 return bootstrap;
165 }
166
167 bootstrap_info_t *
168 lookup_bootstrap_by_port(mach_port_t port)
169 {
170 bootstrap_info_t *bootstrap;
171 bootstrap_info_t *first;
172 server_t *serverp;
173
174 bootstrap = first = FIRST(bootstraps);
175 do {
176 if (bootstrap->bootstrap_port == port)
177 return bootstrap;
178 bootstrap = NEXT(bootstrap);
179 } while (bootstrap != first);
180
181 for ( serverp = FIRST(servers)
182 ; !IS_END(serverp, servers)
183 ; serverp = NEXT(serverp))
184 {
185 if (port == serverp->port)
186 return serverp->bootstrap;
187 }
188 return NULL;
189 }
190
191 bootstrap_info_t *
192 lookup_bootstrap_by_req_port(mach_port_t port)
193 {
194 bootstrap_info_t *bootstrap;
195
196 for ( bootstrap = FIRST(bootstraps)
197 ; !IS_END(bootstrap, bootstraps)
198 ; bootstrap = NEXT(bootstrap))
199 {
200 if (bootstrap->requestor_port == port)
201 return bootstrap;
202 }
203
204 return NULL;
205 }
206
207 service_t *
208 lookup_service_by_name(bootstrap_info_t *bootstrap, name_t name)
209 {
210 service_t *servicep;
211
212 if (bootstrap)
213 do {
214 for ( servicep = FIRST(services)
215 ; !IS_END(servicep, services)
216 ; servicep = NEXT(servicep))
217 {
218 if (!STREQ(name, servicep->name))
219 continue;
220 if (bootstrap && servicep->bootstrap != bootstrap)
221 continue;
222 return servicep;
223 }
224 } while (bootstrap != &bootstraps &&
225 (bootstrap = bootstrap->parent));
226 return NULL;
227 }
228
229 void
230 unlink_service(service_t *servicep)
231 {
232 ASSERT(servicep->prev->next == servicep);
233 ASSERT(servicep->next->prev == servicep);
234 servicep->prev->next = servicep->next;
235 servicep->next->prev = servicep->prev;
236 servicep->prev = servicep->next = servicep; // idempotent
237 }
238
239 void
240 delete_service(service_t *servicep)
241 {
242 unlink_service(servicep);
243 switch (servicep->servicetype) {
244 case REGISTERED:
245 info("Registered service %s deleted", servicep->name);
246 mach_port_deallocate(mach_task_self(), servicep->port);
247 break;
248 case DECLARED:
249 info("Declared service %s now unavailable", servicep->name);
250 mach_port_deallocate(mach_task_self(), servicep->port);
251 mach_port_mod_refs(mach_task_self(), servicep->port,
252 MACH_PORT_RIGHT_RECEIVE, -1);
253 break;
254 default:
255 error("unknown service type %d\n", servicep->servicetype);
256 break;
257 }
258 free(servicep);
259 nservices -= 1;
260 }
261
262 void
263 delete_bootstrap_services(bootstrap_info_t *bootstrap)
264 {
265 server_t *serverp;
266 service_t *servicep;
267 service_t *next;
268
269 for ( servicep = FIRST(services)
270 ; !IS_END(servicep, services)
271 ; servicep = next)
272 {
273 next = NEXT(servicep);
274 if (bootstrap != servicep->bootstrap)
275 continue;
276
277 if (!servicep->isActive || !servicep->server) {
278 delete_service(servicep);
279 continue;
280 }
281
282 serverp = servicep->server;
283 delete_service(servicep);
284 serverp->active_services--;
285 if (!active_server(serverp))
286 delete_server(serverp);
287 }
288 }
289
290 service_t *
291 lookup_service_by_port(mach_port_t port)
292 {
293 service_t *servicep;
294
295 for ( servicep = FIRST(services)
296 ; !IS_END(servicep, services)
297 ; servicep = NEXT(servicep))
298 {
299 if (port == servicep->port)
300 return servicep;
301 }
302 return NULL;
303 }
304
305 service_t *
306 lookup_service_by_server(server_t *serverp)
307 {
308 service_t *servicep;
309
310 for ( servicep = FIRST(services)
311 ; !IS_END(servicep, services)
312 ; servicep = NEXT(servicep))
313 {
314 if (serverp == servicep->server)
315 return servicep;
316 }
317 return NULL;
318 }
319
320 server_t *
321 lookup_server_by_task_port(mach_port_t port)
322 {
323 server_t *serverp;
324
325 for ( serverp = FIRST(servers)
326 ; !IS_END(serverp, servers)
327 ; serverp = NEXT(serverp))
328 {
329 if (port == serverp->task_port)
330 return serverp;
331 }
332 return NULL;
333 }
334
335 server_t *
336 lookup_server_by_port(mach_port_t port)
337 {
338 server_t *serverp;
339
340 for ( serverp = FIRST(servers)
341 ; !IS_END(serverp, servers)
342 ; serverp = NEXT(serverp))
343 {
344 if (port == serverp->port)
345 return serverp;
346 }
347 return NULL;
348 }
349
350 void
351 delete_server(server_t *serverp)
352 {
353 service_t *servicep;
354 service_t *next;
355
356 info("Deleting server %s", serverp->cmd);
357 ASSERT(serverp->prev->next == serverp);
358 ASSERT(serverp->next->prev == serverp);
359 serverp->prev->next = serverp->next;
360 serverp->next->prev = serverp->prev;
361
362 for ( servicep = FIRST(services)
363 ; !IS_END(servicep, services)
364 ; servicep = next)
365 {
366 next = NEXT(servicep);
367 if (serverp == servicep->server)
368 delete_service(servicep);
369 }
370
371 deallocate_bootstrap(serverp->bootstrap);
372
373 if (serverp->port)
374 mach_port_mod_refs(mach_task_self(), serverp->port,
375 MACH_PORT_RIGHT_RECEIVE, -1);
376
377 free(serverp);
378 }
379
380 void
381 deactivate_bootstrap(bootstrap_info_t *bootstrap)
382 {
383 bootstrap_info_t *deactivating_bootstraps;
384 bootstrap_info_t *query_bootstrap;
385 bootstrap_info_t *next_limit;
386 bootstrap_info_t *limit;
387
388 /*
389 * we need to recursively deactivate the whole subset tree below
390 * this point. But we don't want to do real recursion because
391 * we don't have a limit on the depth. So, build up a chain of
392 * active bootstraps anywhere underneath this one.
393 */
394 deactivating_bootstraps = bootstrap;
395 bootstrap->deactivate = NULL;
396 for (next_limit = deactivating_bootstraps, limit = NULL
397 ; deactivating_bootstraps != limit
398 ; limit = next_limit, next_limit = deactivating_bootstraps)
399 {
400 for (bootstrap = deactivating_bootstraps
401 ; bootstrap != limit
402 ; bootstrap = bootstrap->deactivate)
403 {
404 for ( query_bootstrap = FIRST(bootstraps)
405 ; !IS_END(query_bootstrap, bootstraps)
406 ; query_bootstrap = NEXT(query_bootstrap))
407 {
408 if (query_bootstrap->parent == bootstrap &&
409 query_bootstrap->requestor_port != MACH_PORT_NULL) {
410 mach_port_deallocate(
411 mach_task_self(),
412 query_bootstrap->requestor_port);
413 query_bootstrap->requestor_port = MACH_PORT_NULL;
414 query_bootstrap->deactivate = deactivating_bootstraps;
415 deactivating_bootstraps = query_bootstrap;
416 }
417 }
418 }
419 }
420
421 /*
422 * The list is ordered with the furthest away progeny being
423 * at the front, and concluding with the one we started with.
424 * This allows us to safely deactivate and remove the reference
425 * each holds on their parent without fear of the chain getting
426 * corrupted (because each active parent holds a reference on
427 * itself and that doesn't get removed until we reach its spot
428 * in the list).
429 */
430 do {
431 bootstrap = deactivating_bootstraps;
432 deactivating_bootstraps = bootstrap->deactivate;
433
434 info("deactivating bootstrap %x", bootstrap->bootstrap_port);
435
436 delete_bootstrap_services(bootstrap);
437
438 mach_port_deallocate(mach_task_self(), bootstrap->bootstrap_port);
439
440 {
441 mach_port_t previous;
442 mach_port_request_notification(
443 mach_task_self(),
444 bootstrap->bootstrap_port,
445 MACH_NOTIFY_NO_SENDERS,
446 1,
447 bootstrap->bootstrap_port,
448 MACH_MSG_TYPE_MAKE_SEND_ONCE,
449 &previous);
450 }
451 } while (deactivating_bootstraps != NULL);
452 }
453
454 void
455 deallocate_bootstrap(bootstrap_info_t *bootstrap)
456 {
457 ASSERT(bootstrap->prev->next == bootstrap);
458 ASSERT(bootstrap->next->prev == bootstrap);
459 if (--bootstrap->ref_count > 0)
460 return;
461
462 bootstrap->prev->next = bootstrap->next;
463 bootstrap->next->prev = bootstrap->prev;
464 deallocate_bootstrap(bootstrap->parent);
465 free(bootstrap);
466 }
467
468 void *
469 ckmalloc(unsigned nbytes)
470 {
471 void *cp;
472
473 if ((cp = malloc(nbytes)) == NULL)
474 fatal("Out of memory");
475 return cp;
476 }
477
478