summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-09-02 23:18:57 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-09-02 23:18:57 +0200
commitb729fbad76622a759c97013989a7df489addfde8 (patch)
tree0ce7b316d031d0d9925215e8b0f5b968df62939a /debian/patches
parenta4a8673373d080d6947a7a026af0ec9932ce96f1 (diff)
add patch series
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/0001-libdiskfs-fix-servers-exec-lookup.patch27
-rw-r--r--debian/patches/0002-Add-proc_set_init_task-make-runsystem-pid-1.patch327
-rw-r--r--debian/patches/0003-startup-rename-init-to-startup.patch3649
-rw-r--r--debian/patches/0004-Add-a-minimalist-init-program.patch537
-rw-r--r--debian/patches/0005-startup-do-not-pass-signals-on-to-the-child.patch251
-rw-r--r--debian/patches/0006-startup-be-more-specific-in-the-shutdown-message.patch29
-rw-r--r--debian/patches/0007-startup-fix-the-declaration-of-the-_server-functions.patch28
-rw-r--r--debian/patches/0008-poc-servers-startup.patch188
-rw-r--r--debian/patches/series8
9 files changed, 5044 insertions, 0 deletions
diff --git a/debian/patches/0001-libdiskfs-fix-servers-exec-lookup.patch b/debian/patches/0001-libdiskfs-fix-servers-exec-lookup.patch
new file mode 100644
index 00000000..0e9e9d2f
--- /dev/null
+++ b/debian/patches/0001-libdiskfs-fix-servers-exec-lookup.patch
@@ -0,0 +1,27 @@
+From 626ff916ca63334e6c170f059ea47f9cfea19661 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Tue, 2 Sep 2014 22:19:54 +0200
+Subject: [PATCH 1/8] libdiskfs: fix /servers/exec lookup
+
+* libdiskfs/boot-start.c (diskfs_start_bootstrap): Pass retry_name to
+dir_lookup, which is later checked to be the empty string.
+---
+ libdiskfs/boot-start.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c
+index 4cc7bb8..a590975 100644
+--- a/libdiskfs/boot-start.c
++++ b/libdiskfs/boot-start.c
+@@ -178,7 +178,7 @@ diskfs_start_bootstrap ()
+ /* Attempt to set the active translator for the exec server so that
+ filesystems other than the bootstrap can find it. */
+ err = dir_lookup (root_pt, _SERVERS_EXEC, O_NOTRANS, 0,
+- &retry, pathbuf, &execnode);
++ &retry, retry_name, &execnode);
+ if (err)
+ {
+ error (0, err, "cannot set translator on %s", _SERVERS_EXEC);
+--
+2.1.0
+
diff --git a/debian/patches/0002-Add-proc_set_init_task-make-runsystem-pid-1.patch b/debian/patches/0002-Add-proc_set_init_task-make-runsystem-pid-1.patch
new file mode 100644
index 00000000..7de211d8
--- /dev/null
+++ b/debian/patches/0002-Add-proc_set_init_task-make-runsystem-pid-1.patch
@@ -0,0 +1,327 @@
+From 19405120ae3c3897bad0d458df0818e015f017ab Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 18 Sep 2013 15:59:31 +0200
+Subject: [PATCH 2/8] Add proc_set_init_task, make runsystem pid 1
+
+* hurd/process.defs (proc_set_init_task): New procedure.
+* hurd/process_reply.defs (proc_set_init_task): Likewise.
+* hurd/process_request.defs (proc_set_init_task): Likewise.
+* include/pids.h: Add HURD_PID_INIT as 1, adjust others accordingly.
+* init/init.c (start_child): Register the child task.
+* proc/proc.h (init_proc): New variable.
+(create_startup_proc): Rename to create_init_proc.
+* proc/main.c (main): Create placeholder proc object for pid 1.
+* proc/mgt.c: Use init_proc instead of startup_proc, as the former is
+ the new root of the process tree.
+(create_startup_proc): Rename to create_init_proc.
+(S_proc_set_init_task): New function.
+---
+ hurd/process.defs | 6 +++-
+ hurd/process_reply.defs | 2 +-
+ hurd/process_request.defs | 7 ++++-
+ include/pids.h | 7 +++--
+ init/init.c | 2 +-
+ proc/main.c | 9 ++++--
+ proc/mgt.c | 76 ++++++++++++++++++++++++++++++++++-------------
+ proc/proc.h | 8 +++--
+ 8 files changed, 85 insertions(+), 32 deletions(-)
+
+diff --git a/hurd/process.defs b/hurd/process.defs
+index bf90556..498faba 100644
+--- a/hurd/process.defs
++++ b/hurd/process.defs
+@@ -373,7 +373,11 @@ routine proc_getnports (
+
+ /*** Routines related to early server bootstrapping ***/
+
+-skip; /* Reserved for proc_set_init_task */
++/* Set the task of process HURD_PID_INIT. Only the startup process
++ HURD_PID_STARTUP may use this interface. */
++routine proc_set_init_task (
++ process: process_t;
++ task: task_t);
+
+ /* Inform the process server that the process is important. */
+ routine proc_mark_important (
+diff --git a/hurd/process_reply.defs b/hurd/process_reply.defs
+index ed46d55..80454a6 100644
+--- a/hurd/process_reply.defs
++++ b/hurd/process_reply.defs
+@@ -177,7 +177,7 @@ simpleroutine proc_getnports_reply (
+
+ /*** Routines related to early server bootstrapping ***/
+
+-skip; /* Reserved for proc_set_init_task */
++skip; /* proc_set_init_task */
+ skip; /* proc_mark_important */
+
+ simpleroutine proc_is_important_reply (
+diff --git a/hurd/process_request.defs b/hurd/process_request.defs
+index 38e7146..7565f03 100644
+--- a/hurd/process_request.defs
++++ b/hurd/process_request.defs
+@@ -374,7 +374,12 @@ simpleroutine proc_getnports_request (
+
+ /*** Routines related to early server bootstrapping ***/
+
+-skip; /* Reserved for proc_set_init_task */
++/* Set the task of process HURD_PID_INIT. Only the startup process
++ HURD_PID_STARTUP may use this interface. */
++simpleroutine proc_set_init_task_request (
++ process: process_t;
++ ureplyport reply: reply_port_t;
++ task: task_t);
+
+ /* Inform the process server that the process is important. */
+ simpleroutine proc_mark_important_request (
+diff --git a/include/pids.h b/include/pids.h
+index 22415f4..dff7635 100644
+--- a/include/pids.h
++++ b/include/pids.h
+@@ -22,8 +22,9 @@
+ #ifndef _HURD_PROCESSES_H
+ #define _HURD_PROCESSES_H
+
+-#define HURD_PID_STARTUP 1
+-#define HURD_PID_KERNEL 2
+-#define HURD_PID_PROC 3
++#define HURD_PID_INIT 1
++#define HURD_PID_STARTUP 2
++#define HURD_PID_KERNEL 3
++#define HURD_PID_PROC 4
+
+ #endif /* _HURD_PROCESSES_H */
+diff --git a/init/init.c b/init/init.c
+index b7b40bd..6bc6701 100644
+--- a/init/init.c
++++ b/init/init.c
+@@ -1058,7 +1058,7 @@ start_child (const char *prog, char **progargs)
+ NULL, 0, /* OSF Mach */
+ #endif
+ 0, &child_task);
+- proc_child (procserver, 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]);
+
+diff --git a/proc/main.c b/proc/main.c
+index 73742ed..f1f4e1b 100644
+--- a/proc/main.c
++++ b/proc/main.c
+@@ -1,5 +1,5 @@
+ /* Initialization of the proc server
+- Copyright (C) 1993,94,95,96,97,99,2000,01 Free Software Foundation, Inc.
++ Copyright (C) 1993,94,95,96,97,99,2000,01,13 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -88,7 +88,12 @@ main (int argc, char **argv, char **envp)
+ generic_port = ports_get_right (genport);
+
+ /* Create the initial proc object for init (PID 1). */
+- startup_proc = create_startup_proc ();
++ init_proc = create_init_proc ();
++
++ /* Create the startup proc object for /hurd/init (PID 2). */
++ startup_proc = allocate_proc (MACH_PORT_NULL);
++ startup_proc->p_deadmsg = 1;
++ complete_proc (startup_proc, HURD_PID_STARTUP);
+
+ /* Create our own proc object. */
+ self_proc = allocate_proc (mach_task_self ());
+diff --git a/proc/mgt.c b/proc/mgt.c
+index b8aa0fc..02d69db 100644
+--- a/proc/mgt.c
++++ b/proc/mgt.c
+@@ -1,5 +1,6 @@
+ /* Process management
+- Copyright (C) 1992,93,94,95,96,99,2000,01,02 Free Software Foundation, Inc.
++ Copyright (C) 1992,93,94,95,96,99,2000,01,02,13
++ Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -184,7 +185,7 @@ S_proc_child (struct proc *parentp,
+ /* Process hierarchy. Remove from our current location
+ and place us under our new parent. Sanity check to make sure
+ parent is currently init. */
+- assert (childp->p_parent == startup_proc);
++ assert (childp->p_parent == init_proc);
+ if (childp->p_sib)
+ childp->p_sib->p_prevsib = childp->p_prevsib;
+ *childp->p_prevsib = childp->p_sib;
+@@ -586,7 +587,7 @@ allocate_proc (task_t task)
+ /* Allocate and initialize the proc structure for init (PID 1),
+ the original parent of all other procs. */
+ struct proc *
+-create_startup_proc (void)
++create_init_proc (void)
+ {
+ static const uid_t zero;
+ struct proc *p;
+@@ -595,7 +596,7 @@ create_startup_proc (void)
+ p = allocate_proc (MACH_PORT_NULL);
+ assert (p);
+
+- p->p_pid = HURD_PID_STARTUP;
++ p->p_pid = HURD_PID_INIT;
+
+ p->p_parent = p;
+ p->p_sib = 0;
+@@ -643,7 +644,7 @@ proc_death_notify (struct proc *p)
+ }
+
+ /* Complete a new process that has been allocated but not entirely initialized.
+- This gets called for every process except startup_proc (PID 1). */
++ This gets called for every process except init_proc (PID 1). */
+ void
+ complete_proc (struct proc *p, pid_t pid)
+ {
+@@ -662,30 +663,47 @@ complete_proc (struct proc *p, pid_t pid)
+
+ p->p_pid = pid;
+
+- ids_ref (&nullids);
+- p->p_id = &nullids;
++ if (pid == HURD_PID_STARTUP)
++ {
++ /* Equip HURD_PID_STARTUP with the same credentials as
++ HURD_PID_INIT. */
++ static const uid_t zero;
++ p->p_id = make_ids (&zero, 1);
++ assert (p->p_id);
++ }
++ else
++ {
++ ids_ref (&nullids);
++ p->p_id = &nullids;
++ }
+
+ p->p_login = nulllogin;
+ p->p_login->l_refcnt++;
+
+ /* Our parent is init for now. */
+- p->p_parent = startup_proc;
++ p->p_parent = init_proc;
+
+- p->p_sib = startup_proc->p_ochild;
+- p->p_prevsib = &startup_proc->p_ochild;
++ p->p_sib = init_proc->p_ochild;
++ p->p_prevsib = &init_proc->p_ochild;
+ if (p->p_sib)
+ p->p_sib->p_prevsib = &p->p_sib;
+- startup_proc->p_ochild = p;
++ init_proc->p_ochild = p;
+ p->p_loginleader = 0;
+ p->p_ochild = 0;
+ p->p_parentset = 0;
+
+ p->p_noowner = 1;
+
+- p->p_pgrp = startup_proc->p_pgrp;
++ p->p_pgrp = init_proc->p_pgrp;
+
+- proc_death_notify (p);
+- add_proc_to_hash (p);
++ /* At this point, we do not know the task of the startup process,
++ defer registering death notifications and adding it to the hash
++ tables. */
++ if (pid != HURD_PID_STARTUP)
++ {
++ proc_death_notify (p);
++ add_proc_to_hash (p);
++ }
+ join_pgrp (p);
+ }
+
+@@ -747,7 +765,7 @@ process_has_exited (struct proc *p)
+ nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
+ 1, tp->p_pgrp->pg_pgid,
+ !tp->p_pgrp->pg_orphcnt);
+- tp->p_parent = startup_proc;
++ tp->p_parent = init_proc;
+ if (tp->p_dead)
+ isdead = 1;
+ }
+@@ -755,17 +773,17 @@ process_has_exited (struct proc *p)
+ nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
+ 1, tp->p_pgrp->pg_pgid,
+ !tp->p_pgrp->pg_orphcnt);
+- tp->p_parent = startup_proc;
++ tp->p_parent = init_proc;
+
+ /* And now append the lists. */
+- tp->p_sib = startup_proc->p_ochild;
++ tp->p_sib = init_proc->p_ochild;
+ if (tp->p_sib)
+ tp->p_sib->p_prevsib = &tp->p_sib;
+- startup_proc->p_ochild = p->p_ochild;
+- p->p_ochild->p_prevsib = &startup_proc->p_ochild;
++ init_proc->p_ochild = p->p_ochild;
++ p->p_ochild->p_prevsib = &init_proc->p_ochild;
+
+ if (isdead)
+- alert_parent (startup_proc);
++ alert_parent (init_proc);
+ }
+
+ /* If an operation is in progress for this process, cause it
+@@ -883,6 +901,24 @@ genpid ()
+ return nextpid++;
+ }
+
++/* Implement proc_set_init_task as described in <hurd/process.defs>. */
++error_t
++S_proc_set_init_task(struct proc *callerp,
++ task_t task)
++{
++ if (! callerp)
++ return EOPNOTSUPP;
++
++ if (callerp != startup_proc)
++ return EPERM;
++
++ init_proc->p_task = task;
++ proc_death_notify (init_proc);
++ add_proc_to_hash (init_proc);
++
++ return 0;
++}
++
+ /* Implement proc_mark_important as described in <hurd/process.defs>. */
+ kern_return_t
+ S_proc_mark_important (struct proc *p)
+diff --git a/proc/proc.h b/proc/proc.h
+index a2e3c53..6196697 100644
+--- a/proc/proc.h
++++ b/proc/proc.h
+@@ -1,5 +1,6 @@
+ /* Process server definitions
+- Copyright (C) 1992,93,94,95,96,99,2000,01 Free Software Foundation, Inc.
++ Copyright (C) 1992,93,94,95,96,99,2000,01,13
++ Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -134,7 +135,8 @@ struct exc
+
+ mach_port_t authserver;
+ struct proc *self_proc; /* process HURD_PID_PROC (us) */
+-struct proc *startup_proc; /* process 1 (init) */
++struct proc *init_proc; /* process 1 (sysvinit) */
++struct proc *startup_proc; /* process 2 (hurd/init) */
+
+ struct port_bucket *proc_bucket;
+ struct port_class *proc_class;
+@@ -183,7 +185,7 @@ void exc_clean (void *);
+ struct proc *add_tasks (task_t);
+ int pidfree (pid_t);
+
+-struct proc *create_startup_proc (void);
++struct proc *create_init_proc (void);
+ struct proc *allocate_proc (task_t);
+ void proc_death_notify (struct proc *);
+ void complete_proc (struct proc *, pid_t);
+--
+2.1.0
+
diff --git a/debian/patches/0003-startup-rename-init-to-startup.patch b/debian/patches/0003-startup-rename-init-to-startup.patch
new file mode 100644
index 00000000..14126788
--- /dev/null
+++ b/debian/patches/0003-startup-rename-init-to-startup.patch
@@ -0,0 +1,3649 @@
+From 5f316bb5355ad4462884ca1b730b81d2cba8afab 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 init to startup
+
+---
+ Makefile | 3 +-
+ 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 ++++
+ 10 files changed, 1768 insertions(+), 1767 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/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
+
diff --git a/debian/patches/0004-Add-a-minimalist-init-program.patch b/debian/patches/0004-Add-a-minimalist-init-program.patch
new file mode 100644
index 00000000..98185b53
--- /dev/null
+++ b/debian/patches/0004-Add-a-minimalist-init-program.patch
@@ -0,0 +1,537 @@
+From 78672310f29185d1a9605dfc1b2fc4f4c8d6def3 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 18 Sep 2013 15:29:36 +0200
+Subject: [PATCH 4/8] Add a minimalist init program
+
+---
+ Makefile | 1 +
+ daemons/runsystem.hurd | 142 ++++++++++++++++++++++++++++++++++++++++++++
+ daemons/runsystem.sh | 90 ++++++++++------------------
+ init/Makefile | 24 ++++++++
+ init/init.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 352 insertions(+), 60 deletions(-)
+ create mode 100644 daemons/runsystem.hurd
+ create mode 100644 init/Makefile
+ create mode 100644 init/init.c
+
+diff --git a/Makefile b/Makefile
+index 455df67..3178740 100644
+--- a/Makefile
++++ b/Makefile
+@@ -41,6 +41,7 @@ prog-subdirs = auth proc exec term \
+ random \
+ procfs \
+ startup \
++ init \
+
+ ifeq ($(HAVE_SUN_RPC),yes)
+ prog-subdirs += nfs nfsd
+diff --git a/daemons/runsystem.hurd b/daemons/runsystem.hurd
+new file mode 100644
+index 0000000..c3cb2d6
+--- /dev/null
++++ b/daemons/runsystem.hurd
+@@ -0,0 +1,142 @@
++#!/bin/bash
++#
++# This program is run by /hurd/init at boot time after the essential
++# servers are up, and is responsible for running the "userland" parts of a
++# normal system. This includes running the single-user shell as well as a
++# multi-user system. This program is expected never to exit.
++#
++
++
++###
++### Where to find programs, etc.
++###
++
++PATH=/bin:/sbin
++export PATH
++
++umask 022
++
++# If we lose badly, try to exec each of these in turn.
++fallback_shells='/bin/sh /bin/bash /bin/csh /bin/ash /bin/shd'
++
++# Shell used for normal single-user startup.
++SHELL=/bin/sh
++
++# Programs that do multi-user startup.
++RUNCOM=/libexec/rc
++RUNTTYS=/libexec/runttys
++# Signals that we should pass down to runttys.
++runttys_sigs='TERM INT HUP TSTP'
++
++###
++
++
++# If we get a SIGLOST, attempt to reopen the console in case
++# our console ports were revoked. This lets us print messages.
++function reopen_console ()
++{
++ exec 1>/dev/console 2>&1 || exit 3
++}
++trap 'reopen_console' SIGLOST
++
++
++# Call this when we are losing badly enough that we want to punt normal
++# startup entirely. We exec a single-user shell, so we will not come back
++# here. The only way to get to multi-user from that shell will be
++# explicitly exec this script or something like that.
++function singleuser ()
++{
++ test $# -eq 0 || echo "$0: $*"
++ for try in ${fallback_shells}; do
++ SHELL=${try}
++ exec ${SHELL}
++ done
++ exit 127
++}
++
++
++# We expect to be started by console-run, which gives us no arguments and
++# puts FALLBACK_CONSOLE=file-name in the environment if our console is
++# other than a normal /dev/console.
++
++if [ "${FALLBACK_CONSOLE+set}" = set ]; then
++ singleuser "Running on fallback console ${FALLBACK_CONSOLE}"
++fi
++
++
++###
++### Normal startup procedures
++###
++
++# Parse the multiboot command line. We only pay attention to -s and -f.
++# The first argument is the kernel file name; skip that.
++shift
++flags=
++while [ $# -gt 0 ]; do
++ arg="$1"
++ shift
++ case "$arg" in
++ --*) ;;
++ *=*) ;;
++ -*)
++ flags="${flags}${arg#-}"
++ ;;
++ 'single'|'emergency') # Linux compat
++ flags="${flags}s"
++ ;;
++ 'fastboot')
++ flags="${flags}f"
++ ;;
++ esac
++done
++
++# Check boot flags.
++case "$flags" in
++*s*)
++ rc=false # force single-user
++ ;;
++*f*)
++ rc="${RUNCOM}" # fastboot
++ ;;
++*)
++ rc="${RUNCOM} autoboot" # multi-user default
++ ;;
++esac
++
++# Large infinite loop. If this script ever exits, init considers that
++# a serious bogosity and punts to a fallback single-user shell.
++# We handle here the normal transitions between single-user and multi-user.
++while : ; do
++
++ # Run the rc script. As long as it exits nonzero, punt to single-user.
++ # After the single-user shell exits, we will start over attempting to
++ # run rc; but later invocations strip the `autoboot' argument.
++ until $rc; do
++ rc=${RUNCOM}
++
++ # Run single-user shell and repeat as long as it dies with a signal.
++ until ${SHELL} || test $? -lt 128; do
++ :
++ done
++ done
++
++ # Now we are officially ready for normal multi-user operation.
++
++ # Trap certain signals and send them on to runttys. For this to work, we
++ # must run it asynchronously and wait for it with the `wait' built-in.
++ runttys_pid=0
++ for sig in $runttys_sigs; do
++ trap "kill -$sig \${runttys_pid}" $sig
++ done
++
++ # This program reads /etc/ttys and starts the programs it says to.
++ ${RUNTTYS} &
++ runttys_pid=$!
++
++ # Wait for runttys to die, meanwhile handling trapped signals.
++ wait
++
++ # Go back to the top of the infinite loop, as if booting single-user.
++ rc=false
++
++done
+diff --git a/daemons/runsystem.sh b/daemons/runsystem.sh
+index f4f2771..39447ca 100644
+--- a/daemons/runsystem.sh
++++ b/daemons/runsystem.sh
+@@ -1,9 +1,9 @@
+ #!/bin/bash
+ #
+ # This program is run by /hurd/init at boot time after the essential
+-# servers are up, and is responsible for running the "userland" parts of a
+-# normal system. This includes running the single-user shell as well as a
+-# multi-user system. This program is expected never to exit.
++# servers are up. It does some initialization of its own and then
++# execs the SysV init to bring up the "userland" parts of a normal
++# system.
+ #
+
+
+@@ -22,29 +22,27 @@ fallback_shells='/bin/sh /bin/bash /bin/csh /bin/ash /bin/shd'
+ # Shell used for normal single-user startup.
+ SHELL=/bin/sh
+
+-# Programs that do multi-user startup.
+-RUNCOM=/libexec/rc
+-RUNTTYS=/libexec/runttys
+-# Signals that we should pass down to runttys.
+-runttys_sigs='TERM INT HUP TSTP'
++# The init program to call.
++#
++# Can be overridden using init=something in the kernel command line.
++init=/sbin/init
+
+ ###
+
+-
+ # If we get a SIGLOST, attempt to reopen the console in case
+ # our console ports were revoked. This lets us print messages.
+-function reopen_console ()
++reopen_console ()
+ {
+ exec 1>/dev/console 2>&1 || exit 3
+ }
+-trap 'reopen_console' SIGLOST
++trap 'reopen_console' 32 # SIGLOST = server died on GNU
+
+
+ # Call this when we are losing badly enough that we want to punt normal
+ # startup entirely. We exec a single-user shell, so we will not come back
+ # here. The only way to get to multi-user from that shell will be
+ # explicitly exec this script or something like that.
+-function singleuser ()
++singleuser()
+ {
+ test $# -eq 0 || echo "$0: $*"
+ for try in ${fallback_shells}; do
+@@ -54,12 +52,14 @@ function singleuser ()
+ exit 127
+ }
+
++# Print a newline.
++echo
+
+-# See whether pflocal is set up already, and do so if not (install case)
++# See whether pflocal is setup
+ #
+ # Normally this should be the case, but we better make sure since
+ # without the pflocal server, pipe(2) does not work.
+-if ! test -e /servers/socket/1 ; then
++if ! test -e /servers/socket/1 && which settrans >/dev/null ; then
+ # The root filesystem should be read-only at this point.
+ if fsysopts / --update --writable ; then
+ settrans -c /servers/socket/1 /hurd/pflocal
+@@ -76,7 +76,6 @@ if [ "${FALLBACK_CONSOLE+set}" = set ]; then
+ singleuser "Running on fallback console ${FALLBACK_CONSOLE}"
+ fi
+
+-
+ ###
+ ### Normal startup procedures
+ ###
+@@ -85,20 +84,23 @@ fi
+ # The first argument is the kernel file name; skip that.
+ shift
+ flags=
++single=
+ while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+ case "$arg" in
+ --*) ;;
++ init=*)
++ eval "${arg}"
++ ;;
+ *=*) ;;
+ -*)
+ flags="${flags}${arg#-}"
+ ;;
+- 'single'|'emergency') # Linux compat
+- flags="${flags}s"
++ 'single')
++ single="-s"
+ ;;
+- 'fastboot')
+- flags="${flags}f"
++ 'fastboot'|'emergency')
+ ;;
+ esac
+ done
+@@ -106,50 +108,18 @@ done
+ # Check boot flags.
+ case "$flags" in
+ *s*)
+- rc=false # force single-user
+- ;;
+-*f*)
+- rc="${RUNCOM}" # fastboot
+- ;;
+-*)
+- rc="${RUNCOM} autoboot" # multi-user default
++ single="-s" # force single-user
+ ;;
+ esac
+
+-# Large infinite loop. If this script ever exits, init considers that
+-# a serious bogosity and punts to a fallback single-user shell.
+-# We handle here the normal transitions between single-user and multi-user.
+-while : ; do
+-
+- # Run the rc script. As long as it exits nonzero, punt to single-user.
+- # After the single-user shell exits, we will start over attempting to
+- # run rc; but later invocations strip the `autoboot' argument.
+- until $rc; do
+- rc=${RUNCOM}
+-
+- # Run single-user shell and repeat as long as it dies with a signal.
+- until ${SHELL} || test $? -lt 128; do
+- :
+- done
+- done
+-
+- # Now we are officially ready for normal multi-user operation.
+-
+- # Trap certain signals and send them on to runttys. For this to work, we
+- # must run it asynchronously and wait for it with the `wait' built-in.
+- runttys_pid=0
+- for sig in $runttys_sigs; do
+- trap "kill -$sig \${runttys_pid}" $sig
+- done
+-
+- # This program reads /etc/ttys and starts the programs it says to.
+- ${RUNTTYS} &
+- runttys_pid=$!
++# Start the default pager. It will bail if there is already one running.
++/hurd/mach-defpager
+
+- # Wait for runttys to die, meanwhile handling trapped signals.
+- wait
++# This is necessary to make stat / return the correct device ids.
++# Work around a race condition (probably in the root translator).
++for i in `seq 1 100000` ; do : ; done
+
+- # Go back to the top of the infinite loop, as if booting single-user.
+- rc=false
++fsysopts / --update --readonly
+
+-done
++# Finally, start the actual SysV init.
++exec ${init} ${single} -a
+diff --git a/init/Makefile b/init/Makefile
+new file mode 100644
+index 0000000..07b8026
+--- /dev/null
++++ b/init/Makefile
+@@ -0,0 +1,24 @@
++#
++# Copyright (C) 2013 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, see <http://www.gnu.org/licenses/>.
++
++dir := init
++makemode := server
++
++SRCS = init.c
++OBJS = $(SRCS:.c=.o)
++target = init
++
++include ../Makeconf
+diff --git a/init/init.c b/init/init.c
+new file mode 100644
+index 0000000..b3d3301
+--- /dev/null
++++ b/init/init.c
+@@ -0,0 +1,155 @@
++/* A minimalist init for the Hurd
++
++ Copyright (C) 2013,14 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 Hurd. If not, see <http://www.gnu.org/licenses/>. */
++
++#include <argp.h>
++#include <error.h>
++#include <hurd.h>
++#include <signal.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <unistd.h>
++#include <version.h>
++
++const char *argp_program_version = STANDARD_HURD_VERSION (init);
++static pid_t child_pid;
++static int single;
++
++static struct argp_option
++options[] =
++{
++ /* XXX: Currently, -s does nothing. */
++ {"single-user", 's', NULL, 0, "Startup system in single-user mode", 0},
++ {NULL, 'a', NULL, 0, "Ignored for compatibility with sysvinit", 0},
++ {0}
++};
++
++static char doc[] = "A minimalist init for the Hurd";
++
++static error_t
++parse_opt (int key, char *arg, struct argp_state *state)
++{
++ switch (key)
++ {
++ case 's':
++ single = 1;
++ break;
++
++ case 'a':
++ /* Ignored. */
++ break;
++
++ default:
++ return ARGP_ERR_UNKNOWN;
++ }
++
++ return 0;
++}
++
++void
++sigchld_handler(int signal)
++{
++ /* 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. */
++ child_pid = -1;
++
++ char *desc = NULL;
++ 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));
++
++ error (0, 0, "child %s", desc);
++ free (desc);
++
++ /* XXX: launch emergency shell. */
++ error (23, 0, "panic!!");
++ }
++ }
++}
++
++int
++main (int argc, char **argv)
++{
++ struct argp argp =
++ {
++ .options = options,
++ .parser = parse_opt,
++ .doc = doc,
++ };
++ argp_parse (&argp, argc, argv, 0, 0, 0);
++
++ if (getpid () != 1)
++ error (1, 0, "can only be run as PID 1");
++
++ struct sigaction sa;
++ sa.sa_handler = SIG_IGN;
++ sa.sa_flags = 0;
++ sigemptyset (&sa.sa_mask);
++
++ sigaction (SIGHUP, &sa, NULL);
++ sigaction (SIGINT, &sa, NULL);
++ sigaction (SIGQUIT, &sa, NULL);
++ sigaction (SIGTERM, &sa, NULL);
++ sigaction (SIGUSR1, &sa, NULL);
++ sigaction (SIGUSR2, &sa, NULL);
++ sigaction (SIGTSTP, &sa, NULL);
++
++ sa.sa_handler = sigchld_handler;
++ sa.sa_flags |= SA_RESTART;
++ sigaction (SIGCHLD, &sa, NULL);
++
++ char *args[] = { "/etc/hurd/runsystem.hurd", NULL };
++
++ switch (child_pid = fork ())
++ {
++ case -1:
++ error (1, errno, "failed to fork");
++ case 0:
++ execv (args[0], args);
++ error (2, errno, "failed to execv child");
++ }
++
++ select (0, NULL, NULL, NULL, NULL);
++ /* Not reached. */
++ return 0;
++}
+--
+2.1.0
+
diff --git a/debian/patches/0005-startup-do-not-pass-signals-on-to-the-child.patch b/debian/patches/0005-startup-do-not-pass-signals-on-to-the-child.patch
new file mode 100644
index 00000000..c75f7b23
--- /dev/null
+++ b/debian/patches/0005-startup-do-not-pass-signals-on-to-the-child.patch
@@ -0,0 +1,251 @@
+From 4283426f4ba7832a092a7e46a49bec80c56410d1 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 18 Sep 2013 22:58:11 +0200
+Subject: [PATCH 5/8] startup: do not pass signals on to the child
+
+Formerly /hurd/startup would forward all signals to the child it
+started (e.g. /libexec/runsystem).
+
+The motivation for doing so is not revealed in the comments, nor it is
+mentioned in the history of the version control system.
+
+This patch removes the forwarding of signals to the child.
+
+* startup/startup.c (process_signal): Do not pass signals on to the child.
+* startup/stubs.c: Remove file.
+* startup/Makefile: Remove stubs.c.
+---
+ startup/Makefile | 2 +-
+ startup/startup.c | 49 -------------------
+ startup/stubs.c | 139 ------------------------------------------------------
+ 3 files changed, 1 insertion(+), 189 deletions(-)
+ delete mode 100644 startup/stubs.c
+
+diff --git a/startup/Makefile b/startup/Makefile
+index 2d6b892..277fee4 100644
+--- a/startup/Makefile
++++ b/startup/Makefile
+@@ -18,7 +18,7 @@
+ dir := startup
+ makemode := server
+
+-SRCS = startup.c stubs.c
++SRCS = startup.c
+ OBJS = $(SRCS:.c=.o) \
+ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
+ startup_notifyUser.o
+diff --git a/startup/startup.c b/startup/startup.c
+index 29269a6..4c91d4c 100644
+--- a/startup/startup.c
++++ b/startup/startup.c
+@@ -904,9 +904,6 @@ frob_kernel_process (void)
+ 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);
+
+
+@@ -965,52 +962,6 @@ process_signal (int signo)
+ }
+ }
+ }
+- 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
+diff --git a/startup/stubs.c b/startup/stubs.c
+deleted file mode 100644
+index 5292ab6..0000000
+--- a/startup/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;
+-}
+--
+2.1.0
+
diff --git a/debian/patches/0006-startup-be-more-specific-in-the-shutdown-message.patch b/debian/patches/0006-startup-be-more-specific-in-the-shutdown-message.patch
new file mode 100644
index 00000000..715aa38c
--- /dev/null
+++ b/debian/patches/0006-startup-be-more-specific-in-the-shutdown-message.patch
@@ -0,0 +1,29 @@
+From edd30e947fc68ba55226aa7f59ff45428f8fe759 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 18 Sep 2013 23:12:13 +0200
+Subject: [PATCH 6/8] startup: be more specific in the shutdown message
+
+Use the BOOT macro to print either halt or reboot instead of the
+generic shutdown in the event of an system shutdown.
+
+* startup/startup.c (reboot_system): Use more specific message.
+---
+ startup/startup.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/startup/startup.c b/startup/startup.c
+index 4c91d4c..0a33855 100644
+--- a/startup/startup.c
++++ b/startup/startup.c
+@@ -217,7 +217,7 @@ notify_shutdown (const char *msg)
+ void
+ reboot_system (int flags)
+ {
+- notify_shutdown ("shutdown");
++ notify_shutdown (BOOT (flags));
+
+ if (fakeboot)
+ {
+--
+2.1.0
+
diff --git a/debian/patches/0007-startup-fix-the-declaration-of-the-_server-functions.patch b/debian/patches/0007-startup-fix-the-declaration-of-the-_server-functions.patch
new file mode 100644
index 00000000..4d901369
--- /dev/null
+++ b/debian/patches/0007-startup-fix-the-declaration-of-the-_server-functions.patch
@@ -0,0 +1,28 @@
+From 4565524594612d6cd8267e3a74806a0c362636d0 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 18 Sep 2013 23:16:34 +0200
+Subject: [PATCH 7/8] startup: fix the declaration of the *_server functions
+
+* startup/startup.c (demuxer): Fix the declaration of the server functions.
+---
+ startup/startup.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/startup/startup.c b/startup/startup.c
+index 0a33855..fe8471d 100644
+--- a/startup/startup.c
++++ b/startup/startup.c
+@@ -501,7 +501,9 @@ static int
+ demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+ {
+- extern int notify_server (), startup_server (), msg_server ();
++ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
++ extern int startup_server (mach_msg_header_t *, mach_msg_header_t *);
++ extern int msg_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (notify_server (inp, outp) ||
+ msg_server (inp, outp) ||
+--
+2.1.0
+
diff --git a/debian/patches/0008-poc-servers-startup.patch b/debian/patches/0008-poc-servers-startup.patch
new file mode 100644
index 00000000..4ae5b8f8
--- /dev/null
+++ b/debian/patches/0008-poc-servers-startup.patch
@@ -0,0 +1,188 @@
+From d85410e3face63b09aa348aa9d15488fcdabf152 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Thu, 19 Sep 2013 09:15:02 +0200
+Subject: [PATCH 8/8] poc /servers/startup
+
+---
+ hurd/paths.h | 1 +
+ startup/Makefile | 2 +-
+ startup/startup.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 126 insertions(+), 1 deletion(-)
+
+diff --git a/hurd/paths.h b/hurd/paths.h
+index 489da57..568e45f 100644
+--- a/hurd/paths.h
++++ b/hurd/paths.h
+@@ -26,6 +26,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ #define _SERVERS "/servers/"
+ #define _SERVERS_CRASH _SERVERS "crash"
+ #define _SERVERS_EXEC _SERVERS "exec"
++#define _SERVERS_STARTUP _SERVERS "startup"
+ #define _SERVERS_PROC _SERVERS "proc"
+ #define _SERVERS_PASSWORD _SERVERS "password"
+ #define _SERVERS_DEFPAGER _SERVERS "default-pager"
+diff --git a/startup/Makefile b/startup/Makefile
+index 277fee4..23d35cb 100644
+--- a/startup/Makefile
++++ b/startup/Makefile
+@@ -21,7 +21,7 @@ makemode := server
+ SRCS = startup.c
+ OBJS = $(SRCS:.c=.o) \
+ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
+- startup_notifyUser.o
++ startup_notifyUser.o fsysServer.o
+ target = startup
+ HURDLIBS = shouldbeinlibc
+
+diff --git a/startup/startup.c b/startup/startup.c
+index fe8471d..9cff488 100644
+--- a/startup/startup.c
++++ b/startup/startup.c
+@@ -504,9 +504,11 @@ demuxer (mach_msg_header_t *inp,
+ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int startup_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int msg_server (mach_msg_header_t *, mach_msg_header_t *);
++ extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (notify_server (inp, outp) ||
+ msg_server (inp, outp) ||
++ fsys_server (inp, outp) ||
+ startup_server (inp, outp));
+ }
+
+@@ -583,6 +585,15 @@ main (int argc, char **argv, char **envp)
+ /* Crash if the boot filesystem task dies. */
+ request_dead_name (fstask);
+
++ file_t node = file_name_lookup (_SERVERS_STARTUP, O_NOTRANS, 0);
++ if (node != MACH_PORT_NULL)
++ {
++ file_set_translator (node,
++ 0, FS_TRANS_SET, 0,
++ NULL, 0,
++ startup, MACH_MSG_TYPE_COPY_SEND);
++ }
++
+ /* Set up the set of ports we will pass to the programs we exec. */
+ for (i = 0; i < INIT_PORT_MAX; i++)
+ switch (i)
+@@ -1544,3 +1555,116 @@ S_msg_report_wait (mach_port_t process, thread_t thread,
+ *rpc = 0;
+ return 0;
+ }
++
++/* fsys */
++error_t
++S_fsys_getroot (mach_port_t fsys_t,
++ mach_port_t dotdotnode,
++ uid_t *uids, size_t nuids,
++ uid_t *gids, size_t ngids,
++ int flags,
++ retry_type *do_retry,
++ char *retry_name,
++ mach_port_t *ret,
++ mach_msg_type_name_t *rettype)
++{
++ error (0, 0, "S_fsys_getroot");
++ /* XXX check permissions */
++ *do_retry = FS_RETRY_NORMAL;
++ *retry_name = '\0';
++ *ret = startup;
++ *rettype = MACH_MSG_TYPE_COPY_SEND;
++ return 0;
++}
++
++error_t
++S_fsys_goaway (mach_port_t control, int flags)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_startup (mach_port_t bootstrap, int flags, mach_port_t control,
++ mach_port_t *real, mach_msg_type_name_t *realtype)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_syncfs (mach_port_t control,
++ int wait,
++ int recurse)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_set_options (mach_port_t control,
++ char *data, mach_msg_type_number_t len,
++ int do_children)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_get_options (mach_port_t control,
++ char **data, mach_msg_type_number_t *len)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_getfile (mach_port_t control,
++ uid_t *uids, size_t nuids,
++ uid_t *gids, size_t ngids,
++ char *handle, size_t handllen,
++ mach_port_t *pt,
++ mach_msg_type_name_t *pttype)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_getpriv (mach_port_t control,
++ mach_port_t *host_priv, mach_msg_type_name_t *host_priv_type,
++ mach_port_t *dev_master, mach_msg_type_name_t *dev_master_type,
++ task_t *fs_task, mach_msg_type_name_t *fs_task_type)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_init (mach_port_t control,
++ mach_port_t reply,
++ mach_msg_type_name_t replytype,
++ mach_port_t proc,
++ auth_t auth)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_forward (mach_port_t server, mach_port_t requestor,
++ char *argz, size_t argz_len)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_get_children (mach_port_t server,
++ mach_port_t reply,
++ mach_msg_type_name_t replyPoly,
++ char **children,
++ mach_msg_type_number_t *children_len)
++{
++ return EOPNOTSUPP;
++}
++
++error_t
++S_fsys_get_source (mach_port_t server,
++ mach_port_t reply,
++ mach_msg_type_name_t replyPoly,
++ char *source)
++{
++ return EOPNOTSUPP;
++}
+--
+2.1.0
+
diff --git a/debian/patches/series b/debian/patches/series
index f77d9059..a1a12371 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -61,3 +61,11 @@ fix-net_rcv_msg.patch
#pp-dde.patch
#pp-random.patch
+0001-libdiskfs-fix-servers-exec-lookup.patch
+0002-Add-proc_set_init_task-make-runsystem-pid-1.patch
+0003-startup-rename-init-to-startup.patch
+0004-Add-a-minimalist-init-program.patch
+0005-startup-do-not-pass-signals-on-to-the-child.patch
+0006-startup-be-more-specific-in-the-shutdown-message.patch
+0007-startup-fix-the-declaration-of-the-_server-functions.patch
+0008-poc-servers-startup.patch