summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1994-09-20 20:22:57 +0000
committerMichael I. Bushnell <mib@gnu.org>1994-09-20 20:22:57 +0000
commit725fbaebb89dd2043d2df32a68c9ae490c2e3d4b (patch)
treef0fe612950bdd9cfba9d31e8098add2a4ffa7703
parent5dfb41de08fec4f5668d106c8e2e7fc53890684d (diff)
Formerly init.c.~49~
-rw-r--r--init/init.c915
1 files changed, 915 insertions, 0 deletions
diff --git a/init/init.c b/init/init.c
index e69de29b..f78c2d0b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -0,0 +1,915 @@
+/* Init that only bootstraps the hurd and runs sh.
+ Copyright (C) 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell and Roland McGrath. */
+
+#include <hurd.h>
+#include <hurd/fs.h>
+#include <hurd/fsys.h>
+#include <device/device.h>
+#include <stdio.h>
+#include <assert.h>
+#include <hurd/paths.h>
+#include <sys/reboot.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <string.h>
+#include <mach/notify.h>
+#include <stdlib.h>
+#include <hurd/msg.h>
+#include <hurd/term.h>
+
+#include "startup_reply_U.h"
+#include "startup_S.h"
+#include "notify_S.h"
+
+/* Define this if we should really reboot mach instead of
+ just simulating it. */
+#undef STANDALONE
+
+/* host_reboot flags for when we crash. */
+#define CRASH_FLAGS RB_AUTOBOOT
+
+#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot")
+
+/* This structure keeps track of each notified task. */
+struct ntfy_task
+ {
+ mach_port_t notify_port;
+ struct ntfy_task *next;
+ };
+
+/* This structure keeps track of each registered essential task. */
+struct ess_task
+ {
+ struct ess_task *next;
+ task_t task_port;
+ char *name;
+ };
+
+/* These are linked lists of all of the registered items. */
+struct ess_task *ess_tasks;
+struct ntfy_task *ntfy_tasks;
+
+/* Our receive right */
+mach_port_t startup;
+
+/* Ports to the kernel */
+mach_port_t host_priv, device_master;
+
+/* Args to bootstrap, expressed as flags */
+int bootstrap_args;
+
+/* Stored information for returning proc and auth startup messages. */
+mach_port_t procreply, authreply;
+mach_msg_type_name_t procreplytype, authreplytype;
+
+/* Our ports to auth and proc. */
+mach_port_t authserver;
+mach_port_t procserver;
+
+/* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */
+mach_port_t bootport;
+
+/* The tasks of auth and proc and the bootstrap filesystem. */
+task_t authtask, proctask, fstask;
+
+char *init_version = "0.0 pre-alpha";
+
+mach_port_t default_ports[INIT_PORT_MAX];
+mach_port_t default_dtable[3];
+
+char **global_argv;
+
+
+/* Read a string from stdin into BUF. */
+static int
+getstring (char *buf, size_t bufsize)
+{
+ if (fgets (buf, bufsize, stdin) != NULL && buf[0] != '\0')
+ {
+ size_t len = strlen (buf);
+ if (buf[len - 1] == '\n' || buf[len - 1] == '\r')
+ buf[len - 1] = '\0';
+ return 1;
+ }
+ return 0;
+}
+
+/* Reboot the microkernel. */
+void
+reboot_mach (int flags)
+{
+#ifdef STANDALONE
+ printf ("init: %sing Mach (flags %#x)...\n", BOOT (flags), flags);
+ fflush (stdout);
+ while (errno = host_reboot (host_priv, flags))
+ perror ("host_reboot");
+ for (;;);
+#else
+ printf ("init: Would %s Mach with flags %#x\n", BOOT (flags), flags);
+ fflush (stdout);
+ exit (1);
+#endif
+}
+
+/* Reboot the microkernel, specifying that this is a crash. */
+void
+crash_mach (void)
+{
+ reboot_mach (CRASH_FLAGS);
+}
+
+/* Reboot the Hurd. */
+void
+reboot_system (int flags)
+{
+ struct ntfy_task *n;
+
+ for (n = ntfy_tasks; n != NULL; n = n->next)
+ {
+ error_t err;
+ printf ("init: notifying %p\n", (void *) n->notify_port);
+ fflush (stdout);
+ /* XXX need to time out on reply */
+ err = startup_dosync (n->notify_port);
+ if (err && err != MACH_SEND_INVALID_DEST)
+ {
+ printf ("init: %p complained: %s\n",
+ (void *) n->notify_port,
+ strerror (err));
+ fflush (stdout);
+ }
+ }
+
+#ifdef STANDALONE
+ reboot_mach (flags);
+#else
+ {
+ pid_t *pp;
+ u_int npids = 0;
+ error_t err;
+ int ind;
+
+ err = proc_getallpids (procserver, &pp, &npids);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ procbad:
+ /* The procserver must have died. Give up. */
+ printf ("Init: can't simulate crash; proc has died\n");
+ fflush (stdout);
+ reboot_mach (flags);
+ }
+ for (ind = 0; ind < npids; ind++)
+ {
+ task_t task;
+ err = proc_pid2task (procserver, pp[ind], &task);
+ if (err == MACH_SEND_INVALID_DEST)
+ goto procbad;
+
+ else if (err)
+ {
+ printf ("init: getting task for pid %d: %s\n",
+ pp[ind], strerror (err));
+ fflush (stdout);
+ continue;
+ }
+
+ /* Postpone self so we can finish; postpone proc
+ so that we can finish. */
+ if (task != mach_task_self () && task != proctask)
+ {
+ struct procinfo *pi = 0;
+ u_int pisize = 0;
+ err = proc_getprocinfo (procserver, pp[ind], (int **)&pi, &pisize);
+ if (err == MACH_SEND_INVALID_DEST)
+ goto procbad;
+ if (err)
+ {
+ printf ("init: getting procinfo for pid %d: %s\n",
+ pp[ind], strerror (err));
+ fflush (stdout);
+ continue;
+ }
+ if (!(pi->state & PI_NOPARENT))
+ {
+ printf ("init: killing pid %d\n", pp[ind]);
+ fflush (stdout);
+ task_terminate (task);
+ }
+ }
+ }
+ printf ("Killing proc server\n");
+ fflush (stdout);
+ task_terminate (proctask);
+ printf ("Init exiting\n");
+ fflush (stdout);
+ exit (1);
+ }
+#endif
+}
+
+/* Reboot the Hurd, specifying that this is a crash. */
+void
+crash_system (void)
+{
+ reboot_system (CRASH_FLAGS);
+}
+
+/* Run SERVER, giving it INIT_PORT_MAX initial ports from PORTS.
+ Set TASK to be the task port of the new image. */
+void
+run (char *server, mach_port_t *ports, task_t *task)
+{
+ char buf[BUFSIZ];
+ char *prog = server;
+
+ if (bootstrap_args & RB_INITNAME)
+ {
+ printf ("Server file name (default %s): ", server);
+ if (getstring (buf, sizeof (buf)))
+ prog = buf;
+ }
+
+ while (1)
+ {
+ file_t file;
+
+ file = file_name_lookup (prog, O_EXEC, 0);
+ if (file == MACH_PORT_NULL)
+ perror (prog);
+ else
+ {
+ char *progname;
+ task_create (mach_task_self (), 0, task);
+ if (bootstrap_args & RB_KDB)
+ {
+ printf ("Pausing for %s\n", prog);
+ getchar ();
+ }
+ progname = strrchr (prog, '/');
+ if (progname)
+ ++progname;
+ else
+ progname = prog;
+ errno = file_exec (file, *task, 0,
+ progname, strlen (progname) + 1, /* Args. */
+ "", 1, /* No env. */
+ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
+ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+ NULL, 0, /* No info in init ints. */
+ NULL, 0, NULL, 0);
+ if (!errno)
+ break;
+
+ perror (prog);
+ }
+
+ printf ("File name for server %s (or nothing to reboot): ", server);
+ if (getstring (buf, sizeof (buf)))
+ prog = buf;
+ else
+ crash_system ();
+ }
+
+#if 0
+ printf ("started %s\n", prog);
+ fflush (stdout);
+#endif
+}
+
+/* Run FILENAME as root with ARGS as its argv (length ARGLEN).
+ Return the task that we started. If CTTY is set, then make
+ that the controlling terminal of the new process and put it in
+ its own login collection. */
+task_t
+run_for_real (char *filename, char *args, int arglen, mach_port_t ctty)
+{
+ file_t file;
+ error_t err;
+ task_t task;
+ char *progname;
+
+#if 0
+ char buf[512];
+ do
+ {
+ printf ("File name [%s]: ", filename);
+ if (getstring (buf, sizeof (buf)) && *buf)
+ filename = buf;
+ file = file_name_lookup (filename, O_EXEC, 0);
+ if (!file)
+ perror (filename);
+ }
+ while (!file);
+#else
+ file = file_name_lookup (filename, O_EXEC, 0);
+ if (!file)
+ {
+ perror (filename);
+ return MACH_PORT_NULL;
+ }
+#endif
+
+ task_create (mach_task_self (), 0, &task);
+ proc_child (procserver, task);
+ proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]);
+ proc_setsid (default_ports[INIT_PORT_PROC]);
+ if (ctty != MACH_PORT_NULL)
+ {
+ int pid;
+ term_getctty (ctty, &default_ports[INIT_PORT_CTTYID]);
+ proc_task2pid (procserver, task, &pid);
+ io_mod_owner (ctty, -pid);
+ proc_make_login_coll (default_ports[INIT_PORT_PROC]);
+ }
+ if (bootstrap_args & RB_KDB)
+ {
+ printf ("Pausing for %s\n", filename);
+ getchar ();
+ }
+ progname = strrchr (filename, '/');
+ if (progname)
+ ++progname;
+ else
+ progname = filename;
+ err = file_exec (file, task, 0,
+ args, arglen,
+ NULL, 0, /* No env. */
+ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
+ default_ports, MACH_MSG_TYPE_COPY_SEND,
+ INIT_PORT_MAX,
+ NULL, 0, /* No info in init ints. */
+ NULL, 0, NULL, 0);
+ mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]);
+ if (ctty != MACH_PORT_NULL)
+ {
+ mach_port_deallocate (mach_task_self (),
+ default_ports[INIT_PORT_CTTYID]);
+ default_ports[INIT_PORT_CTTYID] = MACH_PORT_NULL;
+ }
+ mach_port_deallocate (mach_task_self (), file);
+ return err ? MACH_PORT_NULL : task;
+}
+
+static int
+demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int notify_server (), startup_server ();
+
+ return (notify_server (inp, outp) ||
+ startup_server (inp, outp));
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+ volatile int err;
+ int i;
+ mach_port_t consdev;
+ extern char _edata, _etext, __data_start;
+
+ global_argv = argv;
+
+ /* Parse the arguments */
+ bootstrap_args = 0;
+ if (argc >= 2)
+ {
+ if (index (argv[1], 'q'))
+ bootstrap_args |= RB_ASKNAME;
+ if (index (argv[1], 's'))
+ bootstrap_args |= RB_SINGLE;
+ if (index (argv[1], 'd'))
+ bootstrap_args |= RB_KDB;
+ if (index (argv[1], 'n'))
+ bootstrap_args |= RB_INITNAME;
+ }
+
+ /* Fetch a port to the bootstrap filesystem, the host priv and
+ master device ports, and the console. */
+ if (task_get_bootstrap_port (mach_task_self (), &bootport)
+ || fsys_getpriv (bootport, &host_priv, &device_master, &fstask)
+ || device_open (device_master, D_WRITE, "console", &consdev))
+ crash_mach ();
+
+ err = vm_wire (host_priv, mach_task_self (),
+ (vm_address_t) 0x10000, /* XXX */
+ (vm_size_t) (&_etext - 0x10000),
+ VM_PROT_READ|VM_PROT_EXECUTE);
+ err = vm_wire (host_priv, mach_task_self (),
+ (vm_address_t) &__data_start,
+ (vm_size_t) (&_edata - &__data_start),
+ VM_PROT_READ|VM_PROT_WRITE);
+
+ /* Clear our bootstrap port so our children don't inherit it. */
+ task_set_bootstrap_port (mach_task_self (), MACH_PORT_NULL);
+
+ stderr = stdout = mach_open_devstream (consdev, "w");
+ stdin = mach_open_devstream (consdev, "r");
+ if (stdout == NULL || stdin == NULL)
+ crash_mach ();
+ setbuf (stdout, NULL);
+
+ /* At this point we can use assert to check for errors. */
+ err = mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE, &startup);
+ assert (!err);
+ err = mach_port_insert_right (mach_task_self (), startup, startup,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert (!err);
+
+ /* Set up the set of ports we will pass to the programs we exec. */
+ for (i = 0; i < INIT_PORT_MAX; i++)
+ switch (i)
+ {
+ case INIT_PORT_CRDIR:
+ default_ports[i] = getcrdir ();
+ break;
+ case INIT_PORT_CWDIR:
+ default_ports[i] = getcwdir ();
+ break;
+ default:
+ default_ports[i] = MACH_PORT_NULL;
+ break;
+ }
+
+ default_dtable[0] = getdport (0);
+ default_dtable[1] = getdport (1);
+ default_dtable[2] = getdport (2);
+
+ default_ports[INIT_PORT_BOOTSTRAP] = startup;
+ run ("/hurd/proc", default_ports, &proctask);
+ printf (" proc");
+ fflush (stdout);
+ run ("/hurd/auth", default_ports, &authtask);
+ printf (" auth");
+ fflush (stdout);
+ default_ports[INIT_PORT_BOOTSTRAP] = MACH_PORT_NULL;
+
+ /* Wait for messages. When both auth and proc have started, we
+ run launch_system which does the rest of the boot. */
+ while (1)
+ {
+ err = mach_msg_server (demuxer, 0, startup);
+ assert (!err);
+ }
+}
+
+void
+launch_core_servers (void)
+{
+ mach_port_t old;
+ mach_port_t authproc, fsproc;
+
+ /* Reply to the proc and auth servers. */
+ startup_procinit_reply (procreply, procreplytype, 0,
+ mach_task_self (), authserver,
+ host_priv, MACH_MSG_TYPE_COPY_SEND,
+ device_master, MACH_MSG_TYPE_COPY_SEND);
+#ifdef STANDALONE
+ mach_port_deallocate (mach_task_self (), device_master);
+ device_master = 0;
+#endif
+
+ /* Declare that the filesystem and auth are our children. */
+ proc_child (procserver, fstask);
+ proc_child (procserver, authtask);
+
+ proc_task2proc (procserver, authtask, &authproc);
+ startup_authinit_reply (authreply, authreplytype, 0, authproc,
+ MACH_MSG_TYPE_MOVE_SEND);
+
+ /* Give the library our auth and proc server ports. */
+ _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
+ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver);
+
+ /* Do NOT run _hurd_proc_init! That will start signals, which we do not
+ want. We listen to our own message port. Tell the proc server where
+ our args and environment are. */
+ proc_set_arg_locations (procserver,
+ (vm_address_t) global_argv, (vm_address_t) environ);
+
+ default_ports[INIT_PORT_AUTH] = authserver;
+
+ proc_register_version (procserver, host_priv, "init", HURD_RELEASE,
+ init_version);
+
+ /* Get the bootstrap filesystem's proc server port.
+ We must do this before calling proc_setmsgport below. */
+ proc_task2proc (procserver, fstask, &fsproc);
+
+#if 0
+ printf ("Init has completed.\n");
+ fflush (stdout);
+#endif
+ printf (".\n");
+ fflush (stdout);
+
+ /* Tell the proc server our msgport. Be sure to do this after we are all
+ done making requests of proc. Once we have done this RPC, proc
+ assumes it can send us requests, so we cannot block on proc again
+ before accepting more RPC requests! However, we must do this before
+ calling fsys_init, because fsys_init blocks on exec_init, and
+ exec_init to block waiting on our message port. */
+ proc_setmsgport (procserver, startup, &old);
+ if (old)
+ mach_port_deallocate (mach_task_self (), old);
+
+ /* Give the bootstrap FS its proc and auth ports. */
+ if (errno = fsys_init (bootport, fsproc, MACH_MSG_TYPE_MOVE_SEND,
+ authserver))
+ perror ("fsys_init");
+}
+
+/* Set up the initial value of the standard exec data. */
+void
+init_stdarrays ()
+{
+ auth_t nullauth;
+ mach_port_t pt;
+ mach_port_t ref;
+ mach_port_t *std_port_array;
+ int *std_int_array;
+
+ std_port_array = alloca (sizeof (mach_port_t) * INIT_PORT_MAX);
+ std_int_array = alloca (sizeof (int) * INIT_INT_MAX);
+
+ bzero (std_port_array, sizeof (mach_port_t) * INIT_PORT_MAX);
+ bzero (std_int_array, sizeof (int) * INIT_INT_MAX);
+
+ __USEPORT (AUTH, auth_makeauth (port, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, &nullauth));
+
+ pt = getcwdir ();
+ ref = mach_reply_port ();
+ io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND);
+ auth_user_authenticate (nullauth, pt, ref, MACH_MSG_TYPE_MAKE_SEND,
+ &std_port_array[INIT_PORT_CWDIR]);
+ mach_port_destroy (mach_task_self (), ref);
+ mach_port_deallocate (mach_task_self (), pt);
+
+ pt = getcrdir ();
+ ref = mach_reply_port ();
+ io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND);
+ auth_user_authenticate (nullauth, pt, ref, MACH_MSG_TYPE_MAKE_SEND,
+ &std_port_array[INIT_PORT_CRDIR]);
+ mach_port_destroy (mach_task_self (), ref);
+ mach_port_deallocate (mach_task_self (), pt);
+
+ std_port_array[INIT_PORT_AUTH] = nullauth;
+
+ std_int_array[INIT_UMASK] = CMASK;
+
+ __USEPORT (PROC, proc_setexecdata (port, std_port_array,
+ MACH_MSG_TYPE_MOVE_SEND, INIT_PORT_MAX,
+ std_int_array, INIT_INT_MAX));
+}
+
+
+/* Start the single-user environment. This can only be done
+ when the core servers have fully started. We know that
+ startup_essential_task is the last thing they do before being
+ ready to handle requests, so we start this once all the necessary
+ servers have identified themselves that way. */
+void
+launch_single_user ()
+{
+ char shell[] = "/bin/sh";
+ char terminal[] = "/hurd/term\0console\0/tmp/console";
+ mach_port_t term, foo;
+ char *termname;
+ task_t termtask;
+ int fd;
+ int foobiebletch[TASK_BASIC_INFO_COUNT];
+ int foobiebletchcount = TASK_BASIC_INFO_COUNT;
+ struct stat st;
+
+ init_stdarrays ();
+
+ printf ("Single-user environment:");
+ fflush (stdout);
+
+ /* Open the console. If we get something which is a terminal, then
+ we conclude that the filesystem has a proper translator for it,
+ and we're done. Otherwise, start /hurd/term on something inside
+ /tmp and use that. */
+ term = file_name_lookup ("/dev/console", O_READ, 0);
+ termname = "/dev/console";
+ if (term != MACH_PORT_NULL)
+ io_stat (term, &st);
+
+ if (term == MACH_PORT_NULL || st.st_fstype != FSTYPE_TERM)
+ {
+ /* Start the terminal server ourselves. */
+
+ termtask = run_for_real (terminal, terminal,
+ sizeof (terminal), MACH_PORT_NULL);
+ printf (" term");
+ fflush (stdout);
+
+ /* Must match arg to terminal above. */
+ termname = "/tmp/console";
+
+ tryagain:
+
+ term = file_name_lookup (termname, O_READ, 0);
+ if (term != MACH_PORT_NULL)
+ io_stat (term, &st);
+ if (term == MACH_PORT_NULL || st.st_fstype != FSTYPE_TERM)
+ {
+ /* It hasn't been set yet; sleep a bit and try again.
+
+ However, if TERMTASK has died, then it has a bug. We'll
+ just let our fd's pass through unchanged. This probably
+ won't work, but it will enable some sort of debugging,
+ maybe. */
+ errno = task_info (termtask, TASK_BASIC_INFO, foobiebletch,
+ &foobiebletchcount);
+ if (errno != MACH_SEND_INVALID_DEST
+ && errno != KERN_INVALID_ARGUMENT)
+ {
+ sleep (1);
+ goto tryagain;
+ }
+ printf ("\nWarning: no normal console terminal.\n");
+ fflush (stdout);
+ term = MACH_PORT_NULL;
+ }
+ mach_port_deallocate (mach_task_self (), termtask);
+ }
+
+ /* At this point either TERM is the console or it's null. If it's
+ null, then don't do anything, and our fd's will be copied.
+ Otherwise, open fd's 0, 1, and 2. */
+ if (term != MACH_PORT_NULL)
+ {
+ fd = open (termname, O_READ);
+ assert (fd != -1);
+ dup2 (fd, 0);
+ close (fd);
+
+ fd = open (termname, O_WRITE);
+ assert (fd != -1);
+ dup2 (fd, 1);
+ dup2 (fd, 2);
+ close (fd);
+
+ fclose (stdin);
+ stdin = fdopen (0, "r");
+
+ /* Don't reopen our output channel for reliability's sake. */
+
+ /* Set ports in init_dtable for programs we start. */
+ mach_port_deallocate (mach_task_self (), default_dtable[0]);
+ mach_port_deallocate (mach_task_self (), default_dtable[1]);
+ mach_port_deallocate (mach_task_self (), default_dtable[2]);
+ default_dtable[0] = getdport (0);
+ default_dtable[1] = getdport (1);
+ default_dtable[2] = getdport (2);
+ }
+
+ /* The shell needs a real controlling terminal, so set that up here. */
+ foo = run_for_real (shell, shell, sizeof (shell), term);
+ mach_port_deallocate (mach_task_self (), term);
+ if (foo != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), foo);
+ printf (" shell.\n");
+ fflush (stdout);
+}
+
+
+kern_return_t
+S_startup_procinit (startup_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_porttype,
+ process_t proc,
+ mach_port_t *startuptask,
+ auth_t *auth,
+ mach_port_t *priv,
+ mach_msg_type_name_t *hostprivtype,
+ mach_port_t *dev,
+ mach_msg_type_name_t *devtype)
+{
+ if (procserver)
+ /* Only one proc server. */
+ return EPERM;
+
+ procserver = proc;
+
+ procreply = reply;
+ procreplytype = reply_porttype;
+
+ /* Save the reply port until we get startup_authinit. */
+ if (authserver)
+ launch_core_servers ();
+
+ return MIG_NO_REPLY;
+}
+
+/* Called by the auth server when it starts up. */
+
+kern_return_t
+S_startup_authinit (startup_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_porttype,
+ mach_port_t auth,
+ mach_port_t *proc,
+ mach_msg_type_name_t *proctype)
+{
+ if (authserver)
+ /* Only one auth server. */
+ return EPERM;
+
+ authserver = auth;
+
+ /* Save the reply port until we get startup_procinit. */
+ authreply = reply;
+ authreplytype = reply_porttype;
+
+ if (procserver)
+ launch_core_servers ();
+
+ return MIG_NO_REPLY;
+}
+
+kern_return_t
+S_startup_essential_task (mach_port_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ task_t task,
+ mach_port_t excpt,
+ char *name,
+ mach_port_t credential)
+{
+ struct ess_task *et;
+ mach_port_t prev;
+ static int authinit, procinit, execinit, initdone;
+
+ if (credential != host_priv)
+ return EPERM;
+ /* Record this task as essential. */
+ et = malloc (sizeof (struct ess_task));
+ if (et == NULL)
+ return ENOMEM;
+ et->task_port = task;
+ et->name = strdup (name);
+ if (et->name == NULL)
+ {
+ free (et);
+ return ENOMEM;
+ }
+ et->next = ess_tasks;
+ ess_tasks = et;
+
+ /* Dead-name notification on the task port will tell us when it dies. */
+ mach_port_request_notification (mach_task_self (), task,
+ MACH_NOTIFY_DEAD_NAME, 1, startup,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
+ if (prev)
+ mach_port_deallocate (mach_task_self (), prev);
+
+#if 0
+ /* Taking over the exception port will give us a better chance
+ if the task tries to get wedged on a fault. */
+ task_set_special_port (task, TASK_EXCEPTION_PORT, startup);
+#endif
+
+ mach_port_deallocate (mach_task_self (), credential);
+
+ if (!initdone)
+ {
+ if (!strcmp (name, "auth"))
+ authinit = 1;
+ else if (!strcmp (name, "exec"))
+ execinit = 1;
+ else if (!strcmp (name, "proc"))
+ procinit = 1;
+
+ if (authinit && execinit && procinit)
+ {
+ /* Reply to this RPC, after that everything
+ is ready for real startup to begin. */
+ startup_essential_task_reply (reply, replytype, 0);
+
+ launch_single_user ();
+ initdone = 1;
+ return MIG_NO_REPLY;
+ }
+ }
+
+ return 0;
+}
+
+kern_return_t
+S_startup_request_notification (mach_port_t server,
+ mach_port_t notify)
+{
+ struct ntfy_task *nt;
+ mach_port_t prev;
+
+ mach_port_request_notification (mach_task_self (), notify,
+ MACH_NOTIFY_DEAD_NAME, 1, startup,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
+ if (prev)
+ mach_port_deallocate (mach_task_self (), prev);
+
+ nt = malloc (sizeof (struct ntfy_task));
+ nt->notify_port = notify;
+ nt->next = ntfy_tasks;
+ ntfy_tasks = nt;
+ return 0;
+}
+
+kern_return_t
+do_mach_notify_dead_name (mach_port_t notify,
+ mach_port_t name)
+{
+ struct ntfy_task *nt, *pnt;
+ struct ess_task *et;
+
+ for (et = ess_tasks; et != NULL; et = et->next)
+ if (et->task_port == name)
+ /* An essential task has died. */
+ {
+ printf ("Init crashing system; essential task %s died\n",
+ et->name);
+ fflush (stdout);
+ crash_system ();
+ }
+
+ for (nt = ntfy_tasks, pnt = NULL; nt != NULL; pnt = nt, nt = nt->next)
+ if (nt->notify_port == name)
+ {
+ /* Someone who wanted to be notified is gone. */
+ mach_port_deallocate (mach_task_self (), name);
+ if (pnt != NULL)
+ pnt->next = nt->next;
+ else
+ ntfy_tasks = nt->next;
+ free (nt);
+ return 0;
+ }
+ return 0;
+}
+
+kern_return_t
+S_startup_reboot (mach_port_t server,
+ mach_port_t refpt,
+ int code)
+{
+ if (refpt != host_priv)
+ return EPERM;
+
+ reboot_system (code);
+ for (;;);
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_t rights)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t mscount)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_deleted (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}