]> git.saurik.com Git - apple/system_cmds.git/blob - mach_init.tproj/bootstrap.c
system_cmds-175.tar.gz
[apple/system_cmds.git] / mach_init.tproj / bootstrap.c
1 /*
2 * Copyright (c) 1999 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 * bootstrap.c -- implementation of bootstrap main service loop
30 */
31
32 /*
33 * Imports
34 */
35 #import <mach/mach.h>
36 #import <mach/boolean.h>
37 #import <mach/message.h>
38 #import <mach/notify.h>
39 #import <mach/mig_errors.h>
40 #include <mach/mach_traps.h>
41 #include <mach/mach_interface.h>
42 #include <mach/bootstrap.h>
43 #include <mach/host_info.h>
44 #include <mach/mach_host.h>
45 #include <mach/exception.h>
46
47 #import <sys/ioctl.h>
48 #import <string.h>
49 #import <ctype.h>
50 #import <stdio.h>
51 #import <libc.h>
52
53 #include "bootstrap.h"
54
55 #import "bootstrap_internal.h"
56 #import "lists.h"
57 #import "error_log.h"
58 #import "parser.h"
59
60 /* Mig should produce a declaration for this, but doesn't */
61 extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
62
63 /*
64 * Exports
65 */
66 const char *program_name; /* our name for error messages */
67
68 #ifndef CONF_FILE
69 #define CONF_FILE "/etc/bootstrap.conf" /* default config file */
70 #endif CONF_FILE
71
72 const char *conf_file = CONF_FILE;
73
74 const unsigned BOOTSTRAP_REPLY_TIMEOUT = 10 * 1000; // 10 sec reply timeout
75 #ifdef notyet
76 port_all_t backup_port;
77 #endif /* notyet */
78 /*
79 * Last resort configuration
80 *
81 * If we can't find a /etc/bootstrap.conf, we use this configuration.
82 * The services defined here are compatable with the old mach port stuff,
83 * and of course, the names for these services should not be modified without
84 * modifying mach_init in libc.
85 */
86 const char *default_conf =
87 "init \"/sbin/init\";"
88 "services NetMessage;";
89
90 mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
91 boolean_t forward_ok = FALSE;
92 boolean_t debugging = FALSE;
93 boolean_t register_self = FALSE;
94 int init_priority = BASEPRI_USER;
95 char *register_name = NULL;
96 mach_port_t bootstrap_master_device_port; /* local name */
97 mach_port_t bootstrap_master_host_port; /* local name */
98 mach_port_t bootstrap_notification_port; /* local name */
99 mach_port_t security_port;
100 mach_port_t root_ledger_wired;
101 mach_port_t root_ledger_paged;
102 task_port_t bootstrap_self;
103
104 #ifndef ASSERT
105 #define ASSERT(p)
106 #endif
107
108 /*
109 * Private macros
110 */
111 #define NELEM(x) (sizeof(x)/sizeof(x[0]))
112 #define END_OF(x) (&(x)[NELEM(x)])
113 #define streq(a,b) (strcmp(a,b) == 0)
114
115 /*
116 * Private declarations
117 */
118 static void add_init_arg(const char *arg);
119 static void wait_for_go(mach_port_t init_notify_port);
120 static void init_ports(void);
121 static void start_server(server_t *serverp);
122 static void unblock_init(task_port_t task, mach_port_t newBootstrap);
123 static void exec_server(server_t *serverp);
124 static char **argvize(const char *string);
125 static void server_loop(void);
126 static void msg_destroy(mach_msg_header_t *m);
127
128 /*
129 * Private ports we hold receive rights for. We also hold receive rights
130 * for all the privileged ports. Those are maintained in the server
131 * structs.
132 */
133 mach_port_t bootstrap_port_set;
134 mach_port_t notify_port;
135
136 static int init_pid;
137 static int running_servers;
138 static char init_args[BOOTSTRAP_MAX_CMD_LEN];
139
140 void _myExit(int arg)
141 {
142 exit(arg);
143 }
144
145 /* It was a bozo who made main return a value! Civil disobedience, here. */
146 void
147 main(int argc, const char * const argv[])
148 {
149 const char *argp;
150 char c;
151 server_t *init_serverp;
152 server_t *serverp;
153 mach_port_t init_notify_port;
154 kern_return_t result;
155 int pid;
156 int force_fork = FALSE;
157 mach_port_t prev_port;
158 #if defined(__APPLE__)
159 extern void exit(int);
160
161 /* signal (SIGUSR2, _myExit); */
162 #endif
163
164 /* Initialize error handling */
165 program_name = rindex(*argv, '/');
166 if (program_name)
167 program_name++;
168 else
169 program_name = *argv;
170 argv++; argc--;
171
172 init_pid = getpid();
173 init_errlog(init_pid == 1);
174
175 /*
176 * Get master host and device ports
177 */
178 #if 0
179 result = bootstrap_ports(bootstrap_port,
180 &bootstrap_master_host_port,
181 &bootstrap_master_device_port,
182 &root_ledger_wired,
183 &root_ledger_paged,
184 &security_port);
185 if (result != KERN_SUCCESS) {
186 printf("bootstrap_ports failed \n");
187 kern_error(result, "bootstrap_ports");
188 }
189 #endif /* 0 */
190 /*
191 * This task will become the bootstrap task.
192 */
193 bootstrap_self = mach_task_self();
194
195 /* Initialize globals */
196 init_lists();
197
198 /* Parse command line args */
199 while (argc > 0 && **argv == '-') {
200 boolean_t init_arg = FALSE;
201 argp = *argv++ + 1; argc--;
202 while (*argp) {
203 switch (c = *argp++) {
204 case 'd':
205 debugging = TRUE;
206 break;
207 case 'D':
208 debugging = FALSE;
209 break;
210 case 'F':
211 force_fork = TRUE;
212 break;
213 case 'f':
214 if (argc > 0) {
215 conf_file = *argv++; argc--;
216 } else
217 fatal("-f requires config file name");
218 break;
219 case '-':
220 init_arg = TRUE;
221 break;
222 case 'r':
223 register_self = forward_ok = TRUE;
224 if (argc > 0) {
225 register_name = *argv++; argc--;
226 } else
227 fatal("-r requires name");
228 break;
229 default:
230 init_arg = TRUE;
231 break;
232 }
233 }
234 if (init_arg) {
235 add_init_arg(argv[-1]);
236 goto copyargs;
237 }
238 }
239 copyargs:
240 while (argc != 0) {
241 argc--;
242 add_init_arg(*argv++);
243 }
244
245 log("Started");
246
247 /* Parse the config file */
248 init_config();
249
250 /* set_default_policy(bootstrap_master_host_port); */
251
252 /*
253 * If we have to run init as pid 1, use notify port to
254 * synchronize init and bootstrap
255 */
256 if ((init_serverp = find_init_server()) != NULL) {
257 if (init_pid != 1 && ! debugging)
258 fatal("Can't start init server if not pid 1");
259 result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
260 &init_notify_port);
261 if (result != KERN_SUCCESS)
262 kern_fatal(result, "mach_port_allocate");
263 result = mach_port_insert_right(mach_task_self(), init_notify_port, init_notify_port, MACH_MSG_TYPE_MAKE_SEND);
264 if (result != KERN_SUCCESS)
265 kern_fatal(result, "mach_port_insert_right");
266 task_set_bootstrap_port(bootstrap_self, init_notify_port);
267 if (result != KERN_SUCCESS)
268 kern_fatal(result, "task_set_bootstrap_port");
269 /*
270 * XXX restart the service if it dies?
271 */
272 result = mach_port_request_notification(mach_task_self(),
273 mach_task_self(),
274 MACH_NOTIFY_DEAD_NAME,
275 0,
276 init_notify_port,
277 MACH_MSG_TYPE_MAKE_SEND_ONCE,
278 &prev_port);
279 if (result != KERN_SUCCESS)
280 kern_fatal(result, "mach_port_request_notification");
281 debug("Set port %d for parent proc notify port",
282 init_notify_port);
283 } else if (init_args[0] != '\0')
284 fatal("Extraneous command line arguments");
285
286 /* Fork if either not debugging or running /etc/init */
287 if (force_fork || !debugging || init_serverp != NULL) {
288 pid = fork();
289 if (pid < 0)
290 unix_fatal("fork");
291 } else
292 pid = 0;
293
294 /* Bootstrap service runs in child (if there is one) */
295 if (pid == 0) { /* CHILD */
296 /*
297 * If we're initiated by pid 1, we shouldn't get ever get
298 * killed; designate ourselves as an "init process".
299 *
300 * This should go away with new signal stuff!
301 */
302 if (init_pid == 1)
303 init_process();
304
305 /* Create declared service ports, our service port, etc */
306 init_ports();
307
308 /* Kick off all server processes */
309 for ( serverp = FIRST(servers)
310 ; !IS_END(serverp, servers)
311 ; serverp = NEXT(serverp))
312 start_server(serverp);
313
314 /*
315 * If our priority's to be changed, set it up here.
316 */
317 #ifdef notyet
318 if (init_priority >= 0) {
319 result = task_priority(mach_task_self(), init_priority,
320 TRUE);
321 if (result != KERN_SUCCESS)
322 kern_error(result, "task_priority %d",
323 init_priority);
324 }
325 #endif /* notyet */
326 /* Process bootstrap service requests */
327 server_loop(); /* Should never return */
328 exit(1);
329 }
330
331 /* PARENT */
332 if (init_serverp != NULL) {
333 int i;
334
335 strncat(init_serverp->cmd,
336 init_args,
337 sizeof(init_serverp->cmd));
338 /*
339 * Wait, then either exec /etc/init or exit
340 * (which panics the system)
341 */
342 for (i = 3; i; i--)
343 close(i);
344 wait_for_go(init_notify_port);
345 exec_server(init_serverp);
346 exit(1);
347 }
348 exit(0);
349 }
350
351 static void
352 add_init_arg(const char *arg)
353 {
354 strncat(init_args, " ", sizeof(init_args));
355 strncat(init_args, arg, sizeof(init_args));
356 }
357
358 static void
359 wait_for_go(mach_port_t init_notify_port)
360 {
361 struct {
362 mach_msg_header_t hdr;
363 mach_msg_trailer_t trailer;
364 } init_go_msg;
365 kern_return_t result;
366
367 /*
368 * For now, we just blindly wait until we receive a message or
369 * timeout. We don't expect any notifications, and if we get one,
370 * it probably means something dire has happened; so we might as
371 * well give a shot at letting init run.
372 */
373 result = mach_msg(&init_go_msg.hdr, MACH_RCV_MSG, 0, sizeof(init_go_msg), init_notify_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
374 if (result != KERN_SUCCESS) {
375 kern_error(result, "mach_msg(receive) failed in wait_for_go");
376 }
377 result = task_set_bootstrap_port(mach_task_self(), init_go_msg.hdr.msgh_remote_port);
378 if (result != KERN_SUCCESS) {
379 kern_error(result, "task_get_bootstrap_port()");
380 }
381 }
382
383 static void
384 init_ports(void)
385 {
386 kern_return_t result;
387 service_t *servicep;
388 mach_port_name_t previous;
389 mach_port_t pport;
390
391 /*
392 * This task will become the bootstrap task.
393 */
394 bootstrap_self = mach_task_self();
395
396 /* get inherited bootstrap port */
397 result = task_get_bootstrap_port(bootstrap_self,
398 &inherited_bootstrap_port);
399 if (result != KERN_SUCCESS)
400 kern_fatal(result, "task_get_bootstrap_port");
401
402 /* We set this explicitly as we start each child */
403 task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
404 if (inherited_bootstrap_port == MACH_PORT_NULL)
405 forward_ok = FALSE;
406
407 /* Create port set that server loop listens to */
408 result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_PORT_SET,
409 &bootstrap_port_set);
410 if (result != KERN_SUCCESS)
411 kern_fatal(result, "port_set_allocate");
412 /* Create notify port and add to server port set */
413 result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
414 &notify_port);
415 if (result != KERN_SUCCESS)
416 kern_fatal(result, "mach_port_allocate");
417
418 result = mach_port_request_notification(bootstrap_self,
419 bootstrap_self,
420 MACH_NOTIFY_DEAD_NAME,
421 0,
422 notify_port,
423 MACH_MSG_TYPE_MAKE_SEND_ONCE,
424 &pport);
425 if (result != KERN_SUCCESS)
426 kern_fatal(result, "task_set_notify_port");
427
428 result = mach_port_move_member(bootstrap_self,
429 notify_port,
430 bootstrap_port_set);
431 if (result != KERN_SUCCESS)
432 kern_fatal(result, "mach_port_move_member");
433
434 /* Create "self" port and add to server port set */
435 result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
436 &bootstraps.bootstrap_port);
437 if (result != KERN_SUCCESS)
438 kern_fatal(result, "mach_port_allocate");
439 result = mach_port_insert_right(mach_task_self(), bootstraps.bootstrap_port, bootstraps.bootstrap_port, MACH_MSG_TYPE_MAKE_SEND);
440 if (result != KERN_SUCCESS)
441 kern_fatal(result, "mach_port_insert_right");
442 result = mach_port_move_member(bootstrap_self,
443 bootstraps.bootstrap_port,
444 bootstrap_port_set);
445 if (result != KERN_SUCCESS)
446 kern_fatal(result, "mach_port_move_member");
447 #ifdef notyet
448 /* register "self" port with anscestor */
449 if (register_self && forward_ok) {
450 result = bootstrap_register(inherited_bootstrap_port, register_name, bootstraps.bootstrap_port);
451 if (result != KERN_SUCCESS)
452 kern_fatal(result, "register self");
453 }
454 #endif /* notyet*/
455 /*
456 * Allocate service ports for declared services.
457 */
458 for ( servicep = FIRST(services)
459 ; ! IS_END(servicep, services)
460 ; servicep = NEXT(servicep))
461 {
462 switch (servicep->servicetype) {
463 case DECLARED:
464 result = mach_port_allocate(bootstrap_self, MACH_PORT_RIGHT_RECEIVE,
465 &(servicep->port));
466 if (result != KERN_SUCCESS)
467 kern_fatal(result, "mach_port_allocate");
468 result = mach_port_insert_right(bootstrap_self, servicep->port, servicep->port, MACH_MSG_TYPE_MAKE_SEND);
469 if (result != KERN_SUCCESS)
470 kern_fatal(result, "mach_port_insert_right");
471 debug("Declared port %d for service %s",
472 servicep->port,
473 servicep->name);
474 #ifdef notyet
475 result = port_set_backup(task_self(),
476 servicep->port,
477 backup_port,
478 &previous);
479 if (result != KERN_SUCCESS)
480 kern_fatal(result, "port_set_backup");
481 #endif /* notyet */
482 break;
483 case SELF:
484 servicep->port = bootstraps.bootstrap_port;
485 servicep->server = new_server(MACHINIT,
486 program_name, init_priority);
487 info("Set port %d for self port",
488 bootstraps.bootstrap_port);
489 break;
490 case REGISTERED:
491 fatal("Can't allocate REGISTERED port!?!");
492 break;
493 }
494 }
495 }
496
497 static void
498 start_server(server_t *serverp)
499 {
500 kern_return_t result;
501 mach_port_t old_port;
502 task_port_t init_task;
503 int pid;
504
505 /* get rid of any old server port (this might be a restart) */
506 old_port = serverp->port;
507 serverp->port = MACH_PORT_NULL;
508 if (old_port != MACH_PORT_NULL) {
509 msg_destroy_port(old_port);
510 }
511 /* Allocate privileged port for requests from service */
512 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE ,&serverp->port);
513 info("Allocating port %d for server %s", serverp->port, serverp->cmd);
514 if (result != KERN_SUCCESS)
515 kern_fatal(result, "port_allocate");
516
517 result = mach_port_insert_right(mach_task_self(), serverp->port, serverp->port, MACH_MSG_TYPE_MAKE_SEND);
518 if (result != KERN_SUCCESS)
519 kern_fatal(result, "mach_port_insert_right");
520 /* Add privileged server port to bootstrap port set */
521 result = mach_port_move_member(mach_task_self(),
522 serverp->port,
523 bootstrap_port_set);
524 if (result != KERN_SUCCESS)
525 kern_fatal(result, "mach_port_move_member");
526
527 /*
528 * Do what's appropriate to get bootstrap port setup in server task
529 */
530 switch (serverp->servertype) {
531 case ETCINIT:
532 /*
533 * This is pid 1 init program -- need to punch stuff
534 * back into pid 1 task rather than create a new task
535 */
536 result = task_for_pid(mach_task_self(), init_pid, &init_task);
537 if (result != KERN_SUCCESS)
538 kern_fatal(result, "task_for_pid");
539 serverp->task_port = init_task;
540 unblock_init(init_task, serverp->port);
541 break;
542
543 case MACHINIT:
544 break;
545
546 case SERVER:
547 case RESTARTABLE:
548 /* Give trusted service a unique bootstrap port */
549 result = task_set_bootstrap_port(mach_task_self(), serverp->port);
550 if (result != KERN_SUCCESS)
551 kern_fatal(result, "task_set_bootstrap_port");
552
553 pid = fork();
554 if (pid < 0)
555 unix_error("fork");
556 else if (pid == 0) { /* CHILD */
557 exec_server(serverp);
558 exit(1);
559 } else { /* PARENT */
560 result = task_set_bootstrap_port(mach_task_self(),
561 MACH_PORT_NULL);
562 if (result != KERN_SUCCESS)
563 kern_fatal(result, "task_set_bootstrap_port");
564
565 result = task_for_pid(mach_task_self(),
566 pid,
567 &serverp->task_port);
568 if (result != KERN_SUCCESS)
569 kern_fatal(result, "getting server task port");
570 running_servers += 1;
571 }
572 break;
573 }
574 }
575
576 static void
577 unblock_init(task_port_t task, mach_port_t newBootstrap)
578 {
579 mach_msg_header_t init_go_msg;
580 kern_return_t result;
581
582 /*
583 * Proc 1 is blocked in a msg_receive on its notify port, this lets
584 * it continue, and we hand off its new bootstrap port
585 */
586 init_go_msg.msgh_remote_port = inherited_bootstrap_port;
587 init_go_msg.msgh_local_port = newBootstrap;
588 init_go_msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND);
589 result = mach_msg(&init_go_msg, MACH_SEND_MSG, sizeof(init_go_msg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
590 if (result != KERN_SUCCESS)
591 kern_fatal(result, "unblock_init mach_msg(send) failed");
592 debug("sent go message");
593 }
594
595 static void
596 exec_server(server_t *serverp)
597 {
598 int nfds, fd;
599 char **argv;
600
601 /*
602 * Setup environment for server, someday this should be Mach stuff
603 * rather than Unix crud
604 */
605 log("Initiating server %s [pid %d]", serverp->cmd, getpid());
606 argv = argvize(serverp->cmd);
607 nfds = getdtablesize();
608
609 #ifdef notyet
610 /*
611 * If our priority's to be changed, set it up here.
612 */
613 if (serverp->priority >= 0) {
614 kern_return_t result;
615 result = task_priority(mach_task_self(), serverp->priority,
616 TRUE);
617 if (result != KERN_SUCCESS)
618 kern_error(result, "task_priority %d",
619 serverp->priority);
620 }
621 #endif /* notyet */
622 close_errlog();
623
624 /*
625 * Mark this process as an "init process" so that it won't be
626 * blown away by init when it starts up (or changes states).
627 */
628 if (init_pid == 1) {
629 debug("marking process %s as init_process\n", argv[0]);
630 init_process();
631 }
632
633 for (fd = debugging ? 3 : 0; fd < nfds; fd++)
634 close(fd);
635 fd = open("/dev/tty", O_RDONLY);
636 if (fd >= 0) {
637 ioctl(fd, TIOCNOTTY, 0);
638 close(fd);
639 }
640
641 execv(argv[0], argv);
642 unix_error("Can't exec %s", argv[0]);
643 }
644
645 static char **
646 argvize(const char *string)
647 {
648 static char *argv[100], args[1000];
649 const char *cp;
650 char *argp, term;
651 int nargs;
652
653 /*
654 * Convert a command line into an argv for execv
655 */
656 nargs = 0;
657 argp = args;
658
659 for (cp = string; *cp;) {
660 while (isspace(*cp))
661 cp++;
662 term = (*cp == '"') ? *cp++ : '\0';
663 if (nargs < NELEM(argv))
664 argv[nargs++] = argp;
665 while (*cp && (term ? *cp != term : !isspace(*cp))
666 && argp < END_OF(args)) {
667 if (*cp == '\\')
668 cp++;
669 *argp++ = *cp;
670 if (*cp)
671 cp++;
672 }
673 *argp++ = '\0';
674 }
675 argv[nargs] = NULL;
676 return argv;
677 }
678
679 /*
680 * server_loop -- pick requests off our service port and process them
681 * Also handles notifications
682 */
683 #define bootstrapMaxRequestSize 1024
684 #define bootstrapMaxReplySize 1024
685
686 static void
687 server_loop(void)
688 {
689 bootstrap_info_t *bootstrap;
690 service_t *servicep;
691 server_t *serverp;
692 kern_return_t result;
693 mach_port_name_t previous;
694 mach_port_array_t array;
695 mach_msg_type_number_t count;
696 int i;
697
698 union {
699 mach_msg_header_t hdr;
700 char body[bootstrapMaxRequestSize];
701 } msg;
702 union {
703 mach_msg_header_t hdr;
704 #ifdef notyet
705 death_pill_t death;
706 #endif /* notyet */
707 char body[bootstrapMaxReplySize];
708 } reply;
709
710 for (;;) {
711 memset(&msg, 0, sizeof(msg));
712 result = mach_msg_overwrite_trap(&msg.hdr, MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_TIMEOUT, 0, sizeof(msg), bootstrap_port_set, 500, MACH_PORT_NULL, MACH_MSG_NULL, 0);
713 if (result != KERN_SUCCESS) {
714 if (result != MACH_RCV_TIMED_OUT) {
715 kern_error(result, "server_loop: msg_receive()");
716 }
717 continue;
718 }
719
720 #if DEBUG
721 debug("received message on port %d\n", msg.hdr.msgh_local_port);
722 #endif DEBUG
723
724 /*
725 * Pick off notification messages
726 */
727 if (msg.hdr.msgh_local_port == notify_port) {
728 mach_port_name_t np;
729
730 switch (msg.hdr.msgh_id) {
731 case MACH_NOTIFY_DEAD_NAME:
732 np = ((mach_dead_name_notification_t *)&msg)->not_port;
733 #if DEBUG
734 info("Notified dead name %d", np);
735 #endif DEBUG
736 if (np == inherited_bootstrap_port)
737 {
738 inherited_bootstrap_port = MACH_PORT_NULL;
739 forward_ok = FALSE;
740 break;
741 }
742
743 /*
744 * This may be notification that the task_port associated
745 * with a task we've launched has been deleted. This
746 * happens only when the server dies.
747 */
748 serverp = lookup_server_by_task_port(np);
749 if (serverp != NULL) {
750 info("Notified that server %s died\n", serverp->cmd);
751 if (running_servers <= 0) {
752 /* This "can't" happen */
753 running_servers = 0;
754 error("task count error");
755 } else {
756 running_servers -= 1;
757 log("server %s died",
758 serverp != NULL ? serverp->cmd : "Unknown");
759 if (serverp != NULL) {
760 /*
761 * FIXME: need to control execs
762 * when server fails immediately
763 */
764 if ( serverp->servertype == RESTARTABLE
765 /*
766 && haven't started this recently */)
767 start_server(serverp);
768 }
769 }
770 break;
771 }
772
773 /*
774 * Check to see if a subset requestor port was deleted.
775 */
776 while (bootstrap = lookup_bootstrap_req_by_port(np)) {
777 info("notified that requestor of subset %d died",
778 bootstrap->bootstrap_port);
779 delete_bootstrap(bootstrap);
780 }
781
782 /*
783 * Check to see if a defined service has gone
784 * away.
785 */
786 while (servicep = lookup_service_by_port(np)) {
787 /*
788 * Port gone, server died.
789 */
790 debug("Received destroyed notification for service %s "
791 "on bootstrap port %d\n",
792 servicep->name, servicep->bootstrap);
793 if (servicep->servicetype == REGISTERED) {
794 debug("Service %s failed - deallocate", servicep->name);
795 mach_port_deallocate(mach_task_self(),np);
796 mach_port_deallocate(mach_task_self(),servicep->port);
797 delete_service(servicep);
798 } else {
799 /*
800 * Allocate a new, backed-up port for this service.
801 */
802 log("Service %s failed - re-initialize",
803 servicep->name);
804 msg_destroy_port(servicep->port);
805 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &servicep->port);
806 if (result != KERN_SUCCESS)
807 kern_fatal(result, "port_allocate");
808 result = mach_port_insert_right(bootstrap_self, servicep->port, servicep->port, MACH_MSG_TYPE_MAKE_SEND);
809 if (result != KERN_SUCCESS)
810 kern_fatal(result, "mach_port_insert_right");
811 #if 0
812 result = port_set_backup(mach_task_self(),
813 servicep->port,
814 backup_port,
815 &previous);
816 if (result != KERN_SUCCESS)
817 kern_fatal(result, "port_set_backup");
818 #endif
819 servicep->isActive = FALSE;
820 }
821 }
822 break;
823 default:
824 error("Unexpected notification: %d", msg.hdr.msgh_id);
825 break;
826 }
827 }
828 #if 0
829 else if (msg.hdr.msg_local_port == backup_port) {
830 notification_t *not = (notification_t *) &msg.hdr;
831 mach_port_name_t np = not->notify_port;
832
833 /*
834 * Port sent back to us, server died.
835 */
836 info("port %d returned via backup", np);
837 servicep = lookup_service_by_port(np);
838 if (servicep != NULL) {
839 debug("Received %s notification for service %s",
840 not->notify_header.msg_id
841 == NOTIFY_PORT_DESTROYED
842 ? "destroyed" : "receive rights",
843 servicep->name);
844 log("Service %s failed - port backed-up", servicep->name);
845 ASSERT(canReceive(servicep->port));
846 servicep->isActive = FALSE;
847 result = port_set_backup(mach_task_self(),
848 servicep->port,
849 backup_port,
850 &previous);
851 if (result != KERN_SUCCESS)
852 kern_fatal(result, "port_set_backup");
853 } else
854 msg_destroy_port(np);
855 }
856 #endif
857 else
858 { /* must be a service request */
859 bootstrap_server(&msg.hdr, &reply.hdr);
860 #ifdef DEBUG
861 debug("Handled request.");
862 #endif DEBUG
863 reply.hdr.msgh_local_port = MACH_PORT_NULL;
864 result = mach_msg(&reply.hdr, MACH_SEND_MSG|MACH_SEND_TIMEOUT, reply.hdr.msgh_size, 0, MACH_PORT_NULL,
865 BOOTSTRAP_REPLY_TIMEOUT, MACH_PORT_NULL);
866 #ifdef DEBUG
867 debug("Reply sent.");
868 #endif DEBUG
869 if (result != MACH_MSG_SUCCESS) {
870 kern_error(result, "msg_send");
871 }
872 }
873 /* deallocate uninteresting ports received in message */
874 msg_destroy(&msg.hdr);
875 }
876 }
877
878 /*
879 * msg_destroy -- walk through a received message and deallocate any
880 * useless ports or out-of-line memory
881 */
882 static void
883 msg_destroy(mach_msg_header_t *m)
884 {
885 #ifdef notyet /* [ */
886 msg_type_t *mtp;
887 msg_type_long_t *mtlp;
888 void *dp;
889 unsigned type, size, num;
890 boolean_t inlne;
891 mach_port_t *pp;
892 kern_return_t result;
893
894 msg_destroy_port(m->msg_remote_port);
895 for ( mtp = (msg_type_t *)(m + 1)
896 ; (unsigned)mtp - (unsigned)m < m->msg_size
897 ;)
898 {
899 inlne = mtp->msg_type_inline;
900 if (mtp->msg_type_longform) {
901 mtlp = (msg_type_long_t *)mtp;
902 type = mtlp->msg_type_long_name;
903 size = mtlp->msg_type_long_size;
904 num = mtlp->msg_type_long_number;
905 dp = (void *)(mtlp + 1);
906 } else {
907 type = mtp->msg_type_name;
908 size = mtp->msg_type_size;
909 num = mtp->msg_type_number;
910 dp = (void *)(mtp + 1);
911 }
912 if (inlne)
913 mtp = (msg_type_t *)(dp + num * (size/BITS_PER_BYTE));
914 else {
915 mtp = (msg_type_t *)(dp + sizeof(void *));
916 dp = *(char **)dp;
917 }
918 if (MSG_TYPE_PORT_ANY(type)) {
919 for (pp = (mach_port_t *)dp; num-- > 0; pp++)
920 msg_destroy_port(*pp);
921 }
922 if ( ! inlne ) {
923 result = vm_deallocate(mach_task_self(), (vm_address_t)dp,
924 num * (size/BITS_PER_BYTE));
925 if (result != KERN_SUCCESS)
926 kern_error(result,
927 "vm_deallocate: msg_destroy");
928 }
929 }
930 #endif /* notyet ] */
931 }
932
933 /*
934 * msg_destroy_port -- deallocate port if it's not important to bootstrap
935 * Bad name, this is used for things other than msg_destroy.
936 */
937 void
938 msg_destroy_port(mach_port_t p)
939 {
940 if ( p == MACH_PORT_NULL
941 || p == mach_task_self()
942 || p == mig_get_reply_port()
943 || p == bootstrap_port_set
944 || p == inherited_bootstrap_port
945 || lookup_service_by_port(p)
946 || lookup_server_by_port(p)
947 || lookup_bootstrap_by_port(p) != &bootstraps
948 || lookup_bootstrap_req_by_port(p) != &bootstraps
949 || p == bootstraps.bootstrap_port
950 || p == bootstraps.requestor_port)
951 return;
952
953 #if DEBUG
954 debug("Deallocating port %d", p);
955 #endif DEBUG
956 (void) mach_port_deallocate(mach_task_self(), p);
957 }
958
959 boolean_t
960 canReceive(mach_port_t port)
961 {
962 mach_port_type_t p_type;
963 kern_return_t result;
964
965 result = mach_port_type(mach_task_self(), port, &p_type);
966 if (result != KERN_SUCCESS) {
967 kern_error(result, "port_type");
968 return FALSE;
969 }
970 return ((p_type & MACH_PORT_TYPE_RECEIVE) != 0);
971 }
972
973
974 boolean_t
975 canSend(mach_port_t port)
976 {
977 mach_port_type_t p_type;
978 kern_return_t result;
979
980 result = mach_port_type(mach_task_self(), port, &p_type);
981 if (result != KERN_SUCCESS) {
982 kern_error(result, "port_type");
983 return FALSE;
984 }
985 return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0);
986 }
987 void
988 set_default_policy(
989 mach_port_t master_host_port)
990 {
991 #if 0
992 host_priority_info_data_t host_pri_info;
993 mach_port_t default_processor_set_name;
994 mach_port_t default_processor_set;
995 policy_rr_base_data_t rr_base;
996 policy_rr_limit_data_t rr_limit;
997 kern_return_t result;
998 mach_msg_type_number_t count;
999 static char here[] = "default_pager_set_policy";
1000
1001 count = HOST_PRIORITY_INFO_COUNT;
1002 result = host_info(mach_host_self(),
1003 HOST_PRIORITY_INFO,
1004 (host_info_t) &host_pri_info,
1005 &count);
1006 if (result != KERN_SUCCESS)
1007 kern_fatal(result, "Could not get host priority info");
1008
1009 rr_base.quantum = 0;
1010 rr_base.base_priority = host_pri_info.system_priority;
1011 rr_limit.max_priority = host_pri_info.system_priority;
1012
1013 (void)processor_set_default(mach_host_self(),
1014 &default_processor_set_name);
1015 (void)host_processor_set_priv(master_host_port,
1016 default_processor_set_name,
1017 &default_processor_set);
1018
1019 result = task_set_policy(mach_host_self(), default_processor_set,
1020 POLICY_RR,
1021 (policy_base_t) & rr_base, POLICY_RR_BASE_COUNT,
1022 (policy_limit_t) & rr_limit, POLICY_RR_LIMIT_COUNT,
1023 TRUE);
1024 if (result != KERN_SUCCESS)
1025 kern_fatal(result, "Could not set task policy ");
1026 #endif
1027 }