diff options
Diffstat (limited to 'debian/patches/bootshell0007-XXX-bootshell.patch')
-rw-r--r-- | debian/patches/bootshell0007-XXX-bootshell.patch | 4500 |
1 files changed, 0 insertions, 4500 deletions
diff --git a/debian/patches/bootshell0007-XXX-bootshell.patch b/debian/patches/bootshell0007-XXX-bootshell.patch deleted file mode 100644 index b3e78a2a..00000000 --- a/debian/patches/bootshell0007-XXX-bootshell.patch +++ /dev/null @@ -1,4500 +0,0 @@ -From aba884a4ee96aa2e7a0383490bfd539210b040c5 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 07/11] XXX bootshell - -XXX hack in toplevel Makefile. ---- - Makefile | 1 + - bootshell/Makefile | 73 +++ - bootshell/boot.scm | 214 ++++++++ - bootshell/bootshell.h | 49 ++ - bootshell/bootstrap.scm | 306 ++++++++++++ - bootshell/elf-exec.c | 211 ++++++++ - bootshell/exceptions.c | 92 ++++ - bootshell/exec-startup.c | 182 +++++++ - bootshell/ffi.c | 1215 +++++++++++++++++++++++++++++++++++++++++++++ - bootshell/ffi.h | 170 +++++++ - bootshell/frob-task.c | 131 +++++ - bootshell/fs.c | 111 +++++ - bootshell/fsys.c | 164 ++++++ - bootshell/fsys.h | 28 ++ - bootshell/hurd.scm | 122 +++++ - bootshell/mach.scm | 93 ++++ - bootshell/main.c | 267 ++++++++++ - bootshell/mig-decls.h | 22 + - bootshell/mig-mutate.h | 27 + - bootshell/runsystem.scm | 78 +++ - bootshell/scheme-config.h | 31 ++ - bootshell/startup.c | 508 +++++++++++++++++++ - bootshell/startup.h | 36 ++ - bootshell/utils.c | 118 +++++ - config.make.in | 4 + - configure.ac | 15 + - 26 files changed, 4268 insertions(+) - create mode 100644 bootshell/Makefile - create mode 100644 bootshell/boot.scm - create mode 100644 bootshell/bootshell.h - create mode 100644 bootshell/bootstrap.scm - 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/frob-task.c - create mode 100644 bootshell/fs.c - create mode 100644 bootshell/fsys.c - create mode 100644 bootshell/fsys.h - create mode 100644 bootshell/hurd.scm - create mode 100644 bootshell/mach.scm - 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 6544cd2..00d64ff 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..e2b09e2 ---- /dev/null -+++ b/bootshell/Makefile -@@ -0,0 +1,73 @@ -+# 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 \ -+ mach.scm \ -+ hurd.scm \ -+ boot.scm \ -+ bootstrap.scm \ -+ runsystem.scm \ -+ -+SRCS := \ -+ scheme.c \ -+ main.c \ -+ exceptions.c \ -+ fs.c \ -+ fsys.c \ -+ exec-startup.c \ -+ startup.c \ -+ utils.c \ -+ ffi.c \ -+ hurd.c \ -+ elf-exec.c \ -+ frob-task.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..75cc75f ---- /dev/null -+++ b/bootshell/boot.scm -@@ -0,0 +1,214 @@ -+;; 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)) -+ (let ((args' (open-output-string))) -+ (write (cons (string->symbol name) args) args') -+ (throw (string-append -+ (get-output-string args') ": " (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)) -+ -+;; XXX -+(define (path->string x) -+ (if (string? x) x (symbol->string x))) -+ -+;; Hurd server bootstrap. -+ -+;; 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. -+")) -+ -+;; 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")) -+ -+;; 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)))) -+ -+;; We store our messages so that we can replay them if we start the -+;; Hurd console which erases the screen. -+(define messages '()) -+(define (log . args) -+ (set! messages (append messages args)) -+ (for-each display args)) -+(define (replay-log) -+ (for-each display messages)) -+ -+(define timeout 1000) ; 1 second -+ -+(define (pause) -+ (if (= 1 boot-pause) (prompt "Press enter to continue..."))) -+ -+;; We're ready. -+(echo version ".") -diff --git a/bootshell/bootshell.h b/bootshell/bootshell.h -new file mode 100644 -index 0000000..fd91ce9 ---- /dev/null -+++ b/bootshell/bootshell.h -@@ -0,0 +1,49 @@ -+/* 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 char **global_argv; -+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/bootstrap.scm b/bootshell/bootstrap.scm -new file mode 100644 -index 0000000..a521e01 ---- /dev/null -+++ b/bootshell/bootstrap.scm -@@ -0,0 +1,306 @@ -+;; 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/>. */ -+ -+;; -+;; The Hurd server bootstrap. -+;; -+ -+(define (run-stage stage) -+ (stage)) -+ -+(define (bootstrap stages) -+ (catch (panic "Hurd bootstrap failed: " (car last-exception) "\n") -+ (log "Hurd server bootstrap: ") -+ (for-each run-stage stages) -+ (log "done.\n")) -+ -+ (shell -+ (lambda (prefix) -+ (prompt-append-prefix -+ (string-append "runsystem@" (hostname) " " (getcwd) " ") prefix)))) -+ -+;; -+;; The stages of the Hurd server bootstrap. -+;; -+ -+(define rootfs-control MACH_PORT_NULL) -+(define console-device "/dev/console") -+ -+(define (first-stage rootfs-device) -+ (set! exec-server-task (task-create mach-task-self 0)) -+ (let -+ ((rootfs-args -+ `("rootfs" -+ ,(make-arg "host-priv-port" rootfs-server-task host-priv) -+ ,(make-arg "device-master-port" rootfs-server-task device-master) -+ ,(make-arg "exec-server-task" rootfs-server-task exec-server-task) -+ "-T" "typed" ,rootfs-device))) -+ (log "rootfs ") -+ (set! rootfs-control (bind-root (resume-translator rootfs-server-task -+ rootfs-args))) -+ (log "/servers/exec ") -+ (task-set-name exec-server-task "/hurd/exec") -+ (task-suspend exec-server-task) -+ (elf-exec exec-server-task -+ `("/lib/ld.so.1" "/hurd/exec" -+ ,(make-arg "device-master-port" exec-server-task device-master))) -+ (bind "/servers/exec" (resume-translator exec-server-task '())))) -+ -+(define (early-startup) -+ (let ((startup-control (mach-port-allocate mach-task-self -+ MACH_PORT_RIGHT_RECEIVE))) -+ (start-handling-early-startup startup-control) -+ (set-active-translator "/servers/startup" 0 0 -+ (make-send-right startup-control)))) -+ -+(define (second-stage) -+ (letport -+ ((proc-task (task-create mach-task-self 0)) -+ (auth-task (task-create mach-task-self 0))) -+ -+ ;; 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")))) -+ ;; Projections for the cookies returned by bootstrap-*. -+ (:reply car) (:replyPoly cadr) (:server caddr)) -+ (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)) -+ -+ ;; Neither the kernel nor our bootscript task have command line -+ ;; arguments. Fix that. -+ (frob-task (proc->pid->task (:server pc) 3) -+ '(gnumach huhu lala XXX)) -+ (if (mach-port-valid? bootscript-task) -+ (frob-task bootscript-task '(/hurd/runsystem.scm))) -+ (frob-task mach-task-self '(/hurd/bootshell)) -+ -+ (mach-port-deallocate mach-task-self (:server pc)) -+ (mach-port-deallocate mach-task-self (:server ac))))) -+ -+(define (start-hurd-console) -+ (log "hurd-console ") -+ (throw 'notyet) ;; XXX -+ (run '(/bin/console -+ --driver-path=/usr/lib/hurd/console ;; XXX -+ --driver=current_vcs -+ --driver=vga -+ --driver=pc_kbd --keymap us -+ --driver=pc_mouse --protocol=ps/2 -+ /dev/vcs)) -+ -+ ;; XXX -+ ;(symlink 'tty1 '/dev/console) -+ (set! console-device "/dev/tty1")) -+ -+(define (start-mach-console) -+ (start-active-translator '/dev/console -+ '(/hurd/term /dev/console device console))) -+ -+(define (start-terminal) -+ (catch (begin (log "failed: ") -+ (log last-exception) -+ (start-mach-console)) -+ (start-hurd-console)) -+ -+ (letport ((term (file-name-lookup console-device O_RDWR 0))) -+ (bind-term term)) -+ -+ (if (equal? console-device "/dev/tty1") -+ ;; If we got the Hurd console running, it erased the screen. -+ (replay-log)) -+ -+ ;; If we made it this far, we can use libreadline! -+ (enable-readline)) -+ -+(define (pflocal) -+ (start-active-translator '/servers/socket/1 '(/hurd/pflocal))) -+ -+(define (mach-defpager) -+ (log "mach-defpager ") -+ (run '(/hurd/mach-defpager)) -+ -+ ;; Wait for it to start. -+ (wait-for have-default-memory-manager? 1000000)) -+ -+(define (rootfs-update) -+ (fsys-set-options rootfs-control '("--update") 0)) -+ -+(define (startup-standalone) -+ ;; The standalone startup server watches essential servers, and -+ ;; handles the system shutdown. -+ (start-active-translator '/servers/startup '(/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))))) -+ -+(define (boot! init) -+ (run-init `(/sbin/console-run --console ,console-device -- ,init -a))) -+ -+;; -+;; Utility functions. -+;; -+ -+;; 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 #o666)) ;; XXX mode 0 should be fine -+ (control (bootstrap-translator prepare-task realnode))) -+ (set-active-translator path 0 0 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 (start-active-translator path args) -+ (log (path->string path) " ") -+ (bind path (start-translator (task-create mach-task-self 0) args))) -+ -+;; Start the userspace init daemon. -+(define (run-init argv) -+ (letport ((proc (getproc)) -+ (task (task-create mach-task-self 0)) -+ (child-proc (proc->task->proc proc task))) -+ (proc->task->set-init-task! proc task) -+ (task-set-name task (car argv)) -+ -+ ;; XXX this is roughly what console-run does -+ ;;(tcsetpgrp 0 (proc->task->pid proc task)) -+ ;;(proc->setsid! child-proc) -+ ;;(proc->make-login-coll! child-proc) -+ -+ (proc->mark-exec! child-proc) -+ (proc->mark-important! child-proc) -+ (proc->task->child! child-proc mach-task-self) -+ (_exec (file-name-lookup (car argv) O_EXEC 0) -+ task argv MACH_PORT_NULL) -+ (copy-send-right task))) -+ -+;; -+;; Legacy support. -+;; -+ -+;; 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)) -+ -+(define (traditional-first-stage) -+ (log "rootfs ") -+ (set! rootfs-control (bind-root (resume-translator rootfs-server-task '()))) -+ (log "/servers/exec ") -+ (bind "/servers/exec" (resume-translator exec-server-task '()))) -+ -+;; XXX fix bootstrap -+(define (traditional-boot) -+ (bootstrap (list traditional-first-stage -+ early-startup -+ second-stage -+ start-terminal -+ startup-standalone -+ (lambda () (boot! "/sbin/init"))))) -diff --git a/bootshell/elf-exec.c b/bootshell/elf-exec.c -new file mode 100644 -index 0000000..a61addb ---- /dev/null -+++ b/bootshell/elf-exec.c -@@ -0,0 +1,211 @@ -+/* 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; -+ err = vm_allocate (task, &stack_start, stack_end - stack_start, FALSE); -+ if (err) -+ return err; -+ -+ 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)); -+ err = vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args, -+ stack_end - trunc_page ((vm_offset_t) arg_pos)); -+ if (err) -+ return err; -+ munmap ((caddr_t) args, -+ stack_end - trunc_page ((vm_offset_t) arg_pos)); -+ -+ err = thread_create (task, &thread); -+ if (err) -+ return err; -+ -+#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) ®s, ®_size); -+ regs.eip = (int) startpc; -+ regs.uesp = (int) arg_pos; -+ err = thread_set_state (thread, i386_THREAD_STATE, -+ (thread_state_t) ®s, reg_size); -+ if (err) -+ return err; -+ } -+#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); -+ if (argv == NULL) -+ return ENOMEM; -+ 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..3b3088a ---- /dev/null -+++ b/bootshell/ffi.c -@@ -0,0 +1,1215 @@ -+/* 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 "fsys.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; -+} -+ -+ -+pointer -+do_logand (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("logand"); -+ unsigned int acc = ~0; -+ while (args != sc->NIL) -+ { -+ SC_ARG (sc, unsigned int, v, number, args); -+ acc &= v; -+ } -+ SC_RETURN_INT (sc, acc); -+} -+ -+pointer -+do_logior (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("logior"); -+ unsigned int acc = 0; -+ while (args != sc->NIL) -+ { -+ SC_ARG (sc, unsigned int, v, number, args); -+ acc |= v; -+ } -+ SC_RETURN_INT (sc, acc); -+} -+ -+pointer -+do_logxor (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("logxor"); -+ unsigned int acc = 0; -+ while (args != sc->NIL) -+ { -+ SC_ARG (sc, unsigned int, v, number, args); -+ acc ^= v; -+ } -+ SC_RETURN_INT (sc, acc); -+} -+ -+pointer -+do_lognot (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("lognot"); -+ SC_ARG (sc, unsigned int, v, number, args); -+ SC_ARGS_DONE (sc); -+ SC_RETURN_INT (sc, ~v); -+} -+ -+ -+ -+ -+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_task_set_name (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("task-terminate"); -+ SC_ARG (sc, task_t, task, number, args); -+ SC_ARG (sc, char *, name, path, args); -+ SC_ARGS_DONE (sc); -+ err = task_set_name (task, name); -+ SC_RETURN (sc); -+} -+ -+pointer -+do_vm_set_default_memory_manager (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("task-terminate"); -+ SC_ARG (sc, mach_port_t, host_priv, number, args); -+ SC_ARG (sc, mach_port_t, defpager, number, args); -+ SC_ARGS_DONE (sc); -+ err = vm_set_default_memory_manager (host_priv, &defpager); -+ SC_RETURN_INT (sc, defpager); -+} -+ -+ -+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, path, 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, path, 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); -+ char *cwd = get_current_dir_name (); -+ if (cwd == NULL) -+ SC_RETURN_ERR (sc, errno); -+ SC_RETURN_STRING (sc, cwd); -+} -+ -+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, path, 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); -+ /* XXX intarray */ -+ _hurd_init (0, global_argv, 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. */ -+ err = mach_port_mod_refs (mach_task_self (), -+ procserver, MACH_PORT_RIGHT_SEND, +1); -+ assert_perror (err); -+ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver); -+ -+ /* When we called _hurd_init, the proc server wasn't around. */ -+ _hurd_new_proc_init (global_argv, NULL, 0); /* XXX intarray */ -+ 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_pid2task (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("proc-pid2task"); -+ SC_ARG (sc, mach_port_t, proc, number, args); -+ SC_ARG (sc, pid_t, pid, number, args); -+ SC_ARGS_DONE (sc); -+ task_t task; -+ err = proc_pid2task (proc, pid, &task); -+ SC_RETURN_INT (sc, task); -+} -+ -+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_proc_make_login_coll (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("proc->make-login-coll!"); -+ SC_ARG (sc, process_t, proc, number, args); -+ SC_ARGS_DONE (sc); -+ err = proc_make_login_coll (proc); -+ SC_RETURN (sc); -+} -+ -+pointer -+do_proc_setsid (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("proc->setsid!"); -+ SC_ARG (sc, process_t, proc, number, args); -+ SC_ARGS_DONE (sc); -+ err = proc_setsid (proc); -+ SC_RETURN (sc); -+} -+ -+pointer -+do_tcsetpgrp (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("tcsetpgrp"); -+ SC_ARG (sc, int, fd, number, args); -+ SC_ARG (sc, pid_t, pgrp, number, args); -+ SC_ARGS_DONE (sc); -+ tcsetpgrp (fd, pgrp); -+ 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) -+{ -+ for (; sc->vptr->is_pair (list); list = sc->vptr->pair_cdr (list)) -+ { -+ char *v; -+ if (sc->vptr->is_string (sc->vptr->pair_car (list))) -+ v = sc->vptr->string_value (sc->vptr->pair_car (list)); -+ else if (sc->vptr->is_symbol (sc->vptr->pair_car (list))) -+ v = sc->vptr->symname (sc->vptr->pair_car (list)); -+ else -+ continue; // XXX this just silently drops values -+ argz_add (argz, argz_len, v); -+ } -+} -+ -+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, pointer, arguments, list, args); -+ char *argz = NULL; -+ size_t argz_len = 0; -+ ffi_list2argz (sc, &argz, &argz_len, arguments); -+ 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); -+} -+ -+// 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); -+ -+ /* bitwise arithmetic */ -+ define_function (sc, "logand", logand); -+ define_function (sc, "logior", logior); -+ define_function (sc, "logxor", logxor); -+ define_function (sc, "lognot", lognot); -+ -+ /* Mach stuff. */ -+ 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-set-name", task_set_name); -+ 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); -+ -+ define_function (sc, "vm-set-default-memory-manager", -+ vm_set_default_memory_manager); -+ -+ /* 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 fsys protocol. */ -+ define_function (sc, "fsys-set-options", fsys_set_options); -+ define_function (sc, "fsys-get-options", fsys_get_options); -+ -+ /* 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->pid->task", proc_pid2task); -+ 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); -+ define_function (sc, "proc->make-login-coll!", proc_make_login_coll); -+ define_function (sc, "proc->setsid!", proc_setsid); -+ -+ /* Terminal magic. */ -+ define_function (sc, "tcsetpgrp", tcsetpgrp); -+ -+ /* Hurd hacks. */ -+ define_function (sc, "frob-task", frob_task); -+ 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..f5d0ac6 ---- /dev/null -+++ b/bootshell/ffi.h -@@ -0,0 +1,170 @@ -+/* 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(SC, X) ivalue -+#define CONVERSION_string(SC, X) string_value -+#define CONVERSION_list(SC, X) -+#define CONVERSION_path(SC, X) ((SC)->vptr->is_string (X) \ -+ ? (SC)->vptr->string_value \ -+ : (SC)->vptr->symname) -+ -+#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) -+#define IS_A_path(SC, X) ((SC)->vptr->is_string (X) \ -+ || (SC)->vptr->is_symbol (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 (SC, pair_car (ARGS)) (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 *, 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, #X); \ -+ if ((S)->retcode != 0) \ -+ fprintf (stderr, "Errors encountered evaluating %s\n", #X); \ -+ }) -+ -+declare_embedded_script (init); -+declare_embedded_script (mach); -+declare_embedded_script (hurd); -+declare_embedded_script (boot); -+declare_embedded_script (bootstrap); -+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); -+ -+/* frob_task.c */ -+pointer do_frob_task (scheme *sc, pointer args); -+ -+#endif /* _HURD_BOOTSHELL_FFI_H */ -diff --git a/bootshell/frob-task.c b/bootshell/frob-task.c -new file mode 100644 -index 0000000..05d0238 ---- /dev/null -+++ b/bootshell/frob-task.c -@@ -0,0 +1,131 @@ -+/* Supply a task (e.g. the kernel) with the command line arguments. -+ -+ 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 <errno.h> -+#include <error.h> -+#include <hurd.h> -+#include <mach.h> -+#include <pids.h> -+#include <string.h> -+#include <sys/mman.h> -+#include <sys/types.h> -+#include <unistd.h> -+ -+#include "ffi.h" -+ -+/* Frobnicate the given TASK and the proc server's idea of it, so the -+ command line can be read as for a normal Hurd process. */ -+error_t -+frob_task (task_t kernel_task, const char *argz, size_t argz_len) -+{ -+ error_t err; -+ process_t proc, kernel_proc = MACH_PORT_NULL; -+ -+ int argc, i; -+ const char *entry; -+ size_t windowsz; -+ vm_address_t mine, his; -+ -+ proc = getproc (); -+ if (! MACH_PORT_VALID (proc)) -+ return EINVAL; -+ -+ err = proc_task2proc (proc, kernel_task, &kernel_proc); -+ if (err) -+ goto out; -+ -+ /* Mark the kernel task as an essential task so that we or the proc server -+ never want to task_terminate it. */ -+ err = proc_mark_important (kernel_proc); -+ if (err) -+ goto out; -+ -+ /* Our arguments make up the multiboot command line used to boot the -+ kernel. We'll write into the kernel task a page containing a -+ canonical argv array and argz of those words. */ -+ -+ argc = argz_count (argz, argz_len); -+ -+ windowsz = round_page (((argc + 1) * sizeof (char *)) + argz_len); -+ -+ mine = (vm_address_t) mmap (0, windowsz, PROT_READ|PROT_WRITE, -+ MAP_ANON, 0, 0); -+ if (mine == (vm_address_t) -1) -+ { -+ err = errno; -+ goto out; -+ } -+ -+ err = vm_allocate (kernel_task, &his, windowsz, 1); -+ if (err) -+ { -+ error (0, err, "cannot allocate %Zu bytes in kernel task", windowsz); -+ munmap ((caddr_t) mine, windowsz); -+ goto out; -+ } -+ -+ for (i = 0, entry = argz; entry != NULL; -+ ++i, entry = argz_next (argz, argz_len, entry)) -+ ((char **) mine)[i] = ((char *) &((char **) his)[argc + 1] -+ + (entry - argz)); -+ ((char **) mine)[argc] = NULL; -+ memcpy (&((char **) mine)[argc + 1], argz, argz_len); -+ -+ /* We have the data all set up in our copy, now just write it over. */ -+ err = vm_write (kernel_task, his, mine, windowsz); -+ munmap ((caddr_t) mine, windowsz); -+ if (err) -+ goto out; -+ -+ /* The argument vector is set up in the kernel task at address HIS. -+ Finally, we can inform the proc server where to find it. */ -+ err = proc_set_arg_locations (kernel_proc, -+ his, his + (argc * sizeof (char *))); -+ if (err) -+ error (0, err, "proc_set_arg_locations for kernel task"); -+ -+ out: -+ { -+ error_t e; -+ e = mach_port_deallocate (mach_task_self (), proc); -+ assert_perror (e); -+ -+ if (MACH_PORT_VALID (kernel_proc)) -+ e = mach_port_deallocate (mach_task_self (), kernel_proc); -+ assert_perror (e); -+ } -+ return err; -+} -+ -+pointer -+do_frob_task (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("frob-task"); -+ 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 = frob_task (task, argz, argz_len); -+ free (argz); -+ SC_RETURN (sc); -+} -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..5383e7f ---- /dev/null -+++ b/bootshell/fsys.c -@@ -0,0 +1,164 @@ -+/* 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 <errno.h> -+#include <error.h> -+#include <hurd.h> -+#include <mach.h> -+#include <mach/message.h> -+#include <mach/mig_support.h> -+#include <stdio.h> -+ -+/* fsys client support. */ -+#include <hurd.h> -+#include <hurd/fsys.h> -+ -+#include "ffi.h" -+ -+pointer -+do_fsys_set_options (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("fsys-set-options"); -+ SC_ARG (sc, fsys_t, control, number, args); -+ char *options = NULL; -+ size_t options_len = 0; -+ SC_ARG (sc, pointer, arguments, list, args); -+ ffi_list2argz (sc, &options, &options_len, arguments); -+ SC_ARG (sc, int, do_children, number, args); -+ SC_ARGS_DONE (sc); -+ err = fsys_set_options (control, options, options_len, do_children); -+ SC_RETURN (sc); -+} -+ -+pointer -+do_fsys_get_options (scheme *sc, pointer args) -+{ -+ SC_FFI_PROLOG ("fsys_get_options"); -+ SC_ARG (sc, fsys_t, control, number, args); -+ SC_ARGS_DONE (sc); -+ char *options = NULL; -+ size_t options_len = 0; -+ pointer result; -+ err = fsys_get_options (control, &options, &options_len); -+ if (err) -+ SC_RETURN (sc); -+ result = ffi_argz2list (sc, options, options_len, NULL); -+ vm_deallocate (mach_task_self (), (vm_address_t) options, options_len); -+ SC_RETURN_POINTER (sc, result); -+} -+ -+/* Partial fsys server support. */ -+// 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 = MACH_PORT_NULL; -+ err = service_fsys_request (bootstrap, -+ realnode, -+ realnodePoly, -+ timeout, -+ &control); -+ SC_RETURN_INT (sc, control); -+} -diff --git a/bootshell/fsys.h b/bootshell/fsys.h -new file mode 100644 -index 0000000..d6f2ea7 ---- /dev/null -+++ b/bootshell/fsys.h -@@ -0,0 +1,28 @@ -+/* 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/>. */ -+ -+#ifndef _HURD_BOOTSHELL_FSYS_H -+#define _HURD_BOOTSHELL_FSYS_H -+ -+#include "ffi.h" -+ -+pointer do_fsys_set_options (scheme *sc, pointer args); -+pointer do_fsys_get_options (scheme *sc, pointer args); -+ -+#endif /* _HURD_BOOTSHELL_FSYS_H */ -diff --git a/bootshell/hurd.scm b/bootshell/hurd.scm -new file mode 100644 -index 0000000..46cbfe3 ---- /dev/null -+++ b/bootshell/hurd.scm -@@ -0,0 +1,122 @@ -+;; The Hurd 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/>. */ -+ -+(define (touch path) -+ (letport ((p (file-name-lookup path O_CREAT #o666))))) ;; XXX mode ? -+ -+(define (chown path owner) #f) ;;XXX -+ -+(define (st path owner mode translator . args) -+ (if (not (null? args)) -+ (for-each display args)) -+ (set-passive-translator path O_CREAT mode translator) -+ (chown path owner)) -+ -+(define (tty n) -+ (let ((path (string-append "/dev/tty" (number->string n)))) -+ (st path 'root #o600 -+ `(/hurd/term -+ ,path hurdio -+ ,(string-append "/dev/vcs/" (number->string n) "/console"))))) -+ -+(define (have-default-memory-manager?) -+ (letport ((p (vm-set-default-memory-manager host-priv -+ MACH_PORT_NULL))) -+ (mach-port-valid? p))) -+ -+ -+(define (path->string x) -+ (if (string? x) x (symbol->string x))) -+ -+(define (start-active-translator path args) -+ (log (path->string path) " ") -+ (bind path (start-translator (task-create mach-task-self 0) args))) -+ -+(define (make-essential-devices) -+ (log "mach-defpager ") -+ (run '(/hurd/mach-defpager)) -+ -+ (start-active-translator '/proc '(/hurd/procfs --compatible)) -+ (start-active-translator '/servers/socket/1 '(/hurd/pflocal)) -+ (start-active-translator '/servers/password '(/hurd/password)) -+ -+ ;; We need the default pager before starting proxy-defpager. -+ (wait-for have-default-memory-manager? 1000000) -+ -+ (start-active-translator '/servers/default-pager '(/hurd/proxy-defpager)) -+ (start-active-translator '/dev '(/hurd/tmpfs 5M)) -+ (start-active-translator '/run '(/hurd/tmpfs 15M)) -+ (start-active-translator '/root '(/hurd/tmpfs 5M)) -+ (start-active-translator '/tmp '(/hurd/tmpfs 15M)) -+ (start-active-translator '/home '(/hurd/tmpfs 20%)) ;; XXX 20% -+ -+ (st '/dev/time 'root #o644 '(/hurd/storeio --no-cache time)) -+ (st '/dev/mem 'root #o660 '(/hurd/storeio --no-cache mem)) -+ (st '/dev/vcs 'root #o600 '(/hurd/console)) -+ (touch '/dev/console) -+ -+ (map tty '(1 2 3 4 5 6)) -+ -+ (st '/dev/fd 'root #o666 '(/hurd/magic --directory fd)) -+ (symlink 'fd/0 '/dev/stdin) -+ (symlink 'fd/1 '/dev/stdout) -+ (symlink 'fd/2 '/dev/stderr)) -+ -+(define (symlink target linkpath) -+ (st linkpath 'root #o644 `(/hurd/symlink ,target))) -+ -+(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) -+ (catch (reboot-mach) -+ (reboot-hurd))) -+(define (halt) -+ (catch (halt-mach) -+ (halt-hurd))) -+ -+(define ESUCCESS 0) ; -+ -+;; translator linkage -+ -+(define (set-passive-translator path flags mode args) -+ (letport ((node (file-name-lookup path (logior O_NOTRANS flags) mode))) -+ (file-set-translator node FS_TRANS_SET 0 0 args -+ MACH_PORT_NULL MACH_MSG_TYPE_COPY_SEND))) -+ -+(define (set-active-translator path flags mode active-control) -+ (letport ((node (file-name-lookup path (logior O_NOTRANS flags) mode))) -+ (file-set-translator node 0 FS_TRANS_SET 0 '() -+ active-control MACH_MSG_TYPE_COPY_SEND))) -+(define (run argv) -+ (letport ((proc (getproc)) -+ (task (task-create mach-task-self 0)) -+ (child-proc (proc->task->proc proc task))) -+ (task-set-name task (car argv)) -+ (_exec (file-name-lookup (car argv) O_EXEC 0) -+ task argv MACH_PORT_NULL) -+ (proc->mark-exec! child-proc) -+ (proc->mark-important! child-proc) -+ (proc->task->child! proc task) -+ (copy-send-right task))) -diff --git a/bootshell/mach.scm b/bootshell/mach.scm -new file mode 100644 -index 0000000..3dd98ac ---- /dev/null -+++ b/bootshell/mach.scm -@@ -0,0 +1,93 @@ -+;; The Mach 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/>. */ -+ -+;; 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 ...)))) -+ -+;; 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)) -+ -+;; Mach task interface. -+(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)) -+ -+;; Mach host interface. -+(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)) -+ -+;; Default memory manager interface. -+(define (have-default-memory-manager?) -+ (letport ((p (vm-set-default-memory-manager host-priv -+ MACH_PORT_NULL))) -+ (mach-port-valid? p))) -+ -+;; 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))) -+ -diff --git a/bootshell/main.c b/bootshell/main.c -new file mode 100644 -index 0000000..54685a7 ---- /dev/null -+++ b/bootshell/main.c -@@ -0,0 +1,267 @@ -+/* 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); -+ global_argv = argv; /* For calling _hurd_new_proc_init later. */ -+ -+ { -+ 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, mach); -+ load_embedded_script (&scm, hurd); -+ load_embedded_script (&scm, boot); -+ load_embedded_script (&scm, bootstrap); -+ 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, "external bootscript"); -+ 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..86b8c16 ---- /dev/null -+++ b/bootshell/runsystem.scm -@@ -0,0 +1,78 @@ -+;; 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 (string-index haystack delimiter) -+ (define (index i haystack delimiter) -+ (if (= (length haystack) 0) -+ #f -+ (if (char=? (car haystack) delimiter) -+ i -+ (index (+ i 1) (cdr haystack) delimiter)))) -+ (index 0 (string->list haystack) delimiter)) -+ -+(define (string-splitn haystack delimiter n) -+ (define (split acc haystack delimiter n) -+ (if (= (string-length haystack) 0) -+ (reverse acc) -+ (let ((i (string-index haystack delimiter))) -+ (if (not (or (eq? i #f) (= 0 n))) -+ (split (cons (substring haystack 0 i) acc) -+ (substring haystack (+ i 1) (string-length haystack)) -+ delimiter (- n 1)) -+ (split (cons haystack acc) "" delimiter 0) -+ )))) -+ (split '() haystack delimiter n)) -+ -+(define (string-split haystack delimiter) -+ (string-splitn haystack delimiter -1)) -+ -+(define (parse-cmdline c) -+ (define (parse args kwargs l) -+ (if (= (length l) 0) -+ (cons (reverse args) kwargs) -+ (let ((kv (string-splitn (car l) #\= 1))) -+ (if (= (length kv) 1) -+ (parse (cons (car kv) args) kwargs (cdr l)) -+ (parse args (cons (cons (car kv) (cadr kv)) kwargs) (cdr l)))))) -+ (parse '() '() (string-split c #\ ))) -+ -+(define (boot) -+ (let* ((arguments (parse-cmdline multiboot-command-line)) -+ (:flag (lambda (key) (member key (car arguments)))) -+ (:kwarg (lambda (key default) -+ (let ((value (assoc key (cdr arguments)))) -+ (if (equal? value #f) -+ (default) -+ (cdr value))))) -+ (init (:kwarg "init" (lambda () "/sbin/init")))) -+ -+ (bootstrap (list -+ (lambda () (first-stage (:kwarg "root" (lambda () "xxx")))) -+ early-startup -+ second-stage -+ start-terminal -+ startup-standalone -+ pflocal -+ mach-defpager -+ rootfs-update -+ ;(lambda () (boot! init)) -+ (lambda () -+ (run '(/sbin/console-run --console=/dev/console -- /bin/bash)) -+ (sleep 60)) -+ )))) -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 (®istered_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 124eb07..819b264 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -341,6 +341,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 - |