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