commit-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[hurd] 01/05: New upstream snapshot


From: Samuel Thibault
Subject: [hurd] 01/05: New upstream snapshot
Date: Wed, 16 Nov 2016 08:30:24 +0000

This is an automated email from the git hooks/post-receive script.

sthibault pushed a commit to branch master
in repository hurd.

commit dd66fe0952d00192e7750a2b8665dca95a5ac0ad
Author: Samuel Thibault <address@hidden>
Date:   Tue Nov 15 20:12:16 2016 +0000

    New upstream snapshot
---
 Makefile                              |   4 +-
 NEWS                                  |   8 +
 boot/Makefile                         |  30 +-
 boot/boot.c                           | 702 ++++++++++++++++++++--------------
 boot/frank1.ld                        |  94 -----
 boot/frankemul.ld                     | 107 ------
 boot/mach-crt0.c                      | 158 --------
 proc/mig-mutate.h => boot/mig-decls.h |  24 +-
 {proc => boot}/mig-mutate.h           |  22 +-
 boot/sigvec.S                         |  23 --
 boot/syscall.S                        |  35 --
 boot/userland-boot.c                  | 226 ++++++++++-
 boot/ux.c                             | 303 ---------------
 boot/ux.h                             | 114 ------
 console/display.c                     |  15 +
 eth-multiplexer/ChangeLog             |  18 +-
 eth-multiplexer/Makefile              |   4 +-
 eth-multiplexer/README                |   2 +-
 eth-multiplexer/demuxer.c             |   2 +-
 eth-multiplexer/dev_stat.c            |  18 +-
 eth-multiplexer/device_impl.c         |  18 +-
 eth-multiplexer/ethernet.c            |  47 ++-
 eth-multiplexer/ethernet.h            |   6 +-
 eth-multiplexer/multiplexer.c         |   6 +-
 eth-multiplexer/netfs_impl.c          |   8 +-
 eth-multiplexer/netfs_impl.h          |   2 +-
 eth-multiplexer/notify_impl.c         |   2 +-
 eth-multiplexer/test.c                |   2 +-
 eth-multiplexer/util.h                |  16 +-
 eth-multiplexer/vdev.c                |  30 +-
 eth-multiplexer/vdev.h                |   5 +
 ext2fs/ext2fs.c                       |   3 +
 ext2fs/ext2fs.h                       |   4 +-
 libbpf/Makefile                       |   4 +-
 libbpf/bpf_impl.c                     |  32 +-
 libbpf/bpf_impl.h                     |  22 +-
 libbpf/queue.c                        |  12 +-
 libbpf/util.h                         |   8 +-
 libdiskfs/Makefile                    |   4 +-
 libdiskfs/file-utimes.c               |   3 +
 libdiskfs/io-stubs.c                  |   8 +-
 libdiskfs/node-lastref.c              |  49 +++
 libdiskfs/node-nput.c                 |  24 +-
 libdiskfs/node-nrele.c                |  12 +-
 libdiskfs/priv.h                      |   4 +
 libnetfs/fsstubs.c                    |   6 +-
 libnetfs/fsysstubs.c                  |  10 +-
 libnetfs/iostubs.c                    |  20 +-
 libpager/data-unlock.c                |   2 +-
 libpager/stubs.c                      |   6 +-
 libtreefs/xinl.c                      |   2 +
 libtrivfs/fsys-stubs.c                |   8 +-
 libtrivfs/io-stubs.c                  |  18 +-
 mach-defpager/main.c                  |   4 +-
 proc/mgt.c                            |  12 +-
 proc/mig-mutate.h                     |   9 +
 startup/startup.c                     |  22 +-
 utils/rpctrace.c                      |   2 +-
 58 files changed, 974 insertions(+), 1387 deletions(-)

diff --git a/Makefile b/Makefile
index d48baaa..a9ad3f6 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,8 @@ include ./Makeconf
 lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
              libpager libfshelp libdiskfs libtrivfs libps \
              libnetfs libpipe libstore libhurdbugaddr libftpconn libcons \
-             libhurd-slab
+             libhurd-slab \
+             libbpf \
 
 # Hurd programs
 prog-subdirs = auth proc exec term \
@@ -44,6 +45,7 @@ prog-subdirs = auth proc exec term \
               startup \
               init \
               devnode \
+              eth-multiplexer \
 
 ifeq ($(HAVE_SUN_RPC),yes)
 prog-subdirs += nfs nfsd
diff --git a/NEWS b/NEWS
index e9c4cb5..d84ae33 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+Version 0.9 (2016-11-XX)
+
+The 'boot' program can now be run as unprivileged user, allowing any
+user to create unprivileged Subhurds.
+
+The Berkeley Packet Filter library and the ethernet multiplexer have
+been merged into this repository.
+
 Version 0.8 (2016-05-18)
 
 The netfs library is using the lockless reference-counting primitives
diff --git a/boot/Makefile b/boot/Makefile
index c877295..ac40044 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -22,31 +22,13 @@ SRCS = mach-crt0.c boot.c ux.c sigvec.S syscall.S \
        boot_script.c userland-boot.c
 COMMON-OBJS = notifyServer.o deviceServer.o \
        ioServer.o io_replyUser.o device_replyUser.o \
-       termServer.o bootstrapServer.o boot_script.o userland-boot.o
-OBJS = boot.o $(COMMON-OBJS)
-UX-OBJS = mach-crt0.o uxboot.o sigvec.o syscall.o ux.o $(COMMON-OBJS)
+       termServer.o boot_script.o userland-boot.o
+MIGSTUBS = machServer.o mach_hostServer.o gnumachServer.o task_notifyServer.o
+OBJS = boot.o $(COMMON-OBJS) $(MIGSTUBS)
 target = boot
-io-MIGSFLAGS=-DREPLY_PORTS
-HURDLIBS = store shouldbeinlibc
+MIGSFLAGS=-imacros $(srcdir)/mig-mutate.h -DHURD_DEFAULT_PAYLOAD_TO_PORT=1
+io-MIGSFLAGS=-DREPLY_PORTS -DHURD_DEFAULT_PAYLOAD_TO_PORT=1
+HURDLIBS = store shouldbeinlibc ihash
 LDLIBS += -lpthread
 
 include ../Makeconf
-
-#install: /usr/local/bin/uxboot
-#
-#/usr/local/bin/uxboot: uxboot
-#      cp $< $@
-
-MIGSFLAGS = -DHURD_DEFAULT_PAYLOAD_TO_PORT=1
-
-all: boot # uxboot
-
-uxboot.o: boot.c
-       $(COMPILE.c) -DUX $< -o $@
-
-uxboot.0: $(UX-OBJS)
-       $(LINK.o) -o $@ -static -nostartfiles -Wl,-T -Wl,$(srcdir)/frank1.ld $^
-uxboot.1: frankemul.ld uxboot.0
-       $(LD) -o $@ -T $^
-uxboot: uxboot.1
-       -$(OBJCOPY) -S --remove-section=.comment -O a.out-mach3 $< $@
diff --git a/boot/boot.c b/boot/boot.c
index 02af068..d0e0207 100644
--- a/boot/boot.c
+++ b/boot/boot.c
@@ -1,6 +1,6 @@
 /* Load a task using the single server, and then run it
    as if we were the kernel.
-   Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006
+   Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006,14,16
      Free Software Foundation, Inc.
 
    This file is part of the GNU Hurd.
@@ -24,20 +24,20 @@
 #include <mach.h>
 #include <mach/notify.h>
 #include <device/device.h>
-#include <a.out.h>
 #include <mach/message.h>
 #include <mach/mig_errors.h>
+#include <mach/task_notify.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <pthread.h>
 #include <fcntl.h>
-#include <elf.h>
 #include <mach/mig_support.h>
 #include <mach/default_pager.h>
-#include <mach/machine/vm_param.h> /* For VM_XXX_ADDRESS */
 #include <argp.h>
 #include <hurd/store.h>
+#include <hurd/ihash.h>
+#include <sys/reboot.h>
 #include <sys/mman.h>
 #include <version.h>
 
@@ -49,23 +49,15 @@
 #include "term_S.h"
 #include "bootstrap_S.h"
 /* #include "tioctl_S.h" */
+#include "mach_S.h"
+#include "mach_host_S.h"
+#include "gnumach_S.h"
+#include "task_notify_S.h"
 
 #include "boot_script.h"
 
 #include <hurd/auth.h>
 
-#ifdef UX
-#undef STORE                   /* We can't use libstore when under UX.  */
-#else
-#define STORE
-#endif
-
-#ifdef UX
-
-#include "ux.h"
-
-#else  /* !UX */
-
 #include <unistd.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -76,6 +68,14 @@
 #include <hurd.h>
 #include <assert.h>
 
+/* We support two modes of operation.  Traditionally, Subhurds were
+   privileged, i.e. they had the privileged kernel ports.  This has a
+   few drawbacks.  Privileged subhurds can manipulate all tasks on the
+   system and halt the system.  Nowadays we allow an unprivileged
+   mode.  */
+static int privileged;
+static int want_privileged;
+
 static struct termios orig_tty_state;
 static int isig;
 static char *kernel_command_line;
@@ -105,14 +105,23 @@ restore_termstate ()
 
 #define host_fstat fstat
 typedef struct stat host_stat_t;
-#define host_exit exit
 
-#endif /* UX */
+void __attribute__ ((__noreturn__))
+host_exit (int status)
+{
+  restore_termstate ();
+  exit (status);
+}
 
 mach_port_t privileged_host_port, master_device_port;
+mach_port_t pseudo_privileged_host_port;
 mach_port_t pseudo_master_device_port;
 mach_port_t receive_set;
 mach_port_t pseudo_console, pseudo_root, pseudo_time;
+mach_port_t pseudo_pset;
+task_t pseudo_kernel;
+mach_port_t task_notification_port;
+mach_port_t dead_task_notification_port;
 auth_t authserver;
 
 struct store *root_store;
@@ -145,29 +154,7 @@ void safe_gets (char *buf, int buf_len)
   fgets (buf, buf_len, stdin);
 }
 
-char *useropen_dir;
-
-int
-useropen (const char *name, int flags, int mode)
-{
-  if (useropen_dir)
-    {
-      static int dlen;
-      if (!dlen) dlen = strlen (useropen_dir);
-      {
-       int len = strlen (name);
-       char try[dlen + 1 + len + 1];
-       int fd;
-       memcpy (try, useropen_dir, dlen);
-       try[dlen] = '/';
-       memcpy (&try[dlen + 1], name, len + 1);
-       fd = open (try, flags, mode);
-       if (fd >= 0)
-         return fd;
-      }
-    }
-  return open (name, flags, mode);
-}
+extern char *useropen_dir;
 
 /* XXX: glibc should provide mig_reply_setup but does not.  */
 /* Fill in default response.  */
@@ -210,7 +197,11 @@ boot_demuxer (mach_msg_header_t *inp,
   if ((routine = io_server_routine (inp)) ||
       (routine = device_server_routine (inp)) ||
       (routine = notify_server_routine (inp)) ||
-      (routine = term_server_routine (inp))
+      (routine = term_server_routine (inp)) ||
+      (routine = mach_server_routine (inp)) ||
+      (routine = mach_host_server_routine (inp)) ||
+      (routine = gnumach_server_routine (inp)) ||
+      (routine = task_notify_server_routine (inp))
       /* (routine = tioctl_server_routine (inp)) */)
     {
       (*routine) (inp, outp);
@@ -220,189 +211,19 @@ boot_demuxer (mach_msg_header_t *inp,
     return FALSE;
 }
 
-vm_address_t
-load_image (task_t t,
-           char *file)
-{
-  int fd;
-  union
-    {
-      struct exec a;
-      Elf32_Ehdr e;
-    } hdr;
-  char msg[] = ": cannot open bootstrap file\n";
-
-  fd = useropen (file, O_RDONLY, 0);
-
-  if (fd == -1)
-    {
-      write (2, file, strlen (file));
-      write (2, msg, sizeof msg - 1);
-      task_terminate (t);
-      host_exit (1);
-    }
-
-  read (fd, &hdr, sizeof hdr);
-  /* File must have magic ELF number.  */
-  if (hdr.e.e_ident[0] == 0177 && hdr.e.e_ident[1] == 'E' &&
-      hdr.e.e_ident[2] == 'L' && hdr.e.e_ident[3] == 'F')
-    {
-      Elf32_Phdr phdrs[hdr.e.e_phnum], *ph;
-      lseek (fd, hdr.e.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;
-
-           vm_allocate (t, (vm_address_t*)&ph->p_vaddr, ph->p_memsz, 0);
-           vm_write (t, ph->p_vaddr, buf, bufsz);
-           munmap ((caddr_t) buf, bufsz);
-           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));
-         }
-      return hdr.e.e_entry;
-    }
-  else
-    {
-      /* a.out */
-      int magic = N_MAGIC (hdr.a);
-      int headercruft;
-      vm_address_t base = 0x10000;
-      int rndamount, amount;
-      vm_address_t bsspagestart, bssstart;
-      char *buf;
-
-      headercruft = sizeof (struct exec) * (magic == ZMAGIC);
-
-      amount = headercruft + hdr.a.a_text + hdr.a.a_data;
-      rndamount = round_page (amount);
-      buf = mmap (0, rndamount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-      lseek (fd, sizeof hdr.a - headercruft, SEEK_SET);
-      read (fd, buf, amount);
-      vm_allocate (t, &base, rndamount, 0);
-      vm_write (t, base, (vm_address_t) buf, rndamount);
-      if (magic != OMAGIC)
-       vm_protect (t, base, trunc_page (headercruft + hdr.a.a_text),
-                   0, VM_PROT_READ | VM_PROT_EXECUTE);
-      munmap ((caddr_t) buf, rndamount);
-
-      bssstart = base + hdr.a.a_text + hdr.a.a_data + headercruft;
-      bsspagestart = round_page (bssstart);
-      vm_allocate (t, &bsspagestart,
-                  hdr.a.a_bss - (bsspagestart - bssstart), 0);
-
-      return hdr.a.a_entry;
-    }
-}
-
-
 void read_reply ();
 void * msg_thread (void *);
 
-/* Callbacks for boot_script.c; see boot_script.h.  */
-int
-boot_script_exec_cmd (void *hook,
-                     mach_port_t task, char *path, int argc,
-                     char **argv, char *strings, int stringlen)
-{
-  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;
-
-  write (2, path, strlen (path));
-  for (i = 1; i < argc; ++i)
-    {
-      write (2, " ", 1);
-      write (2, argv[i], strlen (argv[i]));
-    }
-  write (2, "\r\n", 2);
-
-  startpc = load_image (task, path);
-  arg_len = stringlen + (argc + 2) * sizeof (char *) + sizeof (integer_t);
-  arg_len += 5 * sizeof (int);
-  stack_end = VM_MAX_ADDRESS;
-  stack_start = VM_MAX_ADDRESS - 16 * 1024 * 1024;
-  vm_allocate (task, &stack_start, stack_end - stack_start, FALSE);
-  arg_pos = (void *) ((stack_end - arg_len) & ~(sizeof (natural_t) - 1));
-  args = mmap (0, stack_end - trunc_page ((vm_offset_t) arg_pos),
-              PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-  str_start = ((vm_address_t) arg_pos
-              + (argc + 2) * sizeof (char *) + sizeof (integer_t));
-  p = args + ((vm_address_t) arg_pos & (vm_page_size - 1));
-  *(int *) p = argc;
-  p = (void *) p + sizeof (int);
-  for (i = 0; i < argc; i++)
-    {
-      *(char **) p = argv[i] - strings + (char *) str_start;
-      p = (void *) p + sizeof (char *);
-    }
-  *(char **) p = 0;
-  p = (void *) p + sizeof (char *);
-  *(char **) p = 0;
-  p = (void *) p + sizeof (char *);
-  memcpy (p, strings, stringlen);
-  memset (args, 0, (vm_offset_t)arg_pos & (vm_page_size - 1));
-  vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args,
-           stack_end - trunc_page ((vm_offset_t) arg_pos));
-  munmap ((caddr_t) args,
-         stack_end - trunc_page ((vm_offset_t) arg_pos));
-
-  thread_create (task, &thread);
-#ifdef i386_THREAD_STATE_COUNT
-  {
-    struct i386_thread_state regs;
-    reg_size = i386_THREAD_STATE_COUNT;
-    thread_get_state (thread, i386_THREAD_STATE,
-                     (thread_state_t) &regs, &reg_size);
-    regs.eip = (int) startpc;
-    regs.uesp = (int) arg_pos;
-    thread_set_state (thread, i386_THREAD_STATE,
-                     (thread_state_t) &regs, reg_size);
-  }
-#elif defined(ALPHA_THREAD_STATE_COUNT)
-  {
-    struct alpha_thread_state regs;
-    reg_size = ALPHA_THREAD_STATE_COUNT;
-    thread_get_state (thread, ALPHA_THREAD_STATE,
-                     (thread_state_t) &regs, &reg_size);
-    regs.r30 = (natural_t) arg_pos;
-    regs.pc = (natural_t) startpc;
-    thread_set_state (thread, ALPHA_THREAD_STATE,
-                     (thread_state_t) &regs, reg_size);
-  }
-#else
-# error needs to be ported
-#endif
-
-  thread_resume (thread);
-  mach_port_deallocate (mach_task_self (), thread);
-  return 0;
-}
-
 const char *argp_program_version = STANDARD_HURD_VERSION (boot);
 
+#define OPT_PRIVILEGED -1
+#define OPT_BOOT_SCRIPT        -2
+
 static struct argp_option options[] =
 {
+  { NULL, 0, NULL, 0, "Boot options:" },
+  { "boot-script", OPT_BOOT_SCRIPT, "BOOT-SCRIPT", 0,
+    "boot script to execute" },
   { "boot-root",   'D', "DIR", 0,
     "Root of a directory tree in which to find files specified in BOOT-SCRIPT" 
},
   { "single-user", 's', 0, 0,
@@ -412,32 +233,46 @@ static struct argp_option options[] =
   { "pause" ,      'd', 0, 0,
     "Pause for user confirmation at various times during booting" },
   { "isig",      'I', 0, 0,
-    "Do not disable terminal signals, so you can suspend and interrupt boot."},
-  { "device",     'f', "device_name=device_file", 0,
-    "Specify a device file used by subhurd and its virtual name."},
+    "Do not disable terminal signals, so you can suspend and interrupt boot"},
+  { "device",     'f', "SUBHURD_NAME=DEVICE_FILE", 0,
+    "Pass the given DEVICE_FILE to the Subhurd as device SUBHURD_NAME"},
+  { "privileged", OPT_PRIVILEGED, NULL, 0,
+    "Allow the subhurd to access privileged kernel ports"},
   { 0 }
 };
-static char args_doc[] = "BOOT-SCRIPT";
 static char doc[] = "Boot a second hurd";
 
-struct dev_map 
+
+
+/* Device pass through.  */
+
+struct dev_map
 {
-  char *name;
-  mach_port_t port;
+  char *device_name;   /* The name of the device in the Subhurd.  */
+  char *file_name;     /* The filename outside the Subhurd.  */
   struct dev_map *next;
 };
 
 static struct dev_map *dev_map_head;
 
-static struct dev_map *add_dev_map (char *dev_name, char *dev_file)
+static struct dev_map *
+add_dev_map (const char *dev_name, const char *dev_file)
 {
-  struct dev_map *map = malloc (sizeof (*map));
+  file_t node;
+  struct dev_map *map;
+
+  /* See if we can open the file.  */
+  node = file_name_lookup (dev_file, 0, 0);
+  if (! MACH_PORT_VALID (node))
+    error (1, errno, "%s", dev_file);
+  mach_port_deallocate (mach_task_self (), node);
 
-  assert (map);
-  map->name = dev_name;
-  map->port = file_name_lookup (dev_file, 0, 0);
-  if (map->port == MACH_PORT_NULL)
-    error (1, errno, "file_name_lookup: %s", dev_file);
+  map = malloc (sizeof *map);
+  if (map == NULL)
+    return NULL;
+
+  map->device_name = strdup (dev_name);
+  map->file_name = strdup (dev_file);
   map->next = dev_map_head;
   dev_map_head = map;
   return map;
@@ -449,7 +284,7 @@ static struct dev_map *lookup_dev (char *dev_name)
 
   for (map = dev_map_head; map; map = map->next)
     {
-      if (strcmp (map->name, dev_name) == 0)
+      if (strcmp (map->device_name, dev_name) == 0)
        return map;
     }
   return NULL;
@@ -486,13 +321,17 @@ parse_opt (int key, char *arg, struct argp_state *state)
       add_dev_map (arg, dev_file+1);
       break;
 
-    case ARGP_KEY_ARG:
-      if (state->arg_num == 0)
-       bootscript = arg;
-      else
-       return ARGP_ERR_UNKNOWN;
+    case OPT_PRIVILEGED:
+      want_privileged = 1;
+      break;
+
+    case OPT_BOOT_SCRIPT:
+      bootscript = arg;
       break;
 
+    case ARGP_KEY_ARG:
+      return ARGP_ERR_UNKNOWN;
+
     case ARGP_KEY_INIT:
       state->child_inputs[0] = state->input; break;
 
@@ -502,17 +341,142 @@ parse_opt (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
+static error_t
+allocate_pseudo_ports (void)
+{
+  mach_port_t old;
+
+  /* Allocate a port that we hand out as the privileged host port.  */
+  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+                     &pseudo_privileged_host_port);
+  mach_port_insert_right (mach_task_self (),
+                         pseudo_privileged_host_port,
+                         pseudo_privileged_host_port,
+                         MACH_MSG_TYPE_MAKE_SEND);
+  mach_port_move_member (mach_task_self (), pseudo_privileged_host_port,
+                        receive_set);
+  mach_port_request_notification (mach_task_self (),
+                                  pseudo_privileged_host_port,
+                                 MACH_NOTIFY_NO_SENDERS, 1,
+                                 pseudo_privileged_host_port,
+                                 MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+  assert (old == MACH_PORT_NULL);
+
+  /* Allocate a port that we hand out as the privileged processor set
+     port.  */
+  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+                     &pseudo_pset);
+  mach_port_move_member (mach_task_self (), pseudo_pset,
+                        receive_set);
+  /* Make one send right that we copy when handing it out.  */
+  mach_port_insert_right (mach_task_self (),
+                         pseudo_pset,
+                         pseudo_pset,
+                         MACH_MSG_TYPE_MAKE_SEND);
+
+  /* We will receive new task notifications on this port.  */
+  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+                     &task_notification_port);
+  mach_port_move_member (mach_task_self (), task_notification_port,
+                        receive_set);
+
+  /* And information about dying tasks here.  */
+  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+                     &dead_task_notification_port);
+  mach_port_move_member (mach_task_self (), dead_task_notification_port,
+                        receive_set);
+
+  return 0;
+}
+
+void
+read_boot_script (char **buffer, size_t *length)
+{
+  char *p, *buf;
+  static const char filemsg[] = "Can't open boot script\n";
+  static const char memmsg[] = "Not enough memory\n";
+  int i, fd;
+  size_t amt, len;
+
+  fd = open (bootscript, O_RDONLY, 0);
+  if (fd < 0)
+    {
+      write (2, filemsg, sizeof (filemsg));
+      host_exit (1);
+    }
+  p = buf = malloc (500);
+  if (!buf)
+    {
+      write (2, memmsg, sizeof (memmsg));
+      host_exit (1);
+    }
+  len = 500;
+  amt = 0;
+  while (1)
+    {
+      i = read (fd, p, len - (p - buf));
+      if (i <= 0)
+        break;
+      p += i;
+      amt += i;
+      if (p == buf + len)
+        {
+          char *newbuf;
+
+          len += 500;
+          newbuf = realloc (buf, len);
+          if (!newbuf)
+            {
+              write (2, memmsg, sizeof (memmsg));
+              host_exit (1);
+            }
+          p = newbuf + (p - buf);
+          buf = newbuf;
+        }
+    }
+
+  close (fd);
+  *buffer = buf;
+  *length = amt;
+}
+
+
+/* Boot script file for booting contemporary GNU Hurd systems.  Each
+   line specifies a file to be loaded by the boot loader (the first
+   word), and actions to be done with it.  */
+const char *default_boot_script =
+  /* First, the bootstrap filesystem.  It needs several ports as
+     arguments, as well as the user flags from the boot loader.  */
+  "/hurd/ext2fs.static"
+  " --readonly"
+  " --multiboot-command-line=${kernel-command-line}"
+  " --host-priv-port=${host-port}"
+  " --device-master-port=${device-port}"
+  " --exec-server-task=${exec-task}"
+  " -T device ${root-device} $(task-create) $(task-resume)"
+  "\n"
+
+  /* Now the exec server; to load the dynamically-linked exec server
+     program, we have the boot loader in fact load and run ld.so,
+     which in turn loads and runs /hurd/exec.  This task is created,
+     and its task port saved in ${exec-task} to be passed to the fs
+     above, but it is left suspended; the fs will resume the exec task
+     once it is ready.  */
+  "/lib/ld.so /hurd/exec $(exec-task=task-create)"
+  "\n";
+
+
 int
 main (int argc, char **argv, char **envp)
 {
   error_t err;
   mach_port_t foo;
   char *buf = 0;
-  int i, len;
   pthread_t pthread_id;
   char *root_store_name;
-  const struct argp_child kids[] = { { &store_argp }, { 0 }};
-  struct argp argp = { options, parse_opt, args_doc, doc, kids };
+  const struct argp_child kids[] = { { &store_argp, 0, "Store options:", -2 },
+                                     { 0 }};
+  struct argp argp = { options, parse_opt, NULL, doc, kids };
   struct store_argp_params store_argp_params = { 0 };
 
   argp_parse (&argp, argc, argv, 0, 0, &store_argp_params);
@@ -524,16 +488,26 @@ main (int argc, char **argv, char **envp)
   if (err)
     error (4, err, "%s", root_store_name);
 
-  get_privileged_ports (&privileged_host_port, &master_device_port);
+  if (want_privileged)
+    {
+      get_privileged_ports (&privileged_host_port, &master_device_port);
+      privileged = MACH_PORT_VALID (master_device_port);
+
+      if (! privileged)
+        error (1, 0, "Must be run as root for privileged subhurds");
+    }
 
-  strcat (bootstrap_args, "f");
+  if (privileged)
+    strcat (bootstrap_args, "f");
 
   mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
                      &receive_set);
 
   if (root_store->class == &store_device_class && root_store->name
       && (root_store->flags & STORE_ENFORCED)
-      && root_store->num_runs == 1 && root_store->runs[0].start == 0)
+      && root_store->num_runs == 1
+      && root_store->runs[0].start == 0
+      && privileged)
     /* Let known device nodes pass through directly.  */
     bootdevice = root_store->name;
   else
@@ -578,13 +552,33 @@ main (int argc, char **argv, char **envp)
   if (foo != MACH_PORT_NULL)
     mach_port_deallocate (mach_task_self (), foo);
 
+  if (! privileged)
+    {
+      err = allocate_pseudo_ports ();
+      if (err)
+        error (1, err, "Allocating pseudo ports");
+
+      /* Create a new task namespace for us.  */
+      err = proc_make_task_namespace (getproc (), task_notification_port,
+                                      MACH_MSG_TYPE_MAKE_SEND);
+      if (err)
+        error (1, err, "proc_make_task_namespace");
+
+      /* Create an empty task that the subhurds can freely frobnicate.  */
+      err = task_create (mach_task_self (), 0, &pseudo_kernel);
+      if (err)
+        error (1, err, "task_create");
+    }
+
   if (kernel_command_line == 0)
     asprintf (&kernel_command_line, "%s %s root=%s",
              argv[0], bootstrap_args, bootdevice);
 
   /* Initialize boot script variables.  */
   if (boot_script_set_variable ("host-port", VAL_PORT,
-                               (int) privileged_host_port)
+                                privileged
+                                ? (int) privileged_host_port
+                               : (int) pseudo_privileged_host_port)
       || boot_script_set_variable ("device-port", VAL_PORT,
                                   (integer_t) pseudo_master_device_port)
       || boot_script_set_variable ("kernel-command-line", VAL_STR,
@@ -630,46 +624,12 @@ main (int argc, char **argv, char **envp)
   /* Parse the boot script.  */
   {
     char *p, *line;
-    static const char filemsg[] = "Can't open boot script\n";
-    static const char memmsg[] = "Not enough memory\n";
-    int amt, fd, err;
+    size_t amt;
+    if (bootscript)
+      read_boot_script (&buf, &amt);
+    else
+      buf = strdup (default_boot_script), amt = strlen (default_boot_script);
 
-    fd = open (bootscript, O_RDONLY, 0);
-    if (fd < 0)
-      {
-       write (2, filemsg, sizeof (filemsg));
-       host_exit (1);
-      }
-    p = buf = malloc (500);
-    if (!buf)
-      {
-       write (2, memmsg, sizeof (memmsg));
-       host_exit (1);
-      }
-    len = 500;
-    amt = 0;
-    while (1)
-      {
-       i = read (fd, p, len - (p - buf));
-       if (i <= 0)
-         break;
-       p += i;
-       amt += i;
-       if (p == buf + len)
-         {
-           char *newbuf;
-
-           len += 500;
-           newbuf = realloc (buf, len);
-           if (!newbuf)
-             {
-               write (2, memmsg, sizeof (memmsg));
-               host_exit (1);
-             }
-           p = newbuf + (p - buf);
-           buf = newbuf;
-         }
-      }
     line = p = buf;
     while (1)
       {
@@ -709,8 +669,6 @@ main (int argc, char **argv, char **envp)
   /* The boot script has now been parsed into internal data structures.
      Now execute its directives.  */
   {
-    int err;
-
     err = boot_script_exec ();
     if (err)
       {
@@ -954,8 +912,17 @@ ds_device_open (mach_port_t master_port,
   map = lookup_dev (name);
   if (map)
     {
+      error_t err;
+      file_t node;
+
+      node = file_name_lookup (map->file_name, 0, 0);
+      if (! MACH_PORT_VALID (node))
+        return D_NO_SUCH_DEVICE;
+
       *devicetype = MACH_MSG_TYPE_MOVE_SEND;
-      return device_open (map->port, mode, "", device);
+      err = device_open (node, mode, "", device);
+      mach_port_deallocate (mach_task_self (), node);
+      return err;
     }
 
   *devicetype = MACH_MSG_TYPE_MOVE_SEND;
@@ -1324,6 +1291,8 @@ do_mach_notify_send_once (mach_port_t notify)
   return EOPNOTSUPP;
 }
 
+static void task_died (mach_port_t name);
+
 kern_return_t
 do_mach_notify_dead_name (mach_port_t notify,
                          mach_port_t name)
@@ -1332,7 +1301,11 @@ do_mach_notify_dead_name (mach_port_t notify,
   if (name == child_task && notify == bootport)
     host_exit (0);
 #endif
-  return EOPNOTSUPP;
+  if (notify != dead_task_notification_port)
+    return EOPNOTSUPP;
+  task_died (name);
+  mach_port_deallocate (mach_task_self (), name);
+  return 0;
 }
 
 
@@ -1598,6 +1571,8 @@ S_io_reauthenticate (mach_port_t object,
   size_t gulen = 0, aulen = 0, gglen = 0, aglen = 0;
   error_t err;
 
+  /* XXX: This cannot possibly work, authserver is 0.  */
+
   err = mach_port_insert_right (mach_task_self (), object, object,
                                MACH_MSG_TYPE_MAKE_SEND);
   assert_perror (err);
@@ -1890,3 +1865,154 @@ kern_return_t S_term_on_pty
        io_t *ptymaster
 )
 { return EOPNOTSUPP; }
+
+/* Mach host emulation.  */
+
+kern_return_t
+S_vm_set_default_memory_manager (mach_port_t host_priv,
+                                 mach_port_t *default_manager)
+{
+  if (host_priv != pseudo_privileged_host_port)
+    return KERN_INVALID_HOST;
+
+  if (*default_manager != MACH_PORT_NULL)
+    return KERN_INVALID_ARGUMENT;
+
+  *default_manager = MACH_PORT_NULL;
+  return KERN_SUCCESS;
+}
+
+kern_return_t
+S_host_reboot (mach_port_t host_priv,
+               int flags)
+{
+  fprintf (stderr, "Would %s the system.  Bye.\n",
+           flags & RB_HALT? "halt": "reboot");
+  host_exit (0);
+}
+
+
+kern_return_t
+S_host_processor_set_priv (mach_port_t host_priv,
+                          mach_port_t set_name,
+                          mach_port_t *set)
+{
+  if (host_priv != pseudo_privileged_host_port)
+    return KERN_INVALID_HOST;
+
+  *set = pseudo_pset;
+  return KERN_SUCCESS;
+}
+
+mach_port_t new_task_notification;
+
+kern_return_t
+S_register_new_task_notification (mach_port_t host_priv,
+                                 mach_port_t notification)
+{
+  if (host_priv != pseudo_privileged_host_port)
+    return KERN_INVALID_HOST;
+
+  if (! MACH_PORT_VALID (notification))
+    return KERN_INVALID_ARGUMENT;
+
+  if (MACH_PORT_VALID (new_task_notification))
+    return KERN_NO_ACCESS;
+
+  new_task_notification = notification;
+  return KERN_SUCCESS;
+}
+
+
+/* Managing tasks.  */
+
+static void
+task_ihash_cleanup (hurd_ihash_value_t value, void *cookie)
+{
+  (void) cookie;
+  mach_port_deallocate (mach_task_self (), (mach_port_t) value);
+}
+
+static struct hurd_ihash task_ihash =
+  HURD_IHASH_INITIALIZER_GKI (HURD_IHASH_NO_LOCP, task_ihash_cleanup, NULL,
+                              NULL, NULL);
+
+static void
+task_died (mach_port_t name)
+{
+  hurd_ihash_remove (&task_ihash, (hurd_ihash_key_t) name);
+}
+
+/* Handle new task notifications from proc.  */
+error_t
+S_mach_notify_new_task (mach_port_t notify,
+                       mach_port_t task,
+                       mach_port_t parent)
+{
+  error_t err;
+  mach_port_t previous;
+
+  if (notify != task_notification_port)
+    return EOPNOTSUPP;
+
+  err = mach_port_request_notification (mach_task_self (), task,
+                                        MACH_NOTIFY_DEAD_NAME, 0,
+                                        dead_task_notification_port,
+                                        MACH_MSG_TYPE_MAKE_SEND_ONCE,
+                                        &previous);
+  if (err)
+    goto fail;
+  assert (! MACH_PORT_VALID (previous));
+
+  mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND, +1);
+  err = hurd_ihash_add (&task_ihash,
+                        (hurd_ihash_key_t) task, (hurd_ihash_value_t) task);
+  if (err)
+    {
+      mach_port_deallocate (mach_task_self (), task);
+      goto fail;
+    }
+
+  if (MACH_PORT_VALID (new_task_notification))
+    /* Relay the notification.  This consumes task and parent.  */
+    return mach_notify_new_task (new_task_notification, task, parent);
+
+  mach_port_deallocate (mach_task_self (), task);
+  mach_port_deallocate (mach_task_self (), parent);
+  return 0;
+
+ fail:
+  task_terminate (task);
+  return err;
+}
+
+kern_return_t
+S_processor_set_tasks(mach_port_t processor_set,
+                     task_array_t *task_list,
+                     mach_msg_type_number_t *task_listCnt)
+{
+  error_t err;
+  size_t i;
+
+  err = vm_allocate (mach_task_self (), (vm_address_t *) task_list,
+                    task_ihash.nr_items * sizeof **task_list, 1);
+  if (err)
+    return err;
+
+  /* The first task has to be the kernel.  */
+  (*task_list)[0] = pseudo_kernel;
+
+  i = 1;
+  HURD_IHASH_ITERATE (&task_ihash, value)
+    {
+      task_t task = (task_t) value;
+      if (task == pseudo_kernel)
+        continue;
+
+      (*task_list)[i] = task;
+      i += 1;
+    }
+
+  *task_listCnt = task_ihash.nr_items;
+  return 0;
+}
diff --git a/boot/frank1.ld b/boot/frank1.ld
deleted file mode 100644
index 9de827a..0000000
--- a/boot/frank1.ld
+++ /dev/null
@@ -1,94 +0,0 @@
-OUTPUT_FORMAT("elf32-i386", "elf32-i386",
-             "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
- SEARCH_DIR(/usr/local/i386-gnuelf/lib);
-/* Do we need any of these for elf?
-   __DYNAMIC = 0;    */
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = 0x10020;
-  .text      :
-  {
-    *(.text)
-  *(.interp)
-  *(.hash)
-  *(.dynsym)
-  *(.dynstr)
-  *(.rel.text)
-  *(.rela.text)
-  *(.rel.data)
-  *(.rela.data)
-  *(.rel.rodata)
-  *(.rela.rodata)
-  *(.rel.got)
-  *(.rela.got)
-  *(.rel.ctors)
-  *(.rela.ctors)
-  *(.rel.dtors)
-  *(.rela.dtors)
-  *(.rel.init)
-  *(.rela.init)
-  *(.rel.fini)
-  *(.rela.fini)
-  *(.rel.bss)
-  *(.rela.bss)
-  *(.rel.plt)
-  *(.rela.plt)
-  *(.init)
-  *(.plt)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  *(.fini)
-  *(.rodata)
-  *(.rodata1)
-  _etext = .;
-  PROVIDE (etext = .);
-  . = ALIGN(0x1000);
-  } =0x9090
-  . =  ALIGN(0x1000);
-  .data    :
-  {
-    *(.data)
-    CONSTRUCTORS
-
-  *(.data1) 
-  *(.ctors)
-  *(.dtors)
-  *(.got.plt) *(.got) 
-  *(.dynamic)
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  *(.sdata)
-  _edata  =  .;
-  PROVIDE (edata = .);
-  . = ALIGN(0x10);
-}
-  __bss_start = .;
-  .bss       :
-  {
- *(.sbss) *(.scommon) 
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  _end = ALIGN(4) ;
-  PROVIDE (end = ALIGN(4));
-  }
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* DWARF debug sections.
-     Symbols in the .debug DWARF section are relative to the beginning of the
-     section so we begin .debug at 0.  It's not clear yet what needs to happen
-     for the others.   */
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
-  /* These must appear regardless of  .  */
-}
diff --git a/boot/frankemul.ld b/boot/frankemul.ld
deleted file mode 100644
index 413953e..0000000
--- a/boot/frankemul.ld
+++ /dev/null
@@ -1,107 +0,0 @@
-OUTPUT_FORMAT("elf32-i386", "elf32-i386",
-             "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
- SEARCH_DIR(/usr/local/i386-gnuelf/lib);
-/* Do we need any of these for elf?
-   __DYNAMIC = 0;    */
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = 0x10020;
-  .text      :
-  {
-    *(.text)
-  *(.interp)
-  *(.hash)
-  *(.dynsym)
-  *(.dynstr)
-  *(.rel.text)
-  *(.rela.text)
-  *(.rel.data)
-  *(.rela.data)
-  *(.rel.rodata)
-  *(.rela.rodata)
-  *(.rel.got)
-  *(.rela.got)
-  *(.rel.ctors)
-  *(.rela.ctors)
-  *(.rel.dtors)
-  *(.rela.dtors)
-  *(.rel.init)
-  *(.rela.init)
-  *(.rel.fini)
-  *(.rela.fini)
-  *(.rel.bss)
-  *(.rela.bss)
-  *(.rel.plt)
-  *(.rela.plt)
-  *(.init)
-  *(.plt)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  *(.fini)
-  *(.rodata)
-  *(.rodata1)
-*(_hurd_ioctl_handler_lists)
-*(_hurd_pgrp_changed_hook)
-*(_hurd_fork_locks)
-*(_hurd_subinit)
-*(__libc_atexit)
-*(_hurd_fd_subinit)
-*(_hurd_preinit_hook)
-*(_hurd_fork_child_hook)
-*(_hurd_fork_parent_hook)
-*(_hurd_fork_prepare_hook)
-*(_hurd_reauth_hook)
-*(_hurd_proc_subinit)
-*(__libc_subinit)
-  _etext = .;
-  PROVIDE (etext = .);
-  . = ALIGN(0x1000);
-  } =0x9090
-  . =  ALIGN(0x1000);
-  .data    :
-  {
-    *(.data)
-    CONSTRUCTORS
-
-  *(.data1) 
-  *(.ctors)
-  *(.dtors)
-  *(.got.plt) *(.got) 
-  *(.dynamic)
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  *(.sdata)
-  _edata  =  .;
-  PROVIDE (edata = .);
-  . = ALIGN(0x10);
-}
-  __bss_start = .;
-  .bss       :
-  {
- *(.sbss) *(.scommon) 
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  _end = ALIGN(4) ;
-  PROVIDE (end = ALIGN(4));
-  }
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* DWARF debug sections.
-     Symbols in the .debug DWARF section are relative to the beginning of the
-     section so we begin .debug at 0.  It's not clear yet what needs to happen
-     for the others.   */
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
-  /* These must appear regardless of  .  */
-}
diff --git a/boot/mach-crt0.c b/boot/mach-crt0.c
deleted file mode 100644
index 0469424..0000000
--- a/boot/mach-crt0.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/* 
- * Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
- * All Rights Reserved.
- * 
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- * 
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- * 
- * Carnegie Mellon requests users of this software to return to
- * 
- *  Software Distribution Coordinator  or  address@hidden
- *  School of Computer Science
- *  Carnegie Mellon University
- *  Pittsburgh PA 15213-3890
- * 
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
-/*
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement:  ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)crt0.c     5.2 (Berkeley) 5/14/90";
-#endif /* not lint */
-
-/*
- *     C start up routine.
- *     Robert Henry, UCB, 20 Oct 81
- *
- *     We make the following (true) assumptions:
- *     1) when the kernel calls start, it does a jump to location 2,
- *     and thus avoids the register save mask.  We are NOT called
- *     with a calls!  see sys1.c:setregs().
- *     2) The only register variable that we can trust is sp,
- *     which points to the base of the kernel calling frame.
- *     Do NOT believe the documentation in exec(2) regarding the
- *     values of fp and ap.
- *     3) We can allocate as many register variables as we want,
- *     and don't have to save them for anybody.
- *     4) Because of the ways that asm's work, we can't have
- *     any automatic variables allocated on the stack, because
- *     we must catch the value of sp before any automatics are
- *     allocated.
- */
-
-#include <mach/machine/asm.h>
-
-int __data_start = 0;
-char **environ = (char **)0;
-#ifdef paranoid
-static int fd;
-#endif paranoid
-
-int    (*mach_init_routine)();
-int    (*_cthread_init_routine)();
-int    (*_cthread_exit_routine)();
-int    (*_monstartup_routine)();
-int    (*_StrongBox_init_routine)();
-int    errno = 0;
-int    exit();
-
-extern int main();
-
-extern unsigned char   etext;
-int _start()
-{
-        __label__ eprol;
-       struct kframe {
-               int     kargc;
-               char    *kargv[1];      /* size depends on kargc */
-               char    kargstr[1];     /* size varies */
-               char    kenvstr[1];     /* size varies */
-       };
-       /*
-        *      ALL REGISTER VARIABLES!!!
-        */
-       register struct kframe *kfp;    /* r10 */
-       register char **targv;
-       register char **argv;
-
-#ifdef lint
-       kfp = 0;
-       initcode = initcode = 0;
-#else not lint
-#define Entry_sp() \
-({ int _spl__, _tmp1__; \
-       asm volatile("leal 4(%%ebp), %0" : "=r" (_spl__) : "r" (_tmp1__)); \
-       _spl__; })
-
-       kfp = (struct kframe *)Entry_sp();
-#endif not lint
-       for (argv = targv = &kfp->kargv[0]; *targv++; /* void */)
-               /* void */ ;
-       if (targv >= (char **)(*argv))
-               --targv;
-       environ = targv;
-       if (mach_init_routine)
-               (void) mach_init_routine();
-
- eprol:
-#ifdef paranoid
-       /*
-        * The standard I/O library assumes that file descriptors 0, 1, and 2
-        * are open. If one of these descriptors is closed prior to the start 
-        * of the process, I/O gets very confused. To avoid this problem, we
-        * insure that the first three file descriptors are open before calling
-        * main(). Normally this is undefined, as it adds two unnecessary
-        * system calls.
-        */
-       do      {
-               fd = open("/dev/null", 2);
-       } while (fd >= 0 && fd < 3);
-       close(fd);
-#endif paranoid
-
-
-       if (_cthread_init_routine) {
-           int new_sp;
-           new_sp = (*_cthread_init_routine)();
-           if (new_sp) {
-               asm volatile("movl %0, %%esp" : : "g" (new_sp) );
-           }
-       }
-       if (_StrongBox_init_routine) (*_StrongBox_init_routine)();
-
-       if (_monstartup_routine)  {
-           _monstartup_routine(&&eprol, &etext);
-       }
-
-       (* (_cthread_exit_routine ? _cthread_exit_routine : exit))
-               (main(kfp->kargc, argv, targv));
-}
diff --git a/proc/mig-mutate.h b/boot/mig-decls.h
similarity index 57%
copy from proc/mig-mutate.h
copy to boot/mig-decls.h
index 62dc2a5..d539659 100644
--- a/proc/mig-mutate.h
+++ b/boot/mig-decls.h
@@ -17,21 +17,11 @@
    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 __BOOT_MIG_DECLS_H__
+#define __BOOT_MIG_DECLS_H__
 
-#define PROCESS_INTRAN                                         \
-  pstruct_t begin_using_proc_port (process_t)
-#define PROCESS_INTRAN_PAYLOAD                                 \
-  pstruct_t begin_using_proc_payload
-#define PROCESS_DESTRUCTOR                                     \
-  end_using_proc (pstruct_t)
-#define PROCESS_IMPORTS                                                \
-  import "mig-decls.h";
-
-#define NOTIFY_INTRAN                                          \
-  port_info_t begin_using_port_info_port (mach_port_t)
-#define NOTIFY_INTRAN_PAYLOAD                                  \
-  port_info_t begin_using_port_info_payload
-#define NOTIFY_DESTRUCTOR                                      \
-  end_using_port_info (port_info_t)
-#define NOTIFY_IMPORTS                                         \
-  import "libports/mig-decls.h";
+#include <hurd.h>
+
+#define MIG_EOPNOTSUPP EOPNOTSUPP
+
+#endif /* __BOOT_MIG_DECLS_H__ */
diff --git a/proc/mig-mutate.h b/boot/mig-mutate.h
similarity index 59%
copy from proc/mig-mutate.h
copy to boot/mig-mutate.h
index 62dc2a5..ef90b73 100644
--- a/proc/mig-mutate.h
+++ b/boot/mig-mutate.h
@@ -17,21 +17,9 @@
    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 PROCESS_INTRAN                                         \
-  pstruct_t begin_using_proc_port (process_t)
-#define PROCESS_INTRAN_PAYLOAD                                 \
-  pstruct_t begin_using_proc_payload
-#define PROCESS_DESTRUCTOR                                     \
-  end_using_proc (pstruct_t)
-#define PROCESS_IMPORTS                                                \
+#define MACH_IMPORTS                                           \
+  import "mig-decls.h";
+#define MACH_HOST_IMPORTS                                      \
+  import "mig-decls.h";
+#define GNUMACH_IMPORTS                                                \
   import "mig-decls.h";
-
-#define NOTIFY_INTRAN                                          \
-  port_info_t begin_using_port_info_port (mach_port_t)
-#define NOTIFY_INTRAN_PAYLOAD                                  \
-  port_info_t begin_using_port_info_payload
-#define NOTIFY_DESTRUCTOR                                      \
-  end_using_port_info (port_info_t)
-#define NOTIFY_IMPORTS                                         \
-  import "libports/mig-decls.h";
diff --git a/boot/sigvec.S b/boot/sigvec.S
deleted file mode 100644
index cc7bb94..0000000
--- a/boot/sigvec.S
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <i386/asm.h>
-
-.text
-ENTRY(sigreturn)
-       movl $0x67,%eax
-       lcall $0x7,$0x0
-       jb error
-       ret
-ENTRY(_sigreturn)
-       addl $0xc,%esp
-       call EXT(sigreturn)
-       ret
-ENTRY(sigvec)
-       movl $0x6c,%eax
-       movl $EXT(_sigreturn),%edx
-       orl $0x80000000,%edx
-       lcall $0x7,$0x0
-       jb error
-       ret
-error:
-        movl %eax,EXT(errno)
-        movl $-1,%eax
-        ret
diff --git a/boot/syscall.S b/boot/syscall.S
deleted file mode 100644
index a04ab28..0000000
--- a/boot/syscall.S
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Temporary....
-   Copyright (C) 1993, 1995 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful, 
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-#include <i386/asm.h>
-
-/*     .globl EXT(errno)*/
-.text
-ENTRY(syscall)
-       pop %ecx
-       pop %eax
-       push %ecx
-       lcall $7, $0
-       push %ecx               /* Restore stack position.  */
-       jb error
-       ret
-error:
-       movl %eax,EXT(errno)
-       movl $-1,%eax
-       ret
diff --git a/boot/userland-boot.c b/boot/userland-boot.c
index d048c00..583078f 100644
--- a/boot/userland-boot.c
+++ b/boot/userland-boot.c
@@ -17,11 +17,19 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
+#include <a.out.h>
+#include <elf.h>
+#include <fcntl.h>
 #include <mach.h>
+#include <mach/machine/vm_param.h> /* For VM_XXX_ADDRESS */
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
 #include <errno.h>
 #include <error.h>
+
 #include "boot_script.h"
 
 void *
@@ -90,14 +98,23 @@ boot_script_free_task (task_t task, int aborting)
 int
 boot_script_insert_right (struct cmd *cmd, mach_port_t port, mach_port_t *name)
 {
-  error_t err = mach_port_insert_right (cmd->task,
-                                       port, port, MACH_MSG_TYPE_COPY_SEND);
+  error_t err;
+
+  *name = MACH_PORT_NULL;
+  do
+    {
+      *name += 1;
+      err = mach_port_insert_right (cmd->task,
+                                    *name, port, MACH_MSG_TYPE_COPY_SEND);
+    }
+  while (err == KERN_NAME_EXISTS);
+
   if (err)
     {
       error (0, err, "%s: mach_port_insert_right", cmd->path);
       return BOOT_SCRIPT_MACH_ERROR;
     }
-  *name = port;
+
   return 0;
 }
 
@@ -106,3 +123,206 @@ boot_script_insert_task_port (struct cmd *cmd, task_t 
task, mach_port_t *name)
 {
   return boot_script_insert_right (cmd, task, name);
 }
+
+char *useropen_dir;
+
+static int
+useropen (const char *name, int flags, int mode)
+{
+  if (useropen_dir)
+    {
+      static int dlen;
+      if (!dlen) dlen = strlen (useropen_dir);
+      {
+       int len = strlen (name);
+       char try[dlen + 1 + len + 1];
+       int fd;
+       memcpy (try, useropen_dir, dlen);
+       try[dlen] = '/';
+       memcpy (&try[dlen + 1], name, len + 1);
+       fd = open (try, flags, mode);
+       if (fd >= 0)
+         return fd;
+      }
+    }
+  return open (name, flags, mode);
+}
+
+static vm_address_t
+load_image (task_t t,
+           char *file)
+{
+  int fd;
+  union
+    {
+      struct exec a;
+      Elf32_Ehdr e;
+    } hdr;
+  char msg[] = ": cannot open bootstrap file\n";
+
+  fd = useropen (file, O_RDONLY, 0);
+
+  if (fd == -1)
+    {
+      write (2, file, strlen (file));
+      write (2, msg, sizeof msg - 1);
+      task_terminate (t);
+      exit (1);
+    }
+
+  read (fd, &hdr, sizeof hdr);
+  /* File must have magic ELF number.  */
+  if (hdr.e.e_ident[0] == 0177 && hdr.e.e_ident[1] == 'E' &&
+      hdr.e.e_ident[2] == 'L' && hdr.e.e_ident[3] == 'F')
+    {
+      Elf32_Phdr phdrs[hdr.e.e_phnum], *ph;
+      lseek (fd, hdr.e.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;
+
+           vm_allocate (t, (vm_address_t*)&ph->p_vaddr, ph->p_memsz, 0);
+           vm_write (t, ph->p_vaddr, buf, bufsz);
+           munmap ((caddr_t) buf, bufsz);
+           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));
+         }
+      return hdr.e.e_entry;
+    }
+  else
+    {
+      /* a.out */
+      int magic = N_MAGIC (hdr.a);
+      int headercruft;
+      vm_address_t base = 0x10000;
+      int rndamount, amount;
+      vm_address_t bsspagestart, bssstart;
+      char *buf;
+
+      headercruft = sizeof (struct exec) * (magic == ZMAGIC);
+
+      amount = headercruft + hdr.a.a_text + hdr.a.a_data;
+      rndamount = round_page (amount);
+      buf = mmap (0, rndamount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+      lseek (fd, sizeof hdr.a - headercruft, SEEK_SET);
+      read (fd, buf, amount);
+      vm_allocate (t, &base, rndamount, 0);
+      vm_write (t, base, (vm_address_t) buf, rndamount);
+      if (magic != OMAGIC)
+       vm_protect (t, base, trunc_page (headercruft + hdr.a.a_text),
+                   0, VM_PROT_READ | VM_PROT_EXECUTE);
+      munmap ((caddr_t) buf, rndamount);
+
+      bssstart = base + hdr.a.a_text + hdr.a.a_data + headercruft;
+      bsspagestart = round_page (bssstart);
+      vm_allocate (t, &bsspagestart,
+                  hdr.a.a_bss - (bsspagestart - bssstart), 0);
+
+      return hdr.a.a_entry;
+    }
+}
+
+int
+boot_script_exec_cmd (void *hook,
+                     mach_port_t task, char *path, int argc,
+                     char **argv, char *strings, int stringlen)
+{
+  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;
+
+  write (2, path, strlen (path));
+  for (i = 1; i < argc; ++i)
+    {
+      int quote = !! index (argv[i], ' ') || !! index (argv[i], '\t');
+      write (2, " ", 1);
+      if (quote)
+        write (2, "\"", 1);
+      write (2, argv[i], strlen (argv[i]));
+      if (quote)
+        write (2, "\"", 1);
+    }
+  write (2, "\r\n", 2);
+
+  startpc = load_image (task, path);
+  arg_len = stringlen + (argc + 2) * sizeof (char *) + sizeof (integer_t);
+  arg_len += 5 * sizeof (int);
+  stack_end = VM_MAX_ADDRESS;
+  stack_start = VM_MAX_ADDRESS - 16 * 1024 * 1024;
+  vm_allocate (task, &stack_start, stack_end - stack_start, FALSE);
+  arg_pos = (void *) ((stack_end - arg_len) & ~(sizeof (natural_t) - 1));
+  args = mmap (0, stack_end - trunc_page ((vm_offset_t) arg_pos),
+              PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+  str_start = ((vm_address_t) arg_pos
+              + (argc + 2) * sizeof (char *) + sizeof (integer_t));
+  p = args + ((vm_address_t) arg_pos & (vm_page_size - 1));
+  *(int *) p = argc;
+  p = (void *) p + sizeof (int);
+  for (i = 0; i < argc; i++)
+    {
+      *(char **) p = argv[i] - strings + (char *) str_start;
+      p = (void *) p + sizeof (char *);
+    }
+  *(char **) p = 0;
+  p = (void *) p + sizeof (char *);
+  *(char **) p = 0;
+  p = (void *) p + sizeof (char *);
+  memcpy (p, strings, stringlen);
+  memset (args, 0, (vm_offset_t)arg_pos & (vm_page_size - 1));
+  vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args,
+           stack_end - trunc_page ((vm_offset_t) arg_pos));
+  munmap ((caddr_t) args,
+         stack_end - trunc_page ((vm_offset_t) arg_pos));
+
+  thread_create (task, &thread);
+#ifdef i386_THREAD_STATE_COUNT
+  {
+    struct i386_thread_state regs;
+    reg_size = i386_THREAD_STATE_COUNT;
+    thread_get_state (thread, i386_THREAD_STATE,
+                     (thread_state_t) &regs, &reg_size);
+    regs.eip = (int) startpc;
+    regs.uesp = (int) arg_pos;
+    thread_set_state (thread, i386_THREAD_STATE,
+                     (thread_state_t) &regs, reg_size);
+  }
+#elif defined(ALPHA_THREAD_STATE_COUNT)
+  {
+    struct alpha_thread_state regs;
+    reg_size = ALPHA_THREAD_STATE_COUNT;
+    thread_get_state (thread, ALPHA_THREAD_STATE,
+                     (thread_state_t) &regs, &reg_size);
+    regs.r30 = (natural_t) arg_pos;
+    regs.pc = (natural_t) startpc;
+    thread_set_state (thread, ALPHA_THREAD_STATE,
+                     (thread_state_t) &regs, reg_size);
+  }
+#else
+# error needs to be ported
+#endif
+
+  thread_resume (thread);
+  mach_port_deallocate (mach_task_self (), thread);
+  return 0;
+}
diff --git a/boot/ux.c b/boot/ux.c
deleted file mode 100644
index 7239762..0000000
--- a/boot/ux.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* Hacks to make boot work under UX
-
-   Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
-
-   This file is part of the GNU Hurd.
-
-   The GNU Hurd is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   The GNU Hurd is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with the GNU Hurd; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-#include <mach.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <pthread.h>
-
-#include "ux.h"
-
-#if 0
-static int (* const _sc)(int, ...) = &syscall;
-int _sc_print = 1;
-
-#define syscall(num, args...) \
- ({ int _rv, _num = (num), _pr = _sc_print; \
-    _sc_print = 0; \
-    if (_pr) printf ("syscall (%d) start\r\n", _num); \
-    _rv = (*_sc) (_num , ##args); \
-    if (_pr) printf ("syscall (%d) end\r\n", _num); \
-    _sc_print = _pr; \
-    _rv; \
-   })
-#endif
-
-extern void __mach_init ();
-void   (*mach_init_routine)() = __mach_init;
-
-/* These will prevent the Hurd-ish versions from being used */
-
-struct free_reply_port
-{
-  mach_port_t port;
-  struct free_reply_port *next;
-};
-static struct free_reply_port *free_reply_ports = NULL;
-static pthread_spinlock_t free_reply_ports_lock = PTHREAD_SPINLOCK_INITIALIZER;
-
-mach_port_t __mig_get_reply_port ()
-{
-  pthread_spin_lock (&free_reply_ports_lock);
-  if (free_reply_ports == NULL)
-    {
-      pthread_spin_unlock (&free_reply_ports_lock);
-      return __mach_reply_port ();
-    }
-  else
-    {
-      struct free_reply_port *frp = free_reply_ports;
-      mach_port_t reply_port = frp->port;
-      free_reply_ports = free_reply_ports->next;
-      pthread_spin_unlock (&free_reply_ports_lock);
-      free (frp);
-      return reply_port;
-    }
-}
-mach_port_t mig_get_reply_port ()
-{
-  return __mig_get_reply_port ();
-}
-void __mig_put_reply_port (mach_port_t port)
-{
-  struct free_reply_port *frp = malloc (sizeof (struct free_reply_port));
-  frp->port = port;
-  pthread_spin_lock (&free_reply_ports_lock);
-  frp->next = free_reply_ports;
-  free_reply_ports = frp;
-  pthread_spin_unlock (&free_reply_ports_lock);
-}
-void mig_put_reply_port (mach_port_t port)
-{
-  __mig_put_reply_port (port);
-}
-void __mig_dealloc_reply_port (mach_port_t port)
-{
-  mach_port_mod_refs (__mach_task_self (), port,
-                     MACH_PORT_RIGHT_RECEIVE, -1);
-}
-void mig_dealloc_reply_port (mach_port_t port)
-{
-  __mig_dealloc_reply_port (port);
-}
-void __mig_init (void *stack) {}
-void mig_init (void *stack) {}
-
-int
-task_by_pid (int pid)
-{
-  return syscall (-33, pid);
-}
-
-int
-write (int fd,
-       const void *buf,
-       int buflen)
-{
-  return syscall (4, fd, buf, buflen);
-}
-
-int
-read (int fd,
-      void *buf,
-      int buflen)
-{
-  return syscall (3, fd, buf, buflen);
-}
-
-int
-open (const char *name,
-      int flags,
-      int mode)
-{
-  return syscall (5, name, flags, mode);
-}
-
-int
-uxfstat (int fd, struct uxstat *buf)
-{
-  return syscall (62, fd, buf);
-}
-
-int
-close (int fd)
-{
-  return syscall (6, fd);
-}
-
-int
-lseek (int fd,
-       int off,
-       int whence)
-{
-  return syscall (19, fd, off, whence);
-}
-
-int
-uxexit (int code)
-{
-  return syscall (1, code);
-}
-
-int
-getpid ()
-{
-  return syscall (20);
-}
-
-int
-ioctl (int fd, int code, void *buf)
-{
-  return syscall (54, fd, code, buf);
-}
-
-int
-sigblock (int mask)
-{
-  return syscall (109, mask);
-}
-
-int
-sigsetmask (int mask)
-{
-  return syscall (110, mask);
-}
-
-int
-sigpause (int mask)
-{
-  return syscall (111, mask);
-}
-
-
-#if 0
-void
-sigreturn ()
-{
-  asm volatile ("movl $0x67,%eax\n"
-               "lcall $0x7, $0x0\n"
-               "ret");
-}
-
-void
-_sigreturn ()
-{
-  asm volatile ("addl $0xc, %%esp\n"
-               "call %0\n"
-               "ret"::"m" (sigreturn));
-}
-
-int
-sigvec (int sig, struct sigvec *vec, struct sigvec *ovec)
-{
-  asm volatile ("movl $0x6c,%%eax\n"
-               "movl %0, %%edx\n"
-               "orl $0x80000000, %%edx\n"
-               "lcall $0x7,$0x0\n"
-               "ret"::"g" (_sigreturn));
-}
-#else
-int sigvec ();
-#endif
-
-void get_privileged_ports (mach_port_t *host_port, mach_port_t *device_port)
-{
-  *host_port = task_by_pid (-1);
-  *device_port = task_by_pid (-2);
-}
-
-/* A *really* stupid printf that only understands %s & %d.  */
-int
-printf (const char *fmt, ...)
-{
-  va_list ap;
-  const char *p = fmt, *q = p;
-
-  void flush (const char *new)
-    {
-      if (p > q)
-       write (1, q, p - q);
-      q = p = new;
-    }
-
-  va_start (ap, fmt);
-  while (*p)
-    if (*p == '%' && p[1] == 's')
-      {
-       char *str = va_arg (ap, char *);
-       flush (p + 2);
-       write (1, str, strlen (str));
-      }
-    else if (*p == '%' && p[1] == 'd')
-      {
-       int i = va_arg (ap, int);
-       char rbuf[20], *e = rbuf + sizeof (rbuf), *b = e; 
-
-       if (i == 0)
-         *--b = '0';
-       else
-         while (i)
-           {
-             *--b = i % 10 + '0';
-             i /= 10;
-           }
-
-       flush (p + 2);
-       write (1, b, e - b);
-      }
-    else
-      p++;
-  va_end (ap);
-
-  flush (0);
-
-  return 0;
-}
-
-static struct sgttyb term_sgb;
-static int localbits;
-
-void
-init_termstate ()
-{
-  struct sgttyb sgb;
-  int bits;
-  ioctl (0, TIOCGETP, &term_sgb);
-  ioctl (0, TIOCLGET, &localbits);
-  /* Enter raw made.  Rather than try and interpret these bits,
-     we just do what emacs does in .../emacs/src/sysdep.c for
-     an old style terminal driver. */
-  bits = localbits | LDECCTQ | LLITOUT | LPASS8 | LNOFLSH;
-  ioctl (0, TIOCLSET, &bits);
-  sgb = term_sgb;
-  sgb.sg_flags &= ~ECHO;
-  sgb.sg_flags |= RAW | ANYP;
-  ioctl (0, TIOCSETN, &sgb);
-}
-
-void
-restore_termstate ()
-{
-  ioctl (0, TIOCLSET, &localbits);
-  ioctl (0, TIOCSETN, &term_sgb);
-}
diff --git a/boot/ux.h b/boot/ux.h
deleted file mode 100644
index d3787c5..0000000
--- a/boot/ux.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Hacks to make boot work under UX
-
-   Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
-
-   This file is part of the GNU Hurd.
-
-   The GNU Hurd is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   The GNU Hurd is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with the GNU Hurd; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-#define sigmask(m) (1 << ((m)-1))
-
-#define IOCPARM_MASK 0x7f
-#define IOC_OUT 0x40000000
-#define IOC_IN 0x80000000
-#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
-#define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
-#define FIONREAD _IOR('f', 127, int)
-#define FIOASYNC _IOW('f', 125, int)
-#define TIOCGETP _IOR('t', 8, struct sgttyb)
-#define TIOCLGET _IOR('t', 124, int)
-#define TIOCLSET _IOW('t', 125, int)
-#define TIOCSETN _IOW('t', 10, struct sgttyb)
-#define LDECCTQ 0x4000
-#define LLITOUT 0x0020
-#define LPASS8  0x0800
-#define LNOFLSH 0x8000
-#define RAW 0x0020
-#define ANYP 0x00c0
-#define ECHO 8
-
-
-struct sgttyb
-{
-  char unused[4];
-  short sg_flags;
-};
-
-#define SIGIO 23
-
-struct sigvec
-{
-  void (*sv_handler)();
-  int sv_mask;
-  int sv_flags;
-};
-
-struct uxstat
-  {
-    short int st_dev;          /* Device containing the file.  */
-    __ino_t st_ino;            /* File serial number.          */
-    unsigned short int st_mode;        /* File mode.  */
-    __nlink_t st_nlink;                /* Link count.  */
-    unsigned short int st_uid; /* User ID of the file's owner. */
-    unsigned short int st_gid; /* Group ID of the file's group.*/
-    short int st_rdev;         /* Device number, if device.  */
-    __off_t st_size;           /* Size of file, in bytes.  */
-    __time_t st_atime;         /* Time of last access.  */
-    unsigned long int st_atime_usec;
-    __time_t st_mtime;         /* Time of last modification.  */
-    unsigned long int st_mtime_usec;
-    __time_t st_ctime;         /* Time of last status change.  */
-    unsigned long int st_ctime_usec;
-    unsigned long int st_blksize; /* Optimal block size for I/O.  */
-    unsigned long int st_blocks; /* Number of 512-byte blocks allocated.  */
-    long int st_spare[2];
-  };
-
-void get_privileged_ports (mach_port_t *host_port, mach_port_t *device_port);
-
-/* We can't include <unistd.h> for this, because that will fight witho
-   our definitions of syscalls below. */
-int syscall (int, ...);
-
-int open (const char *name, int flags, int mode);
-int write (int fd, const void *buf, int len);
-int read (int fd, void *buf, int len);
-int uxfstat (int fd, struct uxstat *buf);
-int close (int fd);
-int lseek (int fd, int off, int whence);
-int uxexit (int code);
-int getpid ();
-int ioctl (int fd, int code, void *buf);
-int sigblock (int mask);
-int sigsetmask (int mask);
-int sigpause (int mask);
-int sigvec (int sig, struct sigvec *vec, struct sigvec *ovec);
-
-#undef O_RDONLY
-#undef O_WRONLY
-#undef O_RDWR
-#define O_RDONLY 0
-#define O_WRONLY 1
-#define O_RDWR 2
-
-#define host_exit(c) uxexit(c)
-
-typedef struct uxstat host_stat_t;
-#define host_fstat(fd, st) uxfstat (fd, st)
-
-void init_stdio ();
-
-#undef errno
-int errno;
diff --git a/console/display.c b/console/display.c
index 98c70f5..ed5571e 100644
--- a/console/display.c
+++ b/console/display.c
@@ -814,6 +814,21 @@ user_create (display_t display, uint32_t width, uint32_t 
height,
   user->cursor.status = CONS_CURSOR_NORMAL;
   conchar_memset (user->_matrix, chr, attr,
                  user->screen.width * user->screen.lines);
+
+  /* FIXME: it seems we don't properly handle getting paged out.
+   * For now, just wire the pages to work around the issue.  */
+  {
+    mach_port_t host;
+
+    error_t err = get_privileged_ports (&host, NULL);
+    if (err)
+      host = mach_host_self ();
+
+    vm_wire (host, mach_task_self (), (vm_offset_t) user,
+            (vm_size_t) npages * vm_page_size, VM_PROT_READ);
+    if (host != mach_host_self ())
+       mach_port_deallocate (mach_task_self (), host);
+  }
   return 0;
 }
 
diff --git a/eth-multiplexer/ChangeLog b/eth-multiplexer/ChangeLog
index 3737118..88eebaa 100644
--- a/eth-multiplexer/ChangeLog
+++ b/eth-multiplexer/ChangeLog
@@ -52,7 +52,7 @@
 2008-12-12  Zheng Da  <address@hidden>
 
        * multiplexer.c (main): Initialize the file status of the root node.
-       
+
        * netfs_impl.c (netfs_validate_stat): Set the file status of the node
                                              with the one in the light node.
 
@@ -71,7 +71,7 @@
        (remove_dead_port_from_dev): Use lock.
        (broadcast_pack, broadcast_msg): Use foreach_dev_do.
 
-       * vdev.h (dev_num): Remove declaration. 
+       * vdev.h (dev_num): Remove declaration.
        (get_dev_num): Add declaration.
 
 2008-11-13  Zheng Da  <address@hidden>
@@ -100,7 +100,7 @@
        (SRCS): Add new C files.
        (LCLHDRS): Add new H files.
        (HURDLIBS): Change libraries.
-       
+
        * demuxer.c: New file.
 
        * device_impl.c: New file.
@@ -128,7 +128,7 @@
        * README: Update.
 
        * bpf_impl.c (destroy_filters): New function.
-       
+
        * multiplexer.c (nb_dev): Deleted.
        (options): Remove the option '-v'.
        (do_mach_notify_no_senders): Remove all port_info in the same way.
@@ -140,13 +140,13 @@
        (main): Remove the code of creating virtual devices.
 
        * util.h (ETH_P_IP): New macro.
-       
+
        * vdev.c (all_dev_close): Deleted.
        (add_vdev): Link virtual device.
        (destroy_vdev): New function.
 
        * vdev.h (vether_device): Changed.
-       
+
 
 2008-10-03  Zheng Da  <address@hidden>
 
@@ -274,10 +274,10 @@
 
        * multiplexer.c (options): Change the meaning of '-v' option.
        (parse_opt): Change the way of handling '-v' option.
-       
+
        * vdev.c (has_vdev): New function.
 
-       * vdev.h (has_vdev): New declaration. 
+       * vdev.h (has_vdev): New declaration.
 
 2008-8-17 Zheng Da <address@hidden>
 
@@ -306,7 +306,7 @@
 
        * vdev.c (all_dev_close): Change the way of testing if all devices are
        closed.
-       
+
        * vdev.h (vether_device): Replace count field with used.
 
 2008-8-13 Zheng Da <address@hidden>
diff --git a/eth-multiplexer/Makefile b/eth-multiplexer/Makefile
index 159f385..07f909e 100644
--- a/eth-multiplexer/Makefile
+++ b/eth-multiplexer/Makefile
@@ -26,8 +26,8 @@ MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
 device-MIGSFLAGS="-DMACH_PAYLOAD_TO_PORT=ports_payload_get_name"
 OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
 LCLHDRS = ethernet.h util.h vdev.h netfs_impl.h
-HURDLIBS = ihash iohelp ports fshelp shouldbeinlibc netfs bpf
-LDLIBS += -lpthread
+HURDLIBS = ports ihash fshelp shouldbeinlibc netfs bpf
+LDLIBS = -lpthread
 
 CFLAGS += -I$(top_srcdir)/libbpf
 
diff --git a/eth-multiplexer/README b/eth-multiplexer/README
index 0024a93..940c7e4 100644
--- a/eth-multiplexer/README
+++ b/eth-multiplexer/README
@@ -1,6 +1,6 @@
 [Introduction]
 
-eth-multiplexer is a network multiplexer. It creates virtual ethernet 
interface and dispatches the packet to the right user program that opens its 
virtual interface. It also works as a bridge to connect the real ethernet 
interface and the virtual ones. 
+eth-multiplexer is a network multiplexer. It creates virtual ethernet 
interface and dispatches the packet to the right user program that opens its 
virtual interface. It also works as a bridge to connect the real ethernet 
interface and the virtual ones.
 
 
 [Usage]
diff --git a/eth-multiplexer/demuxer.c b/eth-multiplexer/demuxer.c
index 68bf968..1efbc6d 100644
--- a/eth-multiplexer/demuxer.c
+++ b/eth-multiplexer/demuxer.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 1996, 2013 Free Software Foundation, Inc.
    Written by Michael I. Bushnell, p/BSG.
 
diff --git a/eth-multiplexer/dev_stat.c b/eth-multiplexer/dev_stat.c
index 43c68d6..bfbb433 100644
--- a/eth-multiplexer/dev_stat.c
+++ b/eth-multiplexer/dev_stat.c
@@ -1,25 +1,25 @@
- /* 
+ /*
   * Mach Operating System
   * Copyright (c) 1993-1989 Carnegie Mellon University
   * All Rights Reserved.
-  * 
+  *
   * Permission to use, copy, modify and distribute this software and its
   * documentation is hereby granted, provided that both the copyright
   * notice and this permission notice appear in all copies of the
   * software, derivative works or modified versions, and any portions
   * thereof, and that both notices appear in supporting documentation.
-  * 
+  *
   * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
-  * 
+  *
   * Carnegie Mellon requests users of this software to return to
-  * 
+  *
   *  Software Distribution Coordinator  or  address@hidden
   *  School of Computer Science
   *  Carnegie Mellon University
   *  Pittsburgh PA 15213-3890
-  * 
+  *
   * any improvements or extensions that they make and grant Carnegie Mellon
   * the rights to redistribute these changes.
   */
@@ -29,8 +29,8 @@
  *
  *     Network IO.
  *
- *     Packet filter code taken from vaxif/enet.c written               
- *             CMU and Stanford. 
+ *     Packet filter code taken from vaxif/enet.c written
+ *             CMU and Stanford.
  */
 
 /* the code copied from device/net_io.c in Mach */
@@ -81,7 +81,7 @@ dev_getstat(struct vether_device *ifp, dev_flavor_t flavor,
 
                                memcpy(status, ifp->if_address, 
addr_byte_count);
                                if (addr_byte_count < addr_int_count * 
sizeof(int))
-                                       memset((char *)status + 
addr_byte_count, 0, 
+                                       memset((char *)status + 
addr_byte_count, 0,
                                                        (addr_int_count * 
sizeof(int)
                                                         - addr_byte_count));
 
diff --git a/eth-multiplexer/device_impl.c b/eth-multiplexer/device_impl.c
index b15a009..4796d5b 100644
--- a/eth-multiplexer/device_impl.c
+++ b/eth-multiplexer/device_impl.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008 Free Software Foundation, Inc.
    Written by Zheng Da.
 
@@ -47,7 +47,7 @@ extern struct port_info *notify_pi;
 kern_return_t
 ds_device_open (mach_port_t master_port, mach_port_t reply_port,
                mach_msg_type_name_t reply_portPoly,
-               dev_mode_t mode, dev_name_t name, mach_port_t *device, 
+               dev_mode_t mode, dev_name_t name, mach_port_t *device,
                mach_msg_type_name_t *devicetype)
 {
   struct vether_device *dev;
@@ -178,16 +178,10 @@ kern_return_t
 ds_device_get_status (struct vether_device *vdev, dev_flavor_t flavor,
                      dev_status_t status, size_t *statuslen)
 {
-  extern io_return_t dev_getstat (struct vether_device *, dev_flavor_t,
-                                 dev_status_t, natural_t *);
-  kern_return_t ret = 0;
   if (vdev == NULL)
     return D_NO_SUCH_DEVICE;
-  if(ether_port != MACH_PORT_NULL)
-    ret = device_get_status (ether_port, flavor, status, statuslen);
-  else 
-    ret = dev_getstat (vdev, flavor, status, statuslen);
-  return ret;
+
+  return dev_getstat (vdev, flavor, status, statuslen);
 }
 
 kern_return_t
@@ -198,9 +192,9 @@ ds_device_set_filter (struct vether_device *vdev, 
mach_port_t receive_port,
   kern_return_t err;
   if (vdev == NULL)
     return D_NO_SUCH_DEVICE;
-  err = mach_port_request_notification (mach_task_self (), receive_port, 
+  err = mach_port_request_notification (mach_task_self (), receive_port,
                                        MACH_NOTIFY_DEAD_NAME, 0,
-                                       ports_get_right (notify_pi), 
+                                       ports_get_right (notify_pi),
                                        MACH_MSG_TYPE_MAKE_SEND_ONCE, &tmp);
   if (err != KERN_SUCCESS)
     goto out;
diff --git a/eth-multiplexer/ethernet.c b/eth-multiplexer/ethernet.c
index 886f5df..1f3a57c 100644
--- a/eth-multiplexer/ethernet.c
+++ b/eth-multiplexer/ethernet.c
@@ -2,7 +2,7 @@
    Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002, 2007, 2008
    Free Software Foundation, Inc.
 
-   Written by Zheng Da 
+   Written by Zheng Da
 
    Based on pfinet/ethernet.c, written by Michael I. Bushnell, p/BSG.
 
@@ -42,6 +42,10 @@ static struct port_info *readpt;
 
 /* Port for writing message to the real network interface. */
 mach_port_t ether_port;
+
+/* The ethernet address of the real network interface.  */
+char ether_address[ETH_ALEN];
+
 /* Port for receiving messages from the interface. */
 static mach_port_t readptname;
 
@@ -82,27 +86,45 @@ int set_promisc (char *dev_name, mach_port_t ether_port, 
int is_promisc)
 
   debug ("set_promisc is called, is_promisc: %d\n", is_promisc);
   count = 1;
-  ret = device_get_status (ether_port, NET_FLAGS, (dev_status_t) &flags, 
+  ret = device_get_status (ether_port, NET_FLAGS, (dev_status_t) &flags,
                            &count);
-  if (ret) 
+  if (ret)
     {
-      error (0, ret, "device_get_status");  
+      error (0, ret, "device_get_status");
       return -1;
-    }  
+    }
   if (is_promisc)
     flags |= IFF_PROMISC;
   else
     flags &= ~IFF_PROMISC;
   ret = device_set_status(ether_port, NET_FLAGS, (dev_status_t) &flags, 1);
-  if (ret) 
+  if (ret)
     {
       error (0, ret, "device_set_status");
       return -1;
-    }  
-  return 0;  
-} 
+    }
+  return 0;
+}
 
-int ethernet_open (char *dev_name, device_t master_device, 
+static error_t
+get_ethernet_address (mach_port_t port, char *address)
+{
+  error_t err;
+  int net_address[2];
+  size_t count = 2;
+  assert (count * sizeof (int) >= ETH_ALEN);
+
+  err = device_get_status (port, NET_ADDRESS, net_address, &count);
+  if (err)
+    return err;
+
+  net_address[0] = ntohl (net_address[0]);
+  net_address[1] = ntohl (net_address[1]);
+  memcpy (address, net_address, ETH_ALEN);
+  return 0;
+}
+
+int ethernet_open (char *dev_name, device_t master_device,
                   struct port_bucket *etherport_bucket,
                   struct port_class *etherreadclass)
 {
@@ -132,6 +154,11 @@ int ethernet_open (char *dev_name, device_t master_device,
     error (2, err, "device_set_filter: %s", dev_name);
 
   set_promisc (dev_name, ether_port, 1);
+
+  err = get_ethernet_address (ether_port, ether_address);
+  if (err)
+    error (2, err, "%s: Cannot get hardware Ethernet address", dev_name);
+
   return 0;
 }
 
diff --git a/eth-multiplexer/ethernet.h b/eth-multiplexer/ethernet.h
index 04b41e3..a2b2f5e 100644
--- a/eth-multiplexer/ethernet.h
+++ b/eth-multiplexer/ethernet.h
@@ -23,12 +23,14 @@
 #ifndef ETHERNET_H
 #define ETHERNET_H
 
+#include <mach.h>
+#include <net/if_ether.h>
 #include <netinet/in.h>
-#include <stdlib.h>
 
 extern mach_port_t ether_port;
+extern char ether_address[ETH_ALEN];
 
-int ethernet_open (char *dev_name, device_t master_device, 
+int ethernet_open (char *dev_name, device_t master_device,
                   struct port_bucket *etherport_bucket,
                   struct port_class *etherreadclass);
 int ethernet_close (char *dev_name);
diff --git a/eth-multiplexer/multiplexer.c b/eth-multiplexer/multiplexer.c
index cc0024e..9b661cd 100644
--- a/eth-multiplexer/multiplexer.c
+++ b/eth-multiplexer/multiplexer.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008 Free Software Foundation, Inc.
    Written by Zheng Da.
 
@@ -146,7 +146,7 @@ main (int argc, char *argv[])
     }
 
   /* Prepare for the notification. */
-  err = ports_create_port (other_portclass, port_bucket, 
+  err = ports_create_port (other_portclass, port_bucket,
                           sizeof (struct port_info), &notify_pi);
   if (err)
     error (1, err, "ports_create_port for notification");
@@ -172,7 +172,7 @@ main (int argc, char *argv[])
     error (5, err, "Cannot create root node");
 
   err = io_stat (root_file, &underlying_node_stat);
-  if (err) 
+  if (err)
     error (6, err, "Cannot stat underlying node");
 
   struct stat stat = underlying_node_stat;
diff --git a/eth-multiplexer/netfs_impl.c b/eth-multiplexer/netfs_impl.c
index 29ae072..040512a 100644
--- a/eth-multiplexer/netfs_impl.c
+++ b/eth-multiplexer/netfs_impl.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008, 2009 Free Software Foundation, Inc.
    Written by Zheng Da.
 
@@ -45,7 +45,7 @@
 
 extern struct stat underlying_node_stat;
 
-int 
+int
 is_num (char *str)
 {
   for (; *str; str++)
@@ -164,12 +164,12 @@ error_t
 netfs_validate_stat (struct node *node, struct iouser *cred)
 {
   struct stat st;
-  
+
   if (node->nn->ln)
     st = node->nn->ln->st;
   else
     st = underlying_node_stat;
-  
+
   debug("node: %p", node);
   node->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0;
   node->nn_stat = st;
diff --git a/eth-multiplexer/netfs_impl.h b/eth-multiplexer/netfs_impl.h
index 17c66f6..a3b4c7d 100644
--- a/eth-multiplexer/netfs_impl.h
+++ b/eth-multiplexer/netfs_impl.h
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008, 2009 Free Software Foundation, Inc.
    Written by Zheng Da.
 
diff --git a/eth-multiplexer/notify_impl.c b/eth-multiplexer/notify_impl.c
index 947069f..eef5544 100644
--- a/eth-multiplexer/notify_impl.c
+++ b/eth-multiplexer/notify_impl.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008 Free Software Foundation, Inc.
    Written by Zheng Da.
 
diff --git a/eth-multiplexer/test.c b/eth-multiplexer/test.c
index bf80583..7a4d63e 100644
--- a/eth-multiplexer/test.c
+++ b/eth-multiplexer/test.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008 Free Software Foundation, Inc.
    Written by Zheng Da.
 
diff --git a/eth-multiplexer/util.h b/eth-multiplexer/util.h
index c90b0f8..1e062c4 100644
--- a/eth-multiplexer/util.h
+++ b/eth-multiplexer/util.h
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008 Free Software Foundation, Inc.
    Written by Zheng Da.
 
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
+#include <net/if_ether.h>
 #include <netinet/ip.h>
 
 #include <mach.h>
@@ -56,15 +57,6 @@
   backtrace_symbols_fd(array, size, fileno (stderr));  \
 } while (0)
 
-#define ETH_ALEN 6             /* Octets in one ethernet addr   */
-
-struct ethhdr 
-{
-  unsigned char        h_dest[ETH_ALEN];       /* destination eth addr */
-  unsigned char        h_source[ETH_ALEN];     /* source ether addr    */
-  unsigned short h_proto;              /* packet type ID field */
-};
-
 static inline void
 print_pack (char *packet, int len)
 {
@@ -75,13 +67,13 @@ print_pack (char *packet, int len)
   char src_str[INET_ADDRSTRLEN];
   char dst_str[INET_ADDRSTRLEN];
   if (ntohs (ethh->h_proto) == ETH_P_IP
-      && len >= sizeof (struct ethhdr) + sizeof (struct iphdr)) 
+      && len >= sizeof (struct ethhdr) + sizeof (struct iphdr))
     {
       debug ("multiplexer: get a IP packet from %s to %s\n",
             inet_ntop (AF_INET, &iph->saddr, src_str, INET_ADDRSTRLEN),
             inet_ntop (AF_INET, &iph->daddr, dst_str, INET_ADDRSTRLEN));
     }
-  else 
+  else
     {
       debug ("multiplexer: get a non-IP packet\n");
     }
diff --git a/eth-multiplexer/vdev.c b/eth-multiplexer/vdev.c
index fd88661..47dc8d2 100644
--- a/eth-multiplexer/vdev.c
+++ b/eth-multiplexer/vdev.c
@@ -22,20 +22,22 @@
 
 #include <string.h>
 #include <stdio.h>
+#include <net/if_ether.h>
 #include <netinet/ip.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <stdlib.h>
 #include <error.h>
+#include <hurd/ihash.h>
 
 #include <pthread.h>
 
 #include "vdev.h"
+#include "ethernet.h"
 #include "queue.h"
 #include "bpf_impl.h"
 #include "util.h"
 
-#define ETH_HLEN sizeof (struct ethhdr)
 
 static struct vether_device *dev_head;
 static int dev_num;
@@ -44,7 +46,7 @@ static int dev_num;
  * TODO every device structure should has its own lock to protect itself. */
 static pthread_mutex_t dev_list_lock = PTHREAD_MUTEX_INITIALIZER;
 
-mach_msg_type_t header_type = 
+mach_msg_type_t header_type =
 {
   MACH_MSG_TYPE_BYTE,
   8,
@@ -55,7 +57,7 @@ mach_msg_type_t header_type =
   0
 };
 
-mach_msg_type_t packet_type = 
+mach_msg_type_t packet_type =
 {
   MACH_MSG_TYPE_BYTE,  /* name */
   8,                   /* size */
@@ -105,7 +107,7 @@ foreach_dev_do (int (func) (struct vether_device *))
 }
 
 /* Remove all filters with the dead name. */
-int 
+int
 remove_dead_port_from_dev (mach_port_t dead_port)
 {
   struct vether_device *vdev;
@@ -123,10 +125,11 @@ remove_dead_port_from_dev (mach_port_t dead_port)
 
 /* Add a new virtual interface to the multiplexer. */
 struct vether_device *
-add_vdev (char *name, int size, 
+add_vdev (char *name, int size,
          struct port_class *class, struct port_bucket *bucket)
 {
   error_t err;
+  uint32_t hash;
   struct vether_device *vdev;
 
   if (size < sizeof (*vdev))
@@ -143,9 +146,13 @@ add_vdev (char *name, int size,
   vdev->if_header_format = HDR_ETHERNET;
   vdev->if_address_size = ETH_ALEN;
   vdev->if_flags = 0;
+
+  /* Compute a pseudo-random but stable ethernet address.  */
   vdev->if_address[0] = 0x52;
   vdev->if_address[1] = 0x54;
-  *(int *)(vdev->if_address + 2) = random ();
+  hash = hurd_ihash_hash32 (ether_address, ETH_ALEN, 0);
+  hash = hurd_ihash_hash32 (name, strlen (name), hash);
+  memcpy (&vdev->if_address[2], &hash, 4);
 
   queue_init (&vdev->port_list.if_rcv_port_list);
   queue_init (&vdev->port_list.if_snd_port_list);
@@ -191,7 +198,7 @@ has_vdev ()
 
 /* Broadcast the packet to all virtual interfaces
  * except the one the packet is from */
-int 
+int
 broadcast_pack (char *data, int datalen, struct vether_device *from_vdev)
 {
   int internal_deliver_pack (struct vether_device *vdev)
@@ -205,7 +212,7 @@ broadcast_pack (char *data, int datalen, struct 
vether_device *from_vdev)
 }
 
 /* Create a message, and deliver it. */
-int 
+int
 deliver_pack (char *data, int datalen, struct vether_device *vdev)
 {
   struct net_rcv_msg msg;
@@ -232,7 +239,7 @@ deliver_pack (char *data, int datalen, struct vether_device 
*vdev)
 }
 
 /* Broadcast the message to all virtual interfaces. */
-int 
+int
 broadcast_msg (struct net_rcv_msg *msg)
 {
   int rval = 0;
@@ -268,7 +275,7 @@ deliver_msg(struct net_rcv_msg *msg, struct vether_device 
*vdev)
   msg->msg_hdr.msgh_id = NET_RCV_MSG_ID;
 
   if_port_list = &vdev->port_list.if_rcv_port_list;
-  FILTER_ITERATE (if_port_list, infp, nextfp, &infp->input) 
+  FILTER_ITERATE (if_port_list, infp, nextfp, &infp->input)
     {
       mach_port_t dest;
       net_hash_entry_t entp, *hash_headp;
@@ -284,7 +291,7 @@ deliver_msg(struct net_rcv_msg *msg, struct vether_device 
*vdev)
       else
        dest = entp->rcv_port;
 
-      if (ret_count) 
+      if (ret_count)
        {
          debug ("before delivering the packet\n");
          msg->msg_hdr.msgh_remote_port = dest;
@@ -297,7 +304,6 @@ deliver_msg(struct net_rcv_msg *msg, struct vether_device 
*vdev)
              mach_port_deallocate(mach_task_self (),
                                   ((mach_msg_header_t 
*)msg)->msgh_remote_port);
              error (0, err, "mach_msg");
-             return -1;
            }
          debug ("after delivering the packet\n");
        }
diff --git a/eth-multiplexer/vdev.h b/eth-multiplexer/vdev.h
index c869678..c98c441 100644
--- a/eth-multiplexer/vdev.h
+++ b/eth-multiplexer/vdev.h
@@ -76,4 +76,9 @@ int broadcast_msg (struct net_rcv_msg *msg);
 int get_dev_num ();
 int foreach_dev_do (dev_act_func func);
 
+/* dev_stat.c */
+io_return_t dev_getstat (struct vether_device *, dev_flavor_t,
+                         dev_status_t, natural_t *);
+
+
 #endif
diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
index 1ead6d2..4f38c92 100644
--- a/ext2fs/ext2fs.c
+++ b/ext2fs/ext2fs.c
@@ -55,6 +55,9 @@ struct store *store;
 struct store_parsed *store_parsed;
 
 char *diskfs_disk_name;
+
+pthread_spinlock_t global_lock = PTHREAD_SPINLOCK_INITIALIZER;
+pthread_spinlock_t modified_global_blocks_lock = PTHREAD_SPINLOCK_INITIALIZER;
 
 #ifdef EXT2FS_DEBUG
 int ext2_debug_flag;
diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h
index afcd25c..a3d22b2 100644
--- a/ext2fs/ext2fs.h
+++ b/ext2fs/ext2fs.h
@@ -433,7 +433,7 @@ void write_all_disknodes ();
 
 /* What to lock if changing global data data (e.g., the superblock or block
    group descriptors or bitmaps).  */
-pthread_spinlock_t global_lock;
+extern pthread_spinlock_t global_lock;
 
 /* Where to record such changes.  */
 struct pokel global_pokel;
@@ -442,7 +442,7 @@ struct pokel global_pokel;
    record which disk blocks are actually modified, so we don't stomp on parts
    of the disk which are backed by file pagers.  */
 unsigned char *modified_global_blocks;
-pthread_spinlock_t modified_global_blocks_lock;
+extern pthread_spinlock_t modified_global_blocks_lock;
 
 extern int global_block_modified (block_t block);
 extern void record_global_poke (void *ptr);
diff --git a/libbpf/Makefile b/libbpf/Makefile
index 8b02a2a..0a7ba90 100644
--- a/libbpf/Makefile
+++ b/libbpf/Makefile
@@ -23,9 +23,11 @@ SRCS= bpf_impl.c queue.c
 LCLHDRS = bpf_impl.h queue.h
 installhdrs = bpf_impl.h queue.h
 
-MIGSTUBS = 
+MIGSTUBS =
 OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
 
+LDLIBS = -lpthread
+
 MIGCOMSFLAGS =
 
 include ../Makeconf
diff --git a/libbpf/bpf_impl.c b/libbpf/bpf_impl.c
index c8a250b..03a2a53 100644
--- a/libbpf/bpf_impl.c
+++ b/libbpf/bpf_impl.c
@@ -1,25 +1,25 @@
- /* 
+ /*
   * Mach Operating System
   * Copyright (c) 1993-1989 Carnegie Mellon University
   * All Rights Reserved.
-  * 
+  *
   * Permission to use, copy, modify and distribute this software and its
   * documentation is hereby granted, provided that both the copyright
   * notice and this permission notice appear in all copies of the
   * software, derivative works or modified versions, and any portions
   * thereof, and that both notices appear in supporting documentation.
-  * 
+  *
   * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
-  * 
+  *
   * Carnegie Mellon requests users of this software to return to
-  * 
+  *
   *  Software Distribution Coordinator  or  address@hidden
   *  School of Computer Science
   *  Carnegie Mellon University
   *  Pittsburgh PA 15213-3890
-  * 
+  *
   * any improvements or extensions that they make and grant Carnegie Mellon
   * the rights to redistribute these changes.
   */
@@ -29,8 +29,8 @@
  *
  *     Network IO.
  *
- *     Packet filter code taken from vaxif/enet.c written               
- *             CMU and Stanford. 
+ *     Packet filter code taken from vaxif/enet.c written
+ *             CMU and Stanford.
  */
 
 /* the code copied from device/net_io.c in Mach */
@@ -58,7 +58,7 @@ static struct net_hash_header filter_hash_header[N_NET_HASH];
  */
 
 int
-bpf_do_filter(net_rcv_port_t infp, char *p,    unsigned int wirelen, 
+bpf_do_filter(net_rcv_port_t infp, char *p,    unsigned int wirelen,
                char *header, unsigned int hlen, net_hash_entry_t **hash_headpp,
                net_hash_entry_t *entpp)
 {
@@ -340,9 +340,9 @@ load_byte:
  * instruction. Return 2 if it is a valid filter program with a MATCH
  * instruction. Otherwise, return 0.
  * The constraints are that each jump be forward and to a valid
- * code.  The code must terminate with either an accept or reject. 
+ * code.  The code must terminate with either an accept or reject.
  * 'valid' is an array for use by the routine (it must be at least
- * 'len' bytes long).  
+ * 'len' bytes long).
  *
  * The kernel needs to be able to verify an application's filter code.
  * Otherwise, a bogus program could easily crash the system.
@@ -362,7 +362,7 @@ bpf_validate(bpf_insn_t f, int bytes, bpf_insn_t *match)
 
        for (i = 1; i < len; ++i) {
                /*
-                * Check that that jumps are forward, and within 
+                * Check that that jumps are forward, and within
                 * the code block.
                 */
                p = &f[i];
@@ -380,7 +380,7 @@ bpf_validate(bpf_insn_t f, int bytes, bpf_insn_t *match)
                 * Check that memory operations use valid addresses.
                 */
                if ((BPF_CLASS(p->code) == BPF_ST ||
-                                       (BPF_CLASS(p->code) == BPF_LD && 
+                                       (BPF_CLASS(p->code) == BPF_LD &&
                                         (p->code & 0xe0) == BPF_MEM)) &&
                                (p->k >= BPF_MEMWORDS || p->k < 0)) {
                        return 0;
@@ -534,7 +534,7 @@ net_free_dead_infp (queue_entry_t dead_infp)
                mach_port_deallocate(mach_task_self(), infp->rcv_port);
                free(infp);
                debug ("a dead infp is freed\n");
-       }           
+       }
 }
 
 /*
@@ -657,7 +657,7 @@ net_set_filter(if_filter_list_t *ifp, mach_port_t rcv_port, 
int priority,
                                        do {
                                                nextentp = (net_hash_entry_t) 
entp->he_next;
 
-                                               /* checked without 
+                                               /* checked without
                                                   ip_lock(entp->rcv_port) */
                                                if (entp->rcv_port == rcv_port) 
{
                                                        ret = hash_ent_remove 
(ifp,
@@ -825,7 +825,7 @@ remove_dead_filter (if_filter_list_t *ifp, queue_head_t 
*if_port_list,
                                do {
                                        nextentp = (net_hash_entry_t) 
entp->he_next;
 
-                                       /* checked without 
+                                       /* checked without
                                           ip_lock(entp->rcv_port) */
                                        if (entp->rcv_port == dead_port) {
                                                ret = hash_ent_remove (ifp,
diff --git a/libbpf/bpf_impl.h b/libbpf/bpf_impl.h
index 9073fda..2b092b7 100644
--- a/libbpf/bpf_impl.h
+++ b/libbpf/bpf_impl.h
@@ -1,25 +1,25 @@
- /* 
+ /*
   * Mach Operating System
   * Copyright (c) 1993-1989 Carnegie Mellon University
   * All Rights Reserved.
-  * 
+  *
   * Permission to use, copy, modify and distribute this software and its
   * documentation is hereby granted, provided that both the copyright
   * notice and this permission notice appear in all copies of the
   * software, derivative works or modified versions, and any portions
   * thereof, and that both notices appear in supporting documentation.
-  * 
+  *
   * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
-  * 
+  *
   * Carnegie Mellon requests users of this software to return to
-  * 
+  *
   *  Software Distribution Coordinator  or  address@hidden
   *  School of Computer Science
   *  Carnegie Mellon University
   *  Pittsburgh PA 15213-3890
-  * 
+  *
   * any improvements or extensions that they make and grant Carnegie Mellon
   * the rights to redistribute these changes.
   */
@@ -29,8 +29,8 @@
  *
  *     Network IO.
  *
- *     Packet filter code taken from vaxif/enet.c written               
- *             CMU and Stanford. 
+ *     Packet filter code taken from vaxif/enet.c written
+ *             CMU and Stanford.
  */
 
 /* the code copied from device/net_io.c in Mach */
@@ -125,7 +125,7 @@ typedef struct net_hash_entry *net_hash_entry_t;
  * This structure represents a packet filter with multiple sessions.
  *
  * For example, all application level TCP sessions might be
- * represented by one of these structures.  It looks like a 
+ * represented by one of these structures.  It looks like a
  * net_rcv_port struct so that both types can live on the
  * same packet filter queues.
  */
@@ -138,7 +138,7 @@ struct net_hash_header {
 
 typedef struct net_hash_header *net_hash_header_t;
 
-int bpf_do_filter(net_rcv_port_t infp, char *p,        unsigned int wirelen, 
+int bpf_do_filter(net_rcv_port_t infp, char *p,        unsigned int wirelen,
                char *header, unsigned int hlen, net_hash_entry_t **hash_headpp,
                net_hash_entry_t *entpp);
 io_return_t net_set_filter(if_filter_list_t *ifp, mach_port_t rcv_port,
@@ -154,7 +154,7 @@ int hash_ent_remove (if_filter_list_t *ifp, 
net_hash_header_t hp, int used,
                net_hash_entry_t *head, net_hash_entry_t entp, queue_entry_t 
*dead_p);
 void net_free_dead_infp (queue_entry_t dead_infp);
 void net_free_dead_entp (queue_entry_t dead_entp);
-void remove_dead_filter (if_filter_list_t *ifp, 
+void remove_dead_filter (if_filter_list_t *ifp,
                queue_head_t *if_port_list, mach_port_t dead_port);
 void destroy_filters (if_filter_list_t *ifp);
 
diff --git a/libbpf/queue.c b/libbpf/queue.c
index a43a21b..3323434 100644
--- a/libbpf/queue.c
+++ b/libbpf/queue.c
@@ -1,25 +1,25 @@
-/* 
+/*
  * Mach Operating System
  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
  * All Rights Reserved.
- * 
+ *
  * Permission to use, copy, modify and distribute this software and its
  * documentation is hereby granted, provided that both the copyright
  * notice and this permission notice appear in all copies of the
  * software, derivative works or modified versions, and any portions
  * thereof, and that both notices appear in supporting documentation.
- * 
+ *
  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- * 
+ *
  * Carnegie Mellon requests users of this software to return to
- * 
+ *
  *  Software Distribution Coordinator  or  address@hidden
  *  School of Computer Science
  *  Carnegie Mellon University
  *  Pittsburgh PA 15213-3890
- * 
+ *
  * any improvements or extensions that they make and grant Carnegie Mellon
  * the rights to redistribute these changes.
  */
diff --git a/libbpf/util.h b/libbpf/util.h
index c90b0f8..b062638 100644
--- a/libbpf/util.h
+++ b/libbpf/util.h
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2008 Free Software Foundation, Inc.
    Written by Zheng Da.
 
@@ -58,7 +58,7 @@
 
 #define ETH_ALEN 6             /* Octets in one ethernet addr   */
 
-struct ethhdr 
+struct ethhdr
 {
   unsigned char        h_dest[ETH_ALEN];       /* destination eth addr */
   unsigned char        h_source[ETH_ALEN];     /* source ether addr    */
@@ -75,13 +75,13 @@ print_pack (char *packet, int len)
   char src_str[INET_ADDRSTRLEN];
   char dst_str[INET_ADDRSTRLEN];
   if (ntohs (ethh->h_proto) == ETH_P_IP
-      && len >= sizeof (struct ethhdr) + sizeof (struct iphdr)) 
+      && len >= sizeof (struct ethhdr) + sizeof (struct iphdr))
     {
       debug ("multiplexer: get a IP packet from %s to %s\n",
             inet_ntop (AF_INET, &iph->saddr, src_str, INET_ADDRSTRLEN),
             inet_ntop (AF_INET, &iph->daddr, dst_str, INET_ADDRSTRLEN));
     }
-  else 
+  else
     {
       debug ("multiplexer: get a non-IP packet\n");
     }
diff --git a/libdiskfs/Makefile b/libdiskfs/Makefile
index 803761d..93c96fa 100644
--- a/libdiskfs/Makefile
+++ b/libdiskfs/Makefile
@@ -40,8 +40,8 @@ IFSOCKSRCS=ifsock.c
 OTHERSRCS = conch-fetch.c conch-set.c dir-clear.c dir-init.c dir-renamed.c \
        extern-inline.c \
        node-create.c node-drop.c node-make.c node-rdwr.c node-update.c \
-       node-nref.c node-nput.c node-nrele.c node-nrefl.c node-nputl.c \
-       node-nrelel.c node-cache.c \
+       node-nref.c node-nput.c node-nrele.c node-lastref.c node-nrefl.c \
+       node-nputl.c node-nrelel.c node-cache.c \
        peropen-make.c peropen-rele.c protid-make.c protid-rele.c \
        init-init.c init-startup.c init-first.c init-main.c \
        rdwr-internal.c boot-start.c demuxer.c node-times.c shutdown.c \
diff --git a/libdiskfs/file-utimes.c b/libdiskfs/file-utimes.c
index 39fac50..29839fc 100644
--- a/libdiskfs/file-utimes.c
+++ b/libdiskfs/file-utimes.c
@@ -28,6 +28,9 @@ diskfs_S_file_utimes (struct protid *cred,
                   ({
                     if (!(err = fshelp_isowner (&np->dn_stat, cred->user)))
                       {
+                        /* Flush pending updates first.  */
+                        diskfs_set_node_times (np);
+
                         if (atime.microseconds == -1)
                           np->dn_set_atime = 1;
                         else
diff --git a/libdiskfs/io-stubs.c b/libdiskfs/io-stubs.c
index 592b3d8..103591f 100644
--- a/libdiskfs/io-stubs.c
+++ b/libdiskfs/io-stubs.c
@@ -23,7 +23,7 @@
 /* Implement io_readsleep as described in <hurd/io.defs>
    Semantics of ordinary files say this shouldn't happen, because
    we never set use_read_size in the shared data. */
-kern_return_t
+kern_return_t __attribute__((weak))
 diskfs_S_io_readsleep (struct protid *cred)
 {
   if (!cred)
@@ -34,7 +34,7 @@ diskfs_S_io_readsleep (struct protid *cred)
 
 /* Implement io_eofnotify as described in <hurd/io.defs>. 
    We don't use this feature. */
-kern_return_t
+kern_return_t __attribute__((weak))
 diskfs_S_io_eofnotify (struct protid *cred)
 {
   if (!cred)
@@ -45,7 +45,7 @@ diskfs_S_io_eofnotify (struct protid *cred)
 
 /* Implement io_postnotify as described in <hurd/io.defs>.
    We don't use this feature. */
-kern_return_t
+kern_return_t __attribute__((weak))
 diskfs_S_io_postnotify (struct protid *cred,
                        vm_offset_t start __attribute__ ((unused)), 
                        vm_offset_t end __attribute__ ((unused)))
@@ -55,7 +55,7 @@ diskfs_S_io_postnotify (struct protid *cred,
 
 /* Implement io_readnotify as described in <hurd/io.defs>.
    We don't use this feature. */
-kern_return_t
+kern_return_t __attribute__((weak))
 diskfs_S_io_readnotify (struct protid *cred)
 {
   return cred ? 0 : EOPNOTSUPP;
diff --git a/libdiskfs/node-lastref.c b/libdiskfs/node-lastref.c
new file mode 100644
index 0000000..068566a
--- /dev/null
+++ b/libdiskfs/node-lastref.c
@@ -0,0 +1,49 @@
+/*
+   Copyright (C) 1999 Free Software Foundation, Inc.
+   Written by Thomas Bushnell, BSG.
+
+   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., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+#include "priv.h"
+
+/* Called when the last hard reference is released.  If there are no
+   links, then request soft references to be dropped.  */
+void
+_diskfs_lastref (struct node *np)
+{
+  /* This is our cue that something akin to "last process closes file"
+     in the POSIX.1 sense happened, so make sure any pending node time
+     updates now happen in a timely fashion.  */
+  diskfs_set_node_times (np);
+  diskfs_lost_hardrefs (np);
+  if (!np->dn_stat.st_nlink)
+    {
+      if (np->sockaddr != MACH_PORT_NULL)
+       {
+         mach_port_deallocate (mach_task_self (), np->sockaddr);
+         np->sockaddr = MACH_PORT_NULL;
+       }
+
+      /* There are no links.  If there are soft references that
+        can be dropped, we can't let them postpone deallocation.
+        So attempt to drop them.  But that's a user-supplied
+        routine, which might result in further recursive calls to
+        the ref-counting system.  This is not a problem, as we
+        hold a weak reference ourselves. */
+      diskfs_try_dropping_softrefs (np);
+    }
+}
diff --git a/libdiskfs/node-nput.c b/libdiskfs/node-nput.c
index d59769b..73f6b2c 100644
--- a/libdiskfs/node-nput.c
+++ b/libdiskfs/node-nput.c
@@ -34,29 +34,7 @@ diskfs_nput (struct node *np)
   refcounts_demote (&np->refcounts, &result);
 
   if (result.hard == 0)
-    {
-      /* This is our cue that something akin to "last process closes file"
-        in the POSIX.1 sense happened, so make sure any pending node time
-        updates now happen in a timely fashion.  */
-      diskfs_set_node_times (np);
-      diskfs_lost_hardrefs (np);
-      if (!np->dn_stat.st_nlink)
-       {
-         if (np->sockaddr != MACH_PORT_NULL)
-           {
-             mach_port_deallocate (mach_task_self (), np->sockaddr);
-             np->sockaddr = MACH_PORT_NULL;
-           }
-
-         /* There are no links.  If there are soft references that
-            can be dropped, we can't let them postpone deallocation.
-            So attempt to drop them.  But that's a user-supplied
-            routine, which might result in further recursive calls to
-            the ref-counting system.  This is not a problem, as we
-            hold a weak reference ourselves. */
-         diskfs_try_dropping_softrefs (np);
-       }
-    }
+    _diskfs_lastref (np);
 
   /* Finally get rid of our reference.  */
   refcounts_deref_weak (&np->refcounts, &result);
diff --git a/libdiskfs/node-nrele.c b/libdiskfs/node-nrele.c
index a96d134..6b7b707 100644
--- a/libdiskfs/node-nrele.c
+++ b/libdiskfs/node-nrele.c
@@ -40,17 +40,7 @@ diskfs_nrele (struct node *np)
     {
       locked = TRUE;
       pthread_mutex_lock (&np->lock);
-      diskfs_lost_hardrefs (np);
-      if (!np->dn_stat.st_nlink)
-       {
-         /* There are no links.  If there are soft references that
-            can be dropped, we can't let them postpone deallocation.
-            So attempt to drop them.  But that's a user-supplied
-            routine, which might result in further recursive calls to
-            the ref-counting system.  This is not a problem, as we
-            hold a weak reference ourselves. */
-         diskfs_try_dropping_softrefs (np);
-       }
+      _diskfs_lastref (np);
     }
 
   /* Finally get rid of our reference.  */
diff --git a/libdiskfs/priv.h b/libdiskfs/priv.h
index 2ac3c9e..276d093 100644
--- a/libdiskfs/priv.h
+++ b/libdiskfs/priv.h
@@ -96,6 +96,10 @@ void _diskfs_boot_privports (void);
 /* Clean routine for control port. */
 void _diskfs_control_clean (void *);
 
+/* Called when the last hard reference is released.  If there are no
+   links, then request soft references to be dropped.  */
+void _diskfs_lastref (struct node *np);
+
 /* Number of outstanding PT_CTL ports. */
 extern int _diskfs_ncontrol_ports;
 
diff --git a/libnetfs/fsstubs.c b/libnetfs/fsstubs.c
index 75bd790..b260f5d 100644
--- a/libnetfs/fsstubs.c
+++ b/libnetfs/fsstubs.c
@@ -23,21 +23,21 @@
 #include "fs_S.h"
 #include "ifsock_S.h"
 
-error_t
+error_t __attribute__((weak))
 netfs_S_file_notice_changes (struct protid *user,
                             mach_port_t port)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_file_getfh (struct protid *user,
                    char **data, mach_msg_type_number_t *ndata)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_ifsock_getsockaddr (struct protid *user,
                            mach_port_t *address)
 {
diff --git a/libnetfs/fsysstubs.c b/libnetfs/fsysstubs.c
index a64fd64..6cf12cc 100644
--- a/libnetfs/fsysstubs.c
+++ b/libnetfs/fsysstubs.c
@@ -22,7 +22,7 @@
 #include "netfs.h"
 #include "fsys_S.h"
 
-error_t
+error_t __attribute__((weak))
 netfs_S_fsys_getfile (struct netfs_control *cntl,
                      mach_port_t reply,
                      mach_msg_type_name_t reply_type,
@@ -34,7 +34,7 @@ netfs_S_fsys_getfile (struct netfs_control *cntl,
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_fsys_getpriv (struct netfs_control *cntl,
                      mach_port_t reply,
                      mach_msg_type_name_t reply_type,
@@ -45,7 +45,7 @@ netfs_S_fsys_getpriv (struct netfs_control *cntl,
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_fsys_init (struct netfs_control *cntl,
                   mach_port_t reply,
                   mach_msg_type_name_t reply_type,
@@ -54,7 +54,7 @@ netfs_S_fsys_init (struct netfs_control *cntl,
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_fsys_forward (mach_port_t cntl,
                      mach_port_t reply,
                      mach_msg_type_name_t reply_type,
@@ -64,7 +64,7 @@ netfs_S_fsys_forward (mach_port_t cntl,
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_fsys_startup (mach_port_t bootstrap,
                      mach_port_t reply,
                      mach_msg_type_name_t reply_type,
diff --git a/libnetfs/iostubs.c b/libnetfs/iostubs.c
index 1465b43..a5ff450 100644
--- a/libnetfs/iostubs.c
+++ b/libnetfs/iostubs.c
@@ -22,7 +22,7 @@
 #include "netfs.h"
 #include "io_S.h"
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_map (struct protid *user, 
                mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype,
                mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype)
@@ -30,7 +30,7 @@ netfs_S_io_map (struct protid *user,
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_map_cntl (struct protid *user,
                     mach_port_t *obj,
                     mach_msg_type_name_t *objtype)
@@ -38,51 +38,51 @@ netfs_S_io_map_cntl (struct protid *user,
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_get_conch (struct protid *user)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_release_conch (struct protid *user)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_eofnotify (struct protid *user)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_prenotify (struct protid *user,
                      vm_offset_t start, vm_offset_t stop)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_postnotify (struct protid *user,
                       vm_offset_t start, vm_offset_t stop)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_readnotify (struct protid *user)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_readsleep (struct protid *user)
 {
   return EOPNOTSUPP;
 }
 
-error_t
+error_t __attribute__((weak))
 netfs_S_io_sigio (struct protid *user)
 {
   return EOPNOTSUPP;
diff --git a/libpager/data-unlock.c b/libpager/data-unlock.c
index 8c9680c..077e673 100644
--- a/libpager/data-unlock.c
+++ b/libpager/data-unlock.c
@@ -73,7 +73,7 @@ _pager_S_memory_object_data_unlock (struct pager *p,
       /* Flush the page, and set a bit so that m_o_data_request knows
         to issue an error.  */
       _pager_lock_object (p, offset, length, MEMORY_OBJECT_RETURN_NONE, 1,
-                         VM_PROT_WRITE, 1);
+                         VM_PROT_WRITE, 0);
       _pager_mark_next_request_error (p, offset, length, err);
     }
  out:
diff --git a/libpager/stubs.c b/libpager/stubs.c
index 9a766ec..964985b 100644
--- a/libpager/stubs.c
+++ b/libpager/stubs.c
@@ -20,7 +20,7 @@
 #include "memory_object_S.h"
 #include <stdio.h>
 
-kern_return_t
+kern_return_t __attribute__((weak))
 _pager_S_memory_object_copy (struct pager *p,
                           memory_object_control_t obj_ctl,
                           vm_offset_t off,
@@ -31,7 +31,7 @@ _pager_S_memory_object_copy (struct pager *p,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 _pager_S_memory_object_data_write (struct pager *p,
                                 mach_port_t ctl,
                                 vm_offset_t off,
@@ -42,7 +42,7 @@ _pager_S_memory_object_data_write (struct pager *p,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 _pager_S_memory_object_supply_completed (struct pager *p,
                                       mach_port_t ctl,
                                       vm_offset_t off,
diff --git a/libtreefs/xinl.c b/libtreefs/xinl.c
index fe83e5a..ca7073a 100644
--- a/libtreefs/xinl.c
+++ b/libtreefs/xinl.c
@@ -1,3 +1,5 @@
 #define TREEFS_DEFINE_EI
 #include "treefs.h"
 #include "mig-decls.h"
+
+pthread_spinlock_t treefs_node_refcnt_lock = PTHREAD_SPINLOCK_INITIALIZER;
diff --git a/libtrivfs/fsys-stubs.c b/libtrivfs/fsys-stubs.c
index 313328a..44d411c 100644
--- a/libtrivfs/fsys-stubs.c
+++ b/libtrivfs/fsys-stubs.c
@@ -22,7 +22,7 @@
 #include "priv.h"
 #include "trivfs_fsys_S.h"
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_fsys_startup (mach_port_t bootport,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype,
@@ -34,7 +34,7 @@ trivfs_S_fsys_startup (mach_port_t bootport,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_fsys_getpriv (struct trivfs_control *cntl,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype,
@@ -45,7 +45,7 @@ trivfs_S_fsys_getpriv (struct trivfs_control *cntl,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_fsys_init (struct trivfs_control *control,
                    mach_port_t reply,
                    mach_msg_type_name_t replytype,
@@ -55,7 +55,7 @@ trivfs_S_fsys_init (struct trivfs_control *control,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_fsys_getfile (struct trivfs_control *cntl,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype,
diff --git a/libtrivfs/io-stubs.c b/libtrivfs/io-stubs.c
index ab6b1b3..1686f3f 100644
--- a/libtrivfs/io-stubs.c
+++ b/libtrivfs/io-stubs.c
@@ -22,7 +22,7 @@
 #include "priv.h"
 #include "trivfs_io_S.h"
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_map_cntl (struct trivfs_protid *cred,
                      mach_port_t reply,
                      mach_msg_type_name_t replytype,
@@ -32,7 +32,7 @@ trivfs_S_io_map_cntl (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_get_conch (struct trivfs_protid *cred,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype)
@@ -40,7 +40,7 @@ trivfs_S_io_get_conch (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_release_conch (struct trivfs_protid *cred,
                           mach_port_t reply,
                           mach_msg_type_name_t replytype)
@@ -48,7 +48,7 @@ trivfs_S_io_release_conch (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_eofnotify (struct trivfs_protid *cred,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype)
@@ -56,7 +56,7 @@ trivfs_S_io_eofnotify (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_prenotify (struct trivfs_protid *cred,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype,
@@ -66,7 +66,7 @@ trivfs_S_io_prenotify (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_postnotify (struct trivfs_protid *cred,
                        mach_port_t reply,
                        mach_msg_type_name_t replytype,
@@ -76,7 +76,7 @@ trivfs_S_io_postnotify (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_readsleep (struct trivfs_protid *cred,
                       mach_port_t reply,
                       mach_msg_type_name_t replytype)
@@ -84,7 +84,7 @@ trivfs_S_io_readsleep (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_sigio (struct trivfs_protid *cred,
                   mach_port_t reply,
                   mach_msg_type_name_t replytype)
@@ -92,7 +92,7 @@ trivfs_S_io_sigio (struct trivfs_protid *cred,
   return EOPNOTSUPP;
 }
 
-kern_return_t
+kern_return_t __attribute__((weak))
 trivfs_S_io_readnotify (struct trivfs_protid *cred,
                     mach_port_t reply,
                     mach_msg_type_name_t replytype)
diff --git a/mach-defpager/main.c b/mach-defpager/main.c
index e33c2b3..71615c8 100644
--- a/mach-defpager/main.c
+++ b/mach-defpager/main.c
@@ -104,9 +104,11 @@ main (int argc, char **argv)
         exitting, and the child sends that signal after it is set up.  */
       sigset_t set;
       signal (SIGUSR1, nohandler);
+      signal (SIGCHLD, nohandler);
       sigemptyset (&set);
       sigaddset (&set, SIGUSR1);
-      sigprocmask (SIG_BLOCK, &set, 0);
+      sigaddset (&set, SIGCHLD);
+      sigprocmask (SIG_SETMASK, &set, NULL);
       switch (fork ())
        {
        case -1:
diff --git a/proc/mgt.c b/proc/mgt.c
index cb442b0..8dc82f1 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -41,6 +41,7 @@
 #include "mutated_ourmsg_U.h"
 #include "proc_exc_S.h"
 #include "proc_exc_U.h"
+#include "task_notify_S.h"
 #include <hurd/signal.h>
 
 /* Create a new id structure with the given genuine uids and gids. */
@@ -1048,13 +1049,13 @@ S_proc_get_code (struct proc *callerp,
 
 /* Handle new task notifications from the kernel.  */
 error_t
-S_mach_notify_new_task (mach_port_t notify,
+S_mach_notify_new_task (struct port_info *notify,
                        mach_port_t task,
                        mach_port_t parent)
 {
   struct proc *parentp, *childp;
 
-  if (notify != generic_port)
+  if (! notify || notify->class != generic_port_class)
     return EOPNOTSUPP;
 
   parentp = task_find_nocreate (parent);
@@ -1079,9 +1080,10 @@ S_mach_notify_new_task (mach_port_t notify,
         proc_child, so we do it on their behalf.  */
       mach_port_mod_refs (mach_task_self (), task, MACH_PORT_RIGHT_SEND, +1);
       err = S_proc_child (parentp, task);
-      if (! err)
-       /* Relay the notification.  This consumes TASK and PARENT.  */
-       return mach_notify_new_task (childp->p_task_namespace, task, parent);
+      assert_perror (err);
+
+      /* Relay the notification.  This consumes task and parent.  */
+      return mach_notify_new_task (childp->p_task_namespace, task, parent);
     }
 
   mach_port_deallocate (mach_task_self (), task);
diff --git a/proc/mig-mutate.h b/proc/mig-mutate.h
index 62dc2a5..35b0241 100644
--- a/proc/mig-mutate.h
+++ b/proc/mig-mutate.h
@@ -35,3 +35,12 @@
   end_using_port_info (port_info_t)
 #define NOTIFY_IMPORTS                                         \
   import "libports/mig-decls.h";
+
+#define TASK_NOTIFY_INTRAN                                     \
+  port_info_t begin_using_port_info_port (mach_port_t)
+#define TASK_NOTIFY_INTRAN_PAYLOAD                             \
+  port_info_t begin_using_port_info_payload
+#define TASK_NOTIFY_DESTRUCTOR                                 \
+  end_using_port_info (port_info_t)
+#define TASK_NOTIFY_IMPORTS                                    \
+  import "libports/mig-decls.h";
diff --git a/startup/startup.c b/startup/startup.c
index f54de5e..2eba563 100644
--- a/startup/startup.c
+++ b/startup/startup.c
@@ -880,6 +880,23 @@ init_stdarrays ()
    so the kernel command line can be read as for a normal Hurd process.  */
 
 void
+dump_processes (void)
+{
+  pid_t pid;
+  for (pid = 1; pid < 100; pid++)
+    {
+      char args[256], *buffer = args;
+      size_t len = sizeof args;
+      if (proc_getprocargs (procserver, pid, &buffer, &len) == 0)
+        {
+          fprintf (stderr, "pid%d\t%s\n", (int) pid, buffer);
+          if (buffer != args)
+            vm_deallocate (mach_task_self (), (vm_offset_t) buffer, len);
+        }
+    }
+}
+
+void
 frob_kernel_process (void)
 {
   error_t err;
@@ -904,7 +921,10 @@ frob_kernel_process (void)
   /* Make the kernel our child.  */
   err = proc_child (procserver, task);
   if (err)
-    error (0, err, "cannot make the kernel our child");
+    {
+      error (0, err, "cannot make the kernel our child");
+      dump_processes ();
+    }
 
   err = proc_task2proc (procserver, task, &proc);
   if (err)
diff --git a/utils/rpctrace.c b/utils/rpctrace.c
index 25d9bc6..cb4df8a 100644
--- a/utils/rpctrace.c
+++ b/utils/rpctrace.c
@@ -1307,7 +1307,7 @@ trace_and_forward (mach_msg_header_t *inp, 
mach_msg_header_t *outp)
 
          /* Print something about the message header.  */
          print_request_header ((struct sender_info *) info, inp);
-         /* It's a nofication message. */
+         /* It's a notification message. */
          if (inp->msgh_id <= 72 && inp->msgh_id >= 64)
            {
              assert (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE);

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-hurd/hurd.git



reply via email to

[Prev in Thread] Current Thread [Next in Thread]