]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/lists.c
92bb29ccf7306a539f6c0366600b2fe0682acb8e
[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 case SELF:
254 error("Self service %s now unavailable", servicep->name);
255 break;
256 default:
257 error("unknown service type %d\n", servicep->servicetype);
258 break;
259 }
260 free(servicep);
261 nservices -= 1;
262 }
263
264 void
265 delete_bootstrap_services(bootstrap_info_t *bootstrap)
266 {
267 server_t *serverp;
268 service_t *servicep;
269 service_t *next;
270
271 for ( servicep = FIRST(services)
272 ; !IS_END(servicep, services)
273 ; servicep = next)
274 {
275 next = NEXT(servicep);
276 if (bootstrap != servicep->bootstrap)
277 continue;
278
279 if (!servicep->isActive || !servicep->server) {
280 delete_service(servicep);
281 continue;
282 }
283
284 serverp = servicep->server;
285 delete_service(servicep);
286 serverp->active_services--;
287 if (!active_server(serverp))
288 delete_server(serverp);
289 }
290 }
291
292 service_t *
293 lookup_service_by_port(mach_port_t port)
294 {
295 service_t *servicep;
296
297 for ( servicep = FIRST(services)
298 ; !IS_END(servicep, services)
299 ; servicep = NEXT(servicep))
300 {
301 if (port == servicep->port)
302 return servicep;
303 }
304 return NULL;
305 }
306
307 service_t *
308 lookup_service_by_server(server_t *serverp)
309 {
310 service_t *servicep;
311
312 for ( servicep = FIRST(services)
313 ; !IS_END(servicep, services)
314 ; servicep = NEXT(servicep))
315 {
316 if (serverp == servicep->server)
317 return servicep;
318 }
319 return NULL;
320 }
321
322 server_t *
323 lookup_server_by_task_port(mach_port_t port)
324 {
325 server_t *serverp;
326
327 for ( serverp = FIRST(servers)
328 ; !IS_END(serverp, servers)
329 ; serverp = NEXT(serverp))
330 {
331 if (port == serverp->task_port)
332 return serverp;
333 }
334 return NULL;
335 }
336
337 server_t *
338 lookup_server_by_port(mach_port_t port)
339 {
340 server_t *serverp;
341
342 for ( serverp = FIRST(servers)
343 ; !IS_END(serverp, servers)
344 ; serverp = NEXT(serverp))
345 {
346 if (port == serverp->port)
347 return serverp;
348 }
349 return NULL;
350 }
351
352 void
353 delete_server(server_t *serverp)
354 {
355 service_t *servicep;
356 service_t *next;
357
358 info("Deleting server %s", serverp->cmd);
359 ASSERT(serverp->prev->next == serverp);
360 ASSERT(serverp->next->prev == serverp);
361 serverp->prev->next = serverp->next;
362 serverp->next->prev = serverp->prev;
363
364 for ( servicep = FIRST(services)
365 ; !IS_END(servicep, services)
366 ; servicep = next)
367 {
368 next = NEXT(servicep);
369 if (serverp == servicep->server)
370 delete_service(servicep);
371 }
372
373 deallocate_bootstrap(serverp->bootstrap);
374
375 if (serverp->port)
376 mach_port_mod_refs(mach_task_self(), serverp->port,
377 MACH_PORT_RIGHT_RECEIVE, -1);
378
379 free(serverp);
380 }
381
382 void
383 deactivate_bootstrap(bootstrap_info_t *bootstrap)
384 {
385 bootstrap_info_t *deactivating_bootstraps;
386 bootstrap_info_t *query_bootstrap;
387 bootstrap_info_t *next_limit;
388 bootstrap_info_t *limit;
389
390 /*
391 * we need to recursively deactivate the whole subset tree below
392 * this point. But we don't want to do real recursion because
393 * we don't have a limit on the depth. So, build up a chain of
394 * active bootstraps anywhere underneath this one.
395 */
396 deactivating_bootstraps = bootstrap;
397 bootstrap->deactivate = NULL;
398 for (next_limit = deactivating_bootstraps, limit = NULL
399 ; deactivating_bootstraps != limit
400 ; limit = next_limit, next_limit = deactivating_bootstraps)
401 {
402 for (bootstrap = deactivating_bootstraps
403 ; bootstrap != limit
404 ; bootstrap = bootstrap->deactivate)
405 {
406 for ( query_bootstrap = FIRST(bootstraps)
407 ; !IS_END(query_bootstrap, bootstraps)
408 ; query_bootstrap = NEXT(query_bootstrap))
409 {
410 if (query_bootstrap->parent == bootstrap &&
411 query_bootstrap->requestor_port != MACH_PORT_NULL) {
412 mach_port_deallocate(
413 mach_task_self(),
414 query_bootstrap->requestor_port);
415 query_bootstrap->requestor_port = MACH_PORT_NULL;
416 query_bootstrap->deactivate = deactivating_bootstraps;
417 deactivating_bootstraps = query_bootstrap;
418 }
419 }
420 }
421 }
422
423 /*
424 * The list is ordered with the furthest away progeny being
425 * at the front, and concluding with the one we started with.
426 * This allows us to safely deactivate and remove the reference
427 * each holds on their parent without fear of the chain getting
428 * corrupted (because each active parent holds a reference on
429 * itself and that doesn't get removed until we reach its spot
430 * in the list).
431 */
432 do {
433 bootstrap = deactivating_bootstraps;
434 deactivating_bootstraps = bootstrap->deactivate;
435
436 info("deactivating bootstrap %x", bootstrap->bootstrap_port);
437
438 delete_bootstrap_services(bootstrap);
439
440 mach_port_deallocate(mach_task_self(), bootstrap->bootstrap_port);
441
442 {
443 mach_port_t previous;
444 mach_port_request_notification(
445 mach_task_self(),
446 bootstrap->bootstrap_port,
447 MACH_NOTIFY_NO_SENDERS,
448 1,
449 bootstrap->bootstrap_port,
450 MACH_MSG_TYPE_MAKE_SEND_ONCE,
451 &previous);
452 }
453 } while (deactivating_bootstraps != NULL);
454 }
455
456 void
457 deallocate_bootstrap(bootstrap_info_t *bootstrap)
458 {
459 ASSERT(bootstrap->prev->next == bootstrap);
460 ASSERT(bootstrap->next->prev == bootstrap);
461 if (--bootstrap->ref_count > 0)
462 return;
463
464 bootstrap->prev->next = bootstrap->next;
465 bootstrap->next->prev = bootstrap->prev;
466 deallocate_bootstrap(bootstrap->parent);
467 free(bootstrap);
468 }
469
470 void *
471 ckmalloc(unsigned nbytes)
472 {
473 void *cp;
474
475 if ((cp = malloc(nbytes)) == NULL)
476 fatal("Out of memory");
477 return cp;
478 }
479
480