Back to index

glibc  2.9
dtable.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92,93,94,95,96,97,99 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <hurd.h>
00020 #include <hurd/term.h>
00021 #include <hurd/fd.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <fcntl.h>
00025 #include <limits.h>
00026 #include <cthreads.h>              /* For `struct mutex'.  */
00027 #include "set-hooks.h"
00028 #include "hurdmalloc.h"            /* XXX */
00029 
00030 
00031 struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */
00032 struct hurd_fd **_hurd_dtable;
00033 int _hurd_dtablesize;
00034 
00035 
00036 DEFINE_HOOK (_hurd_fd_subinit, (void));
00037 
00038 /* Initialize the file descriptor table at startup.  */
00039 
00040 static void
00041 init_dtable (void)
00042 {
00043   int i;
00044 
00045   __mutex_init (&_hurd_dtable_lock);
00046 
00047   /* The initial size of the descriptor table is that of the passed-in
00048      table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
00049   _hurd_dtablesize = _hurd_init_dtablesize;
00050 
00051   /* Allocate the vector of pointers.  */
00052   _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
00053   if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
00054     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
00055 
00056   /* Initialize the descriptor table.  */
00057   for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i)
00058     {
00059       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
00060        /* An unused descriptor is marked by a null pointer.  */
00061        _hurd_dtable[i] = NULL;
00062       else
00063        {
00064          /* Allocate a new file descriptor structure.  */
00065          struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
00066          if (new == NULL)
00067            __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
00068 
00069          /* Initialize the port cells.  */
00070          _hurd_port_init (&new->port, MACH_PORT_NULL);
00071          _hurd_port_init (&new->ctty, MACH_PORT_NULL);
00072 
00073          /* Install the port in the descriptor.
00074             This sets up all the ctty magic.  */
00075          _hurd_port2fd (new, _hurd_init_dtable[i], 0);
00076 
00077          _hurd_dtable[i] = new;
00078        }
00079     }
00080 
00081   /* Clear out the initial descriptor table.
00082      Everything must use _hurd_dtable now.  */
00083   __vm_deallocate (__mach_task_self (),
00084                  (vm_address_t) _hurd_init_dtable,
00085                  _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
00086   _hurd_init_dtable = NULL;
00087   _hurd_init_dtablesize = 0;
00088 
00089   /* Initialize the remaining empty slots in the table.  */
00090   for (; i < _hurd_dtablesize; ++i)
00091     _hurd_dtable[i] = NULL;
00092 
00093   /* Run things that want to run after the file descriptor table
00094      is initialized.  */
00095   RUN_HOOK (_hurd_fd_subinit, ());
00096 
00097   (void) &init_dtable;             /* Avoid "defined but not used" warning.  */
00098 }
00099 
00100 text_set_element (_hurd_subinit, init_dtable);
00101 
00102 /* XXX when the linker supports it, the following functions should all be
00103    elsewhere and just have text_set_elements here.  */
00104 
00105 /* Called by `getdport' to do its work.  */
00106 
00107 static file_t
00108 get_dtable_port (int fd)
00109 {
00110   struct hurd_fd *d = _hurd_fd_get (fd);
00111   file_t dport;
00112 
00113   if (!d)
00114     return __hurd_fail (EBADF), MACH_PORT_NULL;
00115 
00116   HURD_CRITICAL_BEGIN;
00117 
00118   dport = HURD_PORT_USE (&d->port,
00119                       ({
00120                         error_t err;
00121                         mach_port_t outport;
00122                         err = __mach_port_mod_refs (__mach_task_self (),
00123                                                  port,
00124                                                  MACH_PORT_RIGHT_SEND,
00125                                                  1);
00126                         if (err)
00127                           {
00128                             errno = err;
00129                             outport = MACH_PORT_NULL;
00130                           }
00131                         else
00132                           outport = port;
00133                         outport;
00134                       }));
00135 
00136   HURD_CRITICAL_END;
00137 
00138   return dport;
00139 }
00140 
00141 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
00142 
00143 #include <hurd/signal.h>
00144 
00145 /* We are in the child fork; the dtable lock is still held.
00146    The parent has inserted send rights for all the normal io ports,
00147    but we must recover ctty-special ports for ourselves.  */
00148 static error_t
00149 fork_child_dtable (void)
00150 {
00151   error_t err;
00152   int i;
00153 
00154   err = 0;
00155 
00156   for (i = 0; !err && i < _hurd_dtablesize; ++i)
00157     {
00158       struct hurd_fd *d = _hurd_dtable[i];
00159       if (d == NULL)
00160        continue;
00161 
00162       /* No other thread is using the send rights in the child task.  */
00163       d->port.users = d->ctty.users = NULL;
00164 
00165       if (d->ctty.port != MACH_PORT_NULL)
00166        {
00167          /* There was a ctty-special port in the parent.
00168             We need to get one for ourselves too.  */
00169          __mach_port_deallocate (__mach_task_self (), d->ctty.port);
00170          err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp,
00171                               &d->ctty.port);
00172          if (err)
00173            d->ctty.port = MACH_PORT_NULL;
00174        }
00175 
00176       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
00177     }
00178   return err;
00179 
00180   (void) &fork_child_dtable;       /* Avoid "defined but not used" warning.  */
00181 }
00182 
00183 data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */
00184 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
00185 
00186 /* Called when our process group has changed.  */
00187 
00188 static void
00189 ctty_new_pgrp (void)
00190 {
00191   int i;
00192 
00193   HURD_CRITICAL_BEGIN;
00194   __mutex_lock (&_hurd_dtable_lock);
00195 
00196   if (__USEPORT (CTTYID, port == MACH_PORT_NULL))
00197     {
00198       /* We have no controlling terminal.  If we haven't had one recently,
00199         but our pgrp is being pointlessly diddled anyway, then we will
00200         have nothing to do in the loop below because no fd will have a
00201         ctty port at all.
00202 
00203         More likely, a setsid call is responsible both for the change
00204         in pgrp and for clearing the cttyid port.  In that case, setsid
00205         held the dtable lock while updating the dtable to clear all the
00206         ctty ports, and ergo must have finished doing so before we run here.
00207         So we can be sure, again, that the loop below has no work to do.  */
00208     }
00209   else
00210     for (i = 0; i < _hurd_dtablesize; ++i)
00211       {
00212        struct hurd_fd *const d = _hurd_dtable[i];
00213        struct hurd_userlink ulink, ctty_ulink;
00214        io_t port, ctty;
00215 
00216        if (d == NULL)
00217          /* Nothing to do for an unused descriptor cell.  */
00218          continue;
00219 
00220        port = _hurd_port_get (&d->port, &ulink);
00221        ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
00222 
00223        if (ctty != MACH_PORT_NULL)
00224          {
00225            /* This fd has a ctty-special port.  We need a new one, to tell
00226               the io server of our different process group.  */
00227            io_t new;
00228            if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
00229              new = MACH_PORT_NULL;
00230            _hurd_port_set (&d->ctty, new);
00231          }
00232 
00233        _hurd_port_free (&d->port, &ulink, port);
00234        _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
00235       }
00236 
00237   __mutex_unlock (&_hurd_dtable_lock);
00238   HURD_CRITICAL_END;
00239 
00240   (void) &ctty_new_pgrp;    /* Avoid "defined but not used" warning.  */
00241 }
00242 
00243 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
00244 
00245 /* Called to reauthenticate the dtable when the auth port changes.  */
00246 
00247 static void
00248 reauth_dtable (void)
00249 {
00250   int i;
00251 
00252   HURD_CRITICAL_BEGIN;
00253   __mutex_lock (&_hurd_dtable_lock);
00254 
00255   for (i = 0; i < _hurd_dtablesize; ++i)
00256     {
00257       struct hurd_fd *const d = _hurd_dtable[i];
00258       mach_port_t new, newctty, ref;
00259 
00260       if (d == NULL)
00261        /* Nothing to do for an unused descriptor cell.  */
00262        continue;
00263 
00264       ref = __mach_reply_port ();
00265 
00266       /* Take the descriptor cell's lock.  */
00267       __spin_lock (&d->port.lock);
00268 
00269       /* Reauthenticate the descriptor's port.  */
00270       if (d->port.port != MACH_PORT_NULL &&
00271          ! __io_reauthenticate (d->port.port,
00272                              ref, MACH_MSG_TYPE_MAKE_SEND) &&
00273          ! __USEPORT (AUTH, __auth_user_authenticate
00274                      (port,
00275                      ref, MACH_MSG_TYPE_MAKE_SEND,
00276                      &new)))
00277        {
00278          /* Replace the port in the descriptor cell
00279             with the newly reauthenticated port.  */
00280 
00281          if (d->ctty.port != MACH_PORT_NULL &&
00282              ! __io_reauthenticate (d->ctty.port,
00283                                  ref, MACH_MSG_TYPE_MAKE_SEND) &&
00284              ! __USEPORT (AUTH, __auth_user_authenticate
00285                         (port,
00286                          ref, MACH_MSG_TYPE_MAKE_SEND,
00287                          &newctty)))
00288            _hurd_port_set (&d->ctty, newctty);
00289 
00290          _hurd_port_locked_set (&d->port, new);
00291        }
00292       else
00293        /* Lost.  Leave this descriptor cell alone.  */
00294        __spin_unlock (&d->port.lock);
00295 
00296       __mach_port_destroy (__mach_task_self (), ref);
00297     }
00298 
00299   __mutex_unlock (&_hurd_dtable_lock);
00300   HURD_CRITICAL_END;
00301 
00302   (void) &reauth_dtable;    /* Avoid "defined but not used" warning.  */
00303 }
00304 
00305 text_set_element (_hurd_reauth_hook, reauth_dtable);