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