diff options
author | Roland McGrath <roland@gnu.org> | 1995-02-18 01:27:10 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1995-02-18 01:27:10 +0000 |
commit | 28f540f45bbacd939bfd07f213bcad2bf730b1bf (patch) | |
tree | 15f07c4c43d635959c6afee96bde71fb1b3614ee /hurd | |
download | glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.gz glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.bz2 glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.zip |
initial import
Diffstat (limited to 'hurd')
66 files changed, 7738 insertions, 0 deletions
diff --git a/hurd/.cvsignore b/hurd/.cvsignore new file mode 100644 index 0000000000..1f69fd919a --- /dev/null +++ b/hurd/.cvsignore @@ -0,0 +1,4 @@ +*.gz *.Z *.tar *.tgz +=* +TODO COPYING* AUTHORS copyr-* copying.* +glibc-* diff --git a/hurd/Makefile b/hurd/Makefile new file mode 100644 index 0000000000..7a5a1ba995 --- /dev/null +++ b/hurd/Makefile @@ -0,0 +1,117 @@ +# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with the GNU C Library; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 675 Mass Ave, +# Cambridge, MA 02139, USA. + +subdir := hurd + +all: + +# Some things below (but before including Rules) use configuration variables. +include ../Makeconfig + + +headers = hurd.h $(interface-headers) \ + $(addprefix hurd/,fd.h id.h port.h signal.h userlink.h \ + resource.h threadvar.h) + +distribute := hurdfault.h intr-rpc.awk intr-rpc.defs STATUS + +# The RPC interfaces go in a separate library. +interface-library := libhurduser.a +user-interfaces := $(addprefix hurd/,\ + auth process startup \ + msg msg_reply msg_request \ + exec core interrupt \ + fs fsys io term socket ifsock) +server-interfaces := hurd/msg + +routines = hurdinit hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \ + setauth \ + pid2task task2pid \ + getuids setuids getumask fchroot \ + hurdsock hurdauth invoke-trans \ + privports \ + msgportdemux \ + fopenport \ + vpprintf \ + ports-get ports-set hurdports hurdmsg \ + $(sig) $(dtable) hurdinline +sig = hurdsig hurdfault faultexc siginfo hurd-raise preempt-sig \ + trampoline longjmp-ts catch-exc exc2signal hurdkill +dtable = dtable port2fd new-fd alloc-fd intern-fd \ + getdport openport \ + fd-close fd-read fd-write hurdioctl ctty-input ctty-output + +# XXX this is a temporary hack; see hurdmalloc.h +routines += hurdmalloc +distribute += hurdmalloc.h + +# Get the proper definition of `hurd-srcdir'. +include ../sysdeps/mach/hurd/Makefile + +# Use and install the Hurd header files directly out of the Hurd source. + +# Find the MiG defs files in the Hurd source. +vpath %.defs $(hurd-srcdir) + +# Install all .h and .defs files we find in the Hurd's hurd/ directory. +hurd-headers := $(patsubst $(hurd-srcdir)/%,%,\ + $(wildcard $(addprefix $(hurd-srcdir)/hurd/,\ + *.defs *.h))) + + +# Don't distribute the Hurd headers; they are in the Hurd distribution. +dont_distribute = $(hurd-headers) + +# DO NOT try to remake these in any way!!! +$(addprefix $(hurd-srcdir)/,$(hurd-headers)) : ; +install-others += $(addprefix $(includedir)/,$(hurd-headers)) +$(includedir)/hurd/%: $(hurd-srcdir)/hurd/%; $(do-install) + +include ../mach/Machrules +include ../Rules + +# intr-rpc.defs defines the INTR_INTERFACE macro to make the generated RPC +# stubs send-interruptible, and to prefix them with `hurd_intr_rpc_'. +user-MIGFLAGS += -imacros intr-rpc.defs + +# Run each generated user stub through intr-rpc.awk, which will detect +# stubs __hurd_intr_rpc_% and generate the user-callable function for the +# stub: this is a wrapper which calls __hurd_intr_rpc_% inside +# HURD_EINTR_RPC. +define transform-user-stub +gawk -v call=$${call} -f $(word 2,$^) \ + $(objpfx)tmp_$${call}.c > $(objpfx)tmpi_$${call}.c; \ +rm -f $(objpfx)tmp_$${call}.c; +endef +transform-user-stub-output = tmpi + +$(foreach if,$(user-interfaces),$($(if)-calls:%=$(objpfx)RPC_%.o))): \ + hurd/signal.h + +$(user-interfaces:%=$(objpfx)%.ustamp): intr-rpc.awk + +$(objpfx)fault%.c $(objpfx)fault%.h: $(mach-srcdir)/mach/%.defs + $(MIG) $(MIGFLAGS) -prefix _hurdsig_fault_ \ + -server $(@:.h=.c) -sheader $(@:.c=.h) \ + -user /dev/null -header /dev/null \ + $< +generated += faultexc.c faultexc.h + +# We need this static dependency to get faultexc.h generated the first time. +$(objpfx)hurdfault.o $(objpfx)hurdfault.d: \ + $(objpfx)faultexc.h $(objpfx)faultexc.c diff --git a/hurd/Notes b/hurd/Notes new file mode 100644 index 0000000000..9052f29096 --- /dev/null +++ b/hurd/Notes @@ -0,0 +1,37 @@ +The library pays attention to some envariables: + +CORESERVER -- Name of core server naming point; falls back to /servers/core +COREFILE -- Name of file to write core dump in; falls back to core +GNUTARGET -- Passed to core server to specify flavor of core dump format + +New functions: + +int openport (io_t port); +FILE *fopenport (mach_port_t, const char *mode); +file_t getdport (int fd); + +task_t pid2task (pid_t); +pid_t task2pid (task_t); + +int fchroot (int fd); +mode_t getumask (void); + +int getuids (int n, uid_t *uidset); + +error_t hurd_path_lookup (file_t root, file_t cwd, + const char *path, int flags, mode_t mode, + file_t *port); +error_t hurd_path_split (file_t root, file_t cwd, + const char *path, + file_t *dir, char **name); +file_t path_lookup (const char *path, int flags, mode_t mode); +file_t path_split (const char *path, char **name); + +process_t getproc (void); +int setproc (process_t); +file_t getcrdir (void); +int setcrdir (file_t); +file_t getcwdir (void); +int setcwdir (file_t); +auth_t getauth (void); +int setauth (auth_t); /* Reauthenticates all library ports. */ diff --git a/hurd/STATUS b/hurd/STATUS new file mode 100644 index 0000000000..ceb0a865d0 --- /dev/null +++ b/hurd/STATUS @@ -0,0 +1,72 @@ +Status of Hurd support in libc. Last updated 22 Nov 1994. +Roland McGrath <roland@gnu.ai.mit.edu> + +Everything not noted below is implemented, most of it tested. There are +various very small things unfinished or thought to be perhaps wrong +throughout the code, marked by comments containing `XXX'. + + +* Signals and job control work, but are a very hairy area. + There are various ways the signal thread can block and fail + to respond when the program is losing badly. + +* We are not sure about possible races between setpgrp (A, pgrp) from + process B vs process A receiving proc_newids. + +* The rest of libc (stdio et al) is not safe for multithreaded programs. + mutex locks should be added to various things. + +* Recovery from faults in the signal thread is not implemented yet. + +* longjmp needs to clean up reply port, intr_port; needs thought about. + +* Cooperation with cthreads is not finished. If you link with cthreads, + libc internal code still does not use real condition variables. + sigsuspend currently does a busy wait where it should use a condition. + Signal state is per kernel thread; for unwired cthreads it should be per + cthread instead. + +* sigaltstack/sigstack do not really work: the signal stack needs thread + variables and cthread data set up, which is not done. + +* malloc is a kludge. + +* Nothing uses mapped io. Eventually stdio and read/write/seek should. I + have written a little code for this, but it is far from finished. + +* Resource limits do not really work; current implementation is patchy and + inconsistent. + +* libc implicitly uses some environment variables. This is a security + problem for setuid exec. Probably crt0 should remove the variables from + the environment if setuid. + +* The miscellaneous msg.defs calls are only partially implemented. + +* The default SIGINFO handler needs to be written. + +* File locking is not implemented; the RPC interface is not there yet. + +* The current getitimer/setitimer implementation is a kludge. + +* mmap cannot do MAP_NOEXTEND. + +* Unimplemented calls (from the 4.4 system call list): +acct +fstatfs +getfh +getfsstat +getrusage +madvise +mincore +mount +msync +profil +recvmsg +revoke +sendmsg +setpriority +sstk +statfs +swapon +unmount diff --git a/hurd/alloc-fd.c b/hurd/alloc-fd.c new file mode 100644 index 0000000000..02a1bdfd52 --- /dev/null +++ b/hurd/alloc-fd.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/fd.h> +#include <hurd/resource.h> +#include <stdlib.h> +#include "hurdmalloc.h" /* XXX */ + +/* Allocate a new file descriptor and return it, locked. The new + descriptor number will be no less than FIRST_FD. If the table is full, + set errno to EMFILE and return NULL. If FIRST_FD is negative or bigger + than the size of the table, set errno to EINVAL and return NULL. */ + +struct hurd_fd * +_hurd_alloc_fd (int *fd, int first_fd) +{ + int i; + void *crit; + long int rlimit; + + if (first_fd < 0) + { + errno = EINVAL; + return NULL; + } + + crit = _hurd_critical_section_lock (); + + __mutex_lock (&_hurd_dtable_lock); + + search: + for (i = first_fd; i < _hurd_dtablesize; ++i) + { + struct hurd_fd *d = _hurd_dtable[i]; + if (d == NULL) + { + /* Allocate a new descriptor structure for this slot, + initializing its port cells to nil. The test below will catch + and return this descriptor cell after locking it. */ + d = _hurd_new_fd (MACH_PORT_NULL, MACH_PORT_NULL); + if (d == NULL) + { + __mutex_unlock (&_hurd_dtable_lock); + _hurd_critical_section_unlock (crit); + return NULL; + } + _hurd_dtable[i] = d; + } + + __spin_lock (&d->port.lock); + if (d->port.port == MACH_PORT_NULL) + { + __mutex_unlock (&_hurd_dtable_lock); + _hurd_critical_section_unlock (crit); + if (fd != NULL) + *fd = i; + return d; + } + else + __spin_unlock (&d->port.lock); + } + + __mutex_lock (&_hurd_rlimit_lock); + rlimit = _hurd_rlimits[RLIMIT_OFILE].rlim_cur; + __mutex_unlock (&_hurd_rlimit_lock); + + if (first_fd < rlimit) + { + /* The descriptor table is full. Check if we have reached the + resource limit, or only the allocated size. */ + if (_hurd_dtablesize < rlimit) + { + /* Enlarge the table. */ + int save = errno; + struct hurd_fd **new; + /* Try to double the table size (but don't exceed the limit). + If there isn't any at all, give it three slots (because + stdio will take that many anyway). */ + int size = _hurd_dtablesize ? _hurd_dtablesize * 2 : 3; + if (size > rlimit) + size = rlimit; + /* If we fail to allocate that, decrement the desired size + until we succeed in allocating it. */ + do + new = realloc (_hurd_dtable, size * sizeof (*_hurd_dtable)); + while (new == NULL && size-- > _hurd_dtablesize); + if (new != NULL) + { + /* We managed to allocate a new table. Now install it. */ + errno = save; + first_fd = _hurd_dtablesize; + /* Initialize the new slots. */ + for (i = first_fd; i < size; ++i) + new[i] = NULL; + _hurd_dtablesize = size; + _hurd_dtable = new; + /* Go back to the loop to initialize the first new slot. */ + goto search; + } + } + else + errno = EMFILE; + } + else + errno = EINVAL; /* Bogus FIRST_FD value. */ + + __mutex_unlock (&_hurd_dtable_lock); + _hurd_critical_section_unlock (crit); + + return NULL; +} diff --git a/hurd/catch-exc.c b/hurd/catch-exc.c new file mode 100644 index 0000000000..72e06db1d3 --- /dev/null +++ b/hurd/catch-exc.c @@ -0,0 +1,78 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <mach/exc_server.h> +#include <hurd/signal.h> + +/* Called by the microkernel when a thread gets an exception. */ + +kern_return_t +_S_catch_exception_raise (mach_port_t port, + thread_t thread, + task_t task, + int exception, + int code, + int subcode) +{ + int signo, error; + long int sigcode; + struct hurd_sigstate *ss; + + if (task != __mach_task_self ()) + /* The sender wasn't the kernel. */ + return EPERM; + + /* Call the machine-dependent function to translate the Mach exception + codes into a signal number and subcode. */ + _hurd_exception2signal (exception, code, subcode, + &signo, &sigcode, &error); + + /* Find the sigstate structure for the faulting thread. */ + __mutex_lock (&_hurd_siglock); + for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) + if (ss->thread == thread) + break; + __mutex_unlock (&_hurd_siglock); + if (ss == NULL) + ss = _hurd_thread_sigstate (thread); /* Allocate a fresh one. */ + + if (__spin_lock_locked (&ss->lock)) + { + /* Loser. The thread faulted with its sigstate lock held. Its + sigstate data is now suspect. So we reset the parts of it which + could cause trouble for the signal thread. Anything else + clobbered therein will just hose this user thread, but it's + faulting already. + + This is almost certainly a library bug: unless random memory + clobberation caused the sigstate lock to gratuitously appear held, + no code should do anything that can fault while holding the + sigstate lock. */ + + ss->critical_section = 0; + ss->context = NULL; + __spin_unlock (&ss->lock); + } + + /* Post the signal. */ + _hurd_internal_post_signal (ss, signo, sigcode, error, + MACH_PORT_NULL, MACH_MSG_TYPE_PORT_SEND, + 0); + + return KERN_SUCCESS; +} diff --git a/hurd/ctty-input.c b/hurd/ctty-input.c new file mode 100644 index 0000000000..71aef1b6cf --- /dev/null +++ b/hurd/ctty-input.c @@ -0,0 +1,77 @@ +/* _hurd_ctty_input -- Do an input RPC and generate SIGTTIN if necessary. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/signal.h> + +/* Call *RPC on PORT and/or CTTY. If a call on CTTY returns EBACKGROUND, + generate SIGTTIN or EIO as appropriate. */ + +error_t +_hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t)) +{ + error_t err; + + do + { + err = (*rpc) (ctty != MACH_PORT_NULL ? ctty : port); + if (ctty != MACH_PORT_NULL && err == EBACKGROUND) + { + /* We are a background job and tried to read from the tty. + We should probably get a SIGTTIN signal. */ + struct hurd_sigstate *ss; + if (_hurd_orphaned) + /* Our process group is orphaned. Don't stop; just fail. */ + err = EIO; + else + { + ss = _hurd_self_sigstate (); + __spin_lock (&ss->lock); + if (__sigismember (&ss->blocked, SIGTTIN) || + ss->actions[SIGTTIN].sa_handler == SIG_IGN) + /* We are blocking or ignoring SIGTTIN. Just fail. */ + err = EIO; + __spin_unlock (&ss->lock); + } + if (err == EBACKGROUND) + { + /* Send a SIGTTIN signal to our process group. + + We must remember here not to clobber ERR, since + the loop condition below uses it to recall that + we should retry after a stop. */ + + __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTIN, port)); + /* XXX what to do if error here? */ + + /* At this point we should have just run the handler for + SIGTTIN or resumed after being stopped. Now this is + still a "system call", so check to see if we should + restart it. */ + __spin_lock (&ss->lock); + if (!(ss->actions[SIGTTIN].sa_flags & SA_RESTART)) + err = EINTR; + __spin_unlock (&ss->lock); + } + } + /* If the last RPC generated a SIGTTIN, loop to try it again. */ + } while (err == EBACKGROUND); + + return err; +} diff --git a/hurd/ctty-output.c b/hurd/ctty-output.c new file mode 100644 index 0000000000..0d9c54383d --- /dev/null +++ b/hurd/ctty-output.c @@ -0,0 +1,82 @@ +/* _hurd_ctty_output -- Do an output RPC and generate SIGTTOU if necessary. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/signal.h> + +/* Call *RPC on PORT and/or CTTY. If a call on CTTY returns EBACKGROUND, + generate SIGTTOU if appropriate. */ + +error_t +_hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t)) +{ + error_t err; + struct hurd_sigstate *ss; + io_t ioport; + + /* Don't use the ctty io port if we are blocking or ignoring SIGTTOU. */ + if (ctty == MACH_PORT_NULL) + ioport = port; + else + { + ss = _hurd_self_sigstate (); + __spin_lock (&ss->lock); + if (__sigismember (&ss->blocked, SIGTTOU) || + ss->actions[SIGTTOU].sa_handler == SIG_IGN) + ioport = port; + else + ioport = ctty; + __spin_unlock (&ss->lock); + } + + do + { + err = (*rpc) (ioport); + if (ioport == ctty && err == EBACKGROUND) + { + if (_hurd_orphaned) + /* Our process group is orphaned, so we never generate a + signal; we just fail. */ + err = EIO; + else + { + /* Send a SIGTTOU signal to our process group. + + We must remember here not to clobber ERR, since + the loop condition below uses it to recall that + we should retry after a stop. */ + + __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port)); + /* XXX what to do if error here? */ + + /* At this point we should have just run the handler for + SIGTTOU or resumed after being stopped. Now this is + still a "system call", so check to see if we should + restart it. */ + __spin_lock (&ss->lock); + if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART)) + err = EINTR; + __spin_unlock (&ss->lock); + } + } + /* If the last RPC generated a SIGTTOU, loop to try it again. */ + } while (err == EBACKGROUND); + + return err; +} diff --git a/hurd/dtable.c b/hurd/dtable.c new file mode 100644 index 0000000000..3e785a9710 --- /dev/null +++ b/hurd/dtable.c @@ -0,0 +1,277 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <hurd.h> +#include <hurd/term.h> +#include <hurd/fd.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <limits.h> +#include <cthreads.h> /* For `struct mutex'. */ +#include "set-hooks.h" +#include "hurdmalloc.h" /* XXX */ + + +struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */ +struct hurd_fd **_hurd_dtable; +int _hurd_dtablesize; + + +DEFINE_HOOK (_hurd_fd_subinit, (void)); + +/* Initialize the file descriptor table at startup. */ + +static void +init_dtable (void) +{ + register size_t i; + + __mutex_init (&_hurd_dtable_lock); + + /* The initial size of the descriptor table is that of the passed-in + table. It will be expanded as necessary up to _hurd_dtable_rlimit. */ + _hurd_dtablesize = _hurd_init_dtablesize; + + /* Allocate the vector of pointers. */ + _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable)); + if (_hurd_dtablesize != 0 && _hurd_dtable == NULL) + __libc_fatal ("hurd: Can't allocate file descriptor table\n"); + + /* Initialize the descriptor table. */ + for (i = 0; i < _hurd_init_dtablesize; ++i) + { + if (_hurd_init_dtable[i] == MACH_PORT_NULL) + /* An unused descriptor is marked by a null pointer. */ + _hurd_dtable[i] = NULL; + else + { + /* Allocate a new file descriptor structure. */ + struct hurd_fd *new = malloc (sizeof (struct hurd_fd)); + if (new == NULL) + __libc_fatal ("hurd: Can't allocate initial file descriptors\n"); + + /* Initialize the port cells. */ + _hurd_port_init (&new->port, MACH_PORT_NULL); + _hurd_port_init (&new->ctty, MACH_PORT_NULL); + + /* Install the port in the descriptor. + This sets up all the ctty magic. */ + _hurd_port2fd (new, _hurd_init_dtable[i], 0); + + _hurd_dtable[i] = new; + } + } + + /* Clear out the initial descriptor table. + Everything must use _hurd_dtable now. */ + __vm_deallocate (__mach_task_self (), + (vm_address_t) _hurd_init_dtable, + _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0])); + _hurd_init_dtable = NULL; + _hurd_init_dtablesize = 0; + + /* Initialize the remaining empty slots in the table. */ + for (; i < _hurd_dtablesize; ++i) + _hurd_dtable[i] = NULL; + + /* Run things that want to run after the file descriptor table + is initialized. */ + RUN_HOOK (_hurd_fd_subinit, ()); + + (void) &init_dtable; /* Avoid "defined but not used" warning. */ +} + +text_set_element (_hurd_subinit, init_dtable); + +/* XXX when the linker supports it, the following functions should all be + elsewhere and just have text_set_elements here. */ + +/* Called by `getdport' to do its work. */ + +static file_t +get_dtable_port (int fd) +{ + file_t dport; + int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (), + (dport = port), + MACH_PORT_RIGHT_SEND, + 1)); + if (err) + { + errno = err; + return MACH_PORT_NULL; + } + else + return dport; +} + +file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port; + +#include <hurd/signal.h> + +/* We are in the child fork; the dtable lock is still held. + The parent has inserted send rights for all the normal io ports, + but we must recover ctty-special ports for ourselves. */ +static error_t +fork_child_dtable (void) +{ + error_t err; + int i; + + err = 0; + + for (i = 0; !err && i < _hurd_dtablesize; ++i) + { + struct hurd_fd *d = _hurd_dtable[i]; + if (d == NULL) + continue; + + /* No other thread is using the send rights in the child task. */ + d->port.users = d->ctty.users = NULL; + + if (d->ctty.port != MACH_PORT_NULL) + { + /* There was a ctty-special port in the parent. + We need to get one for ourselves too. */ + __mach_port_deallocate (__mach_task_self (), d->ctty.port); + err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp, + &d->ctty.port); + if (err) + d->ctty.port = MACH_PORT_NULL; + } + + /* XXX for each fd with a cntlmap, reauth and re-map_cntl. */ + } + return err; + + (void) &fork_child_dtable; /* Avoid "defined but not used" warning. */ +} + +data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */ +text_set_element (_hurd_fork_child_hook, fork_child_dtable); + +/* Called when our process group has changed. */ + +static void +ctty_new_pgrp (void) +{ + int i; + + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_dtable_lock); + + for (i = 0; i < _hurd_dtablesize; ++i) + { + struct hurd_fd *const d = _hurd_dtable[i]; + struct hurd_userlink ulink, ctty_ulink; + io_t port, ctty; + + if (d == NULL) + /* Nothing to do for an unused descriptor cell. */ + continue; + + port = _hurd_port_get (&d->port, &ulink); + ctty = _hurd_port_get (&d->ctty, &ctty_ulink); + + if (ctty != MACH_PORT_NULL) + { + /* This fd has a ctty-special port. We need a new one, to tell + the io server of our different process group. */ + io_t new; + if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new)) + new = MACH_PORT_NULL; + _hurd_port_set (&d->ctty, new); + } + + _hurd_port_free (&d->port, &ulink, port); + _hurd_port_free (&d->ctty, &ctty_ulink, ctty); + } + + __mutex_unlock (&_hurd_dtable_lock); + HURD_CRITICAL_END; + + (void) &ctty_new_pgrp; /* Avoid "defined but not used" warning. */ +} + +text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp); + +/* Called to reauthenticate the dtable when the auth port changes. */ + +static void +reauth_dtable (void) +{ + int i; + + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_dtable_lock); + + for (i = 0; i < _hurd_dtablesize; ++i) + { + struct hurd_fd *const d = _hurd_dtable[i]; + mach_port_t new, newctty, ref; + + if (d == NULL) + /* Nothing to do for an unused descriptor cell. */ + continue; + + ref = __mach_reply_port (); + + /* Take the descriptor cell's lock. */ + __spin_lock (&d->port.lock); + + /* Reauthenticate the descriptor's port. */ + if (d->port.port != MACH_PORT_NULL && + ! __io_reauthenticate (d->port.port, + ref, MACH_MSG_TYPE_MAKE_SEND) && + ! __USEPORT (AUTH, __auth_user_authenticate + (port, + d->port.port, + ref, MACH_MSG_TYPE_MAKE_SEND, + &new))) + { + /* Replace the port in the descriptor cell + with the newly reauthenticated port. */ + + if (d->ctty.port != MACH_PORT_NULL && + ! __io_reauthenticate (d->ctty.port, + ref, MACH_MSG_TYPE_MAKE_SEND) && + ! __USEPORT (AUTH, __auth_user_authenticate + (port, + d->ctty.port, + ref, MACH_MSG_TYPE_MAKE_SEND, + &newctty))) + _hurd_port_set (&d->ctty, newctty); + + _hurd_port_locked_set (&d->port, new); + } + else + /* Lost. Leave this descriptor cell alone. */ + __spin_unlock (&d->port.lock); + + __mach_port_destroy (__mach_task_self (), ref); + } + + __mutex_unlock (&_hurd_dtable_lock); + HURD_CRITICAL_END; + + (void) &reauth_dtable; /* Avoid "defined but not used" warning. */ +} + +text_set_element (_hurd_reauth_hook, reauth_dtable); diff --git a/hurd/fchroot.c b/hurd/fchroot.c new file mode 100644 index 0000000000..cccf1391be --- /dev/null +++ b/hurd/fchroot.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <unistd.h> +#include <hurd.h> +#include <hurd/fd.h> + +/* Change the current root directory to FD. */ +int +DEFUN(fchroot, (fd), int fd) +{ + error_t err; + file_t dir; + + err = __USEPORT (CRDIR, + ({ file_t crdir = port; + HURD_DPORT_USE (fd, + __hurd_file_name_lookup (crdir, port, "", + 0, 0, &dir)); + })); + + if (err) + return __hurd_fail (err); + + _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], dir); + return 0; +} diff --git a/hurd/fd-close.c b/hurd/fd-close.c new file mode 100644 index 0000000000..54beb2a09a --- /dev/null +++ b/hurd/fd-close.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd/fd.h> + +error_t +_hurd_fd_close (struct hurd_fd *fd) +{ + error_t err; + + HURD_CRITICAL_BEGIN; + + __spin_lock (&fd->port.lock); + if (fd->port.port == MACH_PORT_NULL) + { + __spin_unlock (&fd->port.lock); + err = EBADF; + } + else + { + /* Clear the descriptor's port cells. + This deallocates the ports if noone else is still using them. */ + _hurd_port_set (&fd->ctty, MACH_PORT_NULL); + _hurd_port_locked_set (&fd->port, MACH_PORT_NULL); + err = 0; + } + + HURD_CRITICAL_END; + + return err; +} diff --git a/hurd/fd-read.c b/hurd/fd-read.c new file mode 100644 index 0000000000..842066c150 --- /dev/null +++ b/hurd/fd-read.c @@ -0,0 +1,49 @@ +/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <unistd.h> +#include <hurd.h> +#include <hurd/fd.h> +#include <string.h> + +error_t +_hurd_fd_read (struct hurd_fd *fd, void *buf, size_t *nbytes) +{ + error_t err; + char *data; + mach_msg_type_number_t nread; + + error_t readfd (io_t port) + { + return __io_read (port, &data, &nread, -1, *nbytes); + } + + data = buf; + if (err = HURD_FD_PORT_USE (fd, _hurd_ctty_input (port, ctty, readfd))) + return err; + + if (data != buf) + { + memcpy (buf, data, nread); + __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread); + } + + *nbytes = nread; + return 0; +} diff --git a/hurd/fd-write.c b/hurd/fd-write.c new file mode 100644 index 0000000000..f228d5e47c --- /dev/null +++ b/hurd/fd-write.c @@ -0,0 +1,42 @@ +/* _hurd_fd_write -- write to a file descriptor; handles job control et al. +Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <unistd.h> +#include <hurd.h> +#include <hurd/fd.h> + +error_t +_hurd_fd_write (struct hurd_fd *fd, const void *buf, size_t *nbytes) +{ + error_t err; + mach_msg_type_number_t wrote; + + error_t writefd (io_t port) + { + return __io_write (port, buf, *nbytes, -1, &wrote); + } + + err = HURD_FD_PORT_USE (fd, _hurd_ctty_output (port, ctty, writefd)); + + if (! err) + *nbytes = wrote; + + return err; +} diff --git a/hurd/fopenport.c b/hurd/fopenport.c new file mode 100644 index 0000000000..5792b3e26e --- /dev/null +++ b/hurd/fopenport.c @@ -0,0 +1,131 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <hurd.h> +#include <stdio.h> +#include <fcntl.h> +#include <string.h> + +/* Read up to N chars into BUF from COOKIE. + Return how many chars were read, 0 for EOF or -1 for error. */ +static ssize_t +readio (void *cookie, char *buf, size_t n) +{ + mach_msg_type_number_t nread; + error_t err; + char *bufp = buf; + + nread = n; + if (err = __io_read ((io_t) cookie, &bufp, &nread, -1, n)) + return __hurd_fail (err); + + if (bufp != buf) + { + memcpy (buf, bufp, nread); + __vm_deallocate (__mach_task_self (), + (vm_address_t) bufp, (vm_size_t) nread); + } + + return nread; +} + +/* Write up to N chars from BUF to COOKIE. + Return how many chars were written or -1 for error. */ +static ssize_t +writeio (void *cookie, const char *buf, size_t n) +{ + mach_msg_type_number_t wrote; + error_t err; + + if (err = __io_write ((io_t) cookie, buf, n, -1, &wrote)) + return __hurd_fail (err); + + return wrote; +} + +/* Move COOKIE's file position *POS bytes, according to WHENCE. + The current file position is stored in *POS. + Returns zero if successful, nonzero if not. */ +static int +seekio (void *cookie, fpos_t *pos, int whence) +{ + error_t error = __io_seek ((file_t) cookie, *pos, whence, pos); + if (error) + return __hurd_fail (error); + return 0; +} + +/* Close the file associated with COOKIE. + Return 0 for success or -1 for failure. */ +static int +closeio (void *cookie) +{ + error_t error = __mach_port_deallocate (__mach_task_self (), + (mach_port_t) cookie); + if (error) + return __hurd_fail (error); + return 0; +} + +static const __io_functions funcsio = { readio, writeio, seekio, closeio }; + + +/* Defined in fopen.c. */ +extern int EXFUN(__getmode, (CONST char *mode, __io_mode *mptr)); + + +/* Open a stream on PORT. MODE is as for fopen. */ + +FILE * +__fopenport (mach_port_t port, const char *mode) +{ + register FILE *stream; + __io_mode m; + int pflags; + error_t err; + + if (!__getmode (mode, &m)) + return NULL; + + /* Verify the PORT is valid allows the access MODE specifies. */ + + if (err = __io_get_openmodes (port, &pflags)) + return __hurd_fail (err), NULL; + + /* Check the access mode. */ + if ((m.__read && !(pflags & O_READ)) || (m.__write && !(pflags & O_WRITE))) + { + errno = EBADF; + return NULL; + } + + stream = __newstream (); + if (stream == NULL) + return NULL; + + stream->__cookie = (PTR) port; + stream->__mode = m; + stream->__io_funcs = funcsio; + stream->__room_funcs = __default_room_functions; + stream->__seen = 1; + + return stream; +} + +weak_alias (__fopenport, fopenport) diff --git a/hurd/getdport.c b/hurd/getdport.c new file mode 100644 index 0000000000..884deaa868 --- /dev/null +++ b/hurd/getdport.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +/* This is initialized in dtable.c when that gets linked in. + If dtable.c is not linked in, it will be zero. */ +file_t (*_hurd_getdport_fn) (int fd); + +file_t +__getdport (int fd) +{ + if (_hurd_getdport_fn) + /* dtable.c has defined the function to fetch a port from the real file + descriptor table. */ + return (*_hurd_getdport_fn) (fd); + + /* getdport is the only use of file descriptors, + so we don't bother allocating a real table. */ + + if (_hurd_init_dtable == NULL) + /* Never had a descriptor table. */ + return EBADF; + + if (fd < 0 || fd > _hurd_init_dtablesize || + _hurd_init_dtable[fd] == MACH_PORT_NULL) + { + errno = EBADF; + return MACH_PORT_NULL; + } + else + { + __mach_port_mod_refs (__mach_task_self (), _hurd_init_dtable[fd], + MACH_PORT_RIGHT_SEND, 1); + return _hurd_init_dtable[fd]; + } +} + +weak_alias (__getdport, getdport) diff --git a/hurd/getuids.c b/hurd/getuids.c new file mode 100644 index 0000000000..9a62f65611 --- /dev/null +++ b/hurd/getuids.c @@ -0,0 +1,63 @@ +/* Copyright (C) 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/id.h> +#include <string.h> + +int +__getuids (int n, uid_t *uidset) +{ + error_t err; + int nuids; + void *crit; + + crit = _hurd_critical_section_lock (); + __mutex_lock (&_hurd_id.lock); + + if (err = _hurd_check_ids ()) + { + __mutex_unlock (&_hurd_id.lock); + _hurd_critical_section_unlock (crit); + return __hurd_fail (err); + } + + nuids = _hurd_id.gen.nuids; + + if (n != 0) + { + /* Copy the uids onto stack storage and then release the idlock. */ + uid_t uids[nuids]; + memcpy (uids, _hurd_id.gen.uids, sizeof (uids)); + __mutex_unlock (&_hurd_id.lock); + _hurd_critical_section_unlock (crit); + + /* Now that the lock is released, we can safely copy the + uid set into the user's array, which might fault. */ + if (nuids > n) + nuids = n; + memcpy (uidset, uids, nuids * sizeof (uid_t)); + } + else + { + __mutex_unlock (&_hurd_id.lock); + _hurd_critical_section_unlock (crit); + } + + return nuids; +} diff --git a/hurd/getumask.c b/hurd/getumask.c new file mode 100644 index 0000000000..80a8bf4590 --- /dev/null +++ b/hurd/getumask.c @@ -0,0 +1,25 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +mode_t +getumask (void) +{ + return _hurd_umask; +} diff --git a/hurd/hurd-raise.c b/hurd/hurd-raise.c new file mode 100644 index 0000000000..ad01ab9f89 --- /dev/null +++ b/hurd/hurd-raise.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/signal.h> +#include <hurd/msg.h> +#include <setjmp.h> + +/* Handle signal SIGNO in the calling thread. + If SS is not NULL it is the sigstate for the calling thread; + SS->lock is held on entry and released before return. */ + +void +_hurd_raise_signal (struct hurd_sigstate *ss, + int signo, long int sigcode, int sigerror) +{ + if (ss == NULL) + { + ss = _hurd_self_sigstate (); + __spin_lock (&ss->lock); + } + + /* Mark SIGNO as pending to be delivered. */ + __sigaddset (&ss->pending, signo); + ss->pending_data[signo].code = sigcode; + ss->pending_data[signo].error = sigerror; + + __spin_unlock (&ss->lock); + + /* Send a message to the signal thread so it + will wake up and check for pending signals. */ + __msg_sig_post (_hurd_msgport, 0, __mach_task_self ()); +} diff --git a/hurd/hurd.h b/hurd/hurd.h new file mode 100644 index 0000000000..472fb9173b --- /dev/null +++ b/hurd/hurd.h @@ -0,0 +1,292 @@ +/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_H + +#define _HURD_H 1 +#include <features.h> + + +/* Get types, macros, constants and function declarations + for all Mach microkernel interaction. */ +#include <mach.h> +#include <mach/mig_errors.h> + +/* Get types and constants necessary for Hurd interfaces. */ +#include <hurd/hurd_types.h> + +/* Get MiG stub declarations for commonly used Hurd interfaces. */ +#include <hurd/auth.h> +#include <hurd/process.h> +#include <hurd/fs.h> +#include <hurd/io.h> + +/* Get `struct hurd_port' and related definitions implementing lightweight + user references for ports. These are used pervasively throughout the C + library; this is here to avoid putting it in nearly every source file. */ +#include <hurd/port.h> + +#include <errno.h> +#define __hurd_fail(err) (errno = (err), -1) + +/* Basic ports and info, initialized by startup. */ + +extern int _hurd_exec_flags; /* Flags word passed in exec_startup. */ +extern struct hurd_port *_hurd_ports; +extern unsigned int _hurd_nports; +extern volatile mode_t _hurd_umask; + +/* Shorthand macro for referencing _hurd_ports (see <hurd/port.h>). */ + +#define __USEPORT(which, expr) \ + HURD_PORT_USE (&_hurd_ports[INIT_PORT_##which], (expr)) + + +/* Base address and size of the initial stack set up by the exec server. + If using cthreads, this stack is deallocated in startup. + Not locked. */ + +extern vm_address_t _hurd_stack_base; +extern vm_size_t _hurd_stack_size; + +/* Initial file descriptor table we were passed at startup. If we are + using a real dtable, these are turned into that and then cleared at + startup. If not, these are never changed after startup. Not locked. */ + +extern mach_port_t *_hurd_init_dtable; +extern mach_msg_type_number_t _hurd_init_dtablesize; + +/* Current process IDs. */ + +extern pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp; +extern int _hurd_orphaned; + +/* This variable is incremented every time the process IDs change. */ + +unsigned int _hurd_pids_changed_stamp; + +/* This condition is broadcast every time the process IDs change. */ +struct condition _hurd_pids_changed_sync; + +/* Unix `data break', for brk and sbrk. + If brk and sbrk are not used, this info will not be initialized or used. */ + + +/* Data break. This is what `sbrk (0)' returns. */ + +extern vm_address_t _hurd_brk; + +/* End of allocated space. This is generally `round_page (_hurd_brk)'. */ + +extern vm_address_t _hurd_data_end; + +/* This mutex locks _hurd_brk and _hurd_data_end. */ + +extern struct mutex _hurd_brk_lock; + +/* Set the data break to NEWBRK; _hurd_brk_lock must + be held, and is released on return. */ + +extern int _hurd_set_brk (vm_address_t newbrk); + +#define __need_FILE +#include <stdio.h> + +/* Calls to get and set basic ports. */ + +extern error_t _hurd_ports_get (int which, mach_port_t *result); +extern error_t _hurd_ports_set (int which, mach_port_t newport); + +extern process_t getproc (void); +extern file_t getcwdir (void), getcrdir (void); +extern auth_t getauth (void); +extern mach_port_t getcttyid (); +extern int setproc (process_t); +extern int setcwdir (file_t), setcrdir (file_t); +extern int setcttyid (mach_port_t); + +/* Does reauth with the proc server and fd io servers. */ +extern int __setauth (auth_t), setauth (auth_t); + + +/* Split FILE into a directory and a name within the directory. Look up a + port for the directory and store it in *DIR; store in *NAME a pointer + into FILE where the name within directory begins. The directory lookup + uses CRDIR for the root directory and CWDIR for the current directory. + Returns zero on success or an error code. */ + +extern error_t __hurd_file_name_split (file_t crdir, file_t cwdir, + const char *file, + file_t *dir, char **name); +extern error_t hurd_file_name_split (file_t crdir, file_t cwdir, + const char *file, + file_t *dir, char **name); + +/* Open a port to FILE with the given FLAGS and MODE (see <fcntl.h>). + The file lookup uses CRDIR for the root directory and CWDIR for the + current directory. If successful, returns zero and store the port + to FILE in *PORT; otherwise returns an error code. */ + +extern error_t __hurd_file_name_lookup (file_t crdir, file_t cwdir, + const char *file, + int flags, mode_t mode, + file_t *port); +extern error_t hurd_file_name_lookup (file_t crdir, file_t cwdir, + const char *filename, + int flags, mode_t mode, + file_t *port); + +/* Process the values returned by `dir_lookup' et al, and loop doing + `dir_lookup' calls until one returns FS_RETRY_NONE. CRDIR is the + root directory used for things like symlinks to absolute file names; the + other arguments should be those just passed to and/or returned from + `dir_lookup', `fsys_getroot', or `file_invoke_translator'. This + function consumes the reference in *RESULT even if it returns an error. */ + +extern error_t __hurd_file_name_lookup_retry (file_t crdir, + enum retry_type doretry, + char retryname[1024], + int flags, mode_t mode, + file_t *result); +extern error_t hurd_file_name_lookup_retry (file_t crdir, + enum retry_type doretry, + char retryname[1024], + int flags, mode_t mode, + file_t *result); + + +/* Split FILE into a directory and a name within the directory. The + directory lookup uses the current root and working directory. If + successful, stores in *NAME a pointer into FILE where the name + within directory begins and returns a port to the directory; + otherwise sets `errno' and returns MACH_PORT_NULL. */ + +extern file_t __file_name_split (const char *file, char **name); +extern file_t file_name_split (const char *file, char **name); + +/* Open a port to FILE with the given FLAGS and MODE (see <fcntl.h>). + The file lookup uses the current root and working directory. + Returns a port to the file if successful; otherwise sets `errno' + and returns MACH_PORT_NULL. */ + +extern file_t __file_name_lookup (const char *file, int flags, mode_t mode); +extern file_t file_name_lookup (const char *file, int flags, mode_t mode); + +/* Invoke any translator set on the node FILE represents, and return in + *TRANSLATED a port to the translated node. FLAGS are as for + `dir_lookup' et al, but the returned port will not necessarily have + any more access rights than FILE does. */ + +extern error_t __hurd_invoke_translator (file_t file, int flags, + file_t *translated); +extern error_t hurd_invoke_translator (file_t file, int flags, + file_t *translated); + + +/* Open a file descriptor on a port. FLAGS are as for `open'; flags + affected by io_set_openmodes are not changed by this. If successful, + this consumes a user reference for PORT (which will be deallocated on + close). */ + +extern int openport (io_t port, int flags); + +/* Open a stream on a port. MODE is as for `fopen'. + If successful, this consumes a user reference for PORT + (which will be deallocated on fclose). */ + +extern FILE *fopenport (io_t port, const char *mode); +extern FILE *__fopenport (io_t port, const char *mode); + + +/* Execute a file, replacing TASK's current program image. */ + +extern error_t _hurd_exec (task_t task, + file_t file, + char *const argv[], + char *const envp[]); + + +/* Inform the proc server we have exitted with STATUS, and kill the + task thoroughly. This function never returns, no matter what. */ + +extern void _hurd_exit (int status) __attribute__ ((noreturn)); + + +/* Initialize the library data structures from the + ints and ports passed to us by the exec server. + Then vm_deallocate PORTARRAY and INTARRAY. */ + +extern void _hurd_init (int flags, char **argv, + mach_port_t *portarray, size_t portarraysize, + int *intarray, size_t intarraysize); + +/* Do startup handshaking with the proc server. */ + +extern void _hurd_proc_init (char **argv); + + +/* Return the socket server for sockaddr domain DOMAIN. If DEAD is + nonzero, remove the old cached port and always do a fresh lookup. + + It is assumed that a socket server will stay alive during a complex socket + operation involving several RPCs. But a socket server may die during + long idle periods between socket operations. Callers should first pass + zero for DEAD; if the first socket RPC tried on the returned port fails + with MACH_SEND_INVALID_DEST or MIG_SERVER_DIED (indicating the server + went away), the caller should call _hurd_socket_server again with DEAD + nonzero and retry the RPC on the new socket server port. */ + +extern socket_t _hurd_socket_server (int domain, int dead); + +/* Send a `sig_post' RPC to process number PID. If PID is zero, + send the message to all processes in the current process's process group. + If PID is < -1, send SIG to all processes in process group - PID. + SIG and REFPORT are passed along in the request message. */ + +extern error_t _hurd_sig_post (pid_t pid, int sig, mach_port_t refport); +extern error_t hurd_sig_post (pid_t pid, int sig, mach_port_t refport); + +/* Fetch the host privileged port and device master port from the proc + server. They are fetched only once and then cached in the + variables below. A special program that gets them from somewhere + other than the proc server (such as a bootstrap filesystem) can set + these variables to install the ports. */ + +extern kern_return_t get_privileged_ports (host_priv_t *host_priv_ptr, + device_t *device_master_ptr); +extern mach_port_t _hurd_host_priv, _hurd_device_master; + +/* Return the PID of the task whose control port is TASK. + On error, sets `errno' and returns -1. */ + +extern pid_t __task2pid (task_t task), task2pid (task_t task); + +/* Return the task control port of process PID. + On error, sets `errno' and returns MACH_PORT_NULL. */ + +extern task_t __pid2task (pid_t pid), pid2task (pid_t pid); + + +/* Return the io server port for file descriptor FD. + This adds a Mach user reference to the returned port. + On error, sets `errno' and returns MACH_PORT_NULL. */ + +extern io_t __getdport (int fd), getdport (int fd); + + +#endif /* hurd.h */ diff --git a/hurd/hurd/fd.h b/hurd/hurd/fd.h new file mode 100644 index 0000000000..4747c785a5 --- /dev/null +++ b/hurd/hurd/fd.h @@ -0,0 +1,222 @@ +/* File descriptors. +Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_FD_H + +#define _HURD_FD_H 1 +#include <features.h> + +#include <hurd/hurd_types.h> +#include <hurd/port.h> + + +/* Structure representing a file descriptor. */ + +struct hurd_fd + { + struct hurd_port port; /* io server port. */ + int flags; /* fcntl flags; locked by port.lock. */ + + /* Normal port to the ctty. When `port' is our ctty, this is a port to + the same io object but which never returns EBACKGROUND; when not, + this is nil. */ + struct hurd_port ctty; + }; + + +/* Current file descriptor table. */ + +extern int _hurd_dtablesize; +extern struct hurd_fd **_hurd_dtable; +extern struct mutex _hurd_dtable_lock; /* Locks those two variables. */ + +#include <hurd/signal.h> +#include <lock-intern.h> + +#ifndef _EXTERN_INLINE +#define _EXTERN_INLINE extern __inline +#endif + +/* Returns the descriptor cell for FD. If FD is invalid or unused, return + NULL. The cell is unlocked; when ready to use it, lock it and check for + it being unused. */ + +_EXTERN_INLINE struct hurd_fd * +_hurd_fd_get (int fd) +{ + struct hurd_fd *descriptor; + + __mutex_lock (&_hurd_dtable_lock); + if (fd < 0 || fd >= _hurd_dtablesize) + descriptor = NULL; + else + { + struct hurd_fd *cell = _hurd_dtable[fd]; + if (cell == NULL) + /* No descriptor allocated at this index. */ + descriptor = NULL; + else + { + __spin_lock (&cell->port.lock); + if (cell->port.port == MACH_PORT_NULL) + /* The descriptor at this index has no port in it. + This happens if it existed before but was closed. */ + descriptor = NULL; + else + descriptor = cell; + __spin_unlock (&cell->port.lock); + } + } + __mutex_unlock (&_hurd_dtable_lock); + + return descriptor; +} + + +/* Evaluate EXPR with the variable `descriptor' bound to a pointer to the + file descriptor structure for FD. */ + +#define HURD_FD_USE(fd, expr) \ + ({ struct hurd_fd *descriptor = _hurd_fd_get (fd); \ + descriptor == NULL ? EBADF : (expr); }) + +/* Evaluate EXPR with the variable `port' bound to the port to FD, and + `ctty' bound to the ctty port. */ + +#define HURD_DPORT_USE(fd, expr) \ + HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr))) + +/* Likewise, but FD is a pointer to the file descriptor structure. */ + +#define HURD_FD_PORT_USE(fd, expr) \ + ({ error_t __result; \ + struct hurd_fd *const __d = (fd); \ + struct hurd_userlink __ulink, __ctty_ulink; \ + io_t port, ctty; \ + void *crit = _hurd_critical_section_lock (); \ + __spin_lock (&__d->port.lock); \ + if (__d->port.port == MACH_PORT_NULL) \ + { \ + __spin_unlock (&__d->port.lock); \ + _hurd_critical_section_unlock (crit); \ + __result = EBADF; \ + } \ + else \ + { \ + ctty = _hurd_port_get (&__d->ctty, &__ctty_ulink); \ + port = _hurd_port_locked_get (&__d->port, &__ulink); \ + _hurd_critical_section_unlock (crit); \ + __result = (expr); \ + _hurd_port_free (&__d->port, &__ulink, port); \ + if (ctty != MACH_PORT_NULL) \ + _hurd_port_free (&__d->ctty, &__ctty_ulink, ctty); \ + } \ + __result; }) + +#include <errno.h> + +/* Check if ERR should generate a signal. + Returns the signal to take, or zero if none. */ + +_EXTERN_INLINE error_t +_hurd_fd_error_signal (error_t err) +{ + switch (err) + { + case EMACH_SEND_INVALID_DEST: + case EMIG_SERVER_DIED: + /* The server has disappeared! */ + return SIGLOST; + case EPIPE: + return SIGPIPE; + default: + /* Having a default case avoids -Wenum-switch warnings. */ + return 0; + } +} + +/* Handle an error from an RPC on a file descriptor's port. You should + always use this function to handle errors from RPCs made on file + descriptor ports. Some errors are translated into signals. */ + +_EXTERN_INLINE error_t +_hurd_fd_error (int fd, error_t err) +{ + int signo = _hurd_fd_error_signal (err); + if (signo) + _hurd_raise_signal (NULL, signo, fd, err); + return err; +} + +/* Handle error code ERR from an RPC on file descriptor FD's port. + Set `errno' to the appropriate error code, and always return -1. */ + +_EXTERN_INLINE int +__hurd_dfail (int fd, error_t err) +{ + errno = _hurd_fd_error (fd, err); + return -1; +} + +/* Set up *FD to have PORT its server port, doing appropriate ctty magic. + Does no locking or unlocking. */ + +extern void _hurd_port2fd (struct hurd_fd *fd, io_t port, int flags); + +/* Allocate a new file descriptor and install PORT in it (doing any + appropriate ctty magic); consumes a user reference on PORT. FLAGS are + as for `open'; only O_IGNORE_CTTY is meaningful, but all are saved. + + If the descriptor table is full, set errno, and return -1. + If DEALLOC is nonzero, deallocate PORT first. */ + +extern int _hurd_intern_fd (io_t port, int flags, int dealloc); + +/* Allocate a new file descriptor in the table and return it, locked. The + new descriptor number will be no less than FIRST_FD. If the table is + full, set errno to EMFILE and return NULL. If FIRST_FD is negative or + bigger than the size of the table, set errno to EINVAL and return NULL. */ + +extern struct hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd); + +/* Allocate a new file descriptor structure and initialize its port cells + with PORT and CTTY. (This does not affect the descriptor table.) */ + +extern struct hurd_fd *_hurd_new_fd (io_t port, io_t ctty); + +/* Close a file descriptor, making it available for future reallocation. */ + +extern error_t _hurd_fd_close (struct hurd_fd *fd); + +/* Read and write data from a file descriptor; just like `read' and `write'. + If successful, stores the amount actually read or written in *NBYTES. */ + +extern error_t _hurd_fd_read (struct hurd_fd *fd, void *buf, size_t *nbytes); +extern error_t _hurd_fd_write (struct hurd_fd *fd, + const void *buf, size_t *nbytes); + + +/* Call *RPC on PORT and/or CTTY; if a call on CTTY returns EBACKGROUND, + generate SIGTTIN/SIGTTOU or EIO as appropriate. */ + +extern error_t _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t)); +extern error_t _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t)); + + +#endif /* hurd/fd.h */ diff --git a/hurd/hurd/id.h b/hurd/hurd/id.h new file mode 100644 index 0000000000..7a50081038 --- /dev/null +++ b/hurd/hurd/id.h @@ -0,0 +1,55 @@ +/* User and group IDs. +Copyright (C) 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_ID_H + +#define _HURD_ID_H 1 +#include <features.h> + +#include <cthreads.h> /* For `struct mutex'. */ + +/* Structure describing authorization data for the process. */ + +struct hurd_id_data + { + struct mutex lock; + + int valid; /* If following data are up to date. */ + + struct + { + uid_t *uids; + gid_t *gids; + mach_msg_type_number_t nuids, ngids; + } gen, aux; + + auth_t rid_auth; /* Cache used by access. */ + }; + +/* Current data. */ + +extern struct hurd_id_data _hurd_id; + + +/* Update _hurd_id (caller should be holding the lock). */ + +extern error_t _hurd_check_ids (void); + + +#endif /* hurd/id.h */ diff --git a/hurd/hurd/ioctl.h b/hurd/hurd/ioctl.h new file mode 100644 index 0000000000..cc83433c17 --- /dev/null +++ b/hurd/hurd/ioctl.h @@ -0,0 +1,71 @@ +/* User-registered handlers for specific `ioctl' requests. +Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_IOCTL_H +#define _HURD_IOCTL_H 1 + +#define __need___va_list +#include <stdarg.h> + + +/* Type of handler function, called like ioctl to do its entire job. */ +typedef int (*ioctl_handler_t) (int fd, int request, void *arg); + +/* Structure that records an ioctl handler. */ +struct ioctl_handler + { + int first_request, last_request; /* Range of handled request values. */ + + /* Handler function, called like ioctl to do its entire job. */ + ioctl_handler_t handler; + + struct ioctl_handler *next; /* Next handler. */ + }; + + +/* Register HANDLER to handle ioctls with REQUEST values between + FIRST_REQUEST and LAST_REQUEST inclusive. Returns zero if successful. + Return nonzero and sets `errno' for an error. */ + +extern int hurd_register_ioctl_handler (int first_request, int last_request, + ioctl_handler_t handler); + + +/* Define a library-internal handler for ioctl commands between FIRST and + LAST inclusive. The last element gratuitously references HANDLER to + avoid `defined but not used' warnings. */ + +#define _HURD_HANDLE_IOCTLS(handler, first, last) \ + static const struct ioctl_handler handler##_ioctl_handler = \ + { (first), (last), (int (*) (int, int, void *)) (handler), \ + (&(handler), &(handler##_ioctl_handler), NULL) }; \ + text_set_element (_hurd_ioctl_handler_lists, ##handler##_ioctl_handler) + +/* Define a library-internal handler for a single ioctl command. */ + +#define _HURD_HANDLE_IOCTL(handler, ioctl) \ + _HURD_HANDLE_IOCTLS (handler, (ioctl), (ioctl)) + + +/* Lookup the handler for the given ioctl request. */ + +ioctl_handler_t _hurd_lookup_ioctl_handler (int request); + + +#endif /* hurd/ioctl.h */ diff --git a/hurd/hurd/port.h b/hurd/hurd/port.h new file mode 100644 index 0000000000..a057503d4a --- /dev/null +++ b/hurd/hurd/port.h @@ -0,0 +1,152 @@ +/* Lightweight user references for ports. +Copyright (C) 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_PORT_H + +#define _HURD_PORT_H 1 +#include <features.h> + +#include <mach.h> +#include <hurd/userlink.h> +#include <spin-lock.h> +#include <hurd/signal.h> + + +/* Structure describing a cell containing a port. With the lock held, a + user extracts PORT, and attaches his own link (in local storage) to the + USERS chain. PORT can then safely be used. When PORT is no longer + needed, with the lock held, the user removes his link from the chain. + If his link is the last, and PORT has changed since he fetched it, the + user deallocates the port he used. See <hurd/userlink.h>. */ + +struct hurd_port + { + spin_lock_t lock; /* Locks rest. */ + struct hurd_userlink *users; /* Chain of users; see below. */ + mach_port_t port; /* Port. */ + }; + + +/* Evaluate EXPR with the variable `port' bound to the port in PORTCELL. */ + +#define HURD_PORT_USE(portcell, expr) \ + ({ struct hurd_port *const __p = (portcell); \ + struct hurd_userlink __link; \ + const mach_port_t port = _hurd_port_get (__p, &__link); \ + __typeof(expr) __result = (expr); \ + _hurd_port_free (__p, &__link, port); \ + __result; }) + + +#ifndef _EXTERN_INLINE +#define _EXTERN_INLINE extern __inline +#endif + + +/* Initialize *PORT to INIT. */ + +_EXTERN_INLINE void +_hurd_port_init (struct hurd_port *port, mach_port_t init) +{ + __spin_lock_init (&port->lock); + port->users = NULL; + port->port = init; +} + + +/* Get a reference to *PORT, which is locked. + Pass return value and LINK to _hurd_port_free when done. */ + +_EXTERN_INLINE mach_port_t +_hurd_port_locked_get (struct hurd_port *port, + struct hurd_userlink *link) +{ + mach_port_t result; + result = port->port; + if (result != MACH_PORT_NULL) + _hurd_userlink_link (&port->users, link); + __spin_unlock (&port->lock); + return result; +} + +/* Same, but locks PORT first. */ + +_EXTERN_INLINE mach_port_t +_hurd_port_get (struct hurd_port *port, + struct hurd_userlink *link) +{ + mach_port_t result; + HURD_CRITICAL_BEGIN; + __spin_lock (&port->lock); + result = _hurd_port_locked_get (port, link); + HURD_CRITICAL_END; + return result; +} + + +/* Free a reference gotten with `USED_PORT = _hurd_port_get (PORT, LINK);' */ + +_EXTERN_INLINE void +_hurd_port_free (struct hurd_port *port, + struct hurd_userlink *link, + mach_port_t used_port) +{ + int dealloc; + if (used_port == MACH_PORT_NULL) + /* When we fetch an empty port cell with _hurd_port_get, + it does not link us on the users chain, since there is + no shared resource. */ + return; + HURD_CRITICAL_BEGIN; + __spin_lock (&port->lock); + dealloc = _hurd_userlink_unlink (link); + __spin_unlock (&port->lock); + HURD_CRITICAL_END; + if (dealloc) + __mach_port_deallocate (__mach_task_self (), used_port); +} + + +/* Set *PORT's port to NEWPORT. NEWPORT's reference is consumed by PORT->port. + PORT->lock is locked. */ + +_EXTERN_INLINE void +_hurd_port_locked_set (struct hurd_port *port, mach_port_t newport) +{ + mach_port_t old; + old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL; + port->port = newport; + __spin_unlock (&port->lock); + if (old != MACH_PORT_NULL) + __mach_port_deallocate (__mach_task_self (), old); +} + +/* Same, but locks PORT first. */ + +_EXTERN_INLINE void +_hurd_port_set (struct hurd_port *port, mach_port_t newport) +{ + HURD_CRITICAL_BEGIN; + __spin_lock (&port->lock); + _hurd_port_locked_set (port, newport); + HURD_CRITICAL_END; +} + + +#endif /* hurd/port.h */ diff --git a/hurd/hurd/resource.h b/hurd/hurd/resource.h new file mode 100644 index 0000000000..ad2a61ab42 --- /dev/null +++ b/hurd/hurd/resource.h @@ -0,0 +1,50 @@ +/* Resource limits for the Hurd. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_RESOURCE_H +#define _HURD_RESOURCE_H + +#include <sys/types.h> +#include <sys/resource.h> +#include <errno.h> +#include <hurd/process.h> + +/* This array contains the current resource limits for the process. */ +extern struct rlimit _hurd_rlimits[RLIM_NLIMITS]; +extern struct mutex _hurd_rlimit_lock; /* Locks _hurd_rlimits. */ + + +/* Helper function for getpriority and setpriority. Maps FN over all the + processes specified by WHICH and WHO. PI is non-null if a + proc_getprocinfo was already done; FN may use *PI arbitrarily, it is + reset on the next call. Returns FN's result the first time it returns + nonzero. If FN never returns nonzero, this returns zero. */ +extern error_t _hurd_priority_which_map (enum __priority_which which, int who, + error_t (*fn) (pid_t pid, + struct procinfo *pi)); + +/* Convert between Mach priority values and the priority + values used by getpriority, setpriority, and nice. */ +#define MACH_PRIORITY_TO_NICE(prio) (2 * ((prio) - 12)) +#define NICE_TO_MACH_PRIORITY(nice) (12 + ((nice) / 2)) + + + + +#endif diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h new file mode 100644 index 0000000000..76007d5037 --- /dev/null +++ b/hurd/hurd/signal.h @@ -0,0 +1,391 @@ +/* Implementing POSIX.1 signals under the Hurd. +Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_SIGNAL_H + +#define _HURD_SIGNAL_H 1 +#include <features.h> +/* Make sure <signal.h> is going to define NSIG. */ +#ifndef __USE_GNU +#error "Must have `_GNU_SOURCE' feature test macro to use this file" +#endif + +#define __need_NULL +#include <stddef.h> + +#include <mach/mach_types.h> +#include <mach/port.h> +#include <mach/message.h> +#include <hurd/hurd_types.h> +#include <signal.h> +#include <errno.h> +#include <hurd/msg.h> + +#include <cthreads.h> /* For `struct mutex'. */ +#include <spin-lock.h> +#include <hurd/threadvar.h> /* We cache sigstate in a threadvar. */ + + +/* Per-thread signal state. */ + +struct hurd_sigstate + { + spin_lock_t lock; /* Locks most of the rest of the structure. */ + + int critical_section; /* Nonzero if in critical section. */ + + thread_t thread; + struct hurd_sigstate *next; /* Linked-list of thread sigstates. */ + + sigset_t blocked; /* What signals are blocked. */ + sigset_t pending; /* Pending signals, possibly blocked. */ + struct sigaction actions[NSIG]; + struct sigaltstack sigaltstack; + struct + { + /* For each signal that may be pending, the + sigcode and error code to deliver it with. */ + long int code; + error_t error; + } pending_data[NSIG]; + + /* If `suspended' is set when this thread gets a signal, + the signal thread sends an empty message to it. */ + mach_port_t suspended; + + /* The following members are not locked. They are used only by this + thread, or by the signal thread with this thread suspended. */ + + volatile mach_port_t intr_port; /* Port interruptible RPC was sent on. */ + + /* If this is not null, the thread is in sigreturn awaiting delivery of + pending signals. This context (the machine-dependent portions only) + will be passed to sigreturn after running the handler for a pending + signal, instead of examining the thread state. */ + struct sigcontext *context; + }; + +/* Linked list of states of all threads whose state has been asked for. */ + +extern struct hurd_sigstate *_hurd_sigstates; + +extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates. */ + +/* Get the sigstate of a given thread, taking its lock. */ + +extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t); + +/* Get the sigstate of the current thread. + This uses a per-thread variable to optimize the lookup. */ +_EXTERN_INLINE struct hurd_sigstate * +_hurd_self_sigstate (void) +{ + struct hurd_sigstate **location = + (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE); + if (*location == NULL) + *location = _hurd_thread_sigstate (__mach_thread_self ()); + return *location; +} + +/* Thread listening on our message port; also called the "signal thread". */ + +extern thread_t _hurd_msgport_thread; + +/* Our message port. We hold the receive right and _hurd_msgport_thread + listens for messages on it. We also hold a send right, for convenience. */ + +extern mach_port_t _hurd_msgport; + + +/* Thread to receive process-global signals. */ + +extern thread_t _hurd_sigthread; + + +/* Resource limit on core file size. Enforced by hurdsig.c. */ +extern int _hurd_core_limit; + +/* Critical sections. + + A critical section is a section of code which cannot safely be interrupted + to run a signal handler; for example, code that holds any lock cannot be + interrupted lest the signal handler try to take the same lock and + deadlock result. */ + +_EXTERN_INLINE void * +_hurd_critical_section_lock (void) +{ + struct hurd_sigstate **location = + (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE); + struct hurd_sigstate *ss = *location; + if (ss == NULL) + /* The thread variable is unset; this must be the first time we've + asked for it. In this case, the critical section flag cannot + possible already be set. Look up our sigstate structure the slow + way; this locks the sigstate lock. */ + ss = *location = _hurd_thread_sigstate (__mach_thread_self ()); + else + __spin_lock (&ss->lock); + + if (ss->critical_section) + { + /* We are already in a critical section, so do nothing. */ + __spin_unlock (&ss->lock); + return NULL; + } + + /* Set the critical section flag so no signal handler will run. */ + ss->critical_section = 1; + __spin_unlock (&ss->lock); + + /* Return our sigstate pointer; this will be passed to + _hurd_critical_section_unlock to clear the critical section flag. */ + return ss; +} + +_EXTERN_INLINE void +_hurd_critical_section_unlock (void *our_lock) +{ + if (our_lock == NULL) + /* The critical section lock was held when we began. Do nothing. */ + return; + else + { + /* It was us who acquired the critical section lock. Clear the + critical section flag. */ + struct hurd_sigstate *ss = our_lock; + sigset_t pending; + __spin_lock (&ss->lock); + ss->critical_section = 0; + pending = ss->pending & ~ss->blocked; + __spin_unlock (&ss->lock); + if (pending) + /* There are unblocked signals pending, which weren't + delivered because we were in the critical section. + Tell the signal thread to deliver them now. */ + __msg_sig_post (_hurd_msgport, 0, __mach_task_self ()); + } +} + +/* Convenient macros for simple uses of critical sections. + These two must be used as a pair at the same C scoping level. */ + +#define HURD_CRITICAL_BEGIN \ + { void *__hurd_critical__ = _hurd_critical_section_lock () +#define HURD_CRITICAL_END \ + _hurd_critical_section_unlock (__hurd_critical__); } while (0) + +/* Initialize the signal code, and start the signal thread. */ + +extern void _hurdsig_init (void); + +/* Initialize proc server-assisted fault recovery for the signal thread. */ + +extern void _hurdsig_fault_init (void); + +/* Raise a signal as described by SIGNO, SIGCODE and SIGERROR, on the + thread whose sigstate SS points to. If SS is a null pointer, this + instead affects the calling thread. */ + +extern void _hurd_raise_signal (struct hurd_sigstate *ss, + int signo, long int sigcode, int sigerror); + +/* Translate a Mach exception into a signal (machine-dependent). */ + +extern void _hurd_exception2signal (int exception, int code, int subcode, + int *signo, long int *sigcode, int *error); + + +/* Make the thread described by SS take the signal described by SIGNO and + SIGCODE. If the process is traced, this will in fact stop with a SIGNO + as the stop signal unless UNTRACED is nonzero. When the signal can be + considered delivered, sends a sig_post reply message on REPLY_PORT + indicating success. SS is not locked. */ + +extern void _hurd_internal_post_signal (struct hurd_sigstate *ss, + int signo, long int sigcode, int error, + mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, + int untraced); + +/* Set up STATE and SS to handle signal SIGNO by running HANDLER. If + RPC_WAIT is nonzero, the thread needs to wait for a pending RPC to + finish before running the signal handler. The handler is passed SIGNO, + SIGCODE, and the returned `struct sigcontext' (which resides on the + stack the handler will use, and which describes the state of the thread + encoded in STATE before running the handler). */ + +struct machine_thread_all_state; +extern struct sigcontext * +_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler, + int signo, long int sigcode, + int rpc_wait, struct machine_thread_all_state *state); + +/* Function run by the signal thread to receive from the signal port. */ + +extern void _hurd_msgport_receive (void); + +/* STATE describes a thread that had intr_port set (meaning it was inside + HURD_EINTR_RPC), after it has been thread_abort'd. It it looks to have + just completed a mach_msg_trap system call that returned + MACH_RCV_INTERRUPTED, return nonzero and set *PORT to the receive right + being waited on. */ + +extern int _hurdsig_rcv_interrupted_p (struct machine_thread_all_state *state, + mach_port_t *port); + +/* Set up STATE with a thread state that, when resumed, is + like `longjmp (_hurd_sigthread_fault_env, 1)'. */ + +extern void _hurd_initialize_fault_recovery_state (void *state); + + +/* Function run for SIGINFO when its action is SIG_DFL and the current + process is the session leader. */ + +extern void _hurd_siginfo_handler (int); + + +/* Perform interruptible RPC CALL on PORT. + The call should use + The args in CALL should be constant or local variable refs. + They may be evaluated many times, and must not change. + PORT must not be deallocated before this RPC is finished. */ +#define HURD_EINTR_RPC(port, call) \ + ({ \ + __label__ __do_call; /* Give this label block scope. */ \ + error_t __err; \ + struct hurd_sigstate *__ss = _hurd_self_sigstate (); \ + __do_call: \ + /* Tell the signal thread that we are doing an interruptible RPC on \ + this port. If we get a signal and should return EINTR, the signal \ + thread will set this variable to MACH_PORT_NULL. The RPC might \ + return EINTR when some other thread gets a signal, in which case we \ + want to restart our call. */ \ + __ss->intr_port = (port); \ + /* A signal may arrive here, after intr_port is set, but before the \ + mach_msg system call. The signal handler might do an interruptible \ + RPC, and clobber intr_port; then it would not be set properly when \ + we actually did send the RPC, and a later signal wouldn't interrupt \ + that RPC. So, _hurd_setup_sighandler saves intr_port in the \ + sigcontext, and sigreturn restores it. */ \ + switch (__err = (call)) \ + { \ + case EINTR: /* RPC went out and was interrupted. */ \ + case MACH_SEND_INTERRUPTED: /* RPC didn't get out. */ \ + if (__ss->intr_port != MACH_PORT_NULL) \ + /* If this signal was for us and it should interrupt calls, the \ + signal thread will have cleared SS->intr_port. Since it's not \ + cleared, the signal was for another thread, or SA_RESTART is \ + set. Restart the interrupted call. */ \ + goto __do_call; \ + /* FALLTHROUGH */ \ + case MACH_RCV_PORT_DIED: \ + /* Server didn't respond to interrupt_operation, \ + so the signal thread destroyed the reply port. */ \ + __err = EINTR; \ + break; \ + default: /* Quiet -Wswitch-enum. */ \ + } \ + __ss->intr_port = MACH_PORT_NULL; \ + __err; \ + }) \ + + +/* Mask of signals that cannot be caught, blocked, or ignored. */ +#define _SIG_CANT_MASK (__sigmask (SIGSTOP) | __sigmask (SIGKILL)) + +/* Do an RPC to a process's message port. + + Each argument is an expression which returns an error code; each + expression may be evaluated several times. FETCH_MSGPORT_EXPR should + fetch the appropriate message port and store it in the local variable + `msgport'; it will be deallocated after use. FETCH_REFPORT_EXPR should + fetch the appropriate message port and store it in the local variable + `refport' (if no reference port is needed in the call, then + FETCH_REFPORT_EXPR should be simply KERN_SUCCESS or 0); if + DEALLOC_REFPORT evaluates to nonzero it will be deallocated after use, + otherwise the FETCH_REFPORT_EXPR must take care of user references to + `refport'. RPC_EXPR should perform the desired RPC operation using + `msgport' and `refport'. + + The reason for the complexity is that a process's message port and + reference port may change between fetching those ports and completing an + RPC using them (usually they change only when a process execs). The RPC + will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can + send the RPC request; or with MIG_SERVER_DIED if the msgport was + destroyed after we sent the RPC request but before it was serviced. In + either of these cases, we retry the entire operation, discarding the old + message and reference ports and fetch them anew. */ + +#define HURD_MSGPORT_RPC(fetch_msgport_expr, \ + fetch_refport_expr, dealloc_refport, \ + rpc_expr) \ +({ \ + error_t __err; \ + mach_port_t msgport, refport = MACH_PORT_NULL; \ + do \ + { \ + /* Get the message port. */ \ + if (__err = (fetch_msgport_expr)) \ + break; \ + /* Get the reference port. */ \ + if (__err = (fetch_refport_expr)) \ + { \ + /* Couldn't get it; deallocate MSGPORT and fail. */ \ + __mach_port_deallocate (__mach_task_self (), msgport); \ + break; \ + } \ + __err = (rpc_expr); \ + __mach_port_deallocate (__mach_task_self (), msgport); \ + if ((dealloc_refport) && refport != MACH_PORT_NULL) \ + __mach_port_deallocate (__mach_task_self (), refport); \ + } while (__err == MACH_SEND_INVALID_DEST || \ + __err == MIG_SERVER_DIED); \ + __err; \ +}) + +/* Some other parts of the library need to preempt signals, to detect + errors that should not result in a POSIX signal. For example, when + some mapped region of memory is used, an extraneous SIGSEGV might be + generated when the mapping server returns an error for a page fault. */ + +struct hurd_signal_preempt + { + /* Function to examine a thread receiving a given signal. The handler + is called even for blocked signals. This function is run in the + signal thread, with THREAD's sigstate locked; it should be as simple + and robust as possible. THREAD is the thread which is about to + receive the signal. SIGNO and SIGCODE would be passed to the normal + handler. + + If the return value is SIG_DFL, normal signal processing continues. + If it is SIG_IGN, the signal is ignored. + Any other value is used in place of the normal handler. */ + sighandler_t (*handler) (thread_t thread, + int signo, long int sigcode, int sigerror); + long int first, last; /* Range of sigcodes this handler wants. */ + struct hurd_signal_preempt *next; /* Next handler on the chain. */ + }; + +extern struct hurd_signal_preempt *_hurd_signal_preempt[NSIG]; +extern struct mutex _hurd_signal_preempt_lock; + + +#endif /* hurd/signal.h */ diff --git a/hurd/hurd/threadvar.h b/hurd/hurd/threadvar.h new file mode 100644 index 0000000000..eab133a2f6 --- /dev/null +++ b/hurd/hurd/threadvar.h @@ -0,0 +1,107 @@ +/* Internal per-thread variables for the Hurd. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_THREADVAR_H +#define _HURD_THREADVAR_H + +/* The per-thread variables are found by ANDing this mask + with the value of the stack pointer and then adding this offset. + + In the multi-threaded case, cthreads initialization sets + __hurd_threadvar_stack_mask to ~(cthread_stack_size - 1), a mask which + finds the base of the fixed-size cthreads stack; and + __hurd_threadvar_stack_offset to a small offset that skips the data + cthreads itself maintains at the base of each thread's stack. + + In the single-threaded case, __hurd_threadvar_stack_mask is zero, so the + stack pointer is ignored; and __hurd_threadvar_stack_offset gives the + address of a small allocated region which contains the variables for the + single thread. */ + +extern unsigned long int __hurd_threadvar_stack_mask; +extern unsigned long int __hurd_threadvar_stack_offset; + +/* A special case must always be made for the signal thread. Even when there + is only one user thread and an allocated region can be used for the user + thread's variables, the signal thread needs to have its own location for + per-thread variables. The variables __hurd_sigthread_stack_base and + __hurd_sigthread_stack_end define the bounds of the stack used by the + signal thread, so that thread can always be specifically identified. */ + +extern unsigned long int __hurd_sigthread_stack_base; +extern unsigned long int __hurd_sigthread_stack_end; +extern unsigned long int *__hurd_sigthread_variables; + + +/* At the location described by the two variables above, + there are __hurd_threadvar_max `unsigned long int's of per-thread data. */ +extern unsigned int __hurd_threadvar_max; + +/* These values are the indices for the standard per-thread variables. */ +enum __hurd_threadvar_index + { + _HURD_THREADVAR_MIG_REPLY, /* Reply port for MiG user stub functions. */ + _HURD_THREADVAR_ERRNO, /* `errno' value for this thread. */ + _HURD_THREADVAR_SIGSTATE, /* This thread's `struct hurd_sigstate'. */ + _HURD_THREADVAR_DYNAMIC_USER, /* Dynamically-assigned user variables. */ + _HURD_THREADVAR_MAX /* Default value for __hurd_threadvar_max. */ + }; + + +#ifndef _EXTERN_INLINE +#define _EXTERN_INLINE extern __inline +#endif + +/* Return the location of the value for the per-thread variable with index + INDEX used by the thread whose stack pointer is SP. */ + +_EXTERN_INLINE unsigned long int * +__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index, + void *__sp) +{ + unsigned long int __stack = (unsigned long int) __sp; + return &((__stack >= __hurd_sigthread_stack_base && + __stack < __hurd_sigthread_stack_end) + ? __hurd_sigthread_variables + : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + + __hurd_threadvar_stack_offset))[__index]; +} + +#include <machine-sp.h> /* Define __thread_stack_pointer. */ + +/* Return the location of the current thread's value for the + per-thread variable with index INDEX. */ + +_EXTERN_INLINE unsigned long int * +__hurd_threadvar_location (enum __hurd_threadvar_index __index) +{ + return __hurd_threadvar_location_from_sp (__index, + __thread_stack_pointer ()); +} + +/* Return the current thread's location for `errno'. + The syntax of this function allows redeclarations like `int errno'. */ +_EXTERN_INLINE int * +__hurd_errno_location (void) +{ + return (int *) __hurd_threadvar_location (_HURD_THREADVAR_ERRNO); +} + + +#endif /* hurd/threadvar.h */ diff --git a/hurd/hurd/userlink.h b/hurd/hurd/userlink.h new file mode 100644 index 0000000000..337d46aef6 --- /dev/null +++ b/hurd/hurd/userlink.h @@ -0,0 +1,105 @@ +/* Support for chains recording users of a resource; `struct hurd_userlink'. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_USERLINK_H + +#define _HURD_USERLINK_H 1 +#include <features.h> + +#define __need_NULL +#include <stddef.h> + + +/* This structure is simply a doubly-linked list. Users of a given + resource are recorded by their presence in a list associated with that + resource. A user attaches his own link (in local storage) to a shared + chain at the time he begins using some resource. When finished with + that resource, the user removes his link from the chain. If his link is + the last (there are no other users of the resource), and his chain has + been detached from the shared cell (the resource in the cell has been + replaced), then the user deallocates the resource that he used. */ + +struct hurd_userlink + { + struct hurd_userlink *next, **prevp; + }; + + +#ifndef _EXTERN_INLINE +#define _EXTERN_INLINE extern __inline +#endif + + +/* Attach LINK to the chain of users at *CHAINP. */ + +_EXTERN_INLINE void +_hurd_userlink_link (struct hurd_userlink **chainp, + struct hurd_userlink *link) +{ + link->next = *chainp; + if (link->next) + link->next->prevp = &link->next; + link->prevp = chainp; + *chainp = link; +} + + +/* Detach LINK from its chain. If the return value is nonzero, the caller + should deallocate the resource he started using after attaching LINK to + the chain it's on. If the return value is zero, then someone else is + still using the resource. */ + +_EXTERN_INLINE int +_hurd_userlink_unlink (struct hurd_userlink *link) +{ + /* The caller should deallocate the resource he used if his chain has + been detached from the cell (and thus has a nil `prevp'), and there is + no next link representing another user reference to the same resource. */ + int dealloc = ! link->next && ! link->prevp; + + /* Remove our link from the chain of current users. */ + if (link->prevp) + *link->prevp = link->next; + if (link->next) + link->next->prevp = link->prevp; + + return dealloc; +} + + +/* Clear all users from *CHAINP. Call this when the resource *CHAINP + protects is changing. If the return value is nonzero, no users are on + the chain and the caller should deallocate the resource. If the return + value is zero, someone is still using the resource and they will + deallocate it when they are finished. */ + +_EXTERN_INLINE int +_hurd_userlink_clear (struct hurd_userlink **chainp) +{ + if (*chainp == NULL) + return 1; + + /* Detach the chain of current users from the cell. The last user to + remove his link from that chain will deallocate the old resource. */ + (*chainp)->prevp = NULL; + *chainp = NULL; + return 0; +} + +#endif /* hurd/userlink.h */ diff --git a/hurd/hurdauth.c b/hurd/hurdauth.c new file mode 100644 index 0000000000..db93fd6ec3 --- /dev/null +++ b/hurd/hurdauth.c @@ -0,0 +1,130 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/msg_server.h> +#include <hurd/id.h> +#include <string.h> + +int +_hurd_refport_secure_p (mach_port_t ref) +{ + if (ref == __mach_task_self ()) + return 1; + if (__USEPORT (AUTH, ref == port)) + return 1; + return 0; +} + +kern_return_t +_S_msg_add_auth (mach_port_t me, + auth_t addauth) +{ + error_t err; + auth_t newauth; + + if (err = __USEPORT (AUTH, + __auth_makeauth (port, + &addauth, 1, MACH_MSG_TYPE_MOVE_SEND, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + &newauth))) + return err; + + err = __setauth (newauth); + __mach_port_deallocate (__mach_task_self (), newauth); + if (err) + return errno; + + return 0; +} + +kern_return_t +_S_msg_del_auth (mach_port_t me, + task_t task, + intarray_t uids, mach_msg_type_number_t nuids, + intarray_t gids, mach_msg_type_number_t ngids) +{ + error_t err; + auth_t newauth; + + if (!_hurd_refport_secure_p (task)) + return EPERM; + + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_id.lock); + err = _hurd_check_ids (); + + if (!err) + { + size_t i, j; + size_t nu = _hurd_id.gen.nuids, ng = _hurd_id.gen.ngids; + uid_t newu[nu]; + gid_t newg[ng]; + + memcpy (newu, _hurd_id.gen.uids, nu * sizeof (uid_t)); + memcpy (newg, _hurd_id.gen.gids, ng * sizeof (gid_t)); + + for (j = 0; j < nuids; ++j) + { + const uid_t uid = uids[j]; + for (i = 0; i < nu; ++i) + if (newu[i] == uid) + /* Move the last uid into this slot, and decrease the + number of uids so the last slot is no longer used. */ + newu[i] = newu[--nu]; + } + __vm_deallocate (__mach_task_self (), + (vm_address_t) uids, nuids * sizeof (uid_t)); + + for (j = 0; j < ngids; ++j) + { + const gid_t gid = gids[j]; + for (i = 0; i < nu; ++i) + if (newu[i] == gid) + /* Move the last gid into this slot, and decrease the + number of gids so the last slot is no longer used. */ + newu[i] = newu[--nu]; + } + __vm_deallocate (__mach_task_self (), + (vm_address_t) gids, ngids * sizeof (gid_t)); + + err = __USEPORT (AUTH, __auth_makeauth + (port, + NULL, 0, MACH_MSG_TYPE_COPY_SEND, + newu, nu, + _hurd_id.aux.uids, _hurd_id.aux.nuids, + newg, ng, + _hurd_id.aux.uids, _hurd_id.aux.ngids, + &newauth)); + } + __mutex_unlock (&_hurd_id.lock); + HURD_CRITICAL_END; + + if (err) + return err; + + err = __setauth (newauth); + __mach_port_deallocate (__mach_task_self (), newauth); + if (err) + return errno; + + return 0; +} diff --git a/hurd/hurdexec.c b/hurd/hurdexec.c new file mode 100644 index 0000000000..d5d2d080e4 --- /dev/null +++ b/hurd/hurdexec.c @@ -0,0 +1,259 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <hurd.h> +#include <hurd/fd.h> +#include <hurd/signal.h> + +/* Overlay TASK, executing FILE with arguments ARGV and environment ENVP. + If TASK == mach_task_self (), some ports are dealloc'd by the exec server. + ARGV and ENVP are terminated by NULL pointers. */ +error_t +_hurd_exec (task_t task, file_t file, + char *const argv[], char *const envp[]) +{ + error_t err; + char *args, *env, *ap; + size_t argslen, envlen; + int ints[INIT_INT_MAX]; + mach_port_t ports[_hurd_nports]; + struct hurd_userlink ulink_ports[_hurd_nports]; + file_t *dtable; + int dtablesize; + struct hurd_port **dtable_cells; + struct hurd_userlink *ulink_dtable; + int i; + char *const *p; + struct hurd_sigstate *ss; + mach_port_t *please_dealloc, *pdp; + + + /* Pack the arguments into an array with nulls separating the elements. */ + argslen = 0; + if (argv != NULL) + { + p = argv; + while (*p != NULL) + argslen += strlen (*p++) + 1; + args = __alloca (argslen); + ap = args; + for (p = argv; *p != NULL; ++p) + ap = __memccpy (ap, *p, '\0', ULONG_MAX); + } + else + args = NULL; + + /* Pack the environment into an array with nulls separating elements. */ + envlen = 0; + if (envp != NULL) + { + p = envp; + while (*p != NULL) + envlen += strlen (*p++) + 1; + env = __alloca (envlen); + ap = env; + for (p = envp; *p != NULL; ++p) + ap = __memccpy (ap, *p, '\0', ULONG_MAX); + } + else + env = NULL; + + /* Load up the ports to give to the new program. */ + for (i = 0; i < _hurd_nports; ++i) + if (i == INIT_PORT_PROC && task != __mach_task_self ()) + { + /* This is another task, so we need to ask the proc server + for the right proc server port for it. */ + if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i]))) + { + while (--i > 0) + _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]); + return err; + } + } + else + ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]); + + + /* Load up the ints to give the new program. */ + for (i = 0; i < INIT_INT_MAX; ++i) + switch (i) + { + case INIT_UMASK: + ints[i] = _hurd_umask; + break; + + case INIT_SIGMASK: + case INIT_SIGIGN: + case INIT_SIGPENDING: + /* We will set these all below. */ + break; + + default: + ints[i] = 0; + } + + ss = _hurd_self_sigstate (); + __spin_lock (&ss->lock); + ints[INIT_SIGMASK] = ss->blocked; + ints[INIT_SIGPENDING] = ss->pending; + ints[INIT_SIGIGN] = 0; + for (i = 1; i < NSIG; ++i) + if (ss->actions[i].sa_handler == SIG_IGN) + ints[INIT_SIGIGN] |= __sigmask (i); + + /* We hold the sigstate lock until the exec has failed so that no signal + can arrive between when we pack the blocked and ignored signals, and + when the exec actually happens. A signal handler could change what + signals are blocked and ignored. Either the change will be reflected + in the exec, or the signal will never be delivered. Setting the + critical section flag avoids anything we call trying to acquire the + sigstate lock. */ + + ss->critical_section = 1; + __spin_unlock (&ss->lock); + + /* Pack up the descriptor table to give the new program. */ + __mutex_lock (&_hurd_dtable_lock); + + dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize; + + if (task == __mach_task_self ()) + /* Request the exec server to deallocate some ports from us if the exec + succeeds. The init ports and descriptor ports will arrive in the + new program's exec_startup message. If we failed to deallocate + them, the new program would have duplicate user references for them. + But we cannot deallocate them ourselves, because we must still have + them after a failed exec call. */ + please_dealloc = __alloca ((_hurd_nports + (2 * dtablesize)) + * sizeof (mach_port_t)); + else + please_dealloc = NULL; + pdp = please_dealloc; + + if (_hurd_dtable != NULL) + { + dtable = __alloca (dtablesize * sizeof (dtable[0])); + ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0])); + dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0])); + for (i = 0; i < dtablesize; ++i) + { + struct hurd_fd *const d = _hurd_dtable[i]; + if (d == NULL) + { + dtable[i] = MACH_PORT_NULL; + continue; + } + __spin_lock (&d->port.lock); + if (d->flags & FD_CLOEXEC) + { + /* This descriptor is marked to be closed on exec. + So don't pass it to the new program. */ + dtable[i] = MACH_PORT_NULL; + if (pdp && d->port.port != MACH_PORT_NULL) + { + /* We still need to deallocate the ports. */ + *pdp++ = d->port.port; + if (d->ctty.port != MACH_PORT_NULL) + *pdp++ = d->ctty.port; + } + __spin_unlock (&d->port.lock); + } + else + { + if (pdp && d->ctty.port != MACH_PORT_NULL) + /* All the elements of DTABLE are added to PLEASE_DEALLOC + below, so we needn't add the port itself. + But we must deallocate the ctty port as well as + the normal port that got installed in DTABLE[I]. */ + *pdp++ = d->ctty.port; + dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]); + dtable_cells[i] = &d->port; + } + } + } + else + { + dtable = _hurd_init_dtable; + ulink_dtable = NULL; + dtable_cells = NULL; + } + + /* The information is all set up now. Try to exec the file. */ + + { + if (pdp) + { + /* Request the exec server to deallocate some ports from us if the exec + succeeds. The init ports and descriptor ports will arrive in the + new program's exec_startup message. If we failed to deallocate + them, the new program would have duplicate user references for them. + But we cannot deallocate them ourselves, because we must still have + them after a failed exec call. */ + + for (i = 0; i < _hurd_nports; ++i) + *pdp++ = ports[i]; + for (i = 0; i < dtablesize; ++i) + *pdp++ = dtable[i]; + } + + err = __file_exec (file, task, + _hurd_exec_flags & EXEC_INHERITED, + args, argslen, env, envlen, + dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize, + ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports, + ints, INIT_INT_MAX, + please_dealloc, pdp - please_dealloc, + NULL, 0); + } + + /* Release references to the standard ports. */ + for (i = 0; i < _hurd_nports; ++i) + if (i == INIT_PORT_PROC && task != __mach_task_self ()) + __mach_port_deallocate (__mach_task_self (), ports[i]); + else + _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]); + + if (ulink_dtable != NULL) + /* Release references to the file descriptor ports. */ + for (i = 0; i < dtablesize; ++i) + if (dtable[i] != MACH_PORT_NULL) + _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]); + + /* Release lock on the file descriptor table. */ + __mutex_unlock (&_hurd_dtable_lock); + + /* Safe to let signals happen now. */ + { + sigset_t pending; + __spin_lock (&ss->lock); + ss->critical_section = 0; + pending = ss->pending & ~ss->blocked; + __spin_unlock (&ss->lock); + if (pending) + __msg_sig_post (_hurd_msgport, 0, __mach_task_self ()); + } + + return err; +} diff --git a/hurd/hurdfault.c b/hurd/hurdfault.c new file mode 100644 index 0000000000..e8b54660b9 --- /dev/null +++ b/hurd/hurdfault.c @@ -0,0 +1,143 @@ +/* Handle faults in the signal thread. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/signal.h> +#include "hurdfault.h" +#include <errno.h> +#include <string.h> +#include <setjmp.h> +#include <stdio.h> +#include "thread_state.h" +#include "faultexc.h" /* mig-generated header for our exc server. */ + +jmp_buf _hurdsig_fault_env; + +static mach_port_t forward_sigexc; + +int _hurdsig_fault_expect_signo; +long int _hurdsig_fault_sigcode; +int _hurdsig_fault_sigerror; + +kern_return_t +_hurdsig_fault_catch_exception_raise (mach_port_t port, + thread_t thread, + task_t task, + int exception, + int code, + int subcode) +{ + int signo; + + if (port != forward_sigexc || + thread != _hurd_msgport_thread || task != __mach_task_self ()) + return EPERM; /* Strange bogosity. */ + + /* Call the machine-dependent function to translate the Mach exception + codes into a signal number and subcode. */ + _hurd_exception2signal (exception, code, subcode, &signo, + &_hurdsig_fault_sigcode, &_hurdsig_fault_sigerror); + + return signo == _hurdsig_fault_expect_signo ? 0 : EGREGIOUS; +} + +static void +faulted (void) +{ + struct + { + mach_msg_header_t head; + char buf[64]; + } request; + struct + { + mach_msg_header_t head; + mach_msg_type_t type; + int result; + } reply; + extern int _hurdsig_fault_exc_server (mach_msg_header_t *, + mach_msg_header_t *); + + /* Wait for the exception_raise message forwarded by the proc server. */ + + if (__mach_msg (&request.head, MACH_RCV_MSG, 0, + sizeof request, forward_sigexc, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) + != MACH_MSG_SUCCESS) + __libc_fatal ("msg receive failed on signal thread exc\n"); + + /* Run the exc demuxer which should call the server function above. + That function returns 0 if the exception was expected. */ + switch (_hurdsig_fault_exc_server (&request.head, &reply.head)) + { + case KERN_SUCCESS: + if (reply.head.msgh_remote_port != MACH_PORT_NULL) + __mach_msg (&reply.head, MACH_SEND_MSG, reply.head.msgh_size, + 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + break; + default: + __mach_msg_destroy (&request.head); + case MIG_NO_REPLY: + } + + _hurdsig_fault_expect_signo = 0; + longjmp (_hurdsig_fault_env, 1); +} + +static char faultstack[1024]; + +/* Send exceptions for the signal thread to the proc server. + It will forward the message on to our message port, + and then restore the thread's state to code which + does `longjmp (_hurd_sigthread_fault_env, 1)'. */ + +void +_hurdsig_fault_init (void) +{ + error_t err; + struct machine_thread_state state; + mach_port_t sigexc; + + if (err = __mach_port_allocate (__mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &sigexc)) + __libc_fatal ("hurd: Can't create receive right for signal thread exc\n"); + if (err = __mach_port_allocate (__mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &forward_sigexc)) + __libc_fatal ("hurd: Can't create receive right for signal thread exc\n"); + + memset (&state, 0, sizeof state); + MACHINE_THREAD_STATE_SET_PC (&state, faulted); + MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack); + +#if 0 /* Don't confuse gdb. */ + __thread_set_special_port (_hurd_msgport_thread, + THREAD_EXCEPTION_PORT, sigexc); +#endif + + if (err = __USEPORT + (PROC, + __proc_handle_exceptions (port, + sigexc, + forward_sigexc, MACH_MSG_TYPE_MAKE_SEND, + MACHINE_THREAD_STATE_FLAVOR, + (natural_t *) &state, + MACHINE_THREAD_STATE_COUNT))) + __libc_fatal ("hurd: proc won't handle signal thread exceptions\n"); +} + diff --git a/hurd/hurdfault.h b/hurd/hurdfault.h new file mode 100644 index 0000000000..00ec905925 --- /dev/null +++ b/hurd/hurdfault.h @@ -0,0 +1,49 @@ +/* Declarations for handling faults in the signal thread. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _HURD_FAULT_H +#define _HURD_FAULT_H + +#include <setjmp.h> + +/* Call this before code that might fault in the signal thread; SIGNO is + the signal expected to possibly arrive. This behaves like setjmp: it + returns zero the first time, and returns again nonzero if the signal + does arrive. */ + +#define _hurdsig_catch_fault(signo) \ + (_hurdsig_fault_expect_signo = (signo), setjmp (_hurdsig_fault_env)) + +/* Call this at the end of a section protected by _hurdsig_catch_fault. */ + +#define _hurdsig_end_catch_fault() \ + (_hurdsig_fault_expect_signo = 0) + +extern jmp_buf _hurdsig_fault_env; +extern int _hurdsig_fault_expect_signo; + +/* If _hurdsig_catch_fault returns nonzero, these variables + contain information about the signal that arrived. */ + + + +extern long int _hurdsig_fault_sigcode; +extern int _hurdsig_fault_sigerror; + +#endif /* hurd/fault.h */ diff --git a/hurd/hurdid.c b/hurd/hurdid.c new file mode 100644 index 0000000000..6f1c977cc8 --- /dev/null +++ b/hurd/hurdid.c @@ -0,0 +1,91 @@ +/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/id.h> + +struct hurd_id_data _hurd_id; + + +/* Check that _hurd_id.{gen,aux} are valid and update them if not. + Expects _hurd_id.lock to be held and does not release it. */ + +error_t +_hurd_check_ids (void) +{ + if (! _hurd_id.valid) + { + inline void dealloc (__typeof (_hurd_id.gen) *p) + { + if (p->uids) + { + __vm_deallocate (__mach_task_self (), + (vm_address_t) p->uids, + p->nuids * sizeof (uid_t)); + p->uids = NULL; + } + p->nuids = 0; + if (p->gids) + { + __vm_deallocate (__mach_task_self (), + (vm_address_t) p->gids, + p->ngids * sizeof (gid_t)); + p->gids = NULL; + } + p->ngids = 0; + } + + error_t err; + + dealloc (&_hurd_id.gen); + dealloc (&_hurd_id.aux); + + if (_hurd_id.rid_auth != MACH_PORT_NULL) + { + __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth); + _hurd_id.rid_auth = MACH_PORT_NULL; + } + + if (err = __USEPORT (AUTH, __auth_getids + (port, + &_hurd_id.gen.uids, &_hurd_id.gen.nuids, + &_hurd_id.aux.uids, &_hurd_id.aux.nuids, + &_hurd_id.gen.gids, &_hurd_id.gen.ngids, + &_hurd_id.aux.gids, &_hurd_id.aux.ngids))) + return err; + + _hurd_id.valid = 1; + } + + return 0; +} + +static void +init_id (void) +{ + __mutex_init (&_hurd_id.lock); + _hurd_id.valid = 0; + _hurd_id.rid_auth = MACH_PORT_NULL; + _hurd_id.gen.uids = _hurd_id.aux.uids = NULL; + _hurd_id.gen.nuids = _hurd_id.aux.nuids = 0; + _hurd_id.gen.gids = _hurd_id.aux.gids = NULL; + _hurd_id.gen.ngids = _hurd_id.aux.ngids = 0; + + (void) &init_id; /* Avoid "defined but not used" warning. */ +} +text_set_element (_hurd_preinit_hook, init_id); diff --git a/hurd/hurdinit.c b/hurd/hurdinit.c new file mode 100644 index 0000000000..4469a17339 --- /dev/null +++ b/hurd/hurdinit.c @@ -0,0 +1,193 @@ +/* Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <sys/stat.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <hurd.h> +#include <hurd/port.h> +#include "set-hooks.h" +#include "hurdmalloc.h" /* XXX */ + + +int _hurd_exec_flags; +struct hurd_port *_hurd_ports; +unsigned int _hurd_nports; +mode_t _hurd_umask; + +void _hurd_proc_init (char **argv); + +DEFINE_HOOK (_hurd_subinit, (void)); + +/* Initialize the library data structures from the + ints and ports passed to us by the exec server. + + PORTARRAY and INTARRAY are vm_deallocate'd. */ + +void +_hurd_init (int flags, char **argv, + mach_port_t *portarray, size_t portarraysize, + int *intarray, size_t intarraysize) +{ + int i; + + _hurd_exec_flags = flags; + + _hurd_ports = malloc (portarraysize * sizeof (*_hurd_ports)); + if (_hurd_ports == NULL) + __libc_fatal ("Can't allocate _hurd_ports\n"); + _hurd_nports = portarraysize; + + /* See what ports we were passed. */ + for (i = 0; i < portarraysize; ++i) + _hurd_port_init (&_hurd_ports[i], portarray[i]); + + /* When the user asks for the bootstrap port, + he will get the one the exec server passed us. */ + __task_set_special_port (__mach_task_self (), TASK_BOOTSTRAP_PORT, + portarray[INIT_PORT_BOOTSTRAP]); + + /* Tell the proc server we exist, if it does. */ + if (portarray[INIT_PORT_PROC] != MACH_PORT_NULL) + _hurd_proc_init (argv); + + if (intarraysize > INIT_UMASK) + _hurd_umask = intarray[INIT_UMASK] & 0777; + else + _hurd_umask = CMASK; + + /* All done with init ints and ports. */ + __vm_deallocate (__mach_task_self (), + (vm_address_t) intarray, + intarraysize * sizeof (int)); + __vm_deallocate (__mach_task_self (), + (vm_address_t) portarray, + portarraysize * sizeof (mach_port_t)); + + if (flags & EXEC_SECURE) + /* XXX if secure exec, elide environment variables + which the library uses and could be security holes. + CORESERVER, COREFILE + */ ; + + /* Call other things which want to do some initialization. These are not + on the __libc_subinit hook because things there like to be able to + assume the availability of the POSIX.1 services we provide. */ + RUN_HOOK (_hurd_subinit, ()); +} + +#include <hurd/signal.h> + +/* The user can do "int _hide_arguments = 1;" to make + sure the arguments are never visible with `ps'. */ +int _hide_arguments, _hide_environment; + +/* Hook for things which should be initialized as soon as the proc + server is available. */ +DEFINE_HOOK (_hurd_proc_subinit, (void)); + +/* Do startup handshaking with the proc server just installed in _hurd_ports. + Call _hurdsig_init to set up signal processing. */ + +void +_hurd_proc_init (char **argv) +{ + mach_port_t oldmsg; + struct hurd_userlink ulink; + process_t procserver; + + /* Initialize the signal code; Mach exceptions will become signals. */ + _hurdsig_init (); + + /* The signal thread is now prepared to receive messages. + It is safe to give the port to the proc server. */ + + procserver = _hurd_port_get (&_hurd_ports[INIT_PORT_PROC], &ulink); + + /* Give the proc server our message port. */ + __proc_setmsgport (procserver, _hurd_msgport, &oldmsg); + if (oldmsg != MACH_PORT_NULL) + /* Deallocate the old msg port we replaced. */ + __mach_port_deallocate (__mach_task_self (), oldmsg); + + /* Tell the proc server where our args and environment are. */ + __proc_set_arg_locations (procserver, + _hide_arguments ? 0 : (vm_address_t) argv, + _hide_environment ? 0 : (vm_address_t) __environ); + + _hurd_port_free (&_hurd_ports[INIT_PORT_PROC], &ulink, procserver); + + /* Initialize proc server-assisted fault recovery for the signal thread. */ + _hurdsig_fault_init (); + + /* Call other things which want to do some initialization. These are not + on the _hurd_subinit hook because things there assume that things done + here, like _hurd_pid, are already initialized. */ + RUN_HOOK (_hurd_proc_subinit, ()); + + if (_hurd_exec_flags & EXEC_TRACED) + /* This process is "traced", meaning it should stop on signals or exec. + We are all set up now to handle signals. Stop ourselves, to inform + our parent (presumably a debugger) that the exec has completed. */ + _hurd_raise_signal (NULL, SIGTRAP, 0, 0); +} + +/* Called when we get a message telling us to change our proc server port. */ + +error_t +_hurd_setproc (process_t procserver) +{ + error_t err; + mach_port_t oldmsg; + + /* Give the proc server our message port. */ + if (err = __proc_setmsgport (procserver, _hurd_msgport, &oldmsg)) + return err; + if (oldmsg != MACH_PORT_NULL) + /* Deallocate the old msg port we replaced. */ + __mach_port_deallocate (__mach_task_self (), oldmsg); + + /* Tell the proc server where our args and environment are. */ + if (err = __proc_set_arg_locations (procserver, + /* We don't know the ARGV location. */ + (vm_address_t) 0, + _hide_environment ? 0 : + (vm_address_t) __environ)) + return err; + + /* Those calls worked, so the port looks good. */ + _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver); + + { + pid_t oldpgrp = _hurd_pgrp; + + /* Call these functions again so they can fetch the + new information from the new proc server. */ + RUN_HOOK (_hurd_proc_subinit, ()); + + if (_hurd_pgrp != oldpgrp) + { + /* Run things that want notification of a pgrp change. */ + DECLARE_HOOK (_hurd_pgrp_changed_hook, (pid_t)); + RUN_HOOK (_hurd_pgrp_changed_hook, (_hurd_pgrp)); + } + } + + return 0; +} diff --git a/hurd/hurdinline.c b/hurd/hurdinline.c new file mode 100644 index 0000000000..12a5be6508 --- /dev/null +++ b/hurd/hurdinline.c @@ -0,0 +1,11 @@ +/* Include this first to avoid defining its inline functions. */ +#include <lock-intern.h> + +#undef _EXTERN_INLINE +#define _EXTERN_INLINE /* Define the real function. */ + +#include "hurd/fd.h" +#include "hurd/signal.h" +#include "hurd/userlink.h" +#include "hurd/threadvar.h" +#include "hurd/port.h" diff --git a/hurd/hurdintr.awk b/hurd/hurdintr.awk new file mode 100644 index 0000000000..d03940985c --- /dev/null +++ b/hurd/hurdintr.awk @@ -0,0 +1,25 @@ +BEGIN { intr=0; wantcall=0; calls=""; } + +$1 == "/*" && $2 == "INTR" && $3 == "*/" { intr=1; } + +NF == 1 && $1 == "routine" { wantcall=1; next; } + +intr != 0 && wantcall == 0 && NF >= 2 && $1 == "routine" \ + { + if (substr($2, length($2)-2, 1) == "(") + calls = calls " " substr($2, 0, length($2)-1); + else calls = calls " " $2; + intr=0; + } + +wantcall != 0 && NF >= 1 \ + { + if (substr($1, length($1)-2, 1) == "(") + calls = calls " " substr($1, 0, length($1)-1); + else calls = calls " " $1; + intr=0; + } + +{ wantcall=0; } + +END { print varname " :=" calls; } diff --git a/hurd/hurdioctl.c b/hurd/hurdioctl.c new file mode 100644 index 0000000000..5a41eb10f7 --- /dev/null +++ b/hurd/hurdioctl.c @@ -0,0 +1,264 @@ +/* ioctl commands which must be done in the C library. +Copyright (C) 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/fd.h> +#include <sys/ioctl.h> +#include <hurd/ioctl.h> + + + +/* Symbol set of ioctl handler lists. If there are user-registered + handlers, one of these lists will contain them. The other lists are + handlers built into the library. */ +symbol_set_define (_hurd_ioctl_handler_lists) + +/* Look up REQUEST in the set of handlers. */ +ioctl_handler_t +_hurd_lookup_ioctl_handler (int request) +{ + void *const *ptr; + const struct ioctl_handler *h; + + for (ptr = symbol_set_first_element (_hurd_ioctl_handler_lists); + !symbol_set_end_p (_hurd_ioctl_handler_lists, ptr); + ++ptr) + for (h = *ptr; h != NULL; h = h->next) + if (request >= h->first_request && request <= h->last_request) + return h->handler; + + return NULL; +} + +#include <fcntl.h> + +/* Find out how many bytes may be read from FD without blocking. */ + +static int +fioctl (int fd, + int request, + int *arg) +{ + error_t err; + + *(volatile int *) arg = *arg; + + switch (request) + { + default: + err = EGRATUITOUS; + break; + + case FIONREAD: + { + mach_msg_type_number_t navail; + err = HURD_DPORT_USE (fd, __io_readable (port, &navail)); + if (!err) + *arg = (int) navail; + } + break; + + case FIONBIO: + err = HURD_DPORT_USE (fd, (*arg ? + __io_set_some_openmodes : + __io_clear_some_openmodes) + (port, O_NONBLOCK)); + break; + + case FIOASYNC: + err = HURD_DPORT_USE (fd, (*arg ? + __io_set_some_openmodes : + __io_clear_some_openmodes) + (port, O_ASYNC)); + break; + + case FIOSETOWN: + err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg)); + break; + + case FIOGETOWN: + err = HURD_DPORT_USE (fd, __io_get_owner (port, arg)); + break; + } + + return err ? __hurd_fail (err) : 0; +} + +_HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD); + + +static int +fioclex (int fd, + int request) +{ + int flag; + + switch (request) + { + default: + return __hurd_fail (EGRATUITOUS); + case FIOCLEX: + flag = FD_CLOEXEC; + break; + case FIONCLEX: + flag = 0; + break; + } + + return __fcntl (fd, F_SETFD, flag); +} +_HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX); + +#include <hurd/term.h> + +static void +rectty_dtable (mach_port_t cttyid) +{ + int i; + + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_dtable_lock); + + for (i = 0; i < _hurd_dtablesize; ++i) + { + struct hurd_fd *const d = _hurd_dtable[i]; + mach_port_t newctty; + + if (d == NULL) + /* Nothing to do for an unused descriptor cell. */ + continue; + + if (cttyid == MACH_PORT_NULL) + /* We now have no controlling tty at all. */ + newctty = MACH_PORT_NULL; + else + HURD_PORT_USE (&d->port, + ({ mach_port_t id; + /* Get the io object's cttyid port. */ + if (! __term_getctty (port, &id)) + { + if (id == cttyid && /* Is it ours? */ + /* Get the ctty io port. */ + __term_open_ctty (port, + _hurd_pid, _hurd_pgrp, + &newctty)) + /* XXX it is our ctty but the call failed? */ + newctty = MACH_PORT_NULL; + __mach_port_deallocate + (__mach_task_self (), (mach_port_t) id); + } + else + newctty = MACH_PORT_NULL; + 0; + })); + + /* Install the new ctty port. */ + _hurd_port_set (&d->ctty, newctty); + } + + __mutex_unlock (&_hurd_dtable_lock); + HURD_CRITICAL_END; +} + + +/* Called when we have received a message saying to use a new ctty ID port. */ + +error_t +_hurd_setcttyid (mach_port_t cttyid) +{ + error_t err; + + if (cttyid != MACH_PORT_NULL) + { + /* Give the new send right a user reference. + This is a good way to check that it is valid. */ + if (err = __mach_port_mod_refs (__mach_task_self (), cttyid, + MACH_PORT_RIGHT_SEND, 1)) + return err; + } + + /* Install the port, consuming the reference we just created. */ + _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); + + /* Reset all the ctty ports in all the descriptors. */ + __USEPORT (CTTYID, (rectty_dtable (cttyid), 0)); + + return 0; +} + + +/* Make FD be the controlling terminal. + This function is called for `ioctl (fd, TCIOSCTTY)'. */ + +static int +tiocsctty (int fd, + int request) /* Always TIOCSCTTY. */ +{ + mach_port_t cttyid; + error_t err; + + /* Get FD's cttyid port, unless it is already ours. */ + err = HURD_DPORT_USE (fd, ctty != MACH_PORT_NULL ? EADDRINUSE : + __term_getctty (port, &cttyid)); + if (err == EADDRINUSE) + /* FD is already the ctty. Nothing to do. */ + return 0; + else if (err) + return __hurd_fail (err); + + /* Make it our own. */ + _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); + + /* Reset all the ctty ports in all the descriptors. */ + __USEPORT (CTTYID, (rectty_dtable (cttyid), 0)); + + return 0; +} +_HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY); + +/* Dissociate from the controlling terminal. */ + +static int +tiocnotty (int fd, + int request) /* Always TIOCNOTTY. */ +{ + mach_port_t fd_cttyid; + error_t err; + + if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid))) + return __hurd_fail (err); + + if (__USEPORT (CTTYID, port != fd_cttyid)) + err = EINVAL; + + __mach_port_deallocate (__mach_task_self (), fd_cttyid); + + if (err) + return __hurd_fail (err); + + /* Clear our cttyid port cell. */ + _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL); + + /* Reset all the ctty ports in all the descriptors. */ + + __USEPORT (CTTYID, (rectty_dtable (MACH_PORT_NULL), 0)); + + return 0; +} +_HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY); diff --git a/hurd/hurdkill.c b/hurd/hurdkill.c new file mode 100644 index 0000000000..364b6ed692 --- /dev/null +++ b/hurd/hurdkill.c @@ -0,0 +1,84 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <sys/types.h> +#include <signal.h> +#include <hurd.h> +#include <hurd/port.h> +#include <hurd/signal.h> +#include <hurd/msg.h> + +/* Send a `sig_post' RPC to process number PID. If PID is zero, + send the message to all processes in the current process's process group. + If PID is < -1, send SIG to all processes in process group - PID. + SIG and REFPORT are passed along in the request message. */ +error_t +_hurd_sig_post (pid_t pid, int sig, mach_port_t arg_refport) +{ + int delivered = 0; /* Set when we deliver any signal. */ + error_t err; + mach_port_t proc; + struct hurd_userlink ulink; + + inline void kill_pid (pid_t pid) /* Kill one PID. */ + { + err = HURD_MSGPORT_RPC (__proc_getmsgport (proc, pid, &msgport), + (refport = arg_refport, 0), 0, + /* If no message port we cannot send signals. */ + msgport == MACH_PORT_NULL ? EPERM : + __msg_sig_post (msgport, sig, refport)); + if (! err) + delivered = 1; + } + + proc = _hurd_port_get (&_hurd_ports[INIT_PORT_PROC], &ulink); + + if (pid <= 0) + { + /* Send SIG to each process in pgrp (- PID). */ + mach_msg_type_number_t npids = 10, i; + pid_t pidsbuf[10], *pids = pidsbuf; + + err = __proc_getpgrppids (proc, - pid, &pids, &npids); + if (!err) + { + for (i = 0; i < npids; ++i) + { + kill_pid (pids[i]); + if (err == ESRCH) + /* The process died already. Ignore it. */ + err = 0; + } + if (pids != pidsbuf) + __vm_deallocate (__mach_task_self (), + (vm_address_t) pids, npids * sizeof (pids[0])); + } + } + else + kill_pid (pid); + + _hurd_port_free (&_hurd_ports[INIT_PORT_PROC], &ulink, proc); + + /* If we delivered no signals, but ERR is clear, this must mean that + every kill_pid call failed with ESRCH, meaning all the processes in + the pgrp died between proc_getpgrppids and kill_pid; in that case we + fail with ESRCH. */ + return delivered ? 0 : err ?: ESRCH; +} +weak_alias (_hurd_sig_post, hurd_sig_post) diff --git a/hurd/hurdlookup.c b/hurd/hurdlookup.c new file mode 100644 index 0000000000..b467404840 --- /dev/null +++ b/hurd/hurdlookup.c @@ -0,0 +1,381 @@ +/* Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <string.h> +#include <limits.h> +#include <fcntl.h> +#include "stdio/_itoa.h" +#include <hurd/term.h> + + +/* Translate the error from dir_lookup into the error the user sees. */ +static inline error_t +lookup_error (error_t error) +{ + switch (error) + { + case EOPNOTSUPP: + case MIG_BAD_ID: + /* These indicate that the server does not understand dir_lookup + at all. If it were a directory, it would, by definition. */ + return ENOTDIR; + default: + return error; + } +} + +error_t +__hurd_file_name_lookup (file_t crdir, file_t cwdir, + const char *file_name, int flags, mode_t mode, + file_t *result) +{ + error_t err; + enum retry_type doretry; + char retryname[1024]; /* XXX string_t LOSES! */ + file_t startdir; + + startdir = file_name[0] == '/' ? crdir : cwdir; + + while (file_name[0] == '/') + file_name++; + + if (err = __dir_lookup (startdir, file_name, flags, mode, + &doretry, retryname, result)) + return lookup_error (err); + + return __hurd_file_name_lookup_retry (crdir, doretry, retryname, flags, mode, + result); +} +weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup) + +error_t +__hurd_file_name_lookup_retry (file_t crdir, + enum retry_type doretry, + char retryname[1024], + int flags, mode_t mode, + file_t *result) +{ + error_t err; + file_t startdir; + file_t newpt; + char *file_name; + int dealloc_dir; + int nloops; + + dealloc_dir = 0; + nloops = 0; + err = 0; + + while (1) + { + if (dealloc_dir) + __mach_port_deallocate (__mach_task_self (), startdir); + if (err) + return lookup_error (err); + + switch (doretry) + { + case FS_RETRY_REAUTH: + { + mach_port_t ref = __mach_reply_port (); + err = __io_reauthenticate (*result, + ref, MACH_MSG_TYPE_MAKE_SEND); + if (! err) + err = __USEPORT + (AUTH, __auth_user_authenticate (port, *result, + ref, + MACH_MSG_TYPE_MAKE_SEND, + &newpt)); + __mach_port_destroy (__mach_task_self (), ref); + } + __mach_port_deallocate (__mach_task_self (), *result); + if (err) + return err; + *result = newpt; + /* Fall through. */ + + case FS_RETRY_NORMAL: +#ifdef SYMLOOP_MAX + if (nloops++ >= SYMLOOP_MAX) + return ELOOP; +#endif + + /* An empty RETRYNAME indicates we have the final port. */ + if (retryname[0] == '\0') + { + /* We got a successful translation. Now apply any open-time + action flags we were passed. */ + if (flags & O_EXLOCK) + ; /* XXX */ + if (!err && (flags & O_SHLOCK)) + ; /* XXX */ + if (!err && (flags & O_TRUNC)) + err = __file_truncate (*result, 0); + + if (err) + __mach_port_deallocate (__mach_task_self (), *result); + return err; + } + + startdir = *result; + dealloc_dir = 1; + file_name = retryname; + break; + + case FS_RETRY_MAGICAL: + switch (retryname[0]) + { + case '/': + startdir = crdir; + dealloc_dir = 0; + if (*result != MACH_PORT_NULL) + __mach_port_deallocate (__mach_task_self (), *result); + file_name = &retryname[1]; + break; + + case 'f': + if (retryname[1] == 'd' && retryname[2] == '/') + { + int fd; + char *end; + int save = errno; + errno = 0; + fd = (int) strtol (retryname, &end, 10); + if (end == NULL || errno || /* Malformed number. */ + /* Check for excess text after the number. A slash + is valid; it ends the component. Anything else + does not name a numeric file descriptor. */ + (*end != '/' && *end != '\0')) + { + errno = save; + return ENOENT; + } + *result = __getdport (fd); + if (*result == MACH_PORT_NULL) + { + /* If the name was a proper number, but the file + descriptor does not exist, we return EBADF instead + of ENOENT. */ + error_t err = errno; + errno = save; + return err; + } + errno = save; + if (*end == '\0') + return 0; + else + { + /* Do a normal retry on the remaining components. */ + startdir = *result; + dealloc_dir = 1; + file_name = end + 1; /* Skip the slash. */ + break; + } + } + else + goto bad_magic; + break; + + case 'm': + if (retryname[1] == 'a' && retryname[2] == 'c' && + retryname[3] == 'h' && retryname[4] == 't' && + retryname[5] == 'y' && retryname[6] == 'p' && + retryname[7] == 'e') + { + error_t err; + struct host_basic_info hostinfo; + mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT; + char *p; + if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO, + (natural_t *) &hostinfo, + &hostinfocnt)) + return err; + if (hostinfocnt != HOST_BASIC_INFO_COUNT) + return EGRATUITOUS; + p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0); + *--p = '/'; + p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0); + if (p < retryname) + abort (); /* XXX write this right if this ever happens */ + if (p > retryname) + strcpy (retryname, p); + startdir = *result; + dealloc_dir = 1; + } + else + goto bad_magic; + break; + + case 't': + if (retryname[1] == 't' && retryname[2] == 'y') + switch (retryname[3]) + { + error_t opentty (file_t *result) + { + error_t err; + file_t unauth; + err = __USEPORT (CTTYID, + __termctty_open_terminal (port, + flags, + &unauth)); + if (! err) + { + mach_port_t ref = __mach_reply_port (); + err = __io_reauthenticate + (unauth, + ref, + MACH_MSG_TYPE_MAKE_SEND); + if (! err) + err = __USEPORT + (AUTH, __auth_user_authenticate + (port, + unauth, + ref, MACH_MSG_TYPE_MAKE_SEND, + result)); + __mach_port_deallocate (__mach_task_self (), + unauth); + __mach_port_destroy (__mach_task_self (), ref); + } + return err; + } + + case '\0': + return opentty (result); + case '/': + if (err = opentty (&startdir)) + return err; + dealloc_dir = 1; + strcpy (retryname, &retryname[4]); + break; + default: + goto bad_magic; + } + else + goto bad_magic; + break; + + default: + bad_magic: + return EGRATUITOUS; + } + break; + + default: + return EGRATUITOUS; + } + + err = __dir_lookup (startdir, file_name, flags, mode, + &doretry, retryname, result); + } +} +weak_alias (__hurd_file_name_lookup_retry, hurd_file_name_lookup_retry) + +error_t +__hurd_file_name_split (file_t crdir, file_t cwdir, + const char *file_name, + file_t *dir, char **name) +{ + const char *lastslash; + error_t err; + + lastslash = strrchr (file_name, '/'); + if (lastslash != NULL) + { + if (lastslash == file_name) + { + /* "/foobar" => crdir + "foobar". */ + *name = (char *) file_name + 1; + if (err = __mach_port_mod_refs (__mach_task_self (), + crdir, MACH_PORT_RIGHT_SEND, +1)) + return err; + *dir = crdir; + return 0; + } + else + { + /* "/dir1/dir2/.../file". */ + char dirname[lastslash - file_name + 1]; + memcpy (dirname, file_name, lastslash - file_name); + dirname[lastslash - file_name] = '\0'; + *name = (char *) lastslash + 1; + return __hurd_file_name_lookup (crdir, cwdir, dirname, 0, 0, dir); + } + } + else + { + /* "foobar" => cwdir + "foobar". */ + *name = (char *) file_name; + if (err = __mach_port_mod_refs (__mach_task_self (), + cwdir, MACH_PORT_RIGHT_SEND, +1)) + return err; + *dir = cwdir; + return 0; + } +} +weak_alias (__hurd_file_name_split, hurd_file_name_split) + + +file_t +__file_name_lookup (const char *file_name, int flags, mode_t mode) +{ + error_t err; + file_t result, crdir, cwdir; + struct hurd_userlink crdir_ulink, cwdir_ulink; + + crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink); + cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink); + + err = __hurd_file_name_lookup (crdir, cwdir, file_name, flags, mode, + &result); + + _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir); + _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir); + + if (err) + return __hurd_fail (err), MACH_PORT_NULL; + else + return result; +} +weak_alias (__file_name_lookup, file_name_lookup) + + +file_t +__file_name_split (const char *file_name, char **name) +{ + error_t err; + file_t dir, crdir, cwdir; + struct hurd_userlink crdir_ulink, cwdir_ulink; + + crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink); + cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink); + + err = __hurd_file_name_split (crdir, cwdir, file_name, &dir, name); + + _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir); + _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir); + + if (err) + { + errno = err; + return MACH_PORT_NULL; + } + else + return dir; +} +weak_alias (__file_name_split, file_name_split) diff --git a/hurd/hurdmalloc.c b/hurd/hurdmalloc.c new file mode 100644 index 0000000000..1de887bb80 --- /dev/null +++ b/hurd/hurdmalloc.c @@ -0,0 +1,411 @@ +#include <stdlib.h> +#include <string.h> + +#define bcopy(s,d,n) memcpy ((d), (s), (n)) /* No overlap handling. */ + +#include "hurdmalloc.h" /* XXX see that file */ + +#include <mach.h> +#define vm_allocate __vm_allocate +#define vm_page_size __vm_page_size + +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * HISTORY + * $Log$ + * Revision 1.10 1995/02/13 22:04:34 roland + * (malloc_init): Add self reference to avoid not only the `defined but not + * used' warning, but also to avoid GCC optimizing out the entire function + * (!). + * + * Revision 1.9 1995/02/13 16:36:08 roland + * Include string.h; #define bcopy using memcpy. + * + * Revision 1.8 1995/02/03 01:54:21 roland + * Remove bogus bcopy decl. + * + * Revision 1.7 1995/01/26 04:22:02 roland + * Don't include gnu-stabs.h. + * + * Revision 1.6 1994/12/07 19:41:26 roland + * (vm_allocate, vm_page_size): #define these to __ names at top. + * + * Revision 1.5 1994/06/04 01:48:44 roland + * entered into RCS + * + * Revision 2.7 91/05/14 17:57:34 mrt + * Correcting copyright + * + * Revision 2.6 91/02/14 14:20:26 mrt + * Added new Mach copyright + * [91/02/13 12:41:21 mrt] + * + * Revision 2.5 90/11/05 14:37:33 rpd + * Added malloc_fork* code. + * [90/11/02 rwd] + * + * Add spin_lock_t. + * [90/10/31 rwd] + * + * Revision 2.4 90/08/07 14:31:28 rpd + * Removed RCS keyword nonsense. + * + * Revision 2.3 90/06/02 15:14:00 rpd + * Converted to new IPC. + * [90/03/20 20:56:57 rpd] + * + * Revision 2.2 89/12/08 19:53:59 rwd + * Removed conditionals. + * [89/10/23 rwd] + * + * Revision 2.1 89/08/03 17:09:46 rwd + * Created. + * + * + * 13-Sep-88 Eric Cooper (ecc) at Carnegie Mellon University + * Changed realloc() to copy min(old size, new size) bytes. + * Bug found by Mike Kupfer at Olivetti. + */ +/* + * File: malloc.c + * Author: Eric Cooper, Carnegie Mellon University + * Date: July, 1988 + * + * Memory allocator for use with multiple threads. + */ + + +#include <cthreads.h> +#include "cthread_internals.h" + + +/* + * Structure of memory block header. + * When free, next points to next block on free list. + * When allocated, fl points to free list. + * Size of header is 4 bytes, so minimum usable block size is 8 bytes. + */ +typedef union header { + union header *next; + struct free_list *fl; +} *header_t; + +#define MIN_SIZE 8 /* minimum block size */ + +typedef struct free_list { + spin_lock_t lock; /* spin lock for mutual exclusion */ + header_t head; /* head of free list for this size */ +#ifdef DEBUG + int in_use; /* # mallocs - # frees */ +#endif DEBUG +} *free_list_t; + +/* + * Free list with index i contains blocks of size 2^(i+3) including header. + * Smallest block size is 8, with 4 bytes available to user. + * Size argument to malloc is a signed integer for sanity checking, + * so largest block size is 2^31. + */ +#define NBUCKETS 29 + +static struct free_list malloc_free_list[NBUCKETS]; + +/* Initialization just sets everything to zero, but might be necessary on a + machine where spin_lock_init does otherwise, and is necessary when + running an executable that was written by something like Emacs's unexec. + It preserves the values of data variables like malloc_free_list, but + does not save the vm_allocate'd space allocated by this malloc. */ + +static void +malloc_init (void) +{ + int i; + for (i = 0; i < NBUCKETS; ++i) + { + spin_lock_init (&malloc_free_list[i].lock); + malloc_free_list[i].head = NULL; +#ifdef DEBUG + malloc_free_list[i].in_use = 0; +#endif + } + + /* This not only suppresses a `defined but not used' warning, + but it is ABSOLUTELY NECESSARY to avoid the hyperclever + compiler from "optimizing out" the entire function! */ + (void) &malloc_init; +} + +static void +more_memory(size, fl) + int size; + register free_list_t fl; +{ + register int amount; + register int n; + vm_address_t where; + register header_t h; + kern_return_t r; + + if (size <= vm_page_size) { + amount = vm_page_size; + n = vm_page_size / size; + /* + * We lose vm_page_size - n*size bytes here. */ + } else { + amount = size; + n = 1; + } + MACH_CALL(vm_allocate(mach_task_self(), &where, (vm_size_t) amount, TRUE), r); + h = (header_t) where; + do { + h->next = fl->head; + fl->head = h; + h = (header_t) ((char *) h + size); + } while (--n != 0); +} + +/* Declaration changed to standard one for GNU. */ +void * +malloc(size) + register size_t size; +{ + register int i, n; + register free_list_t fl; + register header_t h; + + if ((int) size < 0) /* sanity check */ + return 0; + size += sizeof(union header); + /* + * Find smallest power-of-two block size + * big enough to hold requested size plus header. + */ + i = 0; + n = MIN_SIZE; + while (n < size) { + i += 1; + n <<= 1; + } + ASSERT(i < NBUCKETS); + fl = &malloc_free_list[i]; + spin_lock(&fl->lock); + h = fl->head; + if (h == 0) { + /* + * Free list is empty; + * allocate more blocks. + */ + more_memory(n, fl); + h = fl->head; + if (h == 0) { + /* + * Allocation failed. + */ + spin_unlock(&fl->lock); + return 0; + } + } + /* + * Pop block from free list. + */ + fl->head = h->next; +#ifdef DEBUG + fl->in_use += 1; +#endif DEBUG + spin_unlock(&fl->lock); + /* + * Store free list pointer in block header + * so we can figure out where it goes + * at free() time. + */ + h->fl = fl; + /* + * Return pointer past the block header. + */ + return ((char *) h) + sizeof(union header); +} + +/* Declaration changed to standard one for GNU. */ +void +free(base) + void *base; +{ + register header_t h; + register free_list_t fl; + register int i; + + if (base == 0) + return; + /* + * Find free list for block. + */ + h = (header_t) (base - sizeof(union header)); + fl = h->fl; + i = fl - malloc_free_list; + /* + * Sanity checks. + */ + if (i < 0 || i >= NBUCKETS) { + ASSERT(0 <= i && i < NBUCKETS); + return; + } + if (fl != &malloc_free_list[i]) { + ASSERT(fl == &malloc_free_list[i]); + return; + } + /* + * Push block on free list. + */ + spin_lock(&fl->lock); + h->next = fl->head; + fl->head = h; +#ifdef DEBUG + fl->in_use -= 1; +#endif DEBUG + spin_unlock(&fl->lock); + return; +} + +/* Declaration changed to standard one for GNU. */ +void * +realloc(old_base, new_size) + void *old_base; + size_t new_size; +{ + register header_t h; + register free_list_t fl; + register int i; + unsigned int old_size; + char *new_base; + + if (old_base == 0) + return malloc (new_size); + + /* + * Find size of old block. + */ + h = (header_t) (old_base - sizeof(union header)); + fl = h->fl; + i = fl - malloc_free_list; + /* + * Sanity checks. + */ + if (i < 0 || i >= NBUCKETS) { + ASSERT(0 <= i && i < NBUCKETS); + return 0; + } + if (fl != &malloc_free_list[i]) { + ASSERT(fl == &malloc_free_list[i]); + return 0; + } + /* + * Free list with index i contains blocks of size 2^(i+3) including header. + */ + old_size = (1 << (i+3)) - sizeof(union header); + /* + * Allocate new block, copy old bytes, and free old block. + */ + new_base = malloc(new_size); + if (new_base != 0) + bcopy(old_base, new_base, (int) (old_size < new_size ? old_size : new_size)); + free(old_base); + return new_base; +} + +#ifdef DEBUG +void +print_malloc_free_list() +{ + register int i, size; + register free_list_t fl; + register int n; + register header_t h; + int total_used = 0; + int total_free = 0; + + fprintf(stderr, " Size In Use Free Total\n"); + for (i = 0, size = MIN_SIZE, fl = malloc_free_list; + i < NBUCKETS; + i += 1, size <<= 1, fl += 1) { + spin_lock(&fl->lock); + if (fl->in_use != 0 || fl->head != 0) { + total_used += fl->in_use * size; + for (n = 0, h = fl->head; h != 0; h = h->next, n += 1) + ; + total_free += n * size; + fprintf(stderr, "%10d %10d %10d %10d\n", + size, fl->in_use, n, fl->in_use + n); + } + spin_unlock(&fl->lock); + } + fprintf(stderr, " all sizes %10d %10d %10d\n", + total_used, total_free, total_used + total_free); +} +#endif DEBUG + +static void malloc_fork_prepare() +/* + * Prepare the malloc module for a fork by insuring that no thread is in a + * malloc critical section. + */ +{ + register int i; + + for (i = 0; i < NBUCKETS; i++) { + spin_lock(&malloc_free_list[i].lock); + } +} + +static void malloc_fork_parent() +/* + * Called in the parent process after a fork() to resume normal operation. + */ +{ + register int i; + + for (i = NBUCKETS-1; i >= 0; i--) { + spin_unlock(&malloc_free_list[i].lock); + } +} + +static void malloc_fork_child() +/* + * Called in the child process after a fork() to resume normal operation. + */ +{ + register int i; + + for (i = NBUCKETS-1; i >= 0; i--) { + spin_unlock(&malloc_free_list[i].lock); + } +} + + +text_set_element (_hurd_fork_prepare_hook, malloc_fork_prepare); +text_set_element (_hurd_fork_parent_hook, malloc_fork_parent); +text_set_element (_hurd_fork_child_hook, malloc_fork_child); +text_set_element (_hurd_preinit_hook, malloc_init); diff --git a/hurd/hurdmalloc.h b/hurd/hurdmalloc.h new file mode 100644 index 0000000000..91286093c4 --- /dev/null +++ b/hurd/hurdmalloc.h @@ -0,0 +1,17 @@ +/* XXX this file is a tempoary hack. + + All hurd-internal code which uses malloc et al includes this file so it + will use the internal malloc routines _hurd_{malloc,realloc,free} + instead. The "hurd-internal" functions are the cthreads version, + which uses vm_allocate and is thread-safe. The normal user version + of malloc et al is the unixoid one using sbrk. + + */ + +extern void *_hurd_malloc (size_t); +extern void *_hurd_realloc (void *, size_t); +extern void _hurd_free (void *); + +#define malloc _hurd_malloc +#define realloc _hurd_realloc +#define free _hurd_free diff --git a/hurd/hurdmsg.c b/hurd/hurdmsg.c new file mode 100644 index 0000000000..57b6b8dd67 --- /dev/null +++ b/hurd/hurdmsg.c @@ -0,0 +1,451 @@ +/* Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/msg_server.h> +#include <hurd/fd.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> + + +#define AUTHCHECK \ + if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth)) \ + return EPERM + + +/* Snarfing and frobbing the init ports. */ + +kern_return_t +_S_msg_get_init_port (mach_port_t msgport, mach_port_t auth, int which, + mach_port_t *result, mach_msg_type_name_t *result_type) +{ + AUTHCHECK; + *result_type = MACH_MSG_TYPE_MOVE_SEND; + /* This function adds a new user reference for the *RESULT it gives back. + Our reply message uses a move-send right that consumes this reference. */ + return _hurd_ports_get (which, result); +} + +kern_return_t +_S_msg_set_init_port (mach_port_t msgport, mach_port_t auth, + int which, mach_port_t port) +{ + error_t err; + + AUTHCHECK; + + err = _hurd_ports_set (which, port); + if (err == 0) + __mach_port_deallocate (__mach_task_self (), port); + + return 0; +} + +kern_return_t +_S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth, + mach_port_t **ports, + mach_msg_type_name_t *ports_type, + mach_msg_type_number_t *nports) +{ + mach_msg_type_number_t i; + error_t err; + + AUTHCHECK; + + if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports, + _hurd_nports * sizeof (mach_port_t), 1)) + return err; + *nports = _hurd_nports; + + for (i = 0; i < _hurd_nports; ++i) + /* This function adds a new user ref for the *RESULT it gives back. + Our reply message uses move-send rights that consumes this ref. */ + if (err = _hurd_ports_get (i, &(*ports)[i])) + { + /* Died part way through. Deallocate the ports already fetched. */ + while (i-- > 0) + __mach_port_deallocate (__mach_task_self (), (*ports)[i]); + __vm_deallocate (__mach_task_self (), + (vm_address_t) *ports, + *nports * sizeof (mach_port_t)); + return err; + } + + *ports_type = MACH_MSG_TYPE_MOVE_SEND; + return 0; +} + +kern_return_t +_S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth, + mach_port_t *ports, mach_msg_type_number_t nports) +{ + mach_msg_type_number_t i; + error_t err; + + AUTHCHECK; + + for (i = 0; i < _hurd_nports; ++i) + { + if (err = _hurd_ports_set (i, ports[i])) + return err; + else + __mach_port_deallocate (__mach_task_self (), ports[i]); + } + + return 0; +} + +/* Snarfing and frobbing the init ints. */ + +static kern_return_t +get_int (int which, int *value) +{ + switch (which) + { + case INIT_UMASK: + *value = _hurd_umask; + return 0; + case INIT_SIGMASK: + { + struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); + __spin_lock (&ss->lock); + *value = ss->blocked; + __spin_unlock (&ss->lock); + return 0; + } + case INIT_SIGPENDING: + { + struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); + __spin_lock (&ss->lock); + *value = ss->pending; + __spin_unlock (&ss->lock); + return 0; + } + case INIT_SIGIGN: + { + struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); + sigset_t ign; + int sig; + __spin_lock (&ss->lock); + __sigemptyset (&ign); + for (sig = 1; sig < NSIG; ++sig) + if (ss->actions[sig].sa_handler == SIG_IGN) + __sigaddset (&ign, sig); + __spin_unlock (&ss->lock); + *value = ign; + return 0; + } + default: + return EINVAL; + } +} + +kern_return_t +_S_msg_get_init_int (mach_port_t msgport, mach_port_t auth, + int which, int *value) +{ + AUTHCHECK; + + return get_int (which, value); +} + +kern_return_t +_S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth, + int **values, mach_msg_type_number_t *nvalues) +{ + error_t err; + mach_msg_type_number_t i; + + AUTHCHECK; + + if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values, + INIT_INT_MAX * sizeof (int), 1)) + return err; + *nvalues = INIT_INT_MAX; + + for (i = 0; i < INIT_INT_MAX; ++i) + switch (err = get_int (i, &(*values)[i])) + { + case 0: /* Success. */ + break; + case EINVAL: /* Unknown index. */ + (*values)[i] = 0; + break; + default: /* Lossage. */ + __vm_deallocate (__mach_task_self (), + (vm_address_t) *values, INIT_INT_MAX * sizeof (int)); + return err; + } + + return 0; +} + + +static kern_return_t +set_int (int which, int value) +{ + switch (which) + { + case INIT_UMASK: + _hurd_umask = value; + return 0; + + /* These are pretty odd things to do. But you asked for it. */ + case INIT_SIGMASK: + { + struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); + __spin_lock (&ss->lock); + ss->blocked = value; + __spin_unlock (&ss->lock); + return 0; + } + case INIT_SIGPENDING: + { + struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); + __spin_lock (&ss->lock); + ss->pending = value; + __spin_unlock (&ss->lock); + return 0; + } + case INIT_SIGIGN: + { + struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); + int sig; + const sigset_t ign = value; + __spin_lock (&ss->lock); + for (sig = 1; sig < NSIG; ++sig) + { + if (__sigismember (&ign, sig)) + ss->actions[sig].sa_handler = SIG_IGN; + else if (ss->actions[sig].sa_handler == SIG_IGN) + ss->actions[sig].sa_handler = SIG_DFL; + } + __spin_unlock (&ss->lock); + return 0; + } + default: + return EINVAL; + } +} + +kern_return_t +_S_msg_set_init_int (mach_port_t msgport, mach_port_t auth, + int which, int value) +{ + AUTHCHECK; + + return set_int (which, value); +} + +kern_return_t +_S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth, + int *values, mach_msg_type_number_t nvalues) +{ + error_t err; + mach_msg_type_number_t i; + + AUTHCHECK; + + for (i = 0; i < INIT_INT_MAX; ++i) + switch (err = set_int (i, values[i])) + { + case 0: /* Success. */ + break; + case EINVAL: /* Unknown index. */ + break; + default: /* Lossage. */ + return err; + } + + return 0; +} + + +kern_return_t +_S_msg_get_fd (mach_port_t msgport, mach_port_t auth, + int which, mach_port_t *result, mach_msg_type_name_t *result_type) +{ + AUTHCHECK; + + /* This creates a new user reference for the send right. + Our reply message will move that reference to the caller. */ + *result = __getdport (which); + if (*result == MACH_PORT_NULL) + return errno; + *result_type = MACH_MSG_TYPE_MOVE_SEND; + + return 0; +} + +kern_return_t +_S_msg_set_fd (mach_port_t msgport, mach_port_t auth, + int which, mach_port_t port) +{ + AUTHCHECK; + + /* We consume the reference if successful. */ + return HURD_FD_USE (which, (_hurd_port2fd (descriptor, port, 0), 0)); +} + +/* Snarfing and frobbing environment variables. */ + +kern_return_t +_S_msg_get_env_variable (mach_port_t msgport, + char *variable, + char **data, mach_msg_type_number_t *datalen) +{ + const char *value = getenv (variable); + + if (value == NULL) + return ENOENT; + + /* XXX this pointer might become invalid */ + *data = value; + *datalen = strlen (value); + return 0; +} + + +kern_return_t +_S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth, + char *variable, + char *value, + int replace) +{ + AUTHCHECK; + + if (setenv (variable, value, replace)) /* XXX name space */ + return errno; + return 0; +} + +kern_return_t +_S_msg_get_environment (mach_port_t msgport, + char **data, mach_msg_type_number_t *datalen) +{ + /* Pack the environment into an array with nulls separating elements. */ + if (__environ != NULL) + { + char *ap, **p; + size_t envlen = 0; + + for (p = __environ; *p != NULL; ++p) + envlen += strlen (*p) + 1; + + if (envlen > *datalen) + { + if (__vm_allocate (__mach_task_self (), + (vm_address_t *) data, envlen, 1)) + return ENOMEM; + } + + ap = *data; + for (p = __environ; *p != NULL; ++p) + ap = __memccpy (ap, *p, '\0', ULONG_MAX); + + *datalen = envlen; + } + else + *datalen = 0; + + return 0; +} + +kern_return_t +_S_msg_set_environment (mach_port_t msgport, mach_port_t auth, + char *data, mach_msg_type_number_t datalen) +{ + int _hurd_split_args (char *, mach_msg_type_number_t, char **); + int envc; + char **envp; + + AUTHCHECK; + + envc = _hurd_split_args (data, datalen, NULL); + envp = malloc ((envc + 1) * sizeof (char *)); + if (envp == NULL) + return errno; + _hurd_split_args (data, datalen, envp); + __environ = envp; /* XXX cooperate with loadenv et al */ + return 0; +} + +/* Get and frob the exec flags. */ + +kern_return_t +_S_msg_get_exec_flags (mach_port_t process, mach_port_t auth, + int *flags) +{ + AUTHCHECK; + + *flags = _hurd_exec_flags; + return 0; +} + +kern_return_t +_S_msg_set_all_exec_flags (mach_port_t process, mach_port_t auth, + int flags) +{ + AUTHCHECK; + + _hurd_exec_flags = flags; + return 0; +} + +kern_return_t +_S_msg_set_some_exec_flags (mach_port_t process, mach_port_t auth, + int flags) +{ + AUTHCHECK; + + _hurd_exec_flags |= flags; + return 0; +} + +kern_return_t +_S_msg_clear_some_exec_flags (mach_port_t process, mach_port_t auth, + int flags) +{ + AUTHCHECK; + + _hurd_exec_flags &= ~flags; + return 0; +} + + +/* XXX */ + +kern_return_t +_S_msg_get_dtable (mach_port_t process, + mach_port_t refport, + portarray_t *dtable, + mach_msg_type_name_t *dtablePoly, + mach_msg_type_number_t *dtableCnt) +{ return EOPNOTSUPP; } + +kern_return_t +_S_msg_set_dtable (mach_port_t process, + mach_port_t refport, + portarray_t dtable, + mach_msg_type_number_t dtableCnt) +{ return EOPNOTSUPP; } + +kern_return_t +_S_msg_startup_dosync (mach_port_t process) +{ return EOPNOTSUPP; } diff --git a/hurd/hurdpid.c b/hurd/hurdpid.c new file mode 100644 index 0000000000..23594d9a10 --- /dev/null +++ b/hurd/hurdpid.c @@ -0,0 +1,71 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp; +int _hurd_orphaned; + +static void +init_pids (void) +{ + __USEPORT (PROC, + ({ + __proc_getpids (port, &_hurd_pid, &_hurd_ppid, &_hurd_orphaned); + __proc_getpgrp (port, _hurd_pid, &_hurd_pgrp); + })); + + (void) &init_pids; /* Avoid "defined but not used" warning. */ +} + +text_set_element (_hurd_proc_subinit, init_pids); + +#include <hurd/msg_server.h> +#include "set-hooks.h" +#include <cthreads.h> + +DEFINE_HOOK (_hurd_pgrp_changed_hook, (pid_t)); + +/* These let user threads synchronize with an operation which changes ids. */ +unsigned int _hurd_pids_changed_stamp; +struct condition _hurd_pids_changed_sync; + +kern_return_t +_S_msg_proc_newids (mach_port_t me, + task_t task, + pid_t ppid, pid_t pgrp, int orphaned) +{ + if (task != __mach_task_self ()) + return EPERM; + + __mach_port_deallocate (__mach_task_self (), task); + + _hurd_ppid = ppid; + _hurd_pgrp = pgrp; + _hurd_orphaned = orphaned; + + /* Run things that want notification of a pgrp change. */ + RUN_HOOK (_hurd_pgrp_changed_hook, (_hurd_pgrp)); + + /* Notify any waiting user threads that the id change as been completed. */ + ++_hurd_pids_changed_stamp; +#ifdef noteven + __condition_broadcast (&_hurd_pids_changed_sync); +#endif + + return 0; +} diff --git a/hurd/hurdports.c b/hurd/hurdports.c new file mode 100644 index 0000000000..5b7dfd883f --- /dev/null +++ b/hurd/hurdports.c @@ -0,0 +1,52 @@ +/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/port.h> + + +static inline mach_port_t +get (const int idx) +{ + mach_port_t result; + error_t err = _hurd_ports_get (idx, &result); + + if (err) + return __hurd_fail (err), MACH_PORT_NULL; + return result; +} +#define GET(type, what, idx) \ + type get##what (void) { return get (INIT_PORT_##idx); } + +static inline int +set (const int idx, mach_port_t new) +{ + error_t err = _hurd_ports_set (idx, new); + return err ? __hurd_fail (err) : 0; +} +#define SET(type, what, idx) \ + int set##what (type new) { return set (INIT_PORT_##idx, new); } + +#define GETSET(type, what, idx) \ + GET (type, what, idx) SET (type, what, idx) + +GETSET (process_t, proc, PROC) +GETSET (mach_port_t, cttyid, CTTYID) +GETSET (file_t, cwdir, CWDIR) +GETSET (file_t, crdir, CRDIR) +GETSET (auth_t, auth, AUTH) diff --git a/hurd/hurdprio.c b/hurd/hurdprio.c new file mode 100644 index 0000000000..d7beb3c97a --- /dev/null +++ b/hurd/hurdprio.c @@ -0,0 +1,87 @@ +/* Support code for dealing with priorities in the Hurd. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd/resource.h> +#include <hurd.h> + +error_t +_hurd_priority_which_map (enum __priority_which which, int who, + error_t (*function) (pid_t, struct procinfo *)) +{ + mach_msg_type_number_t npids = 64, i; + pid_t pidbuf[npids], *pids; + error_t err; + struct procinfo *pip; + int pibuf[sizeof *pip + 5 * sizeof (pip->threadinfos[0])], *pi = pibuf; + mach_msg_type_number_t pisize = sizeof (pibuf) / sizeof (int); + + switch (which) + { + case PRIO_PROCESS: + npids = 1; + pids[0] = who; + err = 0; + break; + + case PRIO_PGRP: + err = __USEPORT (PROC, __proc_getpgrppids (port, who, &pids, &npids)); + break; + + case PRIO_USER: + err = __USEPORT (PROC, __proc_getallpids (port, &pids, &npids)); + break; + + default: + return EINVAL; + } + + for (i = 0; !err && i < npids; ++i) + { + if (which == PRIO_USER) + { + /* Get procinfo to check the owner. */ + int *oldpi = pi; + mach_msg_type_number_t oldpisize = pisize; + if (err = __USEPORT (PROC, __proc_getprocinfo (port, pids[i], + &pi, &pisize))) + continue; + if (pi != oldpi && oldpi != pibuf) + /* Old buffer from last call was not reused; free it. */ + __vm_deallocate (__mach_task_self (), + (vm_address_t) oldpi, oldpisize * sizeof pi[0]); + + pip = (struct procinfo *) pi; + if (pip->owner != who) + continue; + } + else + pip = NULL; + + err = (*function) (pids[i], pip); + } + + if (pids != pidbuf) + __vm_deallocate (__mach_task_self (), + (vm_address_t) pids, npids * sizeof pids[0]); + if (pi != pibuf) + __vm_deallocate (__mach_task_self (), + (vm_address_t) pi, pisize * sizeof pi[0]); + + return err; +} diff --git a/hurd/hurdrlimit.c b/hurd/hurdrlimit.c new file mode 100644 index 0000000000..2cc33682a5 --- /dev/null +++ b/hurd/hurdrlimit.c @@ -0,0 +1,50 @@ +/* Resource limits. +Copyright (C) 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <cthreads.h> +#include <hurd/resource.h> + +/* This must be given an initializer, or the a.out linking rules will + not include the entire file when this symbol is referenced. */ +struct rlimit _hurd_rlimits[RLIM_NLIMITS] = { { 0, }, }; + +/* This must be initialized data for the same reason as above, but this is + intentionally initialized to a bogus value to emphasize the point that + mutex_init is still required below just in case of unexec. */ +struct mutex _hurd_rlimit_lock = { SPIN_LOCK_INITIALIZER, }; + +static void +init_rlimit (void) +{ + int i; + + __mutex_init (&_hurd_rlimit_lock); + + for (i = 0; i < RLIM_NLIMITS; ++i) + { + if (_hurd_rlimits[i].rlim_max == 0) + _hurd_rlimits[i].rlim_max = RLIM_INFINITY; + if (_hurd_rlimits[i].rlim_cur == 0) + _hurd_rlimits[i].rlim_cur = _hurd_rlimits[i].rlim_max; + } + + (void) &init_rlimit; +} +text_set_element (_hurd_preinit_hook, init_rlimit); diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c new file mode 100644 index 0000000000..2c6f6a17d2 --- /dev/null +++ b/hurd/hurdsig.c @@ -0,0 +1,1080 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <stdlib.h> +#include <stdio.h> +#include <hurd.h> +#include <hurd/signal.h> +#include <cthreads.h> /* For `struct mutex'. */ +#include <string.h> +#include "hurdfault.h" +#include "hurdmalloc.h" /* XXX */ + +const char *_hurdsig_getenv (const char *); + +struct mutex _hurd_siglock; +int _hurd_stopped; + +/* Port that receives signals and other miscellaneous messages. */ +mach_port_t _hurd_msgport; + +/* Thread listening on it. */ +thread_t _hurd_msgport_thread; + +/* Thread which receives task-global signals. */ +thread_t _hurd_sigthread; + +/* Linked-list of per-thread signal state. */ +struct hurd_sigstate *_hurd_sigstates; + +static void +default_sigaction (struct sigaction actions[NSIG]) +{ + int signo; + + __sigemptyset (&actions[0].sa_mask); + actions[0].sa_flags = SA_RESTART; + actions[0].sa_handler = SIG_DFL; + + for (signo = 1; signo < NSIG; ++signo) + actions[signo] = actions[0]; +} + +struct hurd_sigstate * +_hurd_thread_sigstate (thread_t thread) +{ + struct hurd_sigstate *ss; + __mutex_lock (&_hurd_siglock); + for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) + if (ss->thread == thread) + break; + if (ss == NULL) + { + ss = malloc (sizeof (*ss)); + if (ss == NULL) + __libc_fatal ("hurd: Can't allocate thread sigstate\n"); + ss->thread = thread; + __spin_lock_init (&ss->lock); + + /* Initialze default state. */ + __sigemptyset (&ss->blocked); + __sigemptyset (&ss->pending); + memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack)); + ss->suspended = 0; +#ifdef noteven + __condition_init (&ss->arrived); +#endif + ss->intr_port = MACH_PORT_NULL; + ss->context = NULL; + + /* Initialize the sigaction vector from the default signal receiving + thread's state, and its from the system defaults. */ + if (thread == _hurd_sigthread) + default_sigaction (ss->actions); + else + { + struct hurd_sigstate *s; + for (s = _hurd_sigstates; s != NULL; s = s->next) + if (s->thread == _hurd_sigthread) + break; + if (s) + { + __spin_lock (&s->lock); + memcpy (ss->actions, s->actions, sizeof (s->actions)); + __spin_unlock (&s->lock); + } + else + default_sigaction (ss->actions); + } + + ss->next = _hurd_sigstates; + _hurd_sigstates = ss; + } + __mutex_unlock (&_hurd_siglock); + return ss; +} + +/* Signal delivery itself is on this page. */ + +#include <hurd/fd.h> +#include <hurd/core.h> +#include <hurd/paths.h> +#include <setjmp.h> +#include <fcntl.h> +#include <sys/wait.h> +#include "thread_state.h" +#include <hurd/msg_server.h> +#include <hurd/msg_reply.h> /* For __msg_sig_post_reply. */ +#include <assert.h> +#include <hurd/interrupt.h> + +int _hurd_core_limit; /* XXX */ + +/* Call the core server to mummify us before we die. + Returns nonzero if a core file was written. */ +static int +write_corefile (int signo, long int sigcode, int sigerror) +{ + error_t err; + mach_port_t coreserver; + file_t file, coredir; + const char *name; + + /* XXX RLIMIT_CORE: + When we have a protocol to make the server return an error + for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE + value in place of the RLIMIT_FSIZE value. */ + + /* First get a port to the core dumping server. */ + coreserver = MACH_PORT_NULL; + name = _hurdsig_getenv ("CORESERVER"); + if (name != NULL) + coreserver = __file_name_lookup (name, 0, 0); + if (coreserver == MACH_PORT_NULL) + coreserver = __file_name_lookup (_SERVERS_CORE, 0, 0); + if (coreserver == MACH_PORT_NULL) + return 0; + + /* Get a port to the directory where the new core file will reside. */ + name = _hurdsig_getenv ("COREFILE"); + if (name == NULL) + name = "core"; + coredir = __file_name_split (name, (char **) &name); + if (coredir == MACH_PORT_NULL) + return 0; + /* Create the new file, but don't link it into the directory yet. */ + if (err = __dir_mkfile (coredir, O_WRONLY|O_CREAT, + 0600 & ~_hurd_umask, /* XXX ? */ + &file)) + return 0; + + /* Call the core dumping server to write the core file. */ + err = __core_dump_task (coreserver, + __mach_task_self (), + file, _hurdsig_getenv ("GNUTARGET"), + signo, sigcode, sigerror); + __mach_port_deallocate (__mach_task_self (), coreserver); + if (! err) + /* The core dump into FILE succeeded, so now link it into the + directory. */ + err = __dir_link (file, coredir, name); + __mach_port_deallocate (__mach_task_self (), file); + __mach_port_deallocate (__mach_task_self (), coredir); + return !err; +} + + +/* Send a sig_post reply message if it hasn't already been sent. */ +static inline void +post_reply (mach_port_t *reply_port, mach_msg_type_name_t reply_port_type, + int untraced, + error_t result) +{ + if (reply_port == NULL || *reply_port == MACH_PORT_NULL) + return; + (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply) + (*reply_port, reply_port_type, result); + *reply_port = MACH_PORT_NULL; +} + + +/* The lowest-numbered thread state flavor value is 1, + so we use bit 0 in machine_thread_all_state.set to + record whether we have done thread_abort. */ +#define THREAD_ABORTED 1 + +/* SS->thread is suspended. Abort the thread and get its basic state. If + REPLY_PORT is not NULL, send a reply on *REPLY_PORT after aborting the + thread. */ +static void +abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state, + mach_port_t *reply_port, mach_msg_type_name_t reply_port_type, + int untraced) +{ + if (!(state->set & THREAD_ABORTED)) + { + __thread_abort (ss->thread); + /* Clear all thread state flavor set bits, because thread_abort may + have changed the state. */ + state->set = THREAD_ABORTED; + } + + if (reply_port) + post_reply (reply_port, reply_port_type, untraced, 0); + + machine_get_basic_state (ss->thread, state); +} + +/* Find the location of the MiG reply port cell in use by the thread whose + state is described by THREAD_STATE. Make sure that this location can be + set without faulting, or else return NULL. */ + +static mach_port_t * +interrupted_reply_port_location (struct machine_thread_all_state *thread_state) +{ + mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp + (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP); + + if (_hurdsig_catch_fault (SIGSEGV)) + { + assert (_hurdsig_fault_sigcode == (long int) portloc); + /* Faulted trying to read the stack. */ + return NULL; + } + + /* Fault now if this pointer is bogus. */ + *(volatile mach_port_t *) portloc = *portloc; + + _hurdsig_end_catch_fault (); + + return portloc; +} + + +/* SS->thread is suspended. + + Abort any interruptible RPC operation the thread is doing. + + This uses only the constant member SS->thread and the unlocked, atomically + set member SS->intr_port, so no locking is needed. + + If successfully sent an interrupt_operation and therefore the thread should + wait for its pending RPC to return (possibly EINTR) before taking the + incoming signal, returns the reply port to be received on. Otherwise + returns MACH_PORT_NULL. + + *STATE_CHANGE is set nonzero if STATE->basic was modified and should + be applied back to the thread if it might ever run again, else zero. */ + +static mach_port_t +abort_rpcs (struct hurd_sigstate *ss, int signo, + struct machine_thread_all_state *state, int *state_change, + mach_port_t *reply_port, mach_msg_type_name_t reply_port_type, + int untraced) +{ + mach_port_t msging_port; + mach_port_t intr_port; + + *state_change = 0; + + intr_port = ss->intr_port; + if (intr_port == MACH_PORT_NULL) + /* No interruption needs done. */ + return MACH_PORT_NULL; + + /* Abort the thread's kernel context, so any pending message send or + receive completes immediately or aborts. */ + abort_thread (ss, state, reply_port, reply_port_type, untraced); + + if (_hurdsig_rcv_interrupted_p (state, &msging_port)) + { + error_t err; + + /* The RPC request message was sent and the thread was waiting for + the reply message; now the message receive has been aborted, so + the mach_msg_call will return MACH_RCV_INTERRUPTED. We must tell + the server to interrupt the pending operation. The thread must + wait for the reply message before running the signal handler (to + guarantee that the operation has finished being interrupted), so + our nonzero return tells the trampoline code to finish the message + receive operation before running the handler. */ + + err = __interrupt_operation (intr_port); + + if (err) + { + mach_port_t *reply; + + /* The interrupt didn't work. + Destroy the receive right the thread is blocked on. */ + __mach_port_destroy (__mach_task_self (), msging_port); + + /* The system call return value register now contains + MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the + call. Since we have just destroyed the receive right, the + retry will fail with MACH_RCV_INVALID_NAME. Instead, just + change the return value here to EINTR so mach_msg will not + retry and the EINTR error code will propagate up. */ + state->basic.SYSRETURN = EINTR; + *state_change = 1; + + /* If that was the thread's MiG reply port (which I think should + always be the case), clear the reply port cell so it won't be + reused. */ + reply = interrupted_reply_port_location (state); + if (reply != NULL && *reply == msging_port) + *reply = MACH_PORT_NULL; + } + + /* All threads whose RPCs were interrupted by the interrupt_operation + call above will retry their RPCs unless we clear SS->intr_port. + So we clear it for the thread taking a signal when SA_RESTART is + clear, so that its call returns EINTR. */ + if (!(ss->actions[signo].sa_flags & SA_RESTART)) + ss->intr_port = MACH_PORT_NULL; + + return err ? MACH_PORT_NULL : msging_port; + } + + /* One of the following is true: + + 1. The RPC has not yet been sent. The thread will start its operation + after the signal has been handled. + + 2. The RPC has finished, but not yet cleared SS->intr_port. + The thread will clear SS->intr_port after running the handler. + + 3. The RPC request message was being sent was aborted. The mach_msg + system call will return MACH_SEND_INTERRUPTED, and HURD_EINTR_RPC will + notice the interruption (either retrying the RPC or returning EINTR). */ + + return MACH_PORT_NULL; +} + +/* Abort the RPCs being run by all threads but this one; + all other threads should be suspended. If LIVE is nonzero, those + threads may run again, so they should be adjusted as necessary to be + happy when resumed. STATE is clobbered as a scratch area; its initial + contents are ignored, and its contents on return are not useful. */ + +static void +abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live) +{ + /* We can just loop over the sigstates. Any thread doing something + interruptible must have one. We needn't bother locking because all + other threads are stopped. */ + + struct hurd_sigstate *ss; + size_t nthreads; + mach_port_t *reply_ports; + + /* First loop over the sigstates to count them. + We need to know how big a vector we will need for REPLY_PORTS. */ + nthreads = 0; + for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) + ++nthreads; + + reply_ports = alloca (nthreads * sizeof *reply_ports); + + nthreads = 0; + for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) + if (ss->thread == _hurd_msgport_thread) + reply_ports[nthreads++] = MACH_PORT_NULL; + else + { + int state_changed; + state->set = 0; /* Reset scratch area. */ + + /* Abort any operation in progress with interrupt_operation. + Record the reply port the thread is waiting on. + We will wait for all the replies below. */ + reply_ports[nthreads++] = abort_rpcs (ss, signo, state, &state_changed, + NULL, 0, 0); + if (state_changed && live) + /* Aborting the RPC needed to change this thread's state, + and it might ever run again. So write back its state. */ + __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR, + (natural_t *) &state->basic, + MACHINE_THREAD_STATE_COUNT); + } + + /* Wait for replies from all the successfully interrupted RPCs. */ + while (nthreads-- > 0) + if (reply_ports[nthreads] != MACH_PORT_NULL) + { + error_t err; + mach_msg_header_t head; + err = __mach_msg (&head, MACH_RCV_MSG, 0, sizeof head, + reply_ports[nthreads], + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (err != MACH_RCV_TOO_LARGE) + assert_perror (err); + } +} + + +struct hurd_signal_preempt *_hurd_signal_preempt[NSIG]; +struct mutex _hurd_signal_preempt_lock; + +/* Mask of stop signals. */ +#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \ + sigmask (SIGSTOP) | sigmask (SIGTSTP)) + +/* Deliver a signal. SS is not locked. */ +void +_hurd_internal_post_signal (struct hurd_sigstate *ss, + int signo, long int sigcode, int sigerror, + mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, + int untraced) +{ + struct machine_thread_all_state thread_state; + enum { stop, ignore, core, term, handle } act; + sighandler_t handler; + struct hurd_signal_preempt *pe; + sighandler_t (*preempt) (thread_t, int, long int, int) = NULL; + sigset_t pending; + int ss_suspended; + + /* Reply to this sig_post message. */ + inline void reply (void) + { + post_reply (&reply_port, reply_port_type, untraced, 0); + } + + /* Mark the signal as pending. */ + void mark_pending (void) + { + __sigaddset (&ss->pending, signo); + /* Save the code to be given to the handler when SIGNO is + unblocked. */ + ss->pending_data[signo].code = sigcode; + ss->pending_data[signo].error = sigerror; + } + + /* Suspend the process with SIGNO. */ + void suspend (void) + { + /* Stop all other threads and mark ourselves stopped. */ + __USEPORT (PROC, + ({ + /* Hold the siglock while stopping other threads to be + sure it is not held by another thread afterwards. */ + __mutex_lock (&_hurd_siglock); + __proc_dostop (port, _hurd_msgport_thread); + __mutex_unlock (&_hurd_siglock); + abort_all_rpcs (signo, &thread_state, 1); + __proc_mark_stop (port, signo); + })); + _hurd_stopped = 1; + } + + post_signal: + + thread_state.set = 0; /* We know nothing. */ + + /* Check for a preempted signal. Preempted signals + can arrive during critical sections. */ + __mutex_lock (&_hurd_signal_preempt_lock); + for (pe = _hurd_signal_preempt[signo]; pe != NULL; pe = pe->next) + if (sigcode >= pe->first && sigcode <= pe->last) + { + preempt = pe->handler; + break; + } + __mutex_unlock (&_hurd_signal_preempt_lock); + + handler = SIG_DFL; + if (preempt) + /* Let the preempting handler examine the thread. + If it returns SIG_DFL, we run the normal handler; + otherwise we use the handler it returns. */ + handler = (*preempt) (ss->thread, signo, sigcode, sigerror); + + ss_suspended = 0; + + if (handler != SIG_DFL) + /* Run the preemption-provided handler. */ + act = handle; + else + { + /* No preemption. Do normal handling. */ + + __spin_lock (&ss->lock); + + handler = ss->actions[signo].sa_handler; + + if (!untraced && (_hurd_exec_flags & EXEC_TRACED)) + { + /* We are being traced. Stop to tell the debugger of the signal. */ + if (_hurd_stopped) + /* Already stopped. Mark the signal as pending; + when resumed, we will notice it and stop again. */ + mark_pending (); + else + suspend (); + __spin_unlock (&ss->lock); + reply (); + return; + } + + if (handler == SIG_DFL) + /* Figure out the default action for this signal. */ + switch (signo) + { + case 0: + /* A sig_post msg with SIGNO==0 is sent to + tell us to check for pending signals. */ + act = ignore; + break; + + case SIGTTIN: + case SIGTTOU: + case SIGSTOP: + case SIGTSTP: + act = stop; + break; + + case SIGCONT: + case SIGIO: + case SIGURG: + case SIGCHLD: + case SIGWINCH: + act = ignore; + break; + + case SIGQUIT: + case SIGILL: + case SIGTRAP: + case SIGIOT: + case SIGEMT: + case SIGFPE: + case SIGBUS: + case SIGSEGV: + case SIGSYS: + act = core; + break; + + case SIGINFO: + if (_hurd_pgrp == _hurd_pid) + { + /* We are the process group leader. Since there is no + user-specified handler for SIGINFO, we use a default one + which prints something interesting. We use the normal + handler mechanism instead of just doing it here to avoid + the signal thread faulting or blocking in this + potentially hairy operation. */ + act = handle; + handler = _hurd_siginfo_handler; + } + else + act = ignore; + break; + + default: + act = term; + break; + } + else if (handler == SIG_IGN) + act = ignore; + else + act = handle; + + if (__sigmask (signo) & STOPSIGS) + /* Stop signals clear a pending SIGCONT even if they + are handled or ignored (but not if preempted). */ + ss->pending &= ~sigmask (SIGCONT); + else + { + if (signo == SIGCONT) + /* Even if handled or ignored (but not preempted), SIGCONT clears + stop signals and resumes the process. */ + ss->pending &= ~STOPSIGS; + + if (_hurd_stopped && act != stop && (untraced || signo == SIGCONT)) + { + /* Resume the process from being stopped. */ + thread_t *threads; + mach_msg_type_number_t nthreads, i; + error_t err; + /* Tell the proc server we are continuing. */ + __USEPORT (PROC, __proc_mark_cont (port)); + /* Fetch ports to all our threads and resume them. */ + err = __task_threads (__mach_task_self (), &threads, &nthreads); + assert_perror (err); + for (i = 0; i < nthreads; ++i) + { + if (threads[i] != _hurd_msgport_thread && + (act != handle || threads[i] != ss->thread)) + __thread_resume (threads[i]); + __mach_port_deallocate (__mach_task_self (), threads[i]); + } + __vm_deallocate (__mach_task_self (), + (vm_address_t) threads, + nthreads * sizeof *threads); + _hurd_stopped = 0; + /* The thread that will run the handler is already suspended. */ + ss_suspended = 1; + } + } + } + + if (_hurd_orphaned && act == stop && + (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) | + __sigmask (SIGTSTP)))) + { + /* If we would ordinarily stop for a job control signal, but we are + orphaned so noone would ever notice and continue us again, we just + quietly die, alone and in the dark. */ + sigcode = signo; + signo = SIGKILL; + act = term; + } + + /* Handle receipt of a blocked signal, or any signal while stopped. + It matters that we test ACT first here, because we must never pass + SIGNO==0 to __sigismember. */ + if ((act != ignore && __sigismember (&ss->blocked, signo)) || + (signo != SIGKILL && _hurd_stopped)) + { + mark_pending (); + act = ignore; + } + + /* Perform the chosen action for the signal. */ + switch (act) + { + case stop: + if (_hurd_stopped) + /* We are already stopped, but receiving an untraced stop + signal. Instead of resuming and suspending again, just + notify the proc server of the new stop signal. */ + __USEPORT (PROC, __proc_mark_stop (port, signo)); + else + /* Suspend the process. */ + suspend (); + break; + + case ignore: + /* Nobody cares about this signal. */ + break; + + case term: /* Time to die. */ + case core: /* And leave a rotting corpse. */ + nirvana: + /* Have the proc server stop all other threads in our task. */ + __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread)); + /* No more user instructions will be executed. + The signal can now be considered delivered. */ + reply (); + /* Abort all server operations now in progress. */ + abort_all_rpcs (signo, &thread_state, 0); + + { + int status = W_EXITCODE (0, signo); + /* Do a core dump if desired. Only set the wait status bit saying we + in fact dumped core if the operation was actually successful. */ + if (act == core && write_corefile (signo, sigcode, sigerror)) + status |= WCOREFLAG; + /* Tell proc how we died and then stick the saber in the gut. */ + _hurd_exit (status); + /* NOTREACHED */ + } + + case handle: + /* Call a handler for this signal. */ + { + struct sigcontext *scp; + int wait_for_reply, state_changed; + + /* Stop the thread and abort its pending RPC operations. */ + if (! ss_suspended) + __thread_suspend (ss->thread); + + /* Abort the thread's kernel context, so any pending message send + or receive completes immediately or aborts. If an interruptible + RPC is in progress, abort_rpcs will do this. But we must always + do it before fetching the thread's state, because + thread_get_state is never kosher before thread_abort. */ + abort_thread (ss, &thread_state, NULL, 0, 0); + + wait_for_reply = (abort_rpcs (ss, signo, &thread_state, &state_changed, + &reply_port, reply_port_type, untraced) + != MACH_PORT_NULL); + + if (ss->critical_section) + { + /* The thread is in a critical section. Mark the signal as + pending. When it finishes the critical section, it will + check for pending signals. */ + mark_pending (); + assert (! state_changed); + __thread_resume (ss->thread); + break; + } + + /* Call the machine-dependent function to set the thread up + to run the signal handler, and preserve its old context. */ + scp = _hurd_setup_sighandler (ss, handler, + signo, sigcode, + wait_for_reply, &thread_state); + if (scp == NULL) + { + /* We got a fault setting up the stack frame for the handler. + Nothing to do but die; BSD gets SIGILL in this case. */ + sigcode = signo; /* XXX ? */ + signo = SIGILL; + act = core; + goto nirvana; + } + + /* Set the machine-independent parts of the signal context. */ + + scp->sc_error = sigerror; + { + /* Fetch the thread variable for the MiG reply port, + and set it to MACH_PORT_NULL. */ + mach_port_t *loc = interrupted_reply_port_location (&thread_state); + if (loc) + { + scp->sc_reply_port = *loc; + *loc = MACH_PORT_NULL; + } + else + scp->sc_reply_port = MACH_PORT_NULL; + } + + /* Block SIGNO and requested signals while running the handler. */ + scp->sc_mask = ss->blocked; + ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask; + + /* Save the intr_port in use by the interrupted code, + and clear the cell before running the trampoline. */ + scp->sc_intr_port = ss->intr_port; + ss->intr_port = MACH_PORT_NULL; + + /* Start the thread running the handler (or possibly waiting for an + RPC reply before running the handler). */ + __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR, + (natural_t *) &thread_state.basic, + MACHINE_THREAD_STATE_COUNT); + __thread_resume (ss->thread); + thread_state.set = 0; /* Everything we know is now wrong. */ + break; + } + } + + /* The signal has either been ignored or is now being handled. We can + consider it delivered and reply to the killer. The exception is + signal 0, which can be sent by a user thread to make us check for + pending signals. In that case we want to deliver the pending signals + before replying. */ + if (signo != 0) + reply (); + + /* We get here unless the signal was fatal. We still hold SS->lock. + Check for pending signals, and loop to post them. */ +#define PENDING (!_hurd_stopped && (pending = ss->pending & ~ss->blocked)) + if (PENDING) + { + pending: + for (signo = 1; signo < NSIG; ++signo) + if (__sigismember (&pending, signo)) + { + __sigdelset (&ss->pending, signo); + sigcode = ss->pending_data[signo].code; + sigerror = ss->pending_data[signo].error; + __spin_unlock (&ss->lock); + goto post_signal; + } + } + + /* No pending signals left undelivered for this thread. + If we were sent signal 0, we need to check for pending + signals for all threads. */ + if (signo == 0) + { + __spin_unlock (&ss->lock); + __mutex_lock (&_hurd_siglock); + for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) + { + __spin_lock (&ss->lock); + if (PENDING) + goto pending; + __spin_unlock (&ss->lock); + } + __mutex_unlock (&_hurd_siglock); + } + else + { + /* No more signals pending; SS->lock is still locked. + Wake up any sigsuspend call that is blocking SS->thread. */ + if (ss->suspended != MACH_PORT_NULL) + { + /* There is a sigsuspend waiting. Tell it to wake up. */ + error_t err; + mach_msg_header_t msg; + err = __mach_port_insert_right (__mach_task_self (), + ss->suspended, ss->suspended, + MACH_MSG_TYPE_MAKE_SEND); + assert_perror (err); + msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_SEND, 0); + msg.msgh_remote_port = ss->suspended; + msg.msgh_local_port = MACH_PORT_NULL; + /* These values do not matter. */ + msg.msgh_id = 8675309; /* Jenny, Jenny. */ + msg.msgh_seqno = 17; /* Random. */ + ss->suspended = MACH_PORT_NULL; + err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0, + MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + assert_perror (err); + } + __spin_unlock (&ss->lock); + } + + /* All pending signals delivered to all threads. + Now we can send the reply message even for signal 0. */ + reply (); +} + +/* Decide whether REFPORT enables the sender to send us a SIGNO signal. + Returns zero if so, otherwise the error code to return to the sender. */ + +static error_t +signal_allowed (int signo, mach_port_t refport) +{ + if (signo < 0 || signo >= NSIG) + return EINVAL; + + if (refport == __mach_task_self ()) + /* Can send any signal. */ + goto win; + + /* Avoid needing to check for this below. */ + if (refport == MACH_PORT_NULL) + return EPERM; + + switch (signo) + { + case SIGINT: + case SIGQUIT: + case SIGTSTP: + case SIGHUP: + case SIGINFO: + case SIGTTIN: + case SIGTTOU: + /* Job control signals can be sent by the controlling terminal. */ + if (__USEPORT (CTTYID, port == refport)) + goto win; + break; + + case SIGCONT: + { + /* A continue signal can be sent by anyone in the session. */ + mach_port_t sessport; + if (! __USEPORT (PROC, __proc_getsidport (port, &sessport))) + { + __mach_port_deallocate (__mach_task_self (), sessport); + if (refport == sessport) + goto win; + } + } + break; + + case SIGIO: + case SIGURG: + { + /* Any io object a file descriptor refers to might send us + one of these signals using its async ID port for REFPORT. + + This is pretty wide open; it is not unlikely that some random + process can at least open for reading something we have open, + get its async ID port, and send us a spurious SIGIO or SIGURG + signal. But BSD is actually wider open than that!--you can set + the owner of an io object to any process or process group + whatsoever and send them gratuitous signals. + + Someday we could implement some reasonable scheme for + authorizing SIGIO and SIGURG signals properly. */ + + int d; + __mutex_lock (&_hurd_dtable_lock); + for (d = 0; (unsigned int) d < (unsigned int) _hurd_dtablesize; ++d) + { + struct hurd_userlink ulink; + io_t port; + mach_port_t asyncid; + if (_hurd_dtable[d] == NULL) + continue; + port = _hurd_port_get (&_hurd_dtable[d]->port, &ulink); + if (! __io_get_icky_async_id (port, &asyncid)) + { + if (refport == asyncid) + /* Break out of the loop on the next iteration. */ + d = -1; + __mach_port_deallocate (__mach_task_self (), asyncid); + } + _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port); + } + /* If we found a lucky winner, we've set D to -1 in the loop. */ + if (d < 0) + goto win; + } + } + + /* If this signal is legit, we have done `goto win' by now. + When we return the error, mig deallocates REFPORT. */ + return EPERM; + + win: + /* Deallocate the REFPORT send right; we are done with it. */ + __mach_port_deallocate (__mach_task_self (), refport); + + return 0; +} + +/* Implement the sig_post RPC from <hurd/msg.defs>; + sent when someone wants us to get a signal. */ +kern_return_t +_S_msg_sig_post (mach_port_t me, + mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + int signo, + mach_port_t refport) +{ + error_t err; + + if (err = signal_allowed (signo, refport)) + return err; + + /* Post the signal to the designated signal-receiving thread. This will + reply when the signal can be considered delivered. */ + _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread), + signo, 0, 0, reply_port, reply_port_type, + 0); /* Stop if traced. */ + + return MIG_NO_REPLY; /* Already replied. */ +} + +/* Implement the sig_post_untraced RPC from <hurd/msg.defs>; + sent when the debugger wants us to really get a signal + even if we are traced. */ +kern_return_t +_S_msg_sig_post_untraced (mach_port_t me, + mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, + int signo, + mach_port_t refport) +{ + error_t err; + + if (err = signal_allowed (signo, refport)) + return err; + + /* Post the signal to the designated signal-receiving thread. This will + reply when the signal can be considered delivered. */ + _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread), + signo, 0, 0, reply_port, reply_port_type, + 1); /* Untraced flag. */ + + return MIG_NO_REPLY; /* Already replied. */ +} + +extern void __mig_init (void *); + +#include <mach/task_special_ports.h> + +/* Initialize the message port and _hurd_sigthread and start the signal + thread. */ + +void +_hurdsig_init (void) +{ + error_t err; + vm_size_t stacksize; + + __mutex_init (&_hurd_siglock); + + if (err = __mach_port_allocate (__mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, + &_hurd_msgport)) + __libc_fatal ("hurd: Can't create message port receive right\n"); + + /* Make a send right to the signal port. */ + if (err = __mach_port_insert_right (__mach_task_self (), + _hurd_msgport, + _hurd_msgport, + MACH_MSG_TYPE_MAKE_SEND)) + __libc_fatal ("hurd: Can't create send right to message port\n"); + + /* Set the default thread to receive task-global signals + to this one, the main (first) user thread. */ + _hurd_sigthread = __mach_thread_self (); + + /* Start the signal thread listening on the message port. */ + + if (err = __thread_create (__mach_task_self (), &_hurd_msgport_thread)) + __libc_fatal ("hurd: Can't create signal thread\n"); + + stacksize = __vm_page_size * 4; /* Small stack for signal thread. */ + if (err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread, + _hurd_msgport_receive, + (vm_address_t *) &__hurd_sigthread_stack_base, + &stacksize)) + __libc_fatal ("hurd: Can't setup signal thread\n"); + + __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize; + __hurd_sigthread_variables = + malloc (__hurd_threadvar_max * sizeof (unsigned long int)); + if (__hurd_sigthread_variables == NULL) + __libc_fatal ("hurd: Can't allocate thread variables for signal thread\n"); + + /* Reinitialize the MiG support routines so they will use a per-thread + variable for the cached reply port. */ + __mig_init ((void *) __hurd_sigthread_stack_base); + + if (err = __thread_resume (_hurd_msgport_thread)) + __libc_fatal ("hurd: Can't resume signal thread\n"); + +#if 0 /* Don't confuse poor gdb. */ + /* Receive exceptions on the signal port. */ + __task_set_special_port (__mach_task_self (), + TASK_EXCEPTION_PORT, _hurd_msgport); +#endif +} + /* XXXX */ +/* Reauthenticate with the proc server. */ + +static void +reauth_proc (mach_port_t new) +{ + mach_port_t ref, ignore; + + ref = __mach_reply_port (); + if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC], + __proc_reauthenticate (port, ref, + MACH_MSG_TYPE_MAKE_SEND) || + __auth_user_authenticate (new, port, ref, + MACH_MSG_TYPE_MAKE_SEND, + &ignore)) + && ignore != MACH_PORT_NULL) + __mach_port_deallocate (__mach_task_self (), ignore); + __mach_port_destroy (__mach_task_self (), ref); + + (void) &reauth_proc; /* Silence compiler warning. */ +} +text_set_element (_hurd_reauth_hook, reauth_proc); + +/* Like `getenv', but safe for the signal thread to run. + If the environment is trashed, this will just return NULL. */ + +const char * +_hurdsig_getenv (const char *variable) +{ + if (_hurdsig_catch_fault (SIGSEGV)) + /* We bombed in getenv. */ + return NULL; + else + { + const char *value = getenv (variable); + /* Fault now if VALUE is a bogus string. */ + (void) strlen (value); + _hurdsig_end_catch_fault (); + return value; + } +} diff --git a/hurd/hurdsock.c b/hurd/hurdsock.c new file mode 100644 index 0000000000..266fd40d31 --- /dev/null +++ b/hurd/hurdsock.c @@ -0,0 +1,115 @@ +/* _hurd_socket_server - Find the server for a socket domain. + +Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <sys/socket.h> +#include <stdlib.h> +#include <string.h> +#include <hurd/paths.h> +#include <stdio.h> +#include "stdio/_itoa.h" +#include <cthreads.h> /* For `struct mutex'. */ +#include "hurdmalloc.h" /* XXX */ + +static struct mutex lock; + +static file_t *servers; +static int max_domain; + +/* Return a port to the socket server for DOMAIN. + Socket servers translate nodes in the directory _SERVERS_SOCKET + (canonically /servers/socket). These naming point nodes are named + by the simplest decimal representation of the socket domain number, + for example "/servers/socket/3". + + Socket servers are assumed not to change very often. + The library keeps all the server socket ports it has ever looked up, + and does not look them up in /servers/socket more than once. */ + +socket_t +_hurd_socket_server (int domain, int dead) +{ + socket_t server; + + HURD_CRITICAL_BEGIN; + __mutex_lock (&lock); + + if (domain > max_domain) + { + error_t save = errno; + file_t *new = realloc (servers, (domain + 1) * sizeof (file_t)); + if (new != NULL) + { + while (max_domain <= domain) + new[max_domain++] = MACH_PORT_NULL; + servers = new; + } + else + /* No space to cache the port; we will just fetch it anew below. */ + errno = save; + } + + if (dead && domain <= max_domain) + { + /* The user says the port we returned earlier (now in SERVERS[DOMAIN]) + was dead. Clear the cache and fetch a new one below. */ + __mach_port_deallocate (__mach_task_self (), servers[domain]); + servers[domain] = MACH_PORT_NULL; + } + + if (domain > max_domain || servers[domain] == MACH_PORT_NULL) + { + char name[sizeof (_SERVERS_SOCKET) + 100]; + char *np = &name[sizeof (name)]; + *--np = '\0'; + np = _itoa (domain, np, 10, 0); + *--np = '/'; + np -= sizeof (_SERVERS_SOCKET) - 1; + memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1); + server = __file_name_lookup (np, 0, 0); + if (domain <= max_domain) + servers[domain] = server; + } + else + server = servers[domain]; + + if (server == MACH_PORT_NULL && errno == ENOENT) + /* If the server node is absent, we don't support that protocol. */ + errno = EPFNOSUPPORT; + + __mutex_unlock (&lock); + HURD_CRITICAL_END; + + return server; +} + +static void +init (void) +{ + size_t i; + + __mutex_init (&lock); + + for (i = 0; i < max_domain; ++i) + servers[i] = MACH_PORT_NULL; + + (void) &init; /* Avoid "defined but not used" warning. */ +} +text_set_element (_hurd_preinit_hook, init); diff --git a/hurd/intern-fd.c b/hurd/intern-fd.c new file mode 100644 index 0000000000..fe7424b9bc --- /dev/null +++ b/hurd/intern-fd.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/fd.h> + +/* Allocate a new file descriptor and install PORT in it. FLAGS are as for + `open'; only O_IGNORE_CTTY is meaningful. + + If the descriptor table is full, set errno, and return -1. + If DEALLOC is nonzero, deallocate PORT first. */ +int +_hurd_intern_fd (io_t port, int flags, int dealloc) +{ + int fd; + struct hurd_fd *d; + + HURD_CRITICAL_BEGIN; + d = _hurd_alloc_fd (&fd, 0); + if (d != NULL) + { + _hurd_port2fd (d, port, flags); + __spin_unlock (&d->port.lock); + } + HURD_CRITICAL_END; + + if (d == NULL) + { + if (dealloc) + __mach_port_deallocate (__mach_task_self (), port); + return -1; + } + + return fd; +} diff --git a/hurd/intr-rpc.awk b/hurd/intr-rpc.awk new file mode 100644 index 0000000000..9dbcd6f8e2 --- /dev/null +++ b/hurd/intr-rpc.awk @@ -0,0 +1,45 @@ +# Icky intimate knowledge of MiG output. + +BEGIN \ + { + nprotolines=0; proto=0; + args=""; echo=1; isintr=0; + intrcall = "__hurd_intr_rpc_" call; + print "#include <hurd/signal.h>"; + } + +$NF == intrcall { isintr=1; } + +NF == 1 && $1 == ")" { proto=0; } +proto \ + { + protolines[nprotolines++] = $0; + arg = $NF; + if (substr(arg, 1, 1) == "*") + arg = substr(arg, 2, length(arg)-1); + args = args arg; + } +NF == 1 && $1 == "(" { proto=1; } + +NF == 3 && $1 == "InP->Head.msgh_request_port" \ + { portarg = substr($3, 1, length($3)-1); } + +{ print $0; } + +END \ + { + if (isintr) + { + print "\n\n/* User-callable interrupt-handling stub. */"; + print "kern_return_t __" call; + print "("; + for (i = 0; i < nprotolines; ++i) + print protolines[i]; + print ")"; + print "{"; + print " return HURD_EINTR_RPC (" portarg ", " \ + intrcall "(" args "));"; + print "}"; + } + print "weak_alias (__" call ", " call ")" + } diff --git a/hurd/intr-rpc.defs b/hurd/intr-rpc.defs new file mode 100644 index 0000000000..a2e7b060c9 --- /dev/null +++ b/hurd/intr-rpc.defs @@ -0,0 +1,27 @@ +/* Special MiG definitions for interruptible RPC stubs. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Set the MiG options for an interruptible RPC interface. + We rename each MiG-generated function to hurd_intr_rpc_CALL and + give it the option to return on an interrupted message send. */ + +#define INTR_INTERFACE \ +msgoption MACH_SEND_INTERRUPT;\ +userprefix hurd_intr_rpc_; + diff --git a/hurd/invoke-trans.c b/hurd/invoke-trans.c new file mode 100644 index 0000000000..e11bff5dc3 --- /dev/null +++ b/hurd/invoke-trans.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/fs.h> + +error_t +__hurd_invoke_translator (file_t file, int flags, file_t *newport) +{ + error_t err; + enum retry_type doretry; + char retryname[1024]; /* XXX string_t LOSES! */ + + err = __file_invoke_translator (file, flags, &doretry, retryname, newport); + + if (! err) + err = __USEPORT (CRDIR, __hurd_file_name_lookup_retry (port, + doretry, retryname, + flags, 0, newport)); + + return err; +} diff --git a/hurd/msgportdemux.c b/hurd/msgportdemux.c new file mode 100644 index 0000000000..ae783ef270 --- /dev/null +++ b/hurd/msgportdemux.c @@ -0,0 +1,66 @@ +/* Demux messages sent on the signal port. + +Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/signal.h> +#include <stddef.h> + +struct demux + { + struct demux *next; + boolean_t (*demux) (mach_msg_header_t *inp, + mach_msg_header_t *outp); + }; + +struct demux *_hurd_msgport_demuxers = NULL; + +extern boolean_t __msg_server (mach_msg_header_t *inp, + mach_msg_header_t *outp); + +static boolean_t +msgport_server (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + extern boolean_t _S_msg_server (mach_msg_header_t *inp, + mach_msg_header_t *outp); + extern boolean_t _S_exc_server (mach_msg_header_t *inp, + mach_msg_header_t *outp); + struct demux *d; + + for (d = _hurd_msgport_demuxers; d != NULL; d = d->next) + if ((*d->demux) (inp, outp)) + return 1; + + return (_S_exc_server (inp, outp) || + _S_msg_server (inp, outp)); +} + +/* This is the code that the signal thread runs. */ +void +_hurd_msgport_receive (void) +{ + /* Get our own sigstate cached so we never again have to take a lock to + fetch it. There is much code in hurdsig.c that operates with some + sigstate lock held, which will deadlock with _hurd_thread_sigstate. */ + (void) _hurd_self_sigstate (); + + while (1) + (void) __mach_msg_server (msgport_server, __vm_page_size, _hurd_msgport); +} diff --git a/hurd/msgstub.c b/hurd/msgstub.c new file mode 100644 index 0000000000..d4b59ed635 --- /dev/null +++ b/hurd/msgstub.c @@ -0,0 +1,26 @@ +#include <hurd.h> + +/* XXX */ +#define STUB(fn) error_t fn (mach_port_t port) { return EOPNOTSUPP; } + +STUB(_S_get_init_ports) +STUB(_S_set_init_ports) +STUB(_S_get_init_port) +STUB(_S_set_init_port) +STUB(_S_get_init_ints) +STUB(_S_set_init_ints) +STUB(_S_get_init_int) +STUB(_S_set_init_int) +STUB(_S_get_dtable) +STUB(_S_set_dtable) +STUB(_S_get_fd) +STUB(_S_set_fd) +STUB(_S_get_environment) +STUB(_S_set_environment) +STUB(_S_get_env_variable) +STUB(_S_set_env_variable) +STUB(_S_io_select_done) +STUB(_S_startup_dosync) + +STUB(_S_dir_changed) +STUB(_S_file_changed) diff --git a/hurd/new-fd.c b/hurd/new-fd.c new file mode 100644 index 0000000000..de9a3933f4 --- /dev/null +++ b/hurd/new-fd.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd/fd.h> +#include <stdlib.h> +#include "hurdmalloc.h" /* XXX */ + +/* Allocate a new file descriptor structure + and initialize it with PORT and CTTY. */ + +struct hurd_fd * +_hurd_new_fd (io_t port, io_t ctty) +{ + struct hurd_fd *d = malloc (sizeof (struct hurd_fd)); + + if (d != NULL) + { + /* Initialize the port cells. */ + _hurd_port_init (&d->port, port); + _hurd_port_init (&d->ctty, ctty); + } + + return d; +} diff --git a/hurd/openport.c b/hurd/openport.c new file mode 100644 index 0000000000..244368acaa --- /dev/null +++ b/hurd/openport.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/fd.h> + +/* User entry point for interning a port as a new FD. + Just like _hurd_intern_fd, but don't dealloc PORT on error. */ + +int +openport (io_t port, int flags) +{ + return _hurd_intern_fd (port, flags, 0); +} diff --git a/hurd/pid2task.c b/hurd/pid2task.c new file mode 100644 index 0000000000..6b8182bd02 --- /dev/null +++ b/hurd/pid2task.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +task_t +__pid2task (pid_t pid) +{ + error_t err; + task_t task; + + err = __USEPORT (PROC, __proc_pid2task (port, pid, &task)); + + return err ? (__hurd_fail (err), MACH_PORT_NULL) : task; +} + +weak_alias (__pid2task, pid2task) diff --git a/hurd/port2fd.c b/hurd/port2fd.c new file mode 100644 index 0000000000..cad89e770f --- /dev/null +++ b/hurd/port2fd.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/fd.h> +#include <hurd/signal.h> +#include <hurd/term.h> +#include <fcntl.h> + +/* Store PORT in file descriptor D, doing appropriate ctty magic. + FLAGS are as for `open'; only O_IGNORE_CTTY is meaningful. + D should be locked, and will not be unlocked. */ + +void +_hurd_port2fd (struct hurd_fd *d, io_t port, int flags) +{ + io_t ctty; + mach_port_t cttyid; + int is_ctty = !(flags & O_IGNORE_CTTY) && ! __term_getctty (port, &cttyid); + + if (is_ctty) + { + /* This port is capable of being a controlling tty. + Is it ours? */ + struct hurd_port *const id = &_hurd_ports[INIT_PORT_CTTYID]; + __spin_lock (&id->lock); + if (id->port == MACH_PORT_NULL) + /* We have no controlling tty, so make this one it. */ + _hurd_port_locked_set (id, cttyid); + else + { + if (cttyid != id->port) + /* We have a controlling tty and this is not it. */ + is_ctty = 0; + /* Either we don't want CTTYID, or ID->port already is it. + So we don't need to change ID->port, and we can release + the reference to CTTYID. */ + __spin_unlock (&id->lock); + __mach_port_deallocate (__mach_task_self (), cttyid); + } + } + + if (!is_ctty || __term_open_ctty (port, _hurd_pid, _hurd_pgrp, &ctty) != 0) + /* XXX if IS_CTTY, then this port is our ctty, but we are + not doing ctty style i/o because term_become_ctty barfed. + What to do? */ + /* No ctty magic happening here. */ + ctty = MACH_PORT_NULL; + + /* Install PORT in the descriptor cell, leaving it locked. */ + { + mach_port_t old + = _hurd_userlink_clear (&d->port.users) ? d->port.port : MACH_PORT_NULL; + d->port.port = port; + if (old != MACH_PORT_NULL) + __mach_port_deallocate (__mach_task_self (), old); + } + + _hurd_port_set (&d->ctty, ctty); +} diff --git a/hurd/ports-get.c b/hurd/ports-get.c new file mode 100644 index 0000000000..def59731c5 --- /dev/null +++ b/hurd/ports-get.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +static error_t +getbootstrap (mach_port_t *result) +{ + return __task_get_special_port (__mach_task_self (), + TASK_BOOTSTRAP_PORT, + result); +} + +error_t (*_hurd_ports_getters[INIT_PORT_MAX]) (mach_port_t *result) = + { + [INIT_PORT_BOOTSTRAP] = getbootstrap, + }; + +error_t +_hurd_ports_get (int which, mach_port_t *result) +{ + if (which < 0 || which >= _hurd_nports) + return EINVAL; + if (which >= INIT_PORT_MAX || _hurd_ports_getters[which] == NULL) + return HURD_PORT_USE (&_hurd_ports[which], + __mach_port_mod_refs (__mach_task_self (), + (*result = port), + MACH_PORT_RIGHT_SEND, + +1)); + return (*_hurd_ports_getters[which]) (result); +} diff --git a/hurd/ports-set.c b/hurd/ports-set.c new file mode 100644 index 0000000000..fbc2940217 --- /dev/null +++ b/hurd/ports-set.c @@ -0,0 +1,57 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +static error_t +setbootstrap (mach_port_t newport) +{ + return __task_set_special_port (__mach_task_self (), + TASK_BOOTSTRAP_PORT, + newport); +} + +extern error_t _hurd_setauth (auth_t); +extern error_t _hurd_setproc (process_t); +extern error_t _hurd_setcttyid (mach_port_t); + +error_t (*_hurd_ports_setters[INIT_PORT_MAX]) (mach_port_t newport) = + { + [INIT_PORT_BOOTSTRAP] = setbootstrap, + [INIT_PORT_AUTH] = _hurd_setauth, + [INIT_PORT_PROC] = _hurd_setproc, + [INIT_PORT_CTTYID] = _hurd_setcttyid, + }; + + +error_t +_hurd_ports_set (int which, mach_port_t newport) +{ + error_t err; + if (which < 0 || which >= _hurd_nports) + return EINVAL; + if (err = __mach_port_mod_refs (__mach_task_self (), newport, + MACH_PORT_RIGHT_SEND, 1)) + return err; + if (which >= INIT_PORT_MAX || _hurd_ports_setters[which] == NULL) + { + _hurd_port_set (&_hurd_ports[which], newport); + return 0; + } + return (*_hurd_ports_setters[which]) (newport); +} diff --git a/hurd/preempt-sig.c b/hurd/preempt-sig.c new file mode 100644 index 0000000000..86761967cc --- /dev/null +++ b/hurd/preempt-sig.c @@ -0,0 +1,68 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd/signal.h> + +/* Initialize PREEMPTER with the information given and stick it in the + chain of preempters for SIGNO. */ + +int +hurd_preempt_signals (struct hurd_signal_preempt *preempter, + int signo, int first_code, int last_code, + sighandler_t (*handler) (thread_t, int, long int, int)) +{ + if (signo <= 0 || signo >= NSIG) + { + errno = EINVAL; + return -1; + } + preempter->first = first_code; + preempter->last = last_code; + preempter->handler = handler; + __mutex_lock (&_hurd_signal_preempt_lock); + preempter->next = _hurd_signal_preempt[signo]; + _hurd_signal_preempt[signo] = preempter; + __mutex_unlock (&_hurd_signal_preempt_lock); + return 0; +} + +/* Remove PREEMPTER from the chain for SIGNO. */ + +int +hurd_unpreempt_signals (struct hurd_signal_preempt *preempter, int signo) +{ + struct hurd_signal_preempt *p, *lastp; + if (signo <= 0 || signo >= NSIG) + { + errno = EINVAL; + return -1; + } + __mutex_lock (&_hurd_signal_preempt_lock); + for (p = _hurd_signal_preempt[signo], lastp = NULL; + p != NULL; lastp = p, p = p->next) + if (p == preempter) + { + (lastp == NULL ? _hurd_signal_preempt[signo] : lastp->next) = p->next; + __mutex_unlock (&_hurd_signal_preempt_lock); + return 0; + } + _hurd_signal_preempt[signo] = preempter; + __mutex_unlock (&_hurd_signal_preempt_lock); + errno = ENOENT; + return -1; +} diff --git a/hurd/privports.c b/hurd/privports.c new file mode 100644 index 0000000000..f760e37e6e --- /dev/null +++ b/hurd/privports.c @@ -0,0 +1,60 @@ +/* Copyright (C) 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +/* The program might set these if it is the initial task + bootstrapped by the microkernel. */ + +mach_port_t _hurd_host_priv, _hurd_device_master; + + +kern_return_t +get_privileged_ports (host_priv_t *host_priv_ptr, device_t *device_master_ptr) +{ + if (! _hurd_host_priv) + { + error_t err; + + if (_hurd_ports) + /* We have gotten some initial ports, so perhaps + we have a proc server to talk to. */ + err = __USEPORT (PROC, __proc_getprivports (port, + &_hurd_host_priv, + &_hurd_device_master)); + else + return MACH_SEND_INVALID_DEST; + + if (err) + return err; + } + + if (host_priv_ptr) + { + mach_port_mod_refs (mach_task_self (), + _hurd_host_priv, MACH_PORT_RIGHT_SEND, 1); + *host_priv_ptr = _hurd_host_priv; + } + if (device_master_ptr) + { + mach_port_mod_refs (mach_task_self (), + _hurd_device_master, MACH_PORT_RIGHT_SEND, 1); + *device_master_ptr = _hurd_device_master; + } + return KERN_SUCCESS; +} diff --git a/hurd/setauth.c b/hurd/setauth.c new file mode 100644 index 0000000000..7378e4f070 --- /dev/null +++ b/hurd/setauth.c @@ -0,0 +1,124 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/port.h> +#include <hurd/id.h> +#include "set-hooks.h" + +/* Things in the library which want to be run when the auth port changes. */ +DEFINE_HOOK (_hurd_reauth_hook, (auth_t new_auth)); + +#include <cthreads.h> +static struct mutex reauth_lock = MUTEX_INITIALIZER; + + +/* Set the auth port to NEW, and reauthenticate + everything used by the library. */ +error_t +_hurd_setauth (auth_t new) +{ + error_t err; + int d; + mach_port_t newport, ref; + + /* Give the new send right a user reference. + This is a good way to check that it is valid. */ + if (err = __mach_port_mod_refs (__mach_task_self (), new, + MACH_PORT_RIGHT_SEND, 1)) + return err; + + HURD_CRITICAL_BEGIN; + + /* We lock against another thread doing setauth. Anyone who sets + _hurd_ports[INIT_PORT_AUTH] some other way is asking to lose. */ + __mutex_lock (&reauth_lock); + + /* Install the new port in the cell. */ + __mutex_lock (&_hurd_id.lock); + _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], new); + _hurd_id.valid = 0; + if (_hurd_id.rid_auth) + { + __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth); + _hurd_id.rid_auth = MACH_PORT_NULL; + } + __mutex_unlock (&_hurd_id.lock); + + if (_hurd_init_dtable != NULL) + /* We just have the simple table we got at startup. + Otherwise, a reauth_hook in dtable.c takes care of this. */ + for (d = 0; d < _hurd_init_dtablesize; ++d) + if (_hurd_init_dtable[d] != MACH_PORT_NULL) + { + mach_port_t new; + ref = __mach_reply_port (); + if (! __io_reauthenticate (_hurd_init_dtable[d], + ref, MACH_MSG_TYPE_MAKE_SEND) && + ! HURD_PORT_USE (&_hurd_ports[INIT_PORT_AUTH], + __auth_user_authenticate + (port, + _hurd_init_dtable[d], + ref, MACH_MSG_TYPE_MAKE_SEND, + &new))) + { + __mach_port_deallocate (__mach_task_self (), + _hurd_init_dtable[d]); + _hurd_init_dtable[d] = new; + } + __mach_port_destroy (__mach_task_self (), ref); + } + + ref = __mach_reply_port (); + if (__USEPORT (CRDIR, + ! __io_reauthenticate (port, + ref, MACH_MSG_TYPE_MAKE_SEND) && + ! __auth_user_authenticate (new, port, + ref, MACH_MSG_TYPE_MAKE_SEND, + &newport))) + _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], newport); + __mach_port_destroy (__mach_task_self (), ref); + + ref = __mach_reply_port (); + if (__USEPORT (CWDIR, + ! __io_reauthenticate (port, + ref, MACH_MSG_TYPE_MAKE_SEND) && + ! __auth_user_authenticate (new, port, + ref, MACH_MSG_TYPE_MAKE_SEND, + &newport))) + _hurd_port_set (&_hurd_ports[INIT_PORT_CWDIR], newport); + __mach_port_destroy (__mach_task_self (), ref); + + /* Run things which want to do reauthorization stuff. */ + RUN_HOOK (_hurd_reauth_hook, (new)); + + __mutex_unlock (&reauth_lock); + + HURD_CRITICAL_END; + + return 0; +} + +int +__setauth (auth_t new) +{ + error_t err = _hurd_setauth (new); + return err ? __hurd_fail (err) : 0; +} + +weak_alias (__setauth, setauth) diff --git a/hurd/setuids.c b/hurd/setuids.c new file mode 100644 index 0000000000..3b049b0100 --- /dev/null +++ b/hurd/setuids.c @@ -0,0 +1,59 @@ +/* Copyright (C) 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> +#include <hurd/id.h> + +/* Set the uid set for the current user to UIDS (N of them). */ +int +setuids (int n, const uid_t *uids) +{ + error_t err; + auth_t newauth; + size_t i; + gid_t new[n]; + + /* Fault before taking locks. */ + for (i = 0; i < n; ++i) + new[i] = uids[i]; + + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_id.lock); + err = _hurd_check_ids (); + if (! err) + { + /* Get a new auth port using those IDs. */ + err = __USEPORT (AUTH, + __auth_makeauth (port, NULL, 0, 0, + new, n, + _hurd_id.aux.uids, _hurd_id.aux.nuids, + _hurd_id.gen.gids, _hurd_id.gen.ngids, + _hurd_id.aux.gids, _hurd_id.aux.ngids, + &newauth)); + } + __mutex_unlock (&_hurd_id.lock); + HURD_CRITICAL_END; + + if (err) + return __hurd_fail (err); + + /* Install the new auth port and reauthenticate everything. */ + err = __setauth (newauth); + __mach_port_deallocate (__mach_task_self (), newauth); + return err; +} diff --git a/hurd/siginfo.c b/hurd/siginfo.c new file mode 100644 index 0000000000..eb61fec973 --- /dev/null +++ b/hurd/siginfo.c @@ -0,0 +1,27 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd/signal.h> +#include <stdio.h> + +void +_hurd_siginfo_handler (int signo) +{ + /* XXX */ + puts ("got a SIGINFO"); +} diff --git a/hurd/task2pid.c b/hurd/task2pid.c new file mode 100644 index 0000000000..707753c104 --- /dev/null +++ b/hurd/task2pid.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <hurd.h> + +pid_t +__task2pid (task_t task) +{ + error_t err; + pid_t pid; + err = __USEPORT (PROC, __proc_task2pid (port, task, &pid)); + return err ? (pid_t) __hurd_fail (err) : pid; +} + +weak_alias (__task2pid, task2pid) diff --git a/hurd/vpprintf.c b/hurd/vpprintf.c new file mode 100644 index 0000000000..dcdcd5a13d --- /dev/null +++ b/hurd/vpprintf.c @@ -0,0 +1,60 @@ +/* Copyright (C) 1991, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <hurd.h> + +static ssize_t +DEFUN(pwrite, (cookie, buf, n), + PTR cookie AND CONST char *buf AND size_t n) +{ + error_t error = __io_write ((io_t) cookie, buf, n, -1, + (mach_msg_type_number_t *) &n); + if (error) + return __hurd_fail (error); + return n; +} + + +/* Write formatted output to PORT, a Mach port supporting the i/o protocol, + according to the format string FORMAT, using the argument list in ARG. */ +int +DEFUN(vpprintf, (port, format, arg), + io_t port AND CONST char *format AND va_list arg) +{ + int done; + FILE f; + + /* Create an unbuffered stream talking to PORT on the stack. */ + memset((PTR) &f, 0, sizeof(f)); + f.__magic = _IOMAGIC; + f.__mode.__write = 1; + f.__cookie = (PTR) port; + f.__room_funcs = __default_room_functions; + f.__io_funcs.__write = pwrite; + f.__seen = 1; + f.__userbuf = 1; + + /* vfprintf will use a buffer on the stack for the life of the call. */ + done = vfprintf(&f, format, arg); + + return done; +} |