Formerly ../hurd/hurdkill.c.~5~
[kopensolaris-gnu/glibc.git] / hurd / dtable.c
index 042f0d1..4812c69 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991 Free Software Foundation, Inc.
+/* 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
@@ -16,69 +16,256 @@ 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 <gnu-stabs.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 _hurd_dtable _hurd_dtable;
-text_set_element (_hurd_dtable_set, _hurd_dtable);
+
+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);
+  __mutex_init (&_hurd_dtable_lock);
 
   /* The initial size of the descriptor table is that of the passed-in
-     table, rounded up to a multiple of OPEN_MAX descriptors.  */
-  _hurd_dtable.size
-    = (_hurd_init_dtablesize + OPEN_MAX - 1) / OPEN_MAX * OPEN_MAX;
+     table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
+  _hurd_dtablesize = _hurd_init_dtablesize;
 
-  _hurd_dtable.d = malloc (_hurd_init_dtablesize * sizeof (*_hurd_dtable.d));
-  if (_hurd_dtable.d == NULL)
-    __libc_fatal ("hurd: Can't allocate descriptor table\n");
+  /* 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)
     {
-      _hurd_dtable.d[i] = _hurd_init_dtable[i];
-      __spin_lock_init (&_hurd_dtable.d[i].reflock);
-      _hurd_dtable.d[i].refs = 0;
-      __condition_init (&_hurd_dtable.d[i].free);
-    }
-  for (; i < _hurd_dtable.size; ++i)
-    {
-      _hurd_dtable.d[i].server = MACH_PORT_NULL;
-      __spin_lock_init (&_hurd_dtable.d[i].reflock);
-      _hurd_dtable.d[i].refs = 0;
-      __condition_init (&_hurd_dtable.d[i].free);
+      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.  */
+\f
+/* 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 = ctty ?: port),
+                                                     MACH_PORT_RIGHT_SEND,
+                                                     1));
+  if (err)
+    {
+      errno = err;
+      return MACH_PORT_NULL;
+    }
+  else
+    return dport;
 }
 
-text_set_element (__libc_subinit, init_dtable);
+file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
 \f
-/* Called on fork to install the dtable in NEWTASK.  */
+#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_dtable (task_t newtask)
+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->port.port);
+         err = __term_open_ctty (d->ctty.port, _hurd_pid, _hurd_pgrp,
+                                 &d->port.port);
+         if (err)
+           {
+             d->port.port = d->ctty.port;
+             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);
+\f
+/* 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)
+       {
+         /* 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 (ctty, _hurd_pid, _hurd_pgrp, &new))
+           _hurd_port_set (&d->port, 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);
+\f
+/* Called to reauthenticate the dtable when the auth port changes.  */
+
+static void
+reauth_dtable (void)
 {
   int i;
-  __mutex_lock (&_hurd_dtable.lock);
-  for (i = 0; i < _hurd_dtable.size; ++i)
-    if (err = __mach_port_insert_right (newtask, _hurd_dtable.d[i].server,
-                                       _hurd_dtable.d[i].server,
-                                       MACH_PORT_COPY_SEND))
-      {
-       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
-       __mutex_unlock (&_hurd_dtable.lock);
-       return 1;
-      }
-  __mutex_unlock (&_hurd_dtable.lock);
-  return 0;
+
+  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;
+      
+      if (d == NULL)
+       /* Nothing to do for an unused descriptor cell.  */
+       continue;
+
+      /* 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, _hurd_pid) &&
+         ! __USEPORT (AUTH, __auth_user_authenticate (port,
+                                                      d->port.port, _hurd_pid,
+                                                      &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, _hurd_pid) &&
+             ! __USEPORT (AUTH, __auth_user_authenticate (port,
+                                                          d->ctty.port,
+                                                          _hurd_pid,
+                                                          &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);
+    }
+
+  __mutex_unlock (&_hurd_dtable_lock);
+  HURD_CRITICAL_END;
+
+  (void) &reauth_dtable;       /* Avoid "defined but not used" warning.  */
 }
 
-text_set_element (_hurd_fork_hook, fork_dtable);
+text_set_element (_hurd_reauth_hook, reauth_dtable);