summaryrefslogtreecommitdiff
path: root/debian/patches/0006-XXX-bootshell.patch
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-01-31 01:30:00 +0100
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-01-31 01:30:00 +0100
commiteff9117348b8b0f9df889e31f0c2f874b0d64584 (patch)
treeed780c79177cb627aa4a58a33bf3706e3220435c /debian/patches/0006-XXX-bootshell.patch
parent09ce39f6748d86751c27878827d7288f3f094795 (diff)
drop old patch series
Diffstat (limited to 'debian/patches/0006-XXX-bootshell.patch')
-rw-r--r--debian/patches/0006-XXX-bootshell.patch3741
1 files changed, 0 insertions, 3741 deletions
diff --git a/debian/patches/0006-XXX-bootshell.patch b/debian/patches/0006-XXX-bootshell.patch
deleted file mode 100644
index b6922b36..00000000
--- a/debian/patches/0006-XXX-bootshell.patch
+++ /dev/null
@@ -1,3741 +0,0 @@
-From d4a61b241f947d1c5dbd114190e059e6c93c9504 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 23 Dec 2014 15:03:44 +0100
-Subject: [PATCH hurd 6/6] XXX bootshell
-
-XXX hack in toplevel Makefile.
----
- Makefile | 1 +
- bootshell/Makefile | 68 +++
- bootshell/boot.scm | 270 ++++++++++++
- bootshell/bootshell.h | 48 ++
- bootshell/elf-exec.c | 200 +++++++++
- bootshell/exceptions.c | 92 ++++
- bootshell/exec-startup.c | 182 ++++++++
- bootshell/ffi.c | 1061 +++++++++++++++++++++++++++++++++++++++++++++
- bootshell/ffi.h | 158 +++++++
- bootshell/fs.c | 111 +++++
- bootshell/fsys.c | 123 ++++++
- bootshell/main.c | 263 +++++++++++
- bootshell/mig-decls.h | 22 +
- bootshell/mig-mutate.h | 27 ++
- bootshell/runsystem.scm | 211 +++++++++
- bootshell/scheme-config.h | 31 ++
- bootshell/startup.c | 508 ++++++++++++++++++++++
- bootshell/startup.h | 36 ++
- bootshell/utils.c | 118 +++++
- config.make.in | 4 +
- configure.ac | 15 +
- 21 files changed, 3549 insertions(+)
- create mode 100644 bootshell/Makefile
- create mode 100644 bootshell/boot.scm
- create mode 100644 bootshell/bootshell.h
- create mode 100644 bootshell/elf-exec.c
- create mode 100644 bootshell/exceptions.c
- create mode 100644 bootshell/exec-startup.c
- create mode 100644 bootshell/ffi.c
- create mode 100644 bootshell/ffi.h
- create mode 100644 bootshell/fs.c
- create mode 100644 bootshell/fsys.c
- create mode 100644 bootshell/main.c
- create mode 100644 bootshell/mig-decls.h
- create mode 100644 bootshell/mig-mutate.h
- create mode 100644 bootshell/runsystem.scm
- create mode 100644 bootshell/scheme-config.h
- create mode 100644 bootshell/startup.c
- create mode 100644 bootshell/startup.h
- create mode 100644 bootshell/utils.c
-
-diff --git a/Makefile b/Makefile
-index 3178740..3a2c2ed 100644
---- a/Makefile
-+++ b/Makefile
-@@ -32,6 +32,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
-
- # Hurd programs
- prog-subdirs = auth proc exec term \
-+ bootshell \
- ext2fs isofs tmpfs fatfs \
- storeio pflocal pfinet defpager mach-defpager \
- login daemons boot console \
-diff --git a/bootshell/Makefile b/bootshell/Makefile
-new file mode 100644
-index 0000000..b9e614a
---- /dev/null
-+++ b/bootshell/Makefile
-@@ -0,0 +1,68 @@
-+# Makefile for bootshell subdirectory of hurd sources
-+#
-+# Copyright (C) 1999, 2000, 2002, 2007, 2010, 2012 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 this program; if not, write to the Free Software
-+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+dir := bootshell
-+makemode:= server
-+target := bootshell
-+
-+SCRIPTS := \
-+ init.scm \
-+ boot.scm \
-+ runsystem.scm \
-+
-+SRCS := \
-+ scheme.c \
-+ main.c \
-+ exceptions.c \
-+ fs.c \
-+ fsys.c \
-+ exec-startup.c \
-+ startup.c \
-+ utils.c \
-+ ffi.c \
-+ elf-exec.c \
-+
-+SERVER_PROTOCOLS := exc exec_startup fs fsys startup
-+USER_PROTOCOLS := startup startup_reply
-+
-+MIGSTUBS:= $(foreach p,$(SERVER_PROTOCOLS),$(p)Server.o) \
-+ $(foreach p,$(USER_PROTOCOLS),$(p)User.o)
-+OBJS := $(SRCS:.c=.o) $(SCRIPTS:.scm=.o) $(MIGSTUBS)
-+
-+HURDLIBS:= shouldbeinlibc
-+# XXX why doesn't $(libreadline_LIBS) work ???
-+OTHERLIBS:= $(libreadline_LIBS) -lreadline -lhistory -lncurses -ltinfo -lpthread
-+CFLAGS += -imacros scheme-config.h
-+LDFLAGS += -static
-+MIGSFLAGS := -imacros mig-mutate.h
-+
-+%.o: %.scm
-+ cat <$< >.$@
-+ $(LD) -r --format=binary .$@ -o $@
-+ rm .$@
-+
-+NOWARN := conversion sign-conversion switch unused-function
-+CFLAGS := $(filter-out $(foreach flag,$NOWARN,-W$(flag)),$(CFLAGS))
-+
-+# XXX
-+CFLAGS += -Wno-sign-conversion
-+
-+include ../Makeconf
-diff --git a/bootshell/boot.scm b/bootshell/boot.scm
-new file mode 100644
-index 0000000..cf547d0
---- /dev/null
-+++ b/bootshell/boot.scm
-@@ -0,0 +1,270 @@
-+;; Bootshell, a Scheme shell, a flexible multiserver bootstrap solution.
-+;;
-+;; Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+;; Missing library functions.
-+(define (filter pred lst)
-+ (cond ((null? lst) '())
-+ ((pred (car lst))
-+ (cons (car lst) (filter pred (cdr lst))))
-+ (else (filter pred (cdr lst)))))
-+
-+(define (any p l)
-+ (cond ((null? l) #f)
-+ ((p (car l)) #t)
-+ (else (any p (cdr l)))))
-+
-+;; Is s1 a prefix of s2 ?
-+(define (string-prefix? s1 s2)
-+ (and (>= (string-length s2) (string-length s1))
-+ (string=? s1 (substring s2 0 (string-length s1)))))
-+
-+;; Given a list of prefixes, does s start with any of them ?
-+(define (string-prefix-any? lp s)
-+ (any (lambda (p) (string-prefix? p s)) lp))
-+
-+;; The `catch' from init.scm doesn't give the thrown value to the
-+;; handler. As a crappy workaround, we set! `last-exception' to the
-+;; last the exception.
-+(define last-exception '())
-+(define (throw . x)
-+ (set! last-exception x)
-+ (if (more-handlers?)
-+ (apply (pop-handler))
-+ (apply error x)))
-+(define *error-hook* throw)
-+
-+;; Foreign function wrapper. Expects F to return a list with the
-+;; first element being the `error_t' value returned by the foreign
-+;; function. The error is thrown, or the cdr of the result is
-+;; returned.
-+(define (ffi-apply name f args)
-+ (let ((result (apply f args)))
-+ (cond
-+ ((not (= (car result) 0)) (throw (string-append
-+ name ": " (strerror (car result)))))
-+ ((and (= (car result) 0) (pair? (cdr result))) (cadr result))
-+ ((= (car result) 0) '())
-+ (else
-+ (throw "Weird.")))))
-+
-+;; Convenience functions.
-+(define (echo . msg)
-+ (map display msg)
-+ (newline))
-+
-+(define (trace-show x)
-+ (write x)
-+ x)
-+
-+;; Semi-crappy repl using `prompt' function.
-+(define (shell p)
-+ (call/cc
-+ (lambda (exit)
-+ (let loop ((prefix ""))
-+ (let ((line (prompt (p prefix))))
-+ (if (and (not (eof-object? line)) (eqv? (string-length line) 0))
-+ (exit (loop prefix)))
-+ (if (not (eof-object? line))
-+ (let* ((next (string-append prefix line))
-+ (c (catch (begin (echo "Parse error: " last-exception)
-+ (loop prefix))
-+ (read (open-input-string next)))))
-+ (if (not (eof-object? c))
-+ (begin
-+ (catch (echo "Error: " last-exception)
-+ (echo " ===> " (eval c)))
-+ (exit (loop ""))))
-+ (exit (loop next)))))))))
-+
-+(define (prompt-append-prefix prompt prefix)
-+ (string-append prompt (if (> (string-length prefix) 0)
-+ (string-append prefix "...")
-+ "> ")))
-+
-+;; Default repl run by the bootshell.
-+(define (interactive-repl)
-+ (shell (lambda (p) (prompt-append-prefix "(bootshell) " p))))
-+
-+;; Default repl run by `panic'.
-+(define (emergency-shell)
-+ (shell (lambda (p) (prompt-append-prefix "(emergency-shell) " p))))
-+
-+;; Display a message and run the emergency shell.
-+(define (panic . msg)
-+ (display "\n\npanic: ")
-+ (map display msg)
-+ (newline)
-+ (emergency-shell))
-+
-+;; Mach port management.
-+(define (mach-port-valid? p) (not (or (= p MACH_PORT_NULL)
-+ (= p MACH_PORT_DEAD))))
-+
-+(define (make-send-right receive-right)
-+ (mach-port-insert-right mach-task-self receive-right receive-right
-+ MACH_MSG_TYPE_MAKE_SEND))
-+(define (copy-send-right send-right)
-+ (mach-port-insert-right mach-task-self send-right send-right
-+ MACH_MSG_TYPE_COPY_SEND))
-+
-+;; Binds a send right to an identifier, much like `let'. Deallocates
-+;; the send right once it goes out of scope.
-+(macro (letport form)
-+ (let ((result-sym (gensym)))
-+ `((lambda ((,@(caaadr form)))
-+ (let ((,result-sym
-+ ,(if (= 1 (length (cadr form)))
-+ `(begin ,@(cddr form))
-+ `(letport ,(cdadr form) ,@(cddr form)))))
-+ (if (mach-port-valid? ,(caaadr form))
-+ (mach-port-deallocate mach-task-self ,(caaadr form)))
-+ ,result-sym)) ,@(cdaadr form))))
-+
-+;; TinySCHEME doesn't have define-syntax :(
-+;;
-+;; (define-syntax letport
-+;; (syntax-rules ()
-+;; ((letport ((var expr) ...) body ...)
-+;; ((lambda expressions
-+;; (let ((result (apply (lambda (var ...) body ...) expressions)))
-+;; (map (lambda (p) (mach-port-deallocate mach-task-self p))
-+;; expressions)
-+;; result)) expr ...))))
-+
-+;; task management
-+
-+(define (task-get-kernel-port t)
-+ (task-get-special-port t TASK_KERNEL_PORT))
-+(define (task-get-exception-port t)
-+ (task-get-special-port t TASK_EXCEPTION_PORT))
-+(define (task-get-bootstrap-port t)
-+ (task-get-special-port t TASK_BOOTSTRAP_PORT))
-+
-+(define (task-set-kernel-port t p)
-+ (task-set-special-port t TASK_KERNEL_PORT p))
-+(define (task-set-exception-port t p)
-+ (task-set-special-port t TASK_EXCEPTION_PORT p))
-+(define (task-set-bootstrap-port t p)
-+ (task-set-special-port t TASK_BOOTSTRAP_PORT p))
-+
-+;; Hurd server bootstrap.
-+
-+(define ESUCCESS 0) ;
-+
-+;; translator linkage
-+
-+(define (set-active-translator path active-control)
-+ (letport ((node (file-name-lookup path O_NOTRANS 438))) ;;=^= 0666
-+ (file-set-translator node 0 FS_TRANS_SET 0 0 0
-+ active-control MACH_MSG_TYPE_COPY_SEND)))
-+
-+;; Wait for the predicate CONDITION to return #t, or throw 'timeout
-+;; after T microseconds.
-+(define (wait-for condition t)
-+ (if (<= t 0)
-+ (throw 'timeout)
-+ (if (not (condition))
-+ (begin (usleep 10000)
-+ (wait-for condition (- t 10000))))))
-+
-+;; Read a word from port P.
-+(define (read-word p)
-+ (list->string
-+ (let f ()
-+ (let ((c (peek-char p)))
-+ (cond
-+ ((eof-object? c) '())
-+ ((char-alphabetic? c)
-+ (read-char p)
-+ (cons c (f)))
-+ (else '()))))))
-+
-+;; Read everything from port P.
-+(define (read-all p)
-+ (list->string
-+ (let f ()
-+ (let ((c (peek-char p)))
-+ (cond
-+ ((eof-object? c) '())
-+ (else (read-char p)
-+ (cons c (f))))))))
-+
-+;; Shell-like functions.
-+
-+(define cd chdir)
-+(define (pwd) (echo (getcwd)))
-+(define (cat path)
-+ (display (call-with-input-file path read-all)))
-+(define (hostname)
-+ ((lambda (x) (if (string? x) x "unnamed"))
-+ (call-with-input-file "/etc/hostname" read-word)))
-+
-+(define (print-banner)
-+ (echo "
-+Welcome to bootshell, a scheme shell. Type `(help)' for help.
-+"))
-+
-+(define (reboot-hurd)
-+ (letport ((startup (file-name-lookup "/servers/startup" 0 0)))
-+ (startup-reboot startup host-priv RB_AUTOBOOT)))
-+
-+(define (halt-hurd)
-+ (letport ((startup (file-name-lookup "/servers/startup" 0 0)))
-+ (startup-reboot startup host-priv RB_HALT)))
-+
-+(define (reboot-mach) (host-reboot host-priv RB_AUTOBOOT))
-+(define (halt-mach) (host-reboot host-priv RB_HALT))
-+(define (kdb-mach) (host-reboot host-priv RB_DEBUGGER))
-+
-+(define (reboot)
-+ (catch (reboot-mach)
-+ (reboot-hurd)))
-+(define (halt)
-+ (catch (halt-mach)
-+ (halt-hurd)))
-+
-+;; Online documentation.
-+
-+(define (help)
-+ (echo "Welcome to the Hurd boot shell. XXX this is not up to date :(
-+
-+Functions
-+ General shell-like functions
-+ cat cd echo halt help hostname kdb mach-print panic prompt pwd
-+ reboot shell sleep {reboot,halt}-{mach,hurd}
-+" "
-+ Mach related
-+ mach-port-valid? {copy,make}-send-right task-{create,resume,terminate}
-+ task-{g,s}et-{special,kernel,exception,bootstrap}-port host-reboot
-+" "
-+ Hurd related
-+ file_name_lookup chdir getcwd startup-reboot
-+ XXX write them
-+ {s,g}etauth {s,g}etproc file_name_lookup_under file_name_path_lookup
-+" "
-+Environment:
-+ mach-task-self exception-port bootstrap-port host-priv device-master
-+ rootfs-task hello-task rootfs-control"))
-+
-+;; XXX
-+
-+(define log display)
-+
-+;; We're ready.
-+(echo version ".")
-diff --git a/bootshell/bootshell.h b/bootshell/bootshell.h
-new file mode 100644
-index 0000000..b6dc67a
---- /dev/null
-+++ b/bootshell/bootshell.h
-@@ -0,0 +1,48 @@
-+/* Bootshell, a Scheme shell, a flexible multiserver bootstrap solution.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#ifndef _HURD_BOOTSHELL_H
-+#define _HURD_BOOTSHELL_H
-+
-+#include <mach.h>
-+
-+extern const char *argp_program_version;
-+
-+extern mach_port_t portarray_template[];
-+
-+/* We catch exceptions using this port. */
-+extern mach_port_t exception_port;
-+
-+extern mach_port_t console;
-+extern mach_port_t rootnode;
-+
-+error_t init_exception_handling (void);
-+error_t init_fs_server (void);
-+
-+mach_msg_return_t
-+mach_msg_server_timeout_once (boolean_t (*demux) (mach_msg_header_t *request,
-+ mach_msg_header_t *reply),
-+ mach_msg_size_t max_size,
-+ mach_port_t rcv_name,
-+ mach_msg_option_t option,
-+ mach_msg_timeout_t timeout);
-+
-+#define TRACE error (0, 0, "%s:%d", __FUNCTION__, __LINE__);
-+
-+#endif /* _HURD_BOOTSHELL_H */
-diff --git a/bootshell/elf-exec.c b/bootshell/elf-exec.c
-new file mode 100644
-index 0000000..c8a8e14
---- /dev/null
-+++ b/bootshell/elf-exec.c
-@@ -0,0 +1,200 @@
-+/* Load an ELF image into a task without using the exec server.
-+
-+ Copyright (C) 1993-2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <argz.h>
-+#include <assert.h>
-+#include <elf.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <mach.h>
-+#include <mach/machine/vm_param.h> /* For VM_XXX_ADDRESS */
-+#include <stdlib.h>
-+#include <string.h>
-+#include <sys/ioctl.h>
-+#include <sys/mman.h>
-+#include <unistd.h>
-+
-+#include "ffi.h"
-+
-+error_t
-+load_image (task_t t,
-+ char *file,
-+ vm_address_t *addr)
-+{
-+ error_t err;
-+ int fd;
-+ ssize_t count;
-+ Elf32_Ehdr hdr;
-+
-+ fd = open (file, O_RDONLY, 0);
-+ if (fd == -1)
-+ return errno;
-+
-+ count = read (fd, &hdr, sizeof hdr);
-+ if (count != sizeof hdr)
-+ return errno;
-+
-+ if (*(Elf32_Word *) hdr.e_ident != *(Elf32_Word *) "\177ELF")
-+ return EINVAL; // XXX
-+
-+ Elf32_Phdr phdrs[hdr.e_phnum], *ph;
-+ lseek (fd, hdr.e_phoff, SEEK_SET);
-+ read (fd, phdrs, sizeof phdrs);
-+ for (ph = phdrs; ph < &phdrs[sizeof phdrs/sizeof phdrs[0]]; ++ph)
-+ if (ph->p_type == PT_LOAD)
-+ {
-+ vm_address_t buf;
-+ vm_size_t offs = ph->p_offset & (ph->p_align - 1);
-+ vm_size_t bufsz = round_page (ph->p_filesz + offs);
-+
-+ buf = (vm_address_t) mmap (0, bufsz,
-+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-+
-+ lseek (fd, ph->p_offset, SEEK_SET);
-+ read (fd, (void *)(buf + offs), ph->p_filesz);
-+
-+ ph->p_memsz = ((ph->p_vaddr + ph->p_memsz + ph->p_align - 1)
-+ & ~(ph->p_align - 1));
-+ ph->p_vaddr &= ~(ph->p_align - 1);
-+ ph->p_memsz -= ph->p_vaddr;
-+
-+ err = vm_allocate (t, (vm_address_t*)&ph->p_vaddr, ph->p_memsz, 0);
-+ if (err)
-+ return err;
-+
-+ err = vm_write (t, ph->p_vaddr, buf, bufsz);
-+ if (err)
-+ return err;
-+
-+ munmap ((caddr_t) buf, bufsz);
-+ err = vm_protect (t, ph->p_vaddr, ph->p_memsz, 0,
-+ ((ph->p_flags & PF_R) ? VM_PROT_READ : 0) |
-+ ((ph->p_flags & PF_W) ? VM_PROT_WRITE : 0) |
-+ ((ph->p_flags & PF_X) ? VM_PROT_EXECUTE : 0));
-+ if (err)
-+ return err;
-+ }
-+
-+ *addr = hdr.e_entry;
-+ return 0;
-+}
-+
-+/* XXX refactor this mess */
-+error_t
-+boot_script_exec_cmd (mach_port_t task, char *path, int argc,
-+ char **argv, char *strings, int stringlen)
-+{
-+ error_t err;
-+ char *args, *p;
-+ int arg_len, i;
-+ size_t reg_size;
-+ void *arg_pos;
-+ vm_offset_t stack_start, stack_end;
-+ vm_address_t startpc, str_start;
-+ thread_t thread;
-+
-+ err = load_image (task, path, &startpc);
-+ if (err)
-+ return err;
-+
-+ arg_len = stringlen + (argc + 2) * sizeof (char *) + sizeof (integer_t);
-+ arg_len += 5 * sizeof (int);
-+ stack_end = VM_MAX_ADDRESS;
-+ stack_start = VM_MAX_ADDRESS - 16 * 1024 * 1024;
-+ vm_allocate (task, &stack_start, stack_end - stack_start, FALSE);
-+ arg_pos = (void *) ((stack_end - arg_len) & ~(sizeof (natural_t) - 1));
-+ args = mmap (0, stack_end - trunc_page ((vm_offset_t) arg_pos),
-+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-+ str_start = ((vm_address_t) arg_pos
-+ + (argc + 2) * sizeof (char *) + sizeof (integer_t));
-+ p = args + ((vm_address_t) arg_pos & (vm_page_size - 1));
-+ *(int *) p = argc;
-+ p = (void *) p + sizeof (int);
-+ for (i = 0; i < argc; i++)
-+ {
-+ *(char **) p = argv[i] - strings + (char *) str_start;
-+ p = (void *) p + sizeof (char *);
-+ }
-+ *(char **) p = 0;
-+ p = (void *) p + sizeof (char *);
-+ *(char **) p = 0;
-+ p = (void *) p + sizeof (char *);
-+ memcpy (p, strings, stringlen);
-+ memset (args, 0, (vm_offset_t)arg_pos & (vm_page_size - 1));
-+ vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args,
-+ stack_end - trunc_page ((vm_offset_t) arg_pos));
-+ munmap ((caddr_t) args,
-+ stack_end - trunc_page ((vm_offset_t) arg_pos));
-+
-+ thread_create (task, &thread);
-+
-+#ifdef i386_THREAD_STATE_COUNT
-+ {
-+ struct i386_thread_state regs;
-+ reg_size = i386_THREAD_STATE_COUNT;
-+ thread_get_state (thread, i386_THREAD_STATE,
-+ (thread_state_t) &regs, &reg_size);
-+ regs.eip = (int) startpc;
-+ regs.uesp = (int) arg_pos;
-+ thread_set_state (thread, i386_THREAD_STATE,
-+ (thread_state_t) &regs, reg_size);
-+ }
-+#else
-+# error needs to be ported
-+#endif
-+
-+ err = thread_resume (thread);
-+ if (err)
-+ return err;
-+
-+ err = mach_port_deallocate (mach_task_self (), thread);
-+ assert_perror (err);
-+ return 0;
-+}
-+
-+error_t
-+elf_exec (mach_port_t task, char *argz, size_t argz_len)
-+{
-+ error_t err;
-+ size_t argc;
-+ char **argv;
-+
-+ argc = argz_count (argz, argz_len);
-+ argv = malloc ((argc + 1) * sizeof *argv);
-+ argz_extract (argz, argz_len, argv);
-+
-+ err = boot_script_exec_cmd (task, argz, argc, argv, argz, argz_len);
-+ free (argv);
-+ return err;
-+}
-+
-+pointer
-+do_elf_exec (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("elf-exec");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, pointer, arguments, list, args);
-+ SC_ARGS_DONE (sc);
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ ffi_list2argz (sc, &argz, &argz_len, arguments);
-+ err = elf_exec (task, argz, argz_len);
-+ free (argz);
-+ SC_RETURN (sc);
-+}
-diff --git a/bootshell/exceptions.c b/bootshell/exceptions.c
-new file mode 100644
-index 0000000..3102369
---- /dev/null
-+++ b/bootshell/exceptions.c
-@@ -0,0 +1,92 @@
-+/* Mach exception handling.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <mach.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+
-+#include "bootshell.h"
-+
-+// eek #include "exc_S.h"
-+
-+error_t
-+catch_exception_raise (mach_port_t e,
-+ thread_t thread,
-+ task_t task,
-+ int exception, int code, int subcode)
-+{
-+ if (e != exception_port)
-+ return EOPNOTSUPP;
-+
-+ fprintf (stderr, "catch_exception_raise (%d, %d, %d, %d, %d): ",
-+ thread, task, exception, code, subcode);
-+
-+ if (task == mach_task_self ())
-+ fprintf (stderr, "terminating bootshell. bye.\n");
-+ else
-+ fprintf (stderr, "terminating task %d.\n", task);
-+
-+ task_terminate (task);
-+ return 0;
-+}
-+
-+static void *
-+service_exception_requests (void *arg)
-+{
-+ extern boolean_t exc_server (mach_msg_header_t *, mach_msg_header_t *);
-+
-+ while (1)
-+ mach_msg_server (exc_server, 0, exception_port);
-+
-+ /* Not reached. */
-+ return NULL;
-+}
-+
-+error_t
-+init_exception_handling (void)
-+{
-+ error_t err;
-+ pthread_t t;
-+
-+ err = mach_port_allocate (mach_task_self (),
-+ MACH_PORT_RIGHT_RECEIVE,
-+ &exception_port);
-+ if (err)
-+ return err;
-+
-+ /* Make a thread to service exception requests. */
-+ err = pthread_create (&t, NULL, service_exception_requests, NULL);
-+ if (err)
-+ return err;
-+ pthread_detach (t);
-+
-+ err = mach_port_insert_right (mach_task_self (),
-+ exception_port,
-+ exception_port,
-+ MACH_MSG_TYPE_MAKE_SEND);
-+ if (err)
-+ return err;
-+
-+ err = task_set_exception_port (mach_task_self (), exception_port);
-+ if (err)
-+ return err;
-+
-+ return err;
-+}
-+
-diff --git a/bootshell/exec-startup.c b/bootshell/exec-startup.c
-new file mode 100644
-index 0000000..026687f
---- /dev/null
-+++ b/bootshell/exec-startup.c
-@@ -0,0 +1,182 @@
-+/* Handles the exec_startup protocol.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <assert.h>
-+#include <hurd.h>
-+#include <hurd/paths.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <mach/mig_support.h>
-+#include <stdio.h>
-+#include <sys/mman.h>
-+
-+// eek #include "fsys_S.h"
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+ char *argz;
-+ size_t argz_len;
-+
-+ /* Filled by the server function. */
-+} exec_startup_get_info_args;
-+
-+/* We look like an execserver to the execserver itself; it makes this
-+ call (as does any task) to get its state. We can't give it all of
-+ its ports (we'll provide those with a later call to exec_init). */
-+kern_return_t
-+S_exec_startup_get_info (mach_port_t bootstrap_port,
-+ vm_address_t *user_entry,
-+ vm_address_t *phdr_data,
-+ vm_size_t *phdr_size,
-+ vm_address_t *base_addr,
-+ vm_size_t *stack_size,
-+ int *flags,
-+ char **argz,
-+ mach_msg_type_number_t *argz_len,
-+ char **envz,
-+ mach_msg_type_number_t *envz_len,
-+ mach_port_t **dtableP,
-+ mach_msg_type_name_t *dtablepoly,
-+ mach_msg_type_number_t *dtablelen,
-+ mach_port_t **portarrayP,
-+ mach_msg_type_name_t *portarraypoly,
-+ mach_msg_type_number_t *portarraylen,
-+ int **intarrayP,
-+ mach_msg_type_number_t *intarraylen)
-+{
-+ error_t err;
-+ mach_port_t *portarray, *dtable;
-+
-+ if (bootstrap_port != exec_startup_get_info_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ *user_entry = 0;
-+ *phdr_data = *base_addr = 0;
-+ *phdr_size = *stack_size = 0;
-+
-+ *flags = 0;
-+
-+ /* Arguments. */
-+ *argz = NULL;
-+ *argz_len = exec_startup_get_info_args.argz_len;
-+ if (*argz_len == 0)
-+ /* We have no args for it. Tell it to look on its stack
-+ for the args placed there by the boot loader. */
-+ *flags |= EXEC_STACK_ARGS;
-+ else
-+ {
-+ err = vm_allocate (mach_task_self (),
-+ (vm_address_t *)argz, *argz_len, TRUE);
-+ if (err)
-+ return err;
-+ memcpy (*argz, exec_startup_get_info_args.argz, *argz_len);
-+ }
-+
-+ /* Environment. */
-+ *envz = NULL;
-+ *envz_len = 0;
-+
-+ /* File descriptors. */
-+ if (*dtablelen < 3)
-+ *dtableP = mmap (0, 3 * sizeof (mach_port_t), PROT_READ|PROT_WRITE,
-+ MAP_ANON, 0, 0);
-+ dtable = *dtableP;
-+ *dtablepoly = MACH_MSG_TYPE_COPY_SEND;
-+ *dtablelen = 3;
-+ dtable[0] = dtable[1] = dtable[2] = console;
-+
-+ /* Initial ports. */
-+ if (*portarraylen < INIT_PORT_MAX)
-+ *portarrayP = mmap (0, INIT_PORT_MAX * sizeof (mach_port_t),
-+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-+ portarray = *portarrayP;
-+ *portarraylen = INIT_PORT_MAX;
-+ memcpy (portarray, portarray_template, INIT_PORT_MAX * sizeof *portarray);
-+ portarray[INIT_PORT_BOOTSTRAP] = bootstrap_port; /* use the same port */
-+ *portarraypoly = MACH_MSG_TYPE_COPY_SEND;
-+
-+ /* Initial ints. */
-+ *intarrayP = NULL;
-+ *intarraylen = 0;
-+
-+ return 0;
-+}
-+
-+boolean_t
-+exec_startup_get_info_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ extern boolean_t exec_startup_server (mach_msg_header_t *,
-+ mach_msg_header_t *);
-+ if (request->msgh_id != 30500) /* XXX hardcoded msgh_id */
-+ {
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+ }
-+ return exec_startup_server (request, reply);
-+}
-+
-+error_t
-+service_exec_startup_request (mach_port_t bootstrap,
-+ char *argz,
-+ size_t argz_len,
-+ mach_msg_timeout_t timeout)
-+{
-+ error_t err;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ exec_startup_get_info_args.bootstrap_port = bootstrap;
-+ exec_startup_get_info_args.argz = argz;
-+ exec_startup_get_info_args.argz_len = argz_len;
-+
-+ err = mach_msg_server_timeout_once (exec_startup_get_info_demuxer,
-+ 0, bootstrap,
-+ MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT,
-+ timeout);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ return 0;
-+}
-+
-+pointer
-+do_handle_exec_startup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-exec-startup");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, pointer, arguments, list, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ ffi_list2argz (sc, &argz, &argz_len, arguments);
-+ err = service_exec_startup_request (bootstrap, argz, argz_len, timeout);
-+ free (argz);
-+ SC_RETURN (sc);
-+}
-diff --git a/bootshell/ffi.c b/bootshell/ffi.c
-new file mode 100644
-index 0000000..b1a0ff3
---- /dev/null
-+++ b/bootshell/ffi.c
-@@ -0,0 +1,1061 @@
-+/* Mach, Hurd, and libc primitives for the Scheme environment.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <argz.h>
-+#include <assert.h>
-+#include <ctype.h>
-+#include <device/device.h>
-+#include <errno.h>
-+#include <error.h>
-+#include <fcntl.h>
-+#include <hurd.h>
-+#include <hurd/fsys.h>
-+#include <mach.h>
-+#include <mach/gnumach.h>
-+#include <sys/reboot.h>
-+#include <sys/mman.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+#if HAVE_LIBREADLINE
-+#include <readline/readline.h>
-+#include <readline/history.h>
-+#endif
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+#include "startup.h"
-+
-+static mach_port_t
-+copy_send_right (mach_port_t right)
-+{
-+ error_t err;
-+ if (! MACH_PORT_VALID (right))
-+ return right;
-+
-+ err = mach_port_insert_right (mach_task_self (),
-+ right,
-+ right,
-+ MACH_MSG_TYPE_COPY_SEND);
-+ if (err)
-+ {
-+ error (0, err, "mach_port_insert_right");
-+ return MACH_PORT_NULL;
-+ }
-+
-+ return right;
-+}
-+
-+int use_libreadline;
-+
-+/* Read a string, and return a pointer to it. Returns NULL on EOF. */
-+char *
-+rl_gets (const char *prompt)
-+{
-+ static char *line = NULL;
-+ free (line);
-+
-+#if HAVE_LIBREADLINE
-+ if (use_libreadline)
-+ {
-+ line = readline (prompt);
-+ if (line && *line)
-+ add_history (line);
-+ }
-+ else
-+#endif
-+ {
-+ size_t max_size = 0xff;
-+ printf ("%s", prompt);
-+ fflush (stdout);
-+ line = malloc (max_size);
-+ if (line != NULL)
-+ fgets (line, max_size, stdin);
-+ }
-+
-+ /* Strip trailing whitespace. */
-+ if (line && strlen (line) > 0)
-+ for (char *p = &line[strlen (line) - 1]; isspace (*p); p--)
-+ *p = 0;
-+
-+ return line;
-+}
-+
-+pointer
-+do_enable_readline (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("enable-readline");
-+ SC_ARGS_DONE (sc);
-+ use_libreadline = 1;
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_prompt (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("prompt");
-+ SC_ARG (sc, char *, prompt, string, args);
-+ SC_ARGS_DONE (sc);
-+ const char *line = rl_gets (prompt);
-+ ffi_update (sc);
-+ if (! line)
-+ SC_RETURN_POINTER (sc, sc->EOF_OBJ);
-+
-+ SC_RETURN_STRING (sc, line);
-+}
-+
-+#define is_false(p) ((p) == sc->F)
-+
-+pointer
-+do_host_reboot (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("host-reboot");
-+ SC_ARG (sc, mach_port_t, host_priv, number, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = host_reboot (host_priv, flags);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_task_create (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-create");
-+ SC_ARG (sc, task_t, parent, number, args);
-+ SC_ARG (sc, boolean_t, inherit_memory, number, args);
-+ SC_ARGS_DONE (sc);
-+ task_t task;
-+ err = task_create (parent, inherit_memory, &task);
-+ SC_RETURN_INT (sc, task);
-+}
-+
-+pointer
-+do_task_suspend (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-suspend");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_suspend (task);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_task_resume (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-resume");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_resume (task);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_task_terminate (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-terminate");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_terminate (task);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_sleep (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("sleep");
-+ SC_ARG (sc, unsigned int, seconds, number, args);
-+ SC_ARGS_DONE (sc);
-+ sleep (seconds);
-+ ffi_update (sc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_usleep (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("usleep");
-+ SC_ARG (sc, useconds_t, microseconds, number, args);
-+ SC_ARGS_DONE (sc);
-+ usleep (microseconds);
-+ ffi_update (sc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_file_name_lookup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("file-name-lookup");
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARG (sc, mode_t, mode, number, args);
-+ SC_ARGS_DONE (sc);
-+ file_t file = file_name_lookup (name, flags, mode);
-+ if (! MACH_PORT_VALID (file))
-+ SC_RETURN_ERR (sc, errno);
-+ SC_RETURN_INT (sc, file);
-+}
-+
-+pointer
-+do_chdir (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("chdir");
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARGS_DONE (sc);
-+ if (chdir (name))
-+ SC_RETURN_ERR (sc, errno);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_strerror (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("strerror");
-+ SC_ARG (sc, int, error, number, args);
-+ SC_ARGS_DONE (sc);
-+ char *s, buf[128];
-+ s = strerror_r (error, buf, sizeof buf);
-+ SC_RETURN_STRING (sc, s);
-+}
-+
-+pointer
-+do_getproc (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("getproc");
-+ SC_ARGS_DONE (sc);
-+ SC_RETURN_INT (sc, getproc ());
-+}
-+
-+pointer
-+do_getcwd (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("getcwd");
-+ SC_ARGS_DONE (sc);
-+ SC_RETURN_STRING (sc, get_current_dir_name ());
-+}
-+
-+pointer
-+do_mach_port_allocate (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-allocate");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t name;
-+ err = mach_port_allocate (task, right, &name);
-+ SC_RETURN_INT (sc, name);
-+}
-+
-+pointer
-+do_mach_port_deallocate (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-deallocate");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = mach_port_deallocate (task, right);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_mach_port_destroy (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-destroy");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = mach_port_destroy (task, right);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_mach_port_insert_right (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-insert-right");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, name, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, right_type, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = mach_port_insert_right (task, name, right, right_type);
-+ SC_RETURN_INT (sc, right);
-+}
-+
-+pointer
-+do_task_get_special_port (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-get-special-port");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, int, which, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t special_port;
-+ err = task_get_special_port (task, which, &special_port);
-+ SC_RETURN_INT (sc, special_port);
-+}
-+
-+pointer
-+do_task_set_special_port (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-set-special-port");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, int, which, number, args);
-+ SC_ARG (sc, mach_port_t, special_port, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_set_special_port (task, which, special_port);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_device_open (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("device-open");
-+ SC_ARG (sc, mach_port_t, master, number, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t device;
-+ err = device_open (master, flags, name, &device);
-+ SC_RETURN_INT (sc, device);
-+}
-+
-+/* Hurd functions. */
-+pointer
-+do_bind_root (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("_bind-root");
-+ SC_ARG (sc, mach_port_t, control, number, args);
-+ SC_ARG (sc, file_t, dotdot_node, number, args);
-+ SC_ARGS_DONE (sc);
-+ if (! MACH_PORT_VALID (control)
-+ || ! MACH_PORT_VALID (dotdot_node))
-+ SC_RETURN_ERR (sc, EINVAL);
-+
-+ if (_hurd_ports)
-+ SC_RETURN_ERR (sc, EPERM); /* XXX */
-+
-+ uid_t uids[1] = { 0 };
-+ size_t uids_len = 1;
-+ gid_t gids[1] = { 0 };
-+ size_t gids_len = 1;
-+
-+ retry_type retry;
-+ char retryname[1024]; /* XXX */
-+ file_t root;
-+ err = fsys_getroot (control,
-+ dotdot_node,
-+ MACH_MSG_TYPE_MAKE_SEND,
-+ uids, uids_len,
-+ gids, gids_len,
-+ (O_READ|O_EXEC),
-+ &retry,
-+ retryname,
-+ &root);
-+ if (err)
-+ SC_RETURN (sc);
-+
-+ // XXX check root
-+ portarray_template[INIT_PORT_CRDIR] = root;
-+ portarray_template[INIT_PORT_CWDIR] = root;
-+
-+ err = mach_port_mod_refs (mach_task_self (),
-+ root, MACH_PORT_RIGHT_SEND, +2);
-+ assert_perror (err);
-+
-+ /* We have no portarray or intarray because there was no
-+ exec_startup data; _hurd_init was never called. We now have the
-+ crucial ports, so create a portarray and call _hurd_init. */
-+ mach_port_t *portarray;
-+ portarray = mmap (0, INIT_PORT_MAX * sizeof *portarray,
-+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-+ memcpy (portarray, portarray_template, INIT_PORT_MAX * sizeof *portarray);
-+ _hurd_init (0, NULL, portarray, INIT_PORT_MAX, NULL, 0);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_bind_proc (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("bind-proc");
-+ SC_ARG (sc, mach_port_t, procserver, number, args);
-+ SC_ARGS_DONE (sc);
-+ /* Give the library our proc server port. */
-+ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver);
-+ err = mach_port_mod_refs (mach_task_self (),
-+ procserver, MACH_PORT_RIGHT_SEND, +1);
-+ assert_perror (err);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_bind_auth (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("bind-auth");
-+ SC_ARG (sc, mach_port_t, authserver, number, args);
-+ SC_ARGS_DONE (sc);
-+ /* Give the library our auth server port. */
-+ _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
-+ portarray_template[INIT_PORT_AUTH] = authserver;
-+ err = mach_port_mod_refs (mach_task_self (),
-+ authserver, MACH_PORT_RIGHT_SEND, +2);
-+ assert_perror (err);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_bind_term (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("bind-term");
-+ SC_ARG (sc, mach_port_t, term, number, args);
-+ SC_ARGS_DONE (sc);
-+ int new_fd0, new_fd1, new_fd2;
-+ FILE *new_stdin, *new_stdout, *new_stderr;
-+
-+ new_fd0 = openport (copy_send_right (term), O_RDONLY);
-+ if (new_fd0 < 0)
-+ SC_RETURN_ERR (sc, errno);
-+
-+ new_fd1 = openport (copy_send_right (term), O_WRONLY);
-+ if (new_fd1 < 0)
-+ SC_RETURN_ERR (sc, errno);
-+
-+ new_fd2 = openport (copy_send_right (term), O_WRONLY);
-+ if (new_fd2 < 0)
-+ SC_RETURN_ERR (sc, errno);
-+
-+ dup2 (new_fd0, 0);
-+ close (new_fd0);
-+ dup2 (new_fd1, 1);
-+ close (new_fd1);
-+ dup2 (new_fd2, 2);
-+ close (new_fd2);
-+
-+ // XXX proper error handling, restore all state on error
-+
-+ new_stdin = fdopen (0, "r");
-+ if (new_stdin == NULL)
-+ SC_RETURN_ERR (sc, errno);
-+
-+ new_stdout = fdopen (1, "w");
-+ if (new_stdout == NULL)
-+ SC_RETURN_ERR (sc, errno);
-+
-+ new_stderr = fdopen (2, "w");
-+ if (new_stderr == NULL)
-+ SC_RETURN_ERR (sc, errno);
-+
-+ fclose (stdin);
-+ fclose (stdout);
-+ fclose (stderr);
-+ stdin = new_stdin;
-+ stdout = new_stdout;
-+ stderr = new_stderr;
-+
-+ scheme_set_input_port_file (sc, stdin);
-+ scheme_set_output_port_file (sc, stdout);
-+
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_fsys_init (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("fsys-init!");
-+ SC_ARG (sc, mach_port_t, fsys, number, args);
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, mach_port_t, auth, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = fsys_init (fsys, proc, MACH_MSG_TYPE_COPY_SEND, auth);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_proc_task2proc (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc-task2proc");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t result;
-+ err = proc_task2proc (proc, task, &result);
-+ SC_RETURN_INT (sc, result);
-+}
-+
-+pointer
-+do_proc_task2pid (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc-task2pid");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ pid_t pid;
-+ err = proc_task2pid (proc, task, &pid);
-+ SC_RETURN_INT (sc, pid);
-+}
-+
-+pointer
-+do_proc_wait (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc-wait");
-+ SC_ARG (sc, process_t, proc, number, args);
-+ SC_ARG (sc, pid_t, pid, number, args);
-+ SC_ARG (sc, int, options, number, args);
-+ SC_ARGS_DONE (sc);
-+ int status, sigcode;
-+ rusage_t rusage; // XXX
-+ pid_t pid_status;
-+ err = proc_wait (proc, pid, options,
-+ &status, &sigcode, &rusage, &pid_status);
-+#define IMC(A, B) _cons (sc, sc->vptr->mk_integer (sc, A), (B), 1)
-+ SC_RETURN_POINTER (sc, IMC (status,
-+ IMC (sigcode,
-+ IMC (pid_status, sc->NIL))));
-+#undef IMC
-+}
-+
-+pointer
-+do_proc_mark_exec (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc-mark-exec!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_mark_exec (proc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_proc_mark_important (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->mark-important!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_mark_important (proc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_proc_child (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->proc->child!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, mach_port_t, child, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_child (proc, child);
-+ if (err) error (0, err, "proc_child");
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_proc_set_init_task (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->task->set-init-task!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, mach_port_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_set_init_task (proc, task);
-+ SC_RETURN (sc);
-+}
-+
-+/* Set up the initial value of the standard exec data. */
-+/* XXX: Provide primitives and implement in Scheme. */
-+pointer
-+do_proc_auth_set_std_execdata (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->auth->set-std-execdata!");
-+ SC_ARG (sc, process_t, proc, number, args);
-+ SC_ARG (sc, auth_t, auth, number, args);
-+ SC_ARGS_DONE (sc);
-+
-+ 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);
-+ memset (std_port_array, 0, sizeof(mach_port_t) * INIT_PORT_MAX);
-+ std_int_array = alloca (sizeof (int) * INIT_INT_MAX);
-+ memset (std_int_array, 0, sizeof(int) * INIT_INT_MAX);
-+
-+ err = auth_makeauth (auth,
-+ NULL, MACH_MSG_TYPE_COPY_SEND, 0,
-+ NULL, 0,
-+ NULL, 0,
-+ NULL, 0,
-+ NULL, 0,
-+ &nullauth);
-+ if (err)
-+ goto out;
-+
-+ /* MAKE_SEND is safe in these transactions because we destroy REF
-+ ourselves each time. */
-+ pt = getcwdir ();
-+ ref = mach_reply_port ();
-+ err = io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND);
-+ if (err)
-+ goto out;
-+
-+ err = auth_user_authenticate (nullauth, ref, MACH_MSG_TYPE_MAKE_SEND,
-+ &std_port_array[INIT_PORT_CWDIR]);
-+ if (err)
-+ goto out;
-+
-+ mach_port_destroy (mach_task_self (), ref);
-+ mach_port_deallocate (mach_task_self (), pt);
-+
-+ pt = getcrdir ();
-+ ref = mach_reply_port ();
-+ err = io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND);
-+ if (err)
-+ goto out;
-+
-+ err = auth_user_authenticate (nullauth, ref, MACH_MSG_TYPE_MAKE_SEND,
-+ &std_port_array[INIT_PORT_CRDIR]);
-+ if (err)
-+ goto out;
-+
-+ 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;
-+
-+ err = proc_setexecdata (proc, std_port_array,
-+ MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
-+ std_int_array, INIT_INT_MAX);
-+
-+ out:
-+ for (i = 0; i < INIT_PORT_MAX; i++)
-+ if (MACH_PORT_VALID (std_port_array[i]))
-+ {
-+ error_t err;
-+ err = mach_port_deallocate (mach_task_self (), std_port_array[i]);
-+ assert_perror (err);
-+ }
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_file_set_translator (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("file-set-translator");
-+ SC_ARG (sc, file_t, node, number, args);
-+ SC_ARG (sc, int, passive_flags, number, args);
-+ SC_ARG (sc, int, active_flags, number, args);
-+ SC_ARG (sc, int, goaway_flags, number, args);
-+ SC_ARG (sc, int, argz, number, args); //XXX
-+ SC_ARG (sc, int, argz_len, number, args); //XXX
-+ argz = argz_len = 0;
-+
-+ SC_ARG (sc, mach_port_t, active_control, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, active_controlPoly, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = file_set_translator (node,
-+ passive_flags, active_flags, goaway_flags,
-+ argz, argz_len,
-+ active_control, active_controlPoly);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+ffi_argz2list (scheme *sc, const char *argz, size_t argz_len, const char *entry)
-+{
-+ entry = argz_next (argz, argz_len, entry);
-+ if (argz == NULL || argz_len == 0 || entry == NULL)
-+ return sc->NIL;
-+ return _cons (sc,
-+ mk_string (sc, entry),
-+ ffi_argz2list (sc, argz, argz_len, entry),
-+ 1);
-+}
-+
-+void
-+ffi_list2argz (scheme *sc, char **argz, size_t *argz_len, pointer list)
-+{
-+ while (sc->vptr->is_pair (list))
-+ {
-+ argz_add (argz, argz_len, string_value (sc->vptr->pair_car (list)));
-+ list = sc->vptr->pair_cdr (list);
-+ }
-+}
-+
-+// XXX
-+pointer
-+do__exec (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("_exec");
-+ process_t proc, child_proc = MACH_PORT_NULL;
-+ mach_port_t dtable[STDERR_FILENO+1];
-+ mach_port_t portarray[INIT_PORT_MAX];
-+ int default_ints[INIT_INT_MAX];
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ int i;
-+
-+ SC_ARG (sc, file_t, file, number, args);
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, pointer, arguments, list, args);
-+ ffi_list2argz (sc, &argz, &argz_len, arguments);
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARGS_DONE (sc);
-+
-+ proc = getproc ();
-+ if (MACH_PORT_VALID (proc))
-+ {
-+ err = proc_task2proc (proc, task, &child_proc);
-+ mach_port_deallocate (mach_task_self (), proc);
-+ if (err)
-+ SC_RETURN (sc);
-+ }
-+
-+ dtable[STDIN_FILENO] = getdport (STDIN_FILENO);
-+ dtable[STDOUT_FILENO] = getdport (STDOUT_FILENO);
-+ dtable[STDERR_FILENO] = getdport (STDERR_FILENO);
-+
-+ memcpy (portarray, portarray_template, INIT_PORT_MAX * sizeof *portarray);
-+ for (i = 0; i < INIT_PORT_MAX; i++)
-+ copy_send_right (portarray[i]);
-+
-+ portarray[INIT_PORT_CWDIR] = getcwdir ();
-+ portarray[INIT_PORT_CRDIR] = getcrdir ();
-+ portarray[INIT_PORT_PROC] = child_proc;
-+ portarray[INIT_PORT_BOOTSTRAP] = copy_send_right (bootstrap);
-+
-+ memset (default_ints, 0, INIT_INT_MAX * sizeof *default_ints);
-+ /* 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));
-+
-+ err = task_set_name (task, argz);
-+ if (err)
-+ {
-+ error (0, err, "task_set_name");
-+ goto lose;
-+ }
-+
-+ err = file_exec (file, task, 0,
-+ argz, argz_len,
-+ NULL, 0, /* env, env_len */
-+ dtable, MACH_MSG_TYPE_COPY_SEND, STDERR_FILENO+1,
-+ portarray, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
-+ default_ints, INIT_INT_MAX,
-+ NULL, 0, NULL, 0);
-+
-+ lose:
-+ for (i = 0; i < STDERR_FILENO+1; i++)
-+ if (MACH_PORT_VALID (dtable[i]))
-+ {
-+ error_t err = mach_port_deallocate (mach_task_self (), dtable[i]);
-+ assert_perror (err);
-+ }
-+ for (i = 0; i < INIT_PORT_MAX; i++)
-+ if (MACH_PORT_VALID (portarray[i]))
-+ {
-+ error_t err = mach_port_deallocate (mach_task_self (), portarray[i]);
-+ assert_perror (err);
-+ }
-+
-+ SC_RETURN_INT (sc, task);
-+}
-+
-+pointer
-+do_file_get_fs_options (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("file-get-fs-options");
-+ SC_ARG (sc, file_t, node, number, args);
-+ SC_ARGS_DONE (sc);
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ pointer result;
-+ err = file_get_fs_options (node, &argz, &argz_len);
-+ if (err)
-+ SC_RETURN (sc);
-+ result = ffi_argz2list (sc, argz, argz_len, NULL);
-+ vm_deallocate (mach_task_self (), (vm_address_t) argz, argz_len);
-+ SC_RETURN_POINTER (sc, result);
-+}
-+
-+const char *
-+schemify_name (const char *s, int macro)
-+{
-+ char *n = strdup (s), *p;
-+ if (n == NULL)
-+ return s;
-+ for (p = n; *p; p++)
-+ {
-+ *p = (char) tolower (*p);
-+ /* We convert _ to - in identifiers. We allow, however, for
-+ function names to start with a leading _. The functions in
-+ this namespace are not yet finalized and might change or
-+ vanish without warning. Use them with care. */
-+ if (! macro
-+ && p != n
-+ && *p == '_')
-+ *p = '-';
-+ }
-+ return n;
-+}
-+
-+void
-+ffi_update (scheme *sc)
-+{
-+ // XXX nothng
-+}
-+
-+void
-+ffi_init (scheme *sc)
-+{
-+ char *version;
-+ asprintf (&version, "%s/%s", argp_program_version, "TinyScheme 1.41");
-+ define_ (sc, "version", mk_string (sc, version));
-+ free (version);
-+
-+ define_constant (sc, MACH_PORT_NULL);
-+ define_constant (sc, MACH_PORT_DEAD); // XXX signedness
-+
-+ define_constant (sc, MACH_MSG_TYPE_UNSTRUCTURED);
-+ define_constant (sc, MACH_MSG_TYPE_BIT);
-+ define_constant (sc, MACH_MSG_TYPE_BOOLEAN);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_16);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_32);
-+ define_constant (sc, MACH_MSG_TYPE_CHAR);
-+ define_constant (sc, MACH_MSG_TYPE_BYTE);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_8);
-+ define_constant (sc, MACH_MSG_TYPE_REAL);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_64);
-+ define_constant (sc, MACH_MSG_TYPE_STRING);
-+ define_constant (sc, MACH_MSG_TYPE_STRING_C);
-+ define_constant (sc, MACH_MSG_TYPE_MOVE_RECEIVE);
-+ define_constant (sc, MACH_MSG_TYPE_MOVE_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_MOVE_SEND_ONCE);
-+ define_constant (sc, MACH_MSG_TYPE_COPY_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_MAKE_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_MAKE_SEND_ONCE);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_NAME);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_RECEIVE);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_SEND_ONCE);
-+ define_constant (sc, MACH_MSG_TYPE_PROTECTED_PAYLOAD);
-+ define_constant (sc, MACH_MSG_TYPE_LAST);
-+ define_constant (sc, MACH_MSG_TYPE_POLYMORPHIC);
-+
-+ define_constant (sc, MACH_PORT_RIGHT_SEND);
-+ define_constant (sc, MACH_PORT_RIGHT_RECEIVE);
-+ define_constant (sc, MACH_PORT_RIGHT_SEND_ONCE);
-+ define_constant (sc, MACH_PORT_RIGHT_PORT_SET);
-+ define_constant (sc, MACH_PORT_RIGHT_DEAD_NAME);
-+ define_constant (sc, MACH_PORT_RIGHT_NUMBER);
-+
-+ define_constant (sc, KERN_SUCCESS);
-+ define_constant (sc, KERN_INVALID_ADDRESS);
-+ define_constant (sc, KERN_PROTECTION_FAILURE);
-+ define_constant (sc, KERN_NO_SPACE);
-+ define_constant (sc, KERN_INVALID_ARGUMENT);
-+ define_constant (sc, KERN_FAILURE);
-+ define_constant (sc, KERN_RESOURCE_SHORTAGE);
-+ define_constant (sc, KERN_NOT_RECEIVER);
-+ define_constant (sc, KERN_NO_ACCESS);
-+ define_constant (sc, KERN_MEMORY_FAILURE);
-+ define_constant (sc, KERN_MEMORY_ERROR);
-+ define_constant (sc, KERN_NOT_IN_SET);
-+ define_constant (sc, KERN_NAME_EXISTS);
-+ define_constant (sc, KERN_ABORTED);
-+ define_constant (sc, KERN_INVALID_NAME);
-+ define_constant (sc, KERN_INVALID_TASK);
-+ define_constant (sc, KERN_INVALID_RIGHT);
-+ define_constant (sc, KERN_INVALID_VALUE);
-+ define_constant (sc, KERN_UREFS_OVERFLOW);
-+ define_constant (sc, KERN_INVALID_CAPABILITY);
-+ define_constant (sc, KERN_RIGHT_EXISTS);
-+ define_constant (sc, KERN_INVALID_HOST);
-+ define_constant (sc, KERN_MEMORY_PRESENT);
-+ define_constant (sc, KERN_WRITE_PROTECTION_FAILURE);
-+ define_constant (sc, KERN_TERMINATED);
-+ define_constant (sc, MACH_MSG_SUCCESS);
-+ define_constant (sc, MACH_MSG_MASK);
-+ define_constant (sc, MACH_MSG_IPC_SPACE);
-+ define_constant (sc, MACH_MSG_VM_SPACE);
-+ define_constant (sc, MACH_MSG_IPC_KERNEL);
-+ define_constant (sc, MACH_MSG_VM_KERNEL);
-+ define_constant (sc, MACH_SEND_IN_PROGRESS);
-+ define_constant (sc, MACH_SEND_INVALID_DATA);
-+ define_constant (sc, MACH_SEND_INVALID_DEST);
-+ define_constant (sc, MACH_SEND_TIMED_OUT);
-+ define_constant (sc, MACH_SEND_WILL_NOTIFY);
-+ define_constant (sc, MACH_SEND_NOTIFY_IN_PROGRESS);
-+ define_constant (sc, MACH_SEND_INTERRUPTED);
-+ define_constant (sc, MACH_SEND_MSG_TOO_SMALL);
-+ define_constant (sc, MACH_SEND_INVALID_REPLY);
-+ define_constant (sc, MACH_SEND_INVALID_RIGHT);
-+ define_constant (sc, MACH_SEND_INVALID_NOTIFY);
-+ define_constant (sc, MACH_SEND_INVALID_MEMORY);
-+ define_constant (sc, MACH_SEND_NO_BUFFER);
-+ define_constant (sc, MACH_SEND_NO_NOTIFY);
-+ define_constant (sc, MACH_SEND_INVALID_TYPE);
-+ define_constant (sc, MACH_SEND_INVALID_HEADER);
-+ define_constant (sc, MACH_RCV_IN_PROGRESS);
-+ define_constant (sc, MACH_RCV_INVALID_NAME);
-+ define_constant (sc, MACH_RCV_TIMED_OUT);
-+ define_constant (sc, MACH_RCV_TOO_LARGE);
-+ define_constant (sc, MACH_RCV_INTERRUPTED);
-+ define_constant (sc, MACH_RCV_PORT_CHANGED);
-+ define_constant (sc, MACH_RCV_INVALID_NOTIFY);
-+ define_constant (sc, MACH_RCV_INVALID_DATA);
-+ define_constant (sc, MACH_RCV_PORT_DIED);
-+ define_constant (sc, MACH_RCV_IN_SET);
-+ define_constant (sc, MACH_RCV_HEADER_ERROR);
-+ define_constant (sc, MACH_RCV_BODY_ERROR);
-+
-+ define_constant (sc, TASK_KERNEL_PORT);
-+ define_constant (sc, TASK_EXCEPTION_PORT);
-+ define_constant (sc, TASK_BOOTSTRAP_PORT);
-+
-+ define_constant (sc, RB_DEBUGGER);
-+ define_constant (sc, RB_HALT);
-+ define_constant (sc, RB_AUTOBOOT);
-+
-+ define_ (sc, "mach-task-self", mk_integer (sc, mach_task_self ()));
-+
-+ define_function (sc, "mach-port-allocate", mach_port_allocate);
-+ define_function (sc, "mach-port-deallocate", mach_port_deallocate);
-+ define_function (sc, "mach-port-destroy", mach_port_destroy);
-+ //define_function (sc, "mach-port-get-refs", mach_port_get_refs);
-+ //define_function (sc, "mach-port-mod-refs", mach_port_mod_refs);
-+ define_function (sc, "mach-port-insert-right", mach_port_insert_right);
-+ //define_function (sc, "mach-port-extract-right", mach_port_extract_right);
-+
-+ define_function (sc, "task-create", task_create);
-+ define_function (sc, "task-suspend", task_suspend);
-+ define_function (sc, "task-resume", task_resume);
-+ define_function (sc, "task-terminate", task_terminate);
-+ define_function (sc, "task-get-special-port", task_get_special_port);
-+ define_function (sc, "task-set-special-port", task_set_special_port);
-+ define_function (sc, "host-reboot", host_reboot);
-+
-+ /* Device protocol. */
-+ define_constant (sc, D_READ);
-+ define_constant (sc, D_WRITE);
-+ define_function (sc, "device-open", device_open);
-+
-+ /* Hurd stuff. */
-+ define_constant (sc, EXEC_NEWTASK);
-+ define_constant (sc, EXEC_SECURE);
-+ define_constant (sc, EXEC_DEFAULTS);
-+ define_constant (sc, EXEC_SIGTRAP);
-+ define_constant (sc, EXEC_STACK_ARGS);
-+ define_constant (sc, FS_TRANS_FORCE);
-+ define_constant (sc, FS_TRANS_EXCL);
-+ define_constant (sc, FS_TRANS_SET);
-+ define_constant (sc, FS_TRANS_ORPHAN);
-+ define_constant (sc, FS_RETRY_NORMAL);
-+ define_constant (sc, FS_RETRY_REAUTH);
-+ define_constant (sc, FS_RETRY_MAGICAL);
-+ define_constant (sc, FSYS_GOAWAY_NOWAIT);
-+ define_constant (sc, FSYS_GOAWAY_NOSYNC);
-+ define_constant (sc, FSYS_GOAWAY_FORCE);
-+ define_constant (sc, FSYS_GOAWAY_UNLINK);
-+ define_constant (sc, FSYS_GOAWAY_RECURSE);
-+ define_constant (sc, INIT_PORT_CWDIR);
-+ define_constant (sc, INIT_PORT_CRDIR);
-+ define_constant (sc, INIT_PORT_AUTH);
-+ define_constant (sc, INIT_PORT_PROC);
-+ define_constant (sc, INIT_PORT_CTTYID);
-+ define_constant (sc, INIT_PORT_BOOTSTRAP);
-+ define_constant (sc, INIT_PORT_MAX);
-+ define_constant (sc, INIT_UMASK);
-+ define_constant (sc, INIT_SIGMASK);
-+ define_constant (sc, INIT_SIGIGN);
-+ define_constant (sc, INIT_SIGPENDING);
-+ define_constant (sc, INIT_TRACEMASK);
-+ define_constant (sc, INIT_INT_MAX);
-+
-+ define_constant (sc, O_RDONLY);
-+ define_constant (sc, O_WRONLY);
-+ define_constant (sc, O_RDWR);
-+ define_constant (sc, O_EXEC);
-+ define_constant (sc, O_CREAT);
-+ define_constant (sc, O_NOTRANS);
-+
-+ define_variable (sc, exception_port);
-+ define_variable (sc, rootnode);
-+
-+ /* glibc. */
-+ define_function (sc, "sleep", sleep);
-+ define_function (sc, "usleep", usleep);
-+ define_function (sc, "getcwd", getcwd);
-+ define_function (sc, "chdir", chdir);
-+ define_function (sc, "strerror", strerror);
-+ define_function (sc, "getproc", getproc);
-+
-+ /* Boot process */
-+ define_function (sc, "bind-root", bind_root);
-+ define_function (sc, "bind-proc", bind_proc);
-+ define_function (sc, "bind-auth", bind_auth);
-+ define_function (sc, "bind-term", bind_term);
-+ define_function (sc, "fsys-init", fsys_init);
-+
-+ /* Early bootstrap protocols. */
-+ define_function (sc, "handle-startup-procinit", handle_startup_procinit);
-+ define_function (sc, "handle-startup-authinit", handle_startup_authinit);
-+ define_function (sc, "startup-procinit-reply", startup_procinit_reply);
-+ define_function (sc, "startup-authinit-reply", startup_authinit_reply);
-+
-+ define_function (sc, "startup-essential-task", startup_essential_task);
-+ define_function (sc, "startup-request-notification",
-+ startup_request_notification);
-+ define_function (sc, "startup-reboot", startup_reboot);
-+
-+ /* Process and translator startup. */
-+ define_function (sc, "handle-exec-startup", handle_exec_startup);
-+ define_function (sc, "handle-fsys-startup", handle_fsys_startup);
-+
-+ /* Hurd fs API */
-+ define_function (sc, "file-name-lookup", file_name_lookup);
-+ define_function (sc, "file-set-translator", file_set_translator);
-+ define_function (sc, "file-get-fs-options", file_get_fs_options);
-+
-+ /* Hurd process API */
-+ define_function (sc, "proc-wait!", proc_wait);
-+ define_function (sc, "proc->task->proc", proc_task2proc);
-+ define_function (sc, "proc->task->pid", proc_task2pid);
-+ define_function (sc, "proc->mark-important!", proc_mark_important);
-+ define_function (sc, "proc->mark-exec!", proc_mark_exec);
-+ define_function (sc, "proc->task->child!", proc_child);
-+ define_function (sc, "proc->task->set-init-task!", proc_set_init_task);
-+
-+ /* Hurd hacks. */
-+ define_function (sc, "elf-exec", elf_exec);
-+ define_function (sc, "_exec", _exec);
-+ define_function (sc, "start-handling-early-startup",
-+ start_handling_early_startup);
-+ define_function (sc, "get-essential-tasks", get_essential_tasks);
-+ define_function (sc, "get-registered-tasks", get_registered_tasks);
-+ define_function (sc, "proc->auth->set-std-execdata!",
-+ proc_auth_set_std_execdata);
-+
-+ /* User interface. */
-+ define_function (sc, "enable-readline", enable_readline);
-+ define_function (sc, "prompt", prompt);
-+
-+ /* XXX */
-+ ffi_update (sc);
-+}
-diff --git a/bootshell/ffi.h b/bootshell/ffi.h
-new file mode 100644
-index 0000000..6e52596
---- /dev/null
-+++ b/bootshell/ffi.h
-@@ -0,0 +1,158 @@
-+/* Convenience functions and macros for the foreign function interface.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#ifndef _HURD_BOOTSHELL_FFI_H
-+#define _HURD_BOOTSHELL_FFI_H
-+
-+#include <mach.h>
-+#include <mach/message.h>
-+
-+#include "scheme.h"
-+#include "scheme-private.h"
-+
-+// XXX drop name
-+#define SC_FFI_PROLOG(NAME) \
-+ const char *__ffi_name __attribute__ ((unused)) = NAME; \
-+ unsigned int __ffi_arg_index __attribute__ ((unused)) = 1; \
-+ error_t err = 0; \
-+
-+#define CONVERSION_number ivalue
-+#define CONVERSION_string string_value
-+#define CONVERSION_list
-+#define IS_A_number(SC, X) (SC)->vptr->is_number (X)
-+#define IS_A_string(SC, X) (SC)->vptr->is_string (X)
-+#define IS_A_list(SC, X) (SC)->vptr->is_list (SC, X)
-+
-+// XXX proper error handling
-+#define SC_ARG(SC, CTYPE, TARGET, WANT, ARGS) \
-+ if ((ARGS) == (SC)->NIL) { \
-+ fprintf (stderr, "Error: %s: too few arguments: " \
-+ "want " #TARGET "("#WANT"/"#CTYPE")\n", __ffi_name); \
-+ return (SC)->NIL; \
-+ } \
-+ if (! IS_A_##WANT ((SC), pair_car (ARGS))) { \
-+ fprintf (stderr, "Error: %s: argument %d must be: " \
-+ #WANT "\n", __ffi_name, __ffi_arg_index); \
-+ return (SC)->NIL; \
-+ } \
-+ CTYPE TARGET = CONVERSION_##WANT (pair_car (ARGS)); \
-+ ARGS = pair_cdr (ARGS); \
-+ __ffi_arg_index += 1; \
-+
-+#define SC_ARGS_DONE(SC) \
-+ /* XXX */
-+
-+#define SC_RETURN_ERR(SC, ERR) \
-+ return _cons ((SC), mk_integer ((SC), (ERR)), (SC)->NIL, 1)
-+
-+#define SC_RETURN(SC) SC_RETURN_ERR (SC, err)
-+
-+#define SC_RETURN_POINTER(SC, X) \
-+ return _cons ((SC), mk_integer ((SC), err), \
-+ _cons ((SC), (X), (SC)->NIL, 1), 1)
-+#define SC_RETURN_INT(SC, X) \
-+ SC_RETURN_POINTER ((SC), mk_integer ((SC), (X)))
-+#define SC_RETURN_STRING(SC, X) \
-+ SC_RETURN_POINTER ((SC), mk_string ((SC), (X)))
-+
-+const char *schemify_name (const char *s, int macro);
-+
-+#define define_function(S, P, F) \
-+ ({ \
-+ char _sc_buf[256]; \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name ("_" #F, 0)), \
-+ mk_foreign_func ((S), (do_##F))); \
-+ snprintf (_sc_buf, sizeof _sc_buf, \
-+ "(define (%1$s . a) (ffi-apply \"%1$s\" %2$s a))", \
-+ P, schemify_name ("_" #F, 0)); \
-+ scheme_load_string (S, _sc_buf); \
-+ })
-+
-+#define define_constant(S, C) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#C, 1)), \
-+ mk_integer ((S), (C)))
-+
-+#define define_(S, SYM, EXP) \
-+ scheme_define ((S), (S)->global_env, mk_symbol ((S), (SYM)), EXP)
-+
-+#define define_variable(S, C) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#C, 0)), \
-+ mk_integer ((S), (C)))
-+
-+#define define_variable_pointer(S, C, P) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#C, 0)), \
-+ (P))
-+
-+#define define_variable_string(S, C) \
-+ define_variable_pointer (S, C, (S)->vptr->mk_string (S, C ?: ""))
-+
-+/* A variant of scheme_load_string that does not require the string to
-+ be zero-terminated. */
-+void scheme_load_mem (scheme *, const char *, const char *);
-+
-+#define declare_embedded_script(X) \
-+ extern char X##_size[] asm("_binary__"#X"_o_size"); \
-+ extern char X##_start[] asm("_binary__"#X"_o_start"); \
-+ extern char X##_end[] asm("_binary__"#X"_o_end")
-+
-+#define load_embedded_script(S, X) \
-+ ({ \
-+ scheme_load_mem ((S), X##_start, X##_end); \
-+ if ((S)->retcode != 0) \
-+ fprintf (stderr, "Errors encountered evaluating %s\n", #X); \
-+ })
-+
-+declare_embedded_script (init);
-+declare_embedded_script (boot);
-+declare_embedded_script (runsystem);
-+
-+void ffi_update (scheme *sc);
-+void ffi_init (scheme *sc);
-+
-+pointer ffi_argz2list (scheme *sc,
-+ const char *argz, size_t argz_len, const char *entry);
-+void ffi_list2argz (scheme *sc, char **argz, size_t *argz_len, pointer list);
-+
-+// XXX
-+error_t service_fsys_request (mach_port_t bootstrap,
-+ mach_port_t realnode,
-+ mach_msg_type_name_t realnodePoly,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *control);
-+
-+/* Forward declarations. */
-+
-+/* exec-startup.c */
-+pointer do_handle_exec_startup (scheme *sc, pointer args);
-+
-+/* elf-exec.c */
-+pointer do_elf_exec (scheme *sc, pointer args);
-+
-+/* fsys.c */
-+pointer do_handle_fsys_startup (scheme *sc, pointer args);
-+
-+#endif /* _HURD_BOOTSHELL_FFI_H */
-diff --git a/bootshell/fs.c b/bootshell/fs.c
-new file mode 100644
-index 0000000..88536d8
---- /dev/null
-+++ b/bootshell/fs.c
-@@ -0,0 +1,111 @@
-+/* Handles the fs protocol.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <assert.h>
-+#include <hurd.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+
-+// eek #include "fs_S.h"
-+
-+#include "bootshell.h"
-+
-+mach_port_t rootnode;
-+
-+/* A top-level function for the paging thread that just services paging
-+ requests. */
-+static void *
-+service_fs_requests (void *arg)
-+{
-+ extern boolean_t fs_server ();
-+
-+ int trace_demuxer (mach_msg_header_t *inp,
-+ mach_msg_header_t *outp)
-+ {
-+ error (0, 0, "(fs-server: %d)", inp->msgh_id);
-+ int i = fs_server (inp, outp);
-+ return i;
-+ }
-+
-+ // XXX specialized demuxer
-+ while (1)
-+ mach_msg_server (0? trace_demuxer: fs_server, 0, rootnode);
-+
-+ /* Not reached. */
-+ return NULL;
-+}
-+
-+error_t
-+init_fs_server (void)
-+{
-+ error_t err;
-+ pthread_t t;
-+
-+ err = mach_port_allocate (mach_task_self (),
-+ MACH_PORT_RIGHT_RECEIVE,
-+ &rootnode);
-+ if (err)
-+ return err;
-+
-+ /* Make a thread to service the fs protocol. */
-+ err = pthread_create (&t, NULL, service_fs_requests, NULL);
-+ if (err)
-+ return err;
-+ pthread_detach (t);
-+
-+ err = mach_port_insert_right (mach_task_self (),
-+ rootnode,
-+ rootnode,
-+ MACH_MSG_TYPE_MAKE_SEND);
-+ if (err)
-+ return err;
-+
-+ setcrdir (rootnode); // XXX do we want this? not sure what for tbh.
-+ setcwdir (rootnode);
-+ portarray_template[INIT_PORT_CRDIR] = rootnode;
-+ portarray_template[INIT_PORT_CWDIR] = rootnode;
-+
-+ return err;
-+}
-+
-+error_t
-+S_dir_lookup (file_t file,
-+ char *path,
-+ int flags,
-+ mode_t mode,
-+ enum retry_type *retry,
-+ char *retryname,
-+ file_t *returned_port,
-+ mach_msg_type_name_t *returned_port_poly)
-+{
-+ if (file != rootnode)
-+ return EOPNOTSUPP;
-+
-+ if (portarray_template[INIT_PORT_CRDIR] == rootnode)
-+ /* Still no root filesystem. */
-+ return EOPNOTSUPP;
-+
-+ *retry = FS_RETRY_NORMAL;
-+ strncpy (retryname, path, sizeof (string_t));
-+ *returned_port = portarray_template[INIT_PORT_CRDIR];
-+ *returned_port_poly = MACH_MSG_TYPE_COPY_SEND;
-+ return 0;
-+}
-diff --git a/bootshell/fsys.c b/bootshell/fsys.c
-new file mode 100644
-index 0000000..a92b90d
---- /dev/null
-+++ b/bootshell/fsys.c
-@@ -0,0 +1,123 @@
-+/* Handles the fsys protocol.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <assert.h>
-+#include <hurd.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <mach/mig_support.h>
-+#include <stdio.h>
-+
-+// eek #include "fsys_S.h"
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+ mach_port_t realnode;
-+ mach_msg_type_name_t realnodePoly;
-+
-+ /* Filled by the server function. */
-+ mach_port_t control_port;
-+} fsys_startup_args;
-+
-+error_t
-+S_fsys_startup (mach_port_t bootstrap,
-+ int openflags,
-+ mach_port_t control_port,
-+ mach_port_t *realnode,
-+ mach_msg_type_name_t *realnodePoly)
-+{
-+ assert (MACH_PORT_VALID (fsys_startup_args.bootstrap_port));
-+ if (bootstrap != fsys_startup_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ fsys_startup_args.control_port = control_port;
-+ *realnode = fsys_startup_args.realnode;
-+ *realnodePoly = fsys_startup_args.realnodePoly;
-+ return 0;
-+}
-+
-+static boolean_t
-+fsys_startup_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ // XXX
-+ extern boolean_t fsys_server (mach_msg_header_t *, mach_msg_header_t *);
-+
-+ switch (request->msgh_id)
-+ {
-+ case 22000: /* fsys_startup */
-+ return fsys_server (request, reply);
-+ }
-+
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+}
-+
-+error_t
-+service_fsys_request (mach_port_t bootstrap,
-+ mach_port_t realnode,
-+ mach_msg_type_name_t realnodePoly,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *control)
-+{
-+ error_t err;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ fsys_startup_args.bootstrap_port = bootstrap;
-+ fsys_startup_args.realnode = realnode;
-+ fsys_startup_args.realnodePoly = realnodePoly;
-+ fsys_startup_args.control_port = MACH_PORT_NULL;
-+
-+ err = mach_msg_server_timeout_once (fsys_startup_demuxer, 0, bootstrap,
-+ MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT,
-+ timeout);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ *control = fsys_startup_args.control_port;
-+ return 0;
-+}
-+
-+pointer
-+do_handle_fsys_startup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-fsys-startup");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, mach_port_t, realnode, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, realnodePoly, number, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t control;
-+ err = service_fsys_request (bootstrap,
-+ realnode,
-+ realnodePoly,
-+ timeout,
-+ &control);
-+ SC_RETURN_INT (sc, control);
-+}
-diff --git a/bootshell/main.c b/bootshell/main.c
-new file mode 100644
-index 0000000..e891480
---- /dev/null
-+++ b/bootshell/main.c
-@@ -0,0 +1,263 @@
-+/* Bootshell, a Scheme shell, a flexible multiserver bootstrap solution.
-+
-+ Copyright (C) 1995-2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <argp.h>
-+#include <assert.h>
-+#include <ctype.h>
-+#include <stdarg.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <error.h>
-+#include <hurd.h>
-+#include <hurd/fshelp.h>
-+#include <device/device.h>
-+#include <version.h>
-+
-+#include "scheme.h"
-+#include "scheme-private.h"
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+task_t bootscript_task;
-+task_t rootfs_server_task;
-+task_t exec_server_task;
-+
-+#define _HURD_RUNSYSTEM "/hurd/runsystem.scm"
-+#define _BOOT_COMMAND "(boot)"
-+
-+char *multiboot_command_line;
-+char *boot_init_program;
-+boolean_t boot_pause;
-+char *boot_command = _BOOT_COMMAND;
-+char **global_argv;
-+boolean_t booted;
-+boolean_t interactive;
-+
-+scheme scm;
-+
-+/* We catch exceptions using this port. */
-+mach_port_t exception_port;
-+
-+mach_port_t console;
-+
-+mach_port_t portarray_template[INIT_PORT_MAX];
-+
-+const char *argp_program_version = STANDARD_HURD_VERSION (bootshell);
-+
-+#define OPT_HOST_PRIV_PORT (-1)
-+#define OPT_DEVICE_MASTER_PORT (-2)
-+#define OPT_BOOTSCRIPT_TASK (-3)
-+#define OPT_ROOTFS_SERVER_TASK (-4)
-+#define OPT_EXEC_SERVER_TASK (-5)
-+#define OPT_BOOT_CMDLINE (-6)
-+#define OPT_BOOT_COMMAND (-7)
-+#define OPT_BOOT_INIT_PROGRAM (-8)
-+#define OPT_BOOT_PAUSE (-9)
-+
-+static const struct argp_option options[] =
-+{
-+ {"interactive", 'I', NULL, 0, "start interactive repl"},
-+ {0,0,0,0, "Boot options:", -2},
-+ {"multiboot-command-line", OPT_BOOT_CMDLINE, "ARGS", 0,
-+ "The multiboot kernel command line"},
-+ {"bootflags", 0, 0, OPTION_ALIAS|OPTION_HIDDEN},
-+ {"boot-debug-pause", OPT_BOOT_PAUSE, NULL, 0,
-+ "Pause for keystroke before starting bootstrap programs"},
-+ {"boot-command", OPT_BOOT_COMMAND, "S-EXPRESSION", 0,
-+ "Command to run, default: " _BOOT_COMMAND},
-+ {"host-priv-port", OPT_HOST_PRIV_PORT, "PORT"},
-+ {"device-master-port", OPT_DEVICE_MASTER_PORT, "PORT"},
-+ {"bootscript-task", OPT_BOOTSCRIPT_TASK, "PORT"},
-+ {"rootfs-server-task", OPT_ROOTFS_SERVER_TASK, "PORT"},
-+ {"exec-server-task", OPT_EXEC_SERVER_TASK, "PORT"},
-+ {0}
-+};
-+
-+static error_t
-+parse_opt (int opt, char *arg, struct argp_state *state)
-+{
-+ switch (opt)
-+ {
-+ /* Boot options */
-+ case 'I':
-+ interactive = 1;
-+ break;
-+ case OPT_DEVICE_MASTER_PORT:
-+ _hurd_device_master = atoi (arg); break;
-+ case OPT_HOST_PRIV_PORT:
-+ _hurd_host_priv = atoi (arg); break;
-+ case OPT_BOOTSCRIPT_TASK:
-+ bootscript_task = atoi (arg); break;
-+ case OPT_ROOTFS_SERVER_TASK:
-+ rootfs_server_task = atoi (arg); break;
-+ case OPT_EXEC_SERVER_TASK:
-+ exec_server_task = atoi (arg); break;
-+ case OPT_BOOT_CMDLINE:
-+ multiboot_command_line = arg; break;
-+ case OPT_BOOT_INIT_PROGRAM:
-+ boot_init_program = arg; break;
-+ case OPT_BOOT_PAUSE:
-+ boot_pause = 1; break;
-+ case OPT_BOOT_COMMAND:
-+ boot_command = arg; break;
-+ case ARGP_KEY_END:
-+ global_argv = state->argv; break;
-+ default:
-+ return ARGP_ERR_UNKNOWN;
-+ case ARGP_KEY_INIT:
-+ case ARGP_KEY_SUCCESS:
-+ case ARGP_KEY_ERROR:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static const char doc[] =
-+ "Start and maintain hurd core servers and system run state";
-+
-+static const struct argp argp =
-+{ options, parse_opt, 0, doc };
-+
-+void
-+panic (const char *msg)
-+{
-+ puts (msg);
-+ fflush (stdout);
-+ _exit (127);
-+}
-+
-+int
-+main (int argc, char **argv)
-+{
-+ error_t err;
-+ /* XXX */
-+ setenv ("TERM", "mach", 1);
-+ setenv ("COLS", "80", 1);
-+ setenv ("LINES", "25", 1);
-+
-+ argp_parse (&argp, argc, argv, /*ARGP_NO_ERRS|*/ARGP_IN_ORDER, 0, 0);
-+
-+ {
-+ mach_port_t proc = getproc ();
-+ if (MACH_PORT_VALID (proc))
-+ {
-+ booted = 1;
-+ err = mach_port_deallocate (mach_task_self (), proc);
-+ assert_perror (err);
-+ }
-+ }
-+
-+ if (! booted)
-+ {
-+ err = init_exception_handling ();
-+ if (err)
-+ error (1, err, "init_exception_handling");
-+ }
-+
-+ err = init_fs_server (); // XXX don't start automatically
-+ if (err)
-+ error (1, err, "init_fs_server");
-+
-+ if (MACH_PORT_VALID (_hurd_device_master))
-+ {
-+ err = device_open (_hurd_device_master, D_READ|D_WRITE,
-+ "console", &console);
-+ if (err)
-+ panic ("Failed to open console.");
-+
-+ stdin = mach_open_devstream (console, "r");
-+ stdout = stderr = mach_open_devstream (console, "w");
-+ if (! stdin || ! stdout)
-+ panic ("Failed to open device stream.");
-+
-+ setvbuf (stdout, NULL, _IONBF, 0);
-+ }
-+
-+ if (! scheme_init (&scm))
-+ error (1, errno, "scheme_init");
-+
-+ scheme_set_input_port_file (&scm, stdin);
-+ scheme_set_output_port_file (&scm, stdout);
-+
-+ ffi_init (&scm);
-+
-+ load_embedded_script (&scm, init);
-+ load_embedded_script (&scm, boot);
-+ load_embedded_script (&scm, runsystem);
-+
-+ define_variable (&scm, bootscript_task);
-+ define_variable (&scm, rootfs_server_task);
-+ define_variable (&scm, exec_server_task);
-+ define_variable (&scm, boot_pause);
-+
-+ define_ (&scm, "host-priv",
-+ scm.vptr->mk_integer (&scm, _hurd_host_priv));
-+ define_ (&scm, "device-master",
-+ scm.vptr->mk_integer (&scm, _hurd_device_master));
-+
-+ define_variable_string (&scm, multiboot_command_line);
-+ define_variable_string (&scm, boot_init_program);
-+ define_variable_string (&scm, boot_command);
-+ define_variable (&scm, boot_pause);
-+ {
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ err = argz_create (argv, &argz, &argz_len);
-+ assert_perror (err);
-+ define_ (&scm, "argv", ffi_argz2list (&scm, argz, argz_len, NULL));
-+ }
-+
-+ if (MACH_PORT_VALID (bootscript_task))
-+ {
-+ vm_size_t size;
-+ vm_prot_t prot, max_prot;
-+ mach_port_t obj;
-+ vm_offset_t addr = 0, offs;
-+ vm_inherit_t inh;
-+ int shared;
-+
-+ err =
-+ vm_region (bootscript_task, &addr, &size, &prot, &max_prot, &inh, &shared,
-+ &obj, &offs);
-+ if (err)
-+ error (12, err, "vm_region");
-+
-+ vm_offset_t script;
-+ size_t count;
-+ err = vm_read (bootscript_task, addr, size, &script, &count);
-+ if (err)
-+ error (12, err, "vm_read");
-+ scheme_load_mem (&scm, (char *) script, (char *) script + size);
-+ if (scm.retcode) {
-+ fprintf (stderr, "Error: %d\n", scm.retcode);
-+ }
-+ }
-+
-+ if (! interactive)
-+ scheme_load_string (&scm, boot_command);
-+
-+ while (1)
-+ scheme_load_string (&scm, "(interactive-repl)");
-+
-+ /* Not reached. */
-+ scheme_deinit(&scm);
-+ return 0;
-+}
-diff --git a/bootshell/mig-decls.h b/bootshell/mig-decls.h
-new file mode 100644
-index 0000000..76a67ff
---- /dev/null
-+++ b/bootshell/mig-decls.h
-@@ -0,0 +1,22 @@
-+/* MIG declarations for bootshell.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <hurd.h>
-+
-+#define MIG_EOPNOTSUPP ({ abort (); EOPNOTSUPP; })
-diff --git a/bootshell/mig-mutate.h b/bootshell/mig-mutate.h
-new file mode 100644
-index 0000000..145e83a
---- /dev/null
-+++ b/bootshell/mig-mutate.h
-@@ -0,0 +1,27 @@
-+/* MIG mutations for bootshell.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#define HURD_DEFAULT_PAYLOAD_TO_PORT 1
-+
-+#define FILE_IMPORTS \
-+ import "mig-decls.h";
-+#define FSYS_IMPORTS \
-+ import "mig-decls.h";
-+#define STARTUP_IMPORTS \
-+ import "mig-decls.h";
-diff --git a/bootshell/runsystem.scm b/bootshell/runsystem.scm
-new file mode 100644
-index 0000000..ebfacfe
---- /dev/null
-+++ b/bootshell/runsystem.scm
-@@ -0,0 +1,211 @@
-+;; The Hurd server bootstrap.
-+;;
-+;; Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+(define timeout 1000) ; 1 second
-+
-+(define (pause)
-+ (if (= 1 boot-pause) (prompt "Press enter to continue...")))
-+
-+;; Tests if a device with the given NAME exists.
-+(define (devprobe? name)
-+ (letport ((device (catch MACH_PORT_NULL
-+ (device-open device-master D_READ name))))
-+ (mach-port-valid? device)))
-+
-+;; Insert RIGHT into TASK. Returns the name of RIGHT in TASK.
-+(define (task-insert-send-right task right)
-+ (let loop ((name 1))
-+ (catch (loop (+ name 1))
-+ (mach-port-insert-right task name right MACH_MSG_TYPE_COPY_SEND)
-+ name)))
-+
-+;; Inserts RIGHT into TASK and returns a command line argument OPTION
-+;; with the value set to the name of RIGHT in TASK.
-+(define (make-arg option task right)
-+ (string-append "--" option "="
-+ (number->string (task-insert-send-right task right))))
-+
-+;; Returns a function that can be passed to `bootstrap-translator' to
-+;; resume a translator loaded by the traditional bootscript mechanism.
-+(define (resume-translator task args)
-+ (lambda (bootstrap)
-+ (task-set-exception-port task (make-send-right exception-port))
-+ (task-set-bootstrap-port task bootstrap)
-+ (pause)
-+ (task-resume task)
-+ (handle-exec-startup bootstrap args timeout)
-+ task))
-+
-+;; Returns a function that can be passed to `bootstrap-translator' to
-+;; start a translator that is loaded from a disk.
-+(define (start-translator task argv)
-+ (lambda (bootstrap)
-+ (letport ((proc (getproc)))
-+ (pause)
-+ (_exec (file-name-lookup (car argv) O_EXEC 0) task argv bootstrap)
-+ (if (mach-port-valid? proc)
-+ (let ((child-proc (proc->task->proc proc task)))
-+ (proc->mark-exec! child-proc)
-+ (proc->mark-important! child-proc)
-+ (proc->task->child! proc task))))))
-+
-+;; Bootstraps a translator using the fsys protocol.
-+(define (bootstrap-translator prepare-task realnode)
-+ (let* ((bootstrap
-+ (mach-port-allocate mach-task-self MACH_PORT_RIGHT_RECEIVE))
-+ (task
-+ (prepare-task (make-send-right bootstrap))))
-+ (handle-fsys-startup bootstrap realnode MACH_MSG_TYPE_COPY_SEND timeout)))
-+
-+;; Bootstraps the proc server using the startup protocol.
-+(define (bootstrap-proc prepare-task)
-+ (let* ((bootstrap
-+ (mach-port-allocate mach-task-self MACH_PORT_RIGHT_RECEIVE))
-+ (task
-+ (prepare-task (make-send-right bootstrap))))
-+ (handle-startup-procinit bootstrap timeout)))
-+
-+;; Bootstraps the auth server using the startup protocol.
-+(define (bootstrap-auth prepare-task)
-+ (let* ((bootstrap
-+ (mach-port-allocate mach-task-self MACH_PORT_RIGHT_RECEIVE))
-+ (task
-+ (prepare-task (make-send-right bootstrap))))
-+ (handle-startup-authinit bootstrap timeout)))
-+
-+;; Bootstraps a translator using the fsys protocol and installs it as
-+;; root filesystem.
-+(define (bind-root prepare-task)
-+ (let ((control
-+ (bootstrap-translator prepare-task (make-send-right rootnode))))
-+ (_bind-root control rootnode)
-+ control))
-+
-+;; Bootstraps a translator using the fsys protocol and installs it as
-+;; active translator for the node PATH.
-+(define (bind path prepare-task)
-+ (letport ((realnode (file-name-lookup path O_NOTRANS 438))
-+ (control (bootstrap-translator prepare-task realnode)))
-+ (set-active-translator path control)
-+ (copy-send-right control)))
-+
-+;; We start servers when the proc server is not yet around. Once the
-+;; proc server is available, we use this function to update its state
-+;; related to TASK.
-+(define (fixup-task task)
-+ (letport ((myproc (getproc))
-+ (p (proc->task->proc myproc task)))
-+ (proc->task->child! myproc task)
-+ (proc->mark-important! p)
-+ (proc->mark-exec! p)))
-+
-+(define (bootstrap rootfs-args exec-args)
-+ (log "Hurd server bootstrap: ")
-+
-+ (log "rootfs ")
-+ (let ((rootfs-control (bind-root (resume-translator rootfs-server-task
-+ rootfs-args)))
-+ (startup-control (mach-port-allocate mach-task-self
-+ MACH_PORT_RIGHT_RECEIVE))
-+ (proc-task (task-create mach-task-self 0))
-+ (auth-task (task-create mach-task-self 0))
-+ ;; Projections for the cookies returned by bootstrap-*.
-+ (:reply car) (:replyPoly cadr) (:server caddr))
-+ (start-handling-early-startup startup-control)
-+ (set-active-translator "/servers/startup"
-+ (make-send-right startup-control))
-+ (log "exec ")
-+ (bind "/servers/exec" (resume-translator exec-server-task exec-args))
-+
-+ ;; Starting proc and auth is tricky, we need to do it simultaneously.
-+ (let ((pc (bootstrap-proc (start-translator proc-task '("/hurd/proc"))))
-+ (ac (bootstrap-auth (start-translator auth-task '("/hurd/auth")))))
-+ (log "proc ")
-+ (startup-procinit-reply (:reply pc) (:replyPoly pc) ESUCCESS
-+ mach-task-self (:server ac)
-+ host-priv device-master)
-+ (bind-proc (:server pc))
-+
-+ ;; Declare that these tasks are our children, and fix them up.
-+ (map fixup-task (list rootfs-server-task exec-server-task
-+ proc-task auth-task))
-+
-+ (log "auth ")
-+ (startup-authinit-reply (:reply ac) (:replyPoly ac) ESUCCESS
-+ (proc->task->proc (:server pc) auth-task))
-+ (bind-auth (:server ac))
-+
-+ ;; Give the rootfs its proc and auth port.
-+ (fsys-init rootfs-control
-+ (proc->task->proc (:server pc) rootfs-server-task)
-+ (:server ac))
-+
-+ ;; Supply the proc server with a standard template.
-+ (proc->auth->set-std-execdata! (:server pc) (:server ac))
-+
-+ (mach-port-deallocate mach-task-self (:server pc))
-+ (mach-port-deallocate mach-task-self (:server ac))))
-+
-+ (log "console ")
-+ (bind "/dev/console"
-+ (start-translator (task-create mach-task-self 0)
-+ '("/hurd/term" "/dev/console" "device" "console")))
-+
-+ (letport ((term (file-name-lookup "/dev/console" O_RDWR 0)))
-+ (bind-term term))
-+
-+ ;; If we made it this far, we can use libreadline!
-+ (enable-readline)
-+
-+ ;; The standalone startup server watches essential servers, and
-+ ;; handles the system shutdown.
-+ (log "startup ")
-+ (bind "/servers/startup"
-+ (start-translator (task-create mach-task-self 0)
-+ '("/hurd/startup-standalone")))
-+
-+ ;; Now that we have startup, register all servers to it.
-+ (letport
-+ ((startup (file-name-lookup "/servers/startup" 0 0)))
-+ (let ((:port car) (:name cdr)) ;; Projections.
-+ ;; We are essential.
-+ (startup-essential-task startup mach-task-self MACH_PORT_NULL
-+ "bootshell" host-priv)
-+ (map (lambda (c)
-+ (startup-essential-task startup (:port c) MACH_PORT_NULL
-+ (:name c) host-priv))
-+ (get-essential-tasks))
-+ (map (lambda (c)
-+ (startup-request-notification startup (:port c) (:name c)))
-+ (get-registered-tasks))))
-+
-+ (log "pflocal ")
-+ (bind "/servers/socket/1"
-+ (start-translator (task-create mach-task-self 0)
-+ '("/hurd/pflocal")))
-+
-+ (log "done.\n"))
-+
-+(define (boot)
-+ (catch (panic "Hurd bootstrap failed: " (car last-exception) "\n")
-+ (bootstrap '() '()))
-+
-+ (shell (lambda (prefix)
-+ (prompt-append-prefix
-+ (string-append "runsystem@" (hostname) " " (getcwd) " ") prefix))))
-diff --git a/bootshell/scheme-config.h b/bootshell/scheme-config.h
-new file mode 100644
-index 0000000..127df9f
---- /dev/null
-+++ b/bootshell/scheme-config.h
-@@ -0,0 +1,31 @@
-+/* TinyScheme configuration.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#define STANDALONE 0
-+#define USE_MATH 0
-+#define USE_CHAR_CLASSIFIERS 1
-+#define USE_ASCII_NAMES 1
-+#define USE_STRING_PORTS 1
-+#define USE_ERROR_HOOK 1
-+#define USE_TRACING 1
-+#define USE_COLON_HOOK 0
-+#define USE_DL 0
-+#define USE_PLIST 0
-+#define USE_INTERFACE 1
-+#define SHOW_ERROR_LINE 1
-diff --git a/bootshell/startup.c b/bootshell/startup.c
-new file mode 100644
-index 0000000..4b9f71d
---- /dev/null
-+++ b/bootshell/startup.c
-@@ -0,0 +1,508 @@
-+/* Handles the startup protocol.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#include <assert.h>
-+#include <errno.h>
-+#include <error.h>
-+#include <hurd.h>
-+#include <hurd/startup.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <mach/mig_support.h>
-+#include <mach/notify.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+#include <string.h>
-+
-+#include "startup_reply_U.h"
-+// eek #include "startup_S.h"
-+// eek #include "fsys_S.h"
-+
-+extern boolean_t startup_server (mach_msg_header_t *, mach_msg_header_t *);
-+extern boolean_t fsys_server (mach_msg_header_t *, mach_msg_header_t *);
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+/* Handling of `startup_essential_task'. */
-+
-+static mach_port_t early_startup_port;
-+
-+/* This structure keeps track of each registered essential task. */
-+struct port_string_tuple
-+ {
-+ struct port_string_tuple *next;
-+ task_t port;
-+ char *name;
-+ };
-+
-+static struct port_string_tuple *essential_tasks;
-+static struct port_string_tuple *registered_tasks;
-+
-+/* Record an essential task in the list. */
-+static error_t
-+add_tuple (struct port_string_tuple **list, mach_port_t port, const char *name)
-+{
-+ struct port_string_tuple *et;
-+
-+ et = malloc (sizeof *et);
-+ if (et == NULL)
-+ goto out;
-+
-+ et->port = port;
-+ et->name = strdup (name);
-+ if (et->name == NULL)
-+ goto out;
-+
-+ et->next = *list;
-+ *list = et;
-+ return 0;
-+
-+ out:
-+ free (et);
-+ return ENOMEM;
-+}
-+
-+/* fsys_goaway for early-boot /servers/startup. */
-+error_t
-+S_fsys_goaway (mach_port_t fsys,
-+ int flags)
-+{
-+ if (fsys != early_startup_port)
-+ return EOPNOTSUPP;
-+ // XXX keep going = 0
-+ return 0;
-+}
-+
-+/* fsys_getroot for early-boot /servers/startup. */
-+error_t
-+S_fsys_getroot (mach_port_t fsys,
-+ 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)
-+{
-+ if (fsys != early_startup_port)
-+ return EOPNOTSUPP;
-+
-+ *do_retry = FS_RETRY_NORMAL;
-+ *retry_name = '\0';
-+ *ret = early_startup_port;
-+ *rettype = MACH_MSG_TYPE_MAKE_SEND;
-+ return 0;
-+}
-+
-+error_t
-+S_startup_essential_task (startup_t server,
-+ mach_port_t reply_port,
-+ mach_msg_type_name_t reply_portPoly,
-+ mach_port_t task,
-+ mach_port_t excpt,
-+ string_t name,
-+ mach_port_t credential)
-+{
-+ error_t err;
-+ if (server != early_startup_port)
-+ return EOPNOTSUPP;
-+ if (credential != _hurd_host_priv)
-+ return EPERM;
-+
-+ err = mach_port_deallocate (mach_task_self (), credential);
-+ assert_perror (err);
-+
-+ if (MACH_PORT_VALID (excpt))
-+ {
-+ error (0, 0,
-+ "Oh dear, someone actually send us their exception port.\n"
-+ "I'm going to destroy it. Please investigate.");
-+ err = mach_port_destroy (mach_task_self (), excpt);
-+ assert_perror (err);
-+ }
-+
-+ err = add_tuple (&essential_tasks, task, name);
-+ if (err)
-+ return err;
-+
-+ return 0;
-+}
-+
-+kern_return_t
-+S_startup_request_notification (mach_port_t server,
-+ mach_port_t notify,
-+ char *name)
-+{
-+ if (server != early_startup_port)
-+ return EOPNOTSUPP;
-+
-+ return add_tuple (&registered_tasks, notify, name);
-+}
-+
-+static boolean_t
-+early_startup_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ /* XXX hardcoded msgh_ids */
-+ switch (request->msgh_id)
-+ {
-+ case 29000: /* startup_essential_task */
-+ case 29001: /* startup_request_notification */
-+ return startup_server (request, reply);
-+ case 22001: /* fsys_goaway */
-+ case 22002: /* fsys_getroot */
-+ return fsys_server (request, reply);
-+ }
-+
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+}
-+
-+static void *
-+service_early_startup_requests (void *arg)
-+{
-+ // XXX while (keep_going) ...
-+ while (1)
-+ mach_msg_server (early_startup_demuxer, 0,
-+ early_startup_port);
-+
-+ /* Not reached. */
-+ return NULL;
-+}
-+
-+static error_t
-+start_handling_early_startup (mach_port_t startup_port)
-+{
-+ error_t err;
-+ pthread_t t;
-+
-+ if (MACH_PORT_VALID (early_startup_port))
-+ return EINVAL;
-+ early_startup_port = startup_port;
-+
-+ /* Make a thread to service `startup_essential_task' requests. */
-+ err = pthread_create (&t, NULL, service_early_startup_requests,
-+ NULL);
-+ if (err)
-+ return err;
-+ pthread_detach (t);
-+
-+ return err;
-+}
-+
-+pointer
-+do_start_handling_early_startup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("start-handling-early-startup");
-+ SC_ARG (sc, mach_port_t, server_port, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = start_handling_early_startup (server_port);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_get_essential_tasks (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("get-essential-tasks");
-+ SC_ARGS_DONE (sc);
-+ pointer result = sc->NIL;
-+ struct port_string_tuple *et;
-+ for (et = essential_tasks; et; et = et->next)
-+#define IMC(A, B) _cons (sc, (A), (B), 1)
-+ result = IMC (IMC (mk_integer (sc, et->port),
-+ mk_string (sc, et->name)),
-+ result);
-+#undef IMC
-+ SC_RETURN_POINTER (sc, result);
-+}
-+
-+pointer
-+do_get_registered_tasks (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("get-registered-tasks");
-+ SC_ARGS_DONE (sc);
-+ pointer result = sc->NIL;
-+ struct port_string_tuple *rt;
-+ for (rt = registered_tasks; rt; rt = rt->next)
-+#define IMC(A, B) _cons (sc, (A), (B), 1)
-+ result = IMC (IMC (mk_integer (sc, rt->port),
-+ mk_string (sc, rt->name)),
-+ result);
-+#undef IMC
-+ SC_RETURN_POINTER (sc, result);
-+}
-+
-+/* Client stubs for startup. */
-+pointer
-+do_startup_essential_task (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-essential-task");
-+ SC_ARG (sc, mach_port_t, startup, number, args);
-+ SC_ARG (sc, mach_port_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, exception, number, args);
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARG (sc, mach_port_t, credential, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_essential_task (startup, task, exception, name, credential);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_startup_request_notification (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-request-notification");
-+ SC_ARG (sc, mach_port_t, startup, number, args);
-+ SC_ARG (sc, mach_port_t, notify_port, number, args);
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_request_notification (startup,
-+ notify_port, MACH_MSG_TYPE_COPY_SEND,
-+ name);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_startup_reboot (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-reboot");
-+ SC_ARG (sc, mach_port_t, startup, number, args);
-+ SC_ARG (sc, mach_port_t, credential, number, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_reboot (startup, credential, flags);
-+ SC_RETURN (sc);
-+}
-+
-+/* Handling of `startup_procinit'. */
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+
-+ /* Filled by the server function. */
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ process_t procserver;
-+} startup_procinit_args;
-+
-+kern_return_t
-+S_startup_procinit (startup_t bootstrap,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replyPoly,
-+ process_t procserver,
-+ mach_port_t *startuptask,
-+ auth_t *auth,
-+ mach_port_t *hostpriv,
-+ mach_msg_type_name_t *hostprivPoly,
-+ mach_port_t *devmaster,
-+ mach_msg_type_name_t *devmasterPoly)
-+{
-+ if (bootstrap != startup_procinit_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ startup_procinit_args.reply = reply;
-+ startup_procinit_args.replyPoly = replyPoly;
-+ startup_procinit_args.procserver = procserver;
-+ return MIG_NO_REPLY;
-+}
-+
-+boolean_t
-+startup_procinit_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ if (request->msgh_id != 29003) /* XXX hardcoded msgh_id */
-+ {
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+ }
-+ return startup_server (request, reply);
-+}
-+
-+error_t
-+service_startup_procinit_request (mach_port_t bootstrap,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *reply,
-+ mach_msg_type_name_t *replyPoly,
-+ process_t *procserver)
-+{
-+ error_t err;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ startup_procinit_args.bootstrap_port = bootstrap;
-+
-+ err = mach_msg_server_timeout_once (startup_procinit_demuxer, 0, bootstrap,
-+ MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT,
-+ timeout);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ *reply = startup_procinit_args.reply;
-+ *replyPoly = startup_procinit_args.replyPoly;
-+ *procserver = startup_procinit_args.procserver;
-+ return 0;
-+}
-+
-+pointer
-+do_handle_startup_procinit (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-startup-procinit");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ mach_port_t proc;
-+ err = service_startup_procinit_request (bootstrap, timeout,
-+ &reply, &replyPoly, &proc);
-+#define IMC(A, B) _cons (sc, sc->vptr->mk_integer (sc, A), (B), 1)
-+ SC_RETURN_POINTER (sc, IMC (reply, IMC (replyPoly, IMC (proc, sc->NIL))));
-+#undef IMC
-+}
-+
-+pointer
-+do_startup_procinit_reply (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-procinit-reply");
-+ SC_ARG (sc, mach_port_t, reply, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, replyPoly, number, args);
-+ SC_ARG (sc, int, retCode, number, args);
-+ SC_ARG (sc, mach_port_t, startup_task, number, args);
-+ SC_ARG (sc, mach_port_t, authserver, number, args);
-+ SC_ARG (sc, mach_port_t, host_priv, number, args);
-+ SC_ARG (sc, mach_port_t, device_master, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_procinit_reply (reply, replyPoly, retCode,
-+ startup_task, authserver,
-+ host_priv, MACH_MSG_TYPE_COPY_SEND,
-+ device_master, MACH_MSG_TYPE_COPY_SEND);
-+ SC_RETURN (sc);
-+}
-+
-+/* Handling of `startup_authinit'. */
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+
-+ /* Filled by the server function. */
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ mach_port_t authserver;
-+} startup_authinit_args;
-+
-+/* Called by the auth server when it starts up. */
-+
-+kern_return_t
-+S_startup_authinit (startup_t bootstrap,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replyPoly,
-+ mach_port_t auth,
-+ mach_port_t *proc,
-+ mach_msg_type_name_t *procPoly)
-+{
-+ if (bootstrap != startup_authinit_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ startup_authinit_args.reply = reply;
-+ startup_authinit_args.replyPoly = replyPoly;
-+ startup_authinit_args.authserver = auth;
-+ return MIG_NO_REPLY;
-+}
-+
-+boolean_t
-+startup_authinit_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ if (request->msgh_id != 29004) /* XXX hardcoded msgh_id */
-+ {
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+ }
-+ return startup_server (request, reply);
-+}
-+
-+error_t
-+service_startup_authinit_request (mach_port_t bootstrap,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *reply,
-+ mach_msg_type_name_t *replyPoly,
-+ mach_port_t *authserver)
-+{
-+ error_t err;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ startup_authinit_args.bootstrap_port = bootstrap;
-+
-+ err = mach_msg_server_timeout_once (startup_authinit_demuxer, 0, bootstrap,
-+ MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT,
-+ timeout);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ *reply = startup_authinit_args.reply;
-+ *replyPoly = startup_authinit_args.replyPoly;
-+ *authserver = startup_authinit_args.authserver;
-+ return 0;
-+}
-+
-+pointer
-+do_handle_startup_authinit (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-startup-authinit");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ mach_port_t auth;
-+ err = service_startup_authinit_request (bootstrap, timeout,
-+ &reply, &replyPoly, &auth);
-+#define IMC(A, B) _cons (sc, sc->vptr->mk_integer (sc, A), (B), 1)
-+ SC_RETURN_POINTER (sc, IMC (reply, IMC (replyPoly, IMC (auth, sc->NIL))));
-+#undef IMC
-+}
-+
-+pointer
-+do_startup_authinit_reply (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-authinit-reply");
-+ SC_ARG (sc, mach_port_t, reply, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, replyPoly, number, args);
-+ SC_ARG (sc, int, retCode, number, args);
-+ SC_ARG (sc, mach_port_t, authproc, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_authinit_reply (reply, replyPoly, retCode, authproc,
-+ MACH_MSG_TYPE_COPY_SEND);
-+ SC_RETURN (sc);
-+}
-diff --git a/bootshell/startup.h b/bootshell/startup.h
-new file mode 100644
-index 0000000..0fa9b4c
---- /dev/null
-+++ b/bootshell/startup.h
-@@ -0,0 +1,36 @@
-+/* Handles the startup protocol.
-+
-+ Copyright (C) 2015 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. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#ifndef _HURD_BOOTSHELL_STARTUP_H
-+#define _HURD_BOOTSHELL_STARTUP_H
-+
-+#include <ffi.h>
-+
-+pointer do_handle_startup_procinit (scheme *sc, pointer args);
-+pointer do_handle_startup_authinit (scheme *sc, pointer args);
-+pointer do_startup_procinit_reply (scheme *sc, pointer args);
-+pointer do_startup_authinit_reply (scheme *sc, pointer args);
-+pointer do_start_handling_early_startup (scheme *sc, pointer args);
-+pointer do_get_essential_tasks (scheme *sc, pointer args);
-+pointer do_get_registered_tasks (scheme *sc, pointer args);
-+pointer do_startup_essential_task (scheme *sc, pointer args);
-+pointer do_startup_request_notification (scheme *sc, pointer args);
-+pointer do_startup_reboot (scheme *sc, pointer args);
-+
-+#endif /* _HURD_BOOTSHELL_STARTUP_H */
-diff --git a/bootshell/utils.c b/bootshell/utils.c
-new file mode 100644
-index 0000000..9fcf17c
---- /dev/null
-+++ b/bootshell/utils.c
-@@ -0,0 +1,118 @@
-+#include <assert.h>
-+#include <hurd.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <stdarg.h>
-+#include <stdio.h>
-+
-+mach_msg_return_t
-+mach_msg_server_timeout_once (boolean_t (*demux) (mach_msg_header_t *request,
-+ mach_msg_header_t *reply),
-+ mach_msg_size_t max_size,
-+ mach_port_t rcv_name,
-+ mach_msg_option_t option,
-+ mach_msg_timeout_t timeout)
-+{
-+ mig_reply_header_t *request, *reply;
-+ mach_msg_return_t mr;
-+
-+ if (! MACH_PORT_VALID (rcv_name))
-+ return EINVAL;
-+
-+ if (max_size == 0)
-+ {
-+#ifdef MACH_RCV_LARGE
-+ option |= MACH_RCV_LARGE;
-+ max_size = 2 * __vm_page_size; /* Generic. Good? XXX */
-+#else
-+ max_size = 4 * __vm_page_size; /* XXX */
-+#endif
-+ }
-+
-+ request = alloca (max_size);
-+ reply = alloca (max_size);
-+
-+ mr = mach_msg (&request->Head, MACH_RCV_MSG|option,
-+ 0, max_size, rcv_name,
-+ timeout, MACH_PORT_NULL);
-+ if (mr != MACH_MSG_SUCCESS)
-+ return mr;
-+
-+ /* We have a request message. Pass it to DEMUX for processing. */
-+ (void) (*demux) (&request->Head, &reply->Head);
-+ assert (reply->Head.msgh_size <= max_size);
-+
-+ switch (reply->RetCode)
-+ {
-+ case KERN_SUCCESS:
-+ /* Hunky dory. */
-+ break;
-+
-+ case MIG_NO_REPLY:
-+ /* The server function wanted no reply sent.
-+ Loop for another request. */
-+ return 0;
-+
-+ default:
-+ /* Some error; destroy the request message to release any
-+ port rights or VM it holds. Don't destroy the reply port
-+ right, so we can send an error message. */
-+ request->Head.msgh_remote_port = MACH_PORT_NULL;
-+ mach_msg_destroy (&request->Head);
-+ break;
-+ }
-+
-+ if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
-+ {
-+ /* No reply port, so destroy the reply. */
-+ if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
-+ mach_msg_destroy (&reply->Head);
-+ return reply->RetCode;
-+ }
-+
-+ /* Send the reply. */
-+ mr = mach_msg (&reply->Head,
-+ MACH_SEND_MSG|option,
-+ reply->Head.msgh_size, max_size, rcv_name,
-+ timeout, MACH_PORT_NULL);
-+
-+ /* See if a message error occurred. */
-+ if (mr == MACH_SEND_INVALID_DEST)
-+ /* The reply can't be delivered, so destroy it. This error
-+ indicates only that the requester went away, so we
-+ continue and get the next request. */
-+ mach_msg_destroy (&reply->Head);
-+
-+ return mr != 0 ? mr : reply->RetCode;
-+}
-+
-+/* Fill in default response. */
-+void
-+mig_reply_setup (
-+ const mach_msg_header_t *in,
-+ mach_msg_header_t *out)
-+{
-+ static const mach_msg_type_t RetCodeType = {
-+ /* msgt_name = */ MACH_MSG_TYPE_INTEGER_32,
-+ /* msgt_size = */ 32,
-+ /* msgt_number = */ 1,
-+ /* msgt_inline = */ TRUE,
-+ /* msgt_longform = */ FALSE,
-+ /* msgt_deallocate = */ FALSE,
-+ /* msgt_unused = */ 0
-+ };
-+
-+#define InP (in)
-+#define OutP ((mig_reply_header_t *) out)
-+ OutP->Head.msgh_bits =
-+ MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InP->msgh_bits), 0);
-+ OutP->Head.msgh_size = sizeof *OutP;
-+ OutP->Head.msgh_remote_port = InP->msgh_remote_port;
-+ OutP->Head.msgh_local_port = MACH_PORT_NULL;
-+ OutP->Head.msgh_seqno = 0;
-+ OutP->Head.msgh_id = InP->msgh_id + 100;
-+ OutP->RetCodeType = RetCodeType;
-+ OutP->RetCode = MIG_BAD_ID;
-+#undef InP
-+#undef OutP
-+}
-diff --git a/config.make.in b/config.make.in
-index 0f1390a..012bcd5 100644
---- a/config.make.in
-+++ b/config.make.in
-@@ -95,6 +95,10 @@ HAVE_BLKID = @HAVE_BLKID@
- libblkid_CFLAGS = @libblkid_CFLAGS@
- libblkid_LIBS = @libblkid_LIBS@
-
-+# How to compile and link against libreadline.
-+HAVE_READLINE = @HAVE_READLINE@
-+libreadline_LIBS = @libreadline_LIBS@
-+
- # Whether Sun RPC support is available.
- HAVE_SUN_RPC = @HAVE_SUN_RPC@
-
-diff --git a/configure.ac b/configure.ac
-index a388e09..d08e11d 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -333,6 +333,21 @@ PKG_CHECK_MODULES([libblkid], [blkid],
- AC_SUBST([libblkid_LIBS])
- AC_SUBST([libblkid_CFLAGS])
-
-+AC_ARG_WITH([readline],
-+ [AS_HELP_STRING([--without-readline], [disable support for readline])],
-+ [],
-+ [with_readline=yes])
-+
-+LIBREADLINE=
-+AS_IF([test "x$with_readline" != xno],
-+ [AC_CHECK_LIB([readline], [main],
-+ [AC_SUBST([libreadline_LIBS], ["-lreadline -lhistory -lncurses"])
-+ AC_DEFINE([HAVE_LIBREADLINE], [1], [Define if you have libreadline])
-+ ],
-+ [AC_MSG_FAILURE(
-+ [readline test failed (--without-readline to disable)])],
-+ [-lncurses])])
-+
- AC_CONFIG_FILES([config.make ${makefiles}])
- AC_OUTPUT
-
---
-2.1.4
-