]> git.saurik.com Git - apple/system_cmds.git/blame - mach_init.tproj/bootstrap.c
system_cmds-230.0.2.tar.gz
[apple/system_cmds.git] / mach_init.tproj / bootstrap.c
CommitLineData
1815bff5 1/*
b51d5b5f 2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6d658acd
A
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.
1815bff5
A
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,
6d658acd
A
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.
1815bff5
A
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 * bootstrap.c -- implementation of bootstrap main service loop
31 */
32
33/*
34 * Imports
35 */
36#import <mach/mach.h>
37#import <mach/boolean.h>
38#import <mach/message.h>
39#import <mach/notify.h>
40#import <mach/mig_errors.h>
41#include <mach/mach_traps.h>
42#include <mach/mach_interface.h>
43#include <mach/bootstrap.h>
44#include <mach/host_info.h>
45#include <mach/mach_host.h>
46#include <mach/exception.h>
47
48#import <sys/ioctl.h>
b51d5b5f
A
49#import <sys/types.h>
50#import <sys/wait.h>
51#import <pthread.h>
1815bff5
A
52#import <string.h>
53#import <ctype.h>
54#import <stdio.h>
55#import <libc.h>
56
b51d5b5f 57#import "bootstrap.h"
1815bff5
A
58
59#import "bootstrap_internal.h"
60#import "lists.h"
61#import "error_log.h"
1815bff5
A
62
63/* Mig should produce a declaration for this, but doesn't */
64extern boolean_t bootstrap_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
65
66/*
67 * Exports
68 */
69const char *program_name; /* our name for error messages */
70
b51d5b5f
A
71#ifndef INIT_PATH
72#define INIT_PATH "/sbin/init" /* default init path */
73#endif INIT_PATH
1815bff5 74
b51d5b5f 75uid_t inherited_uid;
1815bff5
A
76mach_port_t inherited_bootstrap_port = MACH_PORT_NULL;
77boolean_t forward_ok = FALSE;
b51d5b5f 78boolean_t shutdown_in_progress = FALSE;
1815bff5
A
79boolean_t debugging = FALSE;
80boolean_t register_self = FALSE;
b51d5b5f
A
81boolean_t force_fork = FALSE;
82const char *register_name;
83task_t bootstrap_self;
1815bff5
A
84
85#ifndef ASSERT
86#define ASSERT(p)
87#endif
88
89/*
90 * Private macros
91 */
92#define NELEM(x) (sizeof(x)/sizeof(x[0]))
93#define END_OF(x) (&(x)[NELEM(x)])
94#define streq(a,b) (strcmp(a,b) == 0)
95
96/*
97 * Private declarations
98 */
1815bff5
A
99static void wait_for_go(mach_port_t init_notify_port);
100static void init_ports(void);
101static void start_server(server_t *serverp);
b51d5b5f 102static void unblock_init(mach_port_t init_notify_port, mach_port_t newBootstrap);
1815bff5
A
103static void exec_server(server_t *serverp);
104static char **argvize(const char *string);
b51d5b5f 105static void *demand_loop(void *arg);
1815bff5 106static void server_loop(void);
b51d5b5f
A
107extern kern_return_t bootstrap_register
108(
109 mach_port_t bootstrap_port,
110 name_t service_name,
111 mach_port_t service_port
112);
1815bff5
A
113
114/*
115 * Private ports we hold receive rights for. We also hold receive rights
116 * for all the privileged ports. Those are maintained in the server
117 * structs.
118 */
119mach_port_t bootstrap_port_set;
b51d5b5f
A
120mach_port_t demand_port_set;
121pthread_t demand_thread;
122
1815bff5 123mach_port_t notify_port;
b51d5b5f 124mach_port_t backup_port;
1815bff5 125
b51d5b5f
A
126static void
127notify_server_loop(mach_port_name_t about)
128{
129 mach_port_destroyed_notification_t not;
130 mach_msg_return_t nresult;
131
132 not.not_header.msgh_id = DEMAND_REQUEST;
133 not.not_header.msgh_remote_port = backup_port;
134 not.not_header.msgh_local_port = MACH_PORT_NULL;
135 not.not_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
136 not.not_header.msgh_size = sizeof(not) - sizeof(not.trailer);
137 not.not_body.msgh_descriptor_count = 1;
138 not.not_port.type = MACH_MSG_PORT_DESCRIPTOR;
139 not.not_port.disposition = MACH_MSG_TYPE_PORT_NAME;
140 not.not_port.name = about;
141 nresult = mach_msg_send(&not.not_header);
142 if (nresult != MACH_MSG_SUCCESS) {
143 kern_error(nresult, "notify_server: mach_msg_send()");
144 }
145}
1815bff5
A
146
147void _myExit(int arg)
148{
149 exit(arg);
150}
151
b51d5b5f
A
152void toggle_debug(int signal)
153{
154 debugging = (debugging) ? FALSE : TRUE;
155}
156
157void start_shutdown(int signal)
158{
159 debug("received SIGTERM");
160 shutdown_in_progress = TRUE;
161 notify_server_loop(MACH_PORT_DEAD);
162}
163
164int
165main(int argc, char * argv[])
1815bff5
A
166{
167 const char *argp;
168 char c;
1815bff5 169 server_t *serverp;
1815bff5 170 kern_return_t result;
b51d5b5f
A
171 mach_port_t init_notify_port;
172 pthread_attr_t attr;
173 sigset_t mask;
1815bff5 174 int pid;
b51d5b5f
A
175
176 /*
177 * If we are pid one, we have to exec init. Before doing so, we'll
178 * fork a child, and that will become the true mach_init. But we have
179 * to be very careful about ports. They aren't inherited across fork,
180 * so we have to avoid storing port names in memory before the fork that
181 * might not be valid after.
182 */
183 pid = getpid();
184 if (pid == 1)
185 {
186 close(0);
187 freopen("/dev/console", "r", stdin);
188 setbuf(stdin, NULL);
189 close(1);
190 freopen("/dev/console", "w", stdout);
191 setbuf(stdout, NULL);
192 close(2);
193 freopen("/dev/console", "w", stderr);
194 setbuf(stderr, NULL);
195
196 result = mach_port_allocate(
197 mach_task_self(),
198 MACH_PORT_RIGHT_RECEIVE,
199 &init_notify_port);
200 if (result != KERN_SUCCESS)
201 kern_fatal(result, "mach_port_allocate");
202
203 result = mach_port_insert_right(
204 mach_task_self(),
205 init_notify_port,
206 init_notify_port,
207 MACH_MSG_TYPE_MAKE_SEND);
208 if (result != KERN_SUCCESS)
209 kern_fatal(result, "mach_port_insert_right");
210
211 result = task_set_bootstrap_port(
212 mach_task_self(),
213 init_notify_port);
214 if (result != KERN_SUCCESS)
215 kern_fatal(result, "task_set_bootstrap_port");
216
217 pid = fork();
218
219 if (pid < 0)
220 unix_fatal("fork");
221
222 else if (pid != 0) { /* PARENT - will become init when ready */
223 int fd;
224
225 /*
226 * Wait for mach_init ot give us a real bootstrap port
227 */
228 wait_for_go(init_notify_port);
229 info("Execing init");
230
231 close(0);
232 close(1);
233 close(2);
234 fd = open("/dev/tty", O_RDONLY);
235 if (fd >= 0) {
236 ioctl(fd, TIOCNOTTY, 0);
237 close(fd);
238 }
239
240 /* pass our arguments on to init */
241 argv[0] = INIT_PATH;
242 execv(argv[0], argv);
243 exit(1); /* will likely trigger a panic */
244
245 }
246 } else
247 init_notify_port = MACH_PORT_NULL;
1815bff5
A
248
249 /* Initialize error handling */
250 program_name = rindex(*argv, '/');
251 if (program_name)
252 program_name++;
253 else
254 program_name = *argv;
255 argv++; argc--;
256
1815bff5
A
257 /* Parse command line args */
258 while (argc > 0 && **argv == '-') {
1815bff5
A
259 argp = *argv++ + 1; argc--;
260 while (*argp) {
261 switch (c = *argp++) {
262 case 'd':
263 debugging = TRUE;
264 break;
265 case 'D':
266 debugging = FALSE;
267 break;
268 case 'F':
269 force_fork = TRUE;
270 break;
1815bff5
A
271 case 'r':
272 register_self = forward_ok = TRUE;
273 if (argc > 0) {
274 register_name = *argv++; argc--;
275 } else
276 fatal("-r requires name");
277 break;
b51d5b5f 278 case '-':
1815bff5 279 default:
1815bff5
A
280 break;
281 }
282 }
1815bff5
A
283 }
284
1815bff5 285 /*
b51d5b5f 286 * If we must fork, do it now before we get Mach ports in use
1815bff5 287 */
b51d5b5f 288 if (force_fork) {
1815bff5
A
289 pid = fork();
290 if (pid < 0)
291 unix_fatal("fork");
b51d5b5f
A
292 else if (pid != 0) /* PARENT: just exit */
293 exit(0);
294 }
295
296 /* block all but SIGHUP and SIGTERM and mark us as an init process */
297 setsid();
298 sigfillset(&mask);
299 sigdelset(&mask, SIGHUP);
300 signal(SIGHUP, toggle_debug);
301 sigdelset(&mask, SIGTERM);
302 signal(SIGTERM, start_shutdown);
303 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
304
305 init_errlog(pid == 0); /* are we a daemon? */
306 init_lists();
307
308 /*
309 * This task will become the bootstrap task, so go ahead and
310 * initialize the ports now.
311 */
312 bootstrap_self = mach_task_self();
313 inherited_uid = getuid();
314 init_ports();
1815bff5 315
b51d5b5f
A
316 log("Started with uid=%d%s%s%s",
317 inherited_uid,
318 (register_self) ? " registered-as=" : "",
319 (register_self) ? register_name : "",
320 (debugging) ? " in debug-mode" : "");
1815bff5 321
1815bff5 322
b51d5b5f
A
323 /*
324 * If we are supposed to coordinate with init, we have to
325 * get that port again, because we only have a (probably wrong)
326 * name in memory, not a proper right.
327 */
328 if (init_notify_port != MACH_PORT_NULL) {
329 result = task_get_bootstrap_port(
330 bootstrap_self,
331 &init_notify_port);
332 if (result != KERN_SUCCESS)
333 kern_fatal(result, "task_get_bootstrap_port");
334
335 unblock_init(init_notify_port, bootstraps.bootstrap_port);
336
337 result = task_set_bootstrap_port(
338 bootstrap_self,
339 MACH_PORT_NULL);
340 if (result != KERN_SUCCESS)
341 kern_fatal(result, "task_set_bootstrap_port");
342
343 result = mach_port_deallocate(
344 bootstrap_self,
345 init_notify_port);
346 if (result != KERN_SUCCESS)
347 kern_fatal(result, "mach_port_deallocate");
348
349 forward_ok = FALSE;
350 inherited_bootstrap_port = MACH_PORT_NULL;
351
352 } else {
353
354 /* get inherited bootstrap port */
355 result = task_get_bootstrap_port(
356 bootstrap_self,
357 &inherited_bootstrap_port);
358 if (result != KERN_SUCCESS)
359 kern_fatal(result, "task_get_bootstrap_port");
360
361 /* We set this explicitly as we start each child */
362 task_set_bootstrap_port(bootstrap_self, MACH_PORT_NULL);
363 if (inherited_bootstrap_port == MACH_PORT_NULL)
364 forward_ok = FALSE;
365
366 /* register "self" port with anscestor */
367 if (register_self && forward_ok) {
368 result = bootstrap_register(
369 inherited_bootstrap_port,
370 (char *)register_name,
371 bootstraps.bootstrap_port);
1815bff5 372 if (result != KERN_SUCCESS)
b51d5b5f 373 kern_fatal(result, "register self");
1815bff5 374 }
1815bff5 375 }
1815bff5 376
b51d5b5f
A
377
378 /* Kick off all continuously running server processes */
379 for ( serverp = FIRST(servers)
380 ; !IS_END(serverp, servers)
381 ; serverp = NEXT(serverp))
382 if (serverp->servertype != DEMAND)
383 start_server(serverp);
384
385 pthread_attr_init (&attr);
386 pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_DETACHED );
387 result = pthread_create(
388 &demand_thread,
389 &attr,
390 demand_loop,
391 NULL);
392 if (result) {
393 unix_error("pthread_create()");
1815bff5
A
394 exit(1);
395 }
1815bff5 396
b51d5b5f
A
397 /* Process bootstrap service requests */
398 server_loop(); /* Should never return */
399 exit(1);
1815bff5
A
400}
401
402static void
403wait_for_go(mach_port_t init_notify_port)
404{
b51d5b5f 405 struct {
1815bff5
A
406 mach_msg_header_t hdr;
407 mach_msg_trailer_t trailer;
b51d5b5f 408 } init_go_msg;
1815bff5
A
409 kern_return_t result;
410
b51d5b5f 411 /*
1815bff5
A
412 * For now, we just blindly wait until we receive a message or
413 * timeout. We don't expect any notifications, and if we get one,
414 * it probably means something dire has happened; so we might as
415 * well give a shot at letting init run.
416 */
b51d5b5f
A
417 result = mach_msg(
418 &init_go_msg.hdr, MACH_RCV_MSG,
419 0, sizeof(init_go_msg), init_notify_port,
420 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
421 if (result != KERN_SUCCESS) {
422 kern_error(result, "mach_msg(receive) failed in wait_for_go");
423 }
424 result = task_set_bootstrap_port(
425 mach_task_self(),
426 init_go_msg.hdr.msgh_remote_port);
427 if (result != KERN_SUCCESS) {
428 kern_error(result, "task_get_bootstrap_port()");
429 }
1815bff5
A
430}
431
b51d5b5f
A
432
433static void
434unblock_init(mach_port_t init_notify_port,
435 mach_port_t newBootstrap)
436{
437 mach_msg_header_t init_go_msg;
438 kern_return_t result;
439
440 /*
441 * Proc 1 is blocked in a msg_receive on its notify port, this lets
442 * it continue, and we hand off its new bootstrap port
443 */
444 init_go_msg.msgh_remote_port = init_notify_port;
445 init_go_msg.msgh_local_port = newBootstrap;
446 init_go_msg.msgh_bits = MACH_MSGH_BITS(
447 MACH_MSG_TYPE_COPY_SEND,
448 MACH_MSG_TYPE_MAKE_SEND);
449 init_go_msg.msgh_size = sizeof(init_go_msg);
450 result = mach_msg_send(&init_go_msg);
451 if (result != KERN_SUCCESS)
452 kern_fatal(result, "unblock_init mach_msg_send() failed");
453 debug("sent go message");
454}
455
456
1815bff5
A
457static void
458init_ports(void)
459{
460 kern_return_t result;
461 service_t *servicep;
1815bff5
A
462
463 /*
464 * This task will become the bootstrap task.
465 */
b51d5b5f
A
466 /* Create port set that server loop listens to */
467 result = mach_port_allocate(
468 bootstrap_self,
469 MACH_PORT_RIGHT_PORT_SET,
470 &bootstrap_port_set);
1815bff5 471 if (result != KERN_SUCCESS)
b51d5b5f 472 kern_fatal(result, "port_set_allocate");
1815bff5 473
b51d5b5f
A
474 /* Create demand port set that second thread listens to */
475 result = mach_port_allocate(
476 bootstrap_self,
477 MACH_PORT_RIGHT_PORT_SET,
478 &demand_port_set);
1815bff5
A
479 if (result != KERN_SUCCESS)
480 kern_fatal(result, "port_set_allocate");
b51d5b5f 481
1815bff5 482 /* Create notify port and add to server port set */
b51d5b5f
A
483 result = mach_port_allocate(
484 bootstrap_self,
485 MACH_PORT_RIGHT_RECEIVE,
486 &notify_port);
1815bff5
A
487 if (result != KERN_SUCCESS)
488 kern_fatal(result, "mach_port_allocate");
489
b51d5b5f 490 result = mach_port_move_member(
1815bff5 491 bootstrap_self,
1815bff5 492 notify_port,
b51d5b5f
A
493 bootstrap_port_set);
494 if (result != KERN_SUCCESS)
495 kern_fatal(result, "mach_port_move_member");
496
497 /* Create backup port and add to server port set */
498 result = mach_port_allocate(
499 bootstrap_self,
500 MACH_PORT_RIGHT_RECEIVE,
501 &backup_port);
1815bff5 502 if (result != KERN_SUCCESS)
b51d5b5f 503 kern_fatal(result, "mach_port_allocate");
1815bff5 504
b51d5b5f
A
505 result = mach_port_move_member(
506 bootstrap_self,
507 backup_port,
508 bootstrap_port_set);
1815bff5
A
509 if (result != KERN_SUCCESS)
510 kern_fatal(result, "mach_port_move_member");
511
512 /* Create "self" port and add to server port set */
b51d5b5f
A
513 result = mach_port_allocate(
514 bootstrap_self,
515 MACH_PORT_RIGHT_RECEIVE,
516 &bootstraps.bootstrap_port);
1815bff5
A
517 if (result != KERN_SUCCESS)
518 kern_fatal(result, "mach_port_allocate");
b51d5b5f
A
519 result = mach_port_insert_right(
520 bootstrap_self,
521 bootstraps.bootstrap_port,
522 bootstraps.bootstrap_port,
523 MACH_MSG_TYPE_MAKE_SEND);
524 if (result != KERN_SUCCESS)
525 kern_fatal(result, "mach_port_insert_right");
526
527 /* keep the root bootstrap port "active" */
528 bootstraps.requestor_port = bootstraps.bootstrap_port;
529
530 result = mach_port_move_member(
531 bootstrap_self,
532 bootstraps.bootstrap_port,
533 bootstrap_port_set);
1815bff5
A
534 if (result != KERN_SUCCESS)
535 kern_fatal(result, "mach_port_move_member");
b51d5b5f 536
1815bff5
A
537 /*
538 * Allocate service ports for declared services.
539 */
540 for ( servicep = FIRST(services)
541 ; ! IS_END(servicep, services)
542 ; servicep = NEXT(servicep))
543 {
544 switch (servicep->servicetype) {
545 case DECLARED:
b51d5b5f
A
546 result = mach_port_allocate(
547 bootstrap_self,
548 MACH_PORT_RIGHT_RECEIVE,
549 &(servicep->port));
1815bff5
A
550 if (result != KERN_SUCCESS)
551 kern_fatal(result, "mach_port_allocate");
b51d5b5f
A
552
553 result = mach_port_insert_right(
554 bootstrap_self,
555 servicep->port,
556 servicep->port,
557 MACH_MSG_TYPE_MAKE_SEND);
1815bff5
A
558 if (result != KERN_SUCCESS)
559 kern_fatal(result, "mach_port_insert_right");
b51d5b5f 560 info("Declared port %x for service %s",
1815bff5
A
561 servicep->port,
562 servicep->name);
b51d5b5f
A
563
564 if (servicep->server != NULL_SERVER &&
565 servicep->server->servertype == DEMAND) {
566 result = mach_port_move_member(
567 bootstrap_self,
568 servicep->port,
569 demand_port_set);
570 if (result != KERN_SUCCESS)
571 kern_fatal(result, "mach_port_move_member");
572 }
1815bff5 573 break;
b51d5b5f 574
1815bff5
A
575 case SELF:
576 servicep->port = bootstraps.bootstrap_port;
b51d5b5f
A
577 servicep->server = new_server(&bootstraps,
578 program_name,
579 inherited_uid,
580 MACHINIT);
581 info("Set port %x for self port",
1815bff5
A
582 bootstraps.bootstrap_port);
583 break;
b51d5b5f 584
1815bff5
A
585 case REGISTERED:
586 fatal("Can't allocate REGISTERED port!?!");
587 break;
588 }
589 }
590}
591
b51d5b5f
A
592boolean_t
593active_bootstrap(bootstrap_info_t *bootstrap)
594{
595 return (bootstrap->requestor_port != MACH_PORT_NULL);
596}
597
598boolean_t
599useless_server(server_t *serverp)
600{
601 return ( !active_bootstrap(serverp->bootstrap) ||
602 !lookup_service_by_server(serverp) ||
603 !serverp->activity);
604}
605
606boolean_t
607active_server(server_t *serverp)
608{
609 return (
610#ifdef DELAYED_BOOTSTRAP_DESTROY
611 serverp->port ||
612#else
613 (serverp->port && serverp->pid == NO_PID) ||
614#endif
615 serverp->task_port || serverp->active_services);
616}
617
1815bff5 618static void
b51d5b5f
A
619reap_server(server_t *serverp)
620{
621 kern_return_t result;
622 pid_t presult;
623 int wstatus;
624
625 /*
626 * Reap our children.
627 */
628 presult = waitpid(serverp->pid, &wstatus, WNOHANG);
629 if (presult != serverp->pid) {
630 unix_error("waitpid: cmd = %s", serverp->cmd);
631 } else if (wstatus) {
632 log("Server %x in bootstrap %x uid %d: \"%s\": %s %d [pid %d]",
633 serverp->port, serverp->bootstrap->bootstrap_port,
634 serverp->uid, serverp->cmd,
635 ((WIFEXITED(wstatus)) ?
636 "exited with non-zero status" :
637 "exited as a result of signal"),
638 ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) : WTERMSIG(wstatus)),
639 serverp->pid);
640 }
641 serverp->pid = 0;
642
643 /*
644 * Release the server task port reference, if we ever
645 * got it in the first place.
646 */
647 if (serverp->task_port != MACH_PORT_NULL) {
648 result = mach_port_deallocate(
649 mach_task_self(),
650 serverp->task_port);
651 if (result != KERN_SUCCESS)
652 kern_error(result, "mach_port_deallocate");
653 serverp->task_port = MACH_PORT_NULL;
654 }
655}
656
657static void
658demand_server(server_t *serverp)
659{
660 service_t *servicep;
661 kern_return_t result;
662
663 /*
664 * For on-demand servers, make sure that the service ports are
665 * back in on-demand portset. Active service ports should come
666 * back through a PORT_DESTROYED notification. We only have to
667 * worry about the inactive ports that may have been previously
668 * pulled from the set but never checked-in by the server.
669 */
670
671 for ( servicep = FIRST(services)
672 ; !IS_END(servicep, services)
673 ; servicep = NEXT(servicep))
674 {
675 if (serverp == servicep->server && !servicep->isActive) {
676 result = mach_port_move_member(
677 mach_task_self(),
678 servicep->port,
679 demand_port_set);
680 if (result != KERN_SUCCESS)
681 kern_fatal(result, "mach_port_move_member");
682 }
683 }
684}
685
686static
687void dispatch_server(server_t *serverp)
688{
689 if (!active_server(serverp)) {
690 if (useless_server(serverp))
691 delete_server(serverp);
692 else if (serverp->servertype == RESTARTABLE)
693 start_server(serverp);
694 else if (serverp->servertype == DEMAND)
695 demand_server(serverp);
696 }
697}
698
699void
700setup_server(server_t *serverp)
1815bff5
A
701{
702 kern_return_t result;
703 mach_port_t old_port;
1815bff5 704
1815bff5 705 /* Allocate privileged port for requests from service */
b51d5b5f
A
706 result = mach_port_allocate(mach_task_self(),
707 MACH_PORT_RIGHT_RECEIVE ,
708 &serverp->port);
709 info("Allocating port %x for server %s", serverp->port, serverp->cmd);
1815bff5
A
710 if (result != KERN_SUCCESS)
711 kern_fatal(result, "port_allocate");
712
b51d5b5f
A
713 /* Request no-senders notification so we can tell when server dies */
714 result = mach_port_request_notification(mach_task_self(),
715 serverp->port,
716 MACH_NOTIFY_NO_SENDERS,
717 1,
718 serverp->port,
719 MACH_MSG_TYPE_MAKE_SEND_ONCE,
720 &old_port);
721 if (result != KERN_SUCCESS)
722 kern_fatal(result, "mach_port_request_notification");
723
1815bff5
A
724 /* Add privileged server port to bootstrap port set */
725 result = mach_port_move_member(mach_task_self(),
b51d5b5f
A
726 serverp->port,
727 bootstrap_port_set);
1815bff5
A
728 if (result != KERN_SUCCESS)
729 kern_fatal(result, "mach_port_move_member");
b51d5b5f
A
730}
731
732static void
733start_server(server_t *serverp)
734{
735 kern_return_t result;
736 mach_port_t old_port;
737 int pid;
1815bff5
A
738
739 /*
740 * Do what's appropriate to get bootstrap port setup in server task
741 */
742 switch (serverp->servertype) {
1815bff5
A
743
744 case MACHINIT:
745 break;
746
747 case SERVER:
b51d5b5f 748 case DEMAND:
1815bff5 749 case RESTARTABLE:
b51d5b5f
A
750#ifdef DELAYED_BOOTSTRAP_DESTROY
751 if (!serverp->port)
752#endif
753 setup_server(serverp);
754
755 serverp->activity = 0;
756
757 /* Insert a send right */
758 result = mach_port_insert_right(mach_task_self(),
759 serverp->port,
760 serverp->port,
761 MACH_MSG_TYPE_MAKE_SEND);
762 if (result != KERN_SUCCESS)
763 kern_fatal(result, "mach_port_insert_right");
764
1815bff5 765 /* Give trusted service a unique bootstrap port */
b51d5b5f
A
766 result = task_set_bootstrap_port(mach_task_self(),
767 serverp->port);
1815bff5
A
768 if (result != KERN_SUCCESS)
769 kern_fatal(result, "task_set_bootstrap_port");
770
b51d5b5f
A
771 result = mach_port_deallocate(mach_task_self(),
772 serverp->port);
773 if (result != KERN_SUCCESS)
774 kern_fatal(result, "mach_port_deallocate");
775
1815bff5 776 pid = fork();
b51d5b5f 777 if (pid < 0) {
1815bff5 778 unix_error("fork");
b51d5b5f 779 } else if (pid == 0) { /* CHILD */
1815bff5
A
780 exec_server(serverp);
781 exit(1);
782 } else { /* PARENT */
b51d5b5f
A
783
784 result = task_set_bootstrap_port(
785 mach_task_self(),
786 MACH_PORT_NULL);
1815bff5
A
787 if (result != KERN_SUCCESS)
788 kern_fatal(result, "task_set_bootstrap_port");
789
b51d5b5f
A
790 info("Launched server %x in bootstrap %x uid %d: \"%s\": [pid %d]",
791 serverp->port, serverp->bootstrap->bootstrap_port,
792 serverp->uid, serverp->cmd, pid);
793 serverp->pid = pid;
794 result = task_for_pid(
795 mach_task_self(),
796 pid,
797 &serverp->task_port);
798 if (result != KERN_SUCCESS) {
799 kern_error(result, "getting server task port");
800 reap_server(serverp);
801 dispatch_server(serverp);
802 break;
803 }
804
805 /* Request dead name notification to tell when task dies */
806 result = mach_port_request_notification(
807 mach_task_self(),
808 serverp->task_port,
809 MACH_NOTIFY_DEAD_NAME,
810 0,
811 notify_port,
812 MACH_MSG_TYPE_MAKE_SEND_ONCE,
813 &old_port);
814 if (result != KERN_SUCCESS) {
815 kern_error(result, "mach_port_request_notification");
816 reap_server(serverp);
817 dispatch_server(serverp);
818 }
1815bff5
A
819 }
820 break;
821 }
822}
823
1815bff5
A
824static void
825exec_server(server_t *serverp)
826{
b51d5b5f
A
827 char **argv;
828 sigset_t mask;
829
1815bff5
A
830 /*
831 * Setup environment for server, someday this should be Mach stuff
832 * rather than Unix crud
833 */
1815bff5 834 argv = argvize(serverp->cmd);
1815bff5
A
835 close_errlog();
836
b51d5b5f
A
837 if (serverp->uid != inherited_uid)
838 if (setuid(serverp->uid) < 0)
839 unix_fatal("Disabled server %x bootstrap %x: \"%s\": setuid(%d)",
840 serverp->port, serverp->bootstrap->bootstrap_port,
841 serverp->cmd, serverp->uid);
842
843 if (setsid() < 0) {
844 /*
845 * We can't keep this from happening, but we shouldn't start
846 * the server not as a process group leader. So, just fake like
847 * there was real activity, and exit the child. If needed,
848 * we'll re-launch it under another pid.
849 */
850 serverp->activity = 1;
851 unix_fatal("Temporary failure server %x bootstrap %x: \"%s\": setsid()",
852 serverp->port, serverp->bootstrap->bootstrap_port,
853 serverp->cmd);
1815bff5
A
854 }
855
b51d5b5f
A
856 sigemptyset(&mask);
857 (void) sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
1815bff5 858
b51d5b5f
A
859 execv(argv[0], argv);
860 unix_fatal("Disabled server %x bootstrap %x: \"%s\": exec()",
861 serverp->port,
862 serverp->bootstrap->bootstrap_port,
863 serverp->cmd);
1815bff5
A
864}
865
866static char **
867argvize(const char *string)
868{
869 static char *argv[100], args[1000];
870 const char *cp;
871 char *argp, term;
872 int nargs;
873
874 /*
875 * Convert a command line into an argv for execv
876 */
877 nargs = 0;
878 argp = args;
879
880 for (cp = string; *cp;) {
881 while (isspace(*cp))
882 cp++;
883 term = (*cp == '"') ? *cp++ : '\0';
884 if (nargs < NELEM(argv))
885 argv[nargs++] = argp;
886 while (*cp && (term ? *cp != term : !isspace(*cp))
887 && argp < END_OF(args)) {
888 if (*cp == '\\')
889 cp++;
890 *argp++ = *cp;
891 if (*cp)
892 cp++;
893 }
894 *argp++ = '\0';
895 }
896 argv[nargs] = NULL;
897 return argv;
898}
899
b51d5b5f
A
900static void *
901demand_loop(void *arg)
902{
903 mach_msg_empty_rcv_t dummy;
904 kern_return_t dresult;
905
906
907 for(;;) {
908 mach_port_name_array_t members;
909 mach_msg_type_number_t membersCnt;
910 mach_port_status_t status;
911 mach_msg_type_number_t statusCnt;
912 int i;
913
914 /*
915 * Receive indication of message on demand service
916 * ports without actually receiving the message (we'll
917 * let the actual server do that.
918 */
919 dresult = mach_msg(
920 &dummy.header,
921 MACH_RCV_MSG|MACH_RCV_LARGE,
922 0,
923 0,
924 demand_port_set,
925 0,
926 MACH_PORT_NULL);
927 if (dresult != MACH_RCV_TOO_LARGE) {
928 kern_error(dresult, "demand_loop: mach_msg()");
929 continue;
930 }
931
932 /*
933 * If we are shutting down, there is no use processing
934 * any more of these messages.
935 */
936 if (shutdown_in_progress == TRUE)
937 return arg;
938
939 /*
940 * Some port(s) now have messages on them, find out
941 * which ones (there is no indication of which port
942 * triggered in the MACH_RCV_TOO_LARGE indication).
943 */
944 dresult = mach_port_get_set_status(
945 mach_task_self(),
946 demand_port_set,
947 &members,
948 &membersCnt);
949 if (dresult != KERN_SUCCESS) {
950 kern_error(dresult, "demand_loop: mach_port_get_set_status()");
951 continue;
952 }
953
954 for (i = 0; i < membersCnt; i++) {
955 statusCnt = MACH_PORT_RECEIVE_STATUS_COUNT;
956 dresult = mach_port_get_attributes(
957 mach_task_self(),
958 members[i],
959 MACH_PORT_RECEIVE_STATUS,
960 (mach_port_info_t)&status,
961 &statusCnt);
962 if (dresult != KERN_SUCCESS) {
963 kern_error(dresult, "demand_loop: mach_port_get_attributes()");
964 continue;
965 }
966
967 /*
968 * For each port with messages, take it out of the
969 * demand service portset, and inform the main thread
970 * that it might have to start the server responsible
971 * for it.
972 */
973 if (status.mps_msgcount) {
974 dresult = mach_port_move_member(
975 mach_task_self(),
976 members[i],
977 MACH_PORT_NULL);
978 if (dresult != KERN_SUCCESS) {
979 kern_error(dresult, "demand_loop: mach_port_move_member()");
980 continue;
981 }
982 notify_server_loop(members[i]);
983 }
984 }
985
986 dresult = vm_deallocate(
987 mach_task_self(),
988 (vm_address_t) members,
989 (vm_size_t) membersCnt * sizeof(mach_port_name_t));
990 if (dresult != KERN_SUCCESS) {
991 kern_error(dresult, "demand_loop: vm_deallocate()");
992 continue;
993 }
994 }
995 return NULL;
996}
997
1815bff5 998/*
b51d5b5f 999 * server_demux -- processes requests off our service port
1815bff5
A
1000 * Also handles notifications
1001 */
1815bff5 1002
b51d5b5f
A
1003static boolean_t
1004server_demux(
1005 mach_msg_header_t *Request,
1006 mach_msg_header_t *Reply)
1815bff5
A
1007{
1008 bootstrap_info_t *bootstrap;
1009 service_t *servicep;
1010 server_t *serverp;
1011 kern_return_t result;
b51d5b5f 1012 mig_reply_error_t *reply;
1815bff5 1013
b51d5b5f 1014 debug("received message on port %x\n", Request->msgh_local_port);
1815bff5 1015
b51d5b5f
A
1016 /*
1017 * Do minimal cleanup and then exit.
1018 */
1019 if (shutdown_in_progress == TRUE) {
1020 log("Shutting down. Deactivating root bootstrap (%x) ...",
1021 bootstraps.bootstrap_port);
1022 deactivate_bootstrap(&bootstraps);
1023 log("Done.");
1024 exit(0);
1025 }
1026
1027 reply = (mig_reply_error_t *)Reply;
1815bff5
A
1028
1029 /*
1030 * Pick off notification messages
1031 */
b51d5b5f
A
1032 if (Request->msgh_local_port == notify_port) {
1033 mach_port_name_t np;
1034
1035 memset(reply, 0, sizeof(*reply));
1036 switch (Request->msgh_id) {
1037 case MACH_NOTIFY_DEAD_NAME:
1038 np = ((mach_dead_name_notification_t *)Request)->not_port;
1039 debug("Notified dead name %x", np);
1040
1041 if (np == inherited_bootstrap_port) {
1042 inherited_bootstrap_port = MACH_PORT_NULL;
1043 forward_ok = FALSE;
1044 }
1815bff5 1045
b51d5b5f
A
1046 /*
1047 * Check to see if a subset requestor port was deleted.
1048 */
1049 while (bootstrap = lookup_bootstrap_by_req_port(np)) {
1050 debug("Received dead name notification for bootstrap subset %x requestor port %x",
1051 bootstrap->bootstrap_port, bootstrap->requestor_port);
1052 mach_port_deallocate(
1053 mach_task_self(),
1054 bootstrap->requestor_port);
1055 bootstrap->requestor_port = MACH_PORT_NULL;
1056 deactivate_bootstrap(bootstrap);
1057 }
1815bff5 1058
b51d5b5f
A
1059 /*
1060 * Check to see if a defined service has gone
1061 * away.
1062 */
1063 while (servicep = lookup_service_by_port(np)) {
1064 /*
1065 * Port gone, registered service died.
1066 */
1067 debug("Received dead name notification for service %s "
1068 "on bootstrap port %x\n",
1069 servicep->name, servicep->bootstrap);
1070 debug("Service %s failed - deallocate", servicep->name);
1071 delete_service(servicep);
1072 }
1815bff5 1073
1815bff5 1074 /*
b51d5b5f
A
1075 * Check to see if a launched server task has gone
1076 * away.
1815bff5 1077 */
b51d5b5f
A
1078 if (serverp = lookup_server_by_task_port(np)) {
1079 /*
1080 * Port gone, server died.
1081 */
1082 debug("Received task death notification for server %s ",
1083 serverp->cmd);
1084 reap_server(serverp);
1085 dispatch_server(serverp);
1086 }
1087
1088 mach_port_deallocate(mach_task_self(), np);
1089 reply->RetCode = KERN_SUCCESS;
1090 break;
1091
1092 case MACH_NOTIFY_PORT_DELETED:
1093 np = ((mach_port_deleted_notification_t *)Request)->not_port;
1094 debug("port deleted notification on 0x%x\n", np);
1095 reply->RetCode = KERN_SUCCESS;
1096 break;
1097
1098 case MACH_NOTIFY_SEND_ONCE:
1099 debug("notification send-once right went unused\n");
1100 reply->RetCode = KERN_SUCCESS;
1101 break;
1102
1103 default:
1104 error("Unexpected notification: %d", Request->msgh_id);
1105 reply->RetCode = KERN_FAILURE;
1106 break;
1815bff5 1107 }
1815bff5 1108 }
1815bff5 1109
b51d5b5f
A
1110 else if (Request->msgh_local_port == backup_port) {
1111 mach_port_name_t np;
1112
1113 memset(reply, 0, sizeof(*reply));
1114
1115 np = ((mach_port_destroyed_notification_t *)Request)->not_port.name;
1116 servicep = lookup_service_by_port(np);
1117 if (servicep != NULL) {
1118 server_t *serverp = servicep->server;
1119
1120 switch (Request->msgh_id) {
1121
1122 case MACH_NOTIFY_PORT_DESTROYED:
1123 /*
1124 * Port sent back to us, server died.
1125 */
1126 debug("Received destroyed notification for service %s",
1127 servicep->name);
1128 debug("Service %x bootstrap %x backed up: %s",
1129 servicep->port, servicep->bootstrap->bootstrap_port,
1130 servicep->name);
1131 ASSERT(canReceive(servicep->port));
1132 servicep->isActive = FALSE;
1133 serverp->active_services--;
1134 dispatch_server(serverp);
1135 reply->RetCode = KERN_SUCCESS;
1136 break;
1815bff5 1137
b51d5b5f
A
1138 case DEMAND_REQUEST:
1139 /* message reflected over from demand start thread */
1140 if (!active_server(serverp))
1141 start_server(serverp);
1142 reply->RetCode = KERN_SUCCESS;
1143 break;
1144
1145 default:
1146 debug("Mysterious backup_port notification %d", Request->msgh_id);
1147 reply->RetCode = KERN_FAILURE;
1148 break;
1149 }
1815bff5 1150 } else {
b51d5b5f
A
1151 debug("Backup_port notification - previously deleted service");
1152 reply->RetCode = KERN_FAILURE;
1815bff5 1153 }
b51d5b5f
A
1154 }
1155
1156 else if (Request->msgh_id == MACH_NOTIFY_NO_SENDERS) {
1157 mach_port_t ns = Request->msgh_local_port;
1158
1159 if ((serverp = lookup_server_by_port(ns)) != NULL_SERVER) {
1160 /*
1161 * A server we launched has released his bootstrap
1162 * port send right. We won't re-launch him unless
1163 * his services came back to roost. But we need to
1164 * destroy the bootstrap port for fear of leaking.
1165 */
1166 debug("server %s dropped server port", serverp->cmd);
1167 serverp->port = MACH_PORT_NULL;
1168 dispatch_server(serverp);
1169 } else if (bootstrap = lookup_bootstrap_by_port(ns)) {
1170 /*
1171 * The last direct user of a deactivated bootstrap went away.
1172 * We can finally free it.
1173 */
1174 debug("Deallocating bootstrap %x: no more clients", ns);
1175 bootstrap->bootstrap_port = MACH_PORT_NULL;
1176 deallocate_bootstrap(bootstrap);
1815bff5 1177 }
b51d5b5f
A
1178
1179 result = mach_port_mod_refs(
1180 mach_task_self(),
1181 ns,
1182 MACH_PORT_RIGHT_RECEIVE,
1183 -1);
1184 if (result != KERN_SUCCESS)
1185 kern_fatal(result, "mach_port_mod_refs");
1186
1187 memset(reply, 0, sizeof(*reply));
1188 reply->RetCode = KERN_SUCCESS;
1189 }
1190
1191 else { /* must be a service request */
1192 debug("Handled request.");
1193 return bootstrap_server(Request, Reply);
1815bff5 1194 }
b51d5b5f 1195 return TRUE;
1815bff5
A
1196}
1197
1198/*
b51d5b5f
A
1199 * server_loop -- pick requests off our service port and process them
1200 * Also handles notifications
1815bff5 1201 */
b51d5b5f
A
1202#define bootstrapMaxRequestSize 1024
1203#define bootstrapMaxReplySize 1024
1204
1205static void
1206server_loop(void)
1815bff5 1207{
b51d5b5f
A
1208 mach_msg_return_t mresult;
1209
1210 for (;;) {
1211 mresult = mach_msg_server(
1212 server_demux,
1213 bootstrapMaxRequestSize,
1214 bootstrap_port_set,
1215 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)|
1216 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
1217 if (mresult != MACH_MSG_SUCCESS)
1218 kern_error(mresult, "mach_msg_server");
1219 }
1815bff5
A
1220}
1221
1222boolean_t
1223canReceive(mach_port_t port)
1224{
1225 mach_port_type_t p_type;
1226 kern_return_t result;
1227
1228 result = mach_port_type(mach_task_self(), port, &p_type);
1229 if (result != KERN_SUCCESS) {
1230 kern_error(result, "port_type");
1231 return FALSE;
1232 }
1233 return ((p_type & MACH_PORT_TYPE_RECEIVE) != 0);
1234}
1235
1236
1237boolean_t
1238canSend(mach_port_t port)
1239{
1240 mach_port_type_t p_type;
1241 kern_return_t result;
1242
1243 result = mach_port_type(mach_task_self(), port, &p_type);
1244 if (result != KERN_SUCCESS) {
1245 kern_error(result, "port_type");
1246 return FALSE;
1247 }
1248 return ((p_type & MACH_PORT_TYPE_PORT_RIGHTS) != 0);
1249}