diff options
Diffstat (limited to 'debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch')
-rw-r--r-- | debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch | 3678 |
1 files changed, 3678 insertions, 0 deletions
diff --git a/debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch b/debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch new file mode 100644 index 00000000..7a874ab6 --- /dev/null +++ b/debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch @@ -0,0 +1,3678 @@ +From 3ead9b6a0328e8aa85d652bcabdb76ce86360907 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 17 Sep 2013 13:44:44 +0200 +Subject: [PATCH 3/8] startup: rename /hurd/init to /hurd/startup + +This patch series splits /hurd/init into two programs. As a first +step, this patch renames /hurd/init to /hurd/startup. It is called +startup because it speaks the startup protocol. + +* startup: Rename init to startup. Adjust accordingly. +* Makefile (prog-subdirs): Likewise. +* doc/hurd.texi (Server Bootstrap): Likewise. +* hurd/paths.h (_HURD_STARTUP): Likewise. +* libdiskfs/boot-start.c (diskfs_boot_init_program): Likewise. +* libdiskfs/opts-std-startup.c (startup_options): Likewise. +--- + Makefile | 3 +- + doc/hurd.texi | 6 +- + hurd/paths.h | 2 +- + init/Makefile | 31 - + init/init.c | 1593 ------------------------------------------ + init/stubs.c | 139 ---- + libdiskfs/boot-start.c | 2 +- + libdiskfs/opts-std-startup.c | 2 +- + startup/Makefile | 31 + + startup/startup.c | 1593 ++++++++++++++++++++++++++++++++++++++++++ + startup/stubs.c | 139 ++++ + 11 files changed, 1771 insertions(+), 1770 deletions(-) + delete mode 100644 init/Makefile + delete mode 100644 init/init.c + delete mode 100644 init/stubs.c + create mode 100644 startup/Makefile + create mode 100644 startup/startup.c + create mode 100644 startup/stubs.c + +diff --git a/Makefile b/Makefile +index 0b9eff2..455df67 100644 +--- a/Makefile ++++ b/Makefile +@@ -31,7 +31,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \ + libnetfs libpipe libstore libhurdbugaddr libftpconn libcons + + # Hurd programs +-prog-subdirs = auth proc exec init term \ ++prog-subdirs = auth proc exec term \ + ext2fs isofs tmpfs fatfs \ + storeio pflocal pfinet defpager mach-defpager \ + login daemons boot console \ +@@ -40,6 +40,7 @@ prog-subdirs = auth proc exec init term \ + benchmarks fstests \ + random \ + procfs \ ++ startup \ + + ifeq ($(HAVE_SUN_RPC),yes) + prog-subdirs += nfs nfsd +diff --git a/doc/hurd.texi b/doc/hurd.texi +index 697cce7..7e7b5ee 100644 +--- a/doc/hurd.texi ++++ b/doc/hurd.texi +@@ -563,10 +563,10 @@ bootstrapped by starting the GNU Mach microkernel and two programs: + the root filesystem and the exec server. + + The @option{--multiboot-command-line} option tells the file system server that +-it is a root filesystem, which triggers it to run @command{/hurd/init} as PID +-2. @command{/hurd/init} starts the @command{/hurd/proc} and ++it is a root filesystem, which triggers it to run @command{/hurd/startup} as PID ++2. @command{/hurd/startup} starts the @command{/hurd/proc} and + @command{/hurd/auth} servers. After the servers are launched +-@command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to ++@command{/hurd/startup} starts the @command{/libexec/runsystem.sh} script to + finish booting. + + After the Hurd has been booted, other sets of core Hurd servers can be +diff --git a/hurd/paths.h b/hurd/paths.h +index 4877132..489da57 100644 +--- a/hurd/paths.h ++++ b/hurd/paths.h +@@ -39,7 +39,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + the canonical pathname being /hurd/foo. */ + + #define _HURD "/hurd/" +-#define _HURD_INIT _HURD "init" ++#define _HURD_STARTUP _HURD "startup" + #define _HURD_PROC _HURD "proc" + #define _HURD_AUTH _HURD "auth" + +diff --git a/init/Makefile b/init/Makefile +deleted file mode 100644 +index ffb82ff..0000000 +--- a/init/Makefile ++++ /dev/null +@@ -1,31 +0,0 @@ +-# +-# Copyright (C) 1994,95,96,99,2001 Free Software Foundation, Inc. +-# +-# This program 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. +-# +-# This program 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 this program; if not, write to the Free Software +-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +- +-dir := init +-makemode := server +- +-SRCS = init.c stubs.c +-OBJS = $(SRCS:.c=.o) \ +- startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ +- startup_notifyUser.o +-target = init +-HURDLIBS = shouldbeinlibc +- +-include ../Makeconf +- +-mung_msg_S.h: msg_S.h +- sed 's/msg_server/mung_msg_server/' < $< > $@ +diff --git a/init/init.c b/init/init.c +deleted file mode 100644 +index 6bc6701..0000000 +--- a/init/init.c ++++ /dev/null +@@ -1,1593 +0,0 @@ +-/* Start and maintain hurd core servers and system run state +- +- Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +- 2005, 2008, 2013 Free Software Foundation, Inc. +- 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. */ +- +-/* This is probably more include files than I've ever seen before for +- one file. */ +-#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 <hurd/fshelp.h> +-#include <paths.h> +-#include <sys/mman.h> +-#include <hurd/msg_server.h> +-#include <wire.h> +-#include <sys/wait.h> +-#include <error.h> +-#include <hurd/msg_reply.h> +-#include <argz.h> +-#include <maptime.h> +-#include <version.h> +-#include <argp.h> +-#include <pids.h> +- +-#include "startup_notify_U.h" +-#include "startup_reply_U.h" +-#include "startup_S.h" +-#include "notify_S.h" +-#include "mung_msg_S.h" +- +-/* host_reboot flags for when we crash. */ +-static int crash_flags = RB_AUTOBOOT; +- +-#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot") +- +- +-const char *argp_program_version = STANDARD_HURD_VERSION (init); +- +-static struct argp_option +-options[] = +-{ +- {"single-user", 's', 0, 0, "Startup system in single-user mode"}, +- {"query", 'q', 0, 0, "Ask for the names of servers to start"}, +- {"init-name", 'n', 0, 0 }, +- {"crash-debug", 'H', 0, 0, "On system crash, go to kernel debugger"}, +- {"debug", 'd', 0, 0 }, +- {"fake-boot", 'f', 0, 0, "This hurd hasn't been booted on the raw machine"}, +- {0, 'x', 0, OPTION_HIDDEN}, +- {0} +-}; +- +-static char doc[] = "Start and maintain hurd core servers and system run state"; +- +-static int booted; /* Set when the core servers are up. */ +- +-/* This structure keeps track of each notified task. */ +-struct ntfy_task +- { +- mach_port_t notify_port; +- struct ntfy_task *next; +- char *name; +- }; +- +-/* 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. */ +-static struct ess_task *ess_tasks; +-static struct ntfy_task *ntfy_tasks; +- +- +-/* Our receive right */ +-static mach_port_t startup; +- +-/* Ports to the kernel */ +-static mach_port_t host_priv, device_master; +- +-/* Args to bootstrap, expressed as flags */ +-static int bootstrap_args = 0; +- +-/* Stored information for returning proc and auth startup messages. */ +-static mach_port_t procreply, authreply; +-static mach_msg_type_name_t procreplytype, authreplytype; +- +-/* Our ports to auth and proc. */ +-static mach_port_t authserver; +-static mach_port_t procserver; +- +-/* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */ +-static mach_port_t bootport; +- +-/* Set iff we are a `fake' bootstrap. */ +-static int fakeboot; +- +-/* The tasks of auth and proc and the bootstrap filesystem. */ +-static task_t authtask, proctask, fstask; +- +-static mach_port_t default_ports[INIT_PORT_MAX]; +-static mach_port_t default_dtable[3]; +-static int default_ints[INIT_INT_MAX]; +- +-static char **global_argv; +-static char *startup_envz; +-static size_t startup_envz_len; +- +-void launch_system (void); +-void process_signal (int signo); +- +-/** Utility functions **/ +- +-/* 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; +-} +- +- +-/** System shutdown **/ +- +-/* Reboot the microkernel. */ +-void +-reboot_mach (int flags) +-{ +- if (fakeboot) +- { +- printf ("%s: Would %s Mach with flags %#x\n", +- program_invocation_short_name, BOOT (flags), flags); +- fflush (stdout); +- exit (1); +- } +- else +- { +- error_t err; +- printf ("%s: %sing Mach (flags %#x)...\n", +- program_invocation_short_name, BOOT (flags), flags); +- fflush (stdout); +- sleep (5); +- while ((err = host_reboot (host_priv, flags))) +- error (0, err, "reboot"); +- for (;;); +- } +-} +- +-/* Reboot the microkernel, specifying that this is a crash. */ +-void +-crash_mach (void) +-{ +- reboot_mach (crash_flags); +-} +- +-/* Notify all tasks that have requested shutdown notifications */ +-void +-notify_shutdown (const char *msg) +-{ +- struct ntfy_task *n; +- +- for (n = ntfy_tasks; n != NULL; n = n->next) +- { +- error_t err; +- printf ("%s: notifying %s of %s...", +- program_invocation_short_name, n->name, msg); +- fflush (stdout); +- err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */ +- if (err == MACH_SEND_INVALID_DEST) +- puts ("(no longer present)"); +- else if (err) +- puts (strerror (err)); +- else +- puts ("done"); +- fflush (stdout); +- } +-} +- +-/* Reboot the Hurd. */ +-void +-reboot_system (int flags) +-{ +- notify_shutdown ("shutdown"); +- +- if (fakeboot) +- { +- pid_t *pp; +- size_t 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. */ +- error (0, 0, "Can't simulate crash; proc has died"); +- 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) +- { +- error (0, err, "Getting task for pid %d", pp[ind]); +- 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; +- size_t pisize = 0; +- char *noise; +- size_t noise_len = 0; +- int flags; +- err = proc_getprocinfo (procserver, pp[ind], &flags, +- (int **)&pi, &pisize, +- &noise, &noise_len); +- if (err == MACH_SEND_INVALID_DEST) +- goto procbad; +- if (err) +- { +- error (0, err, "Getting procinfo for pid %d", pp[ind]); +- continue; +- } +- if (!(pi->state & PI_NOPARENT)) +- { +- printf ("%s: Killing pid %d\n", +- program_invocation_short_name, pp[ind]); +- fflush (stdout); +- task_terminate (task); +- } +- if (noise_len > 0) +- munmap (noise, noise_len); +- } +- } +- printf ("%s: Killing proc server\n", program_invocation_short_name); +- fflush (stdout); +- task_terminate (proctask); +- printf ("%s: Exiting", program_invocation_short_name); +- fflush (stdout); +- } +- reboot_mach (flags); +-} +- +-/* Reboot the Hurd, specifying that this is a crash. */ +-void +-crash_system (void) +-{ +- reboot_system (crash_flags); +-} +- +- +- +-/* Request a dead-name notification sent to our port. */ +-static void +-request_dead_name (mach_port_t name) +-{ +- mach_port_t prev; +- mach_port_request_notification (mach_task_self (), name, +- MACH_NOTIFY_DEAD_NAME, 1, startup, +- MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev); +- if (prev != MACH_PORT_NULL) +- mach_port_deallocate (mach_task_self (), prev); +-} +- +-/* Record an essential task in the list. */ +-static error_t +-record_essential_task (const char *name, task_t task) +-{ +- struct ess_task *et; +- /* 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. */ +- request_dead_name (task); +- +-#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 +- +- return 0; +-} +- +- +-/** Starting programs **/ +- +-/* Run SERVER, giving it INIT_PORT_MAX initial ports from PORTS. +- Set TASK to be the task port of the new image. */ +-void +-run (const char *server, mach_port_t *ports, task_t *task) +-{ +- char buf[BUFSIZ]; +- const 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; +- error_t err; +- +- file = file_name_lookup (prog, O_EXEC, 0); +- if (file == MACH_PORT_NULL) +- error (0, errno, "%s", prog); +- else +- { +- task_create (mach_task_self (), +-#ifdef KERN_INVALID_LEDGER +- NULL, 0, /* OSF Mach */ +-#endif +- 0, task); +- if (bootstrap_args & RB_KDB) +- { +- printf ("Pausing for %s\n", prog); +- getchar (); +- } +- err = file_exec (file, *task, 0, +- (char *)prog, strlen (prog) + 1, /* Args. */ +- startup_envz, startup_envz_len, +- default_dtable, MACH_MSG_TYPE_COPY_SEND, 3, +- ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, +- default_ints, INIT_INT_MAX, +- NULL, 0, NULL, 0); +- if (!err) +- break; +- +- error (0, err, "%s", 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 +- +- /* Dead-name notification on the task port will tell us when it dies, +- so we can crash if we don't make it to a fully bootstrapped Hurd. */ +- request_dead_name (*task); +-} +- +-/* 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. If SETSID is set, put it in a new session. Return +- 0 if the task was not created successfully. */ +-pid_t +-run_for_real (char *filename, char *args, int arglen, mach_port_t ctty, +- int setsid) +-{ +- file_t file; +- error_t err; +- task_t task; +- char *progname; +- int pid; +- +-#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 == MACH_PORT_NULL) +- error (0, errno, "%s", filename); +- } +- while (file == MACH_PORT_NULL); +-#else +- file = file_name_lookup (filename, O_EXEC, 0); +- if (file == MACH_PORT_NULL) +- { +- error (0, errno, "%s", filename); +- return 0; +- } +-#endif +- +- task_create (mach_task_self (), +-#ifdef KERN_INVALID_LEDGER +- NULL, 0, /* OSF Mach */ +-#endif +- 0, &task); +- proc_child (procserver, task); +- proc_task2pid (procserver, task, &pid); +- proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]); +- proc_mark_exec (default_ports[INIT_PORT_PROC]); +- if (setsid) +- proc_setsid (default_ports[INIT_PORT_PROC]); +- if (ctty != MACH_PORT_NULL) +- { +- term_getctty (ctty, &default_ports[INIT_PORT_CTTYID]); +- 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, +- startup_envz, startup_envz_len, +- default_dtable, MACH_MSG_TYPE_COPY_SEND, 3, +- default_ports, MACH_MSG_TYPE_COPY_SEND, +- INIT_PORT_MAX, +- default_ints, INIT_INT_MAX, +- NULL, 0, NULL, 0); +- mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]); +- mach_port_deallocate (mach_task_self (), task); +- 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); +- if (err) +- { +- error (0, err, "Cannot execute %s", filename); +- return 0; +- } +- return pid; +-} +- +- +-/** Main program and setup **/ +- +-static int +-demuxer (mach_msg_header_t *inp, +- mach_msg_header_t *outp) +-{ +- extern int notify_server (), startup_server (), msg_server (); +- +- return (notify_server (inp, outp) || +- msg_server (inp, outp) || +- startup_server (inp, outp)); +-} +- +-static int +-parse_opt (int key, char *arg, struct argp_state *state) +-{ +- switch (key) +- { +- case 'q': bootstrap_args |= RB_ASKNAME; break; +- case 's': bootstrap_args |= RB_SINGLE; break; +- case 'd': bootstrap_args |= RB_KDB; break; +- case 'n': bootstrap_args |= RB_INITNAME; break; +- case 'f': fakeboot = 1; break; +- case 'H': crash_flags = RB_DEBUGGER; break; +- case 'x': /* NOP */ break; +- default: return ARGP_ERR_UNKNOWN; +- } +- return 0; +-} +- +-int +-main (int argc, char **argv, char **envp) +-{ +- volatile int err; +- int i; +- int flags; +- mach_port_t consdev; +- struct argp argp = { options, parse_opt, 0, doc }; +- +- /* Parse the arguments. We don't want the vector reordered, we +- should pass on to our child the exact arguments we got and just +- ignore any arguments that aren't flags for us. ARGP_NO_ERRS +- suppresses --help and --version, so we only use that option if we +- are booting. */ +- flags = ARGP_IN_ORDER; +- if (getpid () == 0) +- flags |= ARGP_NO_ERRS; +- argp_parse (&argp, argc, argv, flags, 0, 0); +- +- if (getpid () > 0) +- error (2, 0, "can only be run by bootstrap filesystem"); +- +- global_argv = argv; +- +- /* 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 (); +- +- wire_task_self (); +- +- /* 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); +- +- err = argz_create (envp, &startup_envz, &startup_envz_len); +- assert_perror (err); +- +- /* At this point we can use assert to check for errors. */ +- err = mach_port_allocate (mach_task_self (), +- MACH_PORT_RIGHT_RECEIVE, &startup); +- assert_perror (err); +- err = mach_port_insert_right (mach_task_self (), startup, startup, +- MACH_MSG_TYPE_MAKE_SEND); +- assert_perror (err); +- +- /* Crash if the boot filesystem task dies. */ +- request_dead_name (fstask); +- +- /* 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); +- +- /* All programs we start should ignore job control stop signals. +- That way Posix.1 B.2.2.2 is satisfied where it says that programs +- not run under job control shells are protected. */ +- default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP) +- | sigmask (SIGTTIN) +- | sigmask (SIGTTOU)); +- +- 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_perror (err); +- } +-} +- +-void +-launch_core_servers (void) +-{ +- mach_port_t old; +- mach_port_t authproc, fsproc, procproc; +- error_t err; +- +- /* 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); +- if (!fakeboot) +- { +- mach_port_deallocate (mach_task_self (), device_master); +- device_master = 0; +- } +- +- /* Mark us as important. */ +- proc_mark_important (procserver); +- proc_mark_exec (procserver); +- +- /* Declare that the filesystem and auth are our children. */ +- proc_child (procserver, fstask); +- proc_child (procserver, authtask); +- +- proc_task2proc (procserver, authtask, &authproc); +- proc_mark_important (authproc); +- proc_mark_exec (authproc); +- startup_authinit_reply (authreply, authreplytype, 0, authproc, +- MACH_MSG_TYPE_COPY_SEND); +- mach_port_deallocate (mach_task_self (), authproc); +- +- /* 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; +- +- /* Declare that the proc server is our child. */ +- proc_child (procserver, proctask); +- err = proc_task2proc (procserver, proctask, &procproc); +- if (!err) +- { +- proc_mark_important (procproc); +- proc_mark_exec (procproc); +- mach_port_deallocate (mach_task_self (), procproc); +- } +- +- proc_register_version (procserver, host_priv, "init", "", HURD_VERSION); +- +- /* Get the bootstrap filesystem's proc server port. +- We must do this before calling proc_setmsgport below. */ +- proc_task2proc (procserver, fstask, &fsproc); +- proc_mark_important (fsproc); +- proc_mark_exec (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 will block waiting on our message port. */ +- proc_setmsgport (procserver, startup, &old); +- if (old != MACH_PORT_NULL) +- mach_port_deallocate (mach_task_self (), old); +- +- /* Give the bootstrap FS its proc and auth ports. */ +- err = fsys_init (bootport, fsproc, MACH_MSG_TYPE_COPY_SEND, authserver); +- mach_port_deallocate (mach_task_self (), fsproc); +- if (err) +- error (0, err, "fsys_init"); /* Not necessarily fatal. */ +-} +- +-/* 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; +- int i; +- +- 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)); +- +- /* MAKE_SEND is safe in these transactions because we destroy REF +- ourselves each time. */ +- pt = getcwdir (); +- ref = mach_reply_port (); +- io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND); +- auth_user_authenticate (nullauth, 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, 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_COPY_SEND, INIT_PORT_MAX, +- std_int_array, INIT_INT_MAX)); +- for (i = 0; i < INIT_PORT_MAX; i++) +- mach_port_deallocate (mach_task_self (), std_port_array[i]); +-} +- +-/* Frobnicate the kernel task and the proc server's idea of it (PID 2), +- so the kernel command line can be read as for a normal Hurd process. */ +- +-void +-frob_kernel_process (void) +-{ +- error_t err; +- int argc, i; +- char *argz, *entry; +- size_t argzlen; +- size_t windowsz; +- vm_address_t mine, his; +- task_t task; +- process_t proc, kbs; +- +- err = proc_pid2task (procserver, HURD_PID_KERNEL, &task); +- if (err) +- { +- error (0, err, "cannot get kernel task port"); +- return; +- } +- err = proc_task2proc (procserver, task, &proc); +- if (err) +- { +- error (0, err, "cannot get kernel task's proc server port"); +- mach_port_deallocate (mach_task_self (), task); +- return; +- } +- +- /* Mark the kernel task as an essential task so that we or the proc server +- never want to task_terminate it. */ +- proc_mark_important (proc); +- +- err = record_essential_task ("kernel", task); +- assert_perror (err); +- +- err = task_get_bootstrap_port (task, &kbs); +- assert_perror (err); +- if (kbs == MACH_PORT_NULL) +- { +- /* The kernel task has no bootstrap port set, so we are presumably +- the first Hurd to boot. Install the kernel task's proc port from +- this Hurd's proc server as the task bootstrap port. Additional +- Hurds will see this. */ +- +- err = task_set_bootstrap_port (task, proc); +- if (err) +- error (0, err, "cannot set kernel task's bootstrap port"); +- +- if (fakeboot) +- error (0, 0, "warning: --fake-boot specified but I see no other Hurd"); +- } +- else +- { +- /* The kernel task has a bootstrap port set. Perhaps it is its proc +- server port from another Hurd. If so, propagate the kernel +- argument locations from that Hurd rather than diddling with the +- kernel task ourselves. */ +- +- vm_address_t kargv, kenvp; +- err = proc_get_arg_locations (kbs, &kargv, &kenvp); +- mach_port_deallocate (mach_task_self (), kbs); +- if (err) +- error (0, err, "kernel task bootstrap port (ignoring)"); +- else +- { +- err = proc_set_arg_locations (proc, kargv, kenvp); +- if (err) +- error (0, err, "cannot propagate original kernel command line"); +- else +- { +- mach_port_deallocate (mach_task_self (), proc); +- mach_port_deallocate (mach_task_self (), task); +- if (! fakeboot) +- error (0, 0, "warning: " +- "I see another Hurd, but --fake-boot was not given"); +- return; +- } +- } +- } +- +- /* Our arguments make up the multiboot command line used to boot the +- kernel. We'll write into the kernel task a page containing a +- canonical argv array and argz of those words. */ +- +- err = argz_create (&global_argv[1], &argz, &argzlen); +- assert_perror (err); +- argc = argz_count (argz, argzlen); +- +- windowsz = round_page (((argc + 1) * sizeof (char *)) + argzlen); +- +- mine = (vm_address_t) mmap (0, windowsz, PROT_READ|PROT_WRITE, +- MAP_ANON, 0, 0); +- assert (mine != -1); +- err = vm_allocate (task, &his, windowsz, 1); +- if (err) +- { +- error (0, err, "cannot allocate %Zu bytes in kernel task", windowsz); +- free (argz); +- mach_port_deallocate (mach_task_self (), proc); +- mach_port_deallocate (mach_task_self (), task); +- munmap ((caddr_t) mine, windowsz); +- return; +- } +- +- for (i = 0, entry = argz; entry != NULL; +- ++i, entry = argz_next (argz, argzlen, entry)) +- ((char **) mine)[i] = ((char *) &((char **) his)[argc + 1] +- + (entry - argz)); +- ((char **) mine)[argc] = NULL; +- memcpy (&((char **) mine)[argc + 1], argz, argzlen); +- +- free (argz); +- +- /* We have the data all set up in our copy, now just write it over. */ +- err = vm_write (task, his, mine, windowsz); +- mach_port_deallocate (mach_task_self (), task); +- munmap ((caddr_t) mine, windowsz); +- if (err) +- { +- error (0, err, "cannot write command line into kernel task"); +- return; +- } +- +- /* The argument vector is set up in the kernel task at address HIS. +- Finally, we can inform the proc server where to find it. */ +- err = proc_set_arg_locations (proc, his, his + (argc * sizeof (char *))); +- mach_port_deallocate (mach_task_self (), proc); +- if (err) +- error (0, err, "proc_set_arg_locations for kernel task"); +-} +- +-/** Running userland. **/ +- +-/* In the "split-init" setup, we just run a single program (usually +- /libexec/runsystem) that is not expected to ever exit (or stop). +- If it does exit (or can't be started), we go to an emergency single-user +- shell as a fallback. */ +- +- +-static pid_t child_pid; /* PID of the child we run */ +-static task_t child_task; /* and its (original) task port */ +- +-error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport, +- mach_msg_timeout_t); +- +-static void launch_something (const char *why); +- +- +-/* SIGNO has arrived and has been validated. Do whatever work it +- implies. */ +-void +-process_signal (int signo) +-{ +- if (signo == SIGCHLD) +- { +- /* A child died. Find its status. */ +- int status; +- pid_t pid; +- +- while (1) +- { +- pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED); +- if (pid <= 0) +- break; /* No more children. */ +- +- /* Since we are init, orphaned processes get reparented to us and +- alas, all our adopted children eventually die. Woe is us. We +- just need to reap the zombies to relieve the proc server of +- its burden, and then we can forget about the little varmints. */ +- +- if (pid == child_pid) +- { +- /* The big magilla bit the dust. */ +- +- char *desc = 0; +- +- mach_port_deallocate (mach_task_self (), child_task); +- child_task = MACH_PORT_NULL; +- child_pid = -1; +- +- if (WIFSIGNALED (status)) +- asprintf (&desc, "terminated abnormally (%s)", +- strsignal (WTERMSIG (status))); +- else if (WIFSTOPPED (status)) +- asprintf (&desc, "stopped abnormally (%s)", +- strsignal (WTERMSIG (status))); +- else if (WEXITSTATUS (status) == 0) +- desc = strdup ("finished"); +- else +- asprintf (&desc, "exited with status %d", +- WEXITSTATUS (status)); +- +- { +- char buf[40]; +- snprintf (buf, sizeof buf, "%d", status); +- setenv ("STATUS", buf, 1); +- } +- +- launch_something (desc); +- free (desc); +- } +- } +- } +- else +- { +- /* Pass the signal on to the child. */ +- task_t task; +- error_t err; +- +- err = proc_pid2task (procserver, child_pid, &task); +- if (err) +- { +- error (0, err, "proc_pid2task on %d", child_pid); +- task = child_task; +- } +- else +- { +- mach_port_deallocate (mach_task_self (), child_task); +- child_task = task; +- } +- +- if (signo == SIGKILL) +- { +- err = task_terminate (task); +- if (err != MACH_SEND_INVALID_DEST) +- error (0, err, "task_terminate"); +- } +- else +- { +- mach_port_t msgport; +- err = proc_getmsgport (procserver, child_pid, &msgport); +- if (err) +- error (0, err, "proc_getmsgport"); +- else +- { +- err = send_signal (msgport, signo, task, +- 500); /* Block only half a second. */ +- mach_port_deallocate (mach_task_self (), msgport); +- if (err) +- { +- error (0, err, "cannot send %s to child %d", +- strsignal (signo), child_pid); +- err = task_terminate (task); +- if (err != MACH_SEND_INVALID_DEST) +- error (0, err, "task_terminate"); +- } +- } +- } +- } +-} +- +-/* Start the child program PROG. It is run via /libexec/console-run +- with the given additional arguments. */ +-static int +-start_child (const char *prog, char **progargs) +-{ +- file_t file; +- error_t err; +- char *args; +- size_t arglen; +- +- if (progargs == 0) +- { +- const char *argv[] = { "/libexec/console-run", prog, 0 }; +- err = argz_create ((char **) argv, &args, &arglen); +- } +- else +- { +- int argc = 0; +- while (progargs[argc] != 0) +- ++argc; +- { +- const char *argv[2 + argc + 1]; +- argv[0] = "/libexec/console-run"; +- argv[1] = prog; +- argv[2 + argc] = 0; +- while (argc-- > 0) +- argv[2 + argc] = progargs[argc]; +- err = argz_create ((char **) argv, &args, &arglen); +- } +- } +- assert_perror (err); +- +- file = file_name_lookup (args, O_EXEC, 0); +- if (file == MACH_PORT_NULL) +- { +- error (0, errno, "%s", args); +- free (args); +- return -1; +- } +- +- task_create (mach_task_self (), +-#ifdef KERN_INVALID_LEDGER +- NULL, 0, /* OSF Mach */ +-#endif +- 0, &child_task); +- proc_set_init_task (procserver, child_task); +- proc_task2pid (procserver, child_task, &child_pid); +- proc_task2proc (procserver, child_task, &default_ports[INIT_PORT_PROC]); +- +- if (bootstrap_args & RB_KDB) +- { +- printf ("Pausing for %s\n", args); +- getchar (); +- } +- +- err = file_exec (file, child_task, 0, +- args, arglen, +- startup_envz, startup_envz_len, +- NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */ +- default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, +- default_ints, INIT_INT_MAX, +- NULL, 0, NULL, 0); +- proc_mark_important (default_ports[INIT_PORT_PROC]); +- mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]); +- mach_port_deallocate (mach_task_self (), file); +- if (err) +- { +- error (0, err, "Cannot execute %s", args); +- free (args); +- return -1; +- } +- free (args); +- return 0; +-} +- +-static void +-launch_something (const char *why) +-{ +- file_t something; +- static unsigned int try; +- static const char *const tries[] = +- { +- "/libexec/runsystem", +- _PATH_BSHELL, +- "/bin/shd", /* XXX */ +- }; +- +- if (why) +- error (0, 0, "%s %s", tries[try - 1], why); +- +- something = file_name_lookup (tries[try], O_EXEC, 0); +- if (something != MACH_PORT_NULL) +- { +- mach_port_deallocate (mach_task_self (), something); +- if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0) +- return; +- } +- else +- try++; +- +- while (try < sizeof tries / sizeof tries[0]) +- { +- something = file_name_lookup (tries[try], O_EXEC, 0); +- if (something != MACH_PORT_NULL) +- { +- mach_port_deallocate (mach_task_self (), something); +- if (start_child (tries[try++], NULL) == 0) +- return; +- } +- } +- +- crash_system (); +-} +- +-void +-launch_system (void) +-{ +- launch_something (0); +-} +- +-/** RPC servers **/ +- +-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) +-{ +- static int authinit, procinit, execinit; +- int fail; +- +- /* Always deallocate the extra reference this message carries. */ +- if (MACH_PORT_VALID (credential)) +- mach_port_deallocate (mach_task_self (), credential); +- +- if (credential != host_priv) +- return EPERM; +- +- fail = record_essential_task (name, task); +- if (fail) +- return fail; +- +- if (!booted) +- { +- if (!strcmp (name, "auth")) +- authinit = 1; +- else if (!strcmp (name, "exec")) +- { +- execinit = 1; +- mach_port_t execproc; +- proc_task2proc (procserver, task, &execproc); +- proc_mark_important (execproc); +- } +- 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); +- +- init_stdarrays (); +- frob_kernel_process (); +- +- launch_system (); +- +- booted = 1; +- +- return MIG_NO_REPLY; +- } +- } +- +- return 0; +-} +- +-kern_return_t +-S_startup_request_notification (mach_port_t server, +- mach_port_t notify, +- char *name) +-{ +- struct ntfy_task *nt; +- +- request_dead_name (notify); +- +- /* Note that the ntfy_tasks list is kept in inverse order of the +- calls; this is important. We need later notification requests +- to get executed first. */ +- nt = malloc (sizeof (struct ntfy_task)); +- nt->notify_port = notify; +- nt->next = ntfy_tasks; +- ntfy_tasks = nt; +- nt->name = malloc (strlen (name) + 1); +- strcpy (nt->name, name); +- 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; +- +- assert (notify == startup); +- +- /* Deallocate the extra reference the notification carries. */ +- mach_port_deallocate (mach_task_self (), name); +- +- for (et = ess_tasks; et != NULL; et = et->next) +- if (et->task_port == name) +- /* An essential task has died. */ +- { +- error (0, 0, "Crashing system; essential task %s died", et->name); +- 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; +- } +- +- if (! booted) +- { +- /* The system has not come up yet, so essential tasks are not yet +- registered. But the essential servers involved in the bootstrap +- handshake might crash before completing it, so we have requested +- dead-name notification on those tasks. */ +- static const struct { task_t *taskp; const char *name; } boots[] = +- { +- {&fstask, "bootstrap filesystem"}, +- {&authtask, "auth"}, +- {&proctask, "proc"}, +- }; +- size_t i; +- for (i = 0; i < sizeof boots / sizeof boots[0]; ++i) +- if (name == *boots[i].taskp) +- { +- error (0, 0, "Crashing system; %s server died during bootstrap", +- boots[i].name); +- crash_mach (); +- } +- error (0, 0, "BUG! Unexpected dead-name notification (name %#zx)", +- name); +- crash_mach (); +- } +- +- 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 (;;); +-} +- +-/* Stubs for unused notification RPCs. */ +- +-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; +-} +- +-/* msg server */ +- +-kern_return_t +-S_msg_sig_post_untraced (mach_port_t msgport, +- mach_port_t reply, mach_msg_type_name_t reply_type, +- int signo, natural_t sigcode, mach_port_t refport) +-{ +- if (refport != mach_task_self ()) +- return EPERM; +- mach_port_deallocate (mach_task_self (), refport); +- +- /* Reply immediately */ +- msg_sig_post_untraced_reply (reply, reply_type, 0); +- +- process_signal (signo); +- return MIG_NO_REPLY; +-} +- +-kern_return_t +-S_msg_sig_post (mach_port_t msgport, +- mach_port_t reply, mach_msg_type_name_t reply_type, +- int signo, natural_t sigcode, mach_port_t refport) +-{ +- if (refport != mach_task_self ()) +- return EPERM; +- mach_port_deallocate (mach_task_self (), refport); +- +- /* Reply immediately */ +- msg_sig_post_reply (reply, reply_type, 0); +- +- process_signal (signo); +- return MIG_NO_REPLY; +-} +- +- +-/* For the rest of the msg functions, just call the C library's +- internal server stubs usually run in the signal thread. */ +- +-kern_return_t +-S_msg_proc_newids (mach_port_t process, +- mach_port_t task, +- pid_t ppid, +- pid_t pgrp, +- int orphaned) +-{ return _S_msg_proc_newids (process, task, ppid, pgrp, orphaned); } +- +- +-kern_return_t +-S_msg_add_auth (mach_port_t process, +- auth_t auth) +-{ return _S_msg_add_auth (process, auth); } +- +- +-kern_return_t +-S_msg_del_auth (mach_port_t process, +- mach_port_t task, +- intarray_t uids, +- mach_msg_type_number_t uidsCnt, +- intarray_t gids, +- mach_msg_type_number_t gidsCnt) +-{ return _S_msg_del_auth (process, task, uids, uidsCnt, gids, gidsCnt); } +- +- +-kern_return_t +-S_msg_get_init_port (mach_port_t process, +- mach_port_t refport, +- int which, +- mach_port_t *port, +- mach_msg_type_name_t *portPoly) +-{ return _S_msg_get_init_port (process, refport, which, port, portPoly); } +- +- +-kern_return_t +-S_msg_set_init_port (mach_port_t process, +- mach_port_t refport, +- int which, +- mach_port_t port) +-{ return _S_msg_set_init_port (process, refport, which, port); } +- +- +-kern_return_t +-S_msg_get_init_ports (mach_port_t process, +- mach_port_t refport, +- portarray_t *ports, +- mach_msg_type_name_t *portsPoly, +- mach_msg_type_number_t *portsCnt) +-{ return _S_msg_get_init_ports (process, refport, ports, portsPoly, portsCnt); } +- +- +-kern_return_t +-S_msg_set_init_ports (mach_port_t process, +- mach_port_t refport, +- portarray_t ports, +- mach_msg_type_number_t portsCnt) +-{ return _S_msg_set_init_ports (process, refport, ports, portsCnt); } +- +- +-kern_return_t +-S_msg_get_init_int (mach_port_t process, +- mach_port_t refport, +- int which, +- int *value) +-{ return _S_msg_get_init_int (process, refport, which, value); } +- +- +-kern_return_t +-S_msg_set_init_int (mach_port_t process, +- mach_port_t refport, +- int which, +- int value) +-{ return _S_msg_set_init_int (process, refport, which, value); } +- +- +-kern_return_t +-S_msg_get_init_ints (mach_port_t process, +- mach_port_t refport, +- intarray_t *values, +- mach_msg_type_number_t *valuesCnt) +-{ return _S_msg_get_init_ints (process, refport, values, valuesCnt); } +- +- +-kern_return_t +-S_msg_set_init_ints (mach_port_t process, +- mach_port_t refport, +- intarray_t values, +- mach_msg_type_number_t valuesCnt) +-{ return _S_msg_set_init_ints (process, refport, values, valuesCnt); } +- +- +-kern_return_t +-S_msg_get_dtable (mach_port_t process, +- mach_port_t refport, +- portarray_t *dtable, +- mach_msg_type_name_t *dtablePoly, +- mach_msg_type_number_t *dtableCnt) +-{ return _S_msg_get_dtable (process, refport, dtable, dtablePoly, dtableCnt); } +- +- +-kern_return_t +-S_msg_set_dtable (mach_port_t process, +- mach_port_t refport, +- portarray_t dtable, +- mach_msg_type_number_t dtableCnt) +-{ return _S_msg_set_dtable (process, refport, dtable, dtableCnt); } +- +- +-kern_return_t +-S_msg_get_fd (mach_port_t process, +- mach_port_t refport, +- int fd, +- mach_port_t *port, +- mach_msg_type_name_t *portPoly) +-{ return _S_msg_get_fd (process, refport, fd, port, portPoly); } +- +- +-kern_return_t +-S_msg_set_fd (mach_port_t process, +- mach_port_t refport, +- int fd, +- mach_port_t port) +-{ return _S_msg_set_fd (process, refport, fd, port); } +- +- +-kern_return_t +-S_msg_get_environment (mach_port_t process, +- data_t *value, +- mach_msg_type_number_t *valueCnt) +-{ return _S_msg_get_environment (process, value, valueCnt); } +- +- +-kern_return_t +-S_msg_set_environment (mach_port_t process, +- mach_port_t refport, +- data_t value, +- mach_msg_type_number_t valueCnt) +-{ return _S_msg_set_environment (process, refport, value, valueCnt); } +- +- +-kern_return_t +-S_msg_get_env_variable (mach_port_t process, +- string_t variable, +- data_t *value, +- mach_msg_type_number_t *valueCnt) +-{ return _S_msg_get_env_variable (process, variable, value, valueCnt); } +- +- +-kern_return_t +-S_msg_set_env_variable (mach_port_t process, +- mach_port_t refport, +- string_t variable, +- string_t value, +- boolean_t replace) +-{ return _S_msg_set_env_variable (process, refport, variable, value, replace); } +- +-error_t +-S_msg_describe_ports (mach_port_t process, +- mach_port_t refport, +- mach_port_array_t names, +- mach_msg_type_number_t namesCnt, +- data_t *descriptions, +- mach_msg_type_number_t *descriptionsCnt) +-{ +- return _S_msg_describe_ports (process, refport, names, namesCnt, +- descriptions, descriptionsCnt); +-} +- +-error_t +-S_msg_report_wait (mach_port_t process, thread_t thread, +- string_t desc, mach_msg_id_t *rpc) +-{ +- *desc = 0; +- *rpc = 0; +- return 0; +-} +diff --git a/init/stubs.c b/init/stubs.c +deleted file mode 100644 +index 5292ab6..0000000 +--- a/init/stubs.c ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* By-hand stubs for some RPC calls +- Copyright (C) 1994,96,99,2000 Free Software Foundation, Inc. +- +- This program 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. +- +- This program 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 this program; if not, write to the Free Software +- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +- +-#include <stdlib.h> +-#include <hurd/hurd_types.h> +-#include <mach.h> +-#include <string.h> +-#include <assert.h> +- +-/* From hurd/msg.defs: */ +-#define RPCID_SIG_POST 23000 +- +- +-/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't +- block in any fashion. */ +-error_t +-send_signal (mach_port_t msgport, +- int signal, +- mach_port_t refport, +- mach_msg_timeout_t timeout) +-{ +- error_t err; +- +- /* This message buffer might be modified by mach_msg in some error cases, +- so we cannot safely reuse a static buffer. */ +- struct +- { +- mach_msg_header_t head; +- mach_msg_type_t signaltype; +- int signal; +- mach_msg_type_t sigcode_type; +- natural_t sigcode; +- mach_msg_type_t refporttype; +- mach_port_t refport; +- } +- message = +- { +- { +- /* Message header: */ +- (MACH_MSGH_BITS_COMPLEX +- | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, +- MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ +- sizeof message, /* msgh_size */ +- msgport, /* msgh_remote_port */ +- MACH_PORT_NULL, /* msgh_local_port */ +- 0, /* msgh_seqno */ +- RPCID_SIG_POST, /* msgh_id */ +- }, +- { +- /* Type descriptor for signo */ +- MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ +- 32, /* msgt_size */ +- 1, /* msgt_number */ +- 1, /* msgt_inline */ +- 0, /* msgt_longform */ +- 0, /* msgt_deallocate */ +- 0, /* msgt_unused */ +- }, +- /* Signal number */ +- signal, +- /* Type descriptor for sigcode */ +- { +- MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ +- 32, /* msgt_size */ +- 1, /* msgt_number */ +- 1, /* msgt_inline */ +- 0, /* msgt_longform */ +- 0, /* msgt_deallocate */ +- 0, /* msgt_unused */ +- }, +- /* Sigcode */ +- 0, +- { +- /* Type descriptor for refport */ +- MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ +- 32, /* msgt_size */ +- 1, /* msgt_number */ +- 1, /* msgt_inline */ +- 0, /* msgt_longform */ +- 0, /* msgt_deallocate */ +- 0, /* msgt_unused */ +- }, +- /* Reference port */ +- refport +- }; +- +- err = mach_msg (&message.head, +- MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, +- MACH_PORT_NULL, timeout, MACH_PORT_NULL); +- +- switch (err) +- { +- case MACH_SEND_TIMED_OUT: +- /* The send could not complete in time. In this error case, the +- kernel has modified the message buffer in a pseudo-receive +- operation. That means our COPY_SEND refs might now be MOVE_SEND +- refs, in which case each has gained user ref accordingly. To +- avoid leaking those refs, we must clean up the buffer. We don't +- use mach_msg_destroy because it assumes the local/remote ports in +- the header have been reversed as from a real receive, while a +- pseudo-receive leaves them as they were. */ +- if (MACH_MSGH_BITS_REMOTE (message.head.msgh_bits) +- == MACH_MSG_TYPE_MOVE_SEND) +- mach_port_deallocate (mach_task_self (), +- message.head.msgh_remote_port); +- if (message.refporttype.msgt_name == MACH_MSG_TYPE_MOVE_SEND) +- mach_port_deallocate (mach_task_self (), message.refport); +- break; +- +- /* These are the other codes that mean a pseudo-receive modified +- the message buffer and we might need to clean up the send rights. +- None of them should be possible in our usage. */ +- case MACH_SEND_INTERRUPTED: +- case MACH_SEND_INVALID_NOTIFY: +- case MACH_SEND_NO_NOTIFY: +- case MACH_SEND_NOTIFY_IN_PROGRESS: +- assert_perror (err); +- break; +- +- default: /* Other errors are safe to ignore. */ +- break; +- } +- +- return err; +-} +diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c +index a590975..42e991e 100644 +--- a/libdiskfs/boot-start.c ++++ b/libdiskfs/boot-start.c +@@ -46,7 +46,7 @@ static task_t parent_task = MACH_PORT_NULL; + static pthread_mutex_t execstartlock; + static pthread_cond_t execstarted; + +-const char *diskfs_boot_init_program = _HURD_INIT; ++const char *diskfs_boot_init_program = _HURD_STARTUP; + + static void start_execserver (); + +diff --git a/libdiskfs/opts-std-startup.c b/libdiskfs/opts-std-startup.c +index 6fe2875..ed25a18 100644 +--- a/libdiskfs/opts-std-startup.c ++++ b/libdiskfs/opts-std-startup.c +@@ -59,7 +59,7 @@ startup_options[] = + "Required for bootstrap filesystem, the multiboot kernel command line"}, + {"bootflags", 0, 0, OPTION_ALIAS|OPTION_HIDDEN}, + {"boot-init-program", OPT_BOOT_INIT_PROGRAM, "FILE", 0, +- "For bootstrap filesystem, init program to run (default " _HURD_INIT ")"}, ++ "For bootstrap filesystem, init program to run (default " _HURD_STARTUP ")"}, + {"boot-debug-pause", OPT_BOOT_PAUSE, 0, 0, + "Pause for keystroke before starting bootstrap programs"}, + {"boot-command", OPT_BOOT_COMMAND, 0, 0, +diff --git a/startup/Makefile b/startup/Makefile +new file mode 100644 +index 0000000..2d6b892 +--- /dev/null ++++ b/startup/Makefile +@@ -0,0 +1,31 @@ ++# ++# Copyright (C) 1994,95,96,99,2001 Free Software Foundation, Inc. ++# ++# This program 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. ++# ++# This program 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 this program; if not, write to the Free Software ++# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++dir := startup ++makemode := server ++ ++SRCS = startup.c stubs.c ++OBJS = $(SRCS:.c=.o) \ ++ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ ++ startup_notifyUser.o ++target = startup ++HURDLIBS = shouldbeinlibc ++ ++include ../Makeconf ++ ++mung_msg_S.h: msg_S.h ++ sed 's/msg_server/mung_msg_server/' < $< > $@ +diff --git a/startup/startup.c b/startup/startup.c +new file mode 100644 +index 0000000..29269a6 +--- /dev/null ++++ b/startup/startup.c +@@ -0,0 +1,1593 @@ ++/* Start and maintain hurd core servers and system run state ++ ++ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, ++ 2005, 2008, 2013 Free Software Foundation, Inc. ++ 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. */ ++ ++/* This is probably more include files than I've ever seen before for ++ one file. */ ++#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 <hurd/fshelp.h> ++#include <paths.h> ++#include <sys/mman.h> ++#include <hurd/msg_server.h> ++#include <wire.h> ++#include <sys/wait.h> ++#include <error.h> ++#include <hurd/msg_reply.h> ++#include <argz.h> ++#include <maptime.h> ++#include <version.h> ++#include <argp.h> ++#include <pids.h> ++ ++#include "startup_notify_U.h" ++#include "startup_reply_U.h" ++#include "startup_S.h" ++#include "notify_S.h" ++#include "mung_msg_S.h" ++ ++/* host_reboot flags for when we crash. */ ++static int crash_flags = RB_AUTOBOOT; ++ ++#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot") ++ ++ ++const char *argp_program_version = STANDARD_HURD_VERSION (startup); ++ ++static struct argp_option ++options[] = ++{ ++ {"single-user", 's', 0, 0, "Startup system in single-user mode"}, ++ {"query", 'q', 0, 0, "Ask for the names of servers to start"}, ++ {"init-name", 'n', 0, 0 }, ++ {"crash-debug", 'H', 0, 0, "On system crash, go to kernel debugger"}, ++ {"debug", 'd', 0, 0 }, ++ {"fake-boot", 'f', 0, 0, "This hurd hasn't been booted on the raw machine"}, ++ {0, 'x', 0, OPTION_HIDDEN}, ++ {0} ++}; ++ ++static char doc[] = "Start and maintain hurd core servers and system run state"; ++ ++static int booted; /* Set when the core servers are up. */ ++ ++/* This structure keeps track of each notified task. */ ++struct ntfy_task ++ { ++ mach_port_t notify_port; ++ struct ntfy_task *next; ++ char *name; ++ }; ++ ++/* 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. */ ++static struct ess_task *ess_tasks; ++static struct ntfy_task *ntfy_tasks; ++ ++ ++/* Our receive right */ ++static mach_port_t startup; ++ ++/* Ports to the kernel */ ++static mach_port_t host_priv, device_master; ++ ++/* Args to bootstrap, expressed as flags */ ++static int bootstrap_args = 0; ++ ++/* Stored information for returning proc and auth startup messages. */ ++static mach_port_t procreply, authreply; ++static mach_msg_type_name_t procreplytype, authreplytype; ++ ++/* Our ports to auth and proc. */ ++static mach_port_t authserver; ++static mach_port_t procserver; ++ ++/* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */ ++static mach_port_t bootport; ++ ++/* Set iff we are a `fake' bootstrap. */ ++static int fakeboot; ++ ++/* The tasks of auth and proc and the bootstrap filesystem. */ ++static task_t authtask, proctask, fstask; ++ ++static mach_port_t default_ports[INIT_PORT_MAX]; ++static mach_port_t default_dtable[3]; ++static int default_ints[INIT_INT_MAX]; ++ ++static char **global_argv; ++static char *startup_envz; ++static size_t startup_envz_len; ++ ++void launch_system (void); ++void process_signal (int signo); ++ ++/** Utility functions **/ ++ ++/* 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; ++} ++ ++ ++/** System shutdown **/ ++ ++/* Reboot the microkernel. */ ++void ++reboot_mach (int flags) ++{ ++ if (fakeboot) ++ { ++ printf ("%s: Would %s Mach with flags %#x\n", ++ program_invocation_short_name, BOOT (flags), flags); ++ fflush (stdout); ++ exit (1); ++ } ++ else ++ { ++ error_t err; ++ printf ("%s: %sing Mach (flags %#x)...\n", ++ program_invocation_short_name, BOOT (flags), flags); ++ fflush (stdout); ++ sleep (5); ++ while ((err = host_reboot (host_priv, flags))) ++ error (0, err, "reboot"); ++ for (;;); ++ } ++} ++ ++/* Reboot the microkernel, specifying that this is a crash. */ ++void ++crash_mach (void) ++{ ++ reboot_mach (crash_flags); ++} ++ ++/* Notify all tasks that have requested shutdown notifications */ ++void ++notify_shutdown (const char *msg) ++{ ++ struct ntfy_task *n; ++ ++ for (n = ntfy_tasks; n != NULL; n = n->next) ++ { ++ error_t err; ++ printf ("%s: notifying %s of %s...", ++ program_invocation_short_name, n->name, msg); ++ fflush (stdout); ++ err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */ ++ if (err == MACH_SEND_INVALID_DEST) ++ puts ("(no longer present)"); ++ else if (err) ++ puts (strerror (err)); ++ else ++ puts ("done"); ++ fflush (stdout); ++ } ++} ++ ++/* Reboot the Hurd. */ ++void ++reboot_system (int flags) ++{ ++ notify_shutdown ("shutdown"); ++ ++ if (fakeboot) ++ { ++ pid_t *pp; ++ size_t 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. */ ++ error (0, 0, "Can't simulate crash; proc has died"); ++ 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) ++ { ++ error (0, err, "Getting task for pid %d", pp[ind]); ++ 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; ++ size_t pisize = 0; ++ char *noise; ++ size_t noise_len = 0; ++ int flags; ++ err = proc_getprocinfo (procserver, pp[ind], &flags, ++ (int **)&pi, &pisize, ++ &noise, &noise_len); ++ if (err == MACH_SEND_INVALID_DEST) ++ goto procbad; ++ if (err) ++ { ++ error (0, err, "Getting procinfo for pid %d", pp[ind]); ++ continue; ++ } ++ if (!(pi->state & PI_NOPARENT)) ++ { ++ printf ("%s: Killing pid %d\n", ++ program_invocation_short_name, pp[ind]); ++ fflush (stdout); ++ task_terminate (task); ++ } ++ if (noise_len > 0) ++ munmap (noise, noise_len); ++ } ++ } ++ printf ("%s: Killing proc server\n", program_invocation_short_name); ++ fflush (stdout); ++ task_terminate (proctask); ++ printf ("%s: Exiting", program_invocation_short_name); ++ fflush (stdout); ++ } ++ reboot_mach (flags); ++} ++ ++/* Reboot the Hurd, specifying that this is a crash. */ ++void ++crash_system (void) ++{ ++ reboot_system (crash_flags); ++} ++ ++ ++ ++/* Request a dead-name notification sent to our port. */ ++static void ++request_dead_name (mach_port_t name) ++{ ++ mach_port_t prev; ++ mach_port_request_notification (mach_task_self (), name, ++ MACH_NOTIFY_DEAD_NAME, 1, startup, ++ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev); ++ if (prev != MACH_PORT_NULL) ++ mach_port_deallocate (mach_task_self (), prev); ++} ++ ++/* Record an essential task in the list. */ ++static error_t ++record_essential_task (const char *name, task_t task) ++{ ++ struct ess_task *et; ++ /* 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. */ ++ request_dead_name (task); ++ ++#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 ++ ++ return 0; ++} ++ ++ ++/** Starting programs **/ ++ ++/* Run SERVER, giving it INIT_PORT_MAX initial ports from PORTS. ++ Set TASK to be the task port of the new image. */ ++void ++run (const char *server, mach_port_t *ports, task_t *task) ++{ ++ char buf[BUFSIZ]; ++ const 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; ++ error_t err; ++ ++ file = file_name_lookup (prog, O_EXEC, 0); ++ if (file == MACH_PORT_NULL) ++ error (0, errno, "%s", prog); ++ else ++ { ++ task_create (mach_task_self (), ++#ifdef KERN_INVALID_LEDGER ++ NULL, 0, /* OSF Mach */ ++#endif ++ 0, task); ++ if (bootstrap_args & RB_KDB) ++ { ++ printf ("Pausing for %s\n", prog); ++ getchar (); ++ } ++ err = file_exec (file, *task, 0, ++ (char *)prog, strlen (prog) + 1, /* Args. */ ++ startup_envz, startup_envz_len, ++ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3, ++ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, ++ default_ints, INIT_INT_MAX, ++ NULL, 0, NULL, 0); ++ if (!err) ++ break; ++ ++ error (0, err, "%s", 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 ++ ++ /* Dead-name notification on the task port will tell us when it dies, ++ so we can crash if we don't make it to a fully bootstrapped Hurd. */ ++ request_dead_name (*task); ++} ++ ++/* 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. If SETSID is set, put it in a new session. Return ++ 0 if the task was not created successfully. */ ++pid_t ++run_for_real (char *filename, char *args, int arglen, mach_port_t ctty, ++ int setsid) ++{ ++ file_t file; ++ error_t err; ++ task_t task; ++ char *progname; ++ int pid; ++ ++#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 == MACH_PORT_NULL) ++ error (0, errno, "%s", filename); ++ } ++ while (file == MACH_PORT_NULL); ++#else ++ file = file_name_lookup (filename, O_EXEC, 0); ++ if (file == MACH_PORT_NULL) ++ { ++ error (0, errno, "%s", filename); ++ return 0; ++ } ++#endif ++ ++ task_create (mach_task_self (), ++#ifdef KERN_INVALID_LEDGER ++ NULL, 0, /* OSF Mach */ ++#endif ++ 0, &task); ++ proc_child (procserver, task); ++ proc_task2pid (procserver, task, &pid); ++ proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]); ++ proc_mark_exec (default_ports[INIT_PORT_PROC]); ++ if (setsid) ++ proc_setsid (default_ports[INIT_PORT_PROC]); ++ if (ctty != MACH_PORT_NULL) ++ { ++ term_getctty (ctty, &default_ports[INIT_PORT_CTTYID]); ++ 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, ++ startup_envz, startup_envz_len, ++ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3, ++ default_ports, MACH_MSG_TYPE_COPY_SEND, ++ INIT_PORT_MAX, ++ default_ints, INIT_INT_MAX, ++ NULL, 0, NULL, 0); ++ mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]); ++ mach_port_deallocate (mach_task_self (), task); ++ 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); ++ if (err) ++ { ++ error (0, err, "Cannot execute %s", filename); ++ return 0; ++ } ++ return pid; ++} ++ ++ ++/** Main program and setup **/ ++ ++static int ++demuxer (mach_msg_header_t *inp, ++ mach_msg_header_t *outp) ++{ ++ extern int notify_server (), startup_server (), msg_server (); ++ ++ return (notify_server (inp, outp) || ++ msg_server (inp, outp) || ++ startup_server (inp, outp)); ++} ++ ++static int ++parse_opt (int key, char *arg, struct argp_state *state) ++{ ++ switch (key) ++ { ++ case 'q': bootstrap_args |= RB_ASKNAME; break; ++ case 's': bootstrap_args |= RB_SINGLE; break; ++ case 'd': bootstrap_args |= RB_KDB; break; ++ case 'n': bootstrap_args |= RB_INITNAME; break; ++ case 'f': fakeboot = 1; break; ++ case 'H': crash_flags = RB_DEBUGGER; break; ++ case 'x': /* NOP */ break; ++ default: return ARGP_ERR_UNKNOWN; ++ } ++ return 0; ++} ++ ++int ++main (int argc, char **argv, char **envp) ++{ ++ volatile int err; ++ int i; ++ int flags; ++ mach_port_t consdev; ++ struct argp argp = { options, parse_opt, 0, doc }; ++ ++ /* Parse the arguments. We don't want the vector reordered, we ++ should pass on to our child the exact arguments we got and just ++ ignore any arguments that aren't flags for us. ARGP_NO_ERRS ++ suppresses --help and --version, so we only use that option if we ++ are booting. */ ++ flags = ARGP_IN_ORDER; ++ if (getpid () == 0) ++ flags |= ARGP_NO_ERRS; ++ argp_parse (&argp, argc, argv, flags, 0, 0); ++ ++ if (getpid () > 0) ++ error (2, 0, "can only be run by bootstrap filesystem"); ++ ++ global_argv = argv; ++ ++ /* 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 (); ++ ++ wire_task_self (); ++ ++ /* 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); ++ ++ err = argz_create (envp, &startup_envz, &startup_envz_len); ++ assert_perror (err); ++ ++ /* At this point we can use assert to check for errors. */ ++ err = mach_port_allocate (mach_task_self (), ++ MACH_PORT_RIGHT_RECEIVE, &startup); ++ assert_perror (err); ++ err = mach_port_insert_right (mach_task_self (), startup, startup, ++ MACH_MSG_TYPE_MAKE_SEND); ++ assert_perror (err); ++ ++ /* Crash if the boot filesystem task dies. */ ++ request_dead_name (fstask); ++ ++ /* 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); ++ ++ /* All programs we start should ignore job control stop signals. ++ That way Posix.1 B.2.2.2 is satisfied where it says that programs ++ not run under job control shells are protected. */ ++ default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP) ++ | sigmask (SIGTTIN) ++ | sigmask (SIGTTOU)); ++ ++ 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_perror (err); ++ } ++} ++ ++void ++launch_core_servers (void) ++{ ++ mach_port_t old; ++ mach_port_t authproc, fsproc, procproc; ++ error_t err; ++ ++ /* 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); ++ if (!fakeboot) ++ { ++ mach_port_deallocate (mach_task_self (), device_master); ++ device_master = 0; ++ } ++ ++ /* Mark us as important. */ ++ proc_mark_important (procserver); ++ proc_mark_exec (procserver); ++ ++ /* Declare that the filesystem and auth are our children. */ ++ proc_child (procserver, fstask); ++ proc_child (procserver, authtask); ++ ++ proc_task2proc (procserver, authtask, &authproc); ++ proc_mark_important (authproc); ++ proc_mark_exec (authproc); ++ startup_authinit_reply (authreply, authreplytype, 0, authproc, ++ MACH_MSG_TYPE_COPY_SEND); ++ mach_port_deallocate (mach_task_self (), authproc); ++ ++ /* 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; ++ ++ /* Declare that the proc server is our child. */ ++ proc_child (procserver, proctask); ++ err = proc_task2proc (procserver, proctask, &procproc); ++ if (!err) ++ { ++ proc_mark_important (procproc); ++ proc_mark_exec (procproc); ++ mach_port_deallocate (mach_task_self (), procproc); ++ } ++ ++ proc_register_version (procserver, host_priv, "init", "", HURD_VERSION); ++ ++ /* Get the bootstrap filesystem's proc server port. ++ We must do this before calling proc_setmsgport below. */ ++ proc_task2proc (procserver, fstask, &fsproc); ++ proc_mark_important (fsproc); ++ proc_mark_exec (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 will block waiting on our message port. */ ++ proc_setmsgport (procserver, startup, &old); ++ if (old != MACH_PORT_NULL) ++ mach_port_deallocate (mach_task_self (), old); ++ ++ /* Give the bootstrap FS its proc and auth ports. */ ++ err = fsys_init (bootport, fsproc, MACH_MSG_TYPE_COPY_SEND, authserver); ++ mach_port_deallocate (mach_task_self (), fsproc); ++ if (err) ++ error (0, err, "fsys_init"); /* Not necessarily fatal. */ ++} ++ ++/* 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; ++ int i; ++ ++ 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)); ++ ++ /* MAKE_SEND is safe in these transactions because we destroy REF ++ ourselves each time. */ ++ pt = getcwdir (); ++ ref = mach_reply_port (); ++ io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND); ++ auth_user_authenticate (nullauth, 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, 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_COPY_SEND, INIT_PORT_MAX, ++ std_int_array, INIT_INT_MAX)); ++ for (i = 0; i < INIT_PORT_MAX; i++) ++ mach_port_deallocate (mach_task_self (), std_port_array[i]); ++} ++ ++/* Frobnicate the kernel task and the proc server's idea of it (PID 2), ++ so the kernel command line can be read as for a normal Hurd process. */ ++ ++void ++frob_kernel_process (void) ++{ ++ error_t err; ++ int argc, i; ++ char *argz, *entry; ++ size_t argzlen; ++ size_t windowsz; ++ vm_address_t mine, his; ++ task_t task; ++ process_t proc, kbs; ++ ++ err = proc_pid2task (procserver, HURD_PID_KERNEL, &task); ++ if (err) ++ { ++ error (0, err, "cannot get kernel task port"); ++ return; ++ } ++ err = proc_task2proc (procserver, task, &proc); ++ if (err) ++ { ++ error (0, err, "cannot get kernel task's proc server port"); ++ mach_port_deallocate (mach_task_self (), task); ++ return; ++ } ++ ++ /* Mark the kernel task as an essential task so that we or the proc server ++ never want to task_terminate it. */ ++ proc_mark_important (proc); ++ ++ err = record_essential_task ("kernel", task); ++ assert_perror (err); ++ ++ err = task_get_bootstrap_port (task, &kbs); ++ assert_perror (err); ++ if (kbs == MACH_PORT_NULL) ++ { ++ /* The kernel task has no bootstrap port set, so we are presumably ++ the first Hurd to boot. Install the kernel task's proc port from ++ this Hurd's proc server as the task bootstrap port. Additional ++ Hurds will see this. */ ++ ++ err = task_set_bootstrap_port (task, proc); ++ if (err) ++ error (0, err, "cannot set kernel task's bootstrap port"); ++ ++ if (fakeboot) ++ error (0, 0, "warning: --fake-boot specified but I see no other Hurd"); ++ } ++ else ++ { ++ /* The kernel task has a bootstrap port set. Perhaps it is its proc ++ server port from another Hurd. If so, propagate the kernel ++ argument locations from that Hurd rather than diddling with the ++ kernel task ourselves. */ ++ ++ vm_address_t kargv, kenvp; ++ err = proc_get_arg_locations (kbs, &kargv, &kenvp); ++ mach_port_deallocate (mach_task_self (), kbs); ++ if (err) ++ error (0, err, "kernel task bootstrap port (ignoring)"); ++ else ++ { ++ err = proc_set_arg_locations (proc, kargv, kenvp); ++ if (err) ++ error (0, err, "cannot propagate original kernel command line"); ++ else ++ { ++ mach_port_deallocate (mach_task_self (), proc); ++ mach_port_deallocate (mach_task_self (), task); ++ if (! fakeboot) ++ error (0, 0, "warning: " ++ "I see another Hurd, but --fake-boot was not given"); ++ return; ++ } ++ } ++ } ++ ++ /* Our arguments make up the multiboot command line used to boot the ++ kernel. We'll write into the kernel task a page containing a ++ canonical argv array and argz of those words. */ ++ ++ err = argz_create (&global_argv[1], &argz, &argzlen); ++ assert_perror (err); ++ argc = argz_count (argz, argzlen); ++ ++ windowsz = round_page (((argc + 1) * sizeof (char *)) + argzlen); ++ ++ mine = (vm_address_t) mmap (0, windowsz, PROT_READ|PROT_WRITE, ++ MAP_ANON, 0, 0); ++ assert (mine != -1); ++ err = vm_allocate (task, &his, windowsz, 1); ++ if (err) ++ { ++ error (0, err, "cannot allocate %Zu bytes in kernel task", windowsz); ++ free (argz); ++ mach_port_deallocate (mach_task_self (), proc); ++ mach_port_deallocate (mach_task_self (), task); ++ munmap ((caddr_t) mine, windowsz); ++ return; ++ } ++ ++ for (i = 0, entry = argz; entry != NULL; ++ ++i, entry = argz_next (argz, argzlen, entry)) ++ ((char **) mine)[i] = ((char *) &((char **) his)[argc + 1] ++ + (entry - argz)); ++ ((char **) mine)[argc] = NULL; ++ memcpy (&((char **) mine)[argc + 1], argz, argzlen); ++ ++ free (argz); ++ ++ /* We have the data all set up in our copy, now just write it over. */ ++ err = vm_write (task, his, mine, windowsz); ++ mach_port_deallocate (mach_task_self (), task); ++ munmap ((caddr_t) mine, windowsz); ++ if (err) ++ { ++ error (0, err, "cannot write command line into kernel task"); ++ return; ++ } ++ ++ /* The argument vector is set up in the kernel task at address HIS. ++ Finally, we can inform the proc server where to find it. */ ++ err = proc_set_arg_locations (proc, his, his + (argc * sizeof (char *))); ++ mach_port_deallocate (mach_task_self (), proc); ++ if (err) ++ error (0, err, "proc_set_arg_locations for kernel task"); ++} ++ ++/** Running userland. **/ ++ ++/* In the "split-init" setup, we just run a single program (usually ++ /libexec/runsystem) that is not expected to ever exit (or stop). ++ If it does exit (or can't be started), we go to an emergency single-user ++ shell as a fallback. */ ++ ++ ++static pid_t child_pid; /* PID of the child we run */ ++static task_t child_task; /* and its (original) task port */ ++ ++error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport, ++ mach_msg_timeout_t); ++ ++static void launch_something (const char *why); ++ ++ ++/* SIGNO has arrived and has been validated. Do whatever work it ++ implies. */ ++void ++process_signal (int signo) ++{ ++ if (signo == SIGCHLD) ++ { ++ /* A child died. Find its status. */ ++ int status; ++ pid_t pid; ++ ++ while (1) ++ { ++ pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED); ++ if (pid <= 0) ++ break; /* No more children. */ ++ ++ /* Since we are init, orphaned processes get reparented to us and ++ alas, all our adopted children eventually die. Woe is us. We ++ just need to reap the zombies to relieve the proc server of ++ its burden, and then we can forget about the little varmints. */ ++ ++ if (pid == child_pid) ++ { ++ /* The big magilla bit the dust. */ ++ ++ char *desc = 0; ++ ++ mach_port_deallocate (mach_task_self (), child_task); ++ child_task = MACH_PORT_NULL; ++ child_pid = -1; ++ ++ if (WIFSIGNALED (status)) ++ asprintf (&desc, "terminated abnormally (%s)", ++ strsignal (WTERMSIG (status))); ++ else if (WIFSTOPPED (status)) ++ asprintf (&desc, "stopped abnormally (%s)", ++ strsignal (WTERMSIG (status))); ++ else if (WEXITSTATUS (status) == 0) ++ desc = strdup ("finished"); ++ else ++ asprintf (&desc, "exited with status %d", ++ WEXITSTATUS (status)); ++ ++ { ++ char buf[40]; ++ snprintf (buf, sizeof buf, "%d", status); ++ setenv ("STATUS", buf, 1); ++ } ++ ++ launch_something (desc); ++ free (desc); ++ } ++ } ++ } ++ else ++ { ++ /* Pass the signal on to the child. */ ++ task_t task; ++ error_t err; ++ ++ err = proc_pid2task (procserver, child_pid, &task); ++ if (err) ++ { ++ error (0, err, "proc_pid2task on %d", child_pid); ++ task = child_task; ++ } ++ else ++ { ++ mach_port_deallocate (mach_task_self (), child_task); ++ child_task = task; ++ } ++ ++ if (signo == SIGKILL) ++ { ++ err = task_terminate (task); ++ if (err != MACH_SEND_INVALID_DEST) ++ error (0, err, "task_terminate"); ++ } ++ else ++ { ++ mach_port_t msgport; ++ err = proc_getmsgport (procserver, child_pid, &msgport); ++ if (err) ++ error (0, err, "proc_getmsgport"); ++ else ++ { ++ err = send_signal (msgport, signo, task, ++ 500); /* Block only half a second. */ ++ mach_port_deallocate (mach_task_self (), msgport); ++ if (err) ++ { ++ error (0, err, "cannot send %s to child %d", ++ strsignal (signo), child_pid); ++ err = task_terminate (task); ++ if (err != MACH_SEND_INVALID_DEST) ++ error (0, err, "task_terminate"); ++ } ++ } ++ } ++ } ++} ++ ++/* Start the child program PROG. It is run via /libexec/console-run ++ with the given additional arguments. */ ++static int ++start_child (const char *prog, char **progargs) ++{ ++ file_t file; ++ error_t err; ++ char *args; ++ size_t arglen; ++ ++ if (progargs == 0) ++ { ++ const char *argv[] = { "/libexec/console-run", prog, 0 }; ++ err = argz_create ((char **) argv, &args, &arglen); ++ } ++ else ++ { ++ int argc = 0; ++ while (progargs[argc] != 0) ++ ++argc; ++ { ++ const char *argv[2 + argc + 1]; ++ argv[0] = "/libexec/console-run"; ++ argv[1] = prog; ++ argv[2 + argc] = 0; ++ while (argc-- > 0) ++ argv[2 + argc] = progargs[argc]; ++ err = argz_create ((char **) argv, &args, &arglen); ++ } ++ } ++ assert_perror (err); ++ ++ file = file_name_lookup (args, O_EXEC, 0); ++ if (file == MACH_PORT_NULL) ++ { ++ error (0, errno, "%s", args); ++ free (args); ++ return -1; ++ } ++ ++ task_create (mach_task_self (), ++#ifdef KERN_INVALID_LEDGER ++ NULL, 0, /* OSF Mach */ ++#endif ++ 0, &child_task); ++ proc_set_init_task (procserver, child_task); ++ proc_task2pid (procserver, child_task, &child_pid); ++ proc_task2proc (procserver, child_task, &default_ports[INIT_PORT_PROC]); ++ ++ if (bootstrap_args & RB_KDB) ++ { ++ printf ("Pausing for %s\n", args); ++ getchar (); ++ } ++ ++ err = file_exec (file, child_task, 0, ++ args, arglen, ++ startup_envz, startup_envz_len, ++ NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */ ++ default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, ++ default_ints, INIT_INT_MAX, ++ NULL, 0, NULL, 0); ++ proc_mark_important (default_ports[INIT_PORT_PROC]); ++ mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]); ++ mach_port_deallocate (mach_task_self (), file); ++ if (err) ++ { ++ error (0, err, "Cannot execute %s", args); ++ free (args); ++ return -1; ++ } ++ free (args); ++ return 0; ++} ++ ++static void ++launch_something (const char *why) ++{ ++ file_t something; ++ static unsigned int try; ++ static const char *const tries[] = ++ { ++ "/libexec/runsystem", ++ _PATH_BSHELL, ++ "/bin/shd", /* XXX */ ++ }; ++ ++ if (why) ++ error (0, 0, "%s %s", tries[try - 1], why); ++ ++ something = file_name_lookup (tries[try], O_EXEC, 0); ++ if (something != MACH_PORT_NULL) ++ { ++ mach_port_deallocate (mach_task_self (), something); ++ if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0) ++ return; ++ } ++ else ++ try++; ++ ++ while (try < sizeof tries / sizeof tries[0]) ++ { ++ something = file_name_lookup (tries[try], O_EXEC, 0); ++ if (something != MACH_PORT_NULL) ++ { ++ mach_port_deallocate (mach_task_self (), something); ++ if (start_child (tries[try++], NULL) == 0) ++ return; ++ } ++ } ++ ++ crash_system (); ++} ++ ++void ++launch_system (void) ++{ ++ launch_something (0); ++} ++ ++/** RPC servers **/ ++ ++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) ++{ ++ static int authinit, procinit, execinit; ++ int fail; ++ ++ /* Always deallocate the extra reference this message carries. */ ++ if (MACH_PORT_VALID (credential)) ++ mach_port_deallocate (mach_task_self (), credential); ++ ++ if (credential != host_priv) ++ return EPERM; ++ ++ fail = record_essential_task (name, task); ++ if (fail) ++ return fail; ++ ++ if (!booted) ++ { ++ if (!strcmp (name, "auth")) ++ authinit = 1; ++ else if (!strcmp (name, "exec")) ++ { ++ execinit = 1; ++ mach_port_t execproc; ++ proc_task2proc (procserver, task, &execproc); ++ proc_mark_important (execproc); ++ } ++ 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); ++ ++ init_stdarrays (); ++ frob_kernel_process (); ++ ++ launch_system (); ++ ++ booted = 1; ++ ++ return MIG_NO_REPLY; ++ } ++ } ++ ++ return 0; ++} ++ ++kern_return_t ++S_startup_request_notification (mach_port_t server, ++ mach_port_t notify, ++ char *name) ++{ ++ struct ntfy_task *nt; ++ ++ request_dead_name (notify); ++ ++ /* Note that the ntfy_tasks list is kept in inverse order of the ++ calls; this is important. We need later notification requests ++ to get executed first. */ ++ nt = malloc (sizeof (struct ntfy_task)); ++ nt->notify_port = notify; ++ nt->next = ntfy_tasks; ++ ntfy_tasks = nt; ++ nt->name = malloc (strlen (name) + 1); ++ strcpy (nt->name, name); ++ 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; ++ ++ assert (notify == startup); ++ ++ /* Deallocate the extra reference the notification carries. */ ++ mach_port_deallocate (mach_task_self (), name); ++ ++ for (et = ess_tasks; et != NULL; et = et->next) ++ if (et->task_port == name) ++ /* An essential task has died. */ ++ { ++ error (0, 0, "Crashing system; essential task %s died", et->name); ++ 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; ++ } ++ ++ if (! booted) ++ { ++ /* The system has not come up yet, so essential tasks are not yet ++ registered. But the essential servers involved in the bootstrap ++ handshake might crash before completing it, so we have requested ++ dead-name notification on those tasks. */ ++ static const struct { task_t *taskp; const char *name; } boots[] = ++ { ++ {&fstask, "bootstrap filesystem"}, ++ {&authtask, "auth"}, ++ {&proctask, "proc"}, ++ }; ++ size_t i; ++ for (i = 0; i < sizeof boots / sizeof boots[0]; ++i) ++ if (name == *boots[i].taskp) ++ { ++ error (0, 0, "Crashing system; %s server died during bootstrap", ++ boots[i].name); ++ crash_mach (); ++ } ++ error (0, 0, "BUG! Unexpected dead-name notification (name %#zx)", ++ name); ++ crash_mach (); ++ } ++ ++ 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 (;;); ++} ++ ++/* Stubs for unused notification RPCs. */ ++ ++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; ++} ++ ++/* msg server */ ++ ++kern_return_t ++S_msg_sig_post_untraced (mach_port_t msgport, ++ mach_port_t reply, mach_msg_type_name_t reply_type, ++ int signo, natural_t sigcode, mach_port_t refport) ++{ ++ if (refport != mach_task_self ()) ++ return EPERM; ++ mach_port_deallocate (mach_task_self (), refport); ++ ++ /* Reply immediately */ ++ msg_sig_post_untraced_reply (reply, reply_type, 0); ++ ++ process_signal (signo); ++ return MIG_NO_REPLY; ++} ++ ++kern_return_t ++S_msg_sig_post (mach_port_t msgport, ++ mach_port_t reply, mach_msg_type_name_t reply_type, ++ int signo, natural_t sigcode, mach_port_t refport) ++{ ++ if (refport != mach_task_self ()) ++ return EPERM; ++ mach_port_deallocate (mach_task_self (), refport); ++ ++ /* Reply immediately */ ++ msg_sig_post_reply (reply, reply_type, 0); ++ ++ process_signal (signo); ++ return MIG_NO_REPLY; ++} ++ ++ ++/* For the rest of the msg functions, just call the C library's ++ internal server stubs usually run in the signal thread. */ ++ ++kern_return_t ++S_msg_proc_newids (mach_port_t process, ++ mach_port_t task, ++ pid_t ppid, ++ pid_t pgrp, ++ int orphaned) ++{ return _S_msg_proc_newids (process, task, ppid, pgrp, orphaned); } ++ ++ ++kern_return_t ++S_msg_add_auth (mach_port_t process, ++ auth_t auth) ++{ return _S_msg_add_auth (process, auth); } ++ ++ ++kern_return_t ++S_msg_del_auth (mach_port_t process, ++ mach_port_t task, ++ intarray_t uids, ++ mach_msg_type_number_t uidsCnt, ++ intarray_t gids, ++ mach_msg_type_number_t gidsCnt) ++{ return _S_msg_del_auth (process, task, uids, uidsCnt, gids, gidsCnt); } ++ ++ ++kern_return_t ++S_msg_get_init_port (mach_port_t process, ++ mach_port_t refport, ++ int which, ++ mach_port_t *port, ++ mach_msg_type_name_t *portPoly) ++{ return _S_msg_get_init_port (process, refport, which, port, portPoly); } ++ ++ ++kern_return_t ++S_msg_set_init_port (mach_port_t process, ++ mach_port_t refport, ++ int which, ++ mach_port_t port) ++{ return _S_msg_set_init_port (process, refport, which, port); } ++ ++ ++kern_return_t ++S_msg_get_init_ports (mach_port_t process, ++ mach_port_t refport, ++ portarray_t *ports, ++ mach_msg_type_name_t *portsPoly, ++ mach_msg_type_number_t *portsCnt) ++{ return _S_msg_get_init_ports (process, refport, ports, portsPoly, portsCnt); } ++ ++ ++kern_return_t ++S_msg_set_init_ports (mach_port_t process, ++ mach_port_t refport, ++ portarray_t ports, ++ mach_msg_type_number_t portsCnt) ++{ return _S_msg_set_init_ports (process, refport, ports, portsCnt); } ++ ++ ++kern_return_t ++S_msg_get_init_int (mach_port_t process, ++ mach_port_t refport, ++ int which, ++ int *value) ++{ return _S_msg_get_init_int (process, refport, which, value); } ++ ++ ++kern_return_t ++S_msg_set_init_int (mach_port_t process, ++ mach_port_t refport, ++ int which, ++ int value) ++{ return _S_msg_set_init_int (process, refport, which, value); } ++ ++ ++kern_return_t ++S_msg_get_init_ints (mach_port_t process, ++ mach_port_t refport, ++ intarray_t *values, ++ mach_msg_type_number_t *valuesCnt) ++{ return _S_msg_get_init_ints (process, refport, values, valuesCnt); } ++ ++ ++kern_return_t ++S_msg_set_init_ints (mach_port_t process, ++ mach_port_t refport, ++ intarray_t values, ++ mach_msg_type_number_t valuesCnt) ++{ return _S_msg_set_init_ints (process, refport, values, valuesCnt); } ++ ++ ++kern_return_t ++S_msg_get_dtable (mach_port_t process, ++ mach_port_t refport, ++ portarray_t *dtable, ++ mach_msg_type_name_t *dtablePoly, ++ mach_msg_type_number_t *dtableCnt) ++{ return _S_msg_get_dtable (process, refport, dtable, dtablePoly, dtableCnt); } ++ ++ ++kern_return_t ++S_msg_set_dtable (mach_port_t process, ++ mach_port_t refport, ++ portarray_t dtable, ++ mach_msg_type_number_t dtableCnt) ++{ return _S_msg_set_dtable (process, refport, dtable, dtableCnt); } ++ ++ ++kern_return_t ++S_msg_get_fd (mach_port_t process, ++ mach_port_t refport, ++ int fd, ++ mach_port_t *port, ++ mach_msg_type_name_t *portPoly) ++{ return _S_msg_get_fd (process, refport, fd, port, portPoly); } ++ ++ ++kern_return_t ++S_msg_set_fd (mach_port_t process, ++ mach_port_t refport, ++ int fd, ++ mach_port_t port) ++{ return _S_msg_set_fd (process, refport, fd, port); } ++ ++ ++kern_return_t ++S_msg_get_environment (mach_port_t process, ++ data_t *value, ++ mach_msg_type_number_t *valueCnt) ++{ return _S_msg_get_environment (process, value, valueCnt); } ++ ++ ++kern_return_t ++S_msg_set_environment (mach_port_t process, ++ mach_port_t refport, ++ data_t value, ++ mach_msg_type_number_t valueCnt) ++{ return _S_msg_set_environment (process, refport, value, valueCnt); } ++ ++ ++kern_return_t ++S_msg_get_env_variable (mach_port_t process, ++ string_t variable, ++ data_t *value, ++ mach_msg_type_number_t *valueCnt) ++{ return _S_msg_get_env_variable (process, variable, value, valueCnt); } ++ ++ ++kern_return_t ++S_msg_set_env_variable (mach_port_t process, ++ mach_port_t refport, ++ string_t variable, ++ string_t value, ++ boolean_t replace) ++{ return _S_msg_set_env_variable (process, refport, variable, value, replace); } ++ ++error_t ++S_msg_describe_ports (mach_port_t process, ++ mach_port_t refport, ++ mach_port_array_t names, ++ mach_msg_type_number_t namesCnt, ++ data_t *descriptions, ++ mach_msg_type_number_t *descriptionsCnt) ++{ ++ return _S_msg_describe_ports (process, refport, names, namesCnt, ++ descriptions, descriptionsCnt); ++} ++ ++error_t ++S_msg_report_wait (mach_port_t process, thread_t thread, ++ string_t desc, mach_msg_id_t *rpc) ++{ ++ *desc = 0; ++ *rpc = 0; ++ return 0; ++} +diff --git a/startup/stubs.c b/startup/stubs.c +new file mode 100644 +index 0000000..5292ab6 +--- /dev/null ++++ b/startup/stubs.c +@@ -0,0 +1,139 @@ ++/* By-hand stubs for some RPC calls ++ Copyright (C) 1994,96,99,2000 Free Software Foundation, Inc. ++ ++ This program 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. ++ ++ This program 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 this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++ ++#include <stdlib.h> ++#include <hurd/hurd_types.h> ++#include <mach.h> ++#include <string.h> ++#include <assert.h> ++ ++/* From hurd/msg.defs: */ ++#define RPCID_SIG_POST 23000 ++ ++ ++/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't ++ block in any fashion. */ ++error_t ++send_signal (mach_port_t msgport, ++ int signal, ++ mach_port_t refport, ++ mach_msg_timeout_t timeout) ++{ ++ error_t err; ++ ++ /* This message buffer might be modified by mach_msg in some error cases, ++ so we cannot safely reuse a static buffer. */ ++ struct ++ { ++ mach_msg_header_t head; ++ mach_msg_type_t signaltype; ++ int signal; ++ mach_msg_type_t sigcode_type; ++ natural_t sigcode; ++ mach_msg_type_t refporttype; ++ mach_port_t refport; ++ } ++ message = ++ { ++ { ++ /* Message header: */ ++ (MACH_MSGH_BITS_COMPLEX ++ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, ++ MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ ++ sizeof message, /* msgh_size */ ++ msgport, /* msgh_remote_port */ ++ MACH_PORT_NULL, /* msgh_local_port */ ++ 0, /* msgh_seqno */ ++ RPCID_SIG_POST, /* msgh_id */ ++ }, ++ { ++ /* Type descriptor for signo */ ++ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ ++ 32, /* msgt_size */ ++ 1, /* msgt_number */ ++ 1, /* msgt_inline */ ++ 0, /* msgt_longform */ ++ 0, /* msgt_deallocate */ ++ 0, /* msgt_unused */ ++ }, ++ /* Signal number */ ++ signal, ++ /* Type descriptor for sigcode */ ++ { ++ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ ++ 32, /* msgt_size */ ++ 1, /* msgt_number */ ++ 1, /* msgt_inline */ ++ 0, /* msgt_longform */ ++ 0, /* msgt_deallocate */ ++ 0, /* msgt_unused */ ++ }, ++ /* Sigcode */ ++ 0, ++ { ++ /* Type descriptor for refport */ ++ MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ ++ 32, /* msgt_size */ ++ 1, /* msgt_number */ ++ 1, /* msgt_inline */ ++ 0, /* msgt_longform */ ++ 0, /* msgt_deallocate */ ++ 0, /* msgt_unused */ ++ }, ++ /* Reference port */ ++ refport ++ }; ++ ++ err = mach_msg (&message.head, ++ MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, ++ MACH_PORT_NULL, timeout, MACH_PORT_NULL); ++ ++ switch (err) ++ { ++ case MACH_SEND_TIMED_OUT: ++ /* The send could not complete in time. In this error case, the ++ kernel has modified the message buffer in a pseudo-receive ++ operation. That means our COPY_SEND refs might now be MOVE_SEND ++ refs, in which case each has gained user ref accordingly. To ++ avoid leaking those refs, we must clean up the buffer. We don't ++ use mach_msg_destroy because it assumes the local/remote ports in ++ the header have been reversed as from a real receive, while a ++ pseudo-receive leaves them as they were. */ ++ if (MACH_MSGH_BITS_REMOTE (message.head.msgh_bits) ++ == MACH_MSG_TYPE_MOVE_SEND) ++ mach_port_deallocate (mach_task_self (), ++ message.head.msgh_remote_port); ++ if (message.refporttype.msgt_name == MACH_MSG_TYPE_MOVE_SEND) ++ mach_port_deallocate (mach_task_self (), message.refport); ++ break; ++ ++ /* These are the other codes that mean a pseudo-receive modified ++ the message buffer and we might need to clean up the send rights. ++ None of them should be possible in our usage. */ ++ case MACH_SEND_INTERRUPTED: ++ case MACH_SEND_INVALID_NOTIFY: ++ case MACH_SEND_NO_NOTIFY: ++ case MACH_SEND_NOTIFY_IN_PROGRESS: ++ assert_perror (err); ++ break; ++ ++ default: /* Other errors are safe to ignore. */ ++ break; ++ } ++ ++ return err; ++} +-- +2.1.0 + |