about summary refs log tree commit diff
path: root/hurd
diff options
context:
space:
mode:
Diffstat (limited to 'hurd')
-rw-r--r--hurd/.cvsignore4
-rw-r--r--hurd/Makefile117
-rw-r--r--hurd/Notes37
-rw-r--r--hurd/STATUS72
-rw-r--r--hurd/alloc-fd.c127
-rw-r--r--hurd/catch-exc.c78
-rw-r--r--hurd/ctty-input.c77
-rw-r--r--hurd/ctty-output.c82
-rw-r--r--hurd/dtable.c277
-rw-r--r--hurd/fchroot.c43
-rw-r--r--hurd/fd-close.c46
-rw-r--r--hurd/fd-read.c49
-rw-r--r--hurd/fd-write.c42
-rw-r--r--hurd/fopenport.c131
-rw-r--r--hurd/getdport.c54
-rw-r--r--hurd/getuids.c63
-rw-r--r--hurd/getumask.c25
-rw-r--r--hurd/hurd-raise.c48
-rw-r--r--hurd/hurd.h292
-rw-r--r--hurd/hurd/fd.h222
-rw-r--r--hurd/hurd/id.h55
-rw-r--r--hurd/hurd/ioctl.h71
-rw-r--r--hurd/hurd/port.h152
-rw-r--r--hurd/hurd/resource.h50
-rw-r--r--hurd/hurd/signal.h391
-rw-r--r--hurd/hurd/threadvar.h107
-rw-r--r--hurd/hurd/userlink.h105
-rw-r--r--hurd/hurdauth.c130
-rw-r--r--hurd/hurdexec.c259
-rw-r--r--hurd/hurdfault.c143
-rw-r--r--hurd/hurdfault.h49
-rw-r--r--hurd/hurdid.c91
-rw-r--r--hurd/hurdinit.c193
-rw-r--r--hurd/hurdinline.c11
-rw-r--r--hurd/hurdintr.awk25
-rw-r--r--hurd/hurdioctl.c264
-rw-r--r--hurd/hurdkill.c84
-rw-r--r--hurd/hurdlookup.c381
-rw-r--r--hurd/hurdmalloc.c411
-rw-r--r--hurd/hurdmalloc.h17
-rw-r--r--hurd/hurdmsg.c451
-rw-r--r--hurd/hurdpid.c71
-rw-r--r--hurd/hurdports.c52
-rw-r--r--hurd/hurdprio.c87
-rw-r--r--hurd/hurdrlimit.c50
-rw-r--r--hurd/hurdsig.c1080
-rw-r--r--hurd/hurdsock.c115
-rw-r--r--hurd/intern-fd.c50
-rw-r--r--hurd/intr-rpc.awk45
-rw-r--r--hurd/intr-rpc.defs27
-rw-r--r--hurd/invoke-trans.c37
-rw-r--r--hurd/msgportdemux.c66
-rw-r--r--hurd/msgstub.c26
-rw-r--r--hurd/new-fd.c39
-rw-r--r--hurd/openport.c29
-rw-r--r--hurd/pid2task.c32
-rw-r--r--hurd/port2fd.c75
-rw-r--r--hurd/ports-get.c46
-rw-r--r--hurd/ports-set.c57
-rw-r--r--hurd/preempt-sig.c68
-rw-r--r--hurd/privports.c60
-rw-r--r--hurd/setauth.c124
-rw-r--r--hurd/setuids.c59
-rw-r--r--hurd/siginfo.c27
-rw-r--r--hurd/task2pid.c30
-rw-r--r--hurd/vpprintf.c60
66 files changed, 7738 insertions, 0 deletions
diff --git a/hurd/.cvsignore b/hurd/.cvsignore
new file mode 100644
index 0000000000..1f69fd919a
--- /dev/null
+++ b/hurd/.cvsignore
@@ -0,0 +1,4 @@
+*.gz *.Z *.tar *.tgz
+=*
+TODO COPYING* AUTHORS copyr-* copying.*
+glibc-*
diff --git a/hurd/Makefile b/hurd/Makefile
new file mode 100644
index 0000000000..7a5a1ba995
--- /dev/null
+++ b/hurd/Makefile
@@ -0,0 +1,117 @@
+# Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License
+# as published by the Free Software Foundation; either version 2 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public
+# License along with the GNU C Library; see the file COPYING.LIB.  If
+# not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+# Cambridge, MA 02139, USA.
+
+subdir := hurd
+
+all:
+
+# Some things below (but before including Rules) use configuration variables.
+include ../Makeconfig
+
+
+headers = hurd.h $(interface-headers) \
+	  $(addprefix hurd/,fd.h id.h port.h signal.h userlink.h \
+		            resource.h threadvar.h)
+
+distribute := hurdfault.h intr-rpc.awk intr-rpc.defs STATUS
+
+# The RPC interfaces go in a separate library.
+interface-library := libhurduser.a
+user-interfaces		:= $(addprefix hurd/,\
+				       auth process startup \
+				       msg msg_reply msg_request \
+				       exec core interrupt \
+				       fs fsys io term socket ifsock)
+server-interfaces	:= hurd/msg
+
+routines = hurdinit hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \
+	   setauth \
+	   pid2task task2pid \
+	   getuids setuids getumask fchroot \
+	   hurdsock hurdauth invoke-trans \
+	   privports \
+	   msgportdemux \
+	   fopenport \
+ 	   vpprintf \
+	   ports-get ports-set hurdports hurdmsg \
+	   $(sig) $(dtable) hurdinline
+sig	= hurdsig hurdfault faultexc siginfo hurd-raise preempt-sig \
+	  trampoline longjmp-ts catch-exc exc2signal hurdkill
+dtable	= dtable port2fd new-fd alloc-fd intern-fd \
+	  getdport openport \
+	  fd-close fd-read fd-write hurdioctl ctty-input ctty-output
+
+# XXX this is a temporary hack; see hurdmalloc.h
+routines += hurdmalloc
+distribute += hurdmalloc.h
+
+# Get the proper definition of `hurd-srcdir'.
+include ../sysdeps/mach/hurd/Makefile
+
+# Use and install the Hurd header files directly out of the Hurd source.
+
+# Find the MiG defs files in the Hurd source.
+vpath %.defs $(hurd-srcdir)
+
+# Install all .h and .defs files we find in the Hurd's hurd/ directory.
+hurd-headers := $(patsubst $(hurd-srcdir)/%,%,\
+			   $(wildcard $(addprefix $(hurd-srcdir)/hurd/,\
+						  *.defs *.h)))
+
+
+# Don't distribute the Hurd headers; they are in the Hurd distribution.
+dont_distribute = $(hurd-headers)
+
+# DO NOT try to remake these in any way!!!
+$(addprefix $(hurd-srcdir)/,$(hurd-headers)) : ;
+install-others += $(addprefix $(includedir)/,$(hurd-headers))
+$(includedir)/hurd/%: $(hurd-srcdir)/hurd/%; $(do-install)
+
+include ../mach/Machrules
+include ../Rules
+
+# intr-rpc.defs defines the INTR_INTERFACE macro to make the generated RPC
+# stubs send-interruptible, and to prefix them with `hurd_intr_rpc_'.
+user-MIGFLAGS += -imacros intr-rpc.defs
+
+# Run each generated user stub through intr-rpc.awk, which will detect
+# stubs __hurd_intr_rpc_% and generate the user-callable function for the
+# stub: this is a wrapper which calls __hurd_intr_rpc_% inside
+# HURD_EINTR_RPC.
+define transform-user-stub
+gawk -v call=$${call} -f $(word 2,$^) \
+	$(objpfx)tmp_$${call}.c > $(objpfx)tmpi_$${call}.c; \
+rm -f $(objpfx)tmp_$${call}.c;
+endef
+transform-user-stub-output = tmpi
+
+$(foreach if,$(user-interfaces),$($(if)-calls:%=$(objpfx)RPC_%.o))): \
+	hurd/signal.h
+
+$(user-interfaces:%=$(objpfx)%.ustamp): intr-rpc.awk
+
+$(objpfx)fault%.c $(objpfx)fault%.h: $(mach-srcdir)/mach/%.defs
+	$(MIG) $(MIGFLAGS) -prefix _hurdsig_fault_ \
+	       -server $(@:.h=.c) -sheader $(@:.c=.h) \
+	       -user /dev/null -header /dev/null \
+	       $<
+generated += faultexc.c faultexc.h
+
+# We need this static dependency to get faultexc.h generated the first time.
+$(objpfx)hurdfault.o $(objpfx)hurdfault.d: \
+	$(objpfx)faultexc.h $(objpfx)faultexc.c
diff --git a/hurd/Notes b/hurd/Notes
new file mode 100644
index 0000000000..9052f29096
--- /dev/null
+++ b/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/hurd/STATUS b/hurd/STATUS
new file mode 100644
index 0000000000..ceb0a865d0
--- /dev/null
+++ b/hurd/STATUS
@@ -0,0 +1,72 @@
+Status of Hurd support in libc.  Last updated 22 Nov 1994.
+Roland McGrath <roland@gnu.ai.mit.edu>
+
+Everything not noted below is implemented, most of it tested.  There are
+various very small things unfinished or thought to be perhaps wrong
+throughout the code, marked by comments containing `XXX'.
+
+
+* Signals and job control work, but are a very hairy area.
+  There are various ways the signal thread can block and fail
+  to respond when the program is losing badly.
+
+* We are not sure about possible races between setpgrp (A, pgrp) from
+  process B vs process A receiving proc_newids.
+
+* The rest of libc (stdio et al) is not safe for multithreaded programs.
+  mutex locks should be added to various things.
+
+* Recovery from faults in the signal thread is not implemented yet.
+
+* longjmp needs to clean up reply port, intr_port; needs thought about.
+
+* Cooperation with cthreads is not finished.  If you link with cthreads,
+  libc internal code still does not use real condition variables.
+  sigsuspend currently does a busy wait where it should use a condition.
+  Signal state is per kernel thread; for unwired cthreads it should be per
+  cthread instead.
+
+* sigaltstack/sigstack do not really work: the signal stack needs thread
+  variables and cthread data set up, which is not done.
+
+* malloc is a kludge.
+
+* Nothing uses mapped io.  Eventually stdio and read/write/seek should.  I
+  have written a little code for this, but it is far from finished.
+
+* Resource limits do not really work; current implementation is patchy and
+  inconsistent.
+
+* libc implicitly uses some environment variables.  This is a security
+  problem for setuid exec.  Probably crt0 should remove the variables from
+  the environment if setuid.
+
+* The miscellaneous msg.defs calls are only partially implemented.
+
+* The default SIGINFO handler needs to be written.
+
+* File locking is not implemented; the RPC interface is not there yet.
+
+* The current getitimer/setitimer implementation is a kludge.
+
+* mmap cannot do MAP_NOEXTEND.
+
+* Unimplemented calls (from the 4.4 system call list):
+acct
+fstatfs
+getfh
+getfsstat
+getrusage
+madvise
+mincore
+mount
+msync
+profil
+recvmsg
+revoke
+sendmsg
+setpriority
+sstk
+statfs
+swapon
+unmount
diff --git a/hurd/alloc-fd.c b/hurd/alloc-fd.c
new file mode 100644
index 0000000000..02a1bdfd52
--- /dev/null
+++ b/hurd/alloc-fd.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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).
+	     If there isn't any at all, give it three slots (because
+	     stdio will take that many anyway).  */
+	  int size = _hurd_dtablesize ? _hurd_dtablesize * 2 : 3;
+	  if (size > rlimit)
+	    size = rlimit;
+	  /* 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-- > _hurd_dtablesize);
+	  if (new != NULL)
+	    {
+	      /* We managed to allocate a new table.  Now install it.  */
+	      errno = save;
+	      first_fd = _hurd_dtablesize;
+	      /* Initialize the new slots.  */
+	      for (i = first_fd; 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 = EMFILE;
+    }
+  else
+    errno = EINVAL;		/* Bogus FIRST_FD value.  */
+
+  __mutex_unlock (&_hurd_dtable_lock);
+  _hurd_critical_section_unlock (crit);
+
+  return NULL;
+}
diff --git a/hurd/catch-exc.c b/hurd/catch-exc.c
new file mode 100644
index 0000000000..72e06db1d3
--- /dev/null
+++ b/hurd/catch-exc.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <mach/exc_server.h>
+#include <hurd/signal.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,
+			  int exception,
+			  int code,
+			  int subcode)
+{
+  int signo, error;
+  long int sigcode;
+  struct hurd_sigstate *ss;
+
+  if (task != __mach_task_self ())
+    /* The sender wasn't the kernel.  */
+    return EPERM;
+
+  /* Call the machine-dependent function to translate the Mach exception
+     codes into a signal number and subcode.  */
+  _hurd_exception2signal (exception, code, subcode,
+			  &signo, &sigcode, &error);
+
+  /* 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.  */
+
+      ss->critical_section = 0;
+      ss->context = NULL;
+      __spin_unlock (&ss->lock);
+    }
+
+  /* Post the signal.  */
+  _hurd_internal_post_signal (ss, signo, sigcode, error,
+			      MACH_PORT_NULL, MACH_MSG_TYPE_PORT_SEND,
+			      0);
+
+  return KERN_SUCCESS;
+}
diff --git a/hurd/ctty-input.c b/hurd/ctty-input.c
new file mode 100644
index 0000000000..71aef1b6cf
--- /dev/null
+++ b/hurd/ctty-input.c
@@ -0,0 +1,77 @@
+/* _hurd_ctty_input -- Do an input RPC and generate SIGTTIN if necessary.
+Copyright (C) 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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;
+
+  do
+    {
+      err = (*rpc) (ctty != MACH_PORT_NULL ? ctty : port);
+      if (ctty != MACH_PORT_NULL && err == EBACKGROUND)
+	{
+	  /* We are a background job and tried to read from the tty.
+	     We should probably get a SIGTTIN signal.  */
+	  struct hurd_sigstate *ss;
+	  if (_hurd_orphaned)
+	    /* Our process group is orphaned.  Don't stop; just fail.  */
+	    err = EIO;
+	  else
+	    {
+	      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/hurd/ctty-output.c b/hurd/ctty-output.c
new file mode 100644
index 0000000000..0d9c54383d
--- /dev/null
+++ b/hurd/ctty-output.c
@@ -0,0 +1,82 @@
+/* _hurd_ctty_output -- Do an output RPC and generate SIGTTOU if necessary.
+Copyright (C) 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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))
+{
+  error_t err;
+  struct hurd_sigstate *ss;
+  io_t ioport;
+
+  /* Don't use the ctty io port if we are blocking or ignoring SIGTTOU.  */
+  if (ctty == MACH_PORT_NULL)
+    ioport = port;
+  else
+    {
+      ss = _hurd_self_sigstate ();
+      __spin_lock (&ss->lock);
+      if (__sigismember (&ss->blocked, SIGTTOU) ||
+	  ss->actions[SIGTTOU].sa_handler == SIG_IGN)
+	ioport = port;
+      else
+	ioport = ctty;
+      __spin_unlock (&ss->lock);
+    }
+
+  do
+    {
+      err = (*rpc) (ioport);
+      if (ioport == ctty && 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/hurd/dtable.c b/hurd/dtable.c
new file mode 100644
index 0000000000..3e785a9710
--- /dev/null
+++ b/hurd/dtable.c
@@ -0,0 +1,277 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#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)
+{
+  register size_t 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; 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)
+{
+  file_t dport;
+  int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (),
+						      (dport = port),
+						      MACH_PORT_RIGHT_SEND,
+						      1));
+  if (err)
+    {
+      errno = err;
+      return MACH_PORT_NULL;
+    }
+  else
+    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);
+
+  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,
+			d->port.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,
+			    d->ctty.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/hurd/fchroot.c b/hurd/fchroot.c
new file mode 100644
index 0000000000..cccf1391be
--- /dev/null
+++ b/hurd/fchroot.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1991, 1992, 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+
+/* Change the current root directory to FD.  */
+int
+DEFUN(fchroot, (fd), int fd)
+{
+  error_t err;
+  file_t dir;
+
+  err = __USEPORT (CRDIR,
+		   ({ file_t crdir = port;
+		      HURD_DPORT_USE (fd,
+				      __hurd_file_name_lookup (crdir, port, "",
+							       0, 0, &dir));
+		    }));
+
+  if (err)
+    return __hurd_fail (err);
+
+  _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], dir);
+  return 0;
+}
diff --git a/hurd/fd-close.c b/hurd/fd-close.c
new file mode 100644
index 0000000000..54beb2a09a
--- /dev/null
+++ b/hurd/fd-close.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/fd-read.c b/hurd/fd-read.c
new file mode 100644
index 0000000000..842066c150
--- /dev/null
+++ b/hurd/fd-read.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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)
+{
+  error_t err;
+  char *data;
+  mach_msg_type_number_t nread;
+
+  error_t readfd (io_t port)
+    {
+      return __io_read (port, &data, &nread, -1, *nbytes);
+    }
+
+  data = buf;
+  if (err = HURD_FD_PORT_USE (fd, _hurd_ctty_input (port, ctty, readfd)))
+    return err;
+
+  if (data != buf)
+    {
+      memcpy (buf, data, nread);
+      __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
+    }
+
+  *nbytes = nread;
+  return 0;
+}
diff --git a/hurd/fd-write.c b/hurd/fd-write.c
new file mode 100644
index 0000000000..f228d5e47c
--- /dev/null
+++ b/hurd/fd-write.c
@@ -0,0 +1,42 @@
+/* _hurd_fd_write -- write to a file descriptor; handles job control et al.
+Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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)
+{
+  error_t err;
+  mach_msg_type_number_t wrote;
+
+  error_t writefd (io_t port)
+    {
+      return __io_write (port, buf, *nbytes, -1, &wrote);
+    }
+
+  err = HURD_FD_PORT_USE (fd, _hurd_ctty_output (port, ctty, writefd));
+
+  if (! err)
+    *nbytes = wrote;
+
+  return err;
+}
diff --git a/hurd/fopenport.c b/hurd/fopenport.c
new file mode 100644
index 0000000000..5792b3e26e
--- /dev/null
+++ b/hurd/fopenport.c
@@ -0,0 +1,131 @@
+/* Copyright (C) 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#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, fpos_t *pos, int whence)
+{
+  error_t error = __io_seek ((file_t) cookie, *pos, whence, pos);
+  if (error)
+    return __hurd_fail (error);
+  return 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;
+}
+
+static const __io_functions funcsio = { readio, writeio, seekio, closeio };
+
+
+/* Defined in fopen.c.  */
+extern int EXFUN(__getmode, (CONST char *mode, __io_mode *mptr));
+
+
+/* Open a stream on PORT.  MODE is as for fopen.  */
+
+FILE *
+__fopenport (mach_port_t port, const char *mode)
+{
+  register FILE *stream;
+  __io_mode m;
+  int pflags;
+  error_t err;
+
+  if (!__getmode (mode, &m))
+    return NULL;
+
+  /* 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 ((m.__read && !(pflags & O_READ)) || (m.__write && !(pflags & O_WRITE)))
+    {
+      errno = EBADF;
+      return NULL;
+    }
+
+  stream = __newstream ();
+  if (stream == NULL)
+    return NULL;
+
+  stream->__cookie = (PTR) port;
+  stream->__mode = m;
+  stream->__io_funcs = funcsio;
+  stream->__room_funcs = __default_room_functions;
+  stream->__seen = 1;
+
+  return stream;
+}
+
+weak_alias (__fopenport, fopenport)
diff --git a/hurd/getdport.c b/hurd/getdport.c
new file mode 100644
index 0000000000..884deaa868
--- /dev/null
+++ b/hurd/getdport.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1991, 1992, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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.  */
+file_t (*_hurd_getdport_fn) (int fd);
+
+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.  */
+    return EBADF;
+
+  if (fd < 0 || 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/hurd/getuids.c b/hurd/getuids.c
new file mode 100644
index 0000000000..9a62f65611
--- /dev/null
+++ b/hurd/getuids.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <hurd/id.h>
+#include <string.h>
+
+int
+__getuids (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;
+}
diff --git a/hurd/getumask.c b/hurd/getumask.c
new file mode 100644
index 0000000000..80a8bf4590
--- /dev/null
+++ b/hurd/getumask.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1992 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+
+mode_t
+getumask (void)
+{
+  return _hurd_umask;
+}
diff --git a/hurd/hurd-raise.c b/hurd/hurd-raise.c
new file mode 100644
index 0000000000..ad01ab9f89
--- /dev/null
+++ b/hurd/hurd-raise.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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.  */
+
+void
+_hurd_raise_signal (struct hurd_sigstate *ss,
+		    int signo, long int sigcode, int sigerror)
+{
+  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].code = sigcode;
+  ss->pending_data[signo].error = sigerror;
+
+  __spin_unlock (&ss->lock);
+
+  /* Send a message to the signal thread so it
+     will wake up and check for pending signals.  */
+  __msg_sig_post (_hurd_msgport, 0, __mach_task_self ());
+}
diff --git a/hurd/hurd.h b/hurd/hurd.h
new file mode 100644
index 0000000000..472fb9173b
--- /dev/null
+++ b/hurd/hurd.h
@@ -0,0 +1,292 @@
+/* Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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>
+#define	__hurd_fail(err)	(errno = (err), -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 volatile mode_t _hurd_umask;
+
+/* Shorthand macro for referencing _hurd_ports (see <hurd/port.h>).  */
+
+#define	__USEPORT(which, expr) \
+  HURD_PORT_USE (&_hurd_ports[INIT_PORT_##which], (expr))
+
+
+/* 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.  */
+
+unsigned int _hurd_pids_changed_stamp;
+
+/* This condition is broadcast every time the process IDs change.  */
+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);
+
+#define __need_FILE
+#include <stdio.h>
+
+/* Calls to get and set basic ports.  */
+
+extern error_t _hurd_ports_get (int which, mach_port_t *result);
+extern error_t _hurd_ports_set (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 ();
+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);
+
+
+/* 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.  The directory lookup
+   uses CRDIR for the root directory and CWDIR for the current directory.
+   Returns zero on success or an error code.  */
+
+extern error_t __hurd_file_name_split (file_t crdir, file_t cwdir,
+				       const char *file,
+				       file_t *dir, char **name);
+extern error_t hurd_file_name_split (file_t crdir, file_t cwdir,
+				     const char *file,
+				     file_t *dir, char **name);
+
+/* Open a port to FILE with the given FLAGS and MODE (see <fcntl.h>).
+   The file lookup uses CRDIR for the root directory and CWDIR for the
+   current directory.  If successful, returns zero and store the port
+   to FILE in *PORT; otherwise returns an error code. */
+
+extern error_t __hurd_file_name_lookup (file_t crdir, file_t cwdir,
+					const char *file,
+					int flags, mode_t mode,
+					file_t *port);
+extern error_t hurd_file_name_lookup (file_t crdir, file_t cwdir,
+				      const char *filename,
+				      int flags, mode_t mode,
+				      file_t *port);
+
+/* Process the values returned by `dir_lookup' et al, and loop doing
+   `dir_lookup' calls until one returns FS_RETRY_NONE.  CRDIR is the
+   root directory used for things like symlinks to absolute file names; the
+   other 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.  */
+
+extern error_t __hurd_file_name_lookup_retry (file_t crdir,
+					      enum retry_type doretry,
+					      char retryname[1024],
+					      int flags, mode_t mode,
+					      file_t *result);
+extern error_t hurd_file_name_lookup_retry (file_t crdir,
+					    enum retry_type doretry,
+					    char retryname[1024],
+					    int flags, mode_t mode,
+					    file_t *result);
+
+
+/* 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);
+
+/* 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);
+
+/* Invoke any translator set on the node FILE represents, and return in
+   *TRANSLATED a port to the translated node.  FLAGS are as for
+   `dir_lookup' et al, but the returned port will not necessarily have
+   any more access rights than FILE does.  */
+
+extern error_t __hurd_invoke_translator (file_t file, int flags,
+					 file_t *translated);
+extern error_t hurd_invoke_translator (file_t file, int flags,
+				       file_t *translated);
+
+
+/* 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 exitted 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.  */
+
+extern void _hurd_proc_init (char **argv);
+
+
+/* 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 (host_priv_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 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);
+
+
+#endif	/* hurd.h */
diff --git a/hurd/hurd/fd.h b/hurd/hurd/fd.h
new file mode 100644
index 0000000000..4747c785a5
--- /dev/null
+++ b/hurd/hurd/fd.h
@@ -0,0 +1,222 @@
+/* File descriptors.
+Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_HURD_FD_H
+
+#define	_HURD_FD_H	1
+#include <features.h>
+
+#include <hurd/hurd_types.h>
+#include <hurd/port.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>
+#include <lock-intern.h>
+
+#ifndef _EXTERN_INLINE
+#define _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.  */
+
+_EXTERN_INLINE struct hurd_fd *
+_hurd_fd_get (int fd)
+{
+  struct hurd_fd *descriptor;
+
+  __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);
+
+  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.  */
+
+_EXTERN_INLINE error_t
+_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.  */   
+
+_EXTERN_INLINE error_t
+_hurd_fd_error (int fd, error_t err)
+{
+  int signo = _hurd_fd_error_signal (err);
+  if (signo)
+    _hurd_raise_signal (NULL, signo, fd, err);
+  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.  */
+
+_EXTERN_INLINE int
+__hurd_dfail (int fd, error_t err)
+{
+  errno = _hurd_fd_error (fd, 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 is 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 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);
+extern error_t _hurd_fd_write (struct hurd_fd *fd,
+			       const void *buf, size_t *nbytes);
+
+
+/* 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));
+
+
+#endif	/* hurd/fd.h */
diff --git a/hurd/hurd/id.h b/hurd/hurd/id.h
new file mode 100644
index 0000000000..7a50081038
--- /dev/null
+++ b/hurd/hurd/id.h
@@ -0,0 +1,55 @@
+/* User and group IDs.
+Copyright (C) 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/hurd/ioctl.h b/hurd/hurd/ioctl.h
new file mode 100644
index 0000000000..cc83433c17
--- /dev/null
+++ b/hurd/hurd/ioctl.h
@@ -0,0 +1,71 @@
+/* User-registered handlers for specific `ioctl' requests.
+Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_HURD_IOCTL_H
+#define	_HURD_IOCTL_H	1
+
+#define	__need___va_list
+#include <stdarg.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
+  {
+    int first_request, last_request; /* Range of handled request values.  */
+
+    /* 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(handler, first, last)			      \
+  static const struct ioctl_handler handler##_ioctl_handler =		      \
+    { (first), (last), (int (*) (int, int, void *)) (handler),	      \
+	(&(handler), &(handler##_ioctl_handler), NULL) };		      \
+  text_set_element (_hurd_ioctl_handler_lists, ##handler##_ioctl_handler)
+
+/* Define a library-internal handler for a single ioctl command.  */
+
+#define _HURD_HANDLE_IOCTL(handler, ioctl) \
+  _HURD_HANDLE_IOCTLS (handler, (ioctl), (ioctl))
+
+
+/* Lookup the handler for the given ioctl request.  */
+
+ioctl_handler_t _hurd_lookup_ioctl_handler (int request);
+
+
+#endif	/* hurd/ioctl.h */
diff --git a/hurd/hurd/port.h b/hurd/hurd/port.h
new file mode 100644
index 0000000000..a057503d4a
--- /dev/null
+++ b/hurd/hurd/port.h
@@ -0,0 +1,152 @@
+/* Lightweight user references for ports.
+Copyright (C) 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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 _EXTERN_INLINE
+#define _EXTERN_INLINE extern __inline
+#endif
+
+
+/* Initialize *PORT to INIT.  */
+
+_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;
+}
+
+
+/* Get a reference to *PORT, which is locked.
+   Pass return value and LINK to _hurd_port_free when done.  */
+
+_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)
+    _hurd_userlink_link (&port->users, link);
+  __spin_unlock (&port->lock);
+  return result;
+}
+
+/* Same, but locks PORT first.  */
+
+_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);' */
+
+_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.  */
+
+_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.  */
+
+_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/hurd/hurd/resource.h b/hurd/hurd/resource.h
new file mode 100644
index 0000000000..ad2a61ab42
--- /dev/null
+++ b/hurd/hurd/resource.h
@@ -0,0 +1,50 @@
+/* Resource limits for the Hurd.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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.  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));
+
+/* Convert between Mach priority values and the priority
+   values used by getpriority, setpriority, and nice.  */
+#define MACH_PRIORITY_TO_NICE(prio) (2 * ((prio) - 12))
+#define NICE_TO_MACH_PRIORITY(nice) (12 + ((nice) / 2))
+
+
+
+
+#endif
diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
new file mode 100644
index 0000000000..76007d5037
--- /dev/null
+++ b/hurd/hurd/signal.h
@@ -0,0 +1,391 @@
+/* Implementing POSIX.1 signals under the Hurd.
+Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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_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 <spin-lock.h>
+#include <hurd/threadvar.h>	/* We cache sigstate in a threadvar.  */
+
+
+/* Per-thread signal state.  */
+
+struct hurd_sigstate
+  {
+    spin_lock_t lock;		/* Locks most of the rest of the structure.  */
+
+    int critical_section;	/* Nonzero if in critical section.  */
+
+    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];
+    struct sigaltstack sigaltstack;
+    struct
+      {
+	/* For each signal that may be pending, the
+	   sigcode and error code to deliver it with.  */
+	long int code;
+	error_t error;
+      } 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;
+  };
+
+/* 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_INLINE struct hurd_sigstate *
+_hurd_self_sigstate (void)
+{
+  struct hurd_sigstate **location =
+    (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.  */
+
+_EXTERN_INLINE void *
+_hurd_critical_section_lock (void)
+{
+  struct hurd_sigstate **location =
+    (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; this locks the sigstate lock.  */
+    ss = *location = _hurd_thread_sigstate (__mach_thread_self ());
+  else
+    __spin_lock (&ss->lock);
+
+  if (ss->critical_section)
+    {
+      /* We are already in a critical section, so do nothing.  */
+      __spin_unlock (&ss->lock);
+      return NULL;
+    }
+
+  /* Set the critical section flag so no signal handler will run.  */
+  ss->critical_section = 1;
+  __spin_unlock (&ss->lock);
+
+  /* Return our sigstate pointer; this will be passed to
+     _hurd_critical_section_unlock to clear the critical section flag. */
+  return ss;
+}
+
+_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.  Clear the
+	 critical section flag.  */
+      struct hurd_sigstate *ss = our_lock;
+      sigset_t pending;
+      __spin_lock (&ss->lock);
+      ss->critical_section = 0;
+      pending = ss->pending & ~ss->blocked;
+      __spin_unlock (&ss->lock);
+      if (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, __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.  */
+
+extern void _hurdsig_init (void);
+
+/* Initialize proc server-assisted fault recovery for the signal thread.  */
+
+extern void _hurdsig_fault_init (void);
+
+/* Raise a signal as described by SIGNO, SIGCODE and SIGERROR, on the
+   thread whose sigstate SS points to.  If SS is a null pointer, this
+   instead affects the calling thread.  */
+
+extern void _hurd_raise_signal (struct hurd_sigstate *ss,
+				int signo, long int sigcode, int sigerror);
+
+/* Translate a Mach exception into a signal (machine-dependent).  */
+
+extern void _hurd_exception2signal (int exception, int code, int subcode,
+				    int *signo, long int *sigcode, int *error);
+
+
+/* Make the thread described by SS take the signal described by SIGNO and
+   SIGCODE.  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, long int sigcode, int error,
+					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, long int sigcode,
+			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);
+
+/* STATE describes a thread that had intr_port set (meaning it was inside
+   HURD_EINTR_RPC), after it has been thread_abort'd.  It it looks to have
+   just completed a mach_msg_trap system call that returned
+   MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right
+   being waited on.  */
+
+extern int _hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state,
+				       mach_port_t *port);
+
+/* 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);
+
+
+/* Function run for SIGINFO when its action is SIG_DFL and the current
+   process is the session leader.  */
+
+extern void _hurd_siginfo_handler (int);
+
+
+/* Perform interruptible RPC CALL on PORT.
+   The call should use 
+   The args in CALL should be constant or local variable refs.
+   They may be evaluated many times, and must not change.
+   PORT must not be deallocated before this RPC is finished.  */
+#define	HURD_EINTR_RPC(port, call)					      \
+  ({									      \
+    __label__ __do_call;	/* Give this label block scope.  */	      \
+    error_t __err;							      \
+    struct hurd_sigstate *__ss = _hurd_self_sigstate ();		      \
+    __do_call:								      \
+    /* 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 = (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.  */			      \
+    switch (__err = (call))						      \
+      {									      \
+      case EINTR:		/* RPC went out and was interrupted.  */      \
+      case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */		      \
+	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.  */			      \
+	  goto __do_call;						      \
+	/* FALLTHROUGH */						      \
+      case MACH_RCV_PORT_DIED:						      \
+	/* Server didn't respond to interrupt_operation,		      \
+	   so the signal thread destroyed the reply port.  */		      \
+	__err = EINTR;							      \
+	break;								      \
+      default:			/* Quiet -Wswitch-enum.  */		      \
+      }									      \
+    __ss->intr_port = MACH_PORT_NULL;					      \
+    __err;								      \
+  })									      \
+
+
+/* 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.  */					      \
+	if (__err = (fetch_msgport_expr))				      \
+	  break;							      \
+	/* Get the reference port.  */					      \
+	if (__err = (fetch_refport_expr))				      \
+	  {								      \
+	    /* Couldn't get it; deallocate MSGPORT and fail.  */	      \
+	    __mach_port_deallocate (__mach_task_self (), msgport);	      \
+	    break;							      \
+	  }								      \
+	__err = (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;								      \
+})
+
+/* Some other parts of the library need to preempt signals, to detect
+   errors that should not result in a POSIX signal.  For example, when
+   some mapped region of memory is used, an extraneous SIGSEGV might be
+   generated when the mapping server returns an error for a page fault.  */
+
+struct hurd_signal_preempt
+  {
+    /* Function to examine a thread receiving a given signal.  The handler
+       is called even for blocked signals.  This function is run in the
+       signal thread, with THREAD's sigstate locked; it should be as simple
+       and robust as possible.  THREAD is the thread which is about to
+       receive the signal.  SIGNO and SIGCODE would be passed to the normal
+       handler.
+
+       If the return value is SIG_DFL, normal signal processing continues.
+       If it is SIG_IGN, the signal is ignored.
+       Any other value is used in place of the normal handler.  */
+    sighandler_t (*handler) (thread_t thread,
+			     int signo, long int sigcode, int sigerror);
+    long int first, last;	/* Range of sigcodes this handler wants.  */
+    struct hurd_signal_preempt *next; /* Next handler on the chain. */
+  };
+
+extern struct hurd_signal_preempt *_hurd_signal_preempt[NSIG];
+extern struct mutex _hurd_signal_preempt_lock;
+
+
+#endif	/* hurd/signal.h */
diff --git a/hurd/hurd/threadvar.h b/hurd/hurd/threadvar.h
new file mode 100644
index 0000000000..eab133a2f6
--- /dev/null
+++ b/hurd/hurd/threadvar.h
@@ -0,0 +1,107 @@
+/* Internal per-thread variables for the Hurd.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _HURD_THREADVAR_H
+#define	_HURD_THREADVAR_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_MAX		/* Default value for __hurd_threadvar_max.  */
+  };
+
+
+#ifndef _EXTERN_INLINE
+#define _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_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_INLINE unsigned long int *
+__hurd_threadvar_location (enum __hurd_threadvar_index __index)
+{
+  return __hurd_threadvar_location_from_sp (__index,
+					    __thread_stack_pointer ());
+}
+
+/* Return the current thread's location for `errno'.
+   The syntax of this function allows redeclarations like `int errno'.  */
+_EXTERN_INLINE int *
+__hurd_errno_location (void)
+{
+  return (int *) __hurd_threadvar_location (_HURD_THREADVAR_ERRNO);
+}
+
+
+#endif	/* hurd/threadvar.h */
diff --git a/hurd/hurd/userlink.h b/hurd/hurd/userlink.h
new file mode 100644
index 0000000000..337d46aef6
--- /dev/null
+++ b/hurd/hurd/userlink.h
@@ -0,0 +1,105 @@
+/* Support for chains recording users of a resource; `struct hurd_userlink'.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_HURD_USERLINK_H
+
+#define	_HURD_USERLINK_H	1
+#include <features.h>
+
+#define __need_NULL
+#include <stddef.h>
+
+
+/* This structure is simply a doubly-linked 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) 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.  */
+
+struct hurd_userlink
+  {
+    struct hurd_userlink *next, **prevp;
+  };
+
+
+#ifndef _EXTERN_INLINE
+#define _EXTERN_INLINE extern __inline
+#endif
+
+
+/* Attach LINK to the chain of users at *CHAINP.  */
+
+_EXTERN_INLINE void
+_hurd_userlink_link (struct hurd_userlink **chainp,
+		     struct hurd_userlink *link)
+{
+  link->next = *chainp;
+  if (link->next)
+    link->next->prevp = &link->next;
+  link->prevp = chainp;
+  *chainp = link;
+}
+
+
+/* Detach LINK from its chain.  If the return value is nonzero, the caller
+   should deallocate the resource he started using after attaching LINK to
+   the chain it's on.  If the return value is zero, then someone else is
+   still using the resource.  */
+
+_EXTERN_INLINE int
+_hurd_userlink_unlink (struct hurd_userlink *link)
+{
+  /* The caller should deallocate the resource he used if his 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->next && ! link->prevp;
+
+  /* Remove our link from the chain of current users.  */
+  if (link->prevp)
+    *link->prevp = link->next;
+  if (link->next)
+    link->next->prevp = link->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.  */
+
+_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)->prevp = NULL;
+  *chainp = NULL;
+  return 0;
+}
+
+#endif	/* hurd/userlink.h */
diff --git a/hurd/hurdauth.c b/hurd/hurdauth.c
new file mode 100644
index 0000000000..db93fd6ec3
--- /dev/null
+++ b/hurd/hurdauth.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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;
+
+  if (err = __USEPORT (AUTH,
+		       __auth_makeauth (port,
+					&addauth, 1, MACH_MSG_TYPE_MOVE_SEND,
+					NULL, 0,
+					NULL, 0,
+					NULL, 0,
+					NULL, 0,
+					&newauth)))
+    return err;
+
+  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, 0, MACH_MSG_TYPE_COPY_SEND,
+			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/hurd/hurdexec.c b/hurd/hurdexec.c
new file mode 100644
index 0000000000..d5d2d080e4
--- /dev/null
+++ b/hurd/hurdexec.c
@@ -0,0 +1,259 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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>
+
+/* 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, *ap;
+  size_t argslen, envlen;
+  int ints[INIT_INT_MAX];
+  mach_port_t ports[_hurd_nports];
+  struct hurd_userlink ulink_ports[_hurd_nports];
+  file_t *dtable;
+  int dtablesize;
+  struct hurd_port **dtable_cells;
+  struct hurd_userlink *ulink_dtable;
+  int i;
+  char *const *p;
+  struct hurd_sigstate *ss;
+  mach_port_t *please_dealloc, *pdp;
+
+
+  /* Pack the arguments into an array with nulls separating the elements.  */
+  argslen = 0;
+  if (argv != NULL)
+    {
+      p = argv;
+      while (*p != NULL)
+	argslen += strlen (*p++) + 1;
+      args = __alloca (argslen);
+      ap = args;
+      for (p = argv; *p != NULL; ++p)
+	ap = __memccpy (ap, *p, '\0', ULONG_MAX);
+    }
+  else
+    args = NULL;
+
+  /* Pack the environment into an array with nulls separating elements.  */
+  envlen = 0;
+  if (envp != NULL)
+    {
+      p = envp;
+      while (*p != NULL)
+	envlen += strlen (*p++) + 1;
+      env = __alloca (envlen);
+      ap = env;
+      for (p = envp; *p != NULL; ++p)
+	ap = __memccpy (ap, *p, '\0', ULONG_MAX);
+    }
+  else
+    env = NULL;
+
+  /* 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)
+	      _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
+	    return err;
+	  }
+      }
+    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;
+
+      default:
+	ints[i] = 0;
+      }
+
+  ss = _hurd_self_sigstate ();
+  __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.  */
+  
+  ss->critical_section = 1;
+  __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 + (2 * 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;
+    }
+
+  /* The information is all set up now.  Try to exec the file.  */
+
+  {
+    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];
+      }
+
+    err = __file_exec (file, task,
+		       _hurd_exec_flags & EXEC_INHERITED,
+		       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,
+		       NULL, 0);
+  }
+
+  /* Release references to the standard ports.  */
+  for (i = 0; i < _hurd_nports; ++i)
+    if (i == INIT_PORT_PROC && task != __mach_task_self ())
+      __mach_port_deallocate (__mach_task_self (), ports[i]);
+    else
+      _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
+
+  if (ulink_dtable != NULL)
+    /* Release references to the file descriptor ports.  */
+    for (i = 0; i < dtablesize; ++i)
+      if (dtable[i] != MACH_PORT_NULL)
+	_hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
+
+  /* Release lock on the file descriptor table. */
+  __mutex_unlock (&_hurd_dtable_lock);
+
+  /* Safe to let signals happen now.  */
+  {
+    sigset_t pending;
+    __spin_lock (&ss->lock);
+    ss->critical_section = 0;
+    pending = ss->pending & ~ss->blocked;
+    __spin_unlock (&ss->lock);
+    if (pending)
+      __msg_sig_post (_hurd_msgport, 0, __mach_task_self ());
+  }
+
+  return err;
+}
diff --git a/hurd/hurdfault.c b/hurd/hurdfault.c
new file mode 100644
index 0000000000..e8b54660b9
--- /dev/null
+++ b/hurd/hurdfault.c
@@ -0,0 +1,143 @@
+/* Handle faults in the signal thread.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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.h"		/* mig-generated header for our exc server.  */
+
+jmp_buf _hurdsig_fault_env;
+
+static mach_port_t forward_sigexc;
+
+int _hurdsig_fault_expect_signo;
+long int _hurdsig_fault_sigcode;
+int _hurdsig_fault_sigerror;
+
+kern_return_t
+_hurdsig_fault_catch_exception_raise (mach_port_t port,
+				      thread_t thread,
+				      task_t task,
+				      int exception,
+				      int code,
+				      int subcode)
+{
+  int signo;
+
+  if (port != forward_sigexc ||
+      thread != _hurd_msgport_thread || task != __mach_task_self ())
+    return EPERM;		/* Strange bogosity.  */
+
+  /* Call the machine-dependent function to translate the Mach exception
+     codes into a signal number and subcode.  */
+  _hurd_exception2signal (exception, code, subcode, &signo,
+			  &_hurdsig_fault_sigcode, &_hurdsig_fault_sigerror);
+
+  return signo == _hurdsig_fault_expect_signo ? 0 : EGREGIOUS;
+}
+
+static void
+faulted (void)
+{
+  struct
+    {
+      mach_msg_header_t head;
+      char buf[64];
+    } request;
+  struct
+    {
+      mach_msg_header_t head;
+      mach_msg_type_t type;
+      int result;
+    } 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.  */
+  switch (_hurdsig_fault_exc_server (&request.head, &reply.head))
+    {
+    case KERN_SUCCESS:
+      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);
+      break;
+    default:
+      __mach_msg_destroy (&request.head);
+    case MIG_NO_REPLY:
+    }
+
+  _hurdsig_fault_expect_signo = 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;
+
+  if (err = __mach_port_allocate (__mach_task_self (),
+				  MACH_PORT_RIGHT_RECEIVE, &sigexc))
+    __libc_fatal ("hurd: Can't create receive right for signal thread exc\n");
+  if (err = __mach_port_allocate (__mach_task_self (),
+				  MACH_PORT_RIGHT_RECEIVE, &forward_sigexc))
+    __libc_fatal ("hurd: Can't create receive right for signal thread exc\n");
+
+  memset (&state, 0, sizeof state);
+  MACHINE_THREAD_STATE_SET_PC (&state, faulted);
+  MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);
+
+#if 0				/* Don't confuse gdb.  */
+  __thread_set_special_port (_hurd_msgport_thread,
+			     THREAD_EXCEPTION_PORT, sigexc);
+#endif
+
+  if (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)))
+    __libc_fatal ("hurd: proc won't handle signal thread exceptions\n");
+}
+
diff --git a/hurd/hurdfault.h b/hurd/hurdfault.h
new file mode 100644
index 0000000000..00ec905925
--- /dev/null
+++ b/hurd/hurdfault.h
@@ -0,0 +1,49 @@
+/* Declarations for handling faults in the signal thread.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _HURD_FAULT_H
+#define _HURD_FAULT_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(signo) \
+  (_hurdsig_fault_expect_signo = (signo), setjmp (_hurdsig_fault_env))
+
+/* Call this at the end of a section protected by _hurdsig_catch_fault.  */
+
+#define _hurdsig_end_catch_fault() \
+  (_hurdsig_fault_expect_signo = 0)
+
+extern jmp_buf _hurdsig_fault_env;
+extern int _hurdsig_fault_expect_signo;
+
+/* If _hurdsig_catch_fault returns nonzero, these variables
+   contain information about the signal that arrived.  */
+
+
+
+extern long int _hurdsig_fault_sigcode;
+extern int _hurdsig_fault_sigerror;
+
+#endif	/* hurd/fault.h */
diff --git a/hurd/hurdid.c b/hurd/hurdid.c
new file mode 100644
index 0000000000..6f1c977cc8
--- /dev/null
+++ b/hurd/hurdid.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/hurdinit.c b/hurd/hurdinit.c
new file mode 100644
index 0000000000..4469a17339
--- /dev/null
+++ b/hurd/hurdinit.c
@@ -0,0 +1,193 @@
+/* Copyright (C) 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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;
+
+void _hurd_proc_init (char **argv);
+
+DEFINE_HOOK (_hurd_subinit, (void));
+
+/* 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)
+{
+  int 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]);
+
+  /* Tell the proc server we exist, if it does.  */
+  if (portarray[INIT_PORT_PROC] != MACH_PORT_NULL)
+    _hurd_proc_init (argv);
+
+  if (intarraysize > INIT_UMASK)
+    _hurd_umask = intarray[INIT_UMASK] & 0777;
+  else
+    _hurd_umask = CMASK;
+
+  /* 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_proc_init (char **argv)
+{
+  mach_port_t oldmsg;
+  struct hurd_userlink ulink;
+  process_t procserver;
+
+  /* Initialize the signal code; Mach exceptions will become signals.  */
+  _hurdsig_init ();
+
+  /* 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, ());
+
+  if (_hurd_exec_flags & EXEC_TRACED)
+    /* 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.  */
+    _hurd_raise_signal (NULL, SIGTRAP, 0, 0);
+}
+
+/* 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,
+				      /* We don't know the ARGV location.  */
+				      (vm_address_t) 0,
+				      _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/hurd/hurdinline.c b/hurd/hurdinline.c
new file mode 100644
index 0000000000..12a5be6508
--- /dev/null
+++ b/hurd/hurdinline.c
@@ -0,0 +1,11 @@
+/* Include this first to avoid defining its inline functions.  */
+#include <lock-intern.h>
+
+#undef _EXTERN_INLINE
+#define _EXTERN_INLINE /* Define the real function. */
+
+#include "hurd/fd.h"
+#include "hurd/signal.h"
+#include "hurd/userlink.h"
+#include "hurd/threadvar.h"
+#include "hurd/port.h"
diff --git a/hurd/hurdintr.awk b/hurd/hurdintr.awk
new file mode 100644
index 0000000000..d03940985c
--- /dev/null
+++ b/hurd/hurdintr.awk
@@ -0,0 +1,25 @@
+BEGIN { intr=0; wantcall=0; calls=""; }
+ 
+$1 == "/*" && $2 == "INTR" && $3 == "*/" { intr=1; }
+
+NF == 1 && $1 == "routine"	{ wantcall=1; next; }
+
+intr != 0 && wantcall == 0 && NF >= 2 && $1 == "routine" \
+  {
+    if (substr($2, length($2)-2, 1) == "(")
+      calls = calls " " substr($2, 0, length($2)-1);
+    else calls = calls " " $2;
+    intr=0;
+  }
+
+wantcall != 0 && NF >= 1 \
+  {
+    if (substr($1, length($1)-2, 1) == "(")
+      calls = calls " " substr($1, 0, length($1)-1);
+    else calls = calls " " $1;
+    intr=0;
+  }
+
+{ wantcall=0; }
+
+END { print varname " :=" calls; }
diff --git a/hurd/hurdioctl.c b/hurd/hurdioctl.c
new file mode 100644
index 0000000000..5a41eb10f7
--- /dev/null
+++ b/hurd/hurdioctl.c
@@ -0,0 +1,264 @@
+/* ioctl commands which must be done in the C library.
+Copyright (C) 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <sys/ioctl.h>
+#include <hurd/ioctl.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;
+
+  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 = EGRATUITOUS;
+      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_fail (err) : 0;
+}
+
+_HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD);
+
+
+static int
+fioclex (int fd,
+	 int request)
+{
+  int flag;
+
+  switch (request)
+    {
+    default:
+      return __hurd_fail (EGRATUITOUS);
+    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>
+
+static void
+rectty_dtable (mach_port_t cttyid)
+{
+  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 newctty;
+
+      if (d == NULL)
+	/* Nothing to do for an unused descriptor cell.  */
+	continue;
+
+      if (cttyid == MACH_PORT_NULL)
+	/* We now have no controlling tty at all.  */
+	newctty = MACH_PORT_NULL;
+      else
+	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 (), (mach_port_t) id);
+			    }
+			  else
+			    newctty = MACH_PORT_NULL;
+			  0;
+			}));
+
+      /* Install the new ctty port.  */
+      _hurd_port_set (&d->ctty, newctty);
+    }
+
+  __mutex_unlock (&_hurd_dtable_lock);
+  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.  */
+  _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid);
+
+  /* Reset all the ctty ports in all the descriptors.  */
+  __USEPORT (CTTYID, (rectty_dtable (cttyid), 0));
+
+  return 0;
+}
+
+
+/* Make FD be the controlling terminal.
+   This function is called for `ioctl (fd, TCIOSCTTY)'.  */
+
+static int
+tiocsctty (int fd,
+	   int request)		/* Always TIOCSCTTY.  */
+{
+  mach_port_t cttyid;
+  error_t err;
+
+  /* Get FD's cttyid port, unless it is already ours.  */
+  err = HURD_DPORT_USE (fd, ctty != MACH_PORT_NULL ? EADDRINUSE :
+			__term_getctty (port, &cttyid));
+  if (err == EADDRINUSE)
+    /* FD is already the ctty.  Nothing to do.  */
+    return 0;
+  else if (err)
+    return __hurd_fail (err);
+
+  /* Make it our own.  */
+  _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid);
+
+  /* Reset all the ctty ports in all the descriptors.  */
+  __USEPORT (CTTYID, (rectty_dtable (cttyid), 0));
+
+  return 0;
+}
+_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 cell.  */
+  _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
+
+  /* Reset all the ctty ports in all the descriptors.  */
+				
+  __USEPORT (CTTYID, (rectty_dtable (MACH_PORT_NULL), 0));
+
+  return 0;
+}
+_HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
diff --git a/hurd/hurdkill.c b/hurd/hurdkill.c
new file mode 100644
index 0000000000..364b6ed692
--- /dev/null
+++ b/hurd/hurdkill.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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, 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)
+	{
+	  for (i = 0; i < npids; ++i)
+	    {
+	      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]));
+	}
+    }
+  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/hurd/hurdlookup.c b/hurd/hurdlookup.c
new file mode 100644
index 0000000000..b467404840
--- /dev/null
+++ b/hurd/hurdlookup.c
@@ -0,0 +1,381 @@
+/* Copyright (C) 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+#include "stdio/_itoa.h"
+#include <hurd/term.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 (file_t crdir, file_t cwdir,
+			 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! */
+  file_t startdir;
+
+  startdir = file_name[0] == '/' ? crdir : cwdir;
+
+  while (file_name[0] == '/')
+    file_name++;
+
+  if (err = __dir_lookup (startdir, file_name, flags, mode,
+			  &doretry, retryname, result))
+    return lookup_error (err);
+
+  return __hurd_file_name_lookup_retry (crdir, doretry, retryname, flags, mode,
+					result);
+}
+weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup)
+
+error_t
+__hurd_file_name_lookup_retry (file_t crdir,
+			       enum retry_type doretry,
+			       char retryname[1024],
+			       int flags, mode_t mode,
+			       file_t *result)
+{
+  error_t err;
+  file_t startdir;
+  file_t newpt;
+  char *file_name;
+  int dealloc_dir;
+  int nloops;
+
+  dealloc_dir = 0;
+  nloops = 0;
+  err = 0;
+  
+  while (1)
+    {
+      if (dealloc_dir)
+	__mach_port_deallocate (__mach_task_self (), startdir);
+      if (err)
+	return lookup_error (err);
+
+      switch (doretry)
+	{
+	case FS_RETRY_REAUTH:
+	  {
+	    mach_port_t ref = __mach_reply_port ();
+	    err = __io_reauthenticate (*result,
+				       ref, MACH_MSG_TYPE_MAKE_SEND);
+	    if (! err)
+	      err = __USEPORT
+		(AUTH, __auth_user_authenticate (port, *result,
+						 ref,
+						 MACH_MSG_TYPE_MAKE_SEND,
+						 &newpt));
+	    __mach_port_destroy (__mach_task_self (), ref);
+	  }
+	  __mach_port_deallocate (__mach_task_self (), *result);
+	  if (err)
+	    return err;
+	  *result = newpt;
+	  /* Fall through.  */
+
+	case FS_RETRY_NORMAL:
+#ifdef SYMLOOP_MAX
+	  if (nloops++ >= SYMLOOP_MAX)
+	    return ELOOP;
+#endif
+
+	  /* An empty RETRYNAME indicates we have the final port.  */
+	  if (retryname[0] == '\0')
+	    {
+	      /* We got a successful translation.  Now apply any open-time
+		 action flags we were passed.  */
+	      if (flags & O_EXLOCK)
+		;		/* XXX */
+	      if (!err && (flags & O_SHLOCK))
+		;		/* XXX */
+	      if (!err && (flags & O_TRUNC))
+		err = __file_truncate (*result, 0);
+
+	      if (err)
+		__mach_port_deallocate (__mach_task_self (), *result);
+	      return err;
+	    }
+
+	  startdir = *result;
+	  dealloc_dir = 1;
+	  file_name = retryname;
+	  break;
+
+	case FS_RETRY_MAGICAL:
+	  switch (retryname[0])
+	    {
+	    case '/':
+	      startdir = crdir;
+	      dealloc_dir = 0;
+	      if (*result != MACH_PORT_NULL)
+		__mach_port_deallocate (__mach_task_self (), *result);
+	      file_name = &retryname[1];
+	      break;
+
+	    case 'f':
+	      if (retryname[1] == 'd' && retryname[2] == '/')
+		{
+		  int fd;
+		  char *end;
+		  int save = errno;
+		  errno = 0;
+		  fd = (int) strtol (retryname, &end, 10);
+		  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;
+		    }
+		  *result = __getdport (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.  */
+		      error_t err = errno;
+		      errno = save;
+		      return err;
+		    }
+		  errno = save;
+		  if (*end == '\0')
+		    return 0;
+		  else
+		    {
+		      /* Do a normal retry on the remaining components.  */
+		      startdir = *result;
+		      dealloc_dir = 1;
+		      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;
+		  if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
+					 (natural_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;
+		  dealloc_dir = 1;
+		}
+	      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;
+			file_t unauth;
+			err = __USEPORT (CTTYID,
+					 __termctty_open_terminal (port,
+								   flags,
+								   &unauth));
+			if (! err)
+			  {
+			    mach_port_t ref = __mach_reply_port ();
+			    err = __io_reauthenticate
+			      (unauth,
+			       ref,
+			       MACH_MSG_TYPE_MAKE_SEND);
+			    if (! err)
+			      err = __USEPORT
+				(AUTH, __auth_user_authenticate
+				 (port,
+				  unauth,
+				  ref, MACH_MSG_TYPE_MAKE_SEND,
+				  result));
+			    __mach_port_deallocate (__mach_task_self (),
+						    unauth);
+			    __mach_port_destroy (__mach_task_self (), ref);
+			  }
+			return err;
+		      }
+
+		  case '\0':
+		    return opentty (result);
+		  case '/':
+		    if (err = opentty (&startdir))
+		      return err;
+		    dealloc_dir = 1;
+		    strcpy (retryname, &retryname[4]);
+		    break;
+		  default:
+		    goto bad_magic;
+		  }
+	      else
+		goto bad_magic;
+	      break;
+
+	    default:
+	    bad_magic:
+	      return EGRATUITOUS;
+	    }
+	  break;		
+
+	default:
+	  return EGRATUITOUS;
+	}
+
+      err = __dir_lookup (startdir, file_name, flags, mode,
+			  &doretry, retryname, result);
+    }
+}
+weak_alias (__hurd_file_name_lookup_retry, hurd_file_name_lookup_retry)
+
+error_t
+__hurd_file_name_split (file_t crdir, file_t cwdir,
+			const char *file_name,
+			file_t *dir, char **name)
+{
+  const char *lastslash;
+  error_t err;
+
+  lastslash = strrchr (file_name, '/');
+  if (lastslash != NULL)
+    {
+      if (lastslash == file_name)
+	{
+	  /* "/foobar" => crdir + "foobar".  */
+	  *name = (char *) file_name + 1;
+	  if (err = __mach_port_mod_refs (__mach_task_self (), 
+					  crdir, MACH_PORT_RIGHT_SEND, +1))
+	    return err;
+	  *dir = crdir;
+	  return 0;
+	}
+      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 (crdir, cwdir, dirname, 0, 0, dir);
+	}
+    }
+  else
+    {
+      /* "foobar" => cwdir + "foobar".  */
+      *name = (char *) file_name;
+      if (err = __mach_port_mod_refs (__mach_task_self (),
+				      cwdir, MACH_PORT_RIGHT_SEND, +1))
+	return err;
+      *dir = cwdir;
+      return 0;
+    }
+}
+weak_alias (__hurd_file_name_split, hurd_file_name_split)
+
+
+file_t
+__file_name_lookup (const char *file_name, int flags, mode_t mode)
+{
+  error_t err;
+  file_t result, crdir, cwdir;
+  struct hurd_userlink crdir_ulink, cwdir_ulink;
+
+  crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
+  cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
+
+  err = __hurd_file_name_lookup (crdir, cwdir, file_name, flags, mode,
+				 &result);
+
+  _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
+  _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
+
+  if (err)
+    return __hurd_fail (err), MACH_PORT_NULL;
+  else
+    return 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 dir, crdir, cwdir;
+  struct hurd_userlink crdir_ulink, cwdir_ulink;
+
+  crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
+  cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
+
+  err = __hurd_file_name_split (crdir, cwdir, file_name, &dir, name);
+
+  _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
+  _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
+
+  if (err)
+    {
+      errno = err;
+      return MACH_PORT_NULL;
+    }
+  else
+    return dir;
+}
+weak_alias (__file_name_split, file_name_split)
diff --git a/hurd/hurdmalloc.c b/hurd/hurdmalloc.c
new file mode 100644
index 0000000000..1de887bb80
--- /dev/null
+++ b/hurd/hurdmalloc.c
@@ -0,0 +1,411 @@
+#include <stdlib.h>
+#include <string.h>
+
+#define bcopy(s,d,n)	memcpy ((d), (s), (n)) /* No overlap handling.  */
+
+#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.
+ */
+/*
+ * HISTORY
+ * $Log$
+ * Revision 1.10  1995/02/13 22:04:34  roland
+ * (malloc_init): Add self reference to avoid not only the `defined but not
+ * used' warning, but also to avoid GCC optimizing out the entire function
+ * (!).
+ *
+ * Revision 1.9  1995/02/13  16:36:08  roland
+ * Include string.h; #define bcopy using memcpy.
+ *
+ * Revision 1.8  1995/02/03  01:54:21  roland
+ * Remove bogus bcopy decl.
+ *
+ * Revision 1.7  1995/01/26  04:22:02  roland
+ * Don't include gnu-stabs.h.
+ *
+ * Revision 1.6  1994/12/07  19:41:26  roland
+ * (vm_allocate, vm_page_size): #define these to __ names at top.
+ *
+ * Revision 1.5  1994/06/04  01:48:44  roland
+ * entered into RCS
+ *
+ * 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 <cthreads.h>
+#include "cthread_internals.h"
+
+
+/*
+ * 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.
+ */
+typedef union header {
+	union header *next;
+	struct free_list *fl;
+} *header_t;
+
+#define MIN_SIZE	8	/* minimum block size */
+
+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+3) including header.
+ * Smallest block size is 8, with 4 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(size, fl)
+	int size;
+	register free_list_t fl;
+{
+	register int amount;
+	register int n;
+	vm_address_t where;
+	register 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;
+	}
+	MACH_CALL(vm_allocate(mach_task_self(), &where, (vm_size_t) amount, TRUE), r);
+	h = (header_t) where;
+	do {
+	  h->next = fl->head;
+	  fl->head = h;
+	  h = (header_t) ((char *) h + size);
+	} while (--n != 0);
+}
+
+/* Declaration changed to standard one for GNU.  */
+void *
+malloc(size)
+	register size_t size;
+{
+	register int i, n;
+	register free_list_t fl;
+	register header_t h;
+
+	if ((int) size < 0)		/* sanity check */
+		return 0;
+	size += sizeof(union header);
+	/*
+	 * 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 = h->next;
+#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.
+	 */
+	h->fl = fl;
+	/*
+	 * Return pointer past the block header.
+	 */
+	return ((char *) h) + sizeof(union header);
+}
+
+/* Declaration changed to standard one for GNU.  */
+void
+free(base)
+	void *base;
+{
+	register header_t h;
+	register free_list_t fl;
+	register int i;
+
+	if (base == 0)
+		return;
+	/*
+	 * Find free list for block.
+	 */
+	h = (header_t) (base - sizeof(union header));
+	fl = h->fl;
+	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);
+	h->next = fl->head;
+	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(old_base, new_size)
+        void *old_base;
+        size_t new_size;
+{
+	register header_t h;
+	register free_list_t fl;
+	register 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 - sizeof(union header));
+	fl = h->fl;
+	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+3) including header.
+	 */
+	old_size = (1 << (i+3)) - sizeof(union header);
+	/*
+	 * Allocate new block, copy old bytes, and free old block.
+	 */
+	new_base = malloc(new_size);
+	if (new_base != 0)
+		bcopy(old_base, new_base, (int) (old_size < new_size ? old_size : new_size));
+	free(old_base);
+	return new_base;
+}
+
+#ifdef	DEBUG
+void
+print_malloc_free_list()
+{
+  	register int i, size;
+	register free_list_t fl;
+	register int n;
+  	register 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 = h->next, 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
+
+static void malloc_fork_prepare()
+/*
+ * Prepare the malloc module for a fork by insuring that no thread is in a
+ * malloc critical section.
+ */
+{
+    register int i;
+    
+    for (i = 0; i < NBUCKETS; i++) {
+	spin_lock(&malloc_free_list[i].lock);
+    }
+}
+
+static void malloc_fork_parent()
+/*
+ * Called in the parent process after a fork() to resume normal operation.
+ */
+{
+    register int i;
+
+    for (i = NBUCKETS-1; i >= 0; i--) {
+	spin_unlock(&malloc_free_list[i].lock);
+    }
+}
+
+static void malloc_fork_child()
+/*
+ * Called in the child process after a fork() to resume normal operation.
+ */
+{
+    register int i;
+
+    for (i = NBUCKETS-1; i >= 0; i--) {
+	spin_unlock(&malloc_free_list[i].lock);
+    }
+}
+
+
+text_set_element (_hurd_fork_prepare_hook, malloc_fork_prepare);
+text_set_element (_hurd_fork_parent_hook, malloc_fork_parent);
+text_set_element (_hurd_fork_child_hook, malloc_fork_child);
+text_set_element (_hurd_preinit_hook, malloc_init);
diff --git a/hurd/hurdmalloc.h b/hurd/hurdmalloc.h
new file mode 100644
index 0000000000..91286093c4
--- /dev/null
+++ b/hurd/hurdmalloc.h
@@ -0,0 +1,17 @@
+/* XXX this file is a tempoary 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 *);
+
+#define malloc	_hurd_malloc
+#define realloc	_hurd_realloc
+#define free	_hurd_free
diff --git a/hurd/hurdmsg.c b/hurd/hurdmsg.c
new file mode 100644
index 0000000000..57b6b8dd67
--- /dev/null
+++ b/hurd/hurdmsg.c
@@ -0,0 +1,451 @@
+/* Copyright (C) 1992, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <hurd/msg_server.h>
+#include <hurd/fd.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.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;
+      }
+    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)
+{
+  const char *value = getenv (variable);
+
+  if (value == NULL)
+    return ENOENT;
+
+  /* XXX this pointer might become invalid */
+  *data = value;
+  *datalen = strlen (value);
+  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 = _hurd_split_args (data, datalen, NULL);
+  envp = malloc ((envc + 1) * sizeof (char *));
+  if (envp == NULL)
+    return errno;
+  _hurd_split_args (data, datalen, envp);
+  __environ = envp;		/* XXX cooperate with loadenv et al */
+  return 0;
+}
+
+/* Get and frob the exec flags.  */
+
+kern_return_t
+_S_msg_get_exec_flags (mach_port_t process, mach_port_t auth,
+		       int *flags)
+{
+  AUTHCHECK;
+
+  *flags = _hurd_exec_flags;
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_all_exec_flags (mach_port_t process, mach_port_t auth,
+			   int flags)
+{
+  AUTHCHECK;
+
+  _hurd_exec_flags = flags;
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_some_exec_flags (mach_port_t process, mach_port_t auth,
+			    int flags)
+{
+  AUTHCHECK;
+
+  _hurd_exec_flags |= flags;
+  return 0;
+}
+
+kern_return_t
+_S_msg_clear_some_exec_flags (mach_port_t process, mach_port_t auth,
+			      int flags)
+{
+  AUTHCHECK;
+
+  _hurd_exec_flags &= ~flags;
+  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; }
+
+kern_return_t
+_S_msg_startup_dosync (mach_port_t process)
+{ return EOPNOTSUPP; }
diff --git a/hurd/hurdpid.c b/hurd/hurdpid.c
new file mode 100644
index 0000000000..23594d9a10
--- /dev/null
+++ b/hurd/hurdpid.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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)
+{
+  if (task != __mach_task_self ())
+    return EPERM;
+
+  __mach_port_deallocate (__mach_task_self (), task);
+
+  _hurd_ppid = ppid;
+  _hurd_pgrp = pgrp;
+  _hurd_orphaned = orphaned;
+
+  /* Run things that want notification of a pgrp change.  */
+  RUN_HOOK (_hurd_pgrp_changed_hook, (_hurd_pgrp));
+
+  /* Notify any waiting user threads that the id change as been completed.  */
+  ++_hurd_pids_changed_stamp;
+#ifdef noteven
+  __condition_broadcast (&_hurd_pids_changed_sync);
+#endif
+
+  return 0;
+}
diff --git a/hurd/hurdports.c b/hurd/hurdports.c
new file mode 100644
index 0000000000..5b7dfd883f
--- /dev/null
+++ b/hurd/hurdports.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1991, 1992, 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/hurdprio.c b/hurd/hurdprio.c
new file mode 100644
index 0000000000..d7beb3c97a
--- /dev/null
+++ b/hurd/hurdprio.c
@@ -0,0 +1,87 @@
+/* Support code for dealing with priorities in the Hurd.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd/resource.h>
+#include <hurd.h>
+
+error_t
+_hurd_priority_which_map (enum __priority_which which, int who,
+			  error_t (*function) (pid_t, struct procinfo *))
+{
+  mach_msg_type_number_t npids = 64, i;
+  pid_t pidbuf[npids], *pids;
+  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)
+    {
+    case PRIO_PROCESS:
+      npids = 1;
+      pids[0] = who;
+      err = 0;
+      break;
+
+    case PRIO_PGRP:
+      err = __USEPORT (PROC, __proc_getpgrppids (port, who, &pids, &npids));
+      break;
+
+    case PRIO_USER:
+      err = __USEPORT (PROC, __proc_getallpids (port, &pids, &npids));
+      break;
+
+    default:
+      return EINVAL;
+    }
+
+  for (i = 0; !err && i < npids; ++i)
+    {
+      if (which == PRIO_USER)
+	{
+	  /* Get procinfo to check the owner.  */
+	  int *oldpi = pi;
+	  mach_msg_type_number_t oldpisize = pisize;
+	  if (err = __USEPORT (PROC, __proc_getprocinfo (port, pids[i],
+							 &pi, &pisize)))
+	    continue;
+	  if (pi != oldpi && oldpi != pibuf)
+	    /* Old buffer from last call was not reused; free it.  */
+	    __vm_deallocate (__mach_task_self (),
+			     (vm_address_t) oldpi, oldpisize * sizeof pi[0]);
+
+	  pip = (struct procinfo *) pi;
+	  if (pip->owner != who)
+	    continue;
+	}
+      else
+	pip = NULL;
+
+      err = (*function) (pids[i], pip);
+    }
+
+  if (pids != pidbuf)
+    __vm_deallocate (__mach_task_self (),
+		     (vm_address_t) pids, npids * sizeof pids[0]);
+  if (pi != pibuf)
+    __vm_deallocate (__mach_task_self (),
+		     (vm_address_t) pi, pisize * sizeof pi[0]);
+
+  return err;
+}
diff --git a/hurd/hurdrlimit.c b/hurd/hurdrlimit.c
new file mode 100644
index 0000000000..2cc33682a5
--- /dev/null
+++ b/hurd/hurdrlimit.c
@@ -0,0 +1,50 @@
+/* Resource limits.
+Copyright (C) 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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)
+	_hurd_rlimits[i].rlim_cur = _hurd_rlimits[i].rlim_max;
+    }
+
+  (void) &init_rlimit;
+}
+text_set_element (_hurd_preinit_hook, init_rlimit);
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
new file mode 100644
index 0000000000..2c6f6a17d2
--- /dev/null
+++ b/hurd/hurdsig.c
@@ -0,0 +1,1080 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <cthreads.h>		/* For `struct mutex'.  */
+#include <string.h>
+#include "hurdfault.h"
+#include "hurdmalloc.h"		/* XXX */
+
+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;
+
+/* Linked-list of per-thread signal state.  */
+struct hurd_sigstate *_hurd_sigstates;
+
+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);
+
+      /* Initialze default state.  */
+      __sigemptyset (&ss->blocked);
+      __sigemptyset (&ss->pending);
+      memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
+      ss->suspended = 0;
+#ifdef noteven
+      __condition_init (&ss->arrived);
+#endif
+      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/core.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 <assert.h>
+#include <hurd/interrupt.h>
+
+int _hurd_core_limit;	/* XXX */
+
+/* Call the core server to mummify us before we die.
+   Returns nonzero if a core file was written.  */
+static int
+write_corefile (int signo, long int sigcode, int sigerror)
+{
+  error_t err;
+  mach_port_t coreserver;
+  file_t file, coredir;
+  const char *name;
+
+  /* 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 ("CORESERVER");
+  if (name != NULL)
+    coreserver = __file_name_lookup (name, 0, 0);
+  if (coreserver == MACH_PORT_NULL)
+    coreserver = __file_name_lookup (_SERVERS_CORE, 0, 0);
+  if (coreserver == MACH_PORT_NULL)
+    return 0;
+
+  /* Get a port to the directory where the new core file will reside.  */
+  name = _hurdsig_getenv ("COREFILE");
+  if (name == NULL)
+    name = "core";
+  coredir = __file_name_split (name, (char **) &name);
+  if (coredir == MACH_PORT_NULL)
+    return 0;
+  /* Create the new file, but don't link it into the directory yet.  */
+  if (err = __dir_mkfile (coredir, O_WRONLY|O_CREAT,
+			  0600 & ~_hurd_umask, /* XXX ? */
+			  &file))
+    return 0;
+
+  /* Call the core dumping server to write the core file.  */
+  err = __core_dump_task (coreserver,
+			  __mach_task_self (),
+			  file, _hurdsig_getenv ("GNUTARGET"),
+			  signo, sigcode, sigerror);
+  __mach_port_deallocate (__mach_task_self (), coreserver);
+  if (! err)
+    /* The core dump into FILE succeeded, so now link it into the
+       directory.  */
+    err = __dir_link (file, coredir, name);
+  __mach_port_deallocate (__mach_task_self (), file);
+  __mach_port_deallocate (__mach_task_self (), coredir);
+  return !err;
+}
+
+
+/* Send a sig_post reply message if it hasn't already been sent.  */
+static inline void
+post_reply (mach_port_t *reply_port, mach_msg_type_name_t reply_port_type,
+	    int untraced,
+	    error_t result)
+{
+  if (reply_port == NULL || *reply_port == MACH_PORT_NULL)
+    return;
+  (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply)
+    (*reply_port, reply_port_type, result);
+  *reply_port = 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.  If
+   REPLY_PORT is not NULL, send a reply on *REPLY_PORT after aborting the
+   thread.  */
+static void
+abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
+	      mach_port_t *reply_port, mach_msg_type_name_t reply_port_type,
+	      int untraced)
+{
+  if (!(state->set & THREAD_ABORTED))
+    {
+      __thread_abort (ss->thread);
+      /* Clear all thread state flavor set bits, because thread_abort may
+	 have changed the state.  */
+      state->set = THREAD_ABORTED;
+    }
+
+  if (reply_port)
+    post_reply (reply_port, reply_port_type, untraced, 0);
+
+  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.  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)
+{
+  mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
+    (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
+
+  if (_hurdsig_catch_fault (SIGSEGV))
+    {
+      assert (_hurdsig_fault_sigcode == (long int) portloc);
+      /* Faulted trying to read the stack.  */
+      return NULL;
+    }
+
+  /* Fault now if this pointer is bogus.  */
+  *(volatile mach_port_t *) portloc = *portloc;
+
+  _hurdsig_end_catch_fault ();
+
+  return portloc;
+}
+
+
+/* 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.
+
+   *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.  */
+
+static mach_port_t
+abort_rpcs (struct hurd_sigstate *ss, int signo,
+	    struct machine_thread_all_state *state, int *state_change,
+	    mach_port_t *reply_port, mach_msg_type_name_t reply_port_type,
+	    int untraced)
+{
+  mach_port_t msging_port;
+  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_port, reply_port_type, untraced);
+
+  if (_hurdsig_rcv_interrupted_p (state, &msging_port))
+    {
+      error_t err;
+
+      /* 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.  */
+
+      err = __interrupt_operation (intr_port);
+
+      if (err)
+	{
+	  mach_port_t *reply;
+
+	  /* The interrupt didn't work.
+	     Destroy the receive right the thread is blocked on.  */
+	  __mach_port_destroy (__mach_task_self (), msging_port);
+
+	  /* 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;
+
+	  /* If that was the thread's MiG reply port (which I think should
+	     always be the case), clear the reply port cell so it won't be
+	     reused.  */
+	  reply = interrupted_reply_port_location (state);
+	  if (reply != NULL && *reply == msging_port)
+	    *reply = MACH_PORT_NULL;
+	}
+
+      /* 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 (!(ss->actions[signo].sa_flags & SA_RESTART))
+	ss->intr_port = MACH_PORT_NULL;
+
+      return err ? MACH_PORT_NULL : msging_port;
+    }
+
+  /* One of the following is true:
+
+     1. The RPC has not yet been sent.  The thread will start its operation
+     after the signal has been handled.
+
+     2. The RPC has finished, but not yet cleared SS->intr_port.
+     The thread will clear SS->intr_port after running the handler.
+
+     3. The RPC request message was being sent was aborted.  The mach_msg
+     system call will return MACH_SEND_INTERRUPTED, and HURD_EINTR_RPC will
+     notice the interruption (either retrying the RPC or returning EINTR).  */
+
+  return MACH_PORT_NULL;
+}
+
+/* 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)
+    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++] = abort_rpcs (ss, signo, state, &state_changed,
+					      NULL, 0, 0);
+	if (state_changed && live)
+	  /* 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, 0, sizeof head,
+			  reply_ports[nthreads],
+			  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+	if (err != MACH_RCV_TOO_LARGE)
+	  assert_perror (err);
+      }
+}
+
+
+struct hurd_signal_preempt *_hurd_signal_preempt[NSIG];
+struct mutex _hurd_signal_preempt_lock;
+
+/* 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, long int sigcode, int sigerror,
+			    mach_port_t reply_port,
+			    mach_msg_type_name_t reply_port_type,
+			    int untraced)
+{
+  struct machine_thread_all_state thread_state;
+  enum { stop, ignore, core, term, handle } act;
+  sighandler_t handler;
+  struct hurd_signal_preempt *pe;
+  sighandler_t (*preempt) (thread_t, int, long int, int) = NULL;
+  sigset_t pending;
+  int ss_suspended;
+
+  /* Reply to this sig_post message.  */
+  inline void reply (void)
+    {
+      post_reply (&reply_port, reply_port_type, untraced, 0);
+    }
+
+  /* Mark the signal as pending.  */
+  void mark_pending (void)
+    {
+      __sigaddset (&ss->pending, signo);
+      /* Save the code to be given to the handler when SIGNO is
+	 unblocked.  */
+      ss->pending_data[signo].code = sigcode;
+      ss->pending_data[signo].error = sigerror;
+    }
+
+  /* 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);
+		   __proc_mark_stop (port, signo);
+		 }));
+      _hurd_stopped = 1;
+    }
+
+ post_signal:
+
+  thread_state.set = 0;		/* We know nothing.  */
+
+  /* Check for a preempted signal.  Preempted signals
+     can arrive during critical sections.  */
+  __mutex_lock (&_hurd_signal_preempt_lock);
+  for (pe = _hurd_signal_preempt[signo]; pe != NULL; pe = pe->next)
+    if (sigcode >= pe->first && sigcode <= pe->last)
+      {
+	preempt = pe->handler;
+	break;
+      }
+  __mutex_unlock (&_hurd_signal_preempt_lock);
+
+  handler = SIG_DFL;
+  if (preempt)
+    /* Let the preempting handler examine the thread.
+       If it returns SIG_DFL, we run the normal handler;
+       otherwise we use the handler it returns.  */
+    handler = (*preempt) (ss->thread, signo, sigcode, sigerror);
+
+  ss_suspended = 0;
+
+  if (handler != SIG_DFL)
+    /* Run the preemption-provided handler.  */
+    act = handle;
+  else
+    {
+      /* No preemption.  Do normal handling.  */
+
+      __spin_lock (&ss->lock);
+
+      handler = ss->actions[signo].sa_handler;
+
+      if (!untraced && (_hurd_exec_flags & EXEC_TRACED))
+	{
+	  /* 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;
+	}
+
+      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).  */
+	ss->pending &= ~sigmask (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 the process from being stopped.  */
+	      thread_t *threads;
+	      mach_msg_type_number_t nthreads, i;
+	      error_t err;
+	      /* 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))
+		    __thread_resume (threads[i]);
+		  __mach_port_deallocate (__mach_task_self (), threads[i]);
+		}
+	      __vm_deallocate (__mach_task_self (),
+			       (vm_address_t) threads,
+			       nthreads * sizeof *threads);
+	      _hurd_stopped = 0;
+	      /* The thread that will run the handler is already suspended.  */
+	      ss_suspended = 1;
+	    }
+	}
+    }
+
+  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.  */
+      sigcode = signo;
+      signo = SIGKILL;
+      act = term;
+    }
+
+  /* Handle receipt of a blocked signal, or any signal while stopped.
+     It matters that we test ACT first here, because we must never pass
+     SIGNO==0 to __sigismember.  */
+  if ((act != ignore && __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.  */
+	__USEPORT (PROC, __proc_mark_stop (port, signo));
+      else
+	/* Suspend the process.  */
+	suspend ();
+      break;
+
+    case ignore:
+      /* Nobody cares about this signal.  */
+      break;
+
+    case term:			/* Time to die.  */
+    case core:			/* And leave a rotting corpse.  */
+    nirvana:
+      /* Have the proc server stop all other threads in our task.  */
+      __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread));
+      /* 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, sigcode, sigerror))
+	  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;
+	int wait_for_reply, state_changed;
+
+	/* Stop the thread and abort its pending RPC operations.  */
+	if (! ss_suspended)
+	  __thread_suspend (ss->thread);
+
+	/* 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, 0, 0);
+
+	wait_for_reply = (abort_rpcs (ss, signo, &thread_state, &state_changed,
+				      &reply_port, reply_port_type, untraced)
+			  != MACH_PORT_NULL);
+
+	if (ss->critical_section)
+	  {
+	    /* 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 ();
+	    assert (! state_changed);
+	    __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, sigcode,
+				      wait_for_reply, &thread_state);
+	if (scp == NULL)
+	  {
+	    /* We got a fault setting up the stack frame for the handler.
+	       Nothing to do but die; BSD gets SIGILL in this case.  */
+	    sigcode = signo;	/* XXX ? */
+	    signo = SIGILL;
+	    act = core;
+	    goto nirvana;
+	  }
+
+	/* Set the machine-independent parts of the signal context.  */
+
+	scp->sc_error = sigerror;
+	{
+	  /* 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);
+	  if (loc)
+	    {
+	      scp->sc_reply_port = *loc;
+	      *loc = MACH_PORT_NULL;
+	    }
+	  else
+	    scp->sc_reply_port = MACH_PORT_NULL;
+	}
+
+	/* Block SIGNO and requested signals while running the handler.  */
+	scp->sc_mask = ss->blocked;
+	ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
+
+	/* 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;
+
+	/* Start the thread running the handler (or possibly waiting for an
+	   RPC reply before running the handler).  */
+	__thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
+			    (natural_t *) &thread_state.basic,
+			    MACHINE_THREAD_STATE_COUNT);
+	__thread_resume (ss->thread);
+	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.  The exception is
+     signal 0, which can be sent by a user thread to make us check for
+     pending signals.  In that case we want to deliver the pending signals
+     before replying.  */
+  if (signo != 0)
+    reply ();
+
+  /* We get here unless the signal was fatal.  We still hold SS->lock.
+     Check for pending signals, and loop to post them.  */
+#define PENDING	(!_hurd_stopped && (pending = ss->pending & ~ss->blocked))
+  if (PENDING)
+    {
+    pending:
+      for (signo = 1; signo < NSIG; ++signo)
+	if (__sigismember (&pending, signo))
+	  {
+	    __sigdelset (&ss->pending, signo);
+	    sigcode = ss->pending_data[signo].code;
+	    sigerror = ss->pending_data[signo].error;
+	    __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);
+	  if (PENDING)
+	    goto 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;
+	  err = __mach_port_insert_right (__mach_task_self (),
+					  ss->suspended, ss->suspended,
+					  MACH_MSG_TYPE_MAKE_SEND);
+	  assert_perror (err);
+	  msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_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.  */
+	  msg.msgh_seqno = 17;	/* Random.  */
+	  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:
+      /* 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;
+	__mutex_lock (&_hurd_dtable_lock);
+	for (d = 0; (unsigned int) d < (unsigned int) _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.  */
+		  d = -1;
+		__mach_port_deallocate (__mach_task_self (), asyncid);
+	      }
+	    _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
+	  }
+	/* If we found a lucky winner, we've set D to -1 in the loop.  */
+	if (d < 0)
+	  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,
+		 mach_port_t refport)
+{
+  error_t err;
+
+  if (err = signal_allowed (signo, refport))
+    return err;
+
+  /* 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, 0, 0, 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,
+			  mach_port_t refport)
+{
+  error_t err;
+
+  if (err = signal_allowed (signo, refport))
+    return err;
+
+  /* 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, 0, 0, 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 (void)
+{
+  error_t err;
+  vm_size_t stacksize;
+
+  __mutex_init (&_hurd_siglock);
+
+  if (err = __mach_port_allocate (__mach_task_self (),
+				  MACH_PORT_RIGHT_RECEIVE,
+				  &_hurd_msgport))
+    __libc_fatal ("hurd: Can't create message port receive right\n");
+  
+  /* Make a send right to the signal port.  */
+  if (err = __mach_port_insert_right (__mach_task_self (),
+				      _hurd_msgport,
+				      _hurd_msgport,
+				      MACH_MSG_TYPE_MAKE_SEND))
+    __libc_fatal ("hurd: Can't create send right to message port\n");
+
+  /* Set the default thread to receive task-global signals
+     to this one, the main (first) user thread.  */
+  _hurd_sigthread = __mach_thread_self ();
+
+  /* Start the signal thread listening on the message port.  */
+
+  if (err = __thread_create (__mach_task_self (), &_hurd_msgport_thread))
+    __libc_fatal ("hurd: Can't create signal thread\n");
+
+  stacksize = __vm_page_size * 4; /* Small stack for signal thread.  */
+  if (err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
+				 _hurd_msgport_receive,
+				 (vm_address_t *) &__hurd_sigthread_stack_base,
+				 &stacksize))
+    __libc_fatal ("hurd: Can't setup signal thread\n");
+
+  __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 thread variables for signal thread\n");
+
+  /* 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);
+
+  if (err = __thread_resume (_hurd_msgport_thread))
+    __libc_fatal ("hurd: Can't resume signal thread\n");
+    
+#if 0				/* Don't confuse poor gdb.  */
+  /* Receive exceptions on the signal port.  */
+  __task_set_special_port (__mach_task_self (),
+			   TASK_EXCEPTION_PORT, _hurd_msgport);
+#endif
+}
+				/* 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, port, 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);
+
+  (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 (_hurdsig_catch_fault (SIGSEGV))
+    /* We bombed in getenv.  */
+    return NULL;
+  else
+    {
+      const char *value = getenv (variable);
+      /* Fault now if VALUE is a bogus string.  */
+      (void) strlen (value);
+      _hurdsig_end_catch_fault ();
+      return value;
+    }
+}
diff --git a/hurd/hurdsock.c b/hurd/hurdsock.c
new file mode 100644
index 0000000000..266fd40d31
--- /dev/null
+++ b/hurd/hurdsock.c
@@ -0,0 +1,115 @@
+/* _hurd_socket_server - Find the server for a socket domain.
+
+Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hurd/paths.h>
+#include <stdio.h>
+#include "stdio/_itoa.h"
+#include <cthreads.h>		/* For `struct mutex'.  */
+#include "hurdmalloc.h"		/* XXX */
+
+static struct mutex lock;
+
+static file_t *servers;
+static int max_domain;
+
+/* 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;
+
+  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)
+	{
+	  while (max_domain <= domain)
+	    new[max_domain++] = MACH_PORT_NULL;
+	  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 = EPFNOSUPPORT;
+
+  __mutex_unlock (&lock);
+  HURD_CRITICAL_END;
+
+  return server;
+}
+
+static void
+init (void)
+{
+  size_t 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/hurd/intern-fd.c b/hurd/intern-fd.c
new file mode 100644
index 0000000000..fe7424b9bc
--- /dev/null
+++ b/hurd/intern-fd.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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 is 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/hurd/intr-rpc.awk b/hurd/intr-rpc.awk
new file mode 100644
index 0000000000..9dbcd6f8e2
--- /dev/null
+++ b/hurd/intr-rpc.awk
@@ -0,0 +1,45 @@
+# Icky intimate knowledge of MiG output.
+
+BEGIN \
+  {
+    nprotolines=0; proto=0;
+    args=""; echo=1; isintr=0;
+    intrcall = "__hurd_intr_rpc_" call;
+    print "#include <hurd/signal.h>";
+  }
+
+$NF == intrcall { isintr=1; }
+
+NF == 1 && $1 == ")" { proto=0; }
+proto \
+  {
+    protolines[nprotolines++] = $0;
+    arg = $NF;
+    if (substr(arg, 1, 1) == "*")
+      arg = substr(arg, 2, length(arg)-1);
+    args = args arg;
+  }
+NF == 1 && $1 == "(" { proto=1; }
+
+NF == 3 && $1 == "InP->Head.msgh_request_port" \
+  { portarg = substr($3, 1, length($3)-1); }
+
+{ print $0; }
+
+END \
+  {
+    if (isintr)
+      {
+	print "\n\n/* User-callable interrupt-handling stub.  */";
+	print "kern_return_t __" call;
+	print "(";
+	for (i = 0; i < nprotolines; ++i)
+	  print protolines[i];
+	print ")";
+	print "{";
+	print "  return HURD_EINTR_RPC (" portarg ", " \
+	  intrcall "(" args "));";
+	print "}";
+      }
+    print "weak_alias (__" call ", " call ")"
+  }
diff --git a/hurd/intr-rpc.defs b/hurd/intr-rpc.defs
new file mode 100644
index 0000000000..a2e7b060c9
--- /dev/null
+++ b/hurd/intr-rpc.defs
@@ -0,0 +1,27 @@
+/* Special MiG definitions for interruptible RPC stubs.
+Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+/* Set the MiG options for an interruptible RPC interface.
+   We rename each MiG-generated function to hurd_intr_rpc_CALL and
+   give it the option to return on an interrupted message send.  */
+
+#define INTR_INTERFACE \
+msgoption MACH_SEND_INTERRUPT;\
+userprefix hurd_intr_rpc_;
+
diff --git a/hurd/invoke-trans.c b/hurd/invoke-trans.c
new file mode 100644
index 0000000000..e11bff5dc3
--- /dev/null
+++ b/hurd/invoke-trans.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <hurd/fs.h>
+
+error_t
+__hurd_invoke_translator (file_t file, int flags, file_t *newport)
+{
+  error_t err;
+  enum retry_type doretry;
+  char retryname[1024];		/* XXX string_t LOSES! */
+
+  err = __file_invoke_translator (file, flags, &doretry, retryname, newport);
+
+  if (! err)
+    err = __USEPORT (CRDIR, __hurd_file_name_lookup_retry (port,
+							   doretry, retryname,
+							   flags, 0, newport));
+
+  return err;
+}
diff --git a/hurd/msgportdemux.c b/hurd/msgportdemux.c
new file mode 100644
index 0000000000..ae783ef270
--- /dev/null
+++ b/hurd/msgportdemux.c
@@ -0,0 +1,66 @@
+/* Demux messages sent on the signal port.
+
+Copyright (C) 1991, 1992, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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.  */
+  (void) _hurd_self_sigstate ();
+
+  while (1)
+    (void) __mach_msg_server (msgport_server, __vm_page_size, _hurd_msgport);
+}
diff --git a/hurd/msgstub.c b/hurd/msgstub.c
new file mode 100644
index 0000000000..d4b59ed635
--- /dev/null
+++ b/hurd/msgstub.c
@@ -0,0 +1,26 @@
+#include <hurd.h>
+
+/* XXX */
+#define STUB(fn) error_t fn (mach_port_t port) { return EOPNOTSUPP; }
+
+STUB(_S_get_init_ports)
+STUB(_S_set_init_ports)
+STUB(_S_get_init_port)
+STUB(_S_set_init_port)
+STUB(_S_get_init_ints)
+STUB(_S_set_init_ints)
+STUB(_S_get_init_int)
+STUB(_S_set_init_int)
+STUB(_S_get_dtable)
+STUB(_S_set_dtable)
+STUB(_S_get_fd)
+STUB(_S_set_fd)
+STUB(_S_get_environment)
+STUB(_S_set_environment)
+STUB(_S_get_env_variable)
+STUB(_S_set_env_variable)
+STUB(_S_io_select_done)
+STUB(_S_startup_dosync)
+
+STUB(_S_dir_changed)
+STUB(_S_file_changed)
diff --git a/hurd/new-fd.c b/hurd/new-fd.c
new file mode 100644
index 0000000000..de9a3933f4
--- /dev/null
+++ b/hurd/new-fd.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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);
+    }
+
+  return d;
+}
diff --git a/hurd/openport.c b/hurd/openport.c
new file mode 100644
index 0000000000..244368acaa
--- /dev/null
+++ b/hurd/openport.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/pid2task.c b/hurd/pid2task.c
new file mode 100644
index 0000000000..6b8182bd02
--- /dev/null
+++ b/hurd/pid2task.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/port2fd.c b/hurd/port2fd.c
new file mode 100644
index 0000000000..cad89e770f
--- /dev/null
+++ b/hurd/port2fd.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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 is meaningful.
+   D should be locked, and will not be unlocked.  */
+
+void
+_hurd_port2fd (struct hurd_fd *d, io_t port, int flags)
+{
+  io_t ctty;
+  mach_port_t cttyid;
+  int is_ctty = !(flags & O_IGNORE_CTTY) && ! __term_getctty (port, &cttyid);
+
+  if (is_ctty)
+    {
+      /* This port is capable of being a controlling tty.
+	 Is it ours?  */
+      struct hurd_port *const id = &_hurd_ports[INIT_PORT_CTTYID];
+      __spin_lock (&id->lock);
+      if (id->port == MACH_PORT_NULL)
+	/* We have no controlling tty, so make this one it.  */
+	_hurd_port_locked_set (id, cttyid);
+      else
+	{
+	  if (cttyid != id->port)
+	    /* We have a controlling tty and this is not it.  */
+	    is_ctty = 0;
+	  /* Either we don't want CTTYID, or ID->port already is it.
+	     So we don't need to change ID->port, and we can release
+	     the reference to CTTYID.  */
+	  __spin_unlock (&id->lock);
+	  __mach_port_deallocate (__mach_task_self (), cttyid);
+	}
+    }
+
+  if (!is_ctty || __term_open_ctty (port, _hurd_pid, _hurd_pgrp, &ctty) != 0)
+    /* XXX if IS_CTTY, then this port is our ctty, but we are
+       not doing ctty style i/o because term_become_ctty barfed.
+       What to do?  */
+    /* No ctty magic happening here.  */
+    ctty = MACH_PORT_NULL;
+
+  /* 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 = port;
+    if (old != MACH_PORT_NULL)
+      __mach_port_deallocate (__mach_task_self (), old);
+  }
+
+  _hurd_port_set (&d->ctty, ctty);
+}
diff --git a/hurd/ports-get.c b/hurd/ports-get.c
new file mode 100644
index 0000000000..def59731c5
--- /dev/null
+++ b/hurd/ports-get.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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 (int which, mach_port_t *result)
+{
+  if (which < 0 || which >= _hurd_nports)
+    return EINVAL;
+  if (which >= INIT_PORT_MAX || _hurd_ports_getters[which] == NULL)
+    return HURD_PORT_USE (&_hurd_ports[which],
+			  __mach_port_mod_refs (__mach_task_self (),
+						(*result = port),
+						MACH_PORT_RIGHT_SEND,
+						+1));
+  return (*_hurd_ports_getters[which]) (result);
+}
diff --git a/hurd/ports-set.c b/hurd/ports-set.c
new file mode 100644
index 0000000000..fbc2940217
--- /dev/null
+++ b/hurd/ports-set.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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 (int which, mach_port_t newport)
+{
+  error_t err;
+  if (which < 0 || 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/hurd/preempt-sig.c b/hurd/preempt-sig.c
new file mode 100644
index 0000000000..86761967cc
--- /dev/null
+++ b/hurd/preempt-sig.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd/signal.h>
+
+/* Initialize PREEMPTER with the information given and stick it in the
+   chain of preempters for SIGNO.  */
+
+int
+hurd_preempt_signals (struct hurd_signal_preempt *preempter,
+		      int signo, int first_code, int last_code,
+		      sighandler_t (*handler) (thread_t, int, long int, int))
+{
+  if (signo <= 0 || signo >= NSIG)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  preempter->first = first_code;
+  preempter->last = last_code;
+  preempter->handler = handler;
+  __mutex_lock (&_hurd_signal_preempt_lock);
+  preempter->next = _hurd_signal_preempt[signo];
+  _hurd_signal_preempt[signo] = preempter;
+  __mutex_unlock (&_hurd_signal_preempt_lock);
+  return 0;
+}
+
+/* Remove PREEMPTER from the chain for SIGNO.  */
+
+int
+hurd_unpreempt_signals (struct hurd_signal_preempt *preempter, int signo)
+{
+  struct hurd_signal_preempt *p, *lastp;
+  if (signo <= 0 || signo >= NSIG)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  __mutex_lock (&_hurd_signal_preempt_lock);
+  for (p = _hurd_signal_preempt[signo], lastp = NULL;
+       p != NULL; lastp = p, p = p->next)
+    if (p == preempter)
+      {
+	(lastp == NULL ? _hurd_signal_preempt[signo] : lastp->next) = p->next;
+	__mutex_unlock (&_hurd_signal_preempt_lock);
+	return 0;
+      }
+  _hurd_signal_preempt[signo] = preempter;
+  __mutex_unlock (&_hurd_signal_preempt_lock);
+  errno = ENOENT;
+  return -1;
+}
diff --git a/hurd/privports.c b/hurd/privports.c
new file mode 100644
index 0000000000..f760e37e6e
--- /dev/null
+++ b/hurd/privports.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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 (host_priv_t *host_priv_ptr, device_t *device_master_ptr)
+{
+  if (! _hurd_host_priv)
+    {
+      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)
+    {
+      mach_port_mod_refs (mach_task_self (),
+			  _hurd_host_priv, MACH_PORT_RIGHT_SEND, 1);
+      *host_priv_ptr = _hurd_host_priv;
+    }
+  if (device_master_ptr)
+    {
+      mach_port_mod_refs (mach_task_self (),
+			  _hurd_device_master, MACH_PORT_RIGHT_SEND, 1);
+      *device_master_ptr = _hurd_device_master;
+    }
+  return KERN_SUCCESS;
+}
diff --git a/hurd/setauth.c b/hurd/setauth.c
new file mode 100644
index 0000000000..7378e4f070
--- /dev/null
+++ b/hurd/setauth.c
@@ -0,0 +1,124 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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;
+  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,
+				_hurd_init_dtable[d],
+				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, port,
+					     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, port,
+					     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/hurd/setuids.c b/hurd/setuids.c
new file mode 100644
index 0000000000..3b049b0100
--- /dev/null
+++ b/hurd/setuids.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 1993, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd.h>
+#include <hurd/id.h>
+
+/* Set the uid set for the current user to UIDS (N of them).  */
+int
+setuids (int n, const uid_t *uids)
+{
+  error_t err;
+  auth_t newauth;
+  size_t 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/hurd/siginfo.c b/hurd/siginfo.c
new file mode 100644
index 0000000000..eb61fec973
--- /dev/null
+++ b/hurd/siginfo.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <hurd/signal.h>
+#include <stdio.h>
+
+void
+_hurd_siginfo_handler (int signo)
+{
+  /* XXX */
+  puts ("got a SIGINFO");
+}
diff --git a/hurd/task2pid.c b/hurd/task2pid.c
new file mode 100644
index 0000000000..707753c104
--- /dev/null
+++ b/hurd/task2pid.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1991, 1992, 1993, 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#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/hurd/vpprintf.c b/hurd/vpprintf.c
new file mode 100644
index 0000000000..dcdcd5a13d
--- /dev/null
+++ b/hurd/vpprintf.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 1991, 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <hurd.h>
+
+static ssize_t
+DEFUN(pwrite, (cookie, buf, n),
+      PTR cookie AND CONST char *buf AND 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
+DEFUN(vpprintf, (port, format, arg),
+      io_t port AND CONST char *format AND va_list arg)
+{
+  int done;
+  FILE f;
+
+  /* Create an unbuffered stream talking to PORT on the stack.  */
+  memset((PTR) &f, 0, sizeof(f));
+  f.__magic = _IOMAGIC;
+  f.__mode.__write = 1;
+  f.__cookie = (PTR) port;
+  f.__room_funcs = __default_room_functions;
+  f.__io_funcs.__write = pwrite;
+  f.__seen = 1;
+  f.__userbuf = 1;
+
+  /* vfprintf will use a buffer on the stack for the life of the call.  */
+  done = vfprintf(&f, format, arg);
+
+  return done;
+}