From 5043bd93caf49bb1c755a35850e26331c4f32be6 Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 29 Oct 2014 15:05:30 +0100 Subject: rename startup series --- ...d-proc_set_init_task-make-runsystem-pid-1.patch | 392 --- ...not-hard-code-the-default-argument-values.patch | 43 - ...-startup-rename-hurd-init-to-hurd-startup.patch | 3678 -------------------- .../0004-init-add-a-minimalist-init-program.patch | 572 --- ...artup-do-not-pass-signals-on-to-the-child.patch | 251 -- ...-be-more-specific-in-the-shutdown-message.patch | 29 - ...-the-declaration-of-the-_server-functions.patch | 28 - ...ind-the-startup-server-to-servers-startup.patch | 344 -- debian/patches/series | 16 +- ...d-proc_set_init_task-make-runsystem-pid-1.patch | 392 +++ ...not-hard-code-the-default-argument-values.patch | 43 + ...-startup-rename-hurd-init-to-hurd-startup.patch | 3678 ++++++++++++++++++++ ...p-0004-init-add-a-minimalist-init-program.patch | 572 +++ ...artup-do-not-pass-signals-on-to-the-child.patch | 251 ++ ...-be-more-specific-in-the-shutdown-message.patch | 29 + ...-the-declaration-of-the-_server-functions.patch | 28 + ...ind-the-startup-server-to-servers-startup.patch | 344 ++ 17 files changed, 5345 insertions(+), 5345 deletions(-) delete mode 100644 debian/patches/0001-Add-proc_set_init_task-make-runsystem-pid-1.patch delete mode 100644 debian/patches/0002-procfs-do-not-hard-code-the-default-argument-values.patch delete mode 100644 debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch delete mode 100644 debian/patches/0004-init-add-a-minimalist-init-program.patch delete mode 100644 debian/patches/0005-startup-do-not-pass-signals-on-to-the-child.patch delete mode 100644 debian/patches/0006-startup-be-more-specific-in-the-shutdown-message.patch delete mode 100644 debian/patches/0007-startup-fix-the-declaration-of-the-_server-functions.patch delete mode 100644 debian/patches/0008-startup-bind-the-startup-server-to-servers-startup.patch create mode 100644 debian/patches/startup-0001-Add-proc_set_init_task-make-runsystem-pid-1.patch create mode 100644 debian/patches/startup-0002-procfs-do-not-hard-code-the-default-argument-values.patch create mode 100644 debian/patches/startup-0003-startup-rename-hurd-init-to-hurd-startup.patch create mode 100644 debian/patches/startup-0004-init-add-a-minimalist-init-program.patch create mode 100644 debian/patches/startup-0005-startup-do-not-pass-signals-on-to-the-child.patch create mode 100644 debian/patches/startup-0006-startup-be-more-specific-in-the-shutdown-message.patch create mode 100644 debian/patches/startup-0007-startup-fix-the-declaration-of-the-_server-functions.patch create mode 100644 debian/patches/startup-0008-startup-bind-the-startup-server-to-servers-startup.patch diff --git a/debian/patches/0001-Add-proc_set_init_task-make-runsystem-pid-1.patch b/debian/patches/0001-Add-proc_set_init_task-make-runsystem-pid-1.patch deleted file mode 100644 index e9d6f9d4..00000000 --- a/debian/patches/0001-Add-proc_set_init_task-make-runsystem-pid-1.patch +++ /dev/null @@ -1,392 +0,0 @@ -From 7814f2ef1f48d90b15c12c5521c9c1193fe80a7b 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 1/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. -* doc/hurd.texi (Server Bootstrap): Update accordingly. -* procfs/main.c: Do not hard-code kernel pid, use pids.h instead. ---- - doc/hurd.texi | 2 +- - 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 +++-- - procfs/main.c | 9 ++++-- - 10 files changed, 93 insertions(+), 35 deletions(-) - -diff --git a/doc/hurd.texi b/doc/hurd.texi -index 8fa6da7..697cce7 100644 ---- a/doc/hurd.texi -+++ b/doc/hurd.texi -@@ -564,7 +564,7 @@ the root filesystem and the exec server. - - The @option{--multiboot-command-line} option tells the file system server that - it is a root filesystem, which triggers it to run @command{/hurd/init} as PID --1. @command{/hurd/init} starts the @command{/hurd/proc} and -+2. @command{/hurd/init} starts the @command{/hurd/proc} and - @command{/hurd/auth} servers. After the servers are launched - @command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to - finish booting. -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 . */ -+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 . */ - 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); -diff --git a/procfs/main.c b/procfs/main.c -index 54e9682..f3067d9 100644 ---- a/procfs/main.c -+++ b/procfs/main.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - #include "procfs.h" - #include "proclist.h" - #include "rootdir.h" -@@ -42,7 +43,7 @@ uid_t opt_anon_owner; - #define OPT_CLK_TCK sysconf(_SC_CLK_TCK) - #define OPT_STAT_MODE 0400 - #define OPT_FAKE_SELF -1 --#define OPT_KERNEL_PID 2 -+#define OPT_KERNEL_PID HURD_PID_KERNEL - #define OPT_ANON_OWNER 0 - - #define NODEV_KEY -1 /* <= 0, so no short option. */ -@@ -137,6 +138,8 @@ argp_parser (int key, char *arg, struct argp_state *state) - } - - struct argp_option common_options[] = { -+#define STR(X) XSTR (X) -+#define XSTR(X) #X - { "clk-tck", 'h', "HZ", 0, - "Unit used for the values expressed in system clock ticks " - "(default: sysconf(_SC_CLK_TCK))" }, -@@ -153,7 +156,7 @@ struct argp_option common_options[] = { - { "kernel-process", 'k', "PID", 0, - "Process identifier for the kernel, used to retreive its command " - "line, as well as the global up and idle times. " -- "(default: 2)" }, -+ "(default: " STR (OPT_KERNEL_PID) ")" }, - { "compatible", 'c', NULL, 0, - "Try to be compatible with the Linux procps utilities. " - "Currently equivalent to -h 100 -s 0444 -S 1." }, -@@ -169,6 +172,8 @@ struct argp_option common_options[] = { - { "nosuid", NOSUID_KEY, NULL, 0, - "Ignored for compatibility with Linux' procfs." }, - {} -+#undef XSTR -+#undef STR - }; - - struct argp argp = { --- -2.1.0 - diff --git a/debian/patches/0002-procfs-do-not-hard-code-the-default-argument-values.patch b/debian/patches/0002-procfs-do-not-hard-code-the-default-argument-values.patch deleted file mode 100644 index 70b41c14..00000000 --- a/debian/patches/0002-procfs-do-not-hard-code-the-default-argument-values.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 7a0bc7740d665cf8ea3442960fde67d28dda4ecf Mon Sep 17 00:00:00 2001 -From: Justus Winter <4winter@informatik.uni-hamburg.de> -Date: Fri, 5 Sep 2014 10:34:24 +0200 -Subject: [PATCH 2/8] procfs: do not hard-code the default argument values - -* procfs/main.c (common_options): If possible, do not hard-code the -default values. ---- - procfs/main.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/procfs/main.c b/procfs/main.c -index f3067d9..36a2d25 100644 ---- a/procfs/main.c -+++ b/procfs/main.c -@@ -142,13 +142,13 @@ struct argp_option common_options[] = { - #define XSTR(X) #X - { "clk-tck", 'h', "HZ", 0, - "Unit used for the values expressed in system clock ticks " -- "(default: sysconf(_SC_CLK_TCK))" }, -+ "(default: " STR (OPT_CLK_TCK) ")" }, - { "stat-mode", 's', "MODE", 0, - "The [pid]/stat file publishes information which on Hurd is only " - "available to the process owner. " - "You can use this option to override its mode to be more permissive " - "for compatibility purposes. " -- "(default: 0400)" }, -+ "(default: " STR (OPT_STAT_MODE) ")" }, - { "fake-self", 'S', "PID", OPTION_ARG_OPTIONAL, - "Provide a fake \"self\" symlink to the given PID, for compatibility " - "purposes. If PID is omitted, \"self\" will point to init. " -@@ -164,7 +164,7 @@ struct argp_option common_options[] = { - "Make USER the owner of files related to processes without one. " - "Be aware that USER will be granted access to the environment and " - "other sensitive information about the processes in question. " -- "(default: use uid 0)" }, -+ "(default: use uid " STR (OPT_ANON_OWNER) ")" }, - { "nodev", NODEV_KEY, NULL, 0, - "Ignored for compatibility with Linux' procfs." }, - { "noexec", NOEXEC_KEY, NULL, 0, --- -2.1.0 - diff --git a/debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch b/debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch deleted file mode 100644 index 7a874ab6..00000000 --- a/debian/patches/0003-startup-rename-hurd-init-to-hurd-startup.patch +++ /dev/null @@ -1,3678 +0,0 @@ -From 3ead9b6a0328e8aa85d652bcabdb76ce86360907 Mon Sep 17 00:00:00 2001 -From: Justus Winter <4winter@informatik.uni-hamburg.de> -Date: Tue, 17 Sep 2013 13:44:44 +0200 -Subject: [PATCH 3/8] startup: rename /hurd/init to /hurd/startup - -This patch series splits /hurd/init into two programs. As a first -step, this patch renames /hurd/init to /hurd/startup. It is called -startup because it speaks the startup protocol. - -* startup: Rename init to startup. Adjust accordingly. -* Makefile (prog-subdirs): Likewise. -* doc/hurd.texi (Server Bootstrap): Likewise. -* hurd/paths.h (_HURD_STARTUP): Likewise. -* libdiskfs/boot-start.c (diskfs_boot_init_program): Likewise. -* libdiskfs/opts-std-startup.c (startup_options): Likewise. ---- - Makefile | 3 +- - doc/hurd.texi | 6 +- - hurd/paths.h | 2 +- - init/Makefile | 31 - - init/init.c | 1593 ------------------------------------------ - init/stubs.c | 139 ---- - libdiskfs/boot-start.c | 2 +- - libdiskfs/opts-std-startup.c | 2 +- - startup/Makefile | 31 + - startup/startup.c | 1593 ++++++++++++++++++++++++++++++++++++++++++ - startup/stubs.c | 139 ++++ - 11 files changed, 1771 insertions(+), 1770 deletions(-) - delete mode 100644 init/Makefile - delete mode 100644 init/init.c - delete mode 100644 init/stubs.c - create mode 100644 startup/Makefile - create mode 100644 startup/startup.c - create mode 100644 startup/stubs.c - -diff --git a/Makefile b/Makefile -index 0b9eff2..455df67 100644 ---- a/Makefile -+++ b/Makefile -@@ -31,7 +31,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \ - libnetfs libpipe libstore libhurdbugaddr libftpconn libcons - - # Hurd programs --prog-subdirs = auth proc exec init term \ -+prog-subdirs = auth proc exec term \ - ext2fs isofs tmpfs fatfs \ - storeio pflocal pfinet defpager mach-defpager \ - login daemons boot console \ -@@ -40,6 +40,7 @@ prog-subdirs = auth proc exec init term \ - benchmarks fstests \ - random \ - procfs \ -+ startup \ - - ifeq ($(HAVE_SUN_RPC),yes) - prog-subdirs += nfs nfsd -diff --git a/doc/hurd.texi b/doc/hurd.texi -index 697cce7..7e7b5ee 100644 ---- a/doc/hurd.texi -+++ b/doc/hurd.texi -@@ -563,10 +563,10 @@ bootstrapped by starting the GNU Mach microkernel and two programs: - the root filesystem and the exec server. - - The @option{--multiboot-command-line} option tells the file system server that --it is a root filesystem, which triggers it to run @command{/hurd/init} as PID --2. @command{/hurd/init} starts the @command{/hurd/proc} and -+it is a root filesystem, which triggers it to run @command{/hurd/startup} as PID -+2. @command{/hurd/startup} starts the @command{/hurd/proc} and - @command{/hurd/auth} servers. After the servers are launched --@command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to -+@command{/hurd/startup} starts the @command{/libexec/runsystem.sh} script to - finish booting. - - After the Hurd has been booted, other sets of core Hurd servers can be -diff --git a/hurd/paths.h b/hurd/paths.h -index 4877132..489da57 100644 ---- a/hurd/paths.h -+++ b/hurd/paths.h -@@ -39,7 +39,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - the canonical pathname being /hurd/foo. */ - - #define _HURD "/hurd/" --#define _HURD_INIT _HURD "init" -+#define _HURD_STARTUP _HURD "startup" - #define _HURD_PROC _HURD "proc" - #define _HURD_AUTH _HURD "auth" - -diff --git a/init/Makefile b/init/Makefile -deleted file mode 100644 -index ffb82ff..0000000 ---- a/init/Makefile -+++ /dev/null -@@ -1,31 +0,0 @@ --# --# Copyright (C) 1994,95,96,99,2001 Free Software Foundation, Inc. --# --# This program is free software; you can redistribute it and/or --# modify it under the terms of the GNU General Public License as --# published by the Free Software Foundation; either version 2, or (at --# your option) any later version. --# --# This program is distributed in the hope that it will be useful, but --# WITHOUT ANY WARRANTY; without even the implied warranty of --# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --# General Public License for more details. --# --# You should have received a copy of the GNU General Public License --# along with this program; if not, write to the Free Software --# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -- --dir := init --makemode := server -- --SRCS = init.c stubs.c --OBJS = $(SRCS:.c=.o) \ -- startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ -- startup_notifyUser.o --target = init --HURDLIBS = shouldbeinlibc -- --include ../Makeconf -- --mung_msg_S.h: msg_S.h -- sed 's/msg_server/mung_msg_server/' < $< > $@ -diff --git a/init/init.c b/init/init.c -deleted file mode 100644 -index 6bc6701..0000000 ---- a/init/init.c -+++ /dev/null -@@ -1,1593 +0,0 @@ --/* Start and maintain hurd core servers and system run state -- -- Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -- 2005, 2008, 2013 Free Software Foundation, Inc. -- This file is part of the GNU Hurd. -- -- The GNU Hurd is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2, or (at your option) -- any later version. -- -- The GNU Hurd is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with the GNU Hurd; see the file COPYING. If not, write to -- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -- --/* Written by Michael I. Bushnell and Roland McGrath. */ -- --/* This is probably more include files than I've ever seen before for -- one file. */ --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#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 --#include --#include --#include --#include -- --/* 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 -+#include -+#include -+#include -+#include -+ -+/* 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-init-add-a-minimalist-init-program.patch b/debian/patches/0004-init-add-a-minimalist-init-program.patch deleted file mode 100644 index 7b6af753..00000000 --- a/debian/patches/0004-init-add-a-minimalist-init-program.patch +++ /dev/null @@ -1,572 +0,0 @@ -From 5551fcc6442401d72b4db5ac5f5de471f07eeb0a 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] init: add a minimalist init program - -This patch adds a minimalist init program. It is somewhat lacking in -features, but is able to bring up a Hurd system with the runsystem and -rc scripts. In fact, it roughly does what the former /hurd/init did, -modulo all the very early bootstrapping stuff and the startup -protocol. It is started when all the essential servers are up and -running, so it can make use of most of the POSIX goodies, making its -implementation much simpler. - -* Makefile (prog-subdirs): Add init. -* daemons/runsystem.sh: Generalize runsystem so that it can start any -init as specified on the kernel command line. By default, it starts -/hurd/init. -* daemons/runsystem.hurd: This is a verbatim copy of runsystem.sh. It -is started by /hurd/init. -* daemons/rc.sh: Do not start /hurd/mach-defpager as it is already -started in runsystem.sh. -* daemons/Makefile (SRCS): Add runsystem.hurd. -* init/Makefile: New file. -* init/init.c: Likewise. ---- - Makefile | 1 + - daemons/Makefile | 4 +- - daemons/rc.sh | 3 - - daemons/runsystem.hurd | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ - daemons/runsystem.sh | 80 +++++++++---------------- - init/Makefile | 24 ++++++++ - init/init.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ - 7 files changed, 364 insertions(+), 58 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/Makefile b/daemons/Makefile -index d16680e..db1acc7 100644 ---- a/daemons/Makefile -+++ b/daemons/Makefile -@@ -22,7 +22,9 @@ makemode := utilities - - targets = rc getty mail.local console-run runttys runsystem - special-targets = rc runsystem --SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c -+SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c \ -+ runsystem.hurd \ -+ - installationdir = $(libexecdir) - - HURDLIBS = fshelp ports shouldbeinlibc -diff --git a/daemons/rc.sh b/daemons/rc.sh -index 5cf44fa..1240883 100644 ---- a/daemons/rc.sh -+++ b/daemons/rc.sh -@@ -2,9 +2,6 @@ - - PATH=/bin:/sbin - --# Start the default pager. It will bail if there is already one running. --/hurd/mach-defpager -- - # Set up swap space. This will complain if no default pager is functioning. - swapon -a - -diff --git a/daemons/runsystem.hurd b/daemons/runsystem.hurd -new file mode 100644 -index 0000000..f4f2771 ---- /dev/null -+++ b/daemons/runsystem.hurd -@@ -0,0 +1,155 @@ -+#!/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 -+} -+ -+ -+# See whether pflocal is set up already, and do so if not (install case) -+# -+# 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 -+ # The root filesystem should be read-only at this point. -+ if fsysopts / --update --writable ; then -+ settrans -c /servers/socket/1 /hurd/pflocal -+ else -+ singleuser "Failed to create /servers/socket/1." -+ fi -+fi -+ -+# 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..bd145ed 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 /hurd/init or any other roughly SysV init-compatible program -+# to bring up the "userland" parts of a normal system. - # - - -@@ -22,11 +22,10 @@ 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=/hurd/init - - ### - -@@ -44,7 +43,7 @@ trap 'reopen_console' SIGLOST - # 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 () -+function singleuser() - { - test $# -eq 0 || echo "$0: $*" - for try in ${fallback_shells}; do -@@ -54,6 +53,8 @@ function singleuser () - exit 127 - } - -+# Print a newline. -+echo - - # See whether pflocal is set up already, and do so if not (install case) - # -@@ -85,20 +86,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 +110,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 -+# Start the default pager. It will bail if there is already one running. -+/hurd/mach-defpager - -- # This program reads /etc/ttys and starts the programs it says to. -- ${RUNTTYS} & -- runttys_pid=$! -+# 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 - -- # Wait for runttys to die, meanwhile handling trapped signals. -- wait -+fsysopts / --update --readonly - -- # Go back to the top of the infinite loop, as if booting single-user. -- rc=false -- --done -+# Finally, start the actual 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 . -+ -+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 . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 deleted file mode 100644 index 33046438..00000000 --- a/debian/patches/0005-startup-do-not-pass-signals-on-to-the-child.patch +++ /dev/null @@ -1,251 +0,0 @@ -From b7eed065f9118964dc875e4f03c8b07332b44a65 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 --#include --#include --#include --#include -- --/* 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 deleted file mode 100644 index d2f9f5ce..00000000 --- a/debian/patches/0006-startup-be-more-specific-in-the-shutdown-message.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 4c6541b4955425e62c2014c66bcb541c95c534db 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 deleted file mode 100644 index b8577c9d..00000000 --- a/debian/patches/0007-startup-fix-the-declaration-of-the-_server-functions.patch +++ /dev/null @@ -1,28 +0,0 @@ -From bbdbeeba0076f31ad78849be86596528dfbeac85 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-startup-bind-the-startup-server-to-servers-startup.patch b/debian/patches/0008-startup-bind-the-startup-server-to-servers-startup.patch deleted file mode 100644 index d3633eb0..00000000 --- a/debian/patches/0008-startup-bind-the-startup-server-to-servers-startup.patch +++ /dev/null @@ -1,344 +0,0 @@ -From ccce2ecc7426fc65d05db387b5d8390644c17dc5 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] startup: bind the startup server to /servers/startup - -Previously, the Hurd (ab)used the fact that the startup server speaks -all protocols on its message port. Any server that wished to register -for shutdown notifications would use XXX to get a port to the startup -server. - -This hardcodes the PID of /hurd/startup, and does not allow one to -point a server to ones own startup server (e.g. using remap). - -Bind the startup server to /servers/startup instead. Use this to -contact the startup server. - -* exec/main.c (S_exec_init): Use /servers/startup. Fall back to the -old method so that the system still boots when the node -/servers/startup is missing. -* hurd/paths.h (_SERVERS_STARTUP): New macro. -* libdiskfs/boot-start.c (diskfs_S_fsys_init): Use /servers/startup. -* libdiskfs/init-startup.c (_diskfs_init_completed): Likewise. -* pfinet/main.c (arrange_shutdown_notification): Likewise. -* startup/Makefile (OBJS): Add fsysServer.o. -* startup/startup.c (demuxer): Handle the fsys protocol. -(main): Bind to /servers/startup. -(S_fsys_getroot): Implement fsys_getroot. Stub out the rest. ---- - exec/main.c | 11 ++++- - hurd/paths.h | 1 + - libdiskfs/boot-start.c | 9 ++-- - libdiskfs/init-startup.c | 13 ++++-- - pfinet/main.c | 12 ++--- - startup/Makefile | 2 +- - startup/startup.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++ - 7 files changed, 146 insertions(+), 21 deletions(-) - -diff --git a/exec/main.c b/exec/main.c -index 78faebd..664f150 100644 ---- a/exec/main.c -+++ b/exec/main.c -@@ -251,8 +251,15 @@ S_exec_init (struct trivfs_protid *protid, - - proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION); - -- err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup); -- assert_perror (err); -+ startup = file_name_lookup (_SERVERS_STARTUP, 0, 0); -+ if (startup == MACH_PORT_NULL) -+ { -+ error (0, errno, "%s", _SERVERS_STARTUP); -+ -+ /* Fall back to abusing the message port lookup. */ -+ err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup); -+ assert_perror (err); -+ } - mach_port_deallocate (mach_task_self (), procserver); - - /* Call startup_essential task last; init assumes we are ready to -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/libdiskfs/boot-start.c b/libdiskfs/boot-start.c -index 42e991e..cfe2303 100644 ---- a/libdiskfs/boot-start.c -+++ b/libdiskfs/boot-start.c -@@ -33,7 +33,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include - #include - #include --#include - #include "exec_S.h" - #include "exec_startup_S.h" - #include "fsys_S.h" -@@ -602,9 +601,12 @@ diskfs_S_fsys_init (struct diskfs_control *pt, - - proc_register_version (procserver, host, diskfs_server_name, "", - diskfs_server_version); -+ mach_port_deallocate (mach_task_self (), procserver); - -- err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup); -- if (!err) -+ startup = file_name_lookup (_SERVERS_STARTUP, 0, 0); -+ if (startup == MACH_PORT_NULL) -+ error (0, errno, "%s", _SERVERS_STARTUP); -+ else - { - startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, - diskfs_server_name, host); -@@ -612,7 +614,6 @@ diskfs_S_fsys_init (struct diskfs_control *pt, - } - - mach_port_deallocate (mach_task_self (), host); -- mach_port_deallocate (mach_task_self (), procserver); - - _diskfs_init_completed (); - -diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c -index d10c964..3a588e1 100644 ---- a/libdiskfs/init-startup.c -+++ b/libdiskfs/init-startup.c -@@ -25,8 +25,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include - #include - #include -+#include - #include --#include - - #include "startup_S.h" - -@@ -195,15 +195,18 @@ _diskfs_init_completed () - - /* Mark us as important. */ - err = proc_mark_important (proc); -+ mach_port_deallocate (mach_task_self (), proc); - /* This might fail due to permissions or because the old proc server - is still running, ignore any such errors. */ - if (err && err != EPERM && err != EMIG_BAD_ID) - goto errout; - -- err = proc_getmsgport (proc, HURD_PID_STARTUP, &init); -- mach_port_deallocate (mach_task_self (), proc); -- if (err) -- goto errout; -+ init = file_name_lookup (_SERVERS_STARTUP, 0, 0); -+ if (init == MACH_PORT_NULL) -+ { -+ err = errno; -+ goto errout; -+ } - - notify = ports_get_send_right (pi); - ports_port_deref (pi); -diff --git a/pfinet/main.c b/pfinet/main.c -index 5b0262f..3cd5f13 100644 ---- a/pfinet/main.c -+++ b/pfinet/main.c -@@ -24,11 +24,11 @@ - #include - #include - #include -+#include - #include - #include - #include - #include --#include - - /* Include Hurd's errno.h file, but don't include glue-include/hurd/errno.h, - since it #undef's the errno macro. */ -@@ -154,7 +154,6 @@ arrange_shutdown_notification () - { - error_t err; - mach_port_t initport, notify; -- process_t procserver; - struct port_info *pi; - - shutdown_notify_class = ports_create_class (0, 0); -@@ -169,13 +168,8 @@ arrange_shutdown_notification () - if (err) - return; - -- procserver = getproc (); -- if (!procserver) -- return; -- -- err = proc_getmsgport (procserver, HURD_PID_STARTUP, &initport); -- mach_port_deallocate (mach_task_self (), procserver); -- if (err) -+ initport = file_name_lookup (_SERVERS_STARTUP, 0, 0); -+ if (initport == MACH_PORT_NULL) - return; - - notify = ports_get_send_right (pi); -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..ff58270 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,18 @@ 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) -+ error (0, errno, "%s", _SERVERS_STARTUP); -+ else -+ { -+ file_set_translator (node, -+ 0, FS_TRANS_SET, 0, -+ NULL, 0, -+ startup, MACH_MSG_TYPE_COPY_SEND); -+ mach_port_deallocate (mach_task_self (), node); -+ } -+ - /* 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 +1558,108 @@ 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) -+{ -+ int is_root = 0; -+ size_t i; -+ -+ for (i = 0; i < nuids; i++) -+ if (uids[i] == 0) -+ { -+ is_root = 1; -+ break; -+ } -+ -+ if (! is_root) -+ return EPERM; -+ -+ *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; -+} --- -2.1.0 - diff --git a/debian/patches/series b/debian/patches/series index 9220eb6c..9d2541ed 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,11 +1,11 @@ -0001-Add-proc_set_init_task-make-runsystem-pid-1.patch -0002-procfs-do-not-hard-code-the-default-argument-values.patch -0003-startup-rename-hurd-init-to-hurd-startup.patch -0004-init-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-startup-bind-the-startup-server-to-servers-startup.patch +startup-0001-Add-proc_set_init_task-make-runsystem-pid-1.patch +startup-0002-procfs-do-not-hard-code-the-default-argument-values.patch +startup-0003-startup-rename-hurd-init-to-hurd-startup.patch +startup-0004-init-add-a-minimalist-init-program.patch +startup-0005-startup-do-not-pass-signals-on-to-the-child.patch +startup-0006-startup-be-more-specific-in-the-shutdown-message.patch +startup-0007-startup-fix-the-declaration-of-the-_server-functions.patch +startup-0008-startup-bind-the-startup-server-to-servers-startup.patch libexec-splitinit.patch diskfs_no_inherit_dir_group.patch diff --git a/debian/patches/startup-0001-Add-proc_set_init_task-make-runsystem-pid-1.patch b/debian/patches/startup-0001-Add-proc_set_init_task-make-runsystem-pid-1.patch new file mode 100644 index 00000000..e9d6f9d4 --- /dev/null +++ b/debian/patches/startup-0001-Add-proc_set_init_task-make-runsystem-pid-1.patch @@ -0,0 +1,392 @@ +From 7814f2ef1f48d90b15c12c5521c9c1193fe80a7b 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 1/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. +* doc/hurd.texi (Server Bootstrap): Update accordingly. +* procfs/main.c: Do not hard-code kernel pid, use pids.h instead. +--- + doc/hurd.texi | 2 +- + 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 +++-- + procfs/main.c | 9 ++++-- + 10 files changed, 93 insertions(+), 35 deletions(-) + +diff --git a/doc/hurd.texi b/doc/hurd.texi +index 8fa6da7..697cce7 100644 +--- a/doc/hurd.texi ++++ b/doc/hurd.texi +@@ -564,7 +564,7 @@ the root filesystem and the exec server. + + The @option{--multiboot-command-line} option tells the file system server that + it is a root filesystem, which triggers it to run @command{/hurd/init} as PID +-1. @command{/hurd/init} starts the @command{/hurd/proc} and ++2. @command{/hurd/init} starts the @command{/hurd/proc} and + @command{/hurd/auth} servers. After the servers are launched + @command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to + finish booting. +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 . */ ++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 . */ + 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); +diff --git a/procfs/main.c b/procfs/main.c +index 54e9682..f3067d9 100644 +--- a/procfs/main.c ++++ b/procfs/main.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include "procfs.h" + #include "proclist.h" + #include "rootdir.h" +@@ -42,7 +43,7 @@ uid_t opt_anon_owner; + #define OPT_CLK_TCK sysconf(_SC_CLK_TCK) + #define OPT_STAT_MODE 0400 + #define OPT_FAKE_SELF -1 +-#define OPT_KERNEL_PID 2 ++#define OPT_KERNEL_PID HURD_PID_KERNEL + #define OPT_ANON_OWNER 0 + + #define NODEV_KEY -1 /* <= 0, so no short option. */ +@@ -137,6 +138,8 @@ argp_parser (int key, char *arg, struct argp_state *state) + } + + struct argp_option common_options[] = { ++#define STR(X) XSTR (X) ++#define XSTR(X) #X + { "clk-tck", 'h', "HZ", 0, + "Unit used for the values expressed in system clock ticks " + "(default: sysconf(_SC_CLK_TCK))" }, +@@ -153,7 +156,7 @@ struct argp_option common_options[] = { + { "kernel-process", 'k', "PID", 0, + "Process identifier for the kernel, used to retreive its command " + "line, as well as the global up and idle times. " +- "(default: 2)" }, ++ "(default: " STR (OPT_KERNEL_PID) ")" }, + { "compatible", 'c', NULL, 0, + "Try to be compatible with the Linux procps utilities. " + "Currently equivalent to -h 100 -s 0444 -S 1." }, +@@ -169,6 +172,8 @@ struct argp_option common_options[] = { + { "nosuid", NOSUID_KEY, NULL, 0, + "Ignored for compatibility with Linux' procfs." }, + {} ++#undef XSTR ++#undef STR + }; + + struct argp argp = { +-- +2.1.0 + diff --git a/debian/patches/startup-0002-procfs-do-not-hard-code-the-default-argument-values.patch b/debian/patches/startup-0002-procfs-do-not-hard-code-the-default-argument-values.patch new file mode 100644 index 00000000..70b41c14 --- /dev/null +++ b/debian/patches/startup-0002-procfs-do-not-hard-code-the-default-argument-values.patch @@ -0,0 +1,43 @@ +From 7a0bc7740d665cf8ea3442960fde67d28dda4ecf Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Fri, 5 Sep 2014 10:34:24 +0200 +Subject: [PATCH 2/8] procfs: do not hard-code the default argument values + +* procfs/main.c (common_options): If possible, do not hard-code the +default values. +--- + procfs/main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/procfs/main.c b/procfs/main.c +index f3067d9..36a2d25 100644 +--- a/procfs/main.c ++++ b/procfs/main.c +@@ -142,13 +142,13 @@ struct argp_option common_options[] = { + #define XSTR(X) #X + { "clk-tck", 'h', "HZ", 0, + "Unit used for the values expressed in system clock ticks " +- "(default: sysconf(_SC_CLK_TCK))" }, ++ "(default: " STR (OPT_CLK_TCK) ")" }, + { "stat-mode", 's', "MODE", 0, + "The [pid]/stat file publishes information which on Hurd is only " + "available to the process owner. " + "You can use this option to override its mode to be more permissive " + "for compatibility purposes. " +- "(default: 0400)" }, ++ "(default: " STR (OPT_STAT_MODE) ")" }, + { "fake-self", 'S', "PID", OPTION_ARG_OPTIONAL, + "Provide a fake \"self\" symlink to the given PID, for compatibility " + "purposes. If PID is omitted, \"self\" will point to init. " +@@ -164,7 +164,7 @@ struct argp_option common_options[] = { + "Make USER the owner of files related to processes without one. " + "Be aware that USER will be granted access to the environment and " + "other sensitive information about the processes in question. " +- "(default: use uid 0)" }, ++ "(default: use uid " STR (OPT_ANON_OWNER) ")" }, + { "nodev", NODEV_KEY, NULL, 0, + "Ignored for compatibility with Linux' procfs." }, + { "noexec", NOEXEC_KEY, NULL, 0, +-- +2.1.0 + diff --git a/debian/patches/startup-0003-startup-rename-hurd-init-to-hurd-startup.patch b/debian/patches/startup-0003-startup-rename-hurd-init-to-hurd-startup.patch new file mode 100644 index 00000000..7a874ab6 --- /dev/null +++ b/debian/patches/startup-0003-startup-rename-hurd-init-to-hurd-startup.patch @@ -0,0 +1,3678 @@ +From 3ead9b6a0328e8aa85d652bcabdb76ce86360907 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 17 Sep 2013 13:44:44 +0200 +Subject: [PATCH 3/8] startup: rename /hurd/init to /hurd/startup + +This patch series splits /hurd/init into two programs. As a first +step, this patch renames /hurd/init to /hurd/startup. It is called +startup because it speaks the startup protocol. + +* startup: Rename init to startup. Adjust accordingly. +* Makefile (prog-subdirs): Likewise. +* doc/hurd.texi (Server Bootstrap): Likewise. +* hurd/paths.h (_HURD_STARTUP): Likewise. +* libdiskfs/boot-start.c (diskfs_boot_init_program): Likewise. +* libdiskfs/opts-std-startup.c (startup_options): Likewise. +--- + Makefile | 3 +- + doc/hurd.texi | 6 +- + hurd/paths.h | 2 +- + init/Makefile | 31 - + init/init.c | 1593 ------------------------------------------ + init/stubs.c | 139 ---- + libdiskfs/boot-start.c | 2 +- + libdiskfs/opts-std-startup.c | 2 +- + startup/Makefile | 31 + + startup/startup.c | 1593 ++++++++++++++++++++++++++++++++++++++++++ + startup/stubs.c | 139 ++++ + 11 files changed, 1771 insertions(+), 1770 deletions(-) + delete mode 100644 init/Makefile + delete mode 100644 init/init.c + delete mode 100644 init/stubs.c + create mode 100644 startup/Makefile + create mode 100644 startup/startup.c + create mode 100644 startup/stubs.c + +diff --git a/Makefile b/Makefile +index 0b9eff2..455df67 100644 +--- a/Makefile ++++ b/Makefile +@@ -31,7 +31,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \ + libnetfs libpipe libstore libhurdbugaddr libftpconn libcons + + # Hurd programs +-prog-subdirs = auth proc exec init term \ ++prog-subdirs = auth proc exec term \ + ext2fs isofs tmpfs fatfs \ + storeio pflocal pfinet defpager mach-defpager \ + login daemons boot console \ +@@ -40,6 +40,7 @@ prog-subdirs = auth proc exec init term \ + benchmarks fstests \ + random \ + procfs \ ++ startup \ + + ifeq ($(HAVE_SUN_RPC),yes) + prog-subdirs += nfs nfsd +diff --git a/doc/hurd.texi b/doc/hurd.texi +index 697cce7..7e7b5ee 100644 +--- a/doc/hurd.texi ++++ b/doc/hurd.texi +@@ -563,10 +563,10 @@ bootstrapped by starting the GNU Mach microkernel and two programs: + the root filesystem and the exec server. + + The @option{--multiboot-command-line} option tells the file system server that +-it is a root filesystem, which triggers it to run @command{/hurd/init} as PID +-2. @command{/hurd/init} starts the @command{/hurd/proc} and ++it is a root filesystem, which triggers it to run @command{/hurd/startup} as PID ++2. @command{/hurd/startup} starts the @command{/hurd/proc} and + @command{/hurd/auth} servers. After the servers are launched +-@command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to ++@command{/hurd/startup} starts the @command{/libexec/runsystem.sh} script to + finish booting. + + After the Hurd has been booted, other sets of core Hurd servers can be +diff --git a/hurd/paths.h b/hurd/paths.h +index 4877132..489da57 100644 +--- a/hurd/paths.h ++++ b/hurd/paths.h +@@ -39,7 +39,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + the canonical pathname being /hurd/foo. */ + + #define _HURD "/hurd/" +-#define _HURD_INIT _HURD "init" ++#define _HURD_STARTUP _HURD "startup" + #define _HURD_PROC _HURD "proc" + #define _HURD_AUTH _HURD "auth" + +diff --git a/init/Makefile b/init/Makefile +deleted file mode 100644 +index ffb82ff..0000000 +--- a/init/Makefile ++++ /dev/null +@@ -1,31 +0,0 @@ +-# +-# Copyright (C) 1994,95,96,99,2001 Free Software Foundation, Inc. +-# +-# This program is free software; you can redistribute it and/or +-# modify it under the terms of the GNU General Public License as +-# published by the Free Software Foundation; either version 2, or (at +-# your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-# General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +- +-dir := init +-makemode := server +- +-SRCS = init.c stubs.c +-OBJS = $(SRCS:.c=.o) \ +- startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ +- startup_notifyUser.o +-target = init +-HURDLIBS = shouldbeinlibc +- +-include ../Makeconf +- +-mung_msg_S.h: msg_S.h +- sed 's/msg_server/mung_msg_server/' < $< > $@ +diff --git a/init/init.c b/init/init.c +deleted file mode 100644 +index 6bc6701..0000000 +--- a/init/init.c ++++ /dev/null +@@ -1,1593 +0,0 @@ +-/* Start and maintain hurd core servers and system run state +- +- Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +- 2005, 2008, 2013 Free Software Foundation, Inc. +- This file is part of the GNU Hurd. +- +- The GNU Hurd is free software; you can redistribute it and/or modify +- it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 2, or (at your option) +- any later version. +- +- The GNU Hurd is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with the GNU Hurd; see the file COPYING. If not, write to +- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +- +-/* Written by Michael I. Bushnell and Roland McGrath. */ +- +-/* This is probably more include files than I've ever seen before for +- one file. */ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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 +-#include +-#include +-#include +-#include +- +-/* 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++ ++/* 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/startup-0004-init-add-a-minimalist-init-program.patch b/debian/patches/startup-0004-init-add-a-minimalist-init-program.patch new file mode 100644 index 00000000..7b6af753 --- /dev/null +++ b/debian/patches/startup-0004-init-add-a-minimalist-init-program.patch @@ -0,0 +1,572 @@ +From 5551fcc6442401d72b4db5ac5f5de471f07eeb0a 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] init: add a minimalist init program + +This patch adds a minimalist init program. It is somewhat lacking in +features, but is able to bring up a Hurd system with the runsystem and +rc scripts. In fact, it roughly does what the former /hurd/init did, +modulo all the very early bootstrapping stuff and the startup +protocol. It is started when all the essential servers are up and +running, so it can make use of most of the POSIX goodies, making its +implementation much simpler. + +* Makefile (prog-subdirs): Add init. +* daemons/runsystem.sh: Generalize runsystem so that it can start any +init as specified on the kernel command line. By default, it starts +/hurd/init. +* daemons/runsystem.hurd: This is a verbatim copy of runsystem.sh. It +is started by /hurd/init. +* daemons/rc.sh: Do not start /hurd/mach-defpager as it is already +started in runsystem.sh. +* daemons/Makefile (SRCS): Add runsystem.hurd. +* init/Makefile: New file. +* init/init.c: Likewise. +--- + Makefile | 1 + + daemons/Makefile | 4 +- + daemons/rc.sh | 3 - + daemons/runsystem.hurd | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ + daemons/runsystem.sh | 80 +++++++++---------------- + init/Makefile | 24 ++++++++ + init/init.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 364 insertions(+), 58 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/Makefile b/daemons/Makefile +index d16680e..db1acc7 100644 +--- a/daemons/Makefile ++++ b/daemons/Makefile +@@ -22,7 +22,9 @@ makemode := utilities + + targets = rc getty mail.local console-run runttys runsystem + special-targets = rc runsystem +-SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c ++SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c \ ++ runsystem.hurd \ ++ + installationdir = $(libexecdir) + + HURDLIBS = fshelp ports shouldbeinlibc +diff --git a/daemons/rc.sh b/daemons/rc.sh +index 5cf44fa..1240883 100644 +--- a/daemons/rc.sh ++++ b/daemons/rc.sh +@@ -2,9 +2,6 @@ + + PATH=/bin:/sbin + +-# Start the default pager. It will bail if there is already one running. +-/hurd/mach-defpager +- + # Set up swap space. This will complain if no default pager is functioning. + swapon -a + +diff --git a/daemons/runsystem.hurd b/daemons/runsystem.hurd +new file mode 100644 +index 0000000..f4f2771 +--- /dev/null ++++ b/daemons/runsystem.hurd +@@ -0,0 +1,155 @@ ++#!/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 ++} ++ ++ ++# See whether pflocal is set up already, and do so if not (install case) ++# ++# 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 ++ # The root filesystem should be read-only at this point. ++ if fsysopts / --update --writable ; then ++ settrans -c /servers/socket/1 /hurd/pflocal ++ else ++ singleuser "Failed to create /servers/socket/1." ++ fi ++fi ++ ++# 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..bd145ed 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 /hurd/init or any other roughly SysV init-compatible program ++# to bring up the "userland" parts of a normal system. + # + + +@@ -22,11 +22,10 @@ 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=/hurd/init + + ### + +@@ -44,7 +43,7 @@ trap 'reopen_console' SIGLOST + # 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 () ++function singleuser() + { + test $# -eq 0 || echo "$0: $*" + for try in ${fallback_shells}; do +@@ -54,6 +53,8 @@ function singleuser () + exit 127 + } + ++# Print a newline. ++echo + + # See whether pflocal is set up already, and do so if not (install case) + # +@@ -85,20 +86,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 +110,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 ++# Start the default pager. It will bail if there is already one running. ++/hurd/mach-defpager + +- # This program reads /etc/ttys and starts the programs it says to. +- ${RUNTTYS} & +- runttys_pid=$! ++# 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 + +- # Wait for runttys to die, meanwhile handling trapped signals. +- wait ++fsysopts / --update --readonly + +- # Go back to the top of the infinite loop, as if booting single-user. +- rc=false +- +-done ++# Finally, start the actual 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 . ++ ++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 . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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/startup-0005-startup-do-not-pass-signals-on-to-the-child.patch b/debian/patches/startup-0005-startup-do-not-pass-signals-on-to-the-child.patch new file mode 100644 index 00000000..33046438 --- /dev/null +++ b/debian/patches/startup-0005-startup-do-not-pass-signals-on-to-the-child.patch @@ -0,0 +1,251 @@ +From b7eed065f9118964dc875e4f03c8b07332b44a65 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 +-#include +-#include +-#include +-#include +- +-/* 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/startup-0006-startup-be-more-specific-in-the-shutdown-message.patch b/debian/patches/startup-0006-startup-be-more-specific-in-the-shutdown-message.patch new file mode 100644 index 00000000..d2f9f5ce --- /dev/null +++ b/debian/patches/startup-0006-startup-be-more-specific-in-the-shutdown-message.patch @@ -0,0 +1,29 @@ +From 4c6541b4955425e62c2014c66bcb541c95c534db 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/startup-0007-startup-fix-the-declaration-of-the-_server-functions.patch b/debian/patches/startup-0007-startup-fix-the-declaration-of-the-_server-functions.patch new file mode 100644 index 00000000..b8577c9d --- /dev/null +++ b/debian/patches/startup-0007-startup-fix-the-declaration-of-the-_server-functions.patch @@ -0,0 +1,28 @@ +From bbdbeeba0076f31ad78849be86596528dfbeac85 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/startup-0008-startup-bind-the-startup-server-to-servers-startup.patch b/debian/patches/startup-0008-startup-bind-the-startup-server-to-servers-startup.patch new file mode 100644 index 00000000..d3633eb0 --- /dev/null +++ b/debian/patches/startup-0008-startup-bind-the-startup-server-to-servers-startup.patch @@ -0,0 +1,344 @@ +From ccce2ecc7426fc65d05db387b5d8390644c17dc5 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] startup: bind the startup server to /servers/startup + +Previously, the Hurd (ab)used the fact that the startup server speaks +all protocols on its message port. Any server that wished to register +for shutdown notifications would use XXX to get a port to the startup +server. + +This hardcodes the PID of /hurd/startup, and does not allow one to +point a server to ones own startup server (e.g. using remap). + +Bind the startup server to /servers/startup instead. Use this to +contact the startup server. + +* exec/main.c (S_exec_init): Use /servers/startup. Fall back to the +old method so that the system still boots when the node +/servers/startup is missing. +* hurd/paths.h (_SERVERS_STARTUP): New macro. +* libdiskfs/boot-start.c (diskfs_S_fsys_init): Use /servers/startup. +* libdiskfs/init-startup.c (_diskfs_init_completed): Likewise. +* pfinet/main.c (arrange_shutdown_notification): Likewise. +* startup/Makefile (OBJS): Add fsysServer.o. +* startup/startup.c (demuxer): Handle the fsys protocol. +(main): Bind to /servers/startup. +(S_fsys_getroot): Implement fsys_getroot. Stub out the rest. +--- + exec/main.c | 11 ++++- + hurd/paths.h | 1 + + libdiskfs/boot-start.c | 9 ++-- + libdiskfs/init-startup.c | 13 ++++-- + pfinet/main.c | 12 ++--- + startup/Makefile | 2 +- + startup/startup.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 146 insertions(+), 21 deletions(-) + +diff --git a/exec/main.c b/exec/main.c +index 78faebd..664f150 100644 +--- a/exec/main.c ++++ b/exec/main.c +@@ -251,8 +251,15 @@ S_exec_init (struct trivfs_protid *protid, + + proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION); + +- err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup); +- assert_perror (err); ++ startup = file_name_lookup (_SERVERS_STARTUP, 0, 0); ++ if (startup == MACH_PORT_NULL) ++ { ++ error (0, errno, "%s", _SERVERS_STARTUP); ++ ++ /* Fall back to abusing the message port lookup. */ ++ err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup); ++ assert_perror (err); ++ } + mach_port_deallocate (mach_task_self (), procserver); + + /* Call startup_essential task last; init assumes we are ready to +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/libdiskfs/boot-start.c b/libdiskfs/boot-start.c +index 42e991e..cfe2303 100644 +--- a/libdiskfs/boot-start.c ++++ b/libdiskfs/boot-start.c +@@ -33,7 +33,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include + #include + #include +-#include + #include "exec_S.h" + #include "exec_startup_S.h" + #include "fsys_S.h" +@@ -602,9 +601,12 @@ diskfs_S_fsys_init (struct diskfs_control *pt, + + proc_register_version (procserver, host, diskfs_server_name, "", + diskfs_server_version); ++ mach_port_deallocate (mach_task_self (), procserver); + +- err = proc_getmsgport (procserver, HURD_PID_STARTUP, &startup); +- if (!err) ++ startup = file_name_lookup (_SERVERS_STARTUP, 0, 0); ++ if (startup == MACH_PORT_NULL) ++ error (0, errno, "%s", _SERVERS_STARTUP); ++ else + { + startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, + diskfs_server_name, host); +@@ -612,7 +614,6 @@ diskfs_S_fsys_init (struct diskfs_control *pt, + } + + mach_port_deallocate (mach_task_self (), host); +- mach_port_deallocate (mach_task_self (), procserver); + + _diskfs_init_completed (); + +diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c +index d10c964..3a588e1 100644 +--- a/libdiskfs/init-startup.c ++++ b/libdiskfs/init-startup.c +@@ -25,8 +25,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include + #include + #include ++#include + #include +-#include + + #include "startup_S.h" + +@@ -195,15 +195,18 @@ _diskfs_init_completed () + + /* Mark us as important. */ + err = proc_mark_important (proc); ++ mach_port_deallocate (mach_task_self (), proc); + /* This might fail due to permissions or because the old proc server + is still running, ignore any such errors. */ + if (err && err != EPERM && err != EMIG_BAD_ID) + goto errout; + +- err = proc_getmsgport (proc, HURD_PID_STARTUP, &init); +- mach_port_deallocate (mach_task_self (), proc); +- if (err) +- goto errout; ++ init = file_name_lookup (_SERVERS_STARTUP, 0, 0); ++ if (init == MACH_PORT_NULL) ++ { ++ err = errno; ++ goto errout; ++ } + + notify = ports_get_send_right (pi); + ports_port_deref (pi); +diff --git a/pfinet/main.c b/pfinet/main.c +index 5b0262f..3cd5f13 100644 +--- a/pfinet/main.c ++++ b/pfinet/main.c +@@ -24,11 +24,11 @@ + #include + #include + #include ++#include + #include + #include + #include + #include +-#include + + /* Include Hurd's errno.h file, but don't include glue-include/hurd/errno.h, + since it #undef's the errno macro. */ +@@ -154,7 +154,6 @@ arrange_shutdown_notification () + { + error_t err; + mach_port_t initport, notify; +- process_t procserver; + struct port_info *pi; + + shutdown_notify_class = ports_create_class (0, 0); +@@ -169,13 +168,8 @@ arrange_shutdown_notification () + if (err) + return; + +- procserver = getproc (); +- if (!procserver) +- return; +- +- err = proc_getmsgport (procserver, HURD_PID_STARTUP, &initport); +- mach_port_deallocate (mach_task_self (), procserver); +- if (err) ++ initport = file_name_lookup (_SERVERS_STARTUP, 0, 0); ++ if (initport == MACH_PORT_NULL) + return; + + notify = ports_get_send_right (pi); +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..ff58270 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,18 @@ 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) ++ error (0, errno, "%s", _SERVERS_STARTUP); ++ else ++ { ++ file_set_translator (node, ++ 0, FS_TRANS_SET, 0, ++ NULL, 0, ++ startup, MACH_MSG_TYPE_COPY_SEND); ++ mach_port_deallocate (mach_task_self (), node); ++ } ++ + /* 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 +1558,108 @@ 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) ++{ ++ int is_root = 0; ++ size_t i; ++ ++ for (i = 0; i < nuids; i++) ++ if (uids[i] == 0) ++ { ++ is_root = 1; ++ break; ++ } ++ ++ if (! is_root) ++ return EPERM; ++ ++ *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; ++} +-- +2.1.0 + -- cgit v1.2.3