/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. This file is part of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <hurd.h> #include <hurd/term.h> #include <hurd/fd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <limits.h> #include <cthreads.h> /* For `struct mutex'. */ #include "set-hooks.h" #include "hurdmalloc.h" /* XXX */ struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */ struct hurd_fd **_hurd_dtable; int _hurd_dtablesize; DEFINE_HOOK (_hurd_fd_subinit, (void)); /* Initialize the file descriptor table at startup. */ static void init_dtable (void) { int i; __mutex_init (&_hurd_dtable_lock); /* The initial size of the descriptor table is that of the passed-in table. It will be expanded as necessary up to _hurd_dtable_rlimit. */ _hurd_dtablesize = _hurd_init_dtablesize; /* Allocate the vector of pointers. */ _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable)); if (_hurd_dtablesize != 0 && _hurd_dtable == NULL) __libc_fatal ("hurd: Can't allocate file descriptor table\n"); /* Initialize the descriptor table. */ for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i) { if (_hurd_init_dtable[i] == MACH_PORT_NULL) /* An unused descriptor is marked by a null pointer. */ _hurd_dtable[i] = NULL; else { /* Allocate a new file descriptor structure. */ struct hurd_fd *new = malloc (sizeof (struct hurd_fd)); if (new == NULL) __libc_fatal ("hurd: Can't allocate initial file descriptors\n"); /* Initialize the port cells. */ _hurd_port_init (&new->port, MACH_PORT_NULL); _hurd_port_init (&new->ctty, MACH_PORT_NULL); /* Install the port in the descriptor. This sets up all the ctty magic. */ _hurd_port2fd (new, _hurd_init_dtable[i], 0); _hurd_dtable[i] = new; } } /* Clear out the initial descriptor table. Everything must use _hurd_dtable now. */ __vm_deallocate (__mach_task_self (), (vm_address_t) _hurd_init_dtable, _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0])); _hurd_init_dtable = NULL; _hurd_init_dtablesize = 0; /* Initialize the remaining empty slots in the table. */ for (; i < _hurd_dtablesize; ++i) _hurd_dtable[i] = NULL; /* Run things that want to run after the file descriptor table is initialized. */ RUN_HOOK (_hurd_fd_subinit, ()); (void) &init_dtable; /* Avoid "defined but not used" warning. */ } text_set_element (_hurd_subinit, init_dtable); /* XXX when the linker supports it, the following functions should all be elsewhere and just have text_set_elements here. */ /* Called by `getdport' to do its work. */ static file_t get_dtable_port (int fd) { 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, ref, MACH_MSG_TYPE_MAKE_SEND, &new))) { /* Replace the port in the descriptor cell with the newly reauthenticated port. */ if (d->ctty.port != MACH_PORT_NULL && ! __io_reauthenticate (d->ctty.port, ref, MACH_MSG_TYPE_MAKE_SEND) && ! __USEPORT (AUTH, __auth_user_authenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND, &newctty))) _hurd_port_set (&d->ctty, newctty); _hurd_port_locked_set (&d->port, new); } else /* Lost. Leave this descriptor cell alone. */ __spin_unlock (&d->port.lock); __mach_port_destroy (__mach_task_self (), ref); } __mutex_unlock (&_hurd_dtable_lock); HURD_CRITICAL_END; (void) &reauth_dtable; /* Avoid "defined but not used" warning. */ } text_set_element (_hurd_reauth_hook, reauth_dtable);