about summary refs log tree commit diff
path: root/REORG.TODO/hurd
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/hurd')
-rw-r--r--REORG.TODO/hurd/Depend9
-rw-r--r--REORG.TODO/hurd/Makefile98
-rw-r--r--REORG.TODO/hurd/Notes37
-rw-r--r--REORG.TODO/hurd/Versions144
-rw-r--r--REORG.TODO/hurd/alloc-fd.c140
-rw-r--r--REORG.TODO/hurd/catch-exc.c131
-rw-r--r--REORG.TODO/hurd/catch-signal.c167
-rw-r--r--REORG.TODO/hurd/compat-20.c37
-rw-r--r--REORG.TODO/hurd/ctty-input.c79
-rw-r--r--REORG.TODO/hurd/ctty-output.c84
-rw-r--r--REORG.TODO/hurd/dtable.c304
-rw-r--r--REORG.TODO/hurd/exc2signal.c70
-rw-r--r--REORG.TODO/hurd/faultexc.defs5
-rw-r--r--REORG.TODO/hurd/fchroot.c49
-rw-r--r--REORG.TODO/hurd/fd-close.c45
-rw-r--r--REORG.TODO/hurd/fd-read.c54
-rw-r--r--REORG.TODO/hurd/fd-write.c42
-rw-r--r--REORG.TODO/hurd/fopenport.c132
-rw-r--r--REORG.TODO/hurd/get-host.c92
-rw-r--r--REORG.TODO/hurd/getdport.c58
-rw-r--r--REORG.TODO/hurd/geteuids.c68
-rw-r--r--REORG.TODO/hurd/getumask.c24
-rw-r--r--REORG.TODO/hurd/hurd-raise.c50
-rw-r--r--REORG.TODO/hurd/hurd.h345
-rw-r--r--REORG.TODO/hurd/hurd/fd.h275
-rw-r--r--REORG.TODO/hurd/hurd/id.h54
-rw-r--r--REORG.TODO/hurd/hurd/ioctl.h81
-rw-r--r--REORG.TODO/hurd/hurd/lookup.h190
-rw-r--r--REORG.TODO/hurd/hurd/port.h158
-rw-r--r--REORG.TODO/hurd/hurd/resource.h51
-rw-r--r--REORG.TODO/hurd/hurd/signal.h364
-rw-r--r--REORG.TODO/hurd/hurd/sigpreempt.h102
-rw-r--r--REORG.TODO/hurd/hurd/threadvar.h116
-rw-r--r--REORG.TODO/hurd/hurd/userlink.h147
-rw-r--r--REORG.TODO/hurd/hurd/xattr.h34
-rw-r--r--REORG.TODO/hurd/hurdauth.c236
-rw-r--r--REORG.TODO/hurd/hurdchdir.c59
-rw-r--r--REORG.TODO/hurd/hurdexec.c403
-rw-r--r--REORG.TODO/hurd/hurdfault.c237
-rw-r--r--REORG.TODO/hurd/hurdfault.h50
-rw-r--r--REORG.TODO/hurd/hurdfchdir.c58
-rw-r--r--REORG.TODO/hurd/hurdhost.h27
-rw-r--r--REORG.TODO/hurd/hurdid.c90
-rw-r--r--REORG.TODO/hurd/hurdinit.c225
-rw-r--r--REORG.TODO/hurd/hurdioctl.c331
-rw-r--r--REORG.TODO/hurd/hurdkill.c92
-rw-r--r--REORG.TODO/hurd/hurdlookup.c281
-rw-r--r--REORG.TODO/hurd/hurdmalloc.c449
-rw-r--r--REORG.TODO/hurd/hurdmalloc.h21
-rw-r--r--REORG.TODO/hurd/hurdmsg.c419
-rw-r--r--REORG.TODO/hurd/hurdpid.c71
-rw-r--r--REORG.TODO/hurd/hurdports.c51
-rw-r--r--REORG.TODO/hurd/hurdprio.c88
-rw-r--r--REORG.TODO/hurd/hurdrlimit.c58
-rw-r--r--REORG.TODO/hurd/hurdselect.c491
-rw-r--r--REORG.TODO/hurd/hurdsig.c1405
-rw-r--r--REORG.TODO/hurd/hurdsock.c120
-rw-r--r--REORG.TODO/hurd/hurdsocket.h30
-rw-r--r--REORG.TODO/hurd/hurdstartup.c194
-rw-r--r--REORG.TODO/hurd/hurdstartup.h63
-rw-r--r--REORG.TODO/hurd/intern-fd.c49
-rw-r--r--REORG.TODO/hurd/intr-msg.c424
-rw-r--r--REORG.TODO/hurd/intr-rpc.defs22
-rw-r--r--REORG.TODO/hurd/intr-rpc.h24
-rw-r--r--REORG.TODO/hurd/longjmp-ts.c31
-rw-r--r--REORG.TODO/hurd/lookup-at.c115
-rw-r--r--REORG.TODO/hurd/lookup-retry.c331
-rw-r--r--REORG.TODO/hurd/msgportdemux.c68
-rw-r--r--REORG.TODO/hurd/new-fd.c41
-rw-r--r--REORG.TODO/hurd/openport.c28
-rw-r--r--REORG.TODO/hurd/path-lookup.c122
-rw-r--r--REORG.TODO/hurd/pid2task.c31
-rw-r--r--REORG.TODO/hurd/port-cleanup.c30
-rw-r--r--REORG.TODO/hurd/port2fd.c63
-rw-r--r--REORG.TODO/hurd/ports-get.c45
-rw-r--r--REORG.TODO/hurd/ports-set.c56
-rw-r--r--REORG.TODO/hurd/preempt-sig.c67
-rw-r--r--REORG.TODO/hurd/privports.c70
-rw-r--r--REORG.TODO/hurd/report-wait.c243
-rw-r--r--REORG.TODO/hurd/set-host.c49
-rw-r--r--REORG.TODO/hurd/setauth.c122
-rw-r--r--REORG.TODO/hurd/seteuids.c58
-rw-r--r--REORG.TODO/hurd/siginfo.c26
-rw-r--r--REORG.TODO/hurd/sigunwind.c149
-rw-r--r--REORG.TODO/hurd/task2pid.c29
-rw-r--r--REORG.TODO/hurd/thread-cancel.c100
-rw-r--r--REORG.TODO/hurd/thread-self.c25
-rw-r--r--REORG.TODO/hurd/trampoline.c36
-rw-r--r--REORG.TODO/hurd/vpprintf.c59
-rw-r--r--REORG.TODO/hurd/xattr.c200
90 files changed, 12098 insertions, 0 deletions
diff --git a/REORG.TODO/hurd/Depend b/REORG.TODO/hurd/Depend
new file mode 100644
index 0000000000..b108b245b8
--- /dev/null
+++ b/REORG.TODO/hurd/Depend
@@ -0,0 +1,9 @@
+# This file says that the mach subdirectory should appear before this one.
+# The mach and hurd subdirectories have many generated header files which
+# much of the rest of the library depends on, so it is best to build them
+# first (and mach before hurd, at that).  The before-compile additions in
+# sysdeps/{mach,hurd}/Makefile should make it reliably work for these files
+# not to exist when making in other directories, but it will be slower that
+# way with more somewhat expensive `make' invocations.
+
+mach
diff --git a/REORG.TODO/hurd/Makefile b/REORG.TODO/hurd/Makefile
new file mode 100644
index 0000000000..9205822b24
--- /dev/null
+++ b/REORG.TODO/hurd/Makefile
@@ -0,0 +1,98 @@
+# Copyright (C) 1991-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+subdir := hurd
+
+include ../Makeconfig
+
+headers = hurd.h $(interface-headers) \
+	  $(addprefix hurd/,fd.h id.h port.h signal.h sigpreempt.h ioctl.h\
+			    userlink.h resource.h threadvar.h lookup.h)
+
+inline-headers = hurd.h $(addprefix hurd/,fd.h signal.h \
+					  userlink.h threadvar.h port.h)
+
+# The RPC interfaces go in a separate library.
+interface-library := libhurduser
+user-interfaces		:= $(addprefix hurd/,\
+				       auth startup \
+				       process process_request \
+				       msg msg_reply msg_request \
+				       exec exec_startup crash interrupt \
+				       fs fsys io term tioctl socket ifsock \
+				       login password pfinet \
+				       )
+server-interfaces	:= hurd/msg faultexc
+
+routines = hurdstartup hurdinit \
+	   hurdid hurdpid hurdrlimit hurdprio hurdexec hurdselect \
+	   hurdlookup lookup-retry lookup-at \
+	   get-host set-host \
+	   path-lookup \
+	   setauth \
+	   pid2task task2pid \
+	   geteuids seteuids getumask fchroot \
+	   hurdsock hurdauth \
+	   hurdchdir hurdfchdir \
+	   privports \
+	   msgportdemux \
+	   fopenport \
+	   vpprintf \
+	   ports-get ports-set hurdports hurdmsg \
+	   errno-loc \
+	   $(sig) $(dtable) $(inlines) port-cleanup report-wait xattr
+sig	= hurdsig hurdfault siginfo hurd-raise preempt-sig \
+	  trampoline longjmp-ts catch-exc exc2signal hurdkill sigunwind \
+	  thread-self thread-cancel intr-msg catch-signal
+dtable	= dtable port2fd new-fd alloc-fd intern-fd \
+	  getdport openport \
+	  fd-close fd-read fd-write hurdioctl ctty-input ctty-output
+inlines = $(inline-headers:%.h=%-inlines)
+
+# XXX this is a temporary hack; see hurdmalloc.h
+routines += hurdmalloc
+
+# Binary compatibility for libc.so.0.2[GLIBC_2.0].
+ifeq ($(build-shared),yes)
+routines += compat-20
+endif
+
+shared-only-routines = compat-20
+
+# For each of the $(inline-headers), generate a trivial source
+# file that will #include it to define its inline functions as real functions.
+$(inlines:%=$(objpfx)%.c): $(objpfx)%-inlines.c: %.h
+	(h="`echo $(subst /,_,$*) | tr '[a-z]' '[A-Z]'`"; \
+	 echo "#define _$${h}_H_EXTERN_INLINE /* Define real function.  */"; \
+	 echo '#include "$<"') > $@-new
+	mv -f $@-new $@
+generated += $(inlines:=.c)
+
+include ../mach/Machrules
+include ../Rules
+
+# intr-rpc.defs defines the INTR_INTERFACE macro to make the generated RPC
+# stubs import <hurd/signal.h> and #define __mach_msg to
+# _hurd_intr_rpc_mach_msg.
+user-MIGFLAGS += -imacros intr-rpc.defs
+
+# The special exc server for sigthread faults uses a special prefix.
+MIGFLAGS-faultexc = -prefix _hurdsig_fault_
+
+# We need this static dependency to get faultexc.h generated the first time.
+$(objpfx)hurdfault.o $(objpfx)hurdfault.d: \
+	$(objpfx)faultexc_server.h $(objpfx)faultexc_server.c
diff --git a/REORG.TODO/hurd/Notes b/REORG.TODO/hurd/Notes
new file mode 100644
index 0000000000..9052f29096
--- /dev/null
+++ b/REORG.TODO/hurd/Notes
@@ -0,0 +1,37 @@
+The library pays attention to some envariables:
+
+CORESERVER     -- Name of core server naming point; falls back to /servers/core
+COREFILE       -- Name of file to write core dump in; falls back to core
+GNUTARGET      -- Passed to core server to specify flavor of core dump format
+
+New functions:
+
+int openport (io_t port);
+FILE *fopenport (mach_port_t, const char *mode);
+file_t getdport (int fd);
+
+task_t pid2task (pid_t);
+pid_t task2pid (task_t);
+
+int fchroot (int fd);
+mode_t getumask (void);
+
+int getuids (int n, uid_t *uidset);
+
+error_t hurd_path_lookup (file_t root, file_t cwd,
+			  const char *path, int flags, mode_t mode,
+			  file_t *port);
+error_t hurd_path_split (file_t root, file_t cwd,
+			 const char *path,
+			 file_t *dir, char **name);
+file_t path_lookup (const char *path, int flags, mode_t mode);
+file_t path_split (const char *path, char **name);
+
+process_t getproc (void);
+int setproc (process_t);
+file_t getcrdir (void);
+int setcrdir (file_t);
+file_t getcwdir (void);
+int setcwdir (file_t);
+auth_t getauth (void);
+int setauth (auth_t);		/* Reauthenticates all library ports.  */
diff --git a/REORG.TODO/hurd/Versions b/REORG.TODO/hurd/Versions
new file mode 100644
index 0000000000..77f5b4271e
--- /dev/null
+++ b/REORG.TODO/hurd/Versions
@@ -0,0 +1,144 @@
+libc {
+  GLIBC_2.0 {
+    # necessary for the Hurd brk implementation
+    _end;
+
+    # variables used in macros & inline functions
+    __hurd_sigthread_stack_base; __hurd_sigthread_stack_end;
+    __hurd_sigthread_variables;
+    __hurd_threadvar_max;
+    __hurd_threadvar_stack_mask; __hurd_threadvar_stack_offset;
+
+    # functions used in macros & inline functions
+    __hurd_errno_location;
+
+    # functions used in libmachuser and libhurduser
+    _S_catch_exception_raise;
+    _S_catch_exception_raise_state;
+    _S_catch_exception_raise_state_identity;
+    _S_msg_add_auth; _S_msg_del_auth;
+    _S_msg_describe_ports;
+    _S_msg_get_dtable; _S_msg_set_dtable;
+    _S_msg_get_env_variable; _S_msg_set_env_variable;
+    _S_msg_get_environment; _S_msg_set_environment;
+    _S_msg_get_fd; _S_msg_set_fd;
+    _S_msg_get_init_int; _S_msg_set_init_int;
+    _S_msg_get_init_ints; _S_msg_set_init_ints;
+    _S_msg_get_init_port; _S_msg_set_init_port;
+    _S_msg_get_init_ports; _S_msg_set_init_ports;
+    _S_msg_proc_newids; _S_msg_report_wait;
+    _S_msg_sig_post; _S_msg_sig_post_untraced;
+    _hurd_intr_rpc_mach_msg;
+    _hurdsig_fault_catch_exception_raise;
+    _hurdsig_fault_catch_exception_raise_state;
+    _hurdsig_fault_catch_exception_raise_state_identity;
+
+    # "quasi-internal" variables
+    _hurd_device_master;
+    _hurd_dtable; _hurd_dtablesize; _hurd_dtable_lock;
+    _hurd_host_priv;
+    _hurd_msgport;
+    _hurd_ports;
+
+    # "quasi-internal" functions
+    _hurd_canonicalize_directory_name_internal;
+    _hurd_critical_section_lock;
+    _hurd_critical_section_unlock;
+    _hurd_exception2signal;
+    _hurd_exec;
+    _hurd_fd_get;
+    _hurd_init;
+    _hurd_intern_fd;
+    _hurd_port_cleanup;
+    _hurd_port_free;
+    _hurd_port_get;
+    _hurd_port_locked_get;
+    _hurd_ports_use;
+    _hurd_thread_sigstate;
+
+    # functions in normal name space
+
+    # f*
+    file_name_lookup; file_name_lookup_under; file_name_path_lookup;
+    file_name_split;
+    fopenport;
+
+    # g*
+    get_privileged_ports;
+    getauth; getcrdir; getcwdir; getcttyid; getdport; getproc; getumask;
+
+    # h*
+    hurd_catch_signal;
+    hurd_check_cancel;
+    hurd_file_name_lookup; hurd_file_name_lookup_retry;
+    hurd_file_name_path_lookup; hurd_file_name_split;
+    hurd_preempt_signals;
+    hurd_safe_copyin; hurd_safe_copyout;
+    hurd_safe_memmove; hurd_safe_memset;
+    hurd_sig_post;
+    hurd_thread_cancel; hurd_thread_self;
+    hurd_unpreempt_signals;
+
+    # o*
+    openport;
+
+    # p*
+    pid2task;
+
+    # s*
+    setauth; setcrdir; setcwdir; setproc; setcttyid;
+
+    # t*
+    task2pid;
+
+    # v*
+    vpprintf;
+  }
+  GLIBC_2.1 {
+    # "quasi-internal" functions
+    _hurd_proc_init;
+
+    # g*
+    geteuids;
+
+    # s*
+    seteuids;
+  }
+  GLIBC_2.1.3 {
+    # d*
+    directory_name_split;
+
+    # h*
+    hurd_directory_name_split;
+  }
+  GLIBC_2.2.5 {
+    # These always existed as inlines but the real functions were not exported.
+    __hurd_fail;
+    _hurd_self_sigstate;
+
+    # Same for these "quasi-internal" functions
+    _hurd_port_init;
+    _hurd_port_set;
+
+    # internal symbols used by other libraries (e.g. librt)
+    _hurd_raise_signal;
+    _hurdsig_interrupt_timeout;
+    _hurdsig_fault_preemptor; _hurdsig_fault_env;
+  }
+  GLIBC_2.2.6 {
+    # functions used in macros & inline functions
+    __errno_location;
+  }
+
+  HURD_CTHREADS_0.3 {
+    # weak refs to libthreads functions that libc calls iff libthreads in use
+    cthread_fork; cthread_detach;
+
+    # variables used for detecting cthreads
+    _cthread_exit_routine; _cthread_init_routine;
+
+    # cthreads functions with stubs in libc
+    cthread_keycreate; cthread_getspecific; cthread_setspecific;
+    __libc_getspecific;
+  }
+}
diff --git a/REORG.TODO/hurd/alloc-fd.c b/REORG.TODO/hurd/alloc-fd.c
new file mode 100644
index 0000000000..18e542ce5f
--- /dev/null
+++ b/REORG.TODO/hurd/alloc-fd.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <hurd/resource.h>
+#include <stdlib.h>
+#include "hurdmalloc.h"		/* XXX */
+
+/* Allocate a new file descriptor and return it, locked.  The new
+   descriptor number will be no less than FIRST_FD.  If the table is full,
+   set errno to EMFILE and return NULL.  If FIRST_FD is negative or bigger
+   than the size of the table, set errno to EINVAL and return NULL.  */
+
+struct hurd_fd *
+_hurd_alloc_fd (int *fd, int first_fd)
+{
+  int i;
+  void *crit;
+  long int rlimit;
+
+  if (first_fd < 0)
+    {
+      errno = EINVAL;
+      return NULL;
+    }
+
+  crit = _hurd_critical_section_lock ();
+
+  __mutex_lock (&_hurd_dtable_lock);
+
+ search:
+  for (i = first_fd; i < _hurd_dtablesize; ++i)
+    {
+      struct hurd_fd *d = _hurd_dtable[i];
+      if (d == NULL)
+	{
+	  /* Allocate a new descriptor structure for this slot,
+	     initializing its port cells to nil.  The test below will catch
+	     and return this descriptor cell after locking it.  */
+	  d = _hurd_new_fd (MACH_PORT_NULL, MACH_PORT_NULL);
+	  if (d == NULL)
+	    {
+	      __mutex_unlock (&_hurd_dtable_lock);
+	      _hurd_critical_section_unlock (crit);
+	      return NULL;
+	    }
+	  _hurd_dtable[i] = d;
+	}
+
+      __spin_lock (&d->port.lock);
+      if (d->port.port == MACH_PORT_NULL)
+	{
+	  __mutex_unlock (&_hurd_dtable_lock);
+	  _hurd_critical_section_unlock (crit);
+	  if (fd != NULL)
+	    *fd = i;
+	  return d;
+	}
+      else
+	__spin_unlock (&d->port.lock);
+    }
+
+  __mutex_lock (&_hurd_rlimit_lock);
+  rlimit = _hurd_rlimits[RLIMIT_OFILE].rlim_cur;
+  __mutex_unlock (&_hurd_rlimit_lock);
+
+  if (first_fd < rlimit)
+    {
+      /* The descriptor table is full.  Check if we have reached the
+	 resource limit, or only the allocated size.  */
+      if (_hurd_dtablesize < rlimit)
+	{
+	  /* Enlarge the table.  */
+	  int save = errno;
+	  struct hurd_fd **new;
+	  /* Try to double the table size, but don't exceed the limit,
+	     and make sure it exceeds FIRST_FD.  */
+	  int size = _hurd_dtablesize * 2;
+	  if (size > rlimit)
+	    size = rlimit;
+	  else if (size <= first_fd)
+	    size = first_fd + 1;
+
+	  if (size * sizeof (*_hurd_dtable) < size)
+	    {
+	      /* Integer overflow! */
+	      errno = ENOMEM;
+	      goto out;
+	    }
+
+	  /* If we fail to allocate that, decrement the desired size
+	     until we succeed in allocating it.  */
+	  do
+	    new = realloc (_hurd_dtable, size * sizeof (*_hurd_dtable));
+	  while (new == NULL && size-- > first_fd);
+
+	  if (new != NULL)
+	    {
+	      /* We managed to allocate a new table.  Now install it.  */
+	      errno = save;
+	      if (first_fd < _hurd_dtablesize)
+		first_fd = _hurd_dtablesize;
+	      /* Initialize the new slots.  */
+	      for (i = _hurd_dtablesize; i < size; ++i)
+		new[i] = NULL;
+	      _hurd_dtablesize = size;
+	      _hurd_dtable = new;
+	      /* Go back to the loop to initialize the first new slot.  */
+	      goto search;
+	    }
+	  else
+	    errno = ENOMEM;
+	}
+      else
+	errno = EMFILE;
+    }
+  else
+    errno = EINVAL;		/* Bogus FIRST_FD value.  */
+
+ out:
+  __mutex_unlock (&_hurd_dtable_lock);
+  _hurd_critical_section_unlock (crit);
+
+  return NULL;
+}
diff --git a/REORG.TODO/hurd/catch-exc.c b/REORG.TODO/hurd/catch-exc.c
new file mode 100644
index 0000000000..1a4fa95c9f
--- /dev/null
+++ b/REORG.TODO/hurd/catch-exc.c
@@ -0,0 +1,131 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <mach/exc_server.h>
+#include <hurd/signal.h>
+#include <assert.h>
+
+/* Called by the microkernel when a thread gets an exception.  */
+
+kern_return_t
+_S_catch_exception_raise (mach_port_t port,
+			  thread_t thread,
+			  task_t task,
+#ifdef EXC_MASK_ALL		/* New interface flavor.  */
+			  exception_type_t exception,
+			  exception_data_t code,
+			  mach_msg_type_number_t codeCnt
+#else				/* Vanilla Mach 3.0 interface.  */
+			  integer_t exception,
+			  integer_t code, integer_t subcode
+#endif
+			  )
+{
+  struct hurd_sigstate *ss;
+  int signo;
+  struct hurd_signal_detail d;
+
+  if (task != __mach_task_self ())
+    /* The sender wasn't the kernel.  */
+    return EPERM;
+
+  d.exc = exception;
+#ifdef EXC_MASK_ALL
+  assert (codeCnt >= 2);
+  d.exc_code = code[0];
+  d.exc_subcode = code[1];
+#else
+  d.exc_code = code;
+  d.exc_subcode = subcode;
+#endif
+
+  /* Call the machine-dependent function to translate the Mach exception
+     codes into a signal number and subcode.  */
+  _hurd_exception2signal (&d, &signo);
+
+  /* Find the sigstate structure for the faulting thread.  */
+  __mutex_lock (&_hurd_siglock);
+  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+    if (ss->thread == thread)
+      break;
+  __mutex_unlock (&_hurd_siglock);
+  if (ss == NULL)
+    ss = _hurd_thread_sigstate (thread); /* Allocate a fresh one.  */
+
+  if (__spin_lock_locked (&ss->lock))
+    {
+      /* Loser.  The thread faulted with its sigstate lock held.  Its
+	 sigstate data is now suspect.  So we reset the parts of it which
+	 could cause trouble for the signal thread.  Anything else
+	 clobbered therein will just hose this user thread, but it's
+	 faulting already.
+
+	 This is almost certainly a library bug: unless random memory
+	 clobberation caused the sigstate lock to gratuitously appear held,
+	 no code should do anything that can fault while holding the
+	 sigstate lock.  */
+
+      __spin_unlock (&ss->critical_section_lock);
+      ss->context = NULL;
+      __spin_unlock (&ss->lock);
+    }
+
+  /* Post the signal.  */
+  _hurd_internal_post_signal (ss, signo, &d,
+			      MACH_PORT_NULL, MACH_MSG_TYPE_PORT_SEND,
+			      0);
+
+  return KERN_SUCCESS;
+}
+
+#ifdef EXC_MASK_ALL
+/* XXX New interface flavor has additional RPCs that we could be using
+   instead.  These RPCs roll a thread_get_state/thread_set_state into
+   the message, so the signal thread ought to use these to save some calls.
+ */
+kern_return_t
+_S_catch_exception_raise_state (mach_port_t port,
+				exception_type_t exception,
+				exception_data_t code,
+				mach_msg_type_number_t codeCnt,
+				int *flavor,
+				thread_state_t old_state,
+				mach_msg_type_number_t old_stateCnt,
+				thread_state_t new_state,
+				mach_msg_type_number_t *new_stateCnt)
+{
+  abort ();
+  return KERN_FAILURE;
+}
+
+kern_return_t
+_S_catch_exception_raise_state_identity (mach_port_t exception_port,
+					 thread_t thread,
+					 task_t task,
+					 exception_type_t exception,
+					 exception_data_t code,
+					 mach_msg_type_number_t codeCnt,
+					 int *flavor,
+					 thread_state_t old_state,
+					 mach_msg_type_number_t old_stateCnt,
+					 thread_state_t new_state,
+					 mach_msg_type_number_t *new_stateCnt)
+{
+  abort ();
+  return KERN_FAILURE;
+}
+#endif
diff --git a/REORG.TODO/hurd/catch-signal.c b/REORG.TODO/hurd/catch-signal.c
new file mode 100644
index 0000000000..1d606ecaf0
--- /dev/null
+++ b/REORG.TODO/hurd/catch-signal.c
@@ -0,0 +1,167 @@
+/* Convenience function to catch expected signals during an operation.
+   Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/signal.h>
+#include <hurd/sigpreempt.h>
+#include <string.h>
+#include <assert.h>
+
+error_t
+hurd_catch_signal (sigset_t sigset,
+		   unsigned long int first, unsigned long int last,
+		   error_t (*operate) (struct hurd_signal_preemptor *),
+		   sighandler_t handler)
+{
+  /* We need to restore the signal mask, because otherwise the
+     signal-handling code will have blocked the caught signal and for
+     instance calling hurd_catch_signal again would then dump core.  */
+  sigjmp_buf buf;
+  void throw (int signo, long int sigcode, struct sigcontext *scp)
+    { siglongjmp (buf, scp->sc_error ?: EGRATUITOUS); }
+
+  struct hurd_signal_preemptor preemptor =
+    {
+      sigset, first, last,
+      NULL, handler == SIG_ERR ? (sighandler_t) &throw : handler,
+    };
+
+  struct hurd_sigstate *const ss = _hurd_self_sigstate ();
+  error_t error;
+
+  if (handler != SIG_ERR)
+    /* Not our handler; don't bother saving state.  */
+    error = 0;
+  else
+    /* This returns again with nonzero value when we preempt a signal.  */
+    error = sigsetjmp (buf, 1);
+
+  if (error == 0)
+    {
+      /* Install a signal preemptor for the thread.  */
+      __spin_lock (&ss->lock);
+      preemptor.next = ss->preemptors;
+      ss->preemptors = &preemptor;
+      __spin_unlock (&ss->lock);
+
+      /* Try the operation that might crash.  */
+      (*operate) (&preemptor);
+    }
+
+  /* Either FUNCTION completed happily and ERROR is still zero, or it hit
+     an expected signal and `throw' made setjmp return the signal error
+     code in ERROR.  Now we can remove the preemptor and return.  */
+
+  __spin_lock (&ss->lock);
+  assert (ss->preemptors == &preemptor);
+  ss->preemptors = preemptor.next;
+  __spin_unlock (&ss->lock);
+
+  return error;
+}
+
+
+error_t
+hurd_safe_memset (void *dest, int byte, size_t nbytes)
+{
+  error_t operate (struct hurd_signal_preemptor *preemptor)
+    {
+      memset (dest, byte, nbytes);
+      return 0;
+    }
+  return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
+			    (vm_address_t) dest, (vm_address_t) dest + nbytes,
+			    &operate, SIG_ERR);
+}
+
+
+error_t
+hurd_safe_copyout (void *dest, const void *src, size_t nbytes)
+{
+  error_t operate (struct hurd_signal_preemptor *preemptor)
+    {
+      memcpy (dest, src, nbytes);
+      return 0;
+    }
+  return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
+			    (vm_address_t) dest, (vm_address_t) dest + nbytes,
+			    &operate, SIG_ERR);
+}
+
+error_t
+hurd_safe_copyin (void *dest, const void *src, size_t nbytes)
+{
+  error_t operate (struct hurd_signal_preemptor *preemptor)
+    {
+      memcpy (dest, src, nbytes);
+      return 0;
+    }
+  return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
+			    (vm_address_t) src, (vm_address_t) src + nbytes,
+			    &operate, SIG_ERR);
+}
+
+error_t
+hurd_safe_memmove (void *dest, const void *src, size_t nbytes)
+{
+  jmp_buf buf;
+  void throw (int signo, long int sigcode, struct sigcontext *scp)
+    { longjmp (buf, scp->sc_error ?: EGRATUITOUS); }
+
+  struct hurd_signal_preemptor src_preemptor =
+    {
+      sigmask (SIGBUS) | sigmask (SIGSEGV),
+      (vm_address_t) src, (vm_address_t) src + nbytes,
+      NULL, (sighandler_t) &throw,
+    };
+  struct hurd_signal_preemptor dest_preemptor =
+    {
+      sigmask (SIGBUS) | sigmask (SIGSEGV),
+      (vm_address_t) dest, (vm_address_t) dest + nbytes,
+      NULL, (sighandler_t) &throw,
+      &src_preemptor
+    };
+
+  struct hurd_sigstate *const ss = _hurd_self_sigstate ();
+  error_t error;
+
+  /* This returns again with nonzero value when we preempt a signal.  */
+  error = setjmp (buf);
+
+  if (error == 0)
+    {
+      /* Install a signal preemptor for the thread.  */
+      __spin_lock (&ss->lock);
+      src_preemptor.next = ss->preemptors;
+      ss->preemptors = &dest_preemptor;
+      __spin_unlock (&ss->lock);
+
+      /* Do the copy; it might fault.  */
+      memmove (dest, src, nbytes);
+    }
+
+  /* Either memmove completed happily and ERROR is still zero, or it hit
+     an expected signal and `throw' made setjmp return the signal error
+     code in ERROR.  Now we can remove the preemptor and return.  */
+
+  __spin_lock (&ss->lock);
+  assert (ss->preemptors == &dest_preemptor);
+  ss->preemptors = src_preemptor.next;
+  __spin_unlock (&ss->lock);
+
+  return error;
+}
diff --git a/REORG.TODO/hurd/compat-20.c b/REORG.TODO/hurd/compat-20.c
new file mode 100644
index 0000000000..0fd1701b26
--- /dev/null
+++ b/REORG.TODO/hurd/compat-20.c
@@ -0,0 +1,37 @@
+/* Old-versioned functions for binary compatibility with glibc-2.0.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+/* This file provides definitions for binary compatibility with
+   the GLIBC_2.0 version set for the libc.so.0.2 soname.
+
+   These definitions can be removed when the soname changes.  */
+
+#include <shlib-compat.h>
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+
+void
+attribute_compat_text_section
+_hurd_proc_init_compat_20 (char **argv)
+{
+  _hurd_proc_init (argv, NULL, 0);
+}
+compat_symbol (libc, _hurd_proc_init_compat_20, _hurd_proc_init, GLIBC_2_0);
+
+#endif
diff --git a/REORG.TODO/hurd/ctty-input.c b/REORG.TODO/hurd/ctty-input.c
new file mode 100644
index 0000000000..826d78bed8
--- /dev/null
+++ b/REORG.TODO/hurd/ctty-input.c
@@ -0,0 +1,79 @@
+/* _hurd_ctty_input -- Do an input RPC and generate SIGTTIN if necessary.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+
+/* Call *RPC on PORT and/or CTTY.  If a call on CTTY returns EBACKGROUND,
+   generate SIGTTIN or EIO as appropriate.  */
+
+error_t
+_hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t))
+{
+  error_t err;
+
+  if (ctty == MACH_PORT_NULL)
+    return (*rpc) (port);
+
+  do
+    {
+      err = (*rpc) (ctty);
+      if (err == EBACKGROUND)
+	{
+	  /* We are a background job and tried to read from the tty.
+	     We should probably get a SIGTTIN signal.  */
+	  if (_hurd_orphaned)
+	    /* Our process group is orphaned.  Don't stop; just fail.  */
+	    err = EIO;
+	  else
+	    {
+	      struct hurd_sigstate *ss = _hurd_self_sigstate ();
+	      __spin_lock (&ss->lock);
+	      if (__sigismember (&ss->blocked, SIGTTIN) ||
+		  ss->actions[SIGTTIN].sa_handler == SIG_IGN)
+		/* We are blocking or ignoring SIGTTIN.  Just fail.  */
+		err = EIO;
+	      __spin_unlock (&ss->lock);
+
+	      if (err == EBACKGROUND)
+		{
+		  /* Send a SIGTTIN signal to our process group.
+
+		     We must remember here not to clobber ERR, since
+		     the loop condition below uses it to recall that
+		  we should retry after a stop.  */
+
+		  __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTIN, port));
+		  /* XXX what to do if error here? */
+
+		  /* At this point we should have just run the handler for
+		     SIGTTIN or resumed after being stopped.  Now this is
+		     still a "system call", so check to see if we should
+		  restart it.  */
+		  __spin_lock (&ss->lock);
+		  if (!(ss->actions[SIGTTIN].sa_flags & SA_RESTART))
+		    err = EINTR;
+		  __spin_unlock (&ss->lock);
+		}
+	    }
+	}
+      /* If the last RPC generated a SIGTTIN, loop to try it again.  */
+    } while (err == EBACKGROUND);
+
+  return err;
+}
diff --git a/REORG.TODO/hurd/ctty-output.c b/REORG.TODO/hurd/ctty-output.c
new file mode 100644
index 0000000000..357adb6563
--- /dev/null
+++ b/REORG.TODO/hurd/ctty-output.c
@@ -0,0 +1,84 @@
+/* _hurd_ctty_output -- Do an output RPC and generate SIGTTOU if necessary.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+
+/* Call *RPC on PORT and/or CTTY.  If a call on CTTY returns EBACKGROUND,
+   generate SIGTTOU if appropriate.  */
+
+error_t
+_hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t))
+{
+  if (ctty == MACH_PORT_NULL)
+    return (*rpc) (port);
+  else
+    {
+      struct hurd_sigstate *ss = _hurd_self_sigstate ();
+      error_t err;
+
+      do
+	{
+	  /* Don't use the ctty io port if we are blocking or ignoring
+	     SIGTTOU.  We redo this check at the top of the loop in case
+	     the signal handler changed the state.  */
+	  __spin_lock (&ss->lock);
+	  if (__sigismember (&ss->blocked, SIGTTOU) ||
+	      ss->actions[SIGTTOU].sa_handler == SIG_IGN)
+	    err = EIO;
+	  else
+	    err = 0;
+	  __spin_unlock (&ss->lock);
+
+	  if (err)
+	    return (*rpc) (port);
+
+	  err = (*rpc) (ctty);
+	  if (err == EBACKGROUND)
+	    {
+	      if (_hurd_orphaned)
+		/* Our process group is orphaned, so we never generate a
+		   signal; we just fail.  */
+		err = EIO;
+	      else
+		{
+		  /* Send a SIGTTOU signal to our process group.
+
+		     We must remember here not to clobber ERR, since
+		     the loop condition below uses it to recall that
+		  we should retry after a stop.  */
+
+		  __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port));
+		  /* XXX what to do if error here? */
+
+		  /* At this point we should have just run the handler for
+		     SIGTTOU or resumed after being stopped.  Now this is
+		     still a "system call", so check to see if we should
+		  restart it.  */
+		  __spin_lock (&ss->lock);
+		  if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
+		    err = EINTR;
+		  __spin_unlock (&ss->lock);
+		}
+	    }
+	  /* If the last RPC generated a SIGTTOU, loop to try it again.  */
+	} while (err == EBACKGROUND);
+
+      return err;
+    }
+}
diff --git a/REORG.TODO/hurd/dtable.c b/REORG.TODO/hurd/dtable.c
new file mode 100644
index 0000000000..46bad42c3c
--- /dev/null
+++ b/REORG.TODO/hurd/dtable.c
@@ -0,0 +1,304 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/term.h>
+#include <hurd/fd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <cthreads.h>		/* For `struct mutex'.  */
+#include "set-hooks.h"
+#include "hurdmalloc.h"		/* XXX */
+
+
+struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */
+struct hurd_fd **_hurd_dtable;
+int _hurd_dtablesize;
+
+
+DEFINE_HOOK (_hurd_fd_subinit, (void));
+
+/* Initialize the file descriptor table at startup.  */
+
+static void
+init_dtable (void)
+{
+  int i;
+
+  __mutex_init (&_hurd_dtable_lock);
+
+  /* The initial size of the descriptor table is that of the passed-in
+     table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
+  _hurd_dtablesize = _hurd_init_dtablesize;
+
+  /* Allocate the vector of pointers.  */
+  _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
+  if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
+    __libc_fatal ("hurd: Can't allocate file descriptor table\n");
+
+  /* Initialize the descriptor table.  */
+  for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i)
+    {
+      if (_hurd_init_dtable[i] == MACH_PORT_NULL)
+	/* An unused descriptor is marked by a null pointer.  */
+	_hurd_dtable[i] = NULL;
+      else
+	{
+	  /* Allocate a new file descriptor structure.  */
+	  struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
+	  if (new == NULL)
+	    __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
+
+	  /* Initialize the port cells.  */
+	  _hurd_port_init (&new->port, MACH_PORT_NULL);
+	  _hurd_port_init (&new->ctty, MACH_PORT_NULL);
+
+	  /* Install the port in the descriptor.
+	     This sets up all the ctty magic.  */
+	  _hurd_port2fd (new, _hurd_init_dtable[i], 0);
+
+	  _hurd_dtable[i] = new;
+	}
+    }
+
+  /* Clear out the initial descriptor table.
+     Everything must use _hurd_dtable now.  */
+  __vm_deallocate (__mach_task_self (),
+		   (vm_address_t) _hurd_init_dtable,
+		   _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
+  _hurd_init_dtable = NULL;
+  _hurd_init_dtablesize = 0;
+
+  /* Initialize the remaining empty slots in the table.  */
+  for (; i < _hurd_dtablesize; ++i)
+    _hurd_dtable[i] = NULL;
+
+  /* Run things that want to run after the file descriptor table
+     is initialized.  */
+  RUN_HOOK (_hurd_fd_subinit, ());
+
+  (void) &init_dtable;		/* Avoid "defined but not used" warning.  */
+}
+
+text_set_element (_hurd_subinit, init_dtable);
+
+/* XXX when the linker supports it, the following functions should all be
+   elsewhere and just have text_set_elements here.  */
+
+/* Called by `getdport' to do its work.  */
+
+static file_t
+get_dtable_port (int fd)
+{
+  struct hurd_fd *d = _hurd_fd_get (fd);
+  file_t dport;
+
+  if (!d)
+    return __hurd_fail (EBADF), MACH_PORT_NULL;
+
+  HURD_CRITICAL_BEGIN;
+
+  dport = HURD_PORT_USE (&d->port,
+			 ({
+			   error_t err;
+			   mach_port_t outport;
+			   err = __mach_port_mod_refs (__mach_task_self (),
+						       port,
+						       MACH_PORT_RIGHT_SEND,
+						       1);
+			   if (err)
+			     {
+			       errno = err;
+			       outport = MACH_PORT_NULL;
+			     }
+			   else
+			     outport = port;
+			   outport;
+			 }));
+
+  HURD_CRITICAL_END;
+
+  return dport;
+}
+
+file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
+
+#include <hurd/signal.h>
+
+/* We are in the child fork; the dtable lock is still held.
+   The parent has inserted send rights for all the normal io ports,
+   but we must recover ctty-special ports for ourselves.  */
+static error_t
+fork_child_dtable (void)
+{
+  error_t err;
+  int i;
+
+  err = 0;
+
+  for (i = 0; !err && i < _hurd_dtablesize; ++i)
+    {
+      struct hurd_fd *d = _hurd_dtable[i];
+      if (d == NULL)
+	continue;
+
+      /* No other thread is using the send rights in the child task.  */
+      d->port.users = d->ctty.users = NULL;
+
+      if (d->ctty.port != MACH_PORT_NULL)
+	{
+	  /* There was a ctty-special port in the parent.
+	     We need to get one for ourselves too.  */
+	  __mach_port_deallocate (__mach_task_self (), d->ctty.port);
+	  err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp,
+				  &d->ctty.port);
+	  if (err)
+	    d->ctty.port = MACH_PORT_NULL;
+	}
+
+      /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
+    }
+  return err;
+
+  (void) &fork_child_dtable;	/* Avoid "defined but not used" warning.  */
+}
+
+data_set_element (_hurd_fork_locks, _hurd_dtable_lock);	/* XXX ld bug: bss */
+text_set_element (_hurd_fork_child_hook, fork_child_dtable);
+
+/* Called when our process group has changed.  */
+
+static void
+ctty_new_pgrp (void)
+{
+  int i;
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_dtable_lock);
+
+  if (__USEPORT (CTTYID, port == MACH_PORT_NULL))
+    {
+      /* We have no controlling terminal.  If we haven't had one recently,
+	 but our pgrp is being pointlessly diddled anyway, then we will
+	 have nothing to do in the loop below because no fd will have a
+	 ctty port at all.
+
+	 More likely, a setsid call is responsible both for the change
+	 in pgrp and for clearing the cttyid port.  In that case, setsid
+	 held the dtable lock while updating the dtable to clear all the
+	 ctty ports, and ergo must have finished doing so before we run here.
+	 So we can be sure, again, that the loop below has no work to do.  */
+    }
+  else
+    for (i = 0; i < _hurd_dtablesize; ++i)
+      {
+	struct hurd_fd *const d = _hurd_dtable[i];
+	struct hurd_userlink ulink, ctty_ulink;
+	io_t port, ctty;
+
+	if (d == NULL)
+	  /* Nothing to do for an unused descriptor cell.  */
+	  continue;
+
+	port = _hurd_port_get (&d->port, &ulink);
+	ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
+
+	if (ctty != MACH_PORT_NULL)
+	  {
+	    /* This fd has a ctty-special port.  We need a new one, to tell
+	       the io server of our different process group.  */
+	    io_t new;
+	    if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
+	      new = MACH_PORT_NULL;
+	    _hurd_port_set (&d->ctty, new);
+	  }
+
+	_hurd_port_free (&d->port, &ulink, port);
+	_hurd_port_free (&d->ctty, &ctty_ulink, ctty);
+      }
+
+  __mutex_unlock (&_hurd_dtable_lock);
+  HURD_CRITICAL_END;
+
+  (void) &ctty_new_pgrp;	/* Avoid "defined but not used" warning.  */
+}
+
+text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
+
+/* Called to reauthenticate the dtable when the auth port changes.  */
+
+static void
+reauth_dtable (void)
+{
+  int i;
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_dtable_lock);
+
+  for (i = 0; i < _hurd_dtablesize; ++i)
+    {
+      struct hurd_fd *const d = _hurd_dtable[i];
+      mach_port_t new, newctty, ref;
+
+      if (d == NULL)
+	/* Nothing to do for an unused descriptor cell.  */
+	continue;
+
+      ref = __mach_reply_port ();
+
+      /* Take the descriptor cell's lock.  */
+      __spin_lock (&d->port.lock);
+
+      /* Reauthenticate the descriptor's port.  */
+      if (d->port.port != MACH_PORT_NULL &&
+	  ! __io_reauthenticate (d->port.port,
+				 ref, MACH_MSG_TYPE_MAKE_SEND) &&
+	  ! __USEPORT (AUTH, __auth_user_authenticate
+		       (port,
+			ref, MACH_MSG_TYPE_MAKE_SEND,
+			&new)))
+	{
+	  /* Replace the port in the descriptor cell
+	     with the newly reauthenticated port.  */
+
+	  if (d->ctty.port != MACH_PORT_NULL &&
+	      ! __io_reauthenticate (d->ctty.port,
+				     ref, MACH_MSG_TYPE_MAKE_SEND) &&
+	      ! __USEPORT (AUTH, __auth_user_authenticate
+			   (port,
+			    ref, MACH_MSG_TYPE_MAKE_SEND,
+			    &newctty)))
+	    _hurd_port_set (&d->ctty, newctty);
+
+	  _hurd_port_locked_set (&d->port, new);
+	}
+      else
+	/* Lost.  Leave this descriptor cell alone.  */
+	__spin_unlock (&d->port.lock);
+
+      __mach_port_destroy (__mach_task_self (), ref);
+    }
+
+  __mutex_unlock (&_hurd_dtable_lock);
+  HURD_CRITICAL_END;
+
+  (void) &reauth_dtable;	/* Avoid "defined but not used" warning.  */
+}
+
+text_set_element (_hurd_reauth_hook, reauth_dtable);
diff --git a/REORG.TODO/hurd/exc2signal.c b/REORG.TODO/hurd/exc2signal.c
new file mode 100644
index 0000000000..3b9df0cca8
--- /dev/null
+++ b/REORG.TODO/hurd/exc2signal.c
@@ -0,0 +1,70 @@
+/* Translate Mach exception codes into signal numbers.  Stub version.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+
+/* This file must be modified with machine-dependent details.  */
+#error "need to write sysdeps/mach/hurd/MACHINE/exc2signal.c"
+
+/* Translate the Mach exception codes, as received in an `exception_raise' RPC,
+   into a signal number and signal subcode.  */
+
+void
+_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+{
+  detail->error = 0;
+
+  switch (detail->exc)
+    {
+    default:
+      *signo = SIGIOT;
+      detail->code = detail->exc;
+      break;
+
+    case EXC_BAD_ACCESS:
+      if (detail->exc_code == KERN_PROTECTION_FAILURE)
+	*signo = SIGSEGV;
+      else
+	*signo = SIGBUS;
+      detail->code = detail->exc_subcode;
+      detail->error = detail->exc_code;
+      break;
+
+    case EXC_BAD_INSTRUCTION:
+      *signo = SIGILL;
+      detail->code = 0;
+      break;
+
+    case EXC_ARITHMETIC:
+      *signo = SIGFPE;
+      detail->code = 0;
+      break;
+
+    case EXC_EMULATION:
+    case EXC_SOFTWARE:
+      *signo = SIGEMT;
+      detail->code = 0;
+      break;
+
+    case EXC_BREAKPOINT:
+      *signo = SIGTRAP;
+      detail->code = 0;
+      break;
+    }
+}
diff --git a/REORG.TODO/hurd/faultexc.defs b/REORG.TODO/hurd/faultexc.defs
new file mode 100644
index 0000000000..fe7f02a4cc
--- /dev/null
+++ b/REORG.TODO/hurd/faultexc.defs
@@ -0,0 +1,5 @@
+/* This file is processed by mig with -prefix _hurdsig_fault_
+   to create the special exception server used for signal thread
+   fault recovery.  */
+
+#include <mach/exc.defs>
diff --git a/REORG.TODO/hurd/fchroot.c b/REORG.TODO/hurd/fchroot.c
new file mode 100644
index 0000000000..877a3e9ea6
--- /dev/null
+++ b/REORG.TODO/hurd/fchroot.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1999-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <hurd/port.h>
+
+/* Change the current root directory to FD.  */
+int
+fchroot (int fd)
+{
+  error_t err;
+  file_t dir;
+
+  err = HURD_DPORT_USE (fd,
+			({
+			  dir = __file_name_lookup_under (port, ".", 0, 0);
+			  dir == MACH_PORT_NULL ? errno : 0;
+			}));
+
+  if (! err)
+    {
+      file_t root;
+
+      /* Prevent going through DIR's ..  */
+      err = __file_reparent (dir, MACH_PORT_NULL, &root);
+      __mach_port_deallocate (__mach_task_self (), dir);
+      if (! err)
+	_hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], root);
+    }
+
+  return err ? __hurd_fail (err) : 0;
+}
diff --git a/REORG.TODO/hurd/fd-close.c b/REORG.TODO/hurd/fd-close.c
new file mode 100644
index 0000000000..2024517705
--- /dev/null
+++ b/REORG.TODO/hurd/fd-close.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/fd.h>
+
+error_t
+_hurd_fd_close (struct hurd_fd *fd)
+{
+  error_t err;
+
+  HURD_CRITICAL_BEGIN;
+
+  __spin_lock (&fd->port.lock);
+  if (fd->port.port == MACH_PORT_NULL)
+    {
+      __spin_unlock (&fd->port.lock);
+      err = EBADF;
+    }
+  else
+    {
+      /* Clear the descriptor's port cells.
+	 This deallocates the ports if noone else is still using them.  */
+      _hurd_port_set (&fd->ctty, MACH_PORT_NULL);
+      _hurd_port_locked_set (&fd->port, MACH_PORT_NULL);
+      err = 0;
+    }
+
+  HURD_CRITICAL_END;
+
+  return err;
+}
diff --git a/REORG.TODO/hurd/fd-read.c b/REORG.TODO/hurd/fd-read.c
new file mode 100644
index 0000000000..361b96f969
--- /dev/null
+++ b/REORG.TODO/hurd/fd-read.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <string.h>
+
+error_t
+_hurd_fd_read (struct hurd_fd *fd, void *buf, size_t *nbytes, loff_t offset)
+{
+  error_t err;
+  char *data;
+  mach_msg_type_number_t nread;
+
+  error_t readfd (io_t port)
+    {
+      return __io_read (port, &data, &nread, offset, *nbytes);
+    }
+
+  data = buf;
+  nread = *nbytes;
+  if (err = HURD_FD_PORT_USE (fd, _hurd_ctty_input (port, ctty, readfd)))
+    return err;
+
+  if (data != buf)
+    {
+      if (nread > *nbytes)	/* Sanity check for bogus server.  */
+	{
+	  __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
+	  return EGRATUITOUS;
+	}
+      memcpy (buf, data, nread);
+      __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
+    }
+
+  *nbytes = nread;
+  return 0;
+}
diff --git a/REORG.TODO/hurd/fd-write.c b/REORG.TODO/hurd/fd-write.c
new file mode 100644
index 0000000000..8ab9bbd43b
--- /dev/null
+++ b/REORG.TODO/hurd/fd-write.c
@@ -0,0 +1,42 @@
+/* _hurd_fd_write -- write to a file descriptor; handles job control et al.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+
+error_t
+_hurd_fd_write (struct hurd_fd *fd,
+		const void *buf, size_t *nbytes, loff_t offset)
+{
+  error_t err;
+  mach_msg_type_number_t wrote;
+
+  error_t writefd (io_t port)
+    {
+      return __io_write (port, buf, *nbytes, offset, &wrote);
+    }
+
+  err = HURD_FD_PORT_USE (fd, _hurd_ctty_output (port, ctty, writefd));
+
+  if (! err)
+    *nbytes = wrote;
+
+  return err;
+}
diff --git a/REORG.TODO/hurd/fopenport.c b/REORG.TODO/hurd/fopenport.c
new file mode 100644
index 0000000000..42be313e6a
--- /dev/null
+++ b/REORG.TODO/hurd/fopenport.c
@@ -0,0 +1,132 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+
+/* Read up to N chars into BUF from COOKIE.
+   Return how many chars were read, 0 for EOF or -1 for error.  */
+static ssize_t
+readio (void *cookie, char *buf, size_t n)
+{
+  mach_msg_type_number_t nread;
+  error_t err;
+  char *bufp = buf;
+
+  nread = n;
+  if (err = __io_read ((io_t) cookie, &bufp, &nread, -1, n))
+    return __hurd_fail (err);
+
+  if (bufp != buf)
+    {
+      memcpy (buf, bufp, nread);
+      __vm_deallocate (__mach_task_self (),
+		       (vm_address_t) bufp, (vm_size_t) nread);
+    }
+
+  return nread;
+}
+
+/* Write up to N chars from BUF to COOKIE.
+   Return how many chars were written or -1 for error.  */
+static ssize_t
+writeio (void *cookie, const char *buf, size_t n)
+{
+  mach_msg_type_number_t wrote;
+  error_t err;
+
+  if (err = __io_write ((io_t) cookie, buf, n, -1, &wrote))
+    return __hurd_fail (err);
+
+  return wrote;
+}
+
+/* Move COOKIE's file position *POS bytes, according to WHENCE.
+   The current file position is stored in *POS.
+   Returns zero if successful, nonzero if not.  */
+static int
+seekio (void *cookie,
+	_IO_off64_t *pos,
+	int whence)
+{
+  error_t err = __io_seek ((file_t) cookie, *pos, whence, pos);
+  return err ? __hurd_fail (err) : 0;
+}
+
+/* Close the file associated with COOKIE.
+   Return 0 for success or -1 for failure.  */
+static int
+closeio (void *cookie)
+{
+  error_t error = __mach_port_deallocate (__mach_task_self (),
+					  (mach_port_t) cookie);
+  if (error)
+    return __hurd_fail (error);
+  return 0;
+}
+
+#include "../libio/libioP.h"
+#define fopencookie _IO_fopencookie
+static const cookie_io_functions_t funcsio =
+{ readio, writeio, seekio, closeio };
+
+
+/* Open a stream on PORT.  MODE is as for fopen.  */
+
+FILE *
+__fopenport (mach_port_t port, const char *mode)
+{
+  int pflags;
+  int needflags;
+  error_t err;
+
+  const char *m = mode;
+
+  switch (*m++)
+    {
+    case 'r':
+      needflags = O_READ;
+      break;
+    case 'w':
+      needflags = O_WRITE;
+      break;
+    case 'a':
+      needflags = O_WRITE|O_APPEND;
+      break;
+    default:
+      return NULL;
+  }
+  if (m[0] == '+' || (m[0] == 'b' && m[1] == '+'))
+    needflags |= O_RDWR;
+
+  /* Verify the PORT is valid allows the access MODE specifies.  */
+
+  if (err = __io_get_openmodes (port, &pflags))
+    return __hurd_fail (err), NULL;
+
+  /* Check the access mode.  */
+  if ((pflags & needflags) != needflags)
+    {
+      errno = EBADF;
+      return NULL;
+    }
+
+  return fopencookie ((void *) port, mode, funcsio);
+}
+weak_alias (__fopenport, fopenport)
diff --git a/REORG.TODO/hurd/get-host.c b/REORG.TODO/hurd/get-host.c
new file mode 100644
index 0000000000..be8345fbf9
--- /dev/null
+++ b/REORG.TODO/hurd/get-host.c
@@ -0,0 +1,92 @@
+/* Get a host configuration item kept as the whole contents of a file.
+   Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include "hurdhost.h"
+#include <string.h>
+
+ssize_t
+_hurd_get_host_config (const char *item, char *buf, size_t buflen)
+{
+  error_t err;
+  char *data;
+  mach_msg_type_number_t nread, more;
+  file_t config;
+
+  err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, 0,
+				 item, O_RDONLY, 0, &config);
+  switch (err)
+    {
+    case 0:			/* Success; read file contents below.  */
+      break;
+
+    case ENOENT:		/* ? Others?  All errors? */
+      /* The file does not exist, so no value has been set.  Rather than
+	 causing gethostname et al to fail with ENOENT, give an empty value
+	 as other systems do before sethostname has been called.  */
+      if (buflen != 0)
+	*buf = '\0';
+      return 0;
+
+    default:
+      return __hurd_fail (err);
+    }
+
+  data = buf;
+  nread = buflen;
+  err = __io_read (config, &data, &nread, -1, buflen);
+  if (! err)
+    /* Check if there is more in the file we didn't read.  */
+    err = __io_readable (config, &more);
+  __mach_port_deallocate (__mach_task_self (), config);
+  if (err)
+    return __hurd_fail (err);
+  if (data != buf)
+    {
+      memcpy (buf, data, nread);
+      __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
+    }
+
+  /* If the file is empty, give an empty value.  */
+  if (nread == 0)
+    {
+      if (buflen != 0)
+	*buf = '\0';
+      return 0;
+    }
+
+  /* Remove newlines in case someone wrote the file by hand.  */
+  while (nread > 0 && buf[nread - 1] == '\n')
+    buf[--nread] = '\0';
+
+  /* Null-terminate the result if there is enough space.  */
+  if (nread < buflen)
+    buf[nread] = '\0';
+  else
+    if (buf[nread - 1] != '\0')
+      more = 1;
+
+  if (more)
+    /* If we didn't read the whole file, tell the caller to use a bigger
+       buffer next time.  */
+    return __hurd_fail (ENAMETOOLONG);
+
+  return nread;
+}
diff --git a/REORG.TODO/hurd/getdport.c b/REORG.TODO/hurd/getdport.c
new file mode 100644
index 0000000000..d400a9f62d
--- /dev/null
+++ b/REORG.TODO/hurd/getdport.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+/* This is initialized in dtable.c when that gets linked in.
+   If dtable.c is not linked in, it will be zero.  */
+static file_t (*_default_hurd_getdport_fn) (int fd) = 0;
+weak_alias (_default_hurd_getdport_fn, _hurd_getdport_fn)
+
+file_t
+__getdport (int fd)
+{
+  if (_hurd_getdport_fn)
+    /* dtable.c has defined the function to fetch a port from the real file
+       descriptor table.  */
+    return (*_hurd_getdport_fn) (fd);
+
+  /* getdport is the only use of file descriptors,
+     so we don't bother allocating a real table.  */
+
+  if (_hurd_init_dtable == NULL)
+    {
+      /* Never had a descriptor table.  */
+      errno = EBADF;
+      return MACH_PORT_NULL;
+    }
+
+  if (fd < 0 || (unsigned int) fd > _hurd_init_dtablesize ||
+      _hurd_init_dtable[fd] == MACH_PORT_NULL)
+    {
+      errno = EBADF;
+      return MACH_PORT_NULL;
+    }
+  else
+    {
+      __mach_port_mod_refs (__mach_task_self (), _hurd_init_dtable[fd],
+			    MACH_PORT_RIGHT_SEND, 1);
+      return _hurd_init_dtable[fd];
+    }
+}
+
+weak_alias (__getdport, getdport)
diff --git a/REORG.TODO/hurd/geteuids.c b/REORG.TODO/hurd/geteuids.c
new file mode 100644
index 0000000000..5c0796fef9
--- /dev/null
+++ b/REORG.TODO/hurd/geteuids.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/id.h>
+#include <string.h>
+
+int
+geteuids (int n, uid_t *uidset)
+{
+  error_t err;
+  int nuids;
+  void *crit;
+
+  crit = _hurd_critical_section_lock ();
+  __mutex_lock (&_hurd_id.lock);
+
+  if (err = _hurd_check_ids ())
+    {
+      __mutex_unlock (&_hurd_id.lock);
+      _hurd_critical_section_unlock (crit);
+      return __hurd_fail (err);
+    }
+
+  nuids = _hurd_id.gen.nuids;
+
+  if (n != 0)
+    {
+      /* Copy the uids onto stack storage and then release the idlock.  */
+      uid_t uids[nuids];
+      memcpy (uids, _hurd_id.gen.uids, sizeof (uids));
+      __mutex_unlock (&_hurd_id.lock);
+      _hurd_critical_section_unlock (crit);
+
+      /* Now that the lock is released, we can safely copy the
+	 uid set into the user's array, which might fault.  */
+      if (nuids > n)
+	nuids = n;
+      memcpy (uidset, uids, nuids * sizeof (uid_t));
+    }
+  else
+    {
+      __mutex_unlock (&_hurd_id.lock);
+      _hurd_critical_section_unlock (crit);
+    }
+
+  return nuids;
+}
+
+/* XXX Remove this alias when we bump the libc soname.  */
+
+#ifdef SHARED
+weak_alias (geteuids, __getuids)
+#endif
diff --git a/REORG.TODO/hurd/getumask.c b/REORG.TODO/hurd/getumask.c
new file mode 100644
index 0000000000..452a671720
--- /dev/null
+++ b/REORG.TODO/hurd/getumask.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 1992-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+mode_t
+getumask (void)
+{
+  return _hurd_umask;
+}
diff --git a/REORG.TODO/hurd/hurd-raise.c b/REORG.TODO/hurd/hurd-raise.c
new file mode 100644
index 0000000000..af99db38bd
--- /dev/null
+++ b/REORG.TODO/hurd/hurd-raise.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <hurd/msg.h>
+#include <setjmp.h>
+
+/* Handle signal SIGNO in the calling thread.
+   If SS is not NULL it is the sigstate for the calling thread;
+   SS->lock is held on entry and released before return.  */
+
+int
+_hurd_raise_signal (struct hurd_sigstate *ss,
+		    int signo, const struct hurd_signal_detail *detail)
+{
+  if (ss == NULL)
+    {
+      ss = _hurd_self_sigstate ();
+      __spin_lock (&ss->lock);
+    }
+
+  /* Mark SIGNO as pending to be delivered.  */
+  __sigaddset (&ss->pending, signo);
+  ss->pending_data[signo] = *detail;
+
+  __spin_unlock (&ss->lock);
+
+  /* Send a message to the signal thread so it will wake up and check for
+     pending signals.  This is a generic "poll request" message (SIGNO==0)
+     rather than delivering this signal and its detail, because we have
+     already marked the signal as pending for the particular thread we
+     want.  Generating the signal with an RPC might deliver it to some
+     other thread.  */
+  return __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
+}
diff --git a/REORG.TODO/hurd/hurd.h b/REORG.TODO/hurd/hurd.h
new file mode 100644
index 0000000000..3caa69fbdf
--- /dev/null
+++ b/REORG.TODO/hurd/hurd.h
@@ -0,0 +1,345 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_H
+
+#define	_HURD_H	1
+#include <features.h>
+
+
+/* Get types, macros, constants and function declarations
+   for all Mach microkernel interaction.  */
+#include <mach.h>
+#include <mach/mig_errors.h>
+
+/* Get types and constants necessary for Hurd interfaces.  */
+#include <hurd/hurd_types.h>
+
+/* Get MiG stub declarations for commonly used Hurd interfaces.  */
+#include <hurd/auth.h>
+#include <hurd/process.h>
+#include <hurd/fs.h>
+#include <hurd/io.h>
+
+/* Get `struct hurd_port' and related definitions implementing lightweight
+   user references for ports.  These are used pervasively throughout the C
+   library; this is here to avoid putting it in nearly every source file.  */
+#include <hurd/port.h>
+
+#include <errno.h>
+
+#ifndef _HURD_H_EXTERN_INLINE
+#define _HURD_H_EXTERN_INLINE __extern_inline
+#endif
+
+_HURD_H_EXTERN_INLINE int
+__hurd_fail (error_t err)
+{
+  switch (err)
+    {
+    case EMACH_SEND_INVALID_DEST:
+    case EMIG_SERVER_DIED:
+      /* The server has disappeared!  */
+      err = (error_t) EIEIO;
+      break;
+
+    case KERN_NO_SPACE:
+      err = (error_t) ENOMEM;
+      break;
+
+    case KERN_INVALID_ARGUMENT:
+      err = (error_t) EINVAL;
+      break;
+
+    case 0:
+      return 0;
+
+    default:
+      break;
+    }
+
+  errno = err;
+  return -1;
+}
+
+/* Basic ports and info, initialized by startup.  */
+
+extern int _hurd_exec_flags;	/* Flags word passed in exec_startup.  */
+extern struct hurd_port *_hurd_ports;
+extern unsigned int _hurd_nports;
+extern mode_t _hurd_umask;
+extern sigset_t _hurdsig_traced;
+
+/* Shorthand macro for internal library code referencing _hurd_ports (see
+   <hurd/port.h>).  */
+
+#define	__USEPORT(which, expr) \
+  HURD_PORT_USE (&_hurd_ports[INIT_PORT_##which], (expr))
+
+/* Function version of __USEPORT: calls OPERATE with a send right.  */
+
+extern error_t _hurd_ports_use (int which, error_t (*operate) (mach_port_t));
+
+
+/* Base address and size of the initial stack set up by the exec server.
+   If using cthreads, this stack is deallocated in startup.
+   Not locked.  */
+
+extern vm_address_t _hurd_stack_base;
+extern vm_size_t _hurd_stack_size;
+
+/* Initial file descriptor table we were passed at startup.  If we are
+   using a real dtable, these are turned into that and then cleared at
+   startup.  If not, these are never changed after startup.  Not locked.  */
+
+extern mach_port_t *_hurd_init_dtable;
+extern mach_msg_type_number_t _hurd_init_dtablesize;
+
+/* Current process IDs.  */
+
+extern pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp;
+extern int _hurd_orphaned;
+
+/* This variable is incremented every time the process IDs change.  */
+extern unsigned int _hurd_pids_changed_stamp;
+
+/* This condition is broadcast every time the process IDs change.  */
+extern struct condition _hurd_pids_changed_sync;
+
+/* Unix `data break', for brk and sbrk.
+   If brk and sbrk are not used, this info will not be initialized or used.  */
+
+
+/* Data break.  This is what `sbrk (0)' returns.  */
+
+extern vm_address_t _hurd_brk;
+
+/* End of allocated space.  This is generally `round_page (_hurd_brk)'.  */
+
+extern vm_address_t _hurd_data_end;
+
+/* This mutex locks _hurd_brk and _hurd_data_end.  */
+
+extern struct mutex _hurd_brk_lock;
+
+/* Set the data break to NEWBRK; _hurd_brk_lock must
+   be held, and is released on return.  */
+
+extern int _hurd_set_brk (vm_address_t newbrk);
+
+#include <bits/types/FILE.h>
+
+/* Calls to get and set basic ports.  */
+
+extern error_t _hurd_ports_get (unsigned int which, mach_port_t *result);
+extern error_t _hurd_ports_set (unsigned int which, mach_port_t newport);
+
+extern process_t getproc (void);
+extern file_t getcwdir (void), getcrdir (void);
+extern auth_t getauth (void);
+extern mach_port_t getcttyid (void);
+extern int setproc (process_t);
+extern int setcwdir (file_t), setcrdir (file_t);
+extern int setcttyid (mach_port_t);
+
+/* Does reauth with the proc server and fd io servers.  */
+extern int __setauth (auth_t), setauth (auth_t);
+
+
+/* Modify a port cell by looking up a directory name.
+   This verifies that it is a directory and that we have search permission.  */
+extern int _hurd_change_directory_port_from_name (struct hurd_port *portcell,
+						  const char *name);
+/* Same thing, but using an open file descriptor.
+   Also verifies that it is a directory and that we have search permission.  */
+extern int _hurd_change_directory_port_from_fd (struct hurd_port *portcell,
+						int fd);
+
+
+
+/* Get and set the effective UID set.  */
+extern int geteuids (int __n, uid_t *__uidset);
+extern int seteuids (int __n, const uid_t *__uidset);
+
+
+/* Split FILE into a directory and a name within the directory.  The
+   directory lookup uses the current root and working directory.  If
+   successful, stores in *NAME a pointer into FILE where the name
+   within directory begins and returns a port to the directory;
+   otherwise sets `errno' and returns MACH_PORT_NULL.  */
+
+extern file_t __file_name_split (const char *file, char **name);
+extern file_t file_name_split (const char *file, char **name);
+
+/* Split DIRECTORY into a parent directory and a name within the directory.
+   This is the same as file_name_split, but ignores trailing slashes.  */
+
+extern file_t __directory_name_split (const char *file, char **name);
+extern file_t directory_name_split (const char *file, char **name);
+
+/* Open a port to FILE with the given FLAGS and MODE (see <fcntl.h>).
+   The file lookup uses the current root and working directory.
+   Returns a port to the file if successful; otherwise sets `errno'
+   and returns MACH_PORT_NULL.  */
+
+extern file_t __file_name_lookup (const char *file, int flags, mode_t mode);
+extern file_t file_name_lookup (const char *file, int flags, mode_t mode);
+
+/* Open a port to FILE with the given FLAGS and MODE (see <fcntl.h>).  The
+   file lookup uses the current root directory, but uses STARTDIR as the
+   "working directory" for file relative names.  Returns a port to the file
+   if successful; otherwise sets `errno' and returns MACH_PORT_NULL.  */
+
+extern file_t __file_name_lookup_under (file_t startdir, const char *file,
+					int flags, mode_t mode);
+extern file_t file_name_lookup_under (file_t startdir, const char *file,
+				      int flags, mode_t mode);
+
+
+/* Lookup FILE_NAME and return the node opened with FLAGS & MODE
+   (see hurd_file_name_lookup for details), but a simple file name (without
+   any directory prefixes) will be consecutively prefixed with the pathnames
+   in the `:' separated list PATH until one succeeds in a successful lookup.
+   If none succeed, then the first error that wasn't ENOENT is returned, or
+   ENOENT if no other errors were returned.  If PREFIXED_NAME is non-NULL,
+   then if the result is looked up directly, *PREFIXED_NAME is set to NULL, and
+   if it is looked up using a prefix from PATH, *PREFIXED_NAME is set to
+   malloc'd storage containing the prefixed name.  */
+extern file_t file_name_path_lookup (const char *file_name, const char *path,
+				     int flags, mode_t mode,
+				     char **prefixed_name);
+
+
+
+/* Open a file descriptor on a port.  FLAGS are as for `open'; flags
+   affected by io_set_openmodes are not changed by this.  If successful,
+   this consumes a user reference for PORT (which will be deallocated on
+   close).  */
+
+extern int openport (io_t port, int flags);
+
+/* Open a stream on a port.  MODE is as for `fopen'.
+   If successful, this consumes a user reference for PORT
+   (which will be deallocated on fclose).  */
+
+extern FILE *fopenport (io_t port, const char *mode);
+extern FILE *__fopenport (io_t port, const char *mode);
+
+
+/* Execute a file, replacing TASK's current program image.  */
+
+extern error_t _hurd_exec (task_t task,
+			   file_t file,
+			   char *const argv[],
+			   char *const envp[]);
+
+
+/* Inform the proc server we have exited with STATUS, and kill the
+   task thoroughly.  This function never returns, no matter what.  */
+
+extern void _hurd_exit (int status) __attribute__ ((noreturn));
+
+
+/* Initialize the library data structures from the
+   ints and ports passed to us by the exec server.
+   Then vm_deallocate PORTARRAY and INTARRAY.  */
+
+extern void _hurd_init (int flags, char **argv,
+			mach_port_t *portarray, size_t portarraysize,
+			int *intarray, size_t intarraysize);
+
+/* Do startup handshaking with the proc server, and initialize library data
+   structures that require proc server interaction.  This includes
+   initializing signals; see _hurdsig_init in <hurd/signal.h>.  */
+
+extern void _hurd_proc_init (char **argv,
+			     const int *intarray, size_t intarraysize);
+
+
+/* Return the socket server for sockaddr domain DOMAIN.  If DEAD is
+   nonzero, remove the old cached port and always do a fresh lookup.
+
+   It is assumed that a socket server will stay alive during a complex socket
+   operation involving several RPCs.  But a socket server may die during
+   long idle periods between socket operations.  Callers should first pass
+   zero for DEAD; if the first socket RPC tried on the returned port fails
+   with MACH_SEND_INVALID_DEST or MIG_SERVER_DIED (indicating the server
+   went away), the caller should call _hurd_socket_server again with DEAD
+   nonzero and retry the RPC on the new socket server port.  */
+
+extern socket_t _hurd_socket_server (int domain, int dead);
+
+/* Send a `sig_post' RPC to process number PID.  If PID is zero,
+   send the message to all processes in the current process's process group.
+   If PID is < -1, send SIG to all processes in process group - PID.
+   SIG and REFPORT are passed along in the request message.  */
+
+extern error_t _hurd_sig_post (pid_t pid, int sig, mach_port_t refport);
+extern error_t hurd_sig_post (pid_t pid, int sig, mach_port_t refport);
+
+/* Fetch the host privileged port and device master port from the proc
+   server.  They are fetched only once and then cached in the
+   variables below.  A special program that gets them from somewhere
+   other than the proc server (such as a bootstrap filesystem) can set
+   these variables to install the ports.  */
+
+extern kern_return_t __get_privileged_ports (mach_port_t *host_priv_ptr,
+					     device_t *device_master_ptr);
+extern kern_return_t get_privileged_ports (mach_port_t *host_priv_ptr,
+					   device_t *device_master_ptr);
+extern mach_port_t _hurd_host_priv, _hurd_device_master;
+
+/* Return the PID of the task whose control port is TASK.
+   On error, sets `errno' and returns -1.  */
+
+extern pid_t __task2pid (task_t task), task2pid (task_t task);
+
+/* Return the task control port of process PID.
+   On error, sets `errno' and returns MACH_PORT_NULL.  */
+
+extern task_t __pid2task (pid_t pid), pid2task (pid_t pid);
+
+/* Return the current thread's thread port.  This is a cheap operation (no
+   system call), but it relies on Hurd signal state being set up.  */
+extern thread_t hurd_thread_self (void);
+
+
+/* Cancel pending operations on THREAD.  If it is doing an interruptible RPC,
+   that RPC will now return EINTR; otherwise, the "cancelled" flag will be
+   set, causing the next `hurd_check_cancel' call to return nonzero or the
+   next interruptible RPC to return EINTR (whichever is called first).  */
+extern error_t hurd_thread_cancel (thread_t thread);
+
+/* Test and clear the calling thread's "cancelled" flag.  */
+extern int hurd_check_cancel (void);
+
+
+/* Return the io server port for file descriptor FD.
+   This adds a Mach user reference to the returned port.
+   On error, sets `errno' and returns MACH_PORT_NULL.  */
+
+extern io_t __getdport (int fd), getdport (int fd);
+
+
+#include <stdarg.h>
+
+/* Write formatted output to PORT, a Mach port supporting the i/o protocol,
+   according to the format string FORMAT, using the argument list in ARG.  */
+int vpprintf (io_t port, const char *format, va_list arg);
+
+
+#endif	/* hurd.h */
diff --git a/REORG.TODO/hurd/hurd/fd.h b/REORG.TODO/hurd/hurd/fd.h
new file mode 100644
index 0000000000..8954be0d50
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/fd.h
@@ -0,0 +1,275 @@
+/* File descriptors.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_FD_H
+
+#define	_HURD_FD_H	1
+#include <features.h>
+
+#include <cthreads.h>
+
+#include <hurd/hurd_types.h>
+#include <hurd/port.h>
+#include <sys/socket.h>
+
+
+/* Structure representing a file descriptor.  */
+
+struct hurd_fd
+  {
+    struct hurd_port port;	/* io server port.  */
+    int flags;			/* fcntl flags; locked by port.lock.  */
+
+    /* Normal port to the ctty.  When `port' is our ctty, this is a port to
+       the same io object but which never returns EBACKGROUND; when not,
+       this is nil.  */
+    struct hurd_port ctty;
+  };
+
+
+/* Current file descriptor table.  */
+
+extern int _hurd_dtablesize;
+extern struct hurd_fd **_hurd_dtable;
+extern struct mutex _hurd_dtable_lock; /* Locks those two variables.  */
+
+#include <hurd/signal.h>
+
+#ifndef _HURD_FD_H_EXTERN_INLINE
+#define _HURD_FD_H_EXTERN_INLINE __extern_inline
+#endif
+
+/* Returns the descriptor cell for FD.  If FD is invalid or unused, return
+   NULL.  The cell is unlocked; when ready to use it, lock it and check for
+   it being unused.  */
+
+_HURD_FD_H_EXTERN_INLINE struct hurd_fd *
+_hurd_fd_get (int fd)
+{
+  struct hurd_fd *descriptor;
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_dtable_lock);
+  if (fd < 0 || fd >= _hurd_dtablesize)
+    descriptor = NULL;
+  else
+    {
+      struct hurd_fd *cell = _hurd_dtable[fd];
+      if (cell == NULL)
+	/* No descriptor allocated at this index.  */
+	descriptor = NULL;
+      else
+	{
+	  __spin_lock (&cell->port.lock);
+	  if (cell->port.port == MACH_PORT_NULL)
+	    /* The descriptor at this index has no port in it.
+	       This happens if it existed before but was closed.  */
+	    descriptor = NULL;
+	  else
+	    descriptor = cell;
+	  __spin_unlock (&cell->port.lock);
+	}
+    }
+  __mutex_unlock (&_hurd_dtable_lock);
+  HURD_CRITICAL_END;
+
+  return descriptor;
+}
+
+
+/* Evaluate EXPR with the variable `descriptor' bound to a pointer to the
+   file descriptor structure for FD.   */
+
+#define	HURD_FD_USE(fd, expr)						      \
+  ({ struct hurd_fd *descriptor = _hurd_fd_get (fd);			      \
+     descriptor == NULL ? EBADF : (expr); })
+
+/* Evaluate EXPR with the variable `port' bound to the port to FD, and
+   `ctty' bound to the ctty port.  */
+
+#define HURD_DPORT_USE(fd, expr) \
+  HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr)))
+
+/* Likewise, but FD is a pointer to the file descriptor structure.  */
+
+#define	HURD_FD_PORT_USE(fd, expr)					      \
+  ({ error_t __result;							      \
+     struct hurd_fd *const __d = (fd);					      \
+     struct hurd_userlink __ulink, __ctty_ulink;			      \
+     io_t port, ctty;							      \
+     void *crit = _hurd_critical_section_lock ();			      \
+     __spin_lock (&__d->port.lock);					      \
+     if (__d->port.port == MACH_PORT_NULL)				      \
+       {								      \
+	 __spin_unlock (&__d->port.lock);				      \
+	 _hurd_critical_section_unlock (crit);				      \
+	 __result = EBADF;						      \
+       }								      \
+     else								      \
+       {								      \
+	 ctty = _hurd_port_get (&__d->ctty, &__ctty_ulink);		      \
+	 port = _hurd_port_locked_get (&__d->port, &__ulink);		      \
+	 _hurd_critical_section_unlock (crit);				      \
+	 __result = (expr);						      \
+	 _hurd_port_free (&__d->port, &__ulink, port);			      \
+	 if (ctty != MACH_PORT_NULL)					      \
+	   _hurd_port_free (&__d->ctty, &__ctty_ulink, ctty);		      \
+       }								      \
+     __result; })
+
+#include <errno.h>
+
+/* Check if ERR should generate a signal.
+   Returns the signal to take, or zero if none.  */
+
+_HURD_FD_H_EXTERN_INLINE int
+_hurd_fd_error_signal (error_t err)
+{
+  switch (err)
+    {
+    case EMACH_SEND_INVALID_DEST:
+    case EMIG_SERVER_DIED:
+      /* The server has disappeared!  */
+      return SIGLOST;
+    case EPIPE:
+      return SIGPIPE;
+    default:
+      /* Having a default case avoids -Wenum-switch warnings.  */
+      return 0;
+    }
+}
+
+/* Handle an error from an RPC on a file descriptor's port.  You should
+   always use this function to handle errors from RPCs made on file
+   descriptor ports.  Some errors are translated into signals.  */
+
+_HURD_FD_H_EXTERN_INLINE error_t
+_hurd_fd_error (int fd, error_t err)
+{
+  int signo = _hurd_fd_error_signal (err);
+  if (signo)
+    {
+      const struct hurd_signal_detail detail
+	= { code: fd, error: err, exc: 0 };
+      _hurd_raise_signal (NULL, signo, &detail);
+    }
+  return err;
+}
+
+/* Handle error code ERR from an RPC on file descriptor FD's port.
+   Set `errno' to the appropriate error code, and always return -1.  */
+
+_HURD_FD_H_EXTERN_INLINE int
+__hurd_dfail (int fd, error_t err)
+{
+  errno = _hurd_fd_error (fd, err);
+  return -1;
+}
+
+/* Likewise, but do not raise SIGPIPE on EPIPE if flags contain
+   MSG_NOSIGNAL.  */
+
+_HURD_FD_H_EXTERN_INLINE int
+__hurd_sockfail (int fd, int flags, error_t err)
+{
+  if (!(flags & MSG_NOSIGNAL) || err != EPIPE)
+    err = _hurd_fd_error (fd, err);
+  errno = err;
+  return -1;
+}
+
+/* Set up *FD to have PORT its server port, doing appropriate ctty magic.
+   Does no locking or unlocking.  */
+
+extern void _hurd_port2fd (struct hurd_fd *fd, io_t port, int flags);
+
+/* Allocate a new file descriptor and install PORT in it (doing any
+   appropriate ctty magic); consumes a user reference on PORT.  FLAGS are
+   as for `open'; only O_IGNORE_CTTY and O_CLOEXEC are meaningful, but all are
+   saved.
+
+   If the descriptor table is full, set errno, and return -1.
+   If DEALLOC is nonzero, deallocate PORT first.  */
+
+extern int _hurd_intern_fd (io_t port, int flags, int dealloc);
+
+/* Allocate a new file descriptor in the table and return it, locked.  The
+   new descriptor number will be no less than FIRST_FD.  If the table is
+   full, set errno to EMFILE and return NULL.  If FIRST_FD is negative or
+   bigger than the size of the table, set errno to EINVAL and return NULL.  */
+
+extern struct hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd);
+
+/* Allocate a new file descriptor structure and initialize its port cells
+   with PORT and CTTY.  (This does not affect the descriptor table.)  */
+
+extern struct hurd_fd *_hurd_new_fd (io_t port, io_t ctty);
+
+/* Close a file descriptor, making it available for future reallocation.  */
+
+extern error_t _hurd_fd_close (struct hurd_fd *fd);
+
+/* Read and write data from a file descriptor; just like `read' and `write'
+   if OFFSET is -1, or like `pread' and `pwrite' if OFFSET is not -1.
+   If successful, stores the amount actually read or written in *NBYTES.  */
+
+extern error_t _hurd_fd_read (struct hurd_fd *fd,
+			      void *buf, size_t *nbytes, loff_t offset);
+extern error_t _hurd_fd_write (struct hurd_fd *fd,
+			       const void *buf, size_t *nbytes, loff_t offset);
+
+
+/* Call *RPC on PORT and/or CTTY; if a call on CTTY returns EBACKGROUND,
+   generate SIGTTIN/SIGTTOU or EIO as appropriate.  */
+
+extern error_t _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t));
+extern error_t _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t));
+
+
+/* The guts of `select' and `poll'.  Check the first NFDS descriptors
+   either in POLLFDS (if nonnull) or in each of READFDS, WRITEFDS,
+   EXCEPTFDS that is nonnull.  If TIMEOUT is not NULL, time out after
+   waiting the interval specified therein.  If SIGMASK is nonnull,
+   the set of blocked signals is temporarily set to that during this call.
+   Returns the number of ready descriptors, or -1 for errors.  */
+struct pollfd;
+struct timespec;
+extern int _hurd_select (int nfds, struct pollfd *pollfds,
+			 fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+			 const struct timespec *timeout,
+			 const sigset_t *sigmask);
+
+/* Variant of file_name_lookup used in *at function implementations.
+   AT_FLAGS may only contain AT_SYMLINK_FOLLOW or AT_SYMLINK_NOFOLLOW,
+   which will remove and add O_NOLINK from FLAGS respectively.
+   Other bits cause EINVAL.  */
+extern file_t __file_name_lookup_at (int fd, int at_flags,
+				     const char *file_name,
+				     int flags, mode_t mode);
+
+/* Variant of file_name_split used in *at function implementations.  */
+extern file_t __file_name_split_at (int fd, const char *file_name,
+				    char **name);
+
+/* Variant of directory_name_split used in *at function implementations.  */
+extern file_t __directory_name_split_at (int fd, const char *directory_name,
+					 char **name);
+
+
+
+#endif	/* hurd/fd.h */
diff --git a/REORG.TODO/hurd/hurd/id.h b/REORG.TODO/hurd/hurd/id.h
new file mode 100644
index 0000000000..ef1292ebe8
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/id.h
@@ -0,0 +1,54 @@
+/* User and group IDs.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_ID_H
+
+#define	_HURD_ID_H	1
+#include <features.h>
+
+#include <cthreads.h>		/* For `struct mutex'.  */
+
+/* Structure describing authorization data for the process.  */
+
+struct hurd_id_data
+  {
+    struct mutex lock;
+
+    int valid;			/* If following data are up to date.  */
+
+    struct
+      {
+	uid_t *uids;
+	gid_t *gids;
+	mach_msg_type_number_t nuids, ngids;
+      } gen, aux;
+
+    auth_t rid_auth;		/* Cache used by access.  */
+  };
+
+/* Current data.  */
+
+extern struct hurd_id_data _hurd_id;
+
+
+/* Update _hurd_id (caller should be holding the lock).  */
+
+extern error_t _hurd_check_ids (void);
+
+
+#endif	/* hurd/id.h */
diff --git a/REORG.TODO/hurd/hurd/ioctl.h b/REORG.TODO/hurd/hurd/ioctl.h
new file mode 100644
index 0000000000..0423b8cb9f
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/ioctl.h
@@ -0,0 +1,81 @@
+/* User-registered handlers for specific `ioctl' requests.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_IOCTL_H
+#define	_HURD_IOCTL_H	1
+
+#define	__need___va_list
+#include <stdarg.h>
+#include <bits/ioctls.h>
+
+
+/* Type of handler function, called like ioctl to do its entire job.  */
+typedef int (*ioctl_handler_t) (int fd, int request, void *arg);
+
+/* Structure that records an ioctl handler.  */
+struct ioctl_handler
+  {
+    /* Range of handled _IOC_NOTYPE (REQUEST) values.  */
+    int first_request, last_request;
+
+    /* Handler function, called like ioctl to do its entire job.  */
+    ioctl_handler_t handler;
+
+    struct ioctl_handler *next;	/* Next handler.  */
+  };
+
+
+/* Register HANDLER to handle ioctls with REQUEST values between
+   FIRST_REQUEST and LAST_REQUEST inclusive.  Returns zero if successful.
+   Return nonzero and sets `errno' for an error.  */
+
+extern int hurd_register_ioctl_handler (int first_request, int last_request,
+					ioctl_handler_t handler);
+
+
+/* Define a library-internal handler for ioctl commands between FIRST and
+   LAST inclusive.  The last element gratuitously references HANDLER to
+   avoid `defined but not used' warnings.  */
+
+#define	_HURD_HANDLE_IOCTLS_1(handler, first, last, moniker)		      \
+  static const struct ioctl_handler handler##_ioctl_handler##moniker	      \
+	__attribute__ ((__unused__)) =					      \
+    { _IOC_NOTYPE (first), _IOC_NOTYPE (last),				      \
+	(ioctl_handler_t) (handler), NULL };				      \
+  text_set_element (_hurd_ioctl_handler_lists,				      \
+                    handler##_ioctl_handler##moniker)
+#define	_HURD_HANDLE_IOCTLS(handler, first, last)			      \
+  _HURD_HANDLE_IOCTLS_1 (handler, first, last, first##_to_##last)
+
+/* Define a library-internal handler for a single ioctl command.  */
+
+#define _HURD_HANDLE_IOCTL(handler, ioctl) \
+  _HURD_HANDLE_IOCTLS_1 (handler, ioctl, ioctl, ioctl##_only)
+
+
+/* Install a new CTTYID port, atomically updating the dtable appropriately.
+   This consumes the send right passed in.  */
+
+void _hurd_locked_install_cttyid (mach_port_t cttyid);
+
+/* Lookup the handler for the given ioctl request.  */
+
+ioctl_handler_t _hurd_lookup_ioctl_handler (int request);
+
+
+#endif	/* hurd/ioctl.h */
diff --git a/REORG.TODO/hurd/hurd/lookup.h b/REORG.TODO/hurd/hurd/lookup.h
new file mode 100644
index 0000000000..99052994c7
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/lookup.h
@@ -0,0 +1,190 @@
+/* Declarations of file name translation functions for the GNU Hurd.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURD_LOOKUP_H
+#define _HURD_LOOKUP_H	1
+
+/* These functions all take two callback functions as the first two arguments.
+   The first callback function USE_INIT_PORT is called as follows:
+
+   error_t use_init_port (int which, error_t (*operate) (mach_port_t));
+
+   WHICH is nonnegative value less than INIT_PORT_MAX, indicating which
+   init port is required.  The callback function should call *OPERATE
+   with a send right to the appropriate init port.  No user reference
+   is consumed; the right will only be used after *OPERATE returns if
+   *OPERATE has added its own user reference.
+
+   LOOKUP is a function to do the actual filesystem lookup.  It is passed the
+   same arguments that the dir_lookup rpc accepts, and if 0, __dir_lookup is
+   used.
+
+   The second callback function GET_DTABLE_PORT should behave like `getdport'.
+
+   All these functions return zero on success or an error code on failure.  */
+
+
+/* Open a port to FILE with the given FLAGS and MODE (see <fcntl.h>).  If
+   successful, returns zero and store the port to FILE in *PORT; otherwise
+   returns an error code. */
+
+error_t __hurd_file_name_lookup (error_t (*use_init_port)
+				   (int which,
+				    error_t (*operate) (mach_port_t)),
+				 file_t (*get_dtable_port) (int fd),
+				 error_t (*lookup)
+				   (file_t dir, char *name, int flags, mode_t mode,
+				    retry_type *do_retry, string_t retry_name,
+				    mach_port_t *result),
+				 const char *file_name,
+				 int flags, mode_t mode,
+				 file_t *result);
+error_t hurd_file_name_lookup (error_t (*use_init_port)
+			         (int which,
+				  error_t (*operate) (mach_port_t)),
+			       file_t (*get_dtable_port) (int fd),
+			       error_t (*lookup)
+				 (file_t dir, char *name, int flags, mode_t mode,
+				  retry_type *do_retry, string_t retry_name,
+				  mach_port_t *result),
+			       const char *file_name,
+			       int flags, mode_t mode,
+			       file_t *result);
+
+
+/* Split FILE into a directory and a name within the directory.  Look up a
+   port for the directory and store it in *DIR; store in *NAME a pointer
+   into FILE where the name within directory begins.  */
+
+error_t __hurd_file_name_split (error_t (*use_init_port)
+				  (int which,
+				   error_t (*operate) (mach_port_t)),
+				file_t (*get_dtable_port) (int fd),
+				error_t (*lookup) (file_t dir, char *name,
+						   int flags, mode_t mode,
+				   retry_type *do_retry, string_t retry_name,
+				   mach_port_t *result),
+				const char *file_name,
+				file_t *dir, char **name);
+error_t hurd_file_name_split (error_t (*use_init_port)
+			        (int which,
+				 error_t (*operate) (mach_port_t)),
+			      file_t (*get_dtable_port) (int fd),
+			      error_t (*lookup) (file_t dir, char *name,
+						 int flags, mode_t mode,
+				 retry_type *do_retry, string_t retry_name,
+				 mach_port_t *result),
+			      const char *file_name,
+			      file_t *dir, char **name);
+
+/* Split DIRECTORY into a parent directory and a name within the directory.
+   This is the same as hurd_file_name_split, but ignores trailing slashes.  */
+
+error_t __hurd_directory_name_split (error_t (*use_init_port)
+				  (int which,
+				   error_t (*operate) (mach_port_t)),
+				file_t (*get_dtable_port) (int fd),
+				error_t (*lookup) (file_t dir, char *name,
+						   int flags, mode_t mode,
+				   retry_type *do_retry, string_t retry_name,
+				   mach_port_t *result),
+				const char *directory_name,
+				file_t *dir, char **name);
+error_t hurd_directory_name_split (error_t (*use_init_port)
+				   (int which,
+				    error_t (*operate) (mach_port_t)),
+				   file_t (*get_dtable_port) (int fd),
+				   error_t (*lookup) (file_t dir, char *name,
+						      int flags, mode_t mode,
+				    retry_type *do_retry, string_t retry_name,
+				    mach_port_t *result),
+				   const char *directory_name,
+				   file_t *dir, char **name);
+
+
+/* Process the values returned by `dir_lookup' et al, and loop doing
+   `dir_lookup' calls until one returns FS_RETRY_NONE.  The arguments
+   should be those just passed to and/or returned from `dir_lookup',
+   `fsys_getroot', or `file_invoke_translator'.  This function consumes the
+   reference in *RESULT even if it returns an error.  */
+
+error_t __hurd_file_name_lookup_retry (error_t (*use_init_port)
+				         (int which,
+					  error_t (*operate) (mach_port_t)),
+				       file_t (*get_dtable_port) (int fd),
+				       error_t (*lookup)
+				         (file_t dir, char *name,
+					  int flags, mode_t mode,
+					  retry_type *do_retry,
+					  string_t retry_name,
+					  mach_port_t *result),
+				       enum retry_type doretry,
+				       char retryname[1024],
+				       int flags, mode_t mode,
+				       file_t *result);
+error_t hurd_file_name_lookup_retry (error_t (*use_init_port)
+				       (int which,
+					error_t (*operate) (mach_port_t)),
+				     file_t (*get_dtable_port) (int fd),
+				     error_t (*lookup)
+				       (file_t dir, char *name,
+					int flags, mode_t mode,
+					retry_type *do_retry,
+					string_t retry_name,
+					mach_port_t *result),
+				     enum retry_type doretry,
+				     char retryname[1024],
+				     int flags, mode_t mode,
+				     file_t *result);
+
+
+/* If FILE_NAME contains a '/', or PATH is NULL, call FUN with FILE_NAME, and
+   return the result (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to
+   NULL).  Otherwise, call FUN repeatedly with FILE_NAME prefixed with each
+   successive `:' separated element of PATH, returning whenever FUN returns
+   0 (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to the resulting
+   prefixed path).  If FUN never returns 0, return the first non-ENOENT
+   return value, or ENOENT if there is none.  */
+error_t file_name_path_scan (const char *file_name, const char *path,
+			     error_t (*fun)(const char *name),
+			     char **prefixed_name);
+
+/* Lookup FILE_NAME and return the node opened with FLAGS & MODE in result
+   (see hurd_file_name_lookup for details), but a simple filename (without
+   any directory prefixes) will be consecutively prefixed with the pathnames
+   in the `:' separated list PATH until one succeeds in a successful lookup.
+   If none succeed, then the first error that wasn't ENOENT is returned, or
+   ENOENT if no other errors were returned.  If PREFIXED_NAME is non-NULL,
+   then if RESULT is looked up directly, *PREFIXED_NAME is set to NULL, and
+   if it is looked up using a prefix from PATH, *PREFIXED_NAME is set to
+   malloced storage containing the prefixed name.  */
+error_t hurd_file_name_path_lookup (error_t (*use_init_port)
+				    (int which,
+				     error_t (*operate) (mach_port_t)),
+				    file_t (*get_dtable_port) (int fd),
+				    error_t (*lookup)
+				      (file_t dir, char *name,
+				       int flags, mode_t mode,
+				       retry_type *do_retry,
+				       string_t retry_name,
+				       mach_port_t *result),
+				    const char *file_name, const char *path,
+				    int flags, mode_t mode,
+				    file_t *result, char **prefixed_name);
+
+#endif	/* hurd/lookup.h */
diff --git a/REORG.TODO/hurd/hurd/port.h b/REORG.TODO/hurd/hurd/port.h
new file mode 100644
index 0000000000..94874f8f25
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/port.h
@@ -0,0 +1,158 @@
+/* Lightweight user references for ports.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_PORT_H
+
+#define	_HURD_PORT_H	1
+#include <features.h>
+
+#include <mach.h>
+#include <hurd/userlink.h>
+#include <spin-lock.h>
+#include <hurd/signal.h>
+
+
+/* Structure describing a cell containing a port.  With the lock held, a
+   user extracts PORT, and attaches his own link (in local storage) to the
+   USERS chain.  PORT can then safely be used.  When PORT is no longer
+   needed, with the lock held, the user removes his link from the chain.
+   If his link is the last, and PORT has changed since he fetched it, the
+   user deallocates the port he used.  See <hurd/userlink.h>.  */
+
+struct hurd_port
+  {
+    spin_lock_t lock;		/* Locks rest.  */
+    struct hurd_userlink *users; /* Chain of users; see below.  */
+    mach_port_t port;		/* Port. */
+  };
+
+
+/* Evaluate EXPR with the variable `port' bound to the port in PORTCELL.  */
+
+#define	HURD_PORT_USE(portcell, expr)					      \
+  ({ struct hurd_port *const __p = (portcell);				      \
+     struct hurd_userlink __link;					      \
+     const mach_port_t port = _hurd_port_get (__p, &__link);		      \
+     __typeof(expr) __result = (expr);					      \
+     _hurd_port_free (__p, &__link, port);				      \
+     __result; })
+
+
+#ifndef _HURD_PORT_H_EXTERN_INLINE
+#define _HURD_PORT_H_EXTERN_INLINE __extern_inline
+#endif
+
+
+/* Initialize *PORT to INIT.  */
+
+_HURD_PORT_H_EXTERN_INLINE void
+_hurd_port_init (struct hurd_port *port, mach_port_t init)
+{
+  __spin_lock_init (&port->lock);
+  port->users = NULL;
+  port->port = init;
+}
+
+
+/* Cleanup function for non-local exits.  */
+extern void _hurd_port_cleanup (void *, jmp_buf, int);
+
+/* Get a reference to *PORT, which is locked.
+   Pass return value and LINK to _hurd_port_free when done.  */
+
+_HURD_PORT_H_EXTERN_INLINE mach_port_t
+_hurd_port_locked_get (struct hurd_port *port,
+		       struct hurd_userlink *link)
+{
+  mach_port_t result;
+  result = port->port;
+  if (result != MACH_PORT_NULL)
+    {
+      link->cleanup = &_hurd_port_cleanup;
+      link->cleanup_data = (void *) result;
+      _hurd_userlink_link (&port->users, link);
+    }
+  __spin_unlock (&port->lock);
+  return result;
+}
+
+/* Same, but locks PORT first.  */
+
+_HURD_PORT_H_EXTERN_INLINE mach_port_t
+_hurd_port_get (struct hurd_port *port,
+		struct hurd_userlink *link)
+{
+  mach_port_t result;
+  HURD_CRITICAL_BEGIN;
+  __spin_lock (&port->lock);
+  result = _hurd_port_locked_get (port, link);
+  HURD_CRITICAL_END;
+  return result;
+}
+
+
+/* Free a reference gotten with `USED_PORT = _hurd_port_get (PORT, LINK);' */
+
+_HURD_PORT_H_EXTERN_INLINE void
+_hurd_port_free (struct hurd_port *port,
+		 struct hurd_userlink *link,
+		 mach_port_t used_port)
+{
+  int dealloc;
+  if (used_port == MACH_PORT_NULL)
+    /* When we fetch an empty port cell with _hurd_port_get,
+       it does not link us on the users chain, since there is
+       no shared resource.  */
+    return;
+  HURD_CRITICAL_BEGIN;
+  __spin_lock (&port->lock);
+  dealloc = _hurd_userlink_unlink (link);
+  __spin_unlock (&port->lock);
+  HURD_CRITICAL_END;
+  if (dealloc)
+    __mach_port_deallocate (__mach_task_self (), used_port);
+}
+
+
+/* Set *PORT's port to NEWPORT.  NEWPORT's reference is consumed by PORT->port.
+   PORT->lock is locked.  */
+
+_HURD_PORT_H_EXTERN_INLINE void
+_hurd_port_locked_set (struct hurd_port *port, mach_port_t newport)
+{
+  mach_port_t old;
+  old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL;
+  port->port = newport;
+  __spin_unlock (&port->lock);
+  if (old != MACH_PORT_NULL)
+    __mach_port_deallocate (__mach_task_self (), old);
+}
+
+/* Same, but locks PORT first.  */
+
+_HURD_PORT_H_EXTERN_INLINE void
+_hurd_port_set (struct hurd_port *port, mach_port_t newport)
+{
+  HURD_CRITICAL_BEGIN;
+  __spin_lock (&port->lock);
+  _hurd_port_locked_set (port, newport);
+  HURD_CRITICAL_END;
+}
+
+
+#endif	/* hurd/port.h */
diff --git a/REORG.TODO/hurd/hurd/resource.h b/REORG.TODO/hurd/hurd/resource.h
new file mode 100644
index 0000000000..c550d04f07
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/resource.h
@@ -0,0 +1,51 @@
+/* Resource limits for the Hurd.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURD_RESOURCE_H
+#define _HURD_RESOURCE_H
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <hurd/process.h>
+
+/* This array contains the current resource limits for the process.  */
+extern struct rlimit _hurd_rlimits[RLIM_NLIMITS];
+extern struct mutex _hurd_rlimit_lock; /* Locks _hurd_rlimits.  */
+
+
+/* Helper function for getpriority and setpriority.  Maps FN over all the
+   processes specified by WHICH and WHO.  PI is non-null if a
+   proc_getprocinfo was already done; FN may use *PI arbitrarily, it is
+   reset on the next call; PI_FLAGS is passed to proc_getprocinfo.  Returns
+   FN's result the first time it returns nonzero.  If FN never returns
+   nonzero, this returns zero.  */
+extern error_t _hurd_priority_which_map (enum __priority_which which, int who,
+					 error_t (*fn) (pid_t pid,
+							struct procinfo *pi),
+					 int pi_flags);
+
+/* Convert between Mach priority values and the priority
+   values used by getpriority, setpriority, and nice.  */
+#define MACH_PRIORITY_TO_NICE(prio) ((prio) - 25)
+#define NICE_TO_MACH_PRIORITY(nice) ((nice) + 25)
+
+
+
+
+#endif
diff --git a/REORG.TODO/hurd/hurd/signal.h b/REORG.TODO/hurd/hurd/signal.h
new file mode 100644
index 0000000000..e03d53e6d7
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/signal.h
@@ -0,0 +1,364 @@
+/* Implementing POSIX.1 signals under the Hurd.
+   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_SIGNAL_H
+
+#define	_HURD_SIGNAL_H	1
+#include <features.h>
+/* Make sure <signal.h> is going to define NSIG.  */
+#ifndef __USE_GNU
+#error "Must have `_GNU_SOURCE' feature test macro to use this file"
+#endif
+
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+
+#include <mach/mach_types.h>
+#include <mach/port.h>
+#include <mach/message.h>
+#include <hurd/hurd_types.h>
+#include <signal.h>
+#include <errno.h>
+#include <hurd/msg.h>
+
+#include <cthreads.h>		/* For `struct mutex'.  */
+#include <setjmp.h>		/* For `jmp_buf'.  */
+#include <spin-lock.h>
+#include <hurd/threadvar.h>	/* We cache sigstate in a threadvar.  */
+struct hurd_signal_preemptor;	/* <hurd/sigpreempt.h> */
+
+
+/* Full details of a signal.  */
+struct hurd_signal_detail
+  {
+    /* Codes from origination Mach exception_raise message.  */
+    integer_t exc, exc_code, exc_subcode;
+    /* Sigcode as passed or computed from exception codes.  */
+    integer_t code;
+    /* Error code as passed or extracted from exception codes.  */
+    error_t error;
+  };
+
+
+/* Per-thread signal state.  */
+
+struct hurd_sigstate
+  {
+    spin_lock_t critical_section_lock; /* Held if in critical section.  */
+
+    spin_lock_t lock;		/* Locks most of the rest of the structure.  */
+
+    thread_t thread;
+    struct hurd_sigstate *next; /* Linked-list of thread sigstates.  */
+
+    sigset_t blocked;		/* What signals are blocked.  */
+    sigset_t pending;		/* Pending signals, possibly blocked.  */
+    struct sigaction actions[NSIG];
+    stack_t sigaltstack;
+
+    /* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>.
+       Each element of this chain is in local stack storage, and the chain
+       parallels the stack: the head of this chain is in the innermost
+       stack frame, and each next element in an outermore frame.  */
+    struct hurd_signal_preemptor *preemptors;
+
+    /* For each signal that may be pending, the details to deliver it with.  */
+    struct hurd_signal_detail pending_data[NSIG];
+
+    /* If `suspended' is set when this thread gets a signal,
+       the signal thread sends an empty message to it.  */
+    mach_port_t suspended;
+
+    /* The following members are not locked.  They are used only by this
+       thread, or by the signal thread with this thread suspended.  */
+
+    volatile mach_port_t intr_port; /* Port interruptible RPC was sent on.  */
+
+    /* If this is not null, the thread is in sigreturn awaiting delivery of
+       pending signals.  This context (the machine-dependent portions only)
+       will be passed to sigreturn after running the handler for a pending
+       signal, instead of examining the thread state.  */
+    struct sigcontext *context;
+
+    /* This is the head of the thread's list of active resources; see
+       <hurd/userlink.h> for details.  This member is only used by the
+       thread itself, and always inside a critical section.  */
+    struct hurd_userlink *active_resources;
+
+    /* These are locked normally.  */
+    int cancel;			/* Flag set by hurd_thread_cancel.  */
+    void (*cancel_hook) (void);	/* Called on cancellation.  */
+  };
+
+/* Linked list of states of all threads whose state has been asked for.  */
+
+extern struct hurd_sigstate *_hurd_sigstates;
+
+extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */
+
+/* Get the sigstate of a given thread, taking its lock.  */
+
+extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t);
+
+/* Get the sigstate of the current thread.
+   This uses a per-thread variable to optimize the lookup.  */
+
+extern struct hurd_sigstate *_hurd_self_sigstate (void)
+     /* This declaration tells the compiler that the value is constant.
+	We assume this won't be called twice from the same stack frame
+	by different threads.  */
+     __attribute__ ((__const__));
+
+#ifndef _HURD_SIGNAL_H_EXTERN_INLINE
+#define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline
+#endif
+
+_HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
+_hurd_self_sigstate (void)
+{
+  struct hurd_sigstate **location = (struct hurd_sigstate **)
+    (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
+  if (*location == NULL)
+    *location = _hurd_thread_sigstate (__mach_thread_self ());
+  return *location;
+}
+
+/* Thread listening on our message port; also called the "signal thread".  */
+
+extern thread_t _hurd_msgport_thread;
+
+/* Our message port.  We hold the receive right and _hurd_msgport_thread
+   listens for messages on it.  We also hold a send right, for convenience.  */
+
+extern mach_port_t _hurd_msgport;
+
+
+/* Thread to receive process-global signals.  */
+
+extern thread_t _hurd_sigthread;
+
+
+/* Resource limit on core file size.  Enforced by hurdsig.c.  */
+extern int _hurd_core_limit;
+
+/* Critical sections.
+
+   A critical section is a section of code which cannot safely be interrupted
+   to run a signal handler; for example, code that holds any lock cannot be
+   interrupted lest the signal handler try to take the same lock and
+   deadlock result.  */
+
+_HURD_SIGNAL_H_EXTERN_INLINE void *
+_hurd_critical_section_lock (void)
+{
+  struct hurd_sigstate **location = (struct hurd_sigstate **)
+    (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
+  struct hurd_sigstate *ss = *location;
+  if (ss == NULL)
+    {
+      /* The thread variable is unset; this must be the first time we've
+	 asked for it.  In this case, the critical section flag cannot
+	 possible already be set.  Look up our sigstate structure the slow
+	 way.  */
+      ss = *location = _hurd_thread_sigstate (__mach_thread_self ());
+    }
+
+  if (! __spin_try_lock (&ss->critical_section_lock))
+    /* We are already in a critical section, so do nothing.  */
+    return NULL;
+
+  /* With the critical section lock held no signal handler will run.
+     Return our sigstate pointer; this will be passed to
+     _hurd_critical_section_unlock to unlock it.  */
+  return ss;
+}
+
+_HURD_SIGNAL_H_EXTERN_INLINE void
+_hurd_critical_section_unlock (void *our_lock)
+{
+  if (our_lock == NULL)
+    /* The critical section lock was held when we began.  Do nothing.  */
+    return;
+  else
+    {
+      /* It was us who acquired the critical section lock.  Unlock it.  */
+      struct hurd_sigstate *ss = (struct hurd_sigstate *) our_lock;
+      sigset_t pending;
+      __spin_lock (&ss->lock);
+      __spin_unlock (&ss->critical_section_lock);
+      pending = ss->pending & ~ss->blocked;
+      __spin_unlock (&ss->lock);
+      if (! __sigisemptyset (&pending))
+	/* There are unblocked signals pending, which weren't
+	   delivered because we were in the critical section.
+	   Tell the signal thread to deliver them now.  */
+	__msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
+    }
+}
+
+/* Convenient macros for simple uses of critical sections.
+   These two must be used as a pair at the same C scoping level.  */
+
+#define HURD_CRITICAL_BEGIN \
+  { void *__hurd_critical__ = _hurd_critical_section_lock ()
+#define HURD_CRITICAL_END \
+      _hurd_critical_section_unlock (__hurd_critical__); } while (0)
+
+/* Initialize the signal code, and start the signal thread.
+   Arguments give the "init ints" from exec_startup.  */
+
+extern void _hurdsig_init (const int *intarray, size_t intarraysize);
+
+/* Initialize proc server-assisted fault recovery for the signal thread.  */
+
+extern void _hurdsig_fault_init (void);
+
+/* Raise a signal as described by SIGNO an DETAIL, on the thread whose
+   sigstate SS points to.  If SS is a null pointer, this instead affects
+   the calling thread.  */
+
+extern int _hurd_raise_signal (struct hurd_sigstate *ss, int signo,
+			       const struct hurd_signal_detail *detail);
+
+/* Translate a Mach exception into a signal (machine-dependent).  */
+
+extern void _hurd_exception2signal (struct hurd_signal_detail *detail,
+				    int *signo);
+
+
+/* Make the thread described by SS take the signal described by SIGNO and
+   DETAIL.  If the process is traced, this will in fact stop with a SIGNO
+   as the stop signal unless UNTRACED is nonzero.  When the signal can be
+   considered delivered, sends a sig_post reply message on REPLY_PORT
+   indicating success.  SS is not locked.  */
+
+extern void _hurd_internal_post_signal (struct hurd_sigstate *ss,
+					int signo,
+					struct hurd_signal_detail *detail,
+					mach_port_t reply_port,
+					mach_msg_type_name_t reply_port_type,
+					int untraced);
+
+/* Set up STATE and SS to handle signal SIGNO by running HANDLER.  If
+   RPC_WAIT is nonzero, the thread needs to wait for a pending RPC to
+   finish before running the signal handler.  The handler is passed SIGNO,
+   SIGCODE, and the returned `struct sigcontext' (which resides on the
+   stack the handler will use, and which describes the state of the thread
+   encoded in STATE before running the handler).  */
+
+struct machine_thread_all_state;
+extern struct sigcontext *
+_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+			int signo, struct hurd_signal_detail *detail,
+			int rpc_wait, struct machine_thread_all_state *state);
+
+/* Function run by the signal thread to receive from the signal port.  */
+
+extern void _hurd_msgport_receive (void);
+
+/* Set up STATE with a thread state that, when resumed, is
+   like `longjmp (_hurd_sigthread_fault_env, 1)'.  */
+
+extern void _hurd_initialize_fault_recovery_state (void *state);
+
+/* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'.  */
+
+extern void _hurd_longjmp_thread_state (void *state, jmp_buf env, int value);
+
+/* Function run for SIGINFO when its action is SIG_DFL and the current
+   process is the session leader.  */
+
+extern void _hurd_siginfo_handler (int);
+
+/* Replacement for mach_msg used in RPCs to provide Hurd interruption
+   semantics.  Args are all the same as for mach_msg.  intr-rpc.h arranges
+   for this version to be used automatically by the RPC stubs the library
+   builds in place of the normal mach_msg. */
+error_t _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
+				 mach_msg_option_t option,
+				 mach_msg_size_t send_size,
+				 mach_msg_size_t rcv_size,
+				 mach_port_t rcv_name,
+				 mach_msg_timeout_t timeout,
+				 mach_port_t notify);
+
+
+/* Milliseconds to wait for an interruptible RPC to return after
+   `interrupt_operation'.  */
+
+extern mach_msg_timeout_t _hurd_interrupted_rpc_timeout;
+
+
+/* Mask of signals that cannot be caught, blocked, or ignored.  */
+#define	_SIG_CANT_MASK	(__sigmask (SIGSTOP) | __sigmask (SIGKILL))
+
+/* Do an RPC to a process's message port.
+
+   Each argument is an expression which returns an error code; each
+   expression may be evaluated several times.  FETCH_MSGPORT_EXPR should
+   fetch the appropriate message port and store it in the local variable
+   `msgport'; it will be deallocated after use.  FETCH_REFPORT_EXPR should
+   fetch the appropriate message port and store it in the local variable
+   `refport' (if no reference port is needed in the call, then
+   FETCH_REFPORT_EXPR should be simply KERN_SUCCESS or 0); if
+   DEALLOC_REFPORT evaluates to nonzero it will be deallocated after use,
+   otherwise the FETCH_REFPORT_EXPR must take care of user references to
+   `refport'.  RPC_EXPR should perform the desired RPC operation using
+   `msgport' and `refport'.
+
+   The reason for the complexity is that a process's message port and
+   reference port may change between fetching those ports and completing an
+   RPC using them (usually they change only when a process execs).  The RPC
+   will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can
+   send the RPC request; or with MIG_SERVER_DIED if the msgport was
+   destroyed after we sent the RPC request but before it was serviced.  In
+   either of these cases, we retry the entire operation, discarding the old
+   message and reference ports and fetch them anew.  */
+
+#define HURD_MSGPORT_RPC(fetch_msgport_expr,				      \
+			 fetch_refport_expr, dealloc_refport,		      \
+			 rpc_expr) 					      \
+({									      \
+    error_t __err;							      \
+    mach_port_t msgport, refport = MACH_PORT_NULL;			      \
+    do									      \
+      {									      \
+	/* Get the message port.  */					      \
+	__err = (error_t) (fetch_msgport_expr);				      \
+	if (__err)							      \
+	  break;							      \
+	/* Get the reference port.  */					      \
+	__err = (error_t) (fetch_refport_expr);				      \
+	if (__err)							      \
+	  {								      \
+	    /* Couldn't get it; deallocate MSGPORT and fail.  */	      \
+	    __mach_port_deallocate (__mach_task_self (), msgport);	      \
+	    break;							      \
+	  }								      \
+	__err = (error_t) (rpc_expr);					      \
+	__mach_port_deallocate (__mach_task_self (), msgport);		      \
+	if ((dealloc_refport) && refport != MACH_PORT_NULL)		      \
+	  __mach_port_deallocate (__mach_task_self (), refport);    	      \
+      } while (__err == MACH_SEND_INVALID_DEST ||			      \
+	       __err == MIG_SERVER_DIED);				      \
+    __err;								      \
+})
+
+
+#endif	/* hurd/signal.h */
diff --git a/REORG.TODO/hurd/hurd/sigpreempt.h b/REORG.TODO/hurd/hurd/sigpreempt.h
new file mode 100644
index 0000000000..406f0f58fa
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/sigpreempt.h
@@ -0,0 +1,102 @@
+/* Preemption of Hurd signals before POSIX.1 semantics take over.
+   Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_SIGPREEMPT_H
+
+#define	_HURD_SIGPREEMPT_H	1
+#include <errno.h>
+#include <signal.h>		/* For sigset_t, sighandler_t, SIG_ERR.  */
+struct hurd_sigstate;		/* <hurd/signal.h> */
+struct hurd_signal_detail;	/* <hurd/signal.h> */
+
+struct hurd_signal_preemptor
+  {
+    /* These members select which signals this structure will apply to.
+       The rest of the structure is only consulted if these match.  */
+    sigset_t signals;		/* Signals preempted.  */
+    unsigned long int first, last; /* Range of sigcode values preempted.  */
+
+    /* This function will be called (with SS->lock held) to decide what to
+       do with the signal described.  It may modify the codes of the signal
+       passed.  If the return value is SIG_ERR, the next matching preemptor
+       is tried, or the normal handling is done for the signal (which may
+       have been changed by the preemptor function).  Otherwise, the signal
+       is processed as if the return value were its handler setting.  */
+    sighandler_t (*preemptor) (struct hurd_signal_preemptor *preemptor,
+			       struct hurd_sigstate *ss,
+			       int *signo, struct hurd_signal_detail *detail);
+    /* If PREEMPTOR is null, act as if it returned HANDLER.  */
+    sighandler_t handler;
+
+    struct hurd_signal_preemptor *next;	/* List structure.  */
+  };
+
+#define HURD_PREEMPT_SIGNAL_P(preemptor, signo, sigcode) \
+  (((preemptor)->signals & sigmask (signo)) && \
+   (sigcode) >= (preemptor)->first && (sigcode) <= (preemptor)->last)
+
+
+/* Signal preemptors applying to all threads; locked by _hurd_siglock.  */
+extern struct hurd_signal_preemptor *_hurdsig_preemptors;
+extern sigset_t _hurdsig_preempted_set;
+
+
+/* The caller must initialize all members of *PREEMPTOR except `next'.
+   The preemptor is registered on the global list.  */
+void hurd_preempt_signals (struct hurd_signal_preemptor *preemptor);
+
+/* Remove a preemptor registered with hurd_preempt_signals.  */
+void hurd_unpreempt_signals (struct hurd_signal_preemptor *preemptor);
+
+
+/* Call *OPERATE and return its value.  If a signal in SIGSET with a sigcode
+   in the range [FIRST,LAST] arrives during the call, catch it.  If HANDLER
+   is a function, it handles the signal in the normal way (i.e. it should
+   longjmp unless it can restart the insn on return).  If it is SIG_ERR,
+   hurd_catch_signal returns the sc_error value from the signal (or
+   EGRATUITOUS if that is zero).
+
+   The preemptor structure is passed to *OPERATE, which may modify its
+   sigcode range or functions at any time during which it is guaranteed no
+   signal in SIGSET will arrive.  */
+
+error_t hurd_catch_signal (sigset_t sigset,
+			   unsigned long int first, unsigned long int last,
+			   error_t (*operate) (struct hurd_signal_preemptor *),
+			   sighandler_t handler);
+
+
+/* Convenience functions using `hurd_catch_signal'.  */
+
+
+/* Like `memset', but catch faults in DEST.  */
+error_t hurd_safe_memset (void *dest, int byte, size_t nbytes);
+
+/* Like `memcpy', but catch faults in SRC.  */
+error_t hurd_safe_copyin (void *dest, const void *src, size_t nbytes);
+
+/* Like `memcpy', but catch faults in DEST.  */
+error_t hurd_safe_copyout (void *dest, const void *src, size_t nbytes);
+
+/* Like `memmove', but catch faults in SRC or DEST.
+   If only one region is expected to fault, it is more efficient
+   to use `hurd_safe_copyin' or `hurd_safe_copyout' as appropriate.  */
+error_t hurd_safe_memmove (void *dest, const void *src, size_t nbytes);
+
+
+#endif	/* hurd/sigpreempt.h */
diff --git a/REORG.TODO/hurd/hurd/threadvar.h b/REORG.TODO/hurd/hurd/threadvar.h
new file mode 100644
index 0000000000..72982e1744
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/threadvar.h
@@ -0,0 +1,116 @@
+/* Internal per-thread variables for the Hurd.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURD_THREADVAR_H
+#define	_HURD_THREADVAR_H
+
+#include <features.h>
+
+/* The per-thread variables are found by ANDing this mask
+   with the value of the stack pointer and then adding this offset.
+
+   In the multi-threaded case, cthreads initialization sets
+   __hurd_threadvar_stack_mask to ~(cthread_stack_size - 1), a mask which
+   finds the base of the fixed-size cthreads stack; and
+   __hurd_threadvar_stack_offset to a small offset that skips the data
+   cthreads itself maintains at the base of each thread's stack.
+
+   In the single-threaded case, __hurd_threadvar_stack_mask is zero, so the
+   stack pointer is ignored; and __hurd_threadvar_stack_offset gives the
+   address of a small allocated region which contains the variables for the
+   single thread.  */
+
+extern unsigned long int __hurd_threadvar_stack_mask;
+extern unsigned long int __hurd_threadvar_stack_offset;
+
+/* A special case must always be made for the signal thread.  Even when there
+   is only one user thread and an allocated region can be used for the user
+   thread's variables, the signal thread needs to have its own location for
+   per-thread variables.  The variables __hurd_sigthread_stack_base and
+   __hurd_sigthread_stack_end define the bounds of the stack used by the
+   signal thread, so that thread can always be specifically identified.  */
+
+extern unsigned long int __hurd_sigthread_stack_base;
+extern unsigned long int __hurd_sigthread_stack_end;
+extern unsigned long int *__hurd_sigthread_variables;
+
+
+/* At the location described by the two variables above,
+   there are __hurd_threadvar_max `unsigned long int's of per-thread data.  */
+extern unsigned int __hurd_threadvar_max;
+
+/* These values are the indices for the standard per-thread variables.  */
+enum __hurd_threadvar_index
+  {
+    _HURD_THREADVAR_MIG_REPLY,	/* Reply port for MiG user stub functions.  */
+    _HURD_THREADVAR_ERRNO,	/* `errno' value for this thread.  */
+    _HURD_THREADVAR_SIGSTATE,	/* This thread's `struct hurd_sigstate'.  */
+    _HURD_THREADVAR_DYNAMIC_USER, /* Dynamically-assigned user variables.  */
+    _HURD_THREADVAR_MALLOC,	/* For use of malloc.  */
+    _HURD_THREADVAR_DL_ERROR,	/* For use of -ldl and dynamic linker.  */
+    _HURD_THREADVAR_RPC_VARS,	/* For state of RPC functions.  */
+    _HURD_THREADVAR_LOCALE,	/* For thread-local locale setting.  */
+    _HURD_THREADVAR_CTYPE_B,	/* Cache of thread-local locale data.  */
+    _HURD_THREADVAR_CTYPE_TOLOWER, /* Cache of thread-local locale data.  */
+    _HURD_THREADVAR_CTYPE_TOUPPER, /* Cache of thread-local locale data.  */
+    _HURD_THREADVAR_MAX		/* Default value for __hurd_threadvar_max.  */
+  };
+
+
+#ifndef _HURD_THREADVAR_H_EXTERN_INLINE
+#define _HURD_THREADVAR_H_EXTERN_INLINE __extern_inline
+#endif
+
+/* Return the location of the value for the per-thread variable with index
+   INDEX used by the thread whose stack pointer is SP.  */
+
+extern unsigned long int *__hurd_threadvar_location_from_sp
+  (enum __hurd_threadvar_index __index, void *__sp);
+_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
+__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index,
+				   void *__sp)
+{
+  unsigned long int __stack = (unsigned long int) __sp;
+  return &((__stack >= __hurd_sigthread_stack_base &&
+	    __stack < __hurd_sigthread_stack_end)
+	   ? __hurd_sigthread_variables
+	   : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) +
+				    __hurd_threadvar_stack_offset))[__index];
+}
+
+#include <machine-sp.h>		/* Define __thread_stack_pointer.  */
+
+/* Return the location of the current thread's value for the
+   per-thread variable with index INDEX.  */
+
+extern unsigned long int *
+__hurd_threadvar_location (enum __hurd_threadvar_index __index) __THROW
+     /* This declaration tells the compiler that the value is constant
+	given the same argument.  We assume this won't be called twice from
+	the same stack frame by different threads.  */
+     __attribute__ ((__const__));
+
+_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
+__hurd_threadvar_location (enum __hurd_threadvar_index __index)
+{
+  return __hurd_threadvar_location_from_sp (__index,
+					    __thread_stack_pointer ());
+}
+
+
+#endif	/* hurd/threadvar.h */
diff --git a/REORG.TODO/hurd/hurd/userlink.h b/REORG.TODO/hurd/hurd/userlink.h
new file mode 100644
index 0000000000..4946402df5
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/userlink.h
@@ -0,0 +1,147 @@
+/* Support for chains recording users of a resource; `struct hurd_userlink'.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_USERLINK_H
+
+#define	_HURD_USERLINK_H	1
+#include <features.h>
+
+#define __need_NULL
+#include <stddef.h>
+
+#include <hurd/signal.h>
+#include <setjmp.h>
+
+
+/* This structure records a link in two doubly-linked lists.
+   We call these the per-resource user list and the per-thread
+   active-resource list.
+
+   Users of a given resource are recorded by their presence in a list
+   associated with that resource.  A user attaches his own link (in local
+   storage on his stack) to a shared chain at the time he begins using some
+   resource.  When finished with that resource, the user removes his link
+   from the chain.  If his link is the last (there are no other users of
+   the resource), and his chain has been detached from the shared cell (the
+   resource in the cell has been replaced), then the user deallocates the
+   resource that he used.
+
+   All uses of shared resources by a single thread are linked together by
+   its `active-resource' list; the head of this list is stored in the
+   per-thread sigstate structure.  When the thread makes a non-local exit
+   (i.e. longjmp), it will examine its active-resource list, and each link
+   residing in a stack frame being jumped out of will be unlinked from both
+   the resource's user list and the thread's active-resource list, and
+   deallocate the resource if that was the last user link for that resource.
+
+   NOTE: Access to a thread's active-resource list must always be done
+   inside a signal-proof critical section; the functions in this file
+   assume they are called inside a critical section, and do no locking of
+   their own.  Also important: the longjmp cleanup relies on all userlink
+   structures residing on the stack of the using thread.  */
+
+struct hurd_userlink
+  {
+    struct
+      {
+	struct hurd_userlink *next, **prevp;
+      } resource, thread;
+
+    /* This function is called when a non-local exit
+       unwinds the frame containing this link.  */
+    void (*cleanup) (void *cleanup_data, jmp_buf env, int val);
+    void *cleanup_data;
+  };
+
+
+#ifndef _HURD_USERLINK_H_EXTERN_INLINE
+#define _HURD_USERLINK_H_EXTERN_INLINE __extern_inline
+#endif
+
+
+/* Attach LINK to the chain of users at *CHAINP.  */
+
+_HURD_USERLINK_H_EXTERN_INLINE void
+_hurd_userlink_link (struct hurd_userlink **chainp,
+		     struct hurd_userlink *link)
+{
+  struct hurd_userlink **thread_chainp;
+
+  link->resource.next = *chainp;
+  if (link->resource.next)
+    link->resource.next->resource.prevp = &link->resource.next;
+  link->resource.prevp = chainp;
+  *chainp = link;
+
+  /* Also chain it on the current thread's list of active resources.  */
+  thread_chainp = &_hurd_self_sigstate ()->active_resources;
+  link->thread.next = *thread_chainp;
+  if (link->thread.next)
+    link->thread.next->thread.prevp = &link->thread.next;
+  link->thread.prevp = thread_chainp;
+  *thread_chainp = link;
+}
+
+
+/* Detach LINK from its chain.  Returns nonzero iff this was the
+   last user of the resource and it should be deallocated.  */
+
+_HURD_USERLINK_H_EXTERN_INLINE int
+_hurd_userlink_unlink (struct hurd_userlink *link)
+{
+  /* We should deallocate the resource used if this chain has been detached
+     from the cell (and thus has a nil `prevp'), and there is no next link
+     representing another user reference to the same resource. */
+  int dealloc = ! link->resource.next && ! link->resource.prevp;
+
+  /* Remove our link from the chain of current users.  */
+  if (link->resource.prevp)
+    *link->resource.prevp = link->resource.next;
+  if (link->resource.next)
+    link->resource.next->resource.prevp = link->resource.prevp;
+
+  /* Remove our link from the chain of currently active resources
+     for this thread.  */
+  *link->thread.prevp = link->thread.next;
+  if (link->thread.next)
+    link->thread.next->thread.prevp = link->thread.prevp;
+
+  return dealloc;
+}
+
+
+/* Clear all users from *CHAINP.  Call this when the resource *CHAINP
+   protects is changing.  If the return value is nonzero, no users are on
+   the chain and the caller should deallocate the resource.  If the return
+   value is zero, someone is still using the resource and they will
+   deallocate it when they are finished.  */
+
+_HURD_USERLINK_H_EXTERN_INLINE int
+_hurd_userlink_clear (struct hurd_userlink **chainp)
+{
+  if (*chainp == NULL)
+    return 1;
+
+  /* Detach the chain of current users from the cell.  The last user to
+     remove his link from that chain will deallocate the old resource.  */
+  (*chainp)->resource.prevp = NULL;
+  *chainp = NULL;
+  return 0;
+}
+
+#endif	/* hurd/userlink.h */
diff --git a/REORG.TODO/hurd/hurd/xattr.h b/REORG.TODO/hurd/hurd/xattr.h
new file mode 100644
index 0000000000..bc4c2ce451
--- /dev/null
+++ b/REORG.TODO/hurd/hurd/xattr.h
@@ -0,0 +1,34 @@
+/* Access to extended attributes on files for GNU/Hurd.
+   Copyright (C) 2005-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_HURD_XATTR_H
+#define	_HURD_XATTR_H	1
+
+#include <sys/xattr.h>		/* This defines the XATTR_* flags.  */
+
+/* These are the internal versions of getxattr/setxattr/listxattr.  */
+extern error_t _hurd_xattr_get (io_t port, const char *name,
+				void *value, size_t *size);
+extern error_t _hurd_xattr_set (io_t port, const char *name,
+				const void *value, size_t size, int flags);
+extern error_t _hurd_xattr_remove (io_t port, const char *name);
+extern error_t _hurd_xattr_list (io_t port, void *buffer, size_t *size);
+
+
+
+#endif	/* hurd/xattr.h */
diff --git a/REORG.TODO/hurd/hurdauth.c b/REORG.TODO/hurd/hurdauth.c
new file mode 100644
index 0000000000..6a7d69d027
--- /dev/null
+++ b/REORG.TODO/hurd/hurdauth.c
@@ -0,0 +1,236 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/msg_server.h>
+#include <hurd/id.h>
+#include <string.h>
+
+int
+_hurd_refport_secure_p (mach_port_t ref)
+{
+  if (ref == __mach_task_self ())
+    return 1;
+  if (__USEPORT (AUTH, ref == port))
+    return 1;
+  return 0;
+}
+
+kern_return_t
+_S_msg_add_auth (mach_port_t me,
+		 auth_t addauth)
+{
+  error_t err;
+  auth_t newauth;
+  uid_t *genuids, *gengids, *auxuids, *auxgids;
+  mach_msg_type_number_t ngenuids, ngengids, nauxuids, nauxgids;
+  uid_t *newgenuids, *newgengids, *newauxuids, *newauxgids;
+  mach_msg_type_number_t nnewgenuids, nnewgengids, nnewauxuids, nnewauxgids;
+
+  /* Create a list of ids and store it in NEWLISTP, length NEWLISTLEN.
+     Keep all the ids in EXIST (len NEXIST), adding in those from NEW
+     (len NNEW) which are not already there.  */
+  error_t make_list (uid_t **newlistp, mach_msg_type_number_t *newlistlen,
+		     uid_t *exist, mach_msg_type_number_t nexist,
+		     uid_t *new, mach_msg_type_number_t nnew)
+    {
+      error_t urp;
+      int i, j, k;
+      vm_size_t offset;
+
+      urp = vm_allocate (mach_task_self (), (vm_address_t *) newlistp,
+			 nexist + nnew * sizeof (uid_t), 1);
+      if (urp)
+	return urp;
+
+      j = 0;
+      for (i = 0; i < nexist; i++)
+	(*newlistp)[j++] = exist[i];
+
+      for (i = 0; i < nnew; i++)
+	{
+	  for (k = 0; k < nexist; k++)
+	    if (exist[k] == new[i])
+	      break;
+	  if (k < nexist)
+	    continue;
+
+	  (*newlistp)[j++] = new[i];
+	}
+
+      offset = (round_page (nexist + nnew * sizeof (uid_t))
+		- round_page (j * sizeof (uid_t)));
+      if (offset)
+	vm_deallocate (mach_task_self (),
+		       (vm_address_t) (*newlistp
+				       + (nexist + nnew * sizeof (uid_t))),
+		       offset);
+      *newlistlen = j;
+      return 0;
+    }
+
+  /* Find out what ids ADDAUTH refers to */
+
+  genuids = gengids = auxuids = auxgids = 0;
+  ngenuids = ngengids = nauxuids = nauxgids = 0;
+  err = __auth_getids (addauth,
+		       &genuids, &ngenuids,
+		       &auxuids, &nauxuids,
+		       &gengids, &ngengids,
+		       &auxgids, &nauxgids);
+  if (err)
+    return err;
+
+  /* OR in these ids to what we already have, creating a new list. */
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_id.lock);
+  _hurd_check_ids ();
+
+#define MAKE(genaux,uidgid) 						    \
+  make_list (&new ## genaux ## uidgid ## s, 				    \
+	     &nnew ## genaux ## uidgid ## s,				    \
+	     _hurd_id.genaux.uidgid ## s,				    \
+	     _hurd_id.genaux.n ## uidgid ## s,				    \
+	     genaux ## uidgid ## s,					    \
+	     n ## genaux ## uidgid ## s)
+
+  err = MAKE (gen, uid);
+  if (!err)
+    MAKE (aux, uid);
+  if (!err)
+    MAKE (gen, gid);
+  if (!err)
+    MAKE (aux, gid);
+#undef MAKE
+
+  __mutex_unlock (&_hurd_id.lock);
+  HURD_CRITICAL_END;
+
+
+  /* Create the new auth port */
+
+  if (!err)
+    err = __USEPORT (AUTH,
+		     __auth_makeauth (port,
+				      &addauth, MACH_MSG_TYPE_MOVE_SEND, 1,
+				      newgenuids, nnewgenuids,
+				      newauxuids, nnewauxuids,
+				      newgengids, nnewgengids,
+				      newauxgids, nnewauxgids,
+				      &newauth));
+
+#define freeup(array, len) \
+  if (array) \
+    vm_deallocate (mach_task_self (), (vm_address_t) array, \
+		   len * sizeof (uid_t));
+
+  freeup (genuids, ngenuids);
+  freeup (auxuids, nauxuids);
+  freeup (gengids, ngengids);
+  freeup (auxgids, nauxgids);
+  freeup (newgenuids, nnewgenuids);
+  freeup (newauxuids, nnewauxuids);
+  freeup (newgengids, nnewgengids);
+  freeup (newauxgids, nnewauxgids);
+#undef freeup
+
+  if (err)
+    return err;
+
+  /* And install it. */
+
+  err = __setauth (newauth);
+  __mach_port_deallocate (__mach_task_self (), newauth);
+  if (err)
+    return errno;
+
+  return 0;
+}
+
+kern_return_t
+_S_msg_del_auth (mach_port_t me,
+		 task_t task,
+		 intarray_t uids, mach_msg_type_number_t nuids,
+		 intarray_t gids, mach_msg_type_number_t ngids)
+{
+  error_t err;
+  auth_t newauth;
+
+  if (!_hurd_refport_secure_p (task))
+    return EPERM;
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_id.lock);
+  err = _hurd_check_ids ();
+
+  if (!err)
+    {
+      size_t i, j;
+      size_t nu = _hurd_id.gen.nuids, ng = _hurd_id.gen.ngids;
+      uid_t newu[nu];
+      gid_t newg[ng];
+
+      memcpy (newu, _hurd_id.gen.uids, nu * sizeof (uid_t));
+      memcpy (newg, _hurd_id.gen.gids, ng * sizeof (gid_t));
+
+      for (j = 0; j < nuids; ++j)
+	{
+	  const uid_t uid = uids[j];
+	  for (i = 0; i < nu; ++i)
+	    if (newu[i] == uid)
+	      /* Move the last uid into this slot, and decrease the
+		 number of uids so the last slot is no longer used.  */
+	      newu[i] = newu[--nu];
+	}
+      __vm_deallocate (__mach_task_self (),
+		       (vm_address_t) uids, nuids * sizeof (uid_t));
+
+      for (j = 0; j < ngids; ++j)
+	{
+	  const gid_t gid = gids[j];
+	  for (i = 0; i < nu; ++i)
+	    if (newu[i] == gid)
+	      /* Move the last gid into this slot, and decrease the
+		 number of gids so the last slot is no longer used.  */
+	      newu[i] = newu[--nu];
+	}
+      __vm_deallocate (__mach_task_self (),
+		       (vm_address_t) gids, ngids * sizeof (gid_t));
+
+      err = __USEPORT (AUTH, __auth_makeauth
+		       (port,
+			NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+			newu, nu,
+			_hurd_id.aux.uids, _hurd_id.aux.nuids,
+			newg, ng,
+			_hurd_id.aux.uids, _hurd_id.aux.ngids,
+			&newauth));
+    }
+  __mutex_unlock (&_hurd_id.lock);
+  HURD_CRITICAL_END;
+
+  if (err)
+    return err;
+
+  err = __setauth (newauth);
+  __mach_port_deallocate (__mach_task_self (), newauth);
+  if (err)
+    return errno;
+
+  return 0;
+}
diff --git a/REORG.TODO/hurd/hurdchdir.c b/REORG.TODO/hurd/hurdchdir.c
new file mode 100644
index 0000000000..b38734d8f6
--- /dev/null
+++ b/REORG.TODO/hurd/hurdchdir.c
@@ -0,0 +1,59 @@
+/* Change a port cell to a directory by looking up a name.
+   Copyright (C) 1999-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/port.h>
+#include <hurd/fd.h>
+#include <fcntl.h>
+#include <string.h>
+
+int
+_hurd_change_directory_port_from_name (struct hurd_port *portcell,
+				       const char *name)
+{
+  size_t len;
+  const char *lookup;
+  file_t dir;
+
+  /* Append trailing "/." to directory name to force ENOTDIR if it's not a
+     directory and EACCES if we don't have search permission.  */
+  len = strlen (name);
+  if (len >= 2 && name[len - 2] == '/' && name[len - 1] == '.')
+    lookup = name;
+  else if (len == 0)
+    /* Special-case empty file name according to POSIX.  */
+    return __hurd_fail (ENOENT);
+  else
+    {
+      char *n = alloca (len + 3);
+      memcpy (n, name, len);
+      n[len] = '/';
+      n[len + 1] = '.';
+      n[len + 2] = '\0';
+      lookup = n;
+    }
+
+  dir = __file_name_lookup (lookup, 0, 0);
+  if (dir == MACH_PORT_NULL)
+    return -1;
+
+  _hurd_port_set (portcell, dir);
+  return 0;
+}
diff --git a/REORG.TODO/hurd/hurdexec.c b/REORG.TODO/hurd/hurdexec.c
new file mode 100644
index 0000000000..98b8dca674
--- /dev/null
+++ b/REORG.TODO/hurd/hurdexec.c
@@ -0,0 +1,403 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <hurd/signal.h>
+#include <hurd/id.h>
+#include <assert.h>
+#include <argz.h>
+
+/* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
+   If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
+   ARGV and ENVP are terminated by NULL pointers.  */
+error_t
+_hurd_exec (task_t task, file_t file,
+	    char *const argv[], char *const envp[])
+{
+  error_t err;
+  char *args, *env;
+  size_t argslen, envlen;
+  int ints[INIT_INT_MAX];
+  mach_port_t ports[_hurd_nports];
+  struct hurd_userlink ulink_ports[_hurd_nports];
+  inline void free_port (unsigned int i)
+    {
+      _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
+    }
+  file_t *dtable;
+  unsigned int dtablesize, i;
+  struct hurd_port **dtable_cells;
+  struct hurd_userlink *ulink_dtable;
+  struct hurd_sigstate *ss;
+  mach_port_t *please_dealloc, *pdp;
+  int reauth = 0;
+
+  /* XXX needs to be hurdmalloc XXX */
+  if (argv == NULL)
+    args = NULL, argslen = 0;
+  else if (err = __argz_create (argv, &args, &argslen))
+    return err;
+  if (envp == NULL)
+    env = NULL, envlen = 0;
+  else if (err = __argz_create (envp, &env, &envlen))
+    goto outargs;
+
+  /* Load up the ports to give to the new program.  */
+  for (i = 0; i < _hurd_nports; ++i)
+    if (i == INIT_PORT_PROC && task != __mach_task_self ())
+      {
+	/* This is another task, so we need to ask the proc server
+	   for the right proc server port for it.  */
+	if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
+	  {
+	    while (--i > 0)
+	      free_port (i);
+	    goto outenv;
+	  }
+      }
+    else
+      ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
+
+
+  /* Load up the ints to give the new program.  */
+  for (i = 0; i < INIT_INT_MAX; ++i)
+    switch (i)
+      {
+      case INIT_UMASK:
+	ints[i] = _hurd_umask;
+	break;
+
+      case INIT_SIGMASK:
+      case INIT_SIGIGN:
+      case INIT_SIGPENDING:
+	/* We will set these all below.  */
+	break;
+
+      case INIT_TRACEMASK:
+	ints[i] = _hurdsig_traced;
+	break;
+
+      default:
+	ints[i] = 0;
+      }
+
+  ss = _hurd_self_sigstate ();
+
+  assert (! __spin_lock_locked (&ss->critical_section_lock));
+  __spin_lock (&ss->critical_section_lock);
+
+  __spin_lock (&ss->lock);
+  ints[INIT_SIGMASK] = ss->blocked;
+  ints[INIT_SIGPENDING] = ss->pending;
+  ints[INIT_SIGIGN] = 0;
+  for (i = 1; i < NSIG; ++i)
+    if (ss->actions[i].sa_handler == SIG_IGN)
+      ints[INIT_SIGIGN] |= __sigmask (i);
+
+  /* We hold the sigstate lock until the exec has failed so that no signal
+     can arrive between when we pack the blocked and ignored signals, and
+     when the exec actually happens.  A signal handler could change what
+     signals are blocked and ignored.  Either the change will be reflected
+     in the exec, or the signal will never be delivered.  Setting the
+     critical section flag avoids anything we call trying to acquire the
+     sigstate lock.  */
+
+  __spin_unlock (&ss->lock);
+
+  /* Pack up the descriptor table to give the new program.  */
+  __mutex_lock (&_hurd_dtable_lock);
+
+  dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
+
+  if (task == __mach_task_self ())
+    /* Request the exec server to deallocate some ports from us if the exec
+       succeeds.  The init ports and descriptor ports will arrive in the
+       new program's exec_startup message.  If we failed to deallocate
+       them, the new program would have duplicate user references for them.
+       But we cannot deallocate them ourselves, because we must still have
+       them after a failed exec call.  */
+    please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
+				* sizeof (mach_port_t));
+  else
+    please_dealloc = NULL;
+  pdp = please_dealloc;
+
+  if (_hurd_dtable != NULL)
+    {
+      dtable = __alloca (dtablesize * sizeof (dtable[0]));
+      ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
+      dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
+      for (i = 0; i < dtablesize; ++i)
+	{
+	  struct hurd_fd *const d = _hurd_dtable[i];
+	  if (d == NULL)
+	    {
+	      dtable[i] = MACH_PORT_NULL;
+	      continue;
+	    }
+	  __spin_lock (&d->port.lock);
+	  if (d->flags & FD_CLOEXEC)
+	    {
+	      /* This descriptor is marked to be closed on exec.
+		 So don't pass it to the new program.  */
+	      dtable[i] = MACH_PORT_NULL;
+	      if (pdp && d->port.port != MACH_PORT_NULL)
+		{
+		  /* We still need to deallocate the ports.  */
+		  *pdp++ = d->port.port;
+		  if (d->ctty.port != MACH_PORT_NULL)
+		    *pdp++ = d->ctty.port;
+		}
+	      __spin_unlock (&d->port.lock);
+	    }
+	  else
+	    {
+	      if (pdp && d->ctty.port != MACH_PORT_NULL)
+		/* All the elements of DTABLE are added to PLEASE_DEALLOC
+		   below, so we needn't add the port itself.
+		   But we must deallocate the ctty port as well as
+		   the normal port that got installed in DTABLE[I].  */
+		*pdp++ = d->ctty.port;
+	      dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
+	      dtable_cells[i] = &d->port;
+	    }
+	}
+    }
+  else
+    {
+      dtable = _hurd_init_dtable;
+      ulink_dtable = NULL;
+      dtable_cells = NULL;
+    }
+
+  /* Prune trailing null ports from the descriptor table.  */
+  while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
+    --dtablesize;
+
+  /* See if we need to diddle the auth port of the new program.
+     The purpose of this is to get the effect setting the saved-set UID and
+     GID to the respective effective IDs after the exec, as POSIX.1 requires.
+     Note that we don't reauthenticate with the proc server; that would be a
+     no-op since it only keeps track of the effective UIDs, and if it did
+     keep track of the available IDs we would have the problem that we'd be
+     changing the IDs before the exec and have to change them back after a
+     failure.  Arguably we could skip all the reauthentications because the
+     available IDs have no bearing on any filesystem.  But the conservative
+     approach is to reauthenticate all the io ports so that no state anywhere
+     reflects that our whole ID set differs from what we've set it to.  */
+  __mutex_lock (&_hurd_id.lock);
+  err = _hurd_check_ids ();
+  if (err == 0 && ((_hurd_id.aux.nuids >= 2 && _hurd_id.gen.nuids >= 1
+		    && _hurd_id.aux.uids[1] != _hurd_id.gen.uids[0])
+		   || (_hurd_id.aux.ngids >= 2 && _hurd_id.gen.ngids >= 1
+		       && _hurd_id.aux.gids[1] != _hurd_id.gen.gids[0])))
+    {
+      /* We have euid != svuid or egid != svgid.  POSIX.1 says that exec
+	 sets svuid = euid and svgid = egid.  So we must get a new auth
+	 port and reauthenticate everything with it.  We'll pass the new
+	 ports in file_exec instead of our own ports.  */
+
+      auth_t newauth;
+
+      _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
+      _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
+      _hurd_id.valid = 0;
+      if (_hurd_id.rid_auth != MACH_PORT_NULL)
+	{
+	  __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
+	  _hurd_id.rid_auth = MACH_PORT_NULL;
+	}
+
+      err = __auth_makeauth (ports[INIT_PORT_AUTH],
+			     NULL, MACH_MSG_TYPE_COPY_SEND, 0,
+			     _hurd_id.gen.uids, _hurd_id.gen.nuids,
+			     _hurd_id.aux.uids, _hurd_id.aux.nuids,
+			     _hurd_id.gen.gids, _hurd_id.gen.ngids,
+			     _hurd_id.aux.gids, _hurd_id.aux.ngids,
+			     &newauth);
+      if (err == 0)
+	{
+	  /* Now we have to reauthenticate the ports with this new ID.
+	   */
+
+	  inline error_t reauth_io (io_t port, io_t *newport)
+	    {
+	      mach_port_t ref = __mach_reply_port ();
+	      *newport = MACH_PORT_NULL;
+	      error_t err = __io_reauthenticate (port,
+						 ref, MACH_MSG_TYPE_MAKE_SEND);
+	      if (!err)
+		err = __auth_user_authenticate (newauth,
+						ref, MACH_MSG_TYPE_MAKE_SEND,
+						newport);
+	      __mach_port_destroy (__mach_task_self (), ref);
+	      return err;
+	    }
+	  inline void reauth_port (unsigned int idx)
+	    {
+	      io_t newport;
+	      err = reauth_io (ports[idx], &newport) ?: err;
+	      if (pdp)
+		*pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
+	      free_port (idx);
+	      ports[idx] = newport;
+	    }
+
+	  if (pdp)
+	    *pdp++ = ports[INIT_PORT_AUTH];
+	  free_port (INIT_PORT_AUTH);
+	  ports[INIT_PORT_AUTH] = newauth;
+
+	  reauth_port (INIT_PORT_CRDIR);
+	  reauth_port (INIT_PORT_CWDIR);
+
+	  if (!err)
+	    {
+	      /* Now we'll reauthenticate each file descriptor.  */
+	      if (ulink_dtable == NULL)
+		{
+		  assert (dtable == _hurd_init_dtable);
+		  dtable = __alloca (dtablesize * sizeof (dtable[0]));
+		  for (i = 0; i < dtablesize; ++i)
+		    if (_hurd_init_dtable[i] != MACH_PORT_NULL)
+		      {
+			if (pdp)
+			  *pdp++ = _hurd_init_dtable[i];
+			err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
+			if (err)
+			  {
+			    while (++i < dtablesize)
+			      dtable[i] = MACH_PORT_NULL;
+			    break;
+			  }
+		      }
+		    else
+		      dtable[i] = MACH_PORT_NULL;
+		}
+	      else
+		{
+		  if (pdp)
+		    {
+		      /* Ask to deallocate all the old fd ports,
+			 since we will have new ones in DTABLE.  */
+		      memcpy (pdp, dtable, dtablesize * sizeof pdp[0]);
+		      pdp += dtablesize;
+		    }
+		  for (i = 0; i < dtablesize; ++i)
+		    if (dtable[i] != MACH_PORT_NULL)
+		      {
+			io_t newport;
+			err = reauth_io (dtable[i], &newport);
+			_hurd_port_free (dtable_cells[i], &ulink_dtable[i],
+					 dtable[i]);
+			dtable[i] = newport;
+			if (err)
+			  {
+			    while (++i < dtablesize)
+			      _hurd_port_free (dtable_cells[i],
+					       &ulink_dtable[i], dtable[i]);
+			    break;
+			  }
+		      }
+		  ulink_dtable = NULL;
+		  dtable_cells = NULL;
+		}
+	    }
+	}
+
+      reauth = 1;
+    }
+  __mutex_unlock (&_hurd_id.lock);
+
+  /* The information is all set up now.  Try to exec the file.  */
+  if (!err)
+    {
+      int flags;
+
+      if (pdp)
+	{
+	  /* Request the exec server to deallocate some ports from us if
+	     the exec succeeds.  The init ports and descriptor ports will
+	     arrive in the new program's exec_startup message.  If we
+	     failed to deallocate them, the new program would have
+	     duplicate user references for them.  But we cannot deallocate
+	     them ourselves, because we must still have them after a failed
+	     exec call.  */
+
+	  for (i = 0; i < _hurd_nports; ++i)
+	    *pdp++ = ports[i];
+	  for (i = 0; i < dtablesize; ++i)
+	    *pdp++ = dtable[i];
+	}
+
+      flags = 0;
+#ifdef EXEC_SIGTRAP
+      /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is
+	 propagated through exec by INIT_TRACEMASK, so this checks if
+	 PTRACE_TRACEME has been called in this process in any of its
+	 current or prior lives.  */
+      if (__sigismember (&_hurdsig_traced, SIGKILL))
+	flags |= EXEC_SIGTRAP;
+#endif
+      err = __file_exec (file, task, flags,
+			 args, argslen, env, envlen,
+			 dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
+			 ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
+			 ints, INIT_INT_MAX,
+			 please_dealloc, pdp - please_dealloc,
+			 &_hurd_msgport, task == __mach_task_self () ? 1 : 0);
+    }
+
+  /* Release references to the standard ports.  */
+  for (i = 0; i < _hurd_nports; ++i)
+    if ((i == INIT_PORT_PROC && task != __mach_task_self ())
+	|| (reauth && (i == INIT_PORT_AUTH
+		       || i == INIT_PORT_CRDIR || i == INIT_PORT_CWDIR)))
+      __mach_port_deallocate (__mach_task_self (), ports[i]);
+    else
+      free_port (i);
+
+  /* Release references to the file descriptor ports.  */
+  if (ulink_dtable != NULL)
+    {
+      for (i = 0; i < dtablesize; ++i)
+	if (dtable[i] != MACH_PORT_NULL)
+	  _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
+    }
+  else if (dtable && dtable != _hurd_init_dtable)
+    for (i = 0; i < dtablesize; ++i)
+      __mach_port_deallocate (__mach_task_self (), dtable[i]);
+
+  /* Release lock on the file descriptor table. */
+  __mutex_unlock (&_hurd_dtable_lock);
+
+  /* Safe to let signals happen now.  */
+  _hurd_critical_section_unlock (ss);
+
+ outargs:
+  free (args);
+ outenv:
+  free (env);
+  return err;
+}
diff --git a/REORG.TODO/hurd/hurdfault.c b/REORG.TODO/hurd/hurdfault.c
new file mode 100644
index 0000000000..9cd65b6cd9
--- /dev/null
+++ b/REORG.TODO/hurd/hurdfault.c
@@ -0,0 +1,237 @@
+/* Handle faults in the signal thread.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include "hurdfault.h"
+#include <errno.h>
+#include <string.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <thread_state.h>
+#include "faultexc_server.h"	/* mig-generated header for our exc server.  */
+#include <assert.h>
+
+jmp_buf _hurdsig_fault_env;
+struct hurd_signal_preemptor _hurdsig_fault_preemptor = {0};
+
+/* XXX temporary to deal with spelling fix */
+weak_alias (_hurdsig_fault_preemptor, _hurdsig_fault_preempter)
+
+static mach_port_t forward_sigexc;
+
+kern_return_t
+_hurdsig_fault_catch_exception_raise (mach_port_t port,
+				      thread_t thread,
+				      task_t task,
+#ifdef EXC_MASK_ALL		/* New interface flavor.  */
+				      exception_type_t exception,
+				      exception_data_t code,
+				      mach_msg_type_number_t codeCnt
+#else				/* Vanilla Mach 3.0 interface.  */
+				      integer_t exception,
+				      integer_t code, integer_t subcode
+#endif
+				      )
+{
+  int signo;
+  struct hurd_signal_detail d;
+
+  if (port != forward_sigexc ||
+      thread != _hurd_msgport_thread || task != __mach_task_self ())
+    return EPERM;		/* Strange bogosity.  */
+
+  d.exc = exception;
+#ifdef EXC_MASK_ALL
+  assert (codeCnt >= 2);
+  d.exc_code = code[0];
+  d.exc_subcode = code[1];
+#else
+  d.exc_code = code;
+  d.exc_subcode = subcode;
+#endif
+
+  /* Call the machine-dependent function to translate the Mach exception
+     codes into a signal number and subcode.  */
+  _hurd_exception2signal (&d, &signo);
+
+  return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
+    ? 0 : EGREGIOUS;
+}
+
+#ifdef EXC_MASK_ALL
+/* XXX New interface flavor has additional RPCs that we could be using
+   instead.  These RPCs roll a thread_get_state/thread_set_state into
+   the message, so the signal thread ought to use these to save some calls.
+ */
+kern_return_t
+_hurdsig_fault_catch_exception_raise_state
+(mach_port_t port,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt)
+{
+  abort ();
+  return KERN_FAILURE;
+}
+
+kern_return_t
+_hurdsig_fault_catch_exception_raise_state_identity
+(mach_port_t exception_port,
+ thread_t thread,
+ task_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt)
+{
+  abort ();
+  return KERN_FAILURE;
+}
+#endif
+
+
+#ifdef NDR_CHAR_ASCII		/* OSF Mach flavors have different names.  */
+# define mig_reply_header_t	mig_reply_error_t
+#endif
+
+static void
+faulted (void)
+{
+  struct
+    {
+      mach_msg_header_t head;
+      char buf[64];
+    } request;
+  mig_reply_header_t reply;
+  extern int _hurdsig_fault_exc_server (mach_msg_header_t *,
+					mach_msg_header_t *);
+
+ /* Wait for the exception_raise message forwarded by the proc server.  */
+
+ if (__mach_msg (&request.head, MACH_RCV_MSG, 0,
+		  sizeof request, forward_sigexc,
+		  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
+      != MACH_MSG_SUCCESS)
+    __libc_fatal ("msg receive failed on signal thread exc\n");
+
+  /* Run the exc demuxer which should call the server function above.
+     That function returns 0 if the exception was expected.  */
+  _hurdsig_fault_exc_server (&request.head, &reply.Head);
+  if (reply.Head.msgh_remote_port != MACH_PORT_NULL)
+    __mach_msg (&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size,
+		0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if (reply.RetCode == MIG_BAD_ID)
+    __mach_msg_destroy (&request.head);
+
+  if (reply.RetCode)
+    __libc_fatal ("BUG: unexpected fault in signal thread\n");
+
+  _hurdsig_fault_preemptor.signals = 0;
+  longjmp (_hurdsig_fault_env, 1);
+}
+
+static char faultstack[1024];
+
+/* Send exceptions for the signal thread to the proc server.
+   It will forward the message on to our message port,
+   and then restore the thread's state to code which
+   does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
+
+void
+_hurdsig_fault_init (void)
+{
+  error_t err;
+  struct machine_thread_state state;
+  mach_port_t sigexc;
+
+  /* Allocate a port to receive signal thread exceptions.
+     We will move this receive right to the proc server.  */
+  err = __mach_port_allocate (__mach_task_self (),
+			      MACH_PORT_RIGHT_RECEIVE, &sigexc);
+  assert_perror (err);
+  err = __mach_port_allocate (__mach_task_self (),
+			      MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
+  assert_perror (err);
+
+  /* Allocate a port to receive the exception msgs forwarded
+     from the proc server.  */
+  err = __mach_port_insert_right (__mach_task_self (), sigexc,
+				  sigexc, MACH_MSG_TYPE_MAKE_SEND);
+  assert_perror (err);
+
+  /* Set the queue limit for this port to just one.  The proc server will
+     notice if we ever get a second exception while one remains queued and
+     unreceived, and decide we are hopelessly buggy.  */
+#ifdef MACH_PORT_RECEIVE_STATUS_COUNT
+  {
+    const mach_port_limits_t lim = { mpl_qlimit: 1 };
+    assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
+    err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
+				      MACH_PORT_RECEIVE_STATUS,
+				      (mach_port_info_t) &lim,
+				      MACH_PORT_RECEIVE_STATUS_COUNT);
+  }
+#else
+  err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
+#endif
+  assert_perror (err);
+
+  /* This state will be restored when we fault.
+     It runs the function above.  */
+  memset (&state, 0, sizeof state);
+  MACHINE_THREAD_STATE_SET_PC (&state, faulted);
+  MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);
+
+  err = __USEPORT
+    (PROC,
+     __proc_handle_exceptions (port,
+			       sigexc,
+			       forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
+			       MACHINE_THREAD_STATE_FLAVOR,
+			       (natural_t *) &state,
+			       MACHINE_THREAD_STATE_COUNT));
+  assert_perror (err);
+
+  /* Direct signal thread exceptions to the proc server.  */
+#ifdef THREAD_EXCEPTION_PORT
+  err = __thread_set_special_port (_hurd_msgport_thread,
+				   THREAD_EXCEPTION_PORT, sigexc);
+#elif defined (EXC_MASK_ALL)
+  __thread_set_exception_ports (_hurd_msgport_thread,
+				EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
+						 | EXC_MASK_MACH_SYSCALL
+						 | EXC_MASK_RPC_ALERT),
+				sigexc,
+				EXCEPTION_STATE_IDENTITY,
+				MACHINE_THREAD_STATE);
+#else
+# error thread_set_exception_ports?
+#endif
+  __mach_port_deallocate (__mach_task_self (), sigexc);
+  assert_perror (err);
+}
diff --git a/REORG.TODO/hurd/hurdfault.h b/REORG.TODO/hurd/hurdfault.h
new file mode 100644
index 0000000000..9da5b684dc
--- /dev/null
+++ b/REORG.TODO/hurd/hurdfault.h
@@ -0,0 +1,50 @@
+/* Declarations for handling faults in the signal thread.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURD_FAULT_H
+#define _HURD_FAULT_H
+
+#include <hurd/sigpreempt.h>
+#include <setjmp.h>
+
+/* Call this before code that might fault in the signal thread; SIGNO is
+   the signal expected to possibly arrive.  This behaves like setjmp: it
+   returns zero the first time, and returns again nonzero if the signal
+   does arrive.  */
+
+#define _hurdsig_catch_fault(sigset, firstcode, lastcode)	\
+  (_hurdsig_fault_preemptor.signals = (sigset),			\
+   _hurdsig_fault_preemptor.first = (long int) (firstcode),	\
+   _hurdsig_fault_preemptor.last = (long int) (lastcode),	\
+   setjmp (_hurdsig_fault_env))
+
+/* Call this at the end of a section protected by _hurdsig_catch_fault.  */
+
+#define _hurdsig_end_catch_fault() \
+  (_hurdsig_fault_preemptor.signals = 0)
+
+extern jmp_buf _hurdsig_fault_env;
+extern struct hurd_signal_preemptor _hurdsig_fault_preemptor;
+
+
+#define _hurdsig_catch_memory_fault(object) \
+  _hurdsig_catch_fault (sigmask (SIGSEGV) | sigmask (SIGBUS), \
+			(object), (object) + 1)
+
+
+#endif	/* hurdfault.h */
diff --git a/REORG.TODO/hurd/hurdfchdir.c b/REORG.TODO/hurd/hurdfchdir.c
new file mode 100644
index 0000000000..97c758b67f
--- /dev/null
+++ b/REORG.TODO/hurd/hurdfchdir.c
@@ -0,0 +1,58 @@
+/* Change a port cell to a directory in an open file descriptor.
+   Copyright (C) 1999-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/port.h>
+#include <hurd/fd.h>
+#include <fcntl.h>
+
+int
+_hurd_change_directory_port_from_fd (struct hurd_port *portcell, int fd)
+{
+  int ret;
+  struct hurd_fd *d = _hurd_fd_get (fd);
+
+  if (!d)
+    return __hurd_fail (EBADF);
+
+  HURD_CRITICAL_BEGIN;
+
+  ret = HURD_PORT_USE (&d->port,
+		       ({
+			 int ret;
+			 /* We look up "." to force ENOTDIR if it's not a
+			    directory and EACCES if we don't have search
+			    permission.  */
+			 file_t dir = __file_name_lookup_under (port, ".",
+								O_NOTRANS, 0);
+			 if (dir == MACH_PORT_NULL)
+			   ret = -1;
+			 else
+			   {
+			     _hurd_port_set (portcell, dir);
+			     ret = 0;
+			   }
+			 ret;
+		       }));
+
+  HURD_CRITICAL_END;
+
+  return ret;
+}
diff --git a/REORG.TODO/hurd/hurdhost.h b/REORG.TODO/hurd/hurdhost.h
new file mode 100644
index 0000000000..c4e89517bc
--- /dev/null
+++ b/REORG.TODO/hurd/hurdhost.h
@@ -0,0 +1,27 @@
+/* Host configuration items kept as the whole contents of a file.
+   Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Fetch and atomically store the contents of the file ITEM.
+   Returns the size read or written, or -1 for errors.
+   If BUFLEN is not big enough to contain the whole contents,
+   BUFLEN bytes of BUF are filled in and we fail with ENAMETOOLONG.  */
+
+ssize_t _hurd_get_host_config (const char *item,
+			       char *buf, size_t buflen);
+ssize_t _hurd_set_host_config (const char *item,
+			       const char *value, size_t valuelen);
diff --git a/REORG.TODO/hurd/hurdid.c b/REORG.TODO/hurd/hurdid.c
new file mode 100644
index 0000000000..66d760beef
--- /dev/null
+++ b/REORG.TODO/hurd/hurdid.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/id.h>
+
+struct hurd_id_data _hurd_id;
+
+
+/* Check that _hurd_id.{gen,aux} are valid and update them if not.
+   Expects _hurd_id.lock to be held and does not release it.  */
+
+error_t
+_hurd_check_ids (void)
+{
+  if (! _hurd_id.valid)
+    {
+      inline void dealloc (__typeof (_hurd_id.gen) *p)
+	{
+	  if (p->uids)
+	    {
+	      __vm_deallocate (__mach_task_self (),
+			       (vm_address_t) p->uids,
+			       p->nuids * sizeof (uid_t));
+	      p->uids = NULL;
+	    }
+	  p->nuids = 0;
+	  if (p->gids)
+	    {
+	      __vm_deallocate (__mach_task_self (),
+			       (vm_address_t) p->gids,
+			       p->ngids * sizeof (gid_t));
+	      p->gids = NULL;
+	    }
+	  p->ngids = 0;
+	}
+
+      error_t err;
+
+      dealloc (&_hurd_id.gen);
+      dealloc (&_hurd_id.aux);
+
+      if (_hurd_id.rid_auth != MACH_PORT_NULL)
+	{
+	  __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
+	  _hurd_id.rid_auth = MACH_PORT_NULL;
+	}
+
+      if (err = __USEPORT (AUTH, __auth_getids
+			   (port,
+			    &_hurd_id.gen.uids, &_hurd_id.gen.nuids,
+			    &_hurd_id.aux.uids, &_hurd_id.aux.nuids,
+			    &_hurd_id.gen.gids, &_hurd_id.gen.ngids,
+			    &_hurd_id.aux.gids, &_hurd_id.aux.ngids)))
+	return err;
+
+      _hurd_id.valid = 1;
+    }
+
+  return 0;
+}
+
+static void
+init_id (void)
+{
+  __mutex_init (&_hurd_id.lock);
+  _hurd_id.valid = 0;
+  _hurd_id.rid_auth = MACH_PORT_NULL;
+  _hurd_id.gen.uids = _hurd_id.aux.uids = NULL;
+  _hurd_id.gen.nuids = _hurd_id.aux.nuids = 0;
+  _hurd_id.gen.gids = _hurd_id.aux.gids = NULL;
+  _hurd_id.gen.ngids = _hurd_id.aux.ngids = 0;
+
+  (void) &init_id;		/* Avoid "defined but not used" warning.  */
+}
+text_set_element (_hurd_preinit_hook, init_id);
diff --git a/REORG.TODO/hurd/hurdinit.c b/REORG.TODO/hurd/hurdinit.c
new file mode 100644
index 0000000000..5afdfbc890
--- /dev/null
+++ b/REORG.TODO/hurd/hurdinit.c
@@ -0,0 +1,225 @@
+/* Copyright (C) 1992-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/port.h>
+#include "set-hooks.h"
+#include "hurdmalloc.h"		/* XXX */
+
+
+int _hurd_exec_flags;
+struct hurd_port *_hurd_ports;
+unsigned int _hurd_nports;
+mode_t _hurd_umask;
+sigset_t _hurdsig_traced;
+
+char **__libc_argv;
+int __libc_argc;
+
+
+error_t
+_hurd_ports_use (int which, error_t (*operate) (mach_port_t))
+{
+  if (__glibc_unlikely (_hurd_ports == NULL))
+    /* This means that _hurd_init has not been called yet, which is
+       normally only the case in the bootstrap filesystem, and there
+       only in the early phases of booting.  */
+    return EGRATUITOUS;
+
+  return HURD_PORT_USE (&_hurd_ports[which], (*operate) (port));
+}
+
+DEFINE_HOOK (_hurd_subinit, (void));
+
+__typeof (_hurd_proc_init) _hurd_new_proc_init;	/* below */
+
+/* Initialize the library data structures from the
+   ints and ports passed to us by the exec server.
+
+   PORTARRAY and INTARRAY are vm_deallocate'd.  */
+
+void
+_hurd_init (int flags, char **argv,
+	    mach_port_t *portarray, size_t portarraysize,
+	    int *intarray, size_t intarraysize)
+{
+  size_t i;
+
+  _hurd_exec_flags = flags;
+
+  _hurd_ports = malloc (portarraysize * sizeof (*_hurd_ports));
+  if (_hurd_ports == NULL)
+    __libc_fatal ("Can't allocate _hurd_ports\n");
+  _hurd_nports = portarraysize;
+
+  /* See what ports we were passed.  */
+  for (i = 0; i < portarraysize; ++i)
+    _hurd_port_init (&_hurd_ports[i], portarray[i]);
+
+  /* When the user asks for the bootstrap port,
+     he will get the one the exec server passed us.  */
+  __task_set_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT,
+			   portarray[INIT_PORT_BOOTSTRAP]);
+
+  if (intarraysize > INIT_UMASK)
+    _hurd_umask = intarray[INIT_UMASK] & 0777;
+  else
+    _hurd_umask = CMASK;
+
+  if (intarraysize > INIT_TRACEMASK)
+    _hurdsig_traced = intarray[INIT_TRACEMASK];
+
+  /* Tell the proc server we exist, if it does.  */
+  if (portarray[INIT_PORT_PROC] != MACH_PORT_NULL)
+    _hurd_new_proc_init (argv, intarray, intarraysize);
+
+  /* All done with init ints and ports.  */
+  __vm_deallocate (__mach_task_self (),
+		   (vm_address_t) intarray,
+		   intarraysize * sizeof (int));
+  __vm_deallocate (__mach_task_self (),
+		   (vm_address_t) portarray,
+		   portarraysize * sizeof (mach_port_t));
+
+  if (flags & EXEC_SECURE)
+    /* XXX if secure exec, elide environment variables
+       which the library uses and could be security holes.
+       CORESERVER, COREFILE
+       */ ;
+
+  /* Call other things which want to do some initialization.  These are not
+     on the __libc_subinit hook because things there like to be able to
+     assume the availability of the POSIX.1 services we provide.  */
+  RUN_HOOK (_hurd_subinit, ());
+}
+
+#include <hurd/signal.h>
+
+/* The user can do "int _hide_arguments = 1;" to make
+   sure the arguments are never visible with `ps'.  */
+int _hide_arguments, _hide_environment;
+
+/* Hook for things which should be initialized as soon as the proc
+   server is available.  */
+DEFINE_HOOK (_hurd_proc_subinit, (void));
+
+/* Do startup handshaking with the proc server just installed in _hurd_ports.
+   Call _hurdsig_init to set up signal processing.  */
+
+void
+_hurd_new_proc_init (char **argv,
+		     const int *intarray, size_t intarraysize)
+{
+  mach_port_t oldmsg;
+  struct hurd_userlink ulink;
+  process_t procserver;
+
+  /* Initialize the signal code; Mach exceptions will become signals.  */
+  _hurdsig_init (intarray, intarraysize);
+
+  /* The signal thread is now prepared to receive messages.
+     It is safe to give the port to the proc server.  */
+
+  procserver = _hurd_port_get (&_hurd_ports[INIT_PORT_PROC], &ulink);
+
+  /* Give the proc server our message port.  */
+  __proc_setmsgport (procserver, _hurd_msgport, &oldmsg);
+  if (oldmsg != MACH_PORT_NULL)
+    /* Deallocate the old msg port we replaced.  */
+    __mach_port_deallocate (__mach_task_self (), oldmsg);
+
+  /* Tell the proc server where our args and environment are.  */
+  __proc_set_arg_locations (procserver,
+			    _hide_arguments ? 0 : (vm_address_t) argv,
+			    _hide_environment ? 0 : (vm_address_t) __environ);
+
+  _hurd_port_free (&_hurd_ports[INIT_PORT_PROC], &ulink, procserver);
+
+  /* Initialize proc server-assisted fault recovery for the signal thread.  */
+  _hurdsig_fault_init ();
+
+  /* Call other things which want to do some initialization.  These are not
+     on the _hurd_subinit hook because things there assume that things done
+     here, like _hurd_pid, are already initialized.  */
+  RUN_HOOK (_hurd_proc_subinit, ());
+
+  /* XXX This code should probably be removed entirely at some point.  This
+     conditional should make it reasonably usable with old gdb's for a
+     while.  Eventually it probably makes most sense for the exec server to
+     mask out EXEC_SIGTRAP so the debugged program is closer to not being
+     able to tell it's being debugged.  */
+  if (!__sigisemptyset (&_hurdsig_traced)
+#ifdef EXEC_SIGTRAP
+      && !(_hurd_exec_flags & EXEC_SIGTRAP)
+#endif
+      )
+    /* This process is "traced", meaning it should stop on signals or exec.
+       We are all set up now to handle signals.  Stop ourselves, to inform
+       our parent (presumably a debugger) that the exec has completed.  */
+    __msg_sig_post (_hurd_msgport, SIGTRAP, 0, __mach_task_self ());
+}
+
+#include <shlib-compat.h>
+versioned_symbol (libc, _hurd_new_proc_init, _hurd_proc_init, GLIBC_2_1);
+
+/* Called when we get a message telling us to change our proc server port.  */
+
+error_t
+_hurd_setproc (process_t procserver)
+{
+  error_t err;
+  mach_port_t oldmsg;
+
+  /* Give the proc server our message port.  */
+  if (err = __proc_setmsgport (procserver, _hurd_msgport, &oldmsg))
+    return err;
+  if (oldmsg != MACH_PORT_NULL)
+    /* Deallocate the old msg port we replaced.  */
+    __mach_port_deallocate (__mach_task_self (), oldmsg);
+
+  /* Tell the proc server where our args and environment are.  */
+  if (err = __proc_set_arg_locations (procserver,
+				      _hide_arguments ? 0 :
+				      (vm_address_t) __libc_argv,
+				      _hide_environment ? 0 :
+				      (vm_address_t) __environ))
+    return err;
+
+  /* Those calls worked, so the port looks good.  */
+  _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver);
+
+  {
+    pid_t oldpgrp = _hurd_pgrp;
+
+    /* Call these functions again so they can fetch the
+       new information from the new proc server.  */
+    RUN_HOOK (_hurd_proc_subinit, ());
+
+    if (_hurd_pgrp != oldpgrp)
+      {
+	/* Run things that want notification of a pgrp change.  */
+	DECLARE_HOOK (_hurd_pgrp_changed_hook, (pid_t));
+	RUN_HOOK (_hurd_pgrp_changed_hook, (_hurd_pgrp));
+      }
+  }
+
+  return 0;
+}
diff --git a/REORG.TODO/hurd/hurdioctl.c b/REORG.TODO/hurd/hurdioctl.c
new file mode 100644
index 0000000000..73ec3ea3cc
--- /dev/null
+++ b/REORG.TODO/hurd/hurdioctl.c
@@ -0,0 +1,331 @@
+/* ioctl commands which must be done in the C library.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <sys/ioctl.h>
+#include <hurd/ioctl.h>
+#include <string.h>
+
+
+/* Symbol set of ioctl handler lists.  If there are user-registered
+   handlers, one of these lists will contain them.  The other lists are
+   handlers built into the library.  */
+symbol_set_define (_hurd_ioctl_handler_lists)
+
+/* Look up REQUEST in the set of handlers.  */
+ioctl_handler_t
+_hurd_lookup_ioctl_handler (int request)
+{
+  void *const *ptr;
+  const struct ioctl_handler *h;
+
+  /* Mask off the type bits, so that we see requests in a single group as a
+     contiguous block of values.  */
+  request = _IOC_NOTYPE (request);
+
+  for (ptr = symbol_set_first_element (_hurd_ioctl_handler_lists);
+       !symbol_set_end_p (_hurd_ioctl_handler_lists, ptr);
+       ++ptr)
+    for (h = *ptr; h != NULL; h = h->next)
+      if (request >= h->first_request && request <= h->last_request)
+	return h->handler;
+
+  return NULL;
+}
+
+#include <fcntl.h>
+
+/* Find out how many bytes may be read from FD without blocking.  */
+
+static int
+fioctl (int fd,
+	int request,
+	int *arg)
+{
+  error_t err;
+
+  *(volatile int *) arg = *arg;
+
+  switch (request)
+    {
+    default:
+      err = ENOTTY;
+      break;
+
+    case FIONREAD:
+      {
+	mach_msg_type_number_t navail;
+	err = HURD_DPORT_USE (fd, __io_readable (port, &navail));
+	if (!err)
+	  *arg = (int) navail;
+      }
+      break;
+
+    case FIONBIO:
+      err = HURD_DPORT_USE (fd, (*arg ?
+				 __io_set_some_openmodes :
+				 __io_clear_some_openmodes)
+			    (port, O_NONBLOCK));
+      break;
+
+    case FIOASYNC:
+      err = HURD_DPORT_USE (fd, (*arg ?
+				 __io_set_some_openmodes :
+				 __io_clear_some_openmodes)
+			    (port, O_ASYNC));
+      break;
+
+    case FIOSETOWN:
+      err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg));
+      break;
+
+    case FIOGETOWN:
+      err = HURD_DPORT_USE (fd, __io_get_owner (port, arg));
+      break;
+    }
+
+  return err ? __hurd_dfail (fd, err) : 0;
+}
+
+_HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD);
+
+
+static int
+fioclex (int fd,
+	 int request)
+{
+  int flag;
+
+  switch (request)
+    {
+    default:
+      return __hurd_fail (ENOTTY);
+    case FIOCLEX:
+      flag = FD_CLOEXEC;
+      break;
+    case FIONCLEX:
+      flag = 0;
+      break;
+    }
+
+  return __fcntl (fd, F_SETFD, flag);
+}
+_HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX);
+
+#include <hurd/term.h>
+#include <hurd/tioctl.h>
+
+/* Install a new CTTYID port, atomically updating the dtable appropriately.
+   This consumes the send right passed in.  */
+
+void
+_hurd_locked_install_cttyid (mach_port_t cttyid)
+{
+  mach_port_t old;
+  struct hurd_port *const port = &_hurd_ports[INIT_PORT_CTTYID];
+  struct hurd_userlink ulink;
+  int i;
+
+  /* Install the new cttyid port, and preserve it with a ulink.
+     We unroll the _hurd_port_set + _hurd_port_get here so that
+     there is no window where the cell is unlocked and CTTYID could
+     be changed by another thread.  (We also delay the deallocation
+     of the old port until the end, to minimize the duration of the
+     critical section.)
+
+     It is important that changing the cttyid port is only ever done by
+     holding the dtable lock continuously while updating the port cell and
+     re-ctty'ing the dtable; dtable.c assumes we do this.  Otherwise, the
+     pgrp-change notification code in dtable.c has to worry about racing
+     against us here in odd situations.  The one exception to this is
+     setsid, which holds the dtable lock while changing the pgrp and
+     clearing the cttyid port, and then unlocks the dtable lock to allow
+
+
+  */
+
+  __spin_lock (&port->lock);
+  old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL;
+  port->port = cttyid;
+  cttyid = _hurd_port_locked_get (port, &ulink);
+
+  for (i = 0; i < _hurd_dtablesize; ++i)
+    {
+      struct hurd_fd *const d = _hurd_dtable[i];
+      mach_port_t newctty = MACH_PORT_NULL;
+
+      if (d == NULL)
+	/* Nothing to do for an unused descriptor cell.  */
+	continue;
+
+      if (cttyid != MACH_PORT_NULL)
+	/* We do have some controlling tty.  */
+	HURD_PORT_USE (&d->port,
+		       ({ mach_port_t id;
+			  /* Get the io object's cttyid port.  */
+			  if (! __term_getctty (port, &id))
+			    {
+			      if (id == cttyid /* Is it ours?  */
+				  /* Get the ctty io port.  */
+				  && __term_open_ctty (port,
+						       _hurd_pid, _hurd_pgrp,
+						       &newctty))
+				/* XXX it is our ctty but the call failed? */
+				newctty = MACH_PORT_NULL;
+			      __mach_port_deallocate (__mach_task_self (), id);
+			    }
+			  0;
+			}));
+
+      /* Install the new ctty port.  */
+      _hurd_port_set (&d->ctty, newctty);
+    }
+
+  __mutex_unlock (&_hurd_dtable_lock);
+
+  if (old != MACH_PORT_NULL)
+    __mach_port_deallocate (__mach_task_self (), old);
+  _hurd_port_free (port, &ulink, cttyid);
+}
+
+static void
+install_ctty (mach_port_t cttyid)
+{
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_dtable_lock);
+  _hurd_locked_install_cttyid (cttyid);
+  HURD_CRITICAL_END;
+}
+
+
+/* Called when we have received a message saying to use a new ctty ID port.  */
+
+error_t
+_hurd_setcttyid (mach_port_t cttyid)
+{
+  error_t err;
+
+  if (cttyid != MACH_PORT_NULL)
+    {
+      /* Give the new send right a user reference.
+	 This is a good way to check that it is valid.  */
+      if (err = __mach_port_mod_refs (__mach_task_self (), cttyid,
+				      MACH_PORT_RIGHT_SEND, 1))
+	return err;
+    }
+
+  /* Install the port, consuming the reference we just created.  */
+  install_ctty (cttyid);
+
+  return 0;
+}
+
+
+static inline error_t
+do_tiocsctty (io_t port, io_t ctty)
+{
+  mach_port_t cttyid;
+  error_t err;
+
+  if (ctty != MACH_PORT_NULL)
+    /* PORT is already the ctty.  Nothing to do.  */
+    return 0;
+
+  /* Get PORT's cttyid port.  */
+  err = __term_getctty (port, &cttyid);
+  if (err)
+    return err;
+
+  /* Change the terminal's pgrp to ours.  */
+  err = __tioctl_tiocspgrp (port, _hurd_pgrp);
+  if (err)
+    __mach_port_deallocate (__mach_task_self (), cttyid);
+  else
+    /* Make it our own.  */
+    install_ctty (cttyid);
+
+  return err;
+}
+
+/* Make FD be the controlling terminal.
+   This function is called for `ioctl (fd, TCIOSCTTY)'.  */
+
+static int
+tiocsctty (int fd,
+	   int request)		/* Always TIOCSCTTY.  */
+{
+  return __hurd_fail (HURD_DPORT_USE (fd, do_tiocsctty (port, ctty)));
+}
+_HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
+
+/* Dissociate from the controlling terminal.  */
+
+static int
+tiocnotty (int fd,
+	   int request)		/* Always TIOCNOTTY.  */
+{
+  mach_port_t fd_cttyid;
+  error_t err;
+
+  if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid)))
+    return __hurd_fail (err);
+
+  if (__USEPORT (CTTYID, port != fd_cttyid))
+    err = EINVAL;
+
+  __mach_port_deallocate (__mach_task_self (), fd_cttyid);
+
+  if (err)
+    return __hurd_fail (err);
+
+  /* Clear our cttyid port.  */
+  install_ctty (MACH_PORT_NULL);
+
+  return 0;
+}
+_HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
+
+#include <hurd/pfinet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+/* Fill in the buffer IFC->IFC_BUF of length IFC->IFC_LEN with a list
+   of ifr structures, one for each network interface.  */
+static int
+siocgifconf (int fd, int request, struct ifconf *ifc)
+{
+  error_t err;
+  size_t data_len = ifc->ifc_len;
+  char *data = ifc->ifc_buf;
+
+  if (data_len <= 0)
+    return 0;
+
+  err = HURD_DPORT_USE (fd, __pfinet_siocgifconf (port, ifc->ifc_len,
+						  &data, &data_len));
+  if (data_len < ifc->ifc_len)
+    ifc->ifc_len = data_len;
+  if (data != ifc->ifc_buf)
+    {
+      memcpy (ifc->ifc_buf, data, ifc->ifc_len);
+      __vm_deallocate (__mach_task_self (), (vm_address_t) data, data_len);
+    }
+  return err ? __hurd_dfail (fd, err) : 0;
+}
+_HURD_HANDLE_IOCTL (siocgifconf, SIOCGIFCONF);
diff --git a/REORG.TODO/hurd/hurdkill.c b/REORG.TODO/hurd/hurdkill.c
new file mode 100644
index 0000000000..e8375d3d3d
--- /dev/null
+++ b/REORG.TODO/hurd/hurdkill.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <hurd.h>
+#include <hurd/port.h>
+#include <hurd/signal.h>
+#include <hurd/msg.h>
+
+/* Send a `sig_post' RPC to process number PID.  If PID is zero,
+   send the message to all processes in the current process's process group.
+   If PID is < -1, send SIG to all processes in process group - PID.
+   SIG and REFPORT are passed along in the request message.  */
+error_t
+_hurd_sig_post (pid_t pid, int sig, mach_port_t arg_refport)
+{
+  int delivered = 0;		/* Set when we deliver any signal.  */
+  error_t err;
+  mach_port_t proc;
+  struct hurd_userlink ulink;
+
+  inline void kill_pid (pid_t pid) /* Kill one PID.  */
+    {
+      err = HURD_MSGPORT_RPC (__proc_getmsgport (proc, pid, &msgport),
+			      (refport = arg_refport, 0), 0,
+			      /* If no message port we cannot send signals.  */
+			      msgport == MACH_PORT_NULL ? EPERM :
+			      __msg_sig_post (msgport, sig, 0, refport));
+      if (! err)
+	delivered = 1;
+    }
+
+  proc = _hurd_port_get (&_hurd_ports[INIT_PORT_PROC], &ulink);
+
+  if (pid <= 0)
+    {
+      /* Send SIG to each process in pgrp (- PID).  */
+      mach_msg_type_number_t npids = 10, i;
+      pid_t pidsbuf[10], *pids = pidsbuf;
+
+      err = __proc_getpgrppids (proc, - pid, &pids, &npids);
+      if (!err)
+	{
+	  int self = 0;
+	  for (i = 0; i < npids; ++i)
+	    if (pids[i] == _hurd_pid)
+	      /* We must do ourselves last so we are not suspended
+		 and fail to suspend the other processes in the pgrp.  */
+	      self = 1;
+	    else
+	      {
+		kill_pid (pids[i]);
+		if (err == ESRCH)
+		  /* The process died already.  Ignore it.  */
+		  err = 0;
+	      }
+	  if (pids != pidsbuf)
+	    __vm_deallocate (__mach_task_self (),
+			     (vm_address_t) pids, npids * sizeof (pids[0]));
+
+	  if (self)
+	    kill_pid (_hurd_pid);
+	}
+    }
+  else
+    kill_pid (pid);
+
+  _hurd_port_free (&_hurd_ports[INIT_PORT_PROC], &ulink, proc);
+
+  /* If we delivered no signals, but ERR is clear, this must mean that
+     every kill_pid call failed with ESRCH, meaning all the processes in
+     the pgrp died between proc_getpgrppids and kill_pid; in that case we
+     fail with ESRCH.  */
+  return delivered ? 0 : err ?: ESRCH;
+}
+weak_alias (_hurd_sig_post, hurd_sig_post)
diff --git a/REORG.TODO/hurd/hurdlookup.c b/REORG.TODO/hurd/hurdlookup.c
new file mode 100644
index 0000000000..84cb3d3015
--- /dev/null
+++ b/REORG.TODO/hurd/hurdlookup.c
@@ -0,0 +1,281 @@
+/* Copyright (C) 1992-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include <string.h>
+#include <fcntl.h>
+
+
+/* Translate the error from dir_lookup into the error the user sees.  */
+static inline error_t
+lookup_error (error_t error)
+{
+  switch (error)
+    {
+    case EOPNOTSUPP:
+    case MIG_BAD_ID:
+      /* These indicate that the server does not understand dir_lookup
+	 at all.  If it were a directory, it would, by definition.  */
+      return ENOTDIR;
+    default:
+      return error;
+    }
+}
+
+error_t
+__hurd_file_name_lookup (error_t (*use_init_port)
+			   (int which, error_t (*operate) (file_t)),
+			 file_t (*get_dtable_port) (int fd),
+			 error_t (*lookup)
+			   (file_t dir, char *name, int flags, mode_t mode,
+			    retry_type *do_retry, string_t retry_name,
+			    mach_port_t *result),
+			 const char *file_name, int flags, mode_t mode,
+			 file_t *result)
+{
+  error_t err;
+  enum retry_type doretry;
+  char retryname[1024];		/* XXX string_t LOSES! */
+  int startport;
+
+  error_t lookup_op (mach_port_t startdir)
+    {
+      return lookup_error ((*lookup) (startdir, file_name, flags, mode,
+				      &doretry, retryname, result));
+    }
+
+  if (! lookup)
+    lookup = __dir_lookup;
+
+  if (file_name[0] == '\0')
+    return ENOENT;
+
+  startport = (file_name[0] == '/') ? INIT_PORT_CRDIR : INIT_PORT_CWDIR;
+  while (file_name[0] == '/')
+    file_name++;
+
+  if (flags & O_NOFOLLOW)	/* See lookup-retry.c about O_NOFOLLOW.  */
+    flags |= O_NOTRANS;
+
+  if (flags & O_DIRECTORY)
+    {
+      /* The caller wants to require that the file we look up is a directory.
+	 We can do this without an extra RPC by appending a trailing slash
+	 to the file name we look up.  */
+      size_t len = strlen (file_name);
+      if (len == 0)
+	file_name = "/";
+      else if (file_name[len - 1] != '/')
+	{
+	  char *n = alloca (len + 2);
+	  memcpy (n, file_name, len);
+	  n[len] = '/';
+	  n[len + 1] = '\0';
+	  file_name = n;
+	}
+    }
+
+  err = (*use_init_port) (startport, &lookup_op);
+  if (! err)
+    err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
+					 lookup, doretry, retryname,
+					 flags, mode, result);
+
+  return err;
+}
+weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup)
+
+error_t
+__hurd_file_name_split (error_t (*use_init_port)
+			  (int which, error_t (*operate) (file_t)),
+			file_t (*get_dtable_port) (int fd),
+			error_t (*lookup)
+			  (file_t dir, char *name, int flags, mode_t mode,
+			   retry_type *do_retry, string_t retry_name,
+			   mach_port_t *result),
+			const char *file_name,
+			file_t *dir, char **name)
+{
+  error_t addref (file_t crdir)
+    {
+      *dir = crdir;
+      return __mach_port_mod_refs (__mach_task_self (),
+				   crdir, MACH_PORT_RIGHT_SEND, +1);
+    }
+
+  const char *lastslash = strrchr (file_name, '/');
+
+  if (lastslash != NULL)
+    {
+      if (lastslash == file_name)
+	{
+	  /* "/foobar" => crdir + "foobar".  */
+	  *name = (char *) file_name + 1;
+	  return (*use_init_port) (INIT_PORT_CRDIR, &addref);
+	}
+      else
+	{
+	  /* "/dir1/dir2/.../file".  */
+	  char dirname[lastslash - file_name + 1];
+	  memcpy (dirname, file_name, lastslash - file_name);
+	  dirname[lastslash - file_name] = '\0';
+	  *name = (char *) lastslash + 1;
+	  return
+	    __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
+				     dirname, 0, 0, dir);
+	}
+    }
+  else if (file_name[0] == '\0')
+    return ENOENT;
+  else
+    {
+      /* "foobar" => cwdir + "foobar".  */
+      *name = (char *) file_name;
+      return (*use_init_port) (INIT_PORT_CWDIR, &addref);
+    }
+}
+weak_alias (__hurd_file_name_split, hurd_file_name_split)
+
+/* This is the same as hurd_file_name_split, except that it ignores
+   trailing slashes (so *NAME is never "").  */
+error_t
+__hurd_directory_name_split (error_t (*use_init_port)
+			     (int which, error_t (*operate) (file_t)),
+			     file_t (*get_dtable_port) (int fd),
+			     error_t (*lookup)
+			     (file_t dir, char *name, int flags, mode_t mode,
+			      retry_type *do_retry, string_t retry_name,
+			      mach_port_t *result),
+			     const char *file_name,
+			     file_t *dir, char **name)
+{
+  error_t addref (file_t crdir)
+    {
+      *dir = crdir;
+      return __mach_port_mod_refs (__mach_task_self (),
+				   crdir, MACH_PORT_RIGHT_SEND, +1);
+    }
+
+  const char *lastslash = strrchr (file_name, '/');
+
+  if (lastslash != NULL && lastslash[1] == '\0')
+    {
+      /* Trailing slash doesn't count.  Look back further.  */
+
+      /* Back up over all trailing slashes.  */
+      while (lastslash > file_name && *lastslash == '/')
+	--lastslash;
+
+      /* Find the last one earlier in the string, before the trailing ones.  */
+      lastslash = __memrchr (file_name, '/', lastslash - file_name);
+    }
+
+  if (lastslash != NULL)
+    {
+      if (lastslash == file_name)
+	{
+	  /* "/foobar" => crdir + "foobar".  */
+	  *name = (char *) file_name + 1;
+	  return (*use_init_port) (INIT_PORT_CRDIR, &addref);
+	}
+      else
+	{
+	  /* "/dir1/dir2/.../file".  */
+	  char dirname[lastslash - file_name + 1];
+	  memcpy (dirname, file_name, lastslash - file_name);
+	  dirname[lastslash - file_name] = '\0';
+	  *name = (char *) lastslash + 1;
+	  return
+	    __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
+				     dirname, 0, 0, dir);
+	}
+    }
+  else if (file_name[0] == '\0')
+    return ENOENT;
+  else
+    {
+      /* "foobar" => cwdir + "foobar".  */
+      *name = (char *) file_name;
+      return (*use_init_port) (INIT_PORT_CWDIR, &addref);
+    }
+}
+weak_alias (__hurd_directory_name_split, hurd_directory_name_split)
+
+
+file_t
+__file_name_lookup (const char *file_name, int flags, mode_t mode)
+{
+  error_t err;
+  file_t result;
+
+  err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, 0,
+				 file_name, flags, mode & ~_hurd_umask,
+				 &result);
+
+  return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
+}
+weak_alias (__file_name_lookup, file_name_lookup)
+
+
+file_t
+__file_name_split (const char *file_name, char **name)
+{
+  error_t err;
+  file_t result;
+
+  err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0,
+				file_name, &result, name);
+
+  return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
+}
+weak_alias (__file_name_split, file_name_split)
+
+file_t
+__directory_name_split (const char *directory_name, char **name)
+{
+  error_t err;
+  file_t result;
+
+  err = __hurd_directory_name_split (&_hurd_ports_use, &__getdport, 0,
+				     directory_name, &result, name);
+
+  return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
+}
+weak_alias (__directory_name_split, directory_name_split)
+
+
+file_t
+__file_name_lookup_under (file_t startdir,
+			  const char *file_name, int flags, mode_t mode)
+{
+  error_t err;
+  file_t result;
+
+  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
+    {
+      return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
+	      _hurd_ports_use (which, operate));
+    }
+
+  err = __hurd_file_name_lookup (&use_init_port, &__getdport, 0,
+				 file_name, flags, mode & ~_hurd_umask,
+				 &result);
+
+  return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
+}
+weak_alias (__file_name_lookup_under, file_name_lookup_under)
diff --git a/REORG.TODO/hurd/hurdmalloc.c b/REORG.TODO/hurd/hurdmalloc.c
new file mode 100644
index 0000000000..65fb959d84
--- /dev/null
+++ b/REORG.TODO/hurd/hurdmalloc.c
@@ -0,0 +1,449 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "hurdmalloc.h"		/* XXX see that file */
+
+#include <mach.h>
+#define vm_allocate __vm_allocate
+#define vm_page_size __vm_page_size
+
+/*
+ * 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  Software.Distribution@CS.CMU.EDU
+ *  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.
+ */
+/*
+ * (pre-GNU) HISTORY
+ *
+ * Revision 2.7  91/05/14  17:57:34  mrt
+ * 	Correcting copyright
+ *
+ * Revision 2.6  91/02/14  14:20:26  mrt
+ * 	Added new Mach copyright
+ * 	[91/02/13  12:41:21  mrt]
+ *
+ * Revision 2.5  90/11/05  14:37:33  rpd
+ * 	Added malloc_fork* code.
+ * 	[90/11/02            rwd]
+ *
+ * 	Add spin_lock_t.
+ * 	[90/10/31            rwd]
+ *
+ * Revision 2.4  90/08/07  14:31:28  rpd
+ * 	Removed RCS keyword nonsense.
+ *
+ * Revision 2.3  90/06/02  15:14:00  rpd
+ * 	Converted to new IPC.
+ * 	[90/03/20  20:56:57  rpd]
+ *
+ * Revision 2.2  89/12/08  19:53:59  rwd
+ * 	Removed conditionals.
+ * 	[89/10/23            rwd]
+ *
+ * Revision 2.1  89/08/03  17:09:46  rwd
+ * Created.
+ *
+ *
+ * 13-Sep-88  Eric Cooper (ecc) at Carnegie Mellon University
+ *	Changed realloc() to copy min(old size, new size) bytes.
+ *	Bug found by Mike Kupfer at Olivetti.
+ */
+/*
+ * 	File: 	malloc.c
+ *	Author: Eric Cooper, Carnegie Mellon University
+ *	Date:	July, 1988
+ *
+ * 	Memory allocator for use with multiple threads.
+ */
+
+
+#include <assert.h>
+
+#include <cthreads.h>
+
+#define MCHECK
+
+/*
+ * Structure of memory block header.
+ * When free, next points to next block on free list.
+ * When allocated, fl points to free list.
+ * Size of header is 4 bytes, so minimum usable block size is 8 bytes.
+ */
+
+#define CHECK_BUSY  0x8a3c743e
+#define CHECK_FREE  0x66688b92
+
+#ifdef MCHECK
+
+typedef struct header {
+  long check;
+  union {
+    struct header *next;
+    struct free_list *fl;
+  } u;
+} *header_t;
+
+#define HEADER_SIZE sizeof (struct header)
+#define HEADER_NEXT(h) ((h)->u.next)
+#define HEADER_FREE(h) ((h)->u.fl)
+#define HEADER_CHECK(h) ((h)->check)
+#define MIN_SIZE	16
+#define LOG2_MIN_SIZE	4
+
+#else /* ! MCHECK */
+
+typedef union header {
+	union header *next;
+	struct free_list *fl;
+} *header_t;
+
+#define HEADER_SIZE sizeof (union header)
+#define HEADER_NEXT(h) ((h)->next)
+#define HEADER_FREE(h) ((h)->fl)
+#define MIN_SIZE	8	/* minimum block size */
+#define LOG2_MIN_SIZE	3
+
+#endif /* MCHECK */
+
+typedef struct free_list {
+	spin_lock_t lock;	/* spin lock for mutual exclusion */
+	header_t head;		/* head of free list for this size */
+#ifdef	DEBUG
+	int in_use;		/* # mallocs - # frees */
+#endif	/* DEBUG */
+} *free_list_t;
+
+/*
+ * Free list with index i contains blocks of size 2 ^ (i + LOG2_MIN_SIZE)
+ * including header.  Smallest block size is MIN_SIZE, with MIN_SIZE -
+ * HEADER_SIZE bytes available to user.  Size argument to malloc is a signed
+ * integer for sanity checking, so largest block size is 2^31.
+ */
+#define NBUCKETS	29
+
+static struct free_list malloc_free_list[NBUCKETS];
+
+/* Initialization just sets everything to zero, but might be necessary on a
+   machine where spin_lock_init does otherwise, and is necessary when
+   running an executable that was written by something like Emacs's unexec.
+   It preserves the values of data variables like malloc_free_list, but
+   does not save the vm_allocate'd space allocated by this malloc.  */
+
+static void
+malloc_init (void)
+{
+  int i;
+  for (i = 0; i < NBUCKETS; ++i)
+    {
+      spin_lock_init (&malloc_free_list[i].lock);
+      malloc_free_list[i].head = NULL;
+#ifdef DEBUG
+      malloc_free_list[i].in_use = 0;
+#endif
+    }
+
+  /* This not only suppresses a `defined but not used' warning,
+     but it is ABSOLUTELY NECESSARY to avoid the hyperclever
+     compiler from "optimizing out" the entire function!  */
+  (void) &malloc_init;
+}
+
+static void
+more_memory(int size, free_list_t fl)
+{
+	int amount;
+	int n;
+	vm_address_t where;
+	header_t h;
+	kern_return_t r;
+
+	if (size <= vm_page_size) {
+		amount = vm_page_size;
+		n = vm_page_size / size;
+		/* We lose vm_page_size - n*size bytes here.  */
+	} else {
+		amount = size;
+		n = 1;
+	}
+
+	r = vm_allocate(mach_task_self(), &where, (vm_size_t) amount, TRUE);
+	assert_perror (r);
+
+	h = (header_t) where;
+	do {
+		HEADER_NEXT (h) = fl->head;
+#ifdef MCHECK
+		HEADER_CHECK (h) = CHECK_FREE;
+#endif
+		fl->head = h;
+		h = (header_t) ((char *) h + size);
+	} while (--n != 0);
+}
+
+/* Declaration changed to standard one for GNU.  */
+void *
+malloc (size_t size)
+{
+	int i, n;
+	free_list_t fl;
+	header_t h;
+
+	if ((int) size < 0)		/* sanity check */
+		return 0;
+	size += HEADER_SIZE;
+	/*
+	 * Find smallest power-of-two block size
+	 * big enough to hold requested size plus header.
+	 */
+	i = 0;
+	n = MIN_SIZE;
+	while (n < size) {
+		i += 1;
+		n <<= 1;
+	}
+	ASSERT(i < NBUCKETS);
+	fl = &malloc_free_list[i];
+	spin_lock(&fl->lock);
+	h = fl->head;
+	if (h == 0) {
+		/*
+		 * Free list is empty;
+		 * allocate more blocks.
+		 */
+		more_memory(n, fl);
+		h = fl->head;
+		if (h == 0) {
+			/*
+			 * Allocation failed.
+			 */
+			spin_unlock(&fl->lock);
+			return 0;
+		}
+	}
+	/*
+	 * Pop block from free list.
+	 */
+	fl->head = HEADER_NEXT (h);
+
+#ifdef MCHECK
+	assert (HEADER_CHECK (h) == CHECK_FREE);
+	HEADER_CHECK (h) = CHECK_BUSY;
+#endif
+
+#ifdef	DEBUG
+	fl->in_use += 1;
+#endif	/* DEBUG */
+	spin_unlock(&fl->lock);
+	/*
+	 * Store free list pointer in block header
+	 * so we can figure out where it goes
+	 * at free() time.
+	 */
+	HEADER_FREE (h) = fl;
+	/*
+	 * Return pointer past the block header.
+	 */
+	return ((char *) h) + HEADER_SIZE;
+}
+
+/* Declaration changed to standard one for GNU.  */
+void
+free (void *base)
+{
+	header_t h;
+	free_list_t fl;
+	int i;
+
+	if (base == 0)
+		return;
+	/*
+	 * Find free list for block.
+	 */
+	h = (header_t) (base - HEADER_SIZE);
+
+#ifdef MCHECK
+	assert (HEADER_CHECK (h) == CHECK_BUSY);
+#endif
+
+	fl = HEADER_FREE (h);
+	i = fl - malloc_free_list;
+	/*
+	 * Sanity checks.
+	 */
+	if (i < 0 || i >= NBUCKETS) {
+		ASSERT(0 <= i && i < NBUCKETS);
+		return;
+	}
+	if (fl != &malloc_free_list[i]) {
+		ASSERT(fl == &malloc_free_list[i]);
+		return;
+	}
+	/*
+	 * Push block on free list.
+	 */
+	spin_lock(&fl->lock);
+	HEADER_NEXT (h) = fl->head;
+#ifdef MCHECK
+	HEADER_CHECK (h) = CHECK_FREE;
+#endif
+	fl->head = h;
+#ifdef	DEBUG
+	fl->in_use -= 1;
+#endif	/* DEBUG */
+	spin_unlock(&fl->lock);
+	return;
+}
+
+/* Declaration changed to standard one for GNU.  */
+void *
+realloc (void *old_base, size_t new_size)
+{
+	header_t h;
+	free_list_t fl;
+	int i;
+	unsigned int old_size;
+	char *new_base;
+
+	if (old_base == 0)
+	  return malloc (new_size);
+
+	/*
+	 * Find size of old block.
+	 */
+	h = (header_t) (old_base - HEADER_SIZE);
+#ifdef MCHECK
+	assert (HEADER_CHECK (h) == CHECK_BUSY);
+#endif
+	fl = HEADER_FREE (h);
+	i = fl - malloc_free_list;
+	/*
+	 * Sanity checks.
+	 */
+	if (i < 0 || i >= NBUCKETS) {
+		ASSERT(0 <= i && i < NBUCKETS);
+		return 0;
+	}
+	if (fl != &malloc_free_list[i]) {
+		ASSERT(fl == &malloc_free_list[i]);
+		return 0;
+	}
+	/*
+	 * Free list with index i contains blocks of size
+	 * 2 ^ (i + * LOG2_MIN_SIZE) including header.
+	 */
+	old_size = (1 << (i + LOG2_MIN_SIZE)) - HEADER_SIZE;
+
+	if (new_size <= old_size
+	    && new_size > (((old_size + HEADER_SIZE) >> 1) - HEADER_SIZE))
+	  /* The new size still fits in the same block, and wouldn't fit in
+	     the next smaller block!  */
+	  return old_base;
+
+	/*
+	 * Allocate new block, copy old bytes, and free old block.
+	 */
+	new_base = malloc(new_size);
+	if (new_base)
+	  memcpy (new_base, old_base,
+		  (int) (old_size < new_size ? old_size : new_size));
+
+	if (new_base || new_size == 0)
+	  /* Free OLD_BASE, but only if the malloc didn't fail.  */
+	  free (old_base);
+
+	return new_base;
+}
+
+#ifdef	DEBUG
+void
+print_malloc_free_list (void)
+{
+	int i, size;
+	free_list_t fl;
+	int n;
+	header_t h;
+	int total_used = 0;
+	int total_free = 0;
+
+	fprintf(stderr, "      Size     In Use       Free      Total\n");
+	for (i = 0, size = MIN_SIZE, fl = malloc_free_list;
+	     i < NBUCKETS;
+	     i += 1, size <<= 1, fl += 1) {
+		spin_lock(&fl->lock);
+		if (fl->in_use != 0 || fl->head != 0) {
+			total_used += fl->in_use * size;
+			for (n = 0, h = fl->head; h != 0; h = HEADER_NEXT (h), n += 1)
+				;
+			total_free += n * size;
+			fprintf(stderr, "%10d %10d %10d %10d\n",
+				size, fl->in_use, n, fl->in_use + n);
+		}
+		spin_unlock(&fl->lock);
+	}
+	fprintf(stderr, " all sizes %10d %10d %10d\n",
+		total_used, total_free, total_used + total_free);
+}
+#endif	/* DEBUG */
+
+void
+_hurd_malloc_fork_prepare(void)
+/*
+ * Prepare the malloc module for a fork by insuring that no thread is in a
+ * malloc critical section.
+ */
+{
+    int i;
+
+    for (i = 0; i < NBUCKETS; i++) {
+	spin_lock(&malloc_free_list[i].lock);
+    }
+}
+
+void
+_hurd_malloc_fork_parent(void)
+/*
+ * Called in the parent process after a fork() to resume normal operation.
+ */
+{
+    int i;
+
+    for (i = NBUCKETS-1; i >= 0; i--) {
+	spin_unlock(&malloc_free_list[i].lock);
+    }
+}
+
+void
+_hurd_malloc_fork_child(void)
+/*
+ * Called in the child process after a fork() to resume normal operation.
+ */
+{
+    int i;
+
+    for (i = NBUCKETS-1; i >= 0; i--) {
+	spin_unlock(&malloc_free_list[i].lock);
+    }
+}
+
+
+text_set_element (_hurd_preinit_hook, malloc_init);
diff --git a/REORG.TODO/hurd/hurdmalloc.h b/REORG.TODO/hurd/hurdmalloc.h
new file mode 100644
index 0000000000..3520ffacd8
--- /dev/null
+++ b/REORG.TODO/hurd/hurdmalloc.h
@@ -0,0 +1,21 @@
+/* XXX this file is a temporary hack.
+
+   All hurd-internal code which uses malloc et al includes this file so it
+   will use the internal malloc routines _hurd_{malloc,realloc,free}
+   instead.  The "hurd-internal" functions are the cthreads version,
+   which uses vm_allocate and is thread-safe.  The normal user version
+   of malloc et al is the unixoid one using sbrk.
+
+ */
+
+extern void *_hurd_malloc (size_t);
+extern void *_hurd_realloc (void *, size_t);
+extern void _hurd_free (void *);
+
+extern void _hurd_malloc_fork_prepare (void);
+extern void _hurd_malloc_fork_parent (void);
+extern void _hurd_malloc_fork_child (void);
+
+#define malloc	_hurd_malloc
+#define realloc	_hurd_realloc
+#define free	_hurd_free
diff --git a/REORG.TODO/hurd/hurdmsg.c b/REORG.TODO/hurd/hurdmsg.c
new file mode 100644
index 0000000000..4249ba104a
--- /dev/null
+++ b/REORG.TODO/hurd/hurdmsg.c
@@ -0,0 +1,419 @@
+/* Copyright (C) 1992-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/msg_server.h>
+#include <hurd/fd.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <argz.h>
+
+
+#define AUTHCHECK \
+  if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth)) \
+    return EPERM
+
+
+/* Snarfing and frobbing the init ports.  */
+
+kern_return_t
+  _S_msg_get_init_port (mach_port_t msgport, mach_port_t auth, int which,
+			mach_port_t *result, mach_msg_type_name_t *result_type)
+{
+  AUTHCHECK;
+  *result_type = MACH_MSG_TYPE_MOVE_SEND;
+  /* This function adds a new user reference for the *RESULT it gives back.
+     Our reply message uses a move-send right that consumes this reference.  */
+  return _hurd_ports_get (which, result);
+}
+
+kern_return_t
+_S_msg_set_init_port (mach_port_t msgport, mach_port_t auth,
+		      int which, mach_port_t port)
+{
+  error_t err;
+
+  AUTHCHECK;
+
+  err = _hurd_ports_set (which, port);
+  if (err == 0)
+    __mach_port_deallocate (__mach_task_self (), port);
+
+  return 0;
+}
+
+kern_return_t
+_S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth,
+		       mach_port_t **ports,
+		       mach_msg_type_name_t *ports_type,
+		       mach_msg_type_number_t *nports)
+{
+  mach_msg_type_number_t i;
+  error_t err;
+
+  AUTHCHECK;
+
+  if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports,
+			   _hurd_nports * sizeof (mach_port_t), 1))
+    return err;
+  *nports = _hurd_nports;
+
+  for (i = 0; i < _hurd_nports; ++i)
+    /* This function adds a new user ref for the *RESULT it gives back.
+       Our reply message uses move-send rights that consumes this ref.  */
+    if (err = _hurd_ports_get (i, &(*ports)[i]))
+      {
+	/* Died part way through.  Deallocate the ports already fetched.  */
+	while (i-- > 0)
+	  __mach_port_deallocate (__mach_task_self (), (*ports)[i]);
+	__vm_deallocate (__mach_task_self (),
+			 (vm_address_t) *ports,
+			 *nports * sizeof (mach_port_t));
+	return err;
+      }
+
+  *ports_type = MACH_MSG_TYPE_MOVE_SEND;
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth,
+		       mach_port_t *ports, mach_msg_type_number_t nports)
+{
+  mach_msg_type_number_t i;
+  error_t err;
+
+  AUTHCHECK;
+
+  for (i = 0; i < _hurd_nports; ++i)
+    {
+      if (err = _hurd_ports_set (i, ports[i]))
+	return err;
+      else
+	__mach_port_deallocate (__mach_task_self (), ports[i]);
+    }
+
+  return 0;
+}
+
+/* Snarfing and frobbing the init ints.  */
+
+static kern_return_t
+get_int (int which, int *value)
+{
+  switch (which)
+    {
+    case INIT_UMASK:
+      *value = _hurd_umask;
+      return 0;
+    case INIT_SIGMASK:
+      {
+	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+	__spin_lock (&ss->lock);
+	*value = ss->blocked;
+	__spin_unlock (&ss->lock);
+	return 0;
+      }
+    case INIT_SIGPENDING:
+      {
+	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+	__spin_lock (&ss->lock);
+	*value = ss->pending;
+	__spin_unlock (&ss->lock);
+	return 0;
+      }
+    case INIT_SIGIGN:
+      {
+	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+	sigset_t ign;
+	int sig;
+	__spin_lock (&ss->lock);
+	__sigemptyset (&ign);
+	for (sig = 1; sig < NSIG; ++sig)
+	  if (ss->actions[sig].sa_handler == SIG_IGN)
+	    __sigaddset (&ign, sig);
+	__spin_unlock (&ss->lock);
+	*value = ign;
+	return 0;
+      }
+    default:
+      return EINVAL;
+    }
+}
+
+kern_return_t
+_S_msg_get_init_int (mach_port_t msgport, mach_port_t auth,
+		     int which, int *value)
+{
+  AUTHCHECK;
+
+  return get_int (which, value);
+}
+
+kern_return_t
+_S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth,
+		      int **values, mach_msg_type_number_t *nvalues)
+{
+  error_t err;
+  mach_msg_type_number_t i;
+
+  AUTHCHECK;
+
+  if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values,
+			   INIT_INT_MAX * sizeof (int), 1))
+    return err;
+  *nvalues = INIT_INT_MAX;
+
+  for (i = 0; i < INIT_INT_MAX; ++i)
+    switch (err = get_int (i, &(*values)[i]))
+      {
+      case 0:			/* Success.  */
+	break;
+      case EINVAL:		/* Unknown index.  */
+	(*values)[i] = 0;
+	break;
+      default:			/* Lossage.  */
+	__vm_deallocate (__mach_task_self (),
+			 (vm_address_t) *values, INIT_INT_MAX * sizeof (int));
+	return err;
+      }
+
+  return 0;
+}
+
+
+static kern_return_t
+set_int (int which, int value)
+{
+  switch (which)
+    {
+    case INIT_UMASK:
+      _hurd_umask = value;
+      return 0;
+
+      /* These are pretty odd things to do.  But you asked for it.  */
+    case INIT_SIGMASK:
+      {
+	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+	__spin_lock (&ss->lock);
+	ss->blocked = value;
+	__spin_unlock (&ss->lock);
+	return 0;
+      }
+    case INIT_SIGPENDING:
+      {
+	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+	__spin_lock (&ss->lock);
+	ss->pending = value;
+	__spin_unlock (&ss->lock);
+	return 0;
+      }
+    case INIT_SIGIGN:
+      {
+	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+	int sig;
+	const sigset_t ign = value;
+	__spin_lock (&ss->lock);
+	for (sig = 1; sig < NSIG; ++sig)
+	  {
+	    if (__sigismember (&ign, sig))
+	      ss->actions[sig].sa_handler = SIG_IGN;
+	    else if (ss->actions[sig].sa_handler == SIG_IGN)
+	      ss->actions[sig].sa_handler = SIG_DFL;
+	  }
+	__spin_unlock (&ss->lock);
+	return 0;
+
+      case INIT_TRACEMASK:
+	_hurdsig_traced = value;
+	return 0;
+      }
+    default:
+      return EINVAL;
+    }
+}
+
+kern_return_t
+_S_msg_set_init_int (mach_port_t msgport, mach_port_t auth,
+		     int which, int value)
+{
+  AUTHCHECK;
+
+  return set_int (which, value);
+}
+
+kern_return_t
+_S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth,
+		      int *values, mach_msg_type_number_t nvalues)
+{
+  error_t err;
+  mach_msg_type_number_t i;
+
+  AUTHCHECK;
+
+  for (i = 0; i < INIT_INT_MAX; ++i)
+    switch (err = set_int (i, values[i]))
+      {
+      case 0:			/* Success.  */
+	break;
+      case EINVAL:		/* Unknown index.  */
+	break;
+      default:			/* Lossage.  */
+	return err;
+      }
+
+  return 0;
+}
+
+
+kern_return_t
+_S_msg_get_fd (mach_port_t msgport, mach_port_t auth, int which,
+	       mach_port_t *result, mach_msg_type_name_t *result_type)
+{
+  AUTHCHECK;
+
+  /* This creates a new user reference for the send right.
+     Our reply message will move that reference to the caller.  */
+  *result = __getdport (which);
+  if (*result == MACH_PORT_NULL)
+    return errno;
+  *result_type = MACH_MSG_TYPE_MOVE_SEND;
+
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_fd (mach_port_t msgport, mach_port_t auth,
+	       int which, mach_port_t port)
+{
+  AUTHCHECK;
+
+  /* We consume the reference if successful.  */
+  return HURD_FD_USE (which, (_hurd_port2fd (descriptor, port, 0), 0));
+}
+
+/* Snarfing and frobbing environment variables.  */
+
+kern_return_t
+_S_msg_get_env_variable (mach_port_t msgport,
+			 char *variable,
+			 char **data, mach_msg_type_number_t *datalen)
+{
+  error_t err;
+  mach_msg_type_number_t valuelen;
+  const char *value = getenv (variable);
+
+  if (value == NULL)
+    return ENOENT;
+
+  valuelen = strlen (value);
+  if (valuelen > *datalen)
+    {
+      if (err = __vm_allocate (__mach_task_self (),
+			       (vm_address_t *) data, valuelen, 1))
+	return err;
+    }
+
+  memcpy (*data, value, valuelen);
+  *datalen = valuelen;
+
+  return 0;
+}
+
+
+kern_return_t
+_S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth,
+			 char *variable,
+			 char *value,
+			 int replace)
+{
+  AUTHCHECK;
+
+  if (setenv (variable, value, replace)) /* XXX name space */
+    return errno;
+  return 0;
+}
+
+kern_return_t
+_S_msg_get_environment (mach_port_t msgport,
+			char **data, mach_msg_type_number_t *datalen)
+{
+  /* Pack the environment into an array with nulls separating elements.  */
+  if (__environ != NULL)
+    {
+      char *ap, **p;
+      size_t envlen = 0;
+
+      for (p = __environ; *p != NULL; ++p)
+	envlen += strlen (*p) + 1;
+
+      if (envlen > *datalen)
+	{
+	  if (__vm_allocate (__mach_task_self (),
+			     (vm_address_t *) data, envlen, 1))
+	    return ENOMEM;
+	}
+
+      ap = *data;
+      for (p = __environ; *p != NULL; ++p)
+	ap = __memccpy (ap, *p, '\0', ULONG_MAX);
+
+      *datalen = envlen;
+    }
+  else
+    *datalen = 0;
+
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_environment (mach_port_t msgport, mach_port_t auth,
+			char *data, mach_msg_type_number_t datalen)
+{
+  int _hurd_split_args (char *, mach_msg_type_number_t, char **);
+  int envc;
+  char **envp;
+
+  AUTHCHECK;
+
+  envc = __argz_count (data, datalen);
+  envp = malloc ((envc + 1) * sizeof (char *));
+  if (envp == NULL)
+    return errno;
+  __argz_extract (data, datalen, envp);
+  __environ = envp;		/* XXX cooperate with loadenv et al */
+  return 0;
+}
+
+
+/* XXX */
+
+kern_return_t
+_S_msg_get_dtable (mach_port_t process,
+		   mach_port_t refport,
+		   portarray_t *dtable,
+		   mach_msg_type_name_t *dtablePoly,
+		   mach_msg_type_number_t *dtableCnt)
+{ return EOPNOTSUPP; }
+
+kern_return_t
+_S_msg_set_dtable (mach_port_t process,
+		   mach_port_t refport,
+		   portarray_t dtable,
+		   mach_msg_type_number_t dtableCnt)
+{ return EOPNOTSUPP; }
diff --git a/REORG.TODO/hurd/hurdpid.c b/REORG.TODO/hurd/hurdpid.c
new file mode 100644
index 0000000000..114077d0cc
--- /dev/null
+++ b/REORG.TODO/hurd/hurdpid.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp;
+int _hurd_orphaned;
+
+static void
+init_pids (void)
+{
+  __USEPORT (PROC,
+	     ({
+	       __proc_getpids (port, &_hurd_pid, &_hurd_ppid, &_hurd_orphaned);
+	       __proc_getpgrp (port, _hurd_pid, &_hurd_pgrp);
+	     }));
+
+  (void) &init_pids;		/* Avoid "defined but not used" warning.  */
+}
+
+text_set_element (_hurd_proc_subinit, init_pids);
+
+#include <hurd/msg_server.h>
+#include "set-hooks.h"
+#include <cthreads.h>
+
+DEFINE_HOOK (_hurd_pgrp_changed_hook, (pid_t));
+
+/* These let user threads synchronize with an operation which changes ids.  */
+unsigned int _hurd_pids_changed_stamp;
+struct condition _hurd_pids_changed_sync;
+
+kern_return_t
+_S_msg_proc_newids (mach_port_t me,
+		    task_t task,
+		    pid_t ppid, pid_t pgrp, int orphaned)
+{
+  int pgrp_changed;
+
+  if (task != __mach_task_self ())
+    return EPERM;
+
+  __mach_port_deallocate (__mach_task_self (), task);
+
+  pgrp_changed = pgrp != _hurd_pgrp;
+  _hurd_ppid = ppid;
+  _hurd_pgrp = pgrp;
+  _hurd_orphaned = orphaned;
+
+  if (pgrp_changed)
+    /* Run things that want notification of a pgrp change.  */
+    RUN_HOOK (_hurd_pgrp_changed_hook, (pgrp));
+
+  /* Notify any waiting user threads that the id change as been completed.  */
+  ++_hurd_pids_changed_stamp;
+
+  return 0;
+}
diff --git a/REORG.TODO/hurd/hurdports.c b/REORG.TODO/hurd/hurdports.c
new file mode 100644
index 0000000000..1cf918d944
--- /dev/null
+++ b/REORG.TODO/hurd/hurdports.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/port.h>
+
+
+static inline mach_port_t
+get (const int idx)
+{
+  mach_port_t result;
+  error_t err = _hurd_ports_get (idx, &result);
+
+  if (err)
+    return __hurd_fail (err), MACH_PORT_NULL;
+  return result;
+}
+#define	GET(type, what, idx) \
+  type get##what (void) { return get (INIT_PORT_##idx); }
+
+static inline int
+set (const int idx, mach_port_t new)
+{
+  error_t err = _hurd_ports_set (idx, new);
+  return err ? __hurd_fail (err) : 0;
+}
+#define SET(type, what, idx) \
+  int set##what (type new) { return set (INIT_PORT_##idx, new); }
+
+#define	GETSET(type, what, idx) \
+  GET (type, what, idx) SET (type, what, idx)
+
+GETSET (process_t, proc, PROC)
+GETSET (mach_port_t, cttyid, CTTYID)
+GETSET (file_t, cwdir, CWDIR)
+GETSET (file_t, crdir, CRDIR)
+GETSET (auth_t, auth, AUTH)
diff --git a/REORG.TODO/hurd/hurdprio.c b/REORG.TODO/hurd/hurdprio.c
new file mode 100644
index 0000000000..5ea46b633c
--- /dev/null
+++ b/REORG.TODO/hurd/hurdprio.c
@@ -0,0 +1,88 @@
+/* Support code for dealing with priorities in the Hurd.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/resource.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+error_t
+_hurd_priority_which_map (enum __priority_which which, int who,
+			  error_t (*function) (pid_t, struct procinfo *),
+			  int pi_flags)
+{
+  mach_msg_type_number_t npids = 64, i;
+  pid_t pidbuf[npids], *pids = pidbuf;
+  error_t err;
+  struct procinfo *pip;
+  int pibuf[sizeof *pip + 5 * sizeof (pip->threadinfos[0])], *pi = pibuf;
+  mach_msg_type_number_t pisize = sizeof (pibuf) / sizeof (int);
+
+  switch (which)
+    {
+    default:
+      return EINVAL;
+
+    case PRIO_PROCESS:
+      err = (*function) (who ?: getpid (), 0); /* XXX special-case self? */
+      break;
+
+    case PRIO_PGRP:
+      err = __USEPORT (PROC, __proc_getpgrppids (port, who, &pids, &npids));
+      for (i = 0; !err && i < npids; ++i)
+	err = (*function) (pids[i], 0);
+      break;
+
+    case PRIO_USER:
+      if (who == 0)
+	who = geteuid ();
+      err = __USEPORT (PROC, __proc_getallpids (port, &pids, &npids));
+      for (i = 0; !err && i < npids; ++i)
+	{
+	  /* Get procinfo to check the owner.  */
+	  int *oldpi = pi;
+	  mach_msg_type_number_t oldpisize = pisize;
+	  char *tw = 0;
+	  size_t twsz = 0;
+	  err = __USEPORT (PROC, __proc_getprocinfo (port, pids[i],
+						     &pi_flags,
+						     &pi, &pisize,
+						     &tw, &twsz));
+	  if (!err)
+	    {
+	      if (twsz)		/* Gratuitous.  */
+		__munmap (tw, twsz);
+	      if (pi != oldpi && oldpi != pibuf)
+		/* Old buffer from last call was not reused; free it.  */
+		__munmap (oldpi, oldpisize * sizeof pi[0]);
+
+	      pip = (struct procinfo *) pi;
+	      if (pip->owner == (uid_t) who)
+		err = (*function) (pids[i], pip);
+	    }
+	}
+      break;
+    }
+
+  if (pids != pidbuf)
+    __munmap (pids, npids * sizeof pids[0]);
+  if (pi != pibuf)
+    __munmap (pi, pisize * sizeof pi[0]);
+
+  return err;
+}
diff --git a/REORG.TODO/hurd/hurdrlimit.c b/REORG.TODO/hurd/hurdrlimit.c
new file mode 100644
index 0000000000..6efb8e51c6
--- /dev/null
+++ b/REORG.TODO/hurd/hurdrlimit.c
@@ -0,0 +1,58 @@
+/* Resource limits.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <cthreads.h>
+#include <hurd/resource.h>
+
+/* This must be given an initializer, or the a.out linking rules will
+   not include the entire file when this symbol is referenced. */
+struct rlimit _hurd_rlimits[RLIM_NLIMITS] = { { 0, }, };
+
+/* This must be initialized data for the same reason as above, but this is
+   intentionally initialized to a bogus value to emphasize the point that
+   mutex_init is still required below just in case of unexec.  */
+struct mutex _hurd_rlimit_lock = { SPIN_LOCK_INITIALIZER, };
+
+static void
+init_rlimit (void)
+{
+  int i;
+
+  __mutex_init (&_hurd_rlimit_lock);
+
+  for (i = 0; i < RLIM_NLIMITS; ++i)
+    {
+      if (_hurd_rlimits[i].rlim_max == 0)
+	_hurd_rlimits[i].rlim_max = RLIM_INFINITY;
+      if (_hurd_rlimits[i].rlim_cur == 0)
+#define I(lim, val) case RLIMIT_##lim: _hurd_rlimits[i].rlim_cur = (val); break
+	switch (i)
+	  {
+	    I (NOFILE, 1024);	/* Linux 2.2.12 uses this initial value.  */
+
+	  default:
+	    _hurd_rlimits[i].rlim_cur = _hurd_rlimits[i].rlim_max;
+	    break;
+	  }
+#undef	I
+    }
+
+  (void) &init_rlimit;
+}
+text_set_element (_hurd_preinit_hook, init_rlimit);
diff --git a/REORG.TODO/hurd/hurdselect.c b/REORG.TODO/hurd/hurdselect.c
new file mode 100644
index 0000000000..8dc7c76995
--- /dev/null
+++ b/REORG.TODO/hurd/hurdselect.c
@@ -0,0 +1,491 @@
+/* Guts of both `select' and `poll' for Hurd.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+
+/* All user select types.  */
+#define SELECT_ALL (SELECT_READ | SELECT_WRITE | SELECT_URG)
+
+/* Used to record that a particular select rpc returned.  Must be distinct
+   from SELECT_ALL (which better not have the high bit set).  */
+#define SELECT_RETURNED ((SELECT_ALL << 1) & ~SELECT_ALL)
+
+/* Check the first NFDS descriptors either in POLLFDS (if nonnnull) or in
+   each of READFDS, WRITEFDS, EXCEPTFDS that is nonnull.  If TIMEOUT is not
+   NULL, time out after waiting the interval specified therein.  Returns
+   the number of ready descriptors, or -1 for errors.  */
+int
+_hurd_select (int nfds,
+	      struct pollfd *pollfds,
+	      fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	      const struct timespec *timeout, const sigset_t *sigmask)
+{
+  int i;
+  mach_port_t portset;
+  int got;
+  error_t err;
+  fd_set rfds, wfds, xfds;
+  int firstfd, lastfd;
+  mach_msg_timeout_t to = 0;
+  struct
+    {
+      struct hurd_userlink ulink;
+      struct hurd_fd *cell;
+      mach_port_t io_port;
+      int type;
+      mach_port_t reply_port;
+    } d[nfds];
+  sigset_t oset;
+
+  union typeword		/* Use this to avoid unkosher casts.  */
+    {
+      mach_msg_type_t type;
+      uint32_t word;
+    };
+  assert (sizeof (union typeword) == sizeof (mach_msg_type_t));
+  assert (sizeof (uint32_t) == sizeof (mach_msg_type_t));
+
+  if (nfds < 0 || (pollfds == NULL && nfds > FD_SETSIZE))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (timeout != NULL)
+    {
+      if (timeout->tv_sec < 0 || timeout->tv_nsec < 0)
+	{
+	  errno = EINVAL;
+	  return -1;
+	}
+
+      to = (timeout->tv_sec * 1000 +
+            (timeout->tv_nsec + 999999) / 1000000);
+    }
+
+  if (sigmask && __sigprocmask (SIG_SETMASK, sigmask, &oset))
+    return -1;
+
+  if (pollfds)
+    {
+      /* Collect interesting descriptors from the user's `pollfd' array.
+	 We do a first pass that reads the user's array before taking
+	 any locks.  The second pass then only touches our own stack,
+	 and gets the port references.  */
+
+      for (i = 0; i < nfds; ++i)
+	if (pollfds[i].fd >= 0)
+	  {
+	    int type = 0;
+	    if (pollfds[i].events & POLLIN)
+	      type |= SELECT_READ;
+	    if (pollfds[i].events & POLLOUT)
+	      type |= SELECT_WRITE;
+	    if (pollfds[i].events & POLLPRI)
+	      type |= SELECT_URG;
+
+	    d[i].io_port = pollfds[i].fd;
+	    d[i].type = type;
+	  }
+	else
+	  d[i].type = 0;
+
+      HURD_CRITICAL_BEGIN;
+      __mutex_lock (&_hurd_dtable_lock);
+
+      for (i = 0; i < nfds; ++i)
+	if (d[i].type != 0)
+	  {
+	    const int fd = (int) d[i].io_port;
+
+	    if (fd < _hurd_dtablesize)
+	      {
+		d[i].cell = _hurd_dtable[fd];
+		d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
+		if (d[i].io_port != MACH_PORT_NULL)
+		  continue;
+	      }
+
+	    /* If one descriptor is bogus, we fail completely.  */
+	    while (i-- > 0)
+	      if (d[i].type != 0)
+		_hurd_port_free (&d[i].cell->port,
+				 &d[i].ulink, d[i].io_port);
+	    break;
+	  }
+
+      __mutex_unlock (&_hurd_dtable_lock);
+      HURD_CRITICAL_END;
+
+      if (i < nfds)
+	{
+	  if (sigmask)
+	    __sigprocmask (SIG_SETMASK, &oset, NULL);
+	  errno = EBADF;
+	  return -1;
+	}
+
+      lastfd = i - 1;
+      firstfd = i == 0 ? lastfd : 0;
+    }
+  else
+    {
+      /* Collect interested descriptors from the user's fd_set arguments.
+	 Use local copies so we can't crash from user bogosity.  */
+
+      if (readfds == NULL)
+	FD_ZERO (&rfds);
+      else
+	rfds = *readfds;
+      if (writefds == NULL)
+	FD_ZERO (&wfds);
+      else
+	wfds = *writefds;
+      if (exceptfds == NULL)
+	FD_ZERO (&xfds);
+      else
+	xfds = *exceptfds;
+
+      HURD_CRITICAL_BEGIN;
+      __mutex_lock (&_hurd_dtable_lock);
+
+      if (nfds > _hurd_dtablesize)
+	nfds = _hurd_dtablesize;
+
+      /* Collect the ports for interesting FDs.  */
+      firstfd = lastfd = -1;
+      for (i = 0; i < nfds; ++i)
+	{
+	  int type = 0;
+	  if (readfds != NULL && FD_ISSET (i, &rfds))
+	    type |= SELECT_READ;
+	  if (writefds != NULL && FD_ISSET (i, &wfds))
+	    type |= SELECT_WRITE;
+	  if (exceptfds != NULL && FD_ISSET (i, &xfds))
+	    type |= SELECT_URG;
+	  d[i].type = type;
+	  if (type)
+	    {
+	      d[i].cell = _hurd_dtable[i];
+	      d[i].io_port = _hurd_port_get (&d[i].cell->port, &d[i].ulink);
+	      if (d[i].io_port == MACH_PORT_NULL)
+		{
+		  /* If one descriptor is bogus, we fail completely.  */
+		  while (i-- > 0)
+		    if (d[i].type != 0)
+		      _hurd_port_free (&d[i].cell->port, &d[i].ulink,
+				       d[i].io_port);
+		  break;
+		}
+	      lastfd = i;
+	      if (firstfd == -1)
+		firstfd = i;
+	    }
+	}
+
+      __mutex_unlock (&_hurd_dtable_lock);
+      HURD_CRITICAL_END;
+
+      if (i < nfds)
+	{
+	  if (sigmask)
+	    __sigprocmask (SIG_SETMASK, &oset, NULL);
+	  errno = EBADF;
+	  return -1;
+	}
+    }
+
+
+  err = 0;
+  got = 0;
+
+  /* Send them all io_select request messages.  */
+
+  if (firstfd == -1)
+    /* But not if there were no ports to deal with at all.
+       We are just a pure timeout.  */
+    portset = __mach_reply_port ();
+  else
+    {
+      portset = MACH_PORT_NULL;
+
+      for (i = firstfd; i <= lastfd; ++i)
+	if (d[i].type)
+	  {
+	    int type = d[i].type;
+	    d[i].reply_port = __mach_reply_port ();
+	    err = __io_select (d[i].io_port, d[i].reply_port,
+			       /* Poll only if there's a single descriptor.  */
+			       (firstfd == lastfd) ? to : 0,
+			       &type);
+	    switch (err)
+	      {
+	      case MACH_RCV_TIMED_OUT:
+		/* No immediate response.  This is normal.  */
+		err = 0;
+		if (firstfd == lastfd)
+		  /* When there's a single descriptor, we don't need a
+		     portset, so just pretend we have one, but really
+		     use the single reply port.  */
+		  portset = d[i].reply_port;
+		else if (got == 0)
+		  /* We've got multiple reply ports, so we need a port set to
+		     multiplex them.  */
+		  {
+		    /* We will wait again for a reply later.  */
+		    if (portset == MACH_PORT_NULL)
+		      /* Create the portset to receive all the replies on.  */
+		      err = __mach_port_allocate (__mach_task_self (),
+						  MACH_PORT_RIGHT_PORT_SET,
+						  &portset);
+		    if (! err)
+		      /* Put this reply port in the port set.  */
+		      __mach_port_move_member (__mach_task_self (),
+					       d[i].reply_port, portset);
+		  }
+		break;
+
+	      default:
+		/* No other error should happen.  Callers of select
+		   don't expect to see errors, so we simulate
+		   readiness of the erring object and the next call
+		   hopefully will get the error again.  */
+		type = SELECT_ALL;
+		/* FALLTHROUGH */
+
+	      case 0:
+		/* We got an answer.  */
+		if ((type & SELECT_ALL) == 0)
+		  /* Bogus answer; treat like an error, as a fake positive.  */
+		  type = SELECT_ALL;
+
+		/* This port is already ready already.  */
+		d[i].type &= type;
+		d[i].type |= SELECT_RETURNED;
+		++got;
+		break;
+	      }
+	    _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
+	  }
+    }
+
+  /* Now wait for reply messages.  */
+  if (!err && got == 0)
+    {
+      /* Now wait for io_select_reply messages on PORT,
+	 timing out as appropriate.  */
+
+      union
+	{
+	  mach_msg_header_t head;
+#ifdef MACH_MSG_TRAILER_MINIMUM_SIZE
+	  struct
+	    {
+	      mach_msg_header_t head;
+	      NDR_record_t ndr;
+	      error_t err;
+	    } error;
+	  struct
+	    {
+	      mach_msg_header_t head;
+	      NDR_record_t ndr;
+	      error_t err;
+	      int result;
+	      mach_msg_trailer_t trailer;
+	    } success;
+#else
+	  struct
+	    {
+	      mach_msg_header_t head;
+	      union typeword err_type;
+	      error_t err;
+	    } error;
+	  struct
+	    {
+	      mach_msg_header_t head;
+	      union typeword err_type;
+	      error_t err;
+	      union typeword result_type;
+	      int result;
+	    } success;
+#endif
+	} msg;
+      mach_msg_option_t options = (timeout == NULL ? 0 : MACH_RCV_TIMEOUT);
+      error_t msgerr;
+      while ((msgerr = __mach_msg (&msg.head,
+				   MACH_RCV_MSG | MACH_RCV_INTERRUPT | options,
+				   0, sizeof msg, portset, to,
+				   MACH_PORT_NULL)) == MACH_MSG_SUCCESS)
+	{
+	  /* We got a message.  Decode it.  */
+#define IO_SELECT_REPLY_MSGID (21012 + 100) /* XXX */
+#ifdef MACH_MSG_TYPE_BIT
+	  const union typeword inttype =
+	  { type:
+	    { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8, 1, 1, 0, 0 }
+	  };
+#endif
+	  if (msg.head.msgh_id == IO_SELECT_REPLY_MSGID &&
+	      msg.head.msgh_size >= sizeof msg.error &&
+	      !(msg.head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
+#ifdef MACH_MSG_TYPE_BIT
+	      msg.error.err_type.word == inttype.word
+#endif
+	      )
+	    {
+	      /* This is a properly formatted message so far.
+		 See if it is a success or a failure.  */
+	      if (msg.error.err == EINTR &&
+		  msg.head.msgh_size == sizeof msg.error)
+		{
+		  /* EINTR response; poll for further responses
+		     and then return quickly.  */
+		  err = EINTR;
+		  goto poll;
+		}
+	      if (msg.error.err ||
+		  msg.head.msgh_size != sizeof msg.success ||
+#ifdef MACH_MSG_TYPE_BIT
+		  msg.success.result_type.word != inttype.word ||
+#endif
+		  (msg.success.result & SELECT_ALL) == 0)
+		{
+		  /* Error or bogus reply.  Simulate readiness.  */
+		  __mach_msg_destroy (&msg.head);
+		  msg.success.result = SELECT_ALL;
+		}
+
+	      /* Look up the respondent's reply port and record its
+		 readiness.  */
+	      {
+		int had = got;
+		if (firstfd != -1)
+		  for (i = firstfd; i <= lastfd; ++i)
+		    if (d[i].type
+			&& d[i].reply_port == msg.head.msgh_local_port)
+		      {
+			d[i].type &= msg.success.result;
+			d[i].type |= SELECT_RETURNED;
+			++got;
+		      }
+		assert (got > had);
+	      }
+	    }
+
+	  if (msg.head.msgh_remote_port != MACH_PORT_NULL)
+	    __mach_port_deallocate (__mach_task_self (),
+				    msg.head.msgh_remote_port);
+
+	  if (got)
+	  poll:
+	    {
+	      /* Poll for another message.  */
+	      to = 0;
+	      options |= MACH_RCV_TIMEOUT;
+	    }
+	}
+
+      if (msgerr == MACH_RCV_INTERRUPTED)
+	/* Interruption on our side (e.g. signal reception).  */
+	err = EINTR;
+
+      if (got)
+	/* At least one descriptor is known to be ready now, so we will
+	   return success.  */
+	err = 0;
+    }
+
+  if (firstfd != -1)
+    for (i = firstfd; i <= lastfd; ++i)
+      if (d[i].type)
+	__mach_port_destroy (__mach_task_self (), d[i].reply_port);
+  if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
+    /* Destroy PORTSET, but only if it's not actually the reply port for a
+       single descriptor (in which case it's destroyed in the previous loop;
+       not doing it here is just a bit more efficient).  */
+    __mach_port_destroy (__mach_task_self (), portset);
+
+  if (err)
+    {
+      if (sigmask)
+	__sigprocmask (SIG_SETMASK, &oset, NULL);
+      return __hurd_fail (err);
+    }
+
+  if (pollfds)
+    /* Fill in the `revents' members of the user's array.  */
+    for (i = 0; i < nfds; ++i)
+      {
+	int type = d[i].type;
+	int_fast16_t revents = 0;
+
+	if (type & SELECT_RETURNED)
+	  {
+	    if (type & SELECT_READ)
+	      revents |= POLLIN;
+	    if (type & SELECT_WRITE)
+	      revents |= POLLOUT;
+	    if (type & SELECT_URG)
+	      revents |= POLLPRI;
+	  }
+
+	pollfds[i].revents = revents;
+      }
+  else
+    {
+      /* Below we recalculate GOT to include an increment for each operation
+	 allowed on each fd.  */
+      got = 0;
+
+      /* Set the user bitarrays.  We only ever have to clear bits, as all
+	 desired ones are initially set.  */
+      if (firstfd != -1)
+	for (i = firstfd; i <= lastfd; ++i)
+	  {
+	    int type = d[i].type;
+
+	    if ((type & SELECT_RETURNED) == 0)
+	      type = 0;
+
+	    if (type & SELECT_READ)
+	      got++;
+	    else if (readfds)
+	      FD_CLR (i, readfds);
+	    if (type & SELECT_WRITE)
+	      got++;
+	    else if (writefds)
+	      FD_CLR (i, writefds);
+	    if (type & SELECT_URG)
+	      got++;
+	    else if (exceptfds)
+	      FD_CLR (i, exceptfds);
+	  }
+    }
+
+  if (sigmask && __sigprocmask (SIG_SETMASK, &oset, NULL))
+    return -1;
+
+  return got;
+}
diff --git a/REORG.TODO/hurd/hurdsig.c b/REORG.TODO/hurd/hurdsig.c
new file mode 100644
index 0000000000..ec6a6995e6
--- /dev/null
+++ b/REORG.TODO/hurd/hurdsig.c
@@ -0,0 +1,1405 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cthreads.h>		/* For `struct mutex'.  */
+#include <mach.h>
+#include <mach/thread_switch.h>
+
+#include <hurd.h>
+#include <hurd/id.h>
+#include <hurd/signal.h>
+
+#include "hurdfault.h"
+#include "hurdmalloc.h"		/* XXX */
+#include "../locale/localeinfo.h"
+
+const char *_hurdsig_getenv (const char *);
+
+struct mutex _hurd_siglock;
+int _hurd_stopped;
+
+/* Port that receives signals and other miscellaneous messages.  */
+mach_port_t _hurd_msgport;
+
+/* Thread listening on it.  */
+thread_t _hurd_msgport_thread;
+
+/* Thread which receives task-global signals.  */
+thread_t _hurd_sigthread;
+
+/* These are set up by _hurdsig_init.  */
+unsigned long int __hurd_sigthread_stack_base;
+unsigned long int __hurd_sigthread_stack_end;
+unsigned long int *__hurd_sigthread_variables;
+
+/* Linked-list of per-thread signal state.  */
+struct hurd_sigstate *_hurd_sigstates;
+
+/* Timeout for RPC's after interrupt_operation. */
+mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
+
+static void
+default_sigaction (struct sigaction actions[NSIG])
+{
+  int signo;
+
+  __sigemptyset (&actions[0].sa_mask);
+  actions[0].sa_flags = SA_RESTART;
+  actions[0].sa_handler = SIG_DFL;
+
+  for (signo = 1; signo < NSIG; ++signo)
+    actions[signo] = actions[0];
+}
+
+struct hurd_sigstate *
+_hurd_thread_sigstate (thread_t thread)
+{
+  struct hurd_sigstate *ss;
+  __mutex_lock (&_hurd_siglock);
+  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+    if (ss->thread == thread)
+       break;
+  if (ss == NULL)
+    {
+      ss = malloc (sizeof (*ss));
+      if (ss == NULL)
+	__libc_fatal ("hurd: Can't allocate thread sigstate\n");
+      ss->thread = thread;
+      __spin_lock_init (&ss->lock);
+
+      /* Initialize default state.  */
+      __sigemptyset (&ss->blocked);
+      __sigemptyset (&ss->pending);
+      memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
+      ss->preemptors = NULL;
+      ss->suspended = MACH_PORT_NULL;
+      ss->intr_port = MACH_PORT_NULL;
+      ss->context = NULL;
+
+      /* Initialize the sigaction vector from the default signal receiving
+	 thread's state, and its from the system defaults.  */
+      if (thread == _hurd_sigthread)
+	default_sigaction (ss->actions);
+      else
+	{
+	  struct hurd_sigstate *s;
+	  for (s = _hurd_sigstates; s != NULL; s = s->next)
+	    if (s->thread == _hurd_sigthread)
+	      break;
+	  if (s)
+	    {
+	      __spin_lock (&s->lock);
+	      memcpy (ss->actions, s->actions, sizeof (s->actions));
+	      __spin_unlock (&s->lock);
+	    }
+	  else
+	    default_sigaction (ss->actions);
+	}
+
+      ss->next = _hurd_sigstates;
+      _hurd_sigstates = ss;
+    }
+  __mutex_unlock (&_hurd_siglock);
+  return ss;
+}
+
+/* Signal delivery itself is on this page.  */
+
+#include <hurd/fd.h>
+#include <hurd/crash.h>
+#include <hurd/resource.h>
+#include <hurd/paths.h>
+#include <setjmp.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <thread_state.h>
+#include <hurd/msg_server.h>
+#include <hurd/msg_reply.h>	/* For __msg_sig_post_reply.  */
+#include <hurd/interrupt.h>
+#include <assert.h>
+#include <unistd.h>
+
+
+/* Call the crash dump server to mummify us before we die.
+   Returns nonzero if a core file was written.  */
+static int
+write_corefile (int signo, const struct hurd_signal_detail *detail)
+{
+  error_t err;
+  mach_port_t coreserver;
+  file_t file, coredir;
+  const char *name;
+
+  /* Don't bother locking since we just read the one word.  */
+  rlim_t corelimit = _hurd_rlimits[RLIMIT_CORE].rlim_cur;
+
+  if (corelimit == 0)
+    /* No core dumping, thank you very much.  Note that this makes
+       `ulimit -c 0' prevent crash-suspension too, which is probably
+       what the user wanted.  */
+    return 0;
+
+  /* XXX RLIMIT_CORE:
+     When we have a protocol to make the server return an error
+     for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE
+     value in place of the RLIMIT_FSIZE value.  */
+
+  /* First get a port to the core dumping server.  */
+  coreserver = MACH_PORT_NULL;
+  name = _hurdsig_getenv ("CRASHSERVER");
+  if (name != NULL)
+    coreserver = __file_name_lookup (name, 0, 0);
+  if (coreserver == MACH_PORT_NULL)
+    coreserver = __file_name_lookup (_SERVERS_CRASH, 0, 0);
+  if (coreserver == MACH_PORT_NULL)
+    return 0;
+
+  /* Get a port to the directory where the new core file will reside.  */
+  file = MACH_PORT_NULL;
+  name = _hurdsig_getenv ("COREFILE");
+  if (name == NULL)
+    name = "core";
+  coredir = __file_name_split (name, (char **) &name);
+  if (coredir != MACH_PORT_NULL)
+    /* Create the new file, but don't link it into the directory yet.  */
+    __dir_mkfile (coredir, O_WRONLY|O_CREAT,
+		  0600 & ~_hurd_umask, /* XXX ? */
+		  &file);
+
+  /* Call the core dumping server to write the core file.  */
+  err = __crash_dump_task (coreserver,
+			   __mach_task_self (),
+			   file,
+			   signo, detail->code, detail->error,
+			   detail->exc, detail->exc_code, detail->exc_subcode,
+			   _hurd_ports[INIT_PORT_CTTYID].port,
+			   MACH_MSG_TYPE_COPY_SEND);
+  __mach_port_deallocate (__mach_task_self (), coreserver);
+
+  if (! err && file != MACH_PORT_NULL)
+    /* The core dump into FILE succeeded, so now link it into the
+       directory.  */
+    err = __dir_link (coredir, file, name, 1);
+  __mach_port_deallocate (__mach_task_self (), file);
+  __mach_port_deallocate (__mach_task_self (), coredir);
+  return !err && file != MACH_PORT_NULL;
+}
+
+
+/* The lowest-numbered thread state flavor value is 1,
+   so we use bit 0 in machine_thread_all_state.set to
+   record whether we have done thread_abort.  */
+#define THREAD_ABORTED 1
+
+/* SS->thread is suspended.  Abort the thread and get its basic state.  */
+static void
+abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
+	      void (*reply) (void))
+{
+  if (!(state->set & THREAD_ABORTED))
+    {
+      error_t err = __thread_abort (ss->thread);
+      assert_perror (err);
+      /* Clear all thread state flavor set bits, because thread_abort may
+	 have changed the state.  */
+      state->set = THREAD_ABORTED;
+    }
+
+  if (reply)
+    (*reply) ();
+
+  machine_get_basic_state (ss->thread, state);
+}
+
+/* Find the location of the MiG reply port cell in use by the thread whose
+   state is described by THREAD_STATE.  If SIGTHREAD is nonzero, make sure
+   that this location can be set without faulting, or else return NULL.  */
+
+static mach_port_t *
+interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
+				 int sigthread)
+{
+  mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
+    (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
+
+  if (sigthread && _hurdsig_catch_memory_fault (portloc))
+    /* Faulted trying to read the stack.  */
+    return NULL;
+
+  /* Fault now if this pointer is bogus.  */
+  *(volatile mach_port_t *) portloc = *portloc;
+
+  if (sigthread)
+    _hurdsig_end_catch_fault ();
+
+  return portloc;
+}
+
+#include <hurd/sigpreempt.h>
+#include <intr-msg.h>
+
+/* Timeout on interrupt_operation calls.  */
+mach_msg_timeout_t _hurdsig_interrupt_timeout = 1000;
+
+/* SS->thread is suspended.
+
+   Abort any interruptible RPC operation the thread is doing.
+
+   This uses only the constant member SS->thread and the unlocked, atomically
+   set member SS->intr_port, so no locking is needed.
+
+   If successfully sent an interrupt_operation and therefore the thread should
+   wait for its pending RPC to return (possibly EINTR) before taking the
+   incoming signal, returns the reply port to be received on.  Otherwise
+   returns MACH_PORT_NULL.
+
+   SIGNO is used to find the applicable SA_RESTART bit.  If SIGNO is zero,
+   the RPC fails with EINTR instead of restarting (thread_cancel).
+
+   *STATE_CHANGE is set nonzero if STATE->basic was modified and should
+   be applied back to the thread if it might ever run again, else zero.  */
+
+mach_port_t
+_hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
+		     struct machine_thread_all_state *state, int *state_change,
+		     void (*reply) (void))
+{
+  extern const void _hurd_intr_rpc_msg_in_trap;
+  mach_port_t rcv_port = MACH_PORT_NULL;
+  mach_port_t intr_port;
+
+  *state_change = 0;
+
+  intr_port = ss->intr_port;
+  if (intr_port == MACH_PORT_NULL)
+    /* No interruption needs done.  */
+    return MACH_PORT_NULL;
+
+  /* Abort the thread's kernel context, so any pending message send or
+     receive completes immediately or aborts.  */
+  abort_thread (ss, state, reply);
+
+  if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
+    {
+      /* The thread is about to do the RPC, but hasn't yet entered
+	 mach_msg.  Mutate the thread's state so it knows not to try
+	 the RPC.  */
+      INTR_MSG_BACK_OUT (&state->basic);
+      MACHINE_THREAD_STATE_SET_PC (&state->basic,
+				   &_hurd_intr_rpc_msg_in_trap);
+      state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
+      *state_change = 1;
+    }
+  else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
+	   /* The thread was blocked in the system call.  After thread_abort,
+	      the return value register indicates what state the RPC was in
+	      when interrupted.  */
+	   state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
+      {
+	/* The RPC request message was sent and the thread was waiting for
+	   the reply message; now the message receive has been aborted, so
+	   the mach_msg call will return MACH_RCV_INTERRUPTED.  We must tell
+	   the server to interrupt the pending operation.  The thread must
+	   wait for the reply message before running the signal handler (to
+	   guarantee that the operation has finished being interrupted), so
+	   our nonzero return tells the trampoline code to finish the message
+	   receive operation before running the handler.  */
+
+	mach_port_t *reply = interrupted_reply_port_location (state,
+							      sigthread);
+	error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout);
+
+	if (err)
+	  {
+	    if (reply)
+	      {
+		/* The interrupt didn't work.
+		   Destroy the receive right the thread is blocked on.  */
+		__mach_port_destroy (__mach_task_self (), *reply);
+		*reply = MACH_PORT_NULL;
+	      }
+
+	    /* The system call return value register now contains
+	       MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
+	       call.  Since we have just destroyed the receive right, the
+	       retry will fail with MACH_RCV_INVALID_NAME.  Instead, just
+	       change the return value here to EINTR so mach_msg will not
+	       retry and the EINTR error code will propagate up.  */
+	    state->basic.SYSRETURN = EINTR;
+	    *state_change = 1;
+	  }
+	else if (reply)
+	  rcv_port = *reply;
+
+	/* All threads whose RPCs were interrupted by the interrupt_operation
+	   call above will retry their RPCs unless we clear SS->intr_port.
+	   So we clear it for the thread taking a signal when SA_RESTART is
+	   clear, so that its call returns EINTR.  */
+	if (! signo || !(ss->actions[signo].sa_flags & SA_RESTART))
+	  ss->intr_port = MACH_PORT_NULL;
+      }
+
+  return rcv_port;
+}
+
+
+/* Abort the RPCs being run by all threads but this one;
+   all other threads should be suspended.  If LIVE is nonzero, those
+   threads may run again, so they should be adjusted as necessary to be
+   happy when resumed.  STATE is clobbered as a scratch area; its initial
+   contents are ignored, and its contents on return are not useful.  */
+
+static void
+abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
+{
+  /* We can just loop over the sigstates.  Any thread doing something
+     interruptible must have one.  We needn't bother locking because all
+     other threads are stopped.  */
+
+  struct hurd_sigstate *ss;
+  size_t nthreads;
+  mach_port_t *reply_ports;
+
+  /* First loop over the sigstates to count them.
+     We need to know how big a vector we will need for REPLY_PORTS.  */
+  nthreads = 0;
+  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+    ++nthreads;
+
+  reply_ports = alloca (nthreads * sizeof *reply_ports);
+
+  nthreads = 0;
+  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next, ++nthreads)
+    if (ss->thread == _hurd_msgport_thread)
+      reply_ports[nthreads] = MACH_PORT_NULL;
+    else
+      {
+	int state_changed;
+	state->set = 0;		/* Reset scratch area.  */
+
+	/* Abort any operation in progress with interrupt_operation.
+	   Record the reply port the thread is waiting on.
+	   We will wait for all the replies below.  */
+	reply_ports[nthreads] = _hurdsig_abort_rpcs (ss, signo, 1,
+						     state, &state_changed,
+						     NULL);
+	if (live)
+	  {
+	    if (reply_ports[nthreads] != MACH_PORT_NULL)
+	      {
+		/* We will wait for the reply to this RPC below, so the
+		   thread must issue a new RPC rather than waiting for the
+		   reply to the one it sent.  */
+		state->basic.SYSRETURN = EINTR;
+		state_changed = 1;
+	      }
+	    if (state_changed)
+	      /* Aborting the RPC needed to change this thread's state,
+		 and it might ever run again.  So write back its state.  */
+	      __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
+				  (natural_t *) &state->basic,
+				  MACHINE_THREAD_STATE_COUNT);
+	  }
+      }
+
+  /* Wait for replies from all the successfully interrupted RPCs.  */
+  while (nthreads-- > 0)
+    if (reply_ports[nthreads] != MACH_PORT_NULL)
+      {
+	error_t err;
+	mach_msg_header_t head;
+	err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
+			  reply_ports[nthreads],
+			  _hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
+	switch (err)
+	  {
+	  case MACH_RCV_TIMED_OUT:
+	  case MACH_RCV_TOO_LARGE:
+	    break;
+
+	  default:
+	    assert_perror (err);
+	  }
+      }
+}
+
+struct hurd_signal_preemptor *_hurdsig_preemptors = 0;
+sigset_t _hurdsig_preempted_set;
+
+/* XXX temporary to deal with spelling fix */
+weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
+
+/* Mask of stop signals.  */
+#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
+		  sigmask (SIGSTOP) | sigmask (SIGTSTP))
+
+/* Deliver a signal.  SS is not locked.  */
+void
+_hurd_internal_post_signal (struct hurd_sigstate *ss,
+			    int signo, struct hurd_signal_detail *detail,
+			    mach_port_t reply_port,
+			    mach_msg_type_name_t reply_port_type,
+			    int untraced)
+{
+  error_t err;
+  struct machine_thread_all_state thread_state;
+  enum { stop, ignore, core, term, handle } act;
+  sighandler_t handler;
+  sigset_t pending;
+  int ss_suspended;
+
+  /* Reply to this sig_post message.  */
+  __typeof (__msg_sig_post_reply) *reply_rpc
+    = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
+  void reply (void)
+    {
+      error_t err;
+      if (reply_port == MACH_PORT_NULL)
+	return;
+      err = (*reply_rpc) (reply_port, reply_port_type, 0);
+      reply_port = MACH_PORT_NULL;
+      if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port.  */
+	assert_perror (err);
+    }
+
+  /* Mark the signal as pending.  */
+  void mark_pending (void)
+    {
+      __sigaddset (&ss->pending, signo);
+      /* Save the details to be given to the handler when SIGNO is
+	 unblocked.  */
+      ss->pending_data[signo] = *detail;
+    }
+
+  /* Suspend the process with SIGNO.  */
+  void suspend (void)
+    {
+      /* Stop all other threads and mark ourselves stopped.  */
+      __USEPORT (PROC,
+		 ({
+		   /* Hold the siglock while stopping other threads to be
+		      sure it is not held by another thread afterwards.  */
+		   __mutex_lock (&_hurd_siglock);
+		   __proc_dostop (port, _hurd_msgport_thread);
+		   __mutex_unlock (&_hurd_siglock);
+		   abort_all_rpcs (signo, &thread_state, 1);
+		   reply ();
+		   __proc_mark_stop (port, signo, detail->code);
+		 }));
+      _hurd_stopped = 1;
+    }
+  /* Resume the process after a suspension.  */
+  void resume (void)
+    {
+      /* Resume the process from being stopped.  */
+      thread_t *threads;
+      mach_msg_type_number_t nthreads, i;
+      error_t err;
+
+      if (! _hurd_stopped)
+	return;
+
+      /* Tell the proc server we are continuing.  */
+      __USEPORT (PROC, __proc_mark_cont (port));
+      /* Fetch ports to all our threads and resume them.  */
+      err = __task_threads (__mach_task_self (), &threads, &nthreads);
+      assert_perror (err);
+      for (i = 0; i < nthreads; ++i)
+	{
+	  if (threads[i] != _hurd_msgport_thread &&
+	      (act != handle || threads[i] != ss->thread))
+	    {
+	      err = __thread_resume (threads[i]);
+	      assert_perror (err);
+	    }
+	  err = __mach_port_deallocate (__mach_task_self (),
+					threads[i]);
+	  assert_perror (err);
+	}
+      __vm_deallocate (__mach_task_self (),
+		       (vm_address_t) threads,
+		       nthreads * sizeof *threads);
+      _hurd_stopped = 0;
+      if (act == handle)
+	/* The thread that will run the handler is already suspended.  */
+	ss_suspended = 1;
+    }
+
+  if (signo == 0)
+    {
+      if (untraced)
+	/* This is PTRACE_CONTINUE.  */
+	resume ();
+
+      /* This call is just to check for pending signals.  */
+      __spin_lock (&ss->lock);
+      goto check_pending_signals;
+    }
+
+ post_signal:
+
+  thread_state.set = 0;		/* We know nothing.  */
+
+  __spin_lock (&ss->lock);
+
+  /* Check for a preempted signal.  Preempted signals can arrive during
+     critical sections.  */
+  {
+    inline sighandler_t try_preemptor (struct hurd_signal_preemptor *pe)
+      {				/* PE cannot be null.  */
+	do
+	  {
+	    if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
+	      {
+		if (pe->preemptor)
+		  {
+		    sighandler_t handler = (*pe->preemptor) (pe, ss,
+							     &signo, detail);
+		    if (handler != SIG_ERR)
+		      return handler;
+		  }
+		else
+		  return pe->handler;
+	      }
+	    pe = pe->next;
+	  } while (pe != 0);
+	return SIG_ERR;
+      }
+
+    handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
+
+    /* If no thread-specific preemptor, check for a global one.  */
+    if (handler == SIG_ERR && __sigismember (&_hurdsig_preempted_set, signo))
+      {
+	__mutex_lock (&_hurd_siglock);
+	handler = try_preemptor (_hurdsig_preemptors);
+	__mutex_unlock (&_hurd_siglock);
+      }
+  }
+
+  ss_suspended = 0;
+
+  if (handler == SIG_IGN)
+    /* Ignore the signal altogether.  */
+    act = ignore;
+  else if (handler != SIG_ERR)
+    /* Run the preemption-provided handler.  */
+    act = handle;
+  else
+    {
+      /* No preemption.  Do normal handling.  */
+
+      if (!untraced && __sigismember (&_hurdsig_traced, signo))
+	{
+	  /* We are being traced.  Stop to tell the debugger of the signal.  */
+	  if (_hurd_stopped)
+	    /* Already stopped.  Mark the signal as pending;
+	       when resumed, we will notice it and stop again.  */
+	    mark_pending ();
+	  else
+	    suspend ();
+	  __spin_unlock (&ss->lock);
+	  reply ();
+	  return;
+	}
+
+      handler = ss->actions[signo].sa_handler;
+
+      if (handler == SIG_DFL)
+	/* Figure out the default action for this signal.  */
+	switch (signo)
+	  {
+	  case 0:
+	    /* A sig_post msg with SIGNO==0 is sent to
+	       tell us to check for pending signals.  */
+	    act = ignore;
+	    break;
+
+	  case SIGTTIN:
+	  case SIGTTOU:
+	  case SIGSTOP:
+	  case SIGTSTP:
+	    act = stop;
+	    break;
+
+	  case SIGCONT:
+	  case SIGIO:
+	  case SIGURG:
+	  case SIGCHLD:
+	  case SIGWINCH:
+	    act = ignore;
+	    break;
+
+	  case SIGQUIT:
+	  case SIGILL:
+	  case SIGTRAP:
+	  case SIGIOT:
+	  case SIGEMT:
+	  case SIGFPE:
+	  case SIGBUS:
+	  case SIGSEGV:
+	  case SIGSYS:
+	    act = core;
+	    break;
+
+	  case SIGINFO:
+	    if (_hurd_pgrp == _hurd_pid)
+	      {
+		/* We are the process group leader.  Since there is no
+		   user-specified handler for SIGINFO, we use a default one
+		   which prints something interesting.  We use the normal
+		   handler mechanism instead of just doing it here to avoid
+		   the signal thread faulting or blocking in this
+		   potentially hairy operation.  */
+		act = handle;
+		handler = _hurd_siginfo_handler;
+	      }
+	    else
+	      act = ignore;
+	    break;
+
+	  default:
+	    act = term;
+	    break;
+	  }
+      else if (handler == SIG_IGN)
+	act = ignore;
+      else
+	act = handle;
+
+      if (__sigmask (signo) & STOPSIGS)
+	/* Stop signals clear a pending SIGCONT even if they
+	   are handled or ignored (but not if preempted).  */
+	__sigdelset (&ss->pending, SIGCONT);
+      else
+	{
+	  if (signo == SIGCONT)
+	    /* Even if handled or ignored (but not preempted), SIGCONT clears
+	       stop signals and resumes the process.  */
+	    ss->pending &= ~STOPSIGS;
+
+	  if (_hurd_stopped && act != stop && (untraced || signo == SIGCONT))
+	    resume ();
+	}
+    }
+
+  if (_hurd_orphaned && act == stop &&
+      (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |
+			    __sigmask (SIGTSTP))))
+    {
+      /* If we would ordinarily stop for a job control signal, but we are
+	 orphaned so noone would ever notice and continue us again, we just
+	 quietly die, alone and in the dark.  */
+      detail->code = signo;
+      signo = SIGKILL;
+      act = term;
+    }
+
+  /* Handle receipt of a blocked signal, or any signal while stopped.  */
+  if (act != ignore &&		/* Signals ignored now are forgotten now.  */
+      __sigismember (&ss->blocked, signo) ||
+      (signo != SIGKILL && _hurd_stopped))
+    {
+      mark_pending ();
+      act = ignore;
+    }
+
+  /* Perform the chosen action for the signal.  */
+  switch (act)
+    {
+    case stop:
+      if (_hurd_stopped)
+	{
+	  /* We are already stopped, but receiving an untraced stop
+	     signal.  Instead of resuming and suspending again, just
+	     notify the proc server of the new stop signal.  */
+	  error_t err = __USEPORT (PROC, __proc_mark_stop
+				   (port, signo, detail->code));
+	  assert_perror (err);
+	}
+      else
+	/* Suspend the process.  */
+	suspend ();
+      break;
+
+    case ignore:
+      if (detail->exc)
+	/* Blocking or ignoring a machine exception is fatal.
+	   Otherwise we could just spin on the faulting instruction.  */
+	goto fatal;
+
+      /* Nobody cares about this signal.  If there was a call to resume
+	 above in SIGCONT processing and we've left a thread suspended,
+	 now's the time to set it going. */
+      if (ss_suspended)
+	{
+	  err = __thread_resume (ss->thread);
+	  assert_perror (err);
+	  ss_suspended = 0;
+	}
+      break;
+
+    sigbomb:
+      /* We got a fault setting up the stack frame for the handler.
+	 Nothing to do but die; BSD gets SIGILL in this case.  */
+      detail->code = signo;	/* XXX ? */
+      signo = SIGILL;
+
+    fatal:
+      act = core;
+      /* FALLTHROUGH */
+
+    case term:			/* Time to die.  */
+    case core:			/* And leave a rotting corpse.  */
+      /* Have the proc server stop all other threads in our task.  */
+      err = __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread));
+      assert_perror (err);
+      /* No more user instructions will be executed.
+	 The signal can now be considered delivered.  */
+      reply ();
+      /* Abort all server operations now in progress.  */
+      abort_all_rpcs (signo, &thread_state, 0);
+
+      {
+	int status = W_EXITCODE (0, signo);
+	/* Do a core dump if desired.  Only set the wait status bit saying we
+	   in fact dumped core if the operation was actually successful.  */
+	if (act == core && write_corefile (signo, detail))
+	  status |= WCOREFLAG;
+	/* Tell proc how we died and then stick the saber in the gut.  */
+	_hurd_exit (status);
+	/* NOTREACHED */
+      }
+
+    case handle:
+      /* Call a handler for this signal.  */
+      {
+	struct sigcontext *scp, ocontext;
+	int wait_for_reply, state_changed;
+
+	/* Stop the thread and abort its pending RPC operations.  */
+	if (! ss_suspended)
+	  {
+	    err = __thread_suspend (ss->thread);
+	    assert_perror (err);
+	  }
+
+	/* Abort the thread's kernel context, so any pending message send
+	   or receive completes immediately or aborts.  If an interruptible
+	   RPC is in progress, abort_rpcs will do this.  But we must always
+	   do it before fetching the thread's state, because
+	   thread_get_state is never kosher before thread_abort.  */
+	abort_thread (ss, &thread_state, NULL);
+
+	if (ss->context)
+	  {
+	    /* We have a previous sigcontext that sigreturn was about
+	       to restore when another signal arrived.  */
+
+	    mach_port_t *loc;
+
+	    if (_hurdsig_catch_memory_fault (ss->context))
+	      {
+		/* We faulted reading the thread's stack.  Forget that
+		   context and pretend it wasn't there.  It almost
+		   certainly crash if this handler returns, but that's it's
+		   problem.  */
+		ss->context = NULL;
+	      }
+	    else
+	      {
+		/* Copy the context from the thread's stack before
+		   we start diddling the stack to set up the handler.  */
+		ocontext = *ss->context;
+		ss->context = &ocontext;
+	      }
+	    _hurdsig_end_catch_fault ();
+
+	    if (! machine_get_basic_state (ss->thread, &thread_state))
+	      goto sigbomb;
+	    loc = interrupted_reply_port_location (&thread_state, 1);
+	    if (loc && *loc != MACH_PORT_NULL)
+	      /* This is the reply port for the context which called
+		 sigreturn.  Since we are abandoning that context entirely
+		 and restoring SS->context instead, destroy this port.  */
+	      __mach_port_destroy (__mach_task_self (), *loc);
+
+	    /* The thread was in sigreturn, not in any interruptible RPC.  */
+	    wait_for_reply = 0;
+
+	    assert (! __spin_lock_locked (&ss->critical_section_lock));
+	  }
+	else
+	  {
+	    int crit = __spin_lock_locked (&ss->critical_section_lock);
+
+	    wait_for_reply
+	      = (_hurdsig_abort_rpcs (ss,
+				      /* In a critical section, any RPC
+					 should be cancelled instead of
+					 restarted, regardless of
+					 SA_RESTART, so the entire
+					 "atomic" operation can be aborted
+					 as a unit.  */
+				      crit ? 0 : signo, 1,
+				      &thread_state, &state_changed,
+				      &reply)
+		 != MACH_PORT_NULL);
+
+	    if (crit)
+	      {
+		/* The thread is in a critical section.  Mark the signal as
+		   pending.  When it finishes the critical section, it will
+		   check for pending signals.  */
+		mark_pending ();
+		if (state_changed)
+		  /* Some cases of interrupting an RPC must change the
+		     thread state to back out the call.  Normally this
+		     change is rolled into the warping to the handler and
+		     sigreturn, but we are not running the handler now
+		     because the thread is in a critical section.  Instead,
+		     mutate the thread right away for the RPC interruption
+		     and resume it; the RPC will return early so the
+		     critical section can end soon.  */
+		  __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
+				      (natural_t *) &thread_state.basic,
+				      MACHINE_THREAD_STATE_COUNT);
+		/* */
+		ss->intr_port = MACH_PORT_NULL;
+		__thread_resume (ss->thread);
+		break;
+	      }
+	  }
+
+	/* Call the machine-dependent function to set the thread up
+	   to run the signal handler, and preserve its old context.  */
+	scp = _hurd_setup_sighandler (ss, handler, signo, detail,
+				      wait_for_reply, &thread_state);
+	if (scp == NULL)
+	  goto sigbomb;
+
+	/* Set the machine-independent parts of the signal context.  */
+
+	{
+	  /* Fetch the thread variable for the MiG reply port,
+	     and set it to MACH_PORT_NULL.  */
+	  mach_port_t *loc = interrupted_reply_port_location (&thread_state,
+							      1);
+	  if (loc)
+	    {
+	      scp->sc_reply_port = *loc;
+	      *loc = MACH_PORT_NULL;
+	    }
+	  else
+	    scp->sc_reply_port = MACH_PORT_NULL;
+
+	  /* Save the intr_port in use by the interrupted code,
+	     and clear the cell before running the trampoline.  */
+	  scp->sc_intr_port = ss->intr_port;
+	  ss->intr_port = MACH_PORT_NULL;
+
+	  if (ss->context)
+	    {
+	      /* After the handler runs we will restore to the state in
+		 SS->context, not the state of the thread now.  So restore
+		 that context's reply port and intr port.  */
+
+	      scp->sc_reply_port = ss->context->sc_reply_port;
+	      scp->sc_intr_port = ss->context->sc_intr_port;
+
+	      ss->context = NULL;
+	    }
+	}
+
+	/* Backdoor extra argument to signal handler.  */
+	scp->sc_error = detail->error;
+
+	/* Block requested signals while running the handler.  */
+	scp->sc_mask = ss->blocked;
+	__sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
+
+	/* Also block SIGNO unless we're asked not to.  */
+	if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
+	  __sigaddset (&ss->blocked, signo);
+
+	/* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
+           be automatically reset when delivered; the system silently
+           enforces this restriction.  */
+	if (ss->actions[signo].sa_flags & SA_RESETHAND
+	    && signo != SIGILL && signo != SIGTRAP)
+	  ss->actions[signo].sa_handler = SIG_DFL;
+
+	/* Start the thread running the handler (or possibly waiting for an
+	   RPC reply before running the handler).  */
+	err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
+				  (natural_t *) &thread_state.basic,
+				  MACHINE_THREAD_STATE_COUNT);
+	assert_perror (err);
+	err = __thread_resume (ss->thread);
+	assert_perror (err);
+	thread_state.set = 0;	/* Everything we know is now wrong.  */
+	break;
+      }
+    }
+
+  /* The signal has either been ignored or is now being handled.  We can
+     consider it delivered and reply to the killer.  */
+  reply ();
+
+  /* We get here unless the signal was fatal.  We still hold SS->lock.
+     Check for pending signals, and loop to post them.  */
+  {
+    /* Return nonzero if SS has any signals pending we should worry about.
+       We don't worry about any pending signals if we are stopped, nor if
+       SS is in a critical section.  We are guaranteed to get a sig_post
+       message before any of them become deliverable: either the SIGCONT
+       signal, or a sig_post with SIGNO==0 as an explicit poll when the
+       thread finishes its critical section.  */
+    inline int signals_pending (void)
+      {
+	if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
+	  return 0;
+	return pending = ss->pending & ~ss->blocked;
+      }
+
+  check_pending_signals:
+    untraced = 0;
+
+    if (signals_pending ())
+      {
+	for (signo = 1; signo < NSIG; ++signo)
+	  if (__sigismember (&pending, signo))
+	    {
+	    deliver_pending:
+	      __sigdelset (&ss->pending, signo);
+	      *detail = ss->pending_data[signo];
+	      __spin_unlock (&ss->lock);
+	      goto post_signal;
+	    }
+      }
+
+    /* No pending signals left undelivered for this thread.
+       If we were sent signal 0, we need to check for pending
+       signals for all threads.  */
+    if (signo == 0)
+      {
+	__spin_unlock (&ss->lock);
+	__mutex_lock (&_hurd_siglock);
+	for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+	  {
+	    __spin_lock (&ss->lock);
+	    for (signo = 1; signo < NSIG; ++signo)
+	      if (__sigismember (&ss->pending, signo)
+		  && (!__sigismember (&ss->blocked, signo)
+		      /* We "deliver" immediately pending blocked signals whose
+			 action might be to ignore, so that if ignored they are
+			 dropped right away.  */
+		      || ss->actions[signo].sa_handler == SIG_IGN
+		      || ss->actions[signo].sa_handler == SIG_DFL))
+		{
+		  mutex_unlock (&_hurd_siglock);
+		  goto deliver_pending;
+		}
+	    __spin_unlock (&ss->lock);
+	  }
+	__mutex_unlock (&_hurd_siglock);
+      }
+    else
+      {
+	/* No more signals pending; SS->lock is still locked.
+	   Wake up any sigsuspend call that is blocking SS->thread.  */
+	if (ss->suspended != MACH_PORT_NULL)
+	  {
+	    /* There is a sigsuspend waiting.  Tell it to wake up.  */
+	    error_t err;
+	    mach_msg_header_t msg;
+	    msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
+	    msg.msgh_remote_port = ss->suspended;
+	    msg.msgh_local_port = MACH_PORT_NULL;
+	    /* These values do not matter.  */
+	    msg.msgh_id = 8675309; /* Jenny, Jenny.  */
+	    ss->suspended = MACH_PORT_NULL;
+	    err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
+			      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+			      MACH_PORT_NULL);
+	    assert_perror (err);
+	  }
+	__spin_unlock (&ss->lock);
+      }
+  }
+
+  /* All pending signals delivered to all threads.
+     Now we can send the reply message even for signal 0.  */
+  reply ();
+}
+
+/* Decide whether REFPORT enables the sender to send us a SIGNO signal.
+   Returns zero if so, otherwise the error code to return to the sender.  */
+
+static error_t
+signal_allowed (int signo, mach_port_t refport)
+{
+  if (signo < 0 || signo >= NSIG)
+    return EINVAL;
+
+  if (refport == __mach_task_self ())
+    /* Can send any signal.  */
+    goto win;
+
+  /* Avoid needing to check for this below.  */
+  if (refport == MACH_PORT_NULL)
+    return EPERM;
+
+  switch (signo)
+    {
+    case SIGINT:
+    case SIGQUIT:
+    case SIGTSTP:
+    case SIGHUP:
+    case SIGINFO:
+    case SIGTTIN:
+    case SIGTTOU:
+    case SIGWINCH:
+      /* Job control signals can be sent by the controlling terminal.  */
+      if (__USEPORT (CTTYID, port == refport))
+	goto win;
+      break;
+
+    case SIGCONT:
+      {
+	/* A continue signal can be sent by anyone in the session.  */
+	mach_port_t sessport;
+	if (! __USEPORT (PROC, __proc_getsidport (port, &sessport)))
+	  {
+	    __mach_port_deallocate (__mach_task_self (), sessport);
+	    if (refport == sessport)
+	      goto win;
+	  }
+      }
+      break;
+
+    case SIGIO:
+    case SIGURG:
+      {
+	/* Any io object a file descriptor refers to might send us
+	   one of these signals using its async ID port for REFPORT.
+
+	   This is pretty wide open; it is not unlikely that some random
+	   process can at least open for reading something we have open,
+	   get its async ID port, and send us a spurious SIGIO or SIGURG
+	   signal.  But BSD is actually wider open than that!--you can set
+	   the owner of an io object to any process or process group
+	   whatsoever and send them gratuitous signals.
+
+	   Someday we could implement some reasonable scheme for
+	   authorizing SIGIO and SIGURG signals properly.  */
+
+	int d;
+	int lucky = 0;		/* True if we find a match for REFPORT.  */
+	__mutex_lock (&_hurd_dtable_lock);
+	for (d = 0; !lucky && (unsigned) d < (unsigned) _hurd_dtablesize; ++d)
+	  {
+	    struct hurd_userlink ulink;
+	    io_t port;
+	    mach_port_t asyncid;
+	    if (_hurd_dtable[d] == NULL)
+	      continue;
+	    port = _hurd_port_get (&_hurd_dtable[d]->port, &ulink);
+	    if (! __io_get_icky_async_id (port, &asyncid))
+	      {
+		if (refport == asyncid)
+		  /* Break out of the loop on the next iteration.  */
+		  lucky = 1;
+		__mach_port_deallocate (__mach_task_self (), asyncid);
+	      }
+	    _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
+	  }
+	__mutex_unlock (&_hurd_dtable_lock);
+	/* If we found a lucky winner, we've set D to -1 in the loop.  */
+	if (lucky)
+	  goto win;
+      }
+    }
+
+  /* If this signal is legit, we have done `goto win' by now.
+     When we return the error, mig deallocates REFPORT.  */
+  return EPERM;
+
+ win:
+  /* Deallocate the REFPORT send right; we are done with it.  */
+  __mach_port_deallocate (__mach_task_self (), refport);
+
+  return 0;
+}
+
+/* Implement the sig_post RPC from <hurd/msg.defs>;
+   sent when someone wants us to get a signal.  */
+kern_return_t
+_S_msg_sig_post (mach_port_t me,
+		 mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+		 int signo, natural_t sigcode,
+		 mach_port_t refport)
+{
+  error_t err;
+  struct hurd_signal_detail d;
+
+  if (err = signal_allowed (signo, refport))
+    return err;
+
+  d.code = sigcode;
+  d.exc = 0;
+
+  /* Post the signal to the designated signal-receiving thread.  This will
+     reply when the signal can be considered delivered.  */
+  _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
+			      signo, &d, reply_port, reply_port_type,
+			      0); /* Stop if traced.  */
+
+  return MIG_NO_REPLY;		/* Already replied.  */
+}
+
+/* Implement the sig_post_untraced RPC from <hurd/msg.defs>;
+   sent when the debugger wants us to really get a signal
+   even if we are traced.  */
+kern_return_t
+_S_msg_sig_post_untraced (mach_port_t me,
+			  mach_port_t reply_port,
+			  mach_msg_type_name_t reply_port_type,
+			  int signo, natural_t sigcode,
+			  mach_port_t refport)
+{
+  error_t err;
+  struct hurd_signal_detail d;
+
+  if (err = signal_allowed (signo, refport))
+    return err;
+
+  d.code = sigcode;
+  d.exc = 0;
+
+  /* Post the signal to the designated signal-receiving thread.  This will
+     reply when the signal can be considered delivered.  */
+  _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
+			      signo, &d, reply_port, reply_port_type,
+			      1); /* Untraced flag. */
+
+  return MIG_NO_REPLY;		/* Already replied.  */
+}
+
+extern void __mig_init (void *);
+
+#include <mach/task_special_ports.h>
+
+/* Initialize the message port and _hurd_sigthread and start the signal
+   thread.  */
+
+void
+_hurdsig_init (const int *intarray, size_t intarraysize)
+{
+  error_t err;
+  vm_size_t stacksize;
+  struct hurd_sigstate *ss;
+
+  __mutex_init (&_hurd_siglock);
+
+  err = __mach_port_allocate (__mach_task_self (),
+			      MACH_PORT_RIGHT_RECEIVE,
+			      &_hurd_msgport);
+  assert_perror (err);
+
+  /* Make a send right to the signal port.  */
+  err = __mach_port_insert_right (__mach_task_self (),
+				  _hurd_msgport,
+				  _hurd_msgport,
+				  MACH_MSG_TYPE_MAKE_SEND);
+  assert_perror (err);
+
+  /* Initialize the main thread's signal state.  */
+  ss = _hurd_self_sigstate ();
+
+  /* Copy inherited values from our parent (or pre-exec process state)
+     into the signal settings of the main thread.  */
+  if (intarraysize > INIT_SIGMASK)
+    ss->blocked = intarray[INIT_SIGMASK];
+  if (intarraysize > INIT_SIGPENDING)
+    ss->pending = intarray[INIT_SIGPENDING];
+  if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
+    {
+      int signo;
+      for (signo = 1; signo < NSIG; ++signo)
+	if (intarray[INIT_SIGIGN] & __sigmask(signo))
+	  ss->actions[signo].sa_handler = SIG_IGN;
+    }
+
+  /* Set the default thread to receive task-global signals
+     to this one, the main (first) user thread.  */
+  _hurd_sigthread = ss->thread;
+
+  /* Start the signal thread listening on the message port.  */
+
+  if (__hurd_threadvar_stack_mask == 0)
+    {
+      err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
+      assert_perror (err);
+
+      stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
+      err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
+				 _hurd_msgport_receive,
+				 (vm_address_t *) &__hurd_sigthread_stack_base,
+				 &stacksize);
+      assert_perror (err);
+
+      __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
+      __hurd_sigthread_variables =
+	malloc (__hurd_threadvar_max * sizeof (unsigned long int));
+      if (__hurd_sigthread_variables == NULL)
+	__libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
+      memset (__hurd_sigthread_variables, 0,
+	      __hurd_threadvar_max * sizeof (unsigned long int));
+      __hurd_sigthread_variables[_HURD_THREADVAR_LOCALE]
+	= (unsigned long int) &_nl_global_locale;
+
+      /* Reinitialize the MiG support routines so they will use a per-thread
+	 variable for the cached reply port.  */
+      __mig_init ((void *) __hurd_sigthread_stack_base);
+
+      err = __thread_resume (_hurd_msgport_thread);
+      assert_perror (err);
+    }
+  else
+    {
+      /* When cthreads is being used, we need to make the signal thread a
+         proper cthread.  Otherwise it cannot use mutex_lock et al, which
+         will be the cthreads versions.  Various of the message port RPC
+         handlers need to take locks, so we need to be able to call into
+         cthreads code and meet its assumptions about how our thread and
+         its stack are arranged.  Since cthreads puts it there anyway,
+         we'll let the signal thread's per-thread variables be found as for
+         any normal cthread, and just leave the magic __hurd_sigthread_*
+         values all zero so they'll be ignored.  */
+#pragma weak cthread_fork
+#pragma weak cthread_detach
+      cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
+
+      /* XXX We need the thread port for the signal thread further on
+         in this thread (see hurdfault.c:_hurdsigfault_init).
+         Therefore we block until _hurd_msgport_thread is initialized
+         by the newly created thread.  This really shouldn't be
+         necessary; we should be able to fetch the thread port for a
+         cthread from here.  */
+      while (_hurd_msgport_thread == 0)
+	__swtch_pri (0);
+    }
+
+  /* Receive exceptions on the signal port.  */
+#ifdef TASK_EXCEPTION_PORT
+  __task_set_special_port (__mach_task_self (),
+			   TASK_EXCEPTION_PORT, _hurd_msgport);
+#elif defined (EXC_MASK_ALL)
+  __task_set_exception_ports (__mach_task_self (),
+			      EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
+					       | EXC_MASK_MACH_SYSCALL
+					       | EXC_MASK_RPC_ALERT),
+			      _hurd_msgport,
+			      EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
+#else
+# error task_set_exception_port?
+#endif
+
+  /* Sanity check.  Any pending, unblocked signals should have been
+     taken by our predecessor incarnation (i.e. parent or pre-exec state)
+     before packing up our init ints.  This assert is last (not above)
+     so that signal handling is all set up to handle the abort.  */
+  assert ((ss->pending &~ ss->blocked) == 0);
+}
+				/* XXXX */
+/* Reauthenticate with the proc server.  */
+
+static void
+reauth_proc (mach_port_t new)
+{
+  mach_port_t ref, ignore;
+
+  ref = __mach_reply_port ();
+  if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
+		       __proc_reauthenticate (port, ref,
+					      MACH_MSG_TYPE_MAKE_SEND) ||
+		       __auth_user_authenticate (new, ref,
+						 MACH_MSG_TYPE_MAKE_SEND,
+						 &ignore))
+      && ignore != MACH_PORT_NULL)
+    __mach_port_deallocate (__mach_task_self (), ignore);
+  __mach_port_destroy (__mach_task_self (), ref);
+
+  /* Set the owner of the process here too. */
+  mutex_lock (&_hurd_id.lock);
+  if (!_hurd_check_ids ())
+    HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
+		   __proc_setowner (port,
+				    (_hurd_id.gen.nuids
+				     ? _hurd_id.gen.uids[0] : 0),
+				    !_hurd_id.gen.nuids));
+  mutex_unlock (&_hurd_id.lock);
+
+  (void) &reauth_proc;		/* Silence compiler warning.  */
+}
+text_set_element (_hurd_reauth_hook, reauth_proc);
+
+/* Like `getenv', but safe for the signal thread to run.
+   If the environment is trashed, this will just return NULL.  */
+
+const char *
+_hurdsig_getenv (const char *variable)
+{
+  if (__libc_enable_secure)
+    return NULL;
+
+  if (_hurdsig_catch_memory_fault (__environ))
+    /* We bombed in getenv.  */
+    return NULL;
+  else
+    {
+      const size_t len = strlen (variable);
+      char *value = NULL;
+      char *volatile *ep = __environ;
+      while (*ep)
+	{
+	  const char *p = *ep;
+	  _hurdsig_fault_preemptor.first = (long int) p;
+	  _hurdsig_fault_preemptor.last = VM_MAX_ADDRESS;
+	  if (! strncmp (p, variable, len) && p[len] == '=')
+	    {
+	      size_t valuelen;
+	      p += len + 1;
+	      valuelen = strlen (p);
+	      _hurdsig_fault_preemptor.last = (long int) (p + valuelen);
+	      value = malloc (++valuelen);
+	      if (value)
+		memcpy (value, p, valuelen);
+	      break;
+	    }
+	  _hurdsig_fault_preemptor.first = (long int) ++ep;
+	  _hurdsig_fault_preemptor.last = (long int) (ep + 1);
+	}
+      _hurdsig_end_catch_fault ();
+      return value;
+    }
+}
diff --git a/REORG.TODO/hurd/hurdsock.c b/REORG.TODO/hurd/hurdsock.c
new file mode 100644
index 0000000000..de4158def8
--- /dev/null
+++ b/REORG.TODO/hurd/hurdsock.c
@@ -0,0 +1,120 @@
+/* _hurd_socket_server - Find the server for a socket domain.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hurd/paths.h>
+#include <stdio.h>
+#include <_itoa.h>
+#include <cthreads.h>		/* For `struct mutex'.  */
+#include "hurdmalloc.h"		/* XXX */
+
+static struct mutex lock;
+
+static file_t *servers;
+static int max_domain = -1;
+
+/* Return a port to the socket server for DOMAIN.
+   Socket servers translate nodes in the directory _SERVERS_SOCKET
+   (canonically /servers/socket).  These naming point nodes are named
+   by the simplest decimal representation of the socket domain number,
+   for example "/servers/socket/3".
+
+   Socket servers are assumed not to change very often.
+   The library keeps all the server socket ports it has ever looked up,
+   and does not look them up in /servers/socket more than once.  */
+
+socket_t
+_hurd_socket_server (int domain, int dead)
+{
+  socket_t server;
+
+  if (domain < 0)
+    {
+      errno = EAFNOSUPPORT;
+      return MACH_PORT_NULL;
+    }
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&lock);
+
+  if (domain > max_domain)
+    {
+      error_t save = errno;
+      file_t *new = realloc (servers, (domain + 1) * sizeof (file_t));
+      if (new != NULL)
+	{
+	  do
+	    new[++max_domain] = MACH_PORT_NULL;
+	  while (max_domain < domain);
+	  servers = new;
+	}
+      else
+	/* No space to cache the port; we will just fetch it anew below.  */
+	errno = save;
+    }
+
+  if (dead && domain <= max_domain)
+    {
+      /* The user says the port we returned earlier (now in SERVERS[DOMAIN])
+	 was dead.  Clear the cache and fetch a new one below.  */
+      __mach_port_deallocate (__mach_task_self (), servers[domain]);
+      servers[domain] = MACH_PORT_NULL;
+    }
+
+  if (domain > max_domain || servers[domain] == MACH_PORT_NULL)
+    {
+      char name[sizeof (_SERVERS_SOCKET) + 100];
+      char *np = &name[sizeof (name)];
+      *--np = '\0';
+      np = _itoa (domain, np, 10, 0);
+      *--np = '/';
+      np -= sizeof (_SERVERS_SOCKET) - 1;
+      memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1);
+      server = __file_name_lookup (np, 0, 0);
+      if (domain <= max_domain)
+	servers[domain] = server;
+    }
+  else
+    server = servers[domain];
+
+  if (server == MACH_PORT_NULL && errno == ENOENT)
+    /* If the server node is absent, we don't support that protocol.  */
+    errno = EAFNOSUPPORT;
+
+  __mutex_unlock (&lock);
+  HURD_CRITICAL_END;
+
+  return server;
+}
+
+static void
+init (void)
+{
+  int i;
+
+  __mutex_init (&lock);
+
+  for (i = 0; i < max_domain; ++i)
+    servers[i] = MACH_PORT_NULL;
+
+  (void) &init;			/* Avoid "defined but not used" warning.  */
+}
+text_set_element (_hurd_preinit_hook, init);
diff --git a/REORG.TODO/hurd/hurdsocket.h b/REORG.TODO/hurd/hurdsocket.h
new file mode 100644
index 0000000000..de2111b751
--- /dev/null
+++ b/REORG.TODO/hurd/hurdsocket.h
@@ -0,0 +1,30 @@
+/* Hurd-specific socket functions
+   Copyright (C) 2013-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURD_HURDSOCKET_H
+#define _HURD_HURDSOCKET_H
+
+#include <string.h>
+
+/* Returns a duplicate of ADDR->sun_path with LEN limitation.  This
+   should to be used whenever reading a unix socket address, to cope with
+   sun_path possibly not including a trailing \0.  */
+#define _hurd_sun_path_dupa(addr, len) \
+  strndupa ((addr)->sun_path, (len) - offsetof (struct sockaddr_un, sun_path))
+
+#endif /* hurdsocket.h */
diff --git a/REORG.TODO/hurd/hurdstartup.c b/REORG.TODO/hurd/hurdstartup.c
new file mode 100644
index 0000000000..d057ce1b18
--- /dev/null
+++ b/REORG.TODO/hurd/hurdstartup.c
@@ -0,0 +1,194 @@
+/* Initial program startup for running under the GNU Hurd.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/exec_startup.h>
+#include <sysdep.h>
+#include <hurd/threadvar.h>
+#include <unistd.h>
+#include <elf.h>
+#include <set-hooks.h>
+#include "hurdstartup.h"
+#include <argz.h>
+
+mach_port_t *_hurd_init_dtable;
+mach_msg_type_number_t _hurd_init_dtablesize;
+
+extern void __mach_init (void);
+
+/* Entry point.  This is the first thing in the text segment.
+
+   The exec server started the initial thread in our task with this spot the
+   PC, and a stack that is presumably big enough.  We do basic Mach
+   initialization so mig-generated stubs work, and then do an exec_startup
+   RPC on our bootstrap port, to which the exec server responds with the
+   information passed in the exec call, as well as our original bootstrap
+   port, and the base address and size of the preallocated stack.
+
+   If using cthreads, we are given a new stack by cthreads initialization and
+   deallocate the stack set up by the exec server.  On the new stack we call
+   `start1' (above) to do the rest of the startup work.  Since the stack may
+   disappear out from under us in a machine-dependent way, we use a pile of
+   static variables to communicate the information from exec_startup to start1.
+   This is unfortunate but preferable to machine-dependent frobnication to copy
+   the state from the old stack to the new one.  */
+
+
+void
+_hurd_startup (void **argptr, void (*main) (intptr_t *data))
+{
+  error_t err;
+  mach_port_t in_bootstrap;
+  char *args, *env;
+  mach_msg_type_number_t argslen, envlen;
+  struct hurd_startup_data data;
+  char **argv, **envp;
+  int argc, envc;
+  intptr_t *argcptr;
+  vm_address_t addr;
+
+  /* Attempt to map page zero redzoned before we receive any RPC
+     data that might get allocated there.  We can ignore errors.  */
+  addr = 0;
+  __vm_map (__mach_task_self (),
+	    &addr, __vm_page_size, 0, 0, MACH_PORT_NULL, 0, 1,
+	    VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
+
+  if (err = __task_get_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT,
+				     &in_bootstrap))
+    LOSE;
+
+  if (in_bootstrap != MACH_PORT_NULL)
+    {
+      /* Call the exec server on our bootstrap port and
+	 get all our standard information from it.  */
+
+      argslen = envlen = 0;
+      data.dtablesize = data.portarraysize = data.intarraysize = 0;
+
+      err = __exec_startup_get_info (in_bootstrap,
+				     &data.user_entry,
+				     &data.phdr, &data.phdrsz,
+				     &data.stack_base, &data.stack_size,
+				     &data.flags,
+				     &args, &argslen,
+				     &env, &envlen,
+				     &data.dtable, &data.dtablesize,
+				     &data.portarray, &data.portarraysize,
+				     &data.intarray, &data.intarraysize);
+      __mach_port_deallocate (__mach_task_self (), in_bootstrap);
+    }
+
+  if (err || in_bootstrap == MACH_PORT_NULL || (data.flags & EXEC_STACK_ARGS))
+    {
+      /* Either we have no bootstrap port, or the RPC to the exec server
+	 failed, or whoever started us up passed the flag saying args are
+	 on the stack.  Try to snarf the args in the canonical Mach way.
+	 Hopefully either they will be on the stack as expected, or the
+	 stack will be zeros so we don't crash.  */
+
+      argcptr = (intptr_t *) argptr;
+      argc = argcptr[0];
+      argv = (char **) &argcptr[1];
+      envp = &argv[argc + 1];
+      envc = 0;
+      while (envp[envc])
+	++envc;
+    }
+  else
+    {
+      /* Turn the block of null-separated strings we were passed for the
+	 arguments and environment into vectors of pointers to strings.  */
+
+      /* Count up the arguments so we can allocate ARGV.  */
+      argc = __argz_count (args, argslen);
+      /* Count up the environment variables so we can allocate ENVP.  */
+      envc = __argz_count (env, envlen);
+
+      /* There were some arguments.  Allocate space for the vectors of
+	 pointers and fill them in.  We allocate the space for the
+	 environment pointers immediately after the argv pointers because
+	 the ELF ABI will expect it.  */
+      argcptr = __alloca (sizeof (intptr_t) +
+			  (argc + 1 + envc + 1) * sizeof (char *) +
+			  sizeof (struct hurd_startup_data));
+      *argcptr = argc;
+      argv = (void *) (argcptr + 1);
+      __argz_extract (args, argslen, argv);
+
+      /* There was some environment.  */
+      envp = &argv[argc + 1];
+      __argz_extract (env, envlen, envp);
+    }
+
+  if (err || in_bootstrap == MACH_PORT_NULL)
+    {
+      /* Either we have no bootstrap port, or the RPC to the exec server
+	 failed.  Set all our other variables to have empty information.  */
+
+      data.flags = 0;
+      args = env = NULL;
+      argslen = envlen = 0;
+      data.dtable = NULL;
+      data.dtablesize = 0;
+      data.portarray = NULL;
+      data.portarraysize = 0;
+      data.intarray = NULL;
+      data.intarraysize = 0;
+    }
+  else if ((void *) &envp[envc + 1] == argv[0])
+    {
+      /* The arguments arrived on the stack from the kernel, but our
+	 protocol requires some space after them for a `struct
+	 hurd_startup_data'.  Move them.  */
+      struct
+	{
+	  intptr_t count;
+	  char *argv[argc + 1];
+	  char *envp[envc + 1];
+	  struct hurd_startup_data data;
+	} *args = alloca (sizeof *args);
+      if ((void *) &args[1] == (void *) argcptr)
+	args = alloca (-((char *) &args->data - (char *) args));
+      memmove (args, argcptr, (char *) &args->data - (char *) args);
+      argcptr = (void *) args;
+      argv = args->argv;
+      envp = args->envp;
+    }
+
+  {
+    struct hurd_startup_data *d = (void *) &envp[envc + 1];
+
+    if ((void *) d != argv[0])
+      {
+	*d = data;
+	_hurd_init_dtable = d->dtable;
+	_hurd_init_dtablesize = d->dtablesize;
+      }
+
+    (*main) (argcptr);
+  }
+
+  /* Should never get here.  */
+  LOSE;
+  abort ();
+}
diff --git a/REORG.TODO/hurd/hurdstartup.h b/REORG.TODO/hurd/hurdstartup.h
new file mode 100644
index 0000000000..f0d82d96a5
--- /dev/null
+++ b/REORG.TODO/hurd/hurdstartup.h
@@ -0,0 +1,63 @@
+/* Data from initial program startup for running under the GNU Hurd.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURDSTARTUP_H
+#define _HURDSTARTUP_H 1
+
+# include <stdint.h>
+
+/* Interesting data saved from the exec_startup reply.
+   The DATA argument to *MAIN (see below) points to:
+
+    int argc;
+    char *argv[argc];
+    char *argv_terminator = NULL;
+    char *envp[?];
+    char *envp_terminator = NULL;
+    struct hurd_startup_data data;
+
+*/
+
+struct hurd_startup_data
+  {
+    int flags;
+    mach_port_t *dtable;
+    mach_msg_type_number_t dtablesize;
+    mach_port_t *portarray;
+    mach_msg_type_number_t portarraysize;
+    int *intarray;
+    mach_msg_type_number_t intarraysize;
+    vm_address_t stack_base;
+    vm_size_t stack_size;
+    vm_address_t phdr;
+    vm_size_t phdrsz;
+    vm_address_t user_entry;
+  };
+
+
+/* Initialize Mach RPCs; do initial handshake with the exec server (or
+   extract the arguments from the stack in the case of the bootstrap task);
+   finally, call *MAIN with the information gleaned.  That function is not
+   expected to return.  ARGPTR should be the address of the first argument
+   of the entry point function that is called with the stack exactly as the
+   exec server or kernel sets it.  */
+
+extern void _hurd_startup (void **argptr, void (*main) (intptr_t *data));
+
+
+#endif	/* hurdstartup.h */
diff --git a/REORG.TODO/hurd/intern-fd.c b/REORG.TODO/hurd/intern-fd.c
new file mode 100644
index 0000000000..7e49028659
--- /dev/null
+++ b/REORG.TODO/hurd/intern-fd.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/fd.h>
+
+/* Allocate a new file descriptor and install PORT in it.  FLAGS are as for
+   `open'; only O_IGNORE_CTTY and O_CLOEXEC are meaningful.
+
+   If the descriptor table is full, set errno, and return -1.
+   If DEALLOC is nonzero, deallocate PORT first.  */
+int
+_hurd_intern_fd (io_t port, int flags, int dealloc)
+{
+  int fd;
+  struct hurd_fd *d;
+
+  HURD_CRITICAL_BEGIN;
+  d = _hurd_alloc_fd (&fd, 0);
+  if (d != NULL)
+    {
+      _hurd_port2fd (d, port, flags);
+      __spin_unlock (&d->port.lock);
+    }
+  HURD_CRITICAL_END;
+
+  if (d == NULL)
+    {
+      if (dealloc)
+	__mach_port_deallocate (__mach_task_self (), port);
+      return -1;
+    }
+
+  return fd;
+}
diff --git a/REORG.TODO/hurd/intr-msg.c b/REORG.TODO/hurd/intr-msg.c
new file mode 100644
index 0000000000..636bd7b68d
--- /dev/null
+++ b/REORG.TODO/hurd/intr-msg.c
@@ -0,0 +1,424 @@
+/* Replacement for mach_msg used in interruptible Hurd RPCs.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <mach.h>
+#include <mach/mig_errors.h>
+#include <mach/mig_support.h>
+#include <hurd/signal.h>
+#include <assert.h>
+
+#include "intr-msg.h"
+
+#ifdef NDR_CHAR_ASCII		/* OSF Mach flavors have different names.  */
+# define mig_reply_header_t	mig_reply_error_t
+#endif
+
+error_t
+_hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
+			 mach_msg_option_t option,
+			 mach_msg_size_t send_size,
+			 mach_msg_size_t rcv_size,
+			 mach_port_t rcv_name,
+			 mach_msg_timeout_t timeout,
+			 mach_port_t notify)
+{
+  error_t err;
+  struct hurd_sigstate *ss;
+  const mach_msg_option_t user_option = option;
+  const mach_msg_timeout_t user_timeout = timeout;
+
+  struct clobber
+  {
+#ifdef NDR_CHAR_ASCII
+    NDR_record_t ndr;
+#else
+    mach_msg_type_t type;
+#endif
+    error_t err;
+  };
+  union msg
+  {
+    mach_msg_header_t header;
+    mig_reply_header_t reply;
+    struct
+    {
+      mach_msg_header_t header;
+#ifdef NDR_CHAR_ASCII
+      NDR_record_t ndr;
+#else
+      int type;
+#endif
+      int code;
+    } check;
+    struct
+    {
+      mach_msg_header_t header;
+      struct clobber data;
+    } request;
+  };
+  union msg *const m = (void *) msg;
+  mach_msg_bits_t msgh_bits;
+  mach_port_t remote_port;
+  mach_msg_id_t msgid;
+  struct clobber save_data;
+
+  if ((option & (MACH_SEND_MSG|MACH_RCV_MSG)) != (MACH_SEND_MSG|MACH_RCV_MSG)
+      || _hurd_msgport_thread == MACH_PORT_NULL)
+    {
+      /* Either this is not an RPC (i.e., only a send or only a receive),
+	 so it can't be interruptible; or, the signal thread is not set up
+	 yet, so we cannot do the normal signal magic.  Do a normal,
+	 uninterruptible mach_msg call instead.  */
+      return __mach_msg (&m->header, option, send_size, rcv_size, rcv_name,
+			 timeout, notify);
+    }
+
+  ss = _hurd_self_sigstate ();
+
+  /* Save state that gets clobbered by an EINTR reply message.
+     We will need to restore it if we want to retry the RPC.  */
+  msgh_bits = m->header.msgh_bits;
+  remote_port = m->header.msgh_remote_port;
+  msgid = m->header.msgh_id;
+  assert (rcv_size >= sizeof m->request);
+  save_data = m->request.data;
+
+  /* Tell the signal thread that we are doing an interruptible RPC on
+     this port.  If we get a signal and should return EINTR, the signal
+     thread will set this variable to MACH_PORT_NULL.  The RPC might
+     return EINTR when some other thread gets a signal, in which case we
+     want to restart our call.  */
+  ss->intr_port = m->header.msgh_remote_port;
+
+  /* A signal may arrive here, after intr_port is set, but before the
+     mach_msg system call.  The signal handler might do an interruptible
+     RPC, and clobber intr_port; then it would not be set properly when we
+     actually did send the RPC, and a later signal wouldn't interrupt that
+     RPC.  So, _hurd_setup_sighandler saves intr_port in the sigcontext,
+     and sigreturn restores it.  */
+
+ message:
+
+  /* XXX
+     At all points here (once SS->intr_port is set), the signal thread
+     thinks we are "about to enter the syscall", and might mutate our
+     return-value register.  This is bogus.
+   */
+
+  if (ss->cancel)
+    {
+      /* We have been cancelled.  Don't do an RPC at all.  */
+      ss->intr_port = MACH_PORT_NULL;
+      ss->cancel = 0;
+      return EINTR;
+    }
+
+  /* Note that the signal trampoline code might modify our OPTION!  */
+  err = INTR_MSG_TRAP (msg, option, send_size,
+		       rcv_size, rcv_name, timeout, notify);
+
+  switch (err)
+    {
+    case MACH_RCV_TIMED_OUT:
+      if (user_option & MACH_RCV_TIMEOUT)
+	/* The real user RPC timed out.  */
+	break;
+      else
+	/* The operation was supposedly interrupted, but still has
+	   not returned.  Declare it interrupted.  */
+	goto interrupted;
+
+    case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
+      if (!(option & MACH_SEND_MSG))
+	{
+	  /* Oh yes, it did!  Since we were not doing a message send,
+	     this return code cannot have come from the kernel!
+	     Instead, it was the signal thread mutating our state to tell
+	     us not to enter this RPC.  However, we are already in the receive!
+	     Since the signal thread thought we weren't in the RPC yet,
+	     it didn't do an interrupt_operation.
+	     XXX */
+	  goto retry_receive;
+	}
+      /* FALLTHROUGH */
+
+      /* These are the other codes that mean a pseudo-receive modified
+	 the message buffer and we might need to clean up the port rights.  */
+    case MACH_SEND_TIMED_OUT:
+    case MACH_SEND_INVALID_NOTIFY:
+#ifdef MACH_SEND_NO_NOTIFY
+    case MACH_SEND_NO_NOTIFY:
+#endif
+#ifdef MACH_SEND_NOTIFY_IN_PROGRESS
+    case MACH_SEND_NOTIFY_IN_PROGRESS:
+#endif
+      if (MACH_MSGH_BITS_REMOTE (msg->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND)
+	{
+	  __mach_port_deallocate (__mach_task_self (), msg->msgh_remote_port);
+	  msg->msgh_bits
+	    = (MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
+			       MACH_MSGH_BITS_LOCAL (msg->msgh_bits))
+	       | MACH_MSGH_BITS_OTHER (msg->msgh_bits));
+	}
+      if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+	{
+#ifndef MACH_MSG_PORT_DESCRIPTOR
+	  /* Check for MOVE_SEND rights in the message.  These hold refs
+	     that we need to release in case the message is in fact never
+	     re-sent later.  Since it might in fact be re-sent, we turn
+	     these into COPY_SEND's after deallocating the extra user ref;
+	     the caller is responsible for still holding a ref to go with
+	     the original COPY_SEND right, so the resend copies it again.  */
+
+	  mach_msg_type_long_t *ty = (void *) (msg + 1);
+	  while ((void *) ty < (void *) msg + msg->msgh_size)
+	    {
+	      mach_msg_type_name_t name;
+	      mach_msg_type_size_t size;
+	      mach_msg_type_number_t number;
+
+	      inline void clean_ports (mach_port_t *ports, int dealloc)
+		{
+		  mach_msg_type_number_t i;
+		  switch (name)
+		    {
+		    case MACH_MSG_TYPE_MOVE_SEND:
+		      for (i = 0; i < number; i++)
+			__mach_port_deallocate (__mach_task_self (), *ports++);
+		      if (ty->msgtl_header.msgt_longform)
+			ty->msgtl_name = MACH_MSG_TYPE_COPY_SEND;
+		      else
+			ty->msgtl_header.msgt_name = MACH_MSG_TYPE_COPY_SEND;
+		      break;
+		    case MACH_MSG_TYPE_COPY_SEND:
+		    case MACH_MSG_TYPE_MOVE_RECEIVE:
+		      break;
+		    default:
+		      if (MACH_MSG_TYPE_PORT_ANY (name))
+			assert (! "unexpected port type in interruptible RPC");
+		    }
+		  if (dealloc)
+		    __vm_deallocate (__mach_task_self (),
+				     (vm_address_t) ports,
+				     number * sizeof (mach_port_t));
+		}
+
+	      if (ty->msgtl_header.msgt_longform)
+		{
+		  name = ty->msgtl_name;
+		  size = ty->msgtl_size;
+		  number = ty->msgtl_number;
+		  ty = (void *) ty + sizeof (mach_msg_type_long_t);
+		}
+	      else
+		{
+		  name = ty->msgtl_header.msgt_name;
+		  size = ty->msgtl_header.msgt_size;
+		  number = ty->msgtl_header.msgt_number;
+		  ty = (void *) ty + sizeof (mach_msg_type_t);
+		}
+
+	      if (ty->msgtl_header.msgt_inline)
+		{
+		  clean_ports ((void *) ty, 0);
+		  /* calculate length of data in bytes, rounding up */
+		  ty = (void *) ty + (((((number * size) + 7) >> 3)
+				       + sizeof (mach_msg_type_t) - 1)
+				      &~ (sizeof (mach_msg_type_t) - 1));
+		}
+	      else
+		{
+		  clean_ports (*(void **) ty,
+			       ty->msgtl_header.msgt_deallocate);
+		  ty = (void *) ty + sizeof (void *);
+		}
+	    }
+#else  /* Untyped Mach IPC flavor. */
+	  mach_msg_body_t *body = (void *) (msg + 1);
+	  mach_msg_descriptor_t *desc = (void *) (body + 1);
+	  mach_msg_descriptor_t *desc_end = desc + body->msgh_descriptor_count;
+	  for (; desc < desc_end; ++desc)
+	    switch (desc->type.type)
+	      {
+	      case MACH_MSG_PORT_DESCRIPTOR:
+		switch (desc->port.disposition)
+		  {
+		  case MACH_MSG_TYPE_MOVE_SEND:
+		    __mach_port_deallocate (mach_task_self (),
+					    desc->port.name);
+		    desc->port.disposition = MACH_MSG_TYPE_COPY_SEND;
+		    break;
+		  case MACH_MSG_TYPE_COPY_SEND:
+		  case MACH_MSG_TYPE_MOVE_RECEIVE:
+		    break;
+		  default:
+		    assert (! "unexpected port type in interruptible RPC");
+		  }
+		break;
+	      case MACH_MSG_OOL_DESCRIPTOR:
+		if (desc->out_of_line.deallocate)
+		  __vm_deallocate (__mach_task_self (),
+				   (vm_address_t) desc->out_of_line.address,
+				   desc->out_of_line.size);
+		break;
+	      case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+		switch (desc->ool_ports.disposition)
+		  {
+		  case MACH_MSG_TYPE_MOVE_SEND:
+		    {
+		      mach_msg_size_t i;
+		      const mach_port_t *ports = desc->ool_ports.address;
+		      for (i = 0; i < desc->ool_ports.count; ++i)
+			__mach_port_deallocate (__mach_task_self (), ports[i]);
+		      desc->ool_ports.disposition = MACH_MSG_TYPE_COPY_SEND;
+		      break;
+		    }
+		  case MACH_MSG_TYPE_COPY_SEND:
+		  case MACH_MSG_TYPE_MOVE_RECEIVE:
+		    break;
+		  default:
+		    assert (! "unexpected port type in interruptible RPC");
+		  }
+		if (desc->ool_ports.deallocate)
+		  __vm_deallocate (__mach_task_self (),
+				   (vm_address_t) desc->ool_ports.address,
+				   desc->ool_ports.count
+				   * sizeof (mach_port_t));
+		break;
+	      default:
+		assert (! "unexpected descriptor type in interruptible RPC");
+	      }
+#endif
+	}
+      break;
+
+    case EINTR:
+      /* Either the process was stopped and continued,
+	 or the server doesn't support interrupt_operation.  */
+      if (ss->intr_port != MACH_PORT_NULL)
+	/* If this signal was for us and it should interrupt calls, the
+	   signal thread will have cleared SS->intr_port.
+	   Since it's not cleared, the signal was for another thread,
+	   or SA_RESTART is set.  Restart the interrupted call.  */
+	{
+	  /* Make sure we have a valid reply port.  The one we were using
+	     may have been destroyed by interruption.  */
+	  m->header.msgh_local_port = rcv_name = __mig_get_reply_port ();
+	  m->header.msgh_bits = msgh_bits;
+	  option = user_option;
+	  timeout = user_timeout;
+	  goto message;
+	}
+      /* FALLTHROUGH */
+
+    case MACH_RCV_PORT_DIED:
+      /* Server didn't respond to interrupt_operation,
+	 so the signal thread destroyed the reply port.  */
+      /* FALLTHROUGH */
+
+    interrupted:
+      err = EINTR;
+
+      /* The EINTR return indicates cancellation, so clear the flag.  */
+      ss->cancel = 0;
+      break;
+
+    case MACH_RCV_INTERRUPTED:	/* RPC sent; no reply.  */
+      option &= ~MACH_SEND_MSG;	/* Don't send again.  */
+    retry_receive:
+      if (ss->intr_port == MACH_PORT_NULL)
+	{
+	  /* This signal or cancellation was for us.  We need to wait for
+             the reply, but not hang forever.  */
+	  option |= MACH_RCV_TIMEOUT;
+	  /* Never decrease the user's timeout.  */
+	  if (!(user_option & MACH_RCV_TIMEOUT)
+	      || timeout > _hurd_interrupted_rpc_timeout)
+	    timeout = _hurd_interrupted_rpc_timeout;
+	}
+      else
+	{
+	  option = user_option;
+	  timeout = user_timeout;
+	}
+      goto message;		/* Retry the receive.  */
+
+    case MACH_MSG_SUCCESS:
+      {
+	/* We got a reply.  Was it EINTR?  */
+#ifdef MACH_MSG_TYPE_BIT
+	const union
+	{
+	  mach_msg_type_t t;
+	  int i;
+	} check =
+	  { t: { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8,
+		 1, TRUE, FALSE, FALSE, 0 } };
+#endif
+
+        if (m->reply.RetCode == EINTR &&
+	    m->header.msgh_size == sizeof m->reply &&
+#ifdef MACH_MSG_TYPE_BIT
+	    m->check.type == check.i &&
+#endif
+	    !(m->header.msgh_bits & MACH_MSGH_BITS_COMPLEX))
+	  {
+	    /* It is indeed EINTR.  Is the interrupt for us?  */
+	    if (ss->intr_port != MACH_PORT_NULL)
+	      {
+		/* Nope; repeat the RPC.
+		   XXX Resources moved? */
+
+		assert (m->header.msgh_id == msgid + 100);
+
+		/* We know we have a valid reply port, because we just
+		   received the EINTR reply on it.  Restore it and the
+		   other fields in the message header needed for send,
+		   since the header now reflects receipt of the reply.  */
+		m->header.msgh_local_port = rcv_name;
+		m->header.msgh_remote_port = remote_port;
+		m->header.msgh_id = msgid;
+		m->header.msgh_bits = msgh_bits;
+		/* Restore the two words clobbered by the reply data.  */
+		m->request.data = save_data;
+
+		/* Restore the original mach_msg options.
+		   OPTION may have had MACH_RCV_TIMEOUT added,
+		   and/or MACH_SEND_MSG removed.  */
+		option = user_option;
+		timeout = user_timeout;
+
+		/* Now we are ready to repeat the original message send.  */
+		goto message;
+	      }
+	    else
+	      /* The EINTR return indicates cancellation,
+		 so clear the flag.  */
+	      ss->cancel = 0;
+	  }
+      }
+      break;
+
+    default:			/* Quiet -Wswitch-enum.  */
+      break;
+    }
+
+  ss->intr_port = MACH_PORT_NULL;
+
+  return err;
+}
diff --git a/REORG.TODO/hurd/intr-rpc.defs b/REORG.TODO/hurd/intr-rpc.defs
new file mode 100644
index 0000000000..4acbcc8847
--- /dev/null
+++ b/REORG.TODO/hurd/intr-rpc.defs
@@ -0,0 +1,22 @@
+/* Special MiG definitions for interruptible RPC stubs.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Cause user stubs for interruptible RPCs to import a special header to
+   modify their behavior.  */
+
+#define INTR_INTERFACE	   uimport "intr-rpc.h";
diff --git a/REORG.TODO/hurd/intr-rpc.h b/REORG.TODO/hurd/intr-rpc.h
new file mode 100644
index 0000000000..208e42c2ee
--- /dev/null
+++ b/REORG.TODO/hurd/intr-rpc.h
@@ -0,0 +1,24 @@
+/* Special MiG definitions for interruptible RPC stubs.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file is imported by the MiG-generated user stubs for interruptible
+   RPCs.  We modify them to use our own function in place of mach_msg.  */
+
+#include <hurd/signal.h>
+
+#define	__mach_msg	_hurd_intr_rpc_mach_msg
diff --git a/REORG.TODO/hurd/longjmp-ts.c b/REORG.TODO/hurd/longjmp-ts.c
new file mode 100644
index 0000000000..0fea819a23
--- /dev/null
+++ b/REORG.TODO/hurd/longjmp-ts.c
@@ -0,0 +1,31 @@
+/* Perform a `longjmp' on a Mach thread_state.  Stub version.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <setjmp.h>
+#include <mach/thread_status.h>
+
+/* Set up STATE to do the equivalent of `longjmp (ENV, VAL);'.  */
+
+void
+_hurd_longjmp_thread_state (void *state, jmp_buf env, int val)
+{
+  /* Set all the registers in *STATE to the values described by ENV and
+     RETVAL.  After this, setting that thread's state to STATE should be
+     just like calling `longjmp (ENV, RETVAL)'.  */
+  #error "Need to write sysdeps/mach/hurd/MACHINE/longjmp-ctx.c"
+}
diff --git a/REORG.TODO/hurd/lookup-at.c b/REORG.TODO/hurd/lookup-at.c
new file mode 100644
index 0000000000..b5d605665d
--- /dev/null
+++ b/REORG.TODO/hurd/lookup-at.c
@@ -0,0 +1,115 @@
+/* Lookup helper function for Hurd implementation of *at functions.
+   Copyright (C) 2006-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/fd.h>
+#include <string.h>
+#include <fcntl.h>
+
+file_t
+__file_name_lookup_at (int fd, int at_flags,
+		       const char *file_name, int flags, mode_t mode)
+{
+  error_t err;
+  file_t result;
+
+  if ((at_flags & AT_SYMLINK_FOLLOW) && (at_flags & AT_SYMLINK_NOFOLLOW))
+    return (__hurd_fail (EINVAL), MACH_PORT_NULL);
+
+  flags |= (at_flags & AT_SYMLINK_NOFOLLOW) ? O_NOLINK : 0;
+  at_flags &= ~AT_SYMLINK_NOFOLLOW;
+  if (at_flags & AT_SYMLINK_FOLLOW)
+    flags &= ~O_NOLINK;
+  at_flags &= ~AT_SYMLINK_FOLLOW;
+  if (at_flags != 0)
+    return (__hurd_fail (EINVAL), MACH_PORT_NULL);
+
+  if (fd == AT_FDCWD || file_name[0] == '/')
+    return __file_name_lookup (file_name, flags, mode);
+
+  file_t startdir;
+  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
+    {
+      return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
+	      _hurd_ports_use (which, operate));
+    }
+
+  err = HURD_DPORT_USE (fd, (startdir = port,
+			     __hurd_file_name_lookup (&use_init_port,
+						      &__getdport, NULL,
+						      file_name,
+						      flags,
+						      mode & ~_hurd_umask,
+						      &result)));
+
+  return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result;
+}
+
+file_t
+__file_name_split_at (int fd, const char *file_name, char **name)
+{
+  error_t err;
+  file_t result;
+
+  if (fd == AT_FDCWD || file_name[0] == '/')
+    return __file_name_split (file_name, name);
+
+  err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0,
+				file_name, &result, name);
+
+  file_t startdir;
+  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
+  {
+    return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
+	    _hurd_ports_use (which, operate));
+  }
+
+  err = HURD_DPORT_USE (fd, (startdir = port,
+			     __hurd_file_name_split (&use_init_port,
+						     &__getdport, 0,
+						     file_name,
+						     &result, name)));
+
+  return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result;
+}
+
+file_t
+__directory_name_split_at (int fd, const char *directory_name, char **name)
+{
+  error_t err;
+  file_t result;
+
+  if (fd == AT_FDCWD || directory_name[0] == '/')
+    return __directory_name_split (directory_name, name);
+
+  file_t startdir;
+  error_t use_init_port (int which, error_t (*operate) (mach_port_t))
+    {
+      return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
+	      _hurd_ports_use (which, operate));
+    }
+
+  err = HURD_DPORT_USE (fd, (startdir = port,
+			     __hurd_directory_name_split (&use_init_port,
+							  &__getdport, 0,
+							  directory_name,
+							  &result, name)));
+
+  return err ? (__hurd_dfail (fd, err), MACH_PORT_NULL) : result;
+}
diff --git a/REORG.TODO/hurd/lookup-retry.c b/REORG.TODO/hurd/lookup-retry.c
new file mode 100644
index 0000000000..2d88b98e4f
--- /dev/null
+++ b/REORG.TODO/hurd/lookup-retry.c
@@ -0,0 +1,331 @@
+/* hairy bits of Hurd file name lookup
+   Copyright (C) 1992-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/term.h>
+#include <hurd/paths.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <string.h>
+#include <_itoa.h>
+#include <eloop-threshold.h>
+
+/* Translate the error from dir_lookup into the error the user sees.  */
+static inline error_t
+lookup_error (error_t error)
+{
+  switch (error)
+    {
+    case EOPNOTSUPP:
+    case MIG_BAD_ID:
+      /* These indicate that the server does not understand dir_lookup
+	 at all.  If it were a directory, it would, by definition.  */
+      return ENOTDIR;
+    default:
+      return error;
+    }
+}
+
+error_t
+__hurd_file_name_lookup_retry (error_t (*use_init_port)
+				 (int which, error_t (*operate) (file_t)),
+			       file_t (*get_dtable_port) (int fd),
+			       error_t (*lookup)
+				 (file_t dir, char *name,
+				  int flags, mode_t mode,
+				  retry_type *do_retry, string_t retry_name,
+				  mach_port_t *result),
+			       enum retry_type doretry,
+			       char retryname[1024],
+			       int flags, mode_t mode,
+			       file_t *result)
+{
+  error_t err;
+  char *file_name;
+  int nloops;
+
+  error_t lookup_op (file_t startdir)
+    {
+      if (file_name[0] == '/' && file_name[1] != '\0')
+	{
+	  while (file_name[1] == '/')
+	    /* Remove double leading slash.  */
+	    file_name++;
+	  if (file_name[1] != '\0')
+	    /* Remove leading slash when we have more than the slash.  */
+	    file_name++;
+	}
+
+      return lookup_error ((*lookup) (startdir, file_name, flags, mode,
+				      &doretry, retryname, result));
+    }
+  error_t reauthenticate (file_t unauth)
+    {
+      error_t err;
+      mach_port_t ref = __mach_reply_port ();
+      error_t reauth (auth_t auth)
+	{
+	  return __auth_user_authenticate (auth, ref,
+					   MACH_MSG_TYPE_MAKE_SEND,
+					   result);
+	}
+      err = __io_reauthenticate (unauth, ref, MACH_MSG_TYPE_MAKE_SEND);
+      if (! err)
+	err = (*use_init_port) (INIT_PORT_AUTH, &reauth);
+      __mach_port_destroy (__mach_task_self (), ref);
+      __mach_port_deallocate (__mach_task_self (), unauth);
+      return err;
+    }
+
+  if (! lookup)
+    lookup = __dir_lookup;
+
+  nloops = 0;
+  err = 0;
+  do
+    {
+      file_t startdir = MACH_PORT_NULL;
+      int dirport = INIT_PORT_CWDIR;
+
+      switch (doretry)
+	{
+	case FS_RETRY_REAUTH:
+	  if (err = reauthenticate (*result))
+	    return err;
+	  /* Fall through.  */
+
+	case FS_RETRY_NORMAL:
+	  if (nloops++ >= __eloop_threshold ())
+	    {
+	      __mach_port_deallocate (__mach_task_self (), *result);
+	      return ELOOP;
+	    }
+
+	  /* An empty RETRYNAME indicates we have the final port.  */
+	  if (retryname[0] == '\0' &&
+	      /* If reauth'd, we must do one more retry on "" to give the new
+		 translator a chance to make a new port for us.  */
+	      doretry == FS_RETRY_NORMAL)
+	    {
+	      if (flags & O_NOFOLLOW)
+		{
+		  /* In Linux, O_NOFOLLOW means to reject symlinks.  If we
+		     did an O_NOLINK lookup above and io_stat here to check
+		     for S_IFLNK, a translator like firmlink could easily
+		     spoof this check by not showing S_IFLNK, but in fact
+		     redirecting the lookup to some other name
+		     (i.e. opening the very same holes a symlink would).
+
+		     Instead we do an O_NOTRANS lookup above, and stat the
+		     underlying node: if it has a translator set, and its
+		     owner is not root (st_uid 0) then we reject it.
+		     Since the motivation for this feature is security, and
+		     that security presumes we trust the containing
+		     directory, this check approximates the security of
+		     refusing symlinks while accepting mount points.
+		     Note that we actually permit something Linux doesn't:
+		     we follow root-owned symlinks; if that is deemed
+		     undesireable, we can add a final check for that
+		     one exception to our general translator-based rule.  */
+		  struct stat64 st;
+		  err = __io_stat (*result, &st);
+		  if (!err
+		      && (st.st_mode & (S_IPTRANS|S_IATRANS)))
+		    {
+		      if (st.st_uid != 0)
+			err = ENOENT;
+		      else if (st.st_mode & S_IPTRANS)
+			{
+			  char buf[1024];
+			  char *trans = buf;
+			  size_t translen = sizeof buf;
+			  err = __file_get_translator (*result,
+						       &trans, &translen);
+			  if (!err
+			      && translen > sizeof _HURD_SYMLINK
+			      && !memcmp (trans,
+					  _HURD_SYMLINK, sizeof _HURD_SYMLINK))
+			    err = ENOENT;
+			}
+		    }
+		}
+
+	      /* We got a successful translation.  Now apply any open-time
+		 action flags we were passed.  */
+
+	      if (!err && (flags & O_TRUNC)) /* Asked to truncate the file.  */
+		err = __file_set_size (*result, 0);
+
+	      if (err)
+		__mach_port_deallocate (__mach_task_self (), *result);
+	      return err;
+	    }
+
+	  startdir = *result;
+	  file_name = retryname;
+	  break;
+
+	case FS_RETRY_MAGICAL:
+	  switch (retryname[0])
+	    {
+	    case '/':
+	      dirport = INIT_PORT_CRDIR;
+	      if (*result != MACH_PORT_NULL)
+		__mach_port_deallocate (__mach_task_self (), *result);
+	      if (nloops++ >= __eloop_threshold ())
+		return ELOOP;
+	      file_name = &retryname[1];
+	      break;
+
+	    case 'f':
+	      if (retryname[1] == 'd' && retryname[2] == '/')
+		{
+		  int fd;
+		  char *end;
+		  int save = errno;
+		  errno = 0;
+		  fd = (int) __strtoul_internal (&retryname[3], &end, 10, 0);
+		  if (end == NULL || errno || /* Malformed number.  */
+		      /* Check for excess text after the number.  A slash
+			 is valid; it ends the component.  Anything else
+			 does not name a numeric file descriptor.  */
+		      (*end != '/' && *end != '\0'))
+		    {
+		      errno = save;
+		      return ENOENT;
+		    }
+		  if (! get_dtable_port)
+		    err = EGRATUITOUS;
+		  else
+		    {
+		      *result = (*get_dtable_port) (fd);
+		      if (*result == MACH_PORT_NULL)
+			{
+			  /* If the name was a proper number, but the file
+			     descriptor does not exist, we return EBADF instead
+			     of ENOENT.  */
+			  err = errno;
+			  errno = save;
+			}
+		    }
+		  errno = save;
+		  if (err)
+		    return err;
+		  if (*end == '\0')
+		    return 0;
+		  else
+		    {
+		      /* Do a normal retry on the remaining components.  */
+		      startdir = *result;
+		      file_name = end + 1; /* Skip the slash.  */
+		      break;
+		    }
+		}
+	      else
+		goto bad_magic;
+	      break;
+
+	    case 'm':
+	      if (retryname[1] == 'a' && retryname[2] == 'c' &&
+		  retryname[3] == 'h' && retryname[4] == 't' &&
+		  retryname[5] == 'y' && retryname[6] == 'p' &&
+		  retryname[7] == 'e')
+		{
+		  error_t err;
+		  struct host_basic_info hostinfo;
+		  mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT;
+		  char *p;
+		  /* XXX want client's host */
+		  if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
+					 (integer_t *) &hostinfo,
+					 &hostinfocnt))
+		    return err;
+		  if (hostinfocnt != HOST_BASIC_INFO_COUNT)
+		    return EGRATUITOUS;
+		  p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
+		  *--p = '/';
+		  p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
+		  if (p < retryname)
+		    abort ();	/* XXX write this right if this ever happens */
+		  if (p > retryname)
+		    strcpy (retryname, p);
+		  startdir = *result;
+		}
+	      else
+		goto bad_magic;
+	      break;
+
+	    case 't':
+	      if (retryname[1] == 't' && retryname[2] == 'y')
+		switch (retryname[3])
+		  {
+		    error_t opentty (file_t *result)
+		      {
+			error_t err;
+			error_t ctty_open (file_t port)
+			  {
+			    if (port == MACH_PORT_NULL)
+			      return ENXIO; /* No controlling terminal.  */
+			    return __termctty_open_terminal (port,
+							     flags,
+							     result);
+			  }
+			err = (*use_init_port) (INIT_PORT_CTTYID, &ctty_open);
+			if (! err)
+			  err = reauthenticate (*result);
+			return err;
+		      }
+
+		  case '\0':
+		    return opentty (result);
+		  case '/':
+		    if (err = opentty (&startdir))
+		      return err;
+		    strcpy (retryname, &retryname[4]);
+		    break;
+		  default:
+		    goto bad_magic;
+		  }
+	      else
+		goto bad_magic;
+	      break;
+
+	    default:
+	    bad_magic:
+	      return EGRATUITOUS;
+	    }
+	  break;
+
+	default:
+	  return EGRATUITOUS;
+	}
+
+      if (startdir != MACH_PORT_NULL)
+	{
+	  err = lookup_op (startdir);
+	  __mach_port_deallocate (__mach_task_self (), startdir);
+	  startdir = MACH_PORT_NULL;
+	}
+      else
+	err = (*use_init_port) (dirport, &lookup_op);
+    } while (! err);
+
+  return err;
+}
+weak_alias (__hurd_file_name_lookup_retry, hurd_file_name_lookup_retry)
diff --git a/REORG.TODO/hurd/msgportdemux.c b/REORG.TODO/hurd/msgportdemux.c
new file mode 100644
index 0000000000..05f7117014
--- /dev/null
+++ b/REORG.TODO/hurd/msgportdemux.c
@@ -0,0 +1,68 @@
+/* Demux messages sent on the signal port.
+   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <stddef.h>
+
+struct demux
+  {
+    struct demux *next;
+    boolean_t (*demux) (mach_msg_header_t *inp,
+			mach_msg_header_t *outp);
+  };
+
+struct demux *_hurd_msgport_demuxers = NULL;
+
+extern boolean_t __msg_server (mach_msg_header_t *inp,
+			       mach_msg_header_t *outp);
+
+static boolean_t
+msgport_server (mach_msg_header_t *inp,
+		mach_msg_header_t *outp)
+{
+  extern boolean_t _S_msg_server (mach_msg_header_t *inp,
+				  mach_msg_header_t *outp);
+  extern boolean_t _S_exc_server (mach_msg_header_t *inp,
+				  mach_msg_header_t *outp);
+  struct demux *d;
+
+  for (d = _hurd_msgport_demuxers; d != NULL; d = d->next)
+    if ((*d->demux) (inp, outp))
+      return 1;
+
+  return (_S_exc_server (inp, outp) ||
+	  _S_msg_server (inp, outp));
+}
+
+/* This is the code that the signal thread runs.  */
+void
+_hurd_msgport_receive (void)
+{
+  /* Get our own sigstate cached so we never again have to take a lock to
+     fetch it.  There is much code in hurdsig.c that operates with some
+     sigstate lock held, which will deadlock with _hurd_thread_sigstate.
+
+     Furthermore, in the cthreads case this is the convenient spot
+     to initialize _hurd_msgport_thread (see hurdsig.c:_hurdsig_init).  */
+
+  _hurd_msgport_thread = _hurd_self_sigstate ()->thread;
+
+  while (1)
+    (void) __mach_msg_server (msgport_server, __vm_page_size, _hurd_msgport);
+}
diff --git a/REORG.TODO/hurd/new-fd.c b/REORG.TODO/hurd/new-fd.c
new file mode 100644
index 0000000000..9ea95bbf38
--- /dev/null
+++ b/REORG.TODO/hurd/new-fd.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/fd.h>
+#include <stdlib.h>
+#include "hurdmalloc.h"		/* XXX */
+
+/* Allocate a new file descriptor structure
+   and initialize it with PORT and CTTY.  */
+
+struct hurd_fd *
+_hurd_new_fd (io_t port, io_t ctty)
+{
+  struct hurd_fd *d = malloc (sizeof (struct hurd_fd));
+
+  if (d != NULL)
+    {
+      /* Initialize the port cells.  */
+      _hurd_port_init (&d->port, port);
+      _hurd_port_init (&d->ctty, ctty);
+
+      /* And the fcntl flags.  */
+      d->flags = 0;
+    }
+
+  return d;
+}
diff --git a/REORG.TODO/hurd/openport.c b/REORG.TODO/hurd/openport.c
new file mode 100644
index 0000000000..da889f7225
--- /dev/null
+++ b/REORG.TODO/hurd/openport.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/fd.h>
+
+/* User entry point for interning a port as a new FD.
+   Just like _hurd_intern_fd, but don't dealloc PORT on error.  */
+
+int
+openport (io_t port, int flags)
+{
+  return _hurd_intern_fd (port, flags, 0);
+}
diff --git a/REORG.TODO/hurd/path-lookup.c b/REORG.TODO/hurd/path-lookup.c
new file mode 100644
index 0000000000..f2061b0bff
--- /dev/null
+++ b/REORG.TODO/hurd/path-lookup.c
@@ -0,0 +1,122 @@
+/* Filename lookup using a search path
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <hurd.h>
+#include <hurd/lookup.h>
+
+/* If FILE_NAME contains a '/', or PATH is NULL, call FUN with FILE_NAME, and
+   return the result (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to
+   NULL).  Otherwise, call FUN repeatedly with FILE_NAME prefixed with each
+   successive `:' separated element of PATH, returning whenever FUN returns
+   0 (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to the resulting
+   prefixed path).  If FUN never returns 0, return the first non-ENOENT
+   return value, or ENOENT if there is none.  */
+error_t
+file_name_path_scan (const char *file_name, const char *path,
+		     error_t (*fun)(const char *name),
+		     char **prefixed_name)
+{
+  if (path == NULL || strchr (file_name, '/'))
+    {
+      if (prefixed_name)
+	*prefixed_name = 0;
+      return (*fun)(file_name);
+    }
+  else
+    {
+      error_t real_err = 0;
+      size_t file_name_len = strlen (file_name);
+
+      for (;;)
+	{
+	  error_t err;
+	  const char *next = strchr (path, ':') ?: path + strlen (path);
+	  size_t pfx_len = next - path;
+	  char pfxed_name[pfx_len + 2 + file_name_len + 1];
+
+	  if (pfx_len == 0)
+	    pfxed_name[pfx_len++] = '.';
+	  else
+	    memcpy (pfxed_name, path, pfx_len);
+	  if (pfxed_name[pfx_len - 1] != '/')
+	    pfxed_name[pfx_len++] = '/';
+	  memcpy (pfxed_name + pfx_len, file_name, file_name_len + 1);
+
+	  err = (*fun)(pfxed_name);
+	  if (err == 0)
+	    {
+	      if (prefixed_name)
+		*prefixed_name = strdup (pfxed_name);
+	      return 0;
+	    }
+	  if (!real_err && err != ENOENT)
+	    real_err = err;
+
+	  if (*next == '\0')
+	    return real_err ?: ENOENT;
+	  else
+	    path = next + 1;
+	}
+    }
+}
+
+/* Lookup FILE_NAME and return the node opened with FLAGS & MODE in result
+   (see hurd_file_name_lookup for details), but a simple filename (without
+   any directory prefixes) will be consecutively prefixed with the pathnames
+   in the `:' separated list PATH until one succeeds in a successful lookup.
+   If none succeed, then the first error that wasn't ENOENT is returned, or
+   ENOENT if no other errors were returned.  If PREFIXED_NAME is non-NULL,
+   then if RESULT is looked up directly, *PREFIXED_NAME is set to NULL, and
+   if it is looked up using a prefix from PATH, *PREFIXED_NAME is set to
+   malloced storage containing the prefixed name.  */
+error_t
+hurd_file_name_path_lookup (error_t (*use_init_port)
+			      (int which, error_t (*operate) (mach_port_t)),
+			    file_t (*get_dtable_port) (int fd),
+			    error_t (*lookup)
+			      (file_t dir, char *name, int flags, mode_t mode,
+			       retry_type *do_retry, string_t retry_name,
+			       mach_port_t *result),
+			    const char *file_name, const char *path,
+			    int flags, mode_t mode,
+			    file_t *result, char **prefixed_name)
+{
+  error_t scan_lookup (const char *name)
+    {
+      return
+	__hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
+				 name, flags, mode, result);
+    }
+  return file_name_path_scan (file_name, path, scan_lookup, prefixed_name);
+}
+
+file_t
+file_name_path_lookup (const char *file_name, const char *path,
+		       int flags, mode_t mode, char **prefixed_name)
+{
+  error_t err;
+  file_t result;
+
+  err = hurd_file_name_path_lookup (&_hurd_ports_use, &__getdport, 0,
+				    file_name, path, flags, mode,
+				    &result, prefixed_name);
+
+  return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
+}
diff --git a/REORG.TODO/hurd/pid2task.c b/REORG.TODO/hurd/pid2task.c
new file mode 100644
index 0000000000..5fd2de53c0
--- /dev/null
+++ b/REORG.TODO/hurd/pid2task.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+task_t
+__pid2task (pid_t pid)
+{
+  error_t err;
+  task_t task;
+
+  err = __USEPORT (PROC, __proc_pid2task (port, pid, &task));
+
+  return err ? (__hurd_fail (err), MACH_PORT_NULL) : task;
+}
+
+weak_alias (__pid2task, pid2task)
diff --git a/REORG.TODO/hurd/port-cleanup.c b/REORG.TODO/hurd/port-cleanup.c
new file mode 100644
index 0000000000..6dbd117980
--- /dev/null
+++ b/REORG.TODO/hurd/port-cleanup.c
@@ -0,0 +1,30 @@
+/* Cleanup function for `struct hurd_port' users who longjmp.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <mach.h>
+#include <hurd/port.h>
+
+/* The last user of the send right CLEANUP_DATA is now doing
+   `longjmp (ENV, VAL)', and this will unwind the frame of
+   that last user.  Deallocate the right he will never get back to using.  */
+
+void
+_hurd_port_cleanup (void *cleanup_data, jmp_buf env, int val)
+{
+  __mach_port_deallocate (__mach_task_self (), (mach_port_t) cleanup_data);
+}
diff --git a/REORG.TODO/hurd/port2fd.c b/REORG.TODO/hurd/port2fd.c
new file mode 100644
index 0000000000..83e7b9c47e
--- /dev/null
+++ b/REORG.TODO/hurd/port2fd.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <hurd/signal.h>
+#include <hurd/term.h>
+#include <fcntl.h>
+
+/* Store PORT in file descriptor D, doing appropriate ctty magic.
+   FLAGS are as for `open'; only O_IGNORE_CTTY and O_CLOEXEC are meaningful.
+   D should be locked, and will not be unlocked.  */
+
+void
+_hurd_port2fd (struct hurd_fd *d, io_t dport, int flags)
+{
+  mach_port_t cttyid;
+  io_t ctty = MACH_PORT_NULL;
+
+  if (!(flags & O_IGNORE_CTTY))
+    __USEPORT (CTTYID,
+	       ({
+		 if (port != MACH_PORT_NULL && /* Do we have a ctty? */
+		     ! __term_getctty (dport, &cttyid))	/* Could this be it? */
+		   {
+		     __mach_port_deallocate (__mach_task_self (), cttyid);
+		     /* This port is capable of being a controlling tty.
+			Is it ours?  */
+		     if (cttyid == port)
+		       __term_open_ctty (dport, _hurd_pid, _hurd_pgrp, &ctty);
+		     /* XXX if this port is our ctty, but we are not doing
+			ctty style i/o because term_become_ctty barfed,
+			what to do?  */
+		   }
+		 0;
+	       }));
+
+  /* Install PORT in the descriptor cell, leaving it locked.  */
+  {
+    mach_port_t old
+      = _hurd_userlink_clear (&d->port.users) ? d->port.port : MACH_PORT_NULL;
+    d->port.port = dport;
+    d->flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
+    if (old != MACH_PORT_NULL)
+      __mach_port_deallocate (__mach_task_self (), old);
+  }
+
+  _hurd_port_set (&d->ctty, ctty);
+}
diff --git a/REORG.TODO/hurd/ports-get.c b/REORG.TODO/hurd/ports-get.c
new file mode 100644
index 0000000000..0735ac59b1
--- /dev/null
+++ b/REORG.TODO/hurd/ports-get.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+static error_t
+getbootstrap (mach_port_t *result)
+{
+  return __task_get_special_port (__mach_task_self (),
+				  TASK_BOOTSTRAP_PORT,
+				  result);
+}
+
+error_t (*_hurd_ports_getters[INIT_PORT_MAX]) (mach_port_t *result) =
+  {
+    [INIT_PORT_BOOTSTRAP] = getbootstrap,
+  };
+
+error_t
+_hurd_ports_get (unsigned int which, mach_port_t *result)
+{
+  if (which >= _hurd_nports)
+    return EINVAL;
+  if (which >= INIT_PORT_MAX || _hurd_ports_getters[which] == NULL)
+    return HURD_PORT_USE (&_hurd_ports[which],
+			  (*result = port) == MACH_PORT_NULL ? 0
+			  : __mach_port_mod_refs (__mach_task_self (),
+						  port, MACH_PORT_RIGHT_SEND,
+						  +1));
+  return (*_hurd_ports_getters[which]) (result);
+}
diff --git a/REORG.TODO/hurd/ports-set.c b/REORG.TODO/hurd/ports-set.c
new file mode 100644
index 0000000000..30d47a4281
--- /dev/null
+++ b/REORG.TODO/hurd/ports-set.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+static error_t
+setbootstrap (mach_port_t newport)
+{
+  return __task_set_special_port (__mach_task_self (),
+				  TASK_BOOTSTRAP_PORT,
+				  newport);
+}
+
+extern error_t _hurd_setauth (auth_t);
+extern error_t _hurd_setproc (process_t);
+extern error_t _hurd_setcttyid (mach_port_t);
+
+error_t (*_hurd_ports_setters[INIT_PORT_MAX]) (mach_port_t newport) =
+  {
+    [INIT_PORT_BOOTSTRAP] = setbootstrap,
+    [INIT_PORT_AUTH] = _hurd_setauth,
+    [INIT_PORT_PROC] = _hurd_setproc,
+    [INIT_PORT_CTTYID] = _hurd_setcttyid,
+  };
+
+
+error_t
+_hurd_ports_set (unsigned int which, mach_port_t newport)
+{
+  error_t err;
+  if (which >= _hurd_nports)
+    return EINVAL;
+  if (err = __mach_port_mod_refs (__mach_task_self (), newport,
+				  MACH_PORT_RIGHT_SEND, 1))
+    return err;
+  if (which >= INIT_PORT_MAX || _hurd_ports_setters[which] == NULL)
+    {
+      _hurd_port_set (&_hurd_ports[which], newport);
+      return 0;
+    }
+  return (*_hurd_ports_setters[which]) (newport);
+}
diff --git a/REORG.TODO/hurd/preempt-sig.c b/REORG.TODO/hurd/preempt-sig.c
new file mode 100644
index 0000000000..81c4e905b4
--- /dev/null
+++ b/REORG.TODO/hurd/preempt-sig.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/sigpreempt.h>
+#include <hurd/signal.h>
+#include <assert.h>
+
+void
+hurd_preempt_signals (struct hurd_signal_preemptor *preemptor)
+{
+  __mutex_lock (&_hurd_siglock);
+  preemptor->next = _hurdsig_preemptors;
+  _hurdsig_preemptors = preemptor;
+  _hurdsig_preempted_set |= preemptor->signals;
+  __mutex_unlock (&_hurd_siglock);
+}
+
+void
+hurd_unpreempt_signals (struct hurd_signal_preemptor *preemptor)
+{
+  struct hurd_signal_preemptor **p;
+  sigset_t preempted = 0;
+
+  __mutex_lock (&_hurd_siglock);
+
+  p = &_hurdsig_preemptors;
+  while (*p)
+    if (*p == preemptor)
+      {
+	/* Found it; take it off the chain.  */
+	*p = (*p)->next;
+	if ((preemptor->signals & preempted) != preemptor->signals)
+	  {
+	    /* This might have been the only preemptor for some
+	       of those signals, so we must collect the full mask
+	       from the others.  */
+	    struct hurd_signal_preemptor *pp;
+	    for (pp = *p; pp; pp = pp->next)
+	      preempted |= pp->signals;
+	    _hurdsig_preempted_set = preempted;
+	  }
+	__mutex_unlock (&_hurd_siglock);
+	return;
+      }
+    else
+      {
+	preempted |= (*p)->signals;
+	p = &(*p)->next;
+      }
+
+  __mutex_unlock (&_hurd_siglock); /* Avoid deadlock during death rattle.  */
+  assert (! "removing absent preemptor");
+}
diff --git a/REORG.TODO/hurd/privports.c b/REORG.TODO/hurd/privports.c
new file mode 100644
index 0000000000..90467883a6
--- /dev/null
+++ b/REORG.TODO/hurd/privports.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+/* The program might set these if it is the initial task
+   bootstrapped by the microkernel.  */
+
+mach_port_t _hurd_host_priv, _hurd_device_master;
+
+
+kern_return_t
+__get_privileged_ports (mach_port_t *host_priv_ptr,
+			device_t *device_master_ptr)
+{
+  if ((host_priv_ptr && _hurd_host_priv == MACH_PORT_NULL)
+      || (device_master_ptr && _hurd_device_master == MACH_PORT_NULL))
+    {
+      error_t err;
+
+      if (_hurd_ports)
+	/* We have gotten some initial ports, so perhaps
+	   we have a proc server to talk to.  */
+	err = __USEPORT (PROC, __proc_getprivports (port,
+						    &_hurd_host_priv,
+						    &_hurd_device_master));
+      else
+	return MACH_SEND_INVALID_DEST;
+
+      if (err)
+	return err;
+    }
+
+  if (host_priv_ptr)
+    {
+      error_t err = _hurd_host_priv == MACH_PORT_NULL ? 0
+	: __mach_port_mod_refs (mach_task_self (),
+				_hurd_host_priv, MACH_PORT_RIGHT_SEND, +1);
+      if (err)
+	return err;
+      *host_priv_ptr = _hurd_host_priv;
+    }
+
+  if (device_master_ptr)
+    {
+      error_t err = _hurd_device_master == MACH_PORT_NULL ? 0
+	: __mach_port_mod_refs (mach_task_self (),
+				_hurd_device_master, MACH_PORT_RIGHT_SEND, +1);
+      if (err)
+	return err;
+      *device_master_ptr = _hurd_device_master;
+    }
+
+  return KERN_SUCCESS;
+}
+weak_alias (__get_privileged_ports, get_privileged_ports)
diff --git a/REORG.TODO/hurd/report-wait.c b/REORG.TODO/hurd/report-wait.c
new file mode 100644
index 0000000000..92e8aba71c
--- /dev/null
+++ b/REORG.TODO/hurd/report-wait.c
@@ -0,0 +1,243 @@
+/* Report on what a thread in our task is waiting for.
+   Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <hurd/fd.h>
+#include <string.h>
+#include <assert.h>
+#include <hurd/msg_server.h>
+#include <thread_state.h>
+#include <intr-msg.h>
+
+static char *
+describe_number (string_t description, const char *flavor, long int i)
+{
+  unsigned long int j;
+  char *p = flavor == NULL ? description : __stpcpy (description, flavor);
+  char *end;
+
+  /* Handle sign.  */
+  if (i < 0)
+    {
+      i = -i;
+      *p++ = '-';
+    }
+
+  /* Allocate space for the number at the end of DESCRIPTION.  */
+  for (j = i; j >= 10; j /= 10)
+    p++;
+  end = p + 1;
+  *end = '\0';
+
+  do
+    {
+      *p-- = '0' + i % 10;
+      i /= 10;
+    } while (i != 0);
+
+  return end;
+}
+
+static char *
+describe_port (string_t description, mach_port_t port)
+{
+  int i;
+
+  if (port == MACH_PORT_NULL)
+    return __stpcpy (description, "(null)");
+  if (port == MACH_PORT_DEAD)
+    return __stpcpy (description, "(dead)");
+
+  if (port == __mach_task_self ())
+    return __stpcpy (description, "task-self");
+
+  for (i = 0; i < _hurd_nports; ++i)
+    if (port == _hurd_ports[i].port)
+      return describe_number (description, "init#", i);
+
+  if (_hurd_init_dtable)
+    {
+      for (i = 0; i < _hurd_init_dtablesize; ++i)
+	if (port == _hurd_init_dtable[i])
+	  return describe_number (description, "fd#", i);
+    }
+  else if (_hurd_dtable)
+    {
+      for (i = 0; i < _hurd_dtablesize; ++i)
+	if (_hurd_dtable[i] == NULL)
+	  continue;
+	else if (port == _hurd_dtable[i]->port.port)
+	  return describe_number (description, "fd#", i);
+	else if (port == _hurd_dtable[i]->ctty.port)
+	  return describe_number (description, "bgfd#", i);
+    }
+
+  return describe_number (description, "port#", port);
+}
+
+
+/* We want _HURD_ITIMER_THREAD, but don't want to link in the itimer code
+   unnecessarily.  */
+#if 0 /* libc.so.0.0 needs this defined, so make it a weak alias for now.  */
+extern thread_t _hurd_itimer_thread; /* XXX */
+weak_extern (_hurd_itimer_thread)
+#else
+static thread_t default_hurd_itimer_thread;
+weak_alias (default_hurd_itimer_thread, _hurd_itimer_thread)
+#endif
+
+kern_return_t
+_S_msg_report_wait (mach_port_t msgport, thread_t thread,
+		    string_t description, mach_msg_id_t *msgid)
+{
+  *msgid = 0;
+
+  if (thread == _hurd_msgport_thread)
+    /* Cute.  */
+    strcpy (description, "msgport");
+  else if (&_hurd_itimer_thread && thread == _hurd_itimer_thread)
+    strcpy (description, "itimer");
+  else
+    {
+      /* Make sure this is really one of our threads.  */
+
+      struct hurd_sigstate *ss;
+
+      __mutex_lock (&_hurd_siglock);
+      for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+	if (ss->thread == thread)
+	  break;
+      __mutex_unlock (&_hurd_siglock);
+      if (ss == NULL)
+	/* To hell with you.  */
+	return EINVAL;
+
+      if (ss->suspended != MACH_PORT_NULL)
+	strcpy (description, "sigsuspend");
+      else
+	{
+	  /* Examine the thread's state to see if it is blocked in an RPC.  */
+
+	  struct machine_thread_state state;
+	  mach_msg_type_number_t count = MACHINE_THREAD_STATE_COUNT;
+	  error_t err;
+
+	  err = __thread_get_state (thread, MACHINE_THREAD_STATE_FLAVOR,
+				    (natural_t *) &state, &count);
+	  if (err)
+	    return err;
+	  assert (count == MACHINE_THREAD_STATE_COUNT);
+	  if (SYSCALL_EXAMINE (&state, msgid))
+	    {
+	      mach_port_t send_port, rcv_port;
+	      mach_msg_option_t option;
+	      mach_msg_timeout_t timeout;
+
+	      /* Blocked in a system call.  */
+	      if (*msgid == -25
+		  /* mach_msg system call.  Examine its parameters.  */
+		  && MSG_EXAMINE (&state, msgid, &send_port, &rcv_port,
+				  &option, &timeout) == 0)
+		{
+		  char *p;
+		  if (send_port != MACH_PORT_NULL && *msgid != 0)
+		    {
+		      /* For the normal case of RPCs, we consider the
+			 destination port to be the interesting thing
+			 whether we are in fact sending or receiving at the
+			 moment.  That tells us who we are waiting for the
+			 reply from.  */
+		      if (send_port == ss->intr_port)
+			{
+			  /* This is a Hurd interruptible RPC.
+			     Mark it by surrounding the port description
+			     string with [...] brackets.  */
+			  description[0] = '[';
+			  p = describe_port (description + 1, send_port);
+			  *p++ = ']';
+			  *p = '\0';
+			}
+		      else
+			(void) describe_port (description, send_port);
+		    }
+		  else if (rcv_port != MACH_PORT_NULL)
+		    {
+		      /* This system call had no send port, but had a
+			 receive port.  The msgid we extracted is then just
+			 some garbage or perhaps the msgid of the last
+			 message this thread received, but it's not a
+			 helpful thing to return.  */
+		      strcpy (describe_port (description, rcv_port), ":rcv");
+		      *msgid = 0;
+		    }
+		  else if ((option & (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
+			   == (MACH_RCV_MSG|MACH_RCV_TIMEOUT))
+		    {
+		      /* A receive with no valid port can be used for a
+			 pure timeout.  Report the timeout value (counted
+			 in milliseconds); note this is the original total
+			 time, not the time remaining.  */
+		      strcpy (describe_number (description, 0, timeout), "ms");
+		      *msgid = 0;
+		    }
+		  else
+		    {
+		      strcpy (description, "mach_msg");
+		      *msgid = 0;
+		    }
+		}
+	      else		/* Some other system call.  */
+		{
+		  (void) describe_number (description, "syscall#", *msgid);
+		  *msgid = 0;
+		}
+	    }
+	  else
+	    description[0] = '\0';
+	}
+    }
+
+  __mach_port_deallocate (__mach_task_self (), thread);
+  return 0;
+}
+
+kern_return_t
+_S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
+		       mach_port_t *ports, mach_msg_type_number_t nports,
+		       char **desc, mach_msg_type_number_t *desclen)
+{
+  char *p, *end;
+
+  if (__USEPORT (AUTH, msgport != port))
+    return EPERM;
+
+  end = *desc + *desclen;
+  p = *desc;
+  while (nports-- > 0)
+    {
+      char this[200];
+      describe_port (this, *ports++);
+      p = __stpncpy (p, this, end - p);
+      if (p == end && p[-1] != '\0')
+	return ENOMEM;
+    }
+
+  *desclen = p - *desc;
+  return 0;
+}
diff --git a/REORG.TODO/hurd/set-host.c b/REORG.TODO/hurd/set-host.c
new file mode 100644
index 0000000000..e302d71fb7
--- /dev/null
+++ b/REORG.TODO/hurd/set-host.c
@@ -0,0 +1,49 @@
+/* Set a host configuration item kept as the whole contents of a file.
+   Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <hurd.h>
+#include "hurdhost.h"
+
+ssize_t
+_hurd_set_host_config (const char *item, const char *value, size_t valuelen)
+{
+  error_t err;
+  mach_msg_type_number_t nwrote;
+  file_t new, dir;
+  char *name;
+
+  dir = __file_name_split (item, &name);
+  if (dir == MACH_PORT_NULL)
+    return -1;
+
+  /* Create a new node.  */
+  err = __dir_mkfile (dir, O_WRONLY, 0644, &new);
+  if (! err)
+    {
+      /* Write the contents.  */
+      err = __io_write (new, value, valuelen, 0, &nwrote);
+      if (! err)
+	/* Atomically link the new node onto the name.  */
+	err = __dir_link (dir, new, name, 0);
+      __mach_port_deallocate (__mach_task_self (), new);
+    }
+  __mach_port_deallocate (__mach_task_self (), dir);
+
+  return err ? __hurd_fail (err) : nwrote;
+}
diff --git a/REORG.TODO/hurd/setauth.c b/REORG.TODO/hurd/setauth.c
new file mode 100644
index 0000000000..77bf7ee741
--- /dev/null
+++ b/REORG.TODO/hurd/setauth.c
@@ -0,0 +1,122 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/port.h>
+#include <hurd/id.h>
+#include "set-hooks.h"
+
+/* Things in the library which want to be run when the auth port changes.  */
+DEFINE_HOOK (_hurd_reauth_hook, (auth_t new_auth));
+
+#include <cthreads.h>
+static struct mutex reauth_lock = MUTEX_INITIALIZER;
+
+
+/* Set the auth port to NEW, and reauthenticate
+   everything used by the library.  */
+error_t
+_hurd_setauth (auth_t new)
+{
+  error_t err;
+  unsigned int d;
+  mach_port_t newport, ref;
+
+  /* Give the new send right a user reference.
+     This is a good way to check that it is valid.  */
+  if (err = __mach_port_mod_refs (__mach_task_self (), new,
+				  MACH_PORT_RIGHT_SEND, 1))
+    return err;
+
+  HURD_CRITICAL_BEGIN;
+
+  /* We lock against another thread doing setauth.  Anyone who sets
+     _hurd_ports[INIT_PORT_AUTH] some other way is asking to lose.  */
+  __mutex_lock (&reauth_lock);
+
+  /* Install the new port in the cell.  */
+  __mutex_lock (&_hurd_id.lock);
+  _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], new);
+  _hurd_id.valid = 0;
+  if (_hurd_id.rid_auth)
+    {
+      __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
+      _hurd_id.rid_auth = MACH_PORT_NULL;
+    }
+  __mutex_unlock (&_hurd_id.lock);
+
+  if (_hurd_init_dtable != NULL)
+    /* We just have the simple table we got at startup.
+       Otherwise, a reauth_hook in dtable.c takes care of this.  */
+    for (d = 0; d < _hurd_init_dtablesize; ++d)
+      if (_hurd_init_dtable[d] != MACH_PORT_NULL)
+	{
+	  mach_port_t new;
+	  ref = __mach_reply_port ();
+	  if (! __io_reauthenticate (_hurd_init_dtable[d],
+				     ref, MACH_MSG_TYPE_MAKE_SEND) &&
+	      ! HURD_PORT_USE (&_hurd_ports[INIT_PORT_AUTH],
+			       __auth_user_authenticate
+			       (port,
+				ref, MACH_MSG_TYPE_MAKE_SEND,
+				&new)))
+	    {
+	      __mach_port_deallocate (__mach_task_self (),
+				      _hurd_init_dtable[d]);
+	      _hurd_init_dtable[d] = new;
+	    }
+	  __mach_port_destroy (__mach_task_self (), ref);
+	}
+
+  ref = __mach_reply_port ();
+  if (__USEPORT (CRDIR,
+		 ! __io_reauthenticate (port,
+					ref, MACH_MSG_TYPE_MAKE_SEND) &&
+		 ! __auth_user_authenticate (new,
+					     ref, MACH_MSG_TYPE_MAKE_SEND,
+					     &newport)))
+    _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], newport);
+  __mach_port_destroy (__mach_task_self (), ref);
+
+  ref = __mach_reply_port ();
+  if (__USEPORT (CWDIR,
+		 ! __io_reauthenticate (port,
+					ref, MACH_MSG_TYPE_MAKE_SEND) &&
+		 ! __auth_user_authenticate (new,
+					     ref, MACH_MSG_TYPE_MAKE_SEND,
+					     &newport)))
+    _hurd_port_set (&_hurd_ports[INIT_PORT_CWDIR], newport);
+  __mach_port_destroy (__mach_task_self (), ref);
+
+  /* Run things which want to do reauthorization stuff.  */
+  RUN_HOOK (_hurd_reauth_hook, (new));
+
+  __mutex_unlock (&reauth_lock);
+
+  HURD_CRITICAL_END;
+
+  return 0;
+}
+
+int
+__setauth (auth_t new)
+{
+  error_t err = _hurd_setauth (new);
+  return err ? __hurd_fail (err) : 0;
+}
+
+weak_alias (__setauth, setauth)
diff --git a/REORG.TODO/hurd/seteuids.c b/REORG.TODO/hurd/seteuids.c
new file mode 100644
index 0000000000..edefdf9c12
--- /dev/null
+++ b/REORG.TODO/hurd/seteuids.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/id.h>
+
+/* Set the uid set for the current user to UIDS (N of them).  */
+int
+seteuids (int n, const uid_t *uids)
+{
+  error_t err;
+  auth_t newauth;
+  int i;
+  gid_t new[n];
+
+  /* Fault before taking locks.  */
+  for (i = 0; i < n; ++i)
+    new[i] = uids[i];
+
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_id.lock);
+  err = _hurd_check_ids ();
+  if (! err)
+    {
+      /* Get a new auth port using those IDs.  */
+      err = __USEPORT (AUTH,
+		       __auth_makeauth (port, NULL, 0, 0,
+					new, n,
+					_hurd_id.aux.uids, _hurd_id.aux.nuids,
+					_hurd_id.gen.gids, _hurd_id.gen.ngids,
+					_hurd_id.aux.gids, _hurd_id.aux.ngids,
+					&newauth));
+    }
+  __mutex_unlock (&_hurd_id.lock);
+  HURD_CRITICAL_END;
+
+  if (err)
+    return __hurd_fail (err);
+
+  /* Install the new auth port and reauthenticate everything.  */
+  err = __setauth (newauth);
+  __mach_port_deallocate (__mach_task_self (), newauth);
+  return err;
+}
diff --git a/REORG.TODO/hurd/siginfo.c b/REORG.TODO/hurd/siginfo.c
new file mode 100644
index 0000000000..1db042e4d8
--- /dev/null
+++ b/REORG.TODO/hurd/siginfo.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/signal.h>
+#include <stdio.h>
+
+void
+_hurd_siginfo_handler (int signo)
+{
+  /* XXX */
+  puts ("got a SIGINFO");
+}
diff --git a/REORG.TODO/hurd/sigunwind.c b/REORG.TODO/hurd/sigunwind.c
new file mode 100644
index 0000000000..8025599665
--- /dev/null
+++ b/REORG.TODO/hurd/sigunwind.c
@@ -0,0 +1,149 @@
+/* longjmp cleanup function for unwinding past signal handlers.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <thread_state.h>
+#include <jmpbuf-unwind.h>
+#include <assert.h>
+#include <stdint.h>
+
+
+/* _hurd_setup_sighandler puts a link on the `active resources' chain so that
+   _longjmp_unwind will call this function with the `struct sigcontext *'
+   describing the context interrupted by the signal, when `longjmp' is jumping
+   to an environment that unwinds past the interrupted frame.  */
+
+void
+_hurdsig_longjmp_from_handler (void *data, jmp_buf env, int val)
+{
+  struct sigcontext *scp = data;
+  struct hurd_sigstate *ss = _hurd_self_sigstate ();
+  int onstack;
+  inline void cleanup (void)
+    {
+      /* Destroy the MiG reply port used by the signal handler, and restore
+	 the reply port in use by the thread when interrupted.  */
+      mach_port_t *reply_port =
+	(mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
+      if (*reply_port)
+	{
+	  mach_port_t port = *reply_port;
+	  /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port
+	     not to get another reply port, but avoids mig_dealloc_reply_port
+	     trying to deallocate it after the receive fails (which it will,
+	     because the reply port will be bogus, regardless).  */
+	  *reply_port = MACH_PORT_DEAD;
+	  __mach_port_destroy (__mach_task_self (), port);
+	}
+      if (scp->sc_reply_port)
+	__mach_port_destroy (__mach_task_self (), scp->sc_reply_port);
+    }
+
+  __spin_lock (&ss->lock);
+  /* We should only ever be called from _longjmp_unwind (in jmp-unwind.c),
+     which calls us inside a critical section.  */
+  assert (__spin_lock_locked (&ss->critical_section_lock));
+  /* Are we on the alternate signal stack now?  */
+  onstack = (ss->sigaltstack.ss_flags & SS_ONSTACK);
+  __spin_unlock (&ss->lock);
+
+  if (onstack && ! scp->sc_onstack)
+    {
+      /* We are unwinding off the signal stack.  We must use sigreturn to
+	 do it robustly.  Mutate the sigcontext so that when sigreturn
+	 resumes from that context, it will be as if `__longjmp (ENV, VAL)'
+	 were done.  */
+
+      struct hurd_userlink *link;
+
+      inline uintptr_t demangle_ptr (uintptr_t x)
+	{
+# ifdef PTR_DEMANGLE
+	  PTR_DEMANGLE (x);
+# endif
+	  return x;
+	}
+
+      /* Continue _longjmp_unwind's job of running the unwind
+	 forms for frames being unwound, since we will not
+	 return to its loop like this one, which called us.  */
+      for (link = ss->active_resources;
+	   link && _JMPBUF_UNWINDS (env[0].__jmpbuf, link, demangle_ptr);
+	   link = link->thread.next)
+	if (_hurd_userlink_unlink (link))
+	  {
+	    if (link->cleanup == &_hurdsig_longjmp_from_handler)
+	      {
+		/* We are unwinding past another signal handler invocation.
+		   Just finish the cleanup for this (inner) one, and then
+		   swap SCP to restore to the outer context.  */
+		cleanup ();
+		scp = link->cleanup_data;
+	      }
+	    else
+	      (*link->cleanup) (link->cleanup_data, env, val);
+	  }
+
+#define sc_machine_thread_state paste(sc_,machine_thread_state)
+#define paste(a,b)	paste1(a,b)
+#define paste1(a,b)	a##b
+
+      /* There are no more unwind forms to be run!
+	 Now we can just have the sigreturn do the longjmp for us.  */
+      _hurd_longjmp_thread_state
+	((struct machine_thread_state *) &scp->sc_machine_thread_state,
+	 env, val);
+
+      /* Restore to the same current signal mask.  If sigsetjmp saved the
+	 mask, longjmp has already restored it as desired; if not, we
+	 should leave it as it is.  */
+      scp->sc_mask = ss->blocked;
+
+      /* sigreturn expects the link added by _hurd_setup_sighandler
+	 to still be there, but _longjmp_unwind removed it just before
+	 calling us.  Put it back now so sigreturn can find it.  */
+      link = (void *) &scp[1];
+      assert (! link->resource.next && ! link->resource.prevp);
+      assert (link->thread.next == ss->active_resources);
+      assert (link->thread.prevp == &ss->active_resources);
+      if (link->thread.next)
+	link->thread.next->thread.prevp = &link->thread.next;
+      ss->active_resources = link;
+
+      /* We must momentarily exit the critical section so that sigreturn
+	 does not get upset with us.  But we don't want signal handlers
+	 running right now, because we are presently in the bogus state of
+	 having run all the unwind forms back to ENV's frame, but our SP is
+	 still inside those unwound frames.  */
+      __spin_lock (&ss->lock);
+      __spin_unlock (&ss->critical_section_lock);
+      ss->blocked = ~(sigset_t) 0 & ~_SIG_CANT_MASK;
+      __spin_unlock (&ss->lock);
+
+      /* Restore to the modified signal context that now
+	 performs `longjmp (ENV, VAL)'.  */
+      __sigreturn (scp);
+      assert (! "sigreturn returned!");
+    }
+
+  /* We are not unwinding off the alternate signal stack.  So nothing
+     really funny is going on here.  We can just clean up this handler
+     frame and let _longjmp_unwind continue unwinding.  */
+  cleanup ();
+  ss->intr_port = scp->sc_intr_port;
+}
diff --git a/REORG.TODO/hurd/task2pid.c b/REORG.TODO/hurd/task2pid.c
new file mode 100644
index 0000000000..86c5c659f8
--- /dev/null
+++ b/REORG.TODO/hurd/task2pid.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+
+pid_t
+__task2pid (task_t task)
+{
+  error_t err;
+  pid_t pid;
+  err = __USEPORT (PROC, __proc_task2pid (port, task, &pid));
+  return err ? (pid_t) __hurd_fail (err) : pid;
+}
+
+weak_alias (__task2pid, task2pid)
diff --git a/REORG.TODO/hurd/thread-cancel.c b/REORG.TODO/hurd/thread-cancel.c
new file mode 100644
index 0000000000..722b6adc74
--- /dev/null
+++ b/REORG.TODO/hurd/thread-cancel.c
@@ -0,0 +1,100 @@
+/* Thread cancellation support.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/signal.h>
+#include <hurd/interrupt.h>
+#include <assert.h>
+#include <thread_state.h>
+
+
+/* See hurdsig.c.  */
+extern mach_port_t _hurdsig_abort_rpcs (struct hurd_sigstate *ss,
+					int signo, int sigthread,
+					struct machine_thread_all_state *,
+					int *state_change,
+					mach_port_t *reply_port,
+					mach_msg_type_name_t reply_port_type,
+					int untraced);
+
+error_t
+hurd_thread_cancel (thread_t thread)
+{
+  struct hurd_sigstate *ss = _hurd_thread_sigstate (thread);
+  struct machine_thread_all_state state;
+  int state_change;
+  error_t err;
+
+  if (! ss)
+    return EINVAL;
+  if (ss == _hurd_self_sigstate ())
+    {
+      /* We are cancelling ourselves, so it is easy to succeed
+	 quickly.  Since this function is not a cancellation point, we
+	 just leave the flag set pending the next cancellation point
+	 (hurd_check_cancel or RPC) and return success.  */
+      ss->cancel = 1;
+      return 0;
+    }
+
+  assert (! __spin_lock_locked (&ss->critical_section_lock));
+  __spin_lock (&ss->critical_section_lock);
+  __spin_lock (&ss->lock);
+  err = __thread_suspend (thread);
+  __spin_unlock (&ss->lock);
+
+  if (! err)
+    {
+      /* Set the flag telling the thread its operation is being cancelled.  */
+      ss->cancel = 1;
+
+      /* Interrupt any interruptible RPC now in progress.  */
+      state.set = 0;
+      _hurdsig_abort_rpcs (ss, 0, 0, &state, &state_change, NULL, 0, 0);
+      if (state_change)
+	err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
+				  (natural_t *) &state.basic,
+				  MACHINE_THREAD_STATE_COUNT);
+
+      if (ss->cancel_hook)
+	/* The code being cancelled has a special wakeup function.
+	   Calling this should make the thread wake up and check the
+	   cancellation flag.  */
+	(*ss->cancel_hook) ();
+
+      __thread_resume (thread);
+    }
+
+  _hurd_critical_section_unlock (ss);
+  return err;
+}
+
+
+int
+hurd_check_cancel (void)
+{
+  struct hurd_sigstate *ss = _hurd_self_sigstate ();
+  int cancel;
+
+  __spin_lock (&ss->lock);
+  assert (! __spin_lock_locked (&ss->critical_section_lock));
+  cancel = ss->cancel;
+  ss->cancel = 0;
+  __spin_unlock (&ss->lock);
+
+  return cancel;
+}
diff --git a/REORG.TODO/hurd/thread-self.c b/REORG.TODO/hurd/thread-self.c
new file mode 100644
index 0000000000..3532caff91
--- /dev/null
+++ b/REORG.TODO/hurd/thread-self.c
@@ -0,0 +1,25 @@
+/* Cheap function to get current thread from sigstate without a syscall.
+   Copyright (C) 1995-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd/signal.h>
+
+thread_t
+hurd_thread_self (void)
+{
+  return _hurd_self_sigstate ()->thread;
+}
diff --git a/REORG.TODO/hurd/trampoline.c b/REORG.TODO/hurd/trampoline.c
new file mode 100644
index 0000000000..e506fd8c96
--- /dev/null
+++ b/REORG.TODO/hurd/trampoline.c
@@ -0,0 +1,36 @@
+/* Set thread_state for sighandler, and sigcontext to recover.  Stub version.
+   Copyright (C) 1994-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <mach/thread_status.h>
+
+/* Set up STATE to run a signal handler in the thread it describes.
+   This should save the original state in a `struct sigcontext' on the
+   thread's stack (or possibly a signal stack described by SIGALTSTACK,
+   if the SA_ONSTACK bit is set in FLAGS), and return the address of
+   that structure.  */
+
+struct sigcontext *
+_hurd_setup_sighandler (int flags,
+			__sighandler_t handler,
+			stack_t *sigaltstack,
+			int signo, int sigcode,
+			void *state)
+{
+#error "Need to write sysdeps/mach/hurd/MACHINE/trampoline.c"
+}
diff --git a/REORG.TODO/hurd/vpprintf.c b/REORG.TODO/hurd/vpprintf.c
new file mode 100644
index 0000000000..82cdadd5c7
--- /dev/null
+++ b/REORG.TODO/hurd/vpprintf.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <hurd.h>
+
+#include <libioP.h>
+
+static ssize_t
+do_write (void *cookie,	const char *buf, size_t n)
+{
+  error_t error = __io_write ((io_t) cookie, buf, n, -1,
+			      (mach_msg_type_number_t *) &n);
+  if (error)
+    return __hurd_fail (error);
+  return n;
+}
+
+/* Write formatted output to PORT, a Mach port supporting the i/o protocol,
+   according to the format string FORMAT, using the argument list in ARG.  */
+int
+vpprintf (io_t port, const char *format, va_list arg)
+{
+  int done;
+
+  struct locked_FILE
+  {
+    struct _IO_cookie_file cfile;
+#ifdef _IO_MTSAFE_IO
+    _IO_lock_t lock;
+#endif
+  } temp_f;
+#ifdef _IO_MTSAFE_IO
+  temp_f.cfile.__fp.file._lock = &temp_f.lock;
+#endif
+
+  _IO_cookie_init (&temp_f.cfile, _IO_NO_READS,
+		   (void *) port, (cookie_io_functions_t) { write: do_write });
+
+  done = _IO_vfprintf (&temp_f.cfile.__fp.file, format, arg);
+
+  return done;
+}
diff --git a/REORG.TODO/hurd/xattr.c b/REORG.TODO/hurd/xattr.c
new file mode 100644
index 0000000000..7deef291b4
--- /dev/null
+++ b/REORG.TODO/hurd/xattr.c
@@ -0,0 +1,200 @@
+/* Support for *xattr interfaces on GNU/Hurd.
+   Copyright (C) 2006-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <hurd.h>
+#include <hurd/xattr.h>
+#include <string.h>
+#include <sys/mman.h>
+
+/* Right now we support only a fixed set of xattr names for Hurd features.
+   There are no RPC interfaces for free-form xattr names and values.
+
+   Name			Value encoding
+   ----			----- --------
+   gnu.author		empty if st_author==st_uid
+			uid_t giving st_author value
+   gnu.translator	empty if no passive translator
+			translator and arguments: "/hurd/foo\0arg1\0arg2\0"
+*/
+
+error_t
+_hurd_xattr_get (io_t port, const char *name, void *value, size_t *size)
+{
+  if (strncmp (name, "gnu.", 4))
+    return EOPNOTSUPP;
+  name += 4;
+
+  if (!strcmp (name, "author"))
+    {
+      struct stat64 st;
+      error_t err = __io_stat (port, &st);
+      if (err)
+	return err;
+      if (st.st_author == st.st_uid)
+	*size = 0;
+      else if (value)
+	{
+	  if (*size < sizeof st.st_author)
+	    return ERANGE;
+	  memcpy (value, &st.st_author, sizeof st.st_author);
+	}
+      *size = sizeof st.st_author;
+      return 0;
+    }
+
+  if (!strcmp (name, "translator"))
+    {
+      char *buf = value;
+      size_t bufsz = value ? *size : 0;
+      error_t err = __file_get_translator (port, &buf, &bufsz);
+      if (err)
+	return err;
+      if (value != NULL && *size < bufsz)
+	{
+	  if (buf != value)
+	    munmap (buf, bufsz);
+	  return -ERANGE;
+	}
+      if (buf != value && bufsz > 0)
+	{
+	  if (value != NULL)
+	    memcpy (value, buf, bufsz);
+	  munmap (buf, bufsz);
+	}
+      *size = bufsz;
+      return 0;
+    }
+
+  return EOPNOTSUPP;
+}
+
+error_t
+_hurd_xattr_set (io_t port, const char *name, const void *value, size_t size,
+		 int flags)
+{
+  if (strncmp (name, "gnu.", 4))
+    return EOPNOTSUPP;
+  name += 4;
+
+  if (!strcmp (name, "author"))
+    switch (size)
+      {
+      default:
+	return EINVAL;
+      case 0:			/* "Clear" author by setting to st_uid. */
+	{
+	  struct stat64 st;
+	  error_t err = __io_stat (port, &st);
+	  if (err)
+	    return err;
+	  if (st.st_author == st.st_uid)
+	    {
+	      /* Nothing to do.  */
+	      if (flags & XATTR_REPLACE)
+		return ENODATA;
+	      return 0;
+	    }
+	  if (flags & XATTR_CREATE)
+	    return EEXIST;
+	  return __file_chauthor (port, st.st_uid);
+	}
+      case sizeof (uid_t):	/* Set the author.  */
+	{
+	  uid_t id;
+	  memcpy (&id, value, sizeof id);
+	  if (flags & (XATTR_CREATE|XATTR_REPLACE))
+	    {
+	      struct stat64 st;
+	      error_t err = __io_stat (port, &st);
+	      if (err)
+		return err;
+	      if (st.st_author == st.st_uid)
+		{
+		  if (flags & XATTR_REPLACE)
+		    return ENODATA;
+		}
+	      else if (flags & XATTR_CREATE)
+		return EEXIST;
+	      if (st.st_author == id)
+		/* Nothing to do.  */
+		return 0;
+	    }
+	  return __file_chauthor (port, id);
+	}
+      }
+
+  if (!strcmp (name, "translator"))
+    {
+      if (flags & XATTR_REPLACE)
+	{
+	  /* Must make sure it's already there.  */
+	  char *buf = NULL;
+	  size_t bufsz = 0;
+	  error_t err = __file_get_translator (port, &buf, &bufsz);
+	  if (err)
+	    return err;
+	  if (bufsz > 0)
+	    {
+	      munmap (buf, bufsz);
+	      return ENODATA;
+	    }
+	}
+      return __file_set_translator (port,
+				    FS_TRANS_SET | ((flags & XATTR_CREATE)
+						    ? FS_TRANS_EXCL : 0), 0, 0,
+				    value, size,
+				    MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+    }
+
+  return EOPNOTSUPP;
+}
+
+error_t
+_hurd_xattr_remove (io_t port, const char *name)
+{
+  return _hurd_xattr_set (port, name, NULL, 0, XATTR_REPLACE);
+}
+
+error_t
+_hurd_xattr_list (io_t port, void *buffer, size_t *size)
+{
+  size_t total = 0;
+  char *bufp = buffer;
+  inline void add (const char *name, size_t len)
+    {
+      total += len;
+      if (bufp != NULL && total <= *size)
+	bufp = __mempcpy (bufp, name, len);
+    }
+#define add(s) add (s, sizeof s)
+
+  struct stat64 st;
+  error_t err = __io_stat (port, &st);
+  if (err)
+    return err;
+
+  if (st.st_author != st.st_uid)
+    add ("gnu.author");
+  if (st.st_mode & S_IPTRANS)
+    add ("gnu.translator");
+
+  if (buffer != NULL && total > *size)
+    return ERANGE;
+  *size = total;
+  return 0;
+}