diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-09-02 23:18:57 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-09-02 23:18:57 +0200 |
commit | b729fbad76622a759c97013989a7df489addfde8 (patch) | |
tree | 0ce7b316d031d0d9925215e8b0f5b968df62939a | |
parent | a4a8673373d080d6947a7a026af0ec9932ce96f1 (diff) |
add patch series
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 |