summaryrefslogtreecommitdiff
path: root/hurd
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-02-18 01:27:10 +0000
committerRoland McGrath <roland@gnu.org>1995-02-18 01:27:10 +0000
commit28f540f45bbacd939bfd07f213bcad2bf730b1bf (patch)
tree15f07c4c43d635959c6afee96bde71fb1b3614ee /hurd
initial import
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;
+}