Blame hurd/dtable.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/term.h>
Packit 6c4009
#include <hurd/fd.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <cthreads.h>		/* For `struct mutex'.  */
Packit 6c4009
#include "set-hooks.h"
Packit 6c4009
#include "hurdmalloc.h"		/* XXX */
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */
Packit 6c4009
struct hurd_fd **_hurd_dtable;
Packit 6c4009
int _hurd_dtablesize;
Packit 6c4009
Packit 6c4009
Packit 6c4009
DEFINE_HOOK (_hurd_fd_subinit, (void));
Packit 6c4009
Packit 6c4009
/* Initialize the file descriptor table at startup.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
init_dtable (void)
Packit 6c4009
{
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  __mutex_init (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
  /* The initial size of the descriptor table is that of the passed-in
Packit 6c4009
     table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
Packit 6c4009
  _hurd_dtablesize = _hurd_init_dtablesize;
Packit 6c4009
Packit 6c4009
  /* Allocate the vector of pointers.  */
Packit 6c4009
  _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
Packit 6c4009
  if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
Packit 6c4009
    __libc_fatal ("hurd: Can't allocate file descriptor table\n");
Packit 6c4009
Packit 6c4009
  /* Initialize the descriptor table.  */
Packit 6c4009
  for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i)
Packit 6c4009
    {
Packit 6c4009
      if (_hurd_init_dtable[i] == MACH_PORT_NULL)
Packit 6c4009
	/* An unused descriptor is marked by a null pointer.  */
Packit 6c4009
	_hurd_dtable[i] = NULL;
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* Allocate a new file descriptor structure.  */
Packit 6c4009
	  struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
Packit 6c4009
	  if (new == NULL)
Packit 6c4009
	    __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
Packit 6c4009
Packit 6c4009
	  /* Initialize the port cells.  */
Packit 6c4009
	  _hurd_port_init (&new->port, MACH_PORT_NULL);
Packit 6c4009
	  _hurd_port_init (&new->ctty, MACH_PORT_NULL);
Packit 6c4009
Packit 6c4009
	  /* Install the port in the descriptor.
Packit 6c4009
	     This sets up all the ctty magic.  */
Packit 6c4009
	  _hurd_port2fd (new, _hurd_init_dtable[i], 0);
Packit 6c4009
Packit 6c4009
	  _hurd_dtable[i] = new;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Clear out the initial descriptor table.
Packit 6c4009
     Everything must use _hurd_dtable now.  */
Packit 6c4009
  __vm_deallocate (__mach_task_self (),
Packit 6c4009
		   (vm_address_t) _hurd_init_dtable,
Packit 6c4009
		   _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
Packit 6c4009
  _hurd_init_dtable = NULL;
Packit 6c4009
  _hurd_init_dtablesize = 0;
Packit 6c4009
Packit 6c4009
  /* Initialize the remaining empty slots in the table.  */
Packit 6c4009
  for (; i < _hurd_dtablesize; ++i)
Packit 6c4009
    _hurd_dtable[i] = NULL;
Packit 6c4009
Packit 6c4009
  /* Run things that want to run after the file descriptor table
Packit 6c4009
     is initialized.  */
Packit 6c4009
  RUN_HOOK (_hurd_fd_subinit, ());
Packit 6c4009
Packit 6c4009
  (void) &init_dtable;		/* Avoid "defined but not used" warning.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
text_set_element (_hurd_subinit, init_dtable);
Packit 6c4009
Packit 6c4009
/* XXX when the linker supports it, the following functions should all be
Packit 6c4009
   elsewhere and just have text_set_elements here.  */
Packit 6c4009

Packit 6c4009
/* Called by `getdport' to do its work.  */
Packit 6c4009
Packit 6c4009
static file_t
Packit 6c4009
get_dtable_port (int fd)
Packit 6c4009
{
Packit 6c4009
  struct hurd_fd *d = _hurd_fd_get (fd);
Packit 6c4009
  file_t dport;
Packit 6c4009
Packit 6c4009
  if (!d)
Packit 6c4009
    return __hurd_fail (EBADF), MACH_PORT_NULL;
Packit 6c4009
Packit 6c4009
  HURD_CRITICAL_BEGIN;
Packit 6c4009
Packit 6c4009
  dport = HURD_PORT_USE (&d->port,
Packit 6c4009
			 ({
Packit 6c4009
			   error_t err;
Packit 6c4009
			   mach_port_t outport;
Packit 6c4009
			   err = __mach_port_mod_refs (__mach_task_self (),
Packit 6c4009
						       port,
Packit 6c4009
						       MACH_PORT_RIGHT_SEND,
Packit 6c4009
						       1);
Packit 6c4009
			   if (err)
Packit 6c4009
			     {
Packit 6c4009
			       errno = err;
Packit 6c4009
			       outport = MACH_PORT_NULL;
Packit 6c4009
			     }
Packit 6c4009
			   else
Packit 6c4009
			     outport = port;
Packit 6c4009
			   outport;
Packit 6c4009
			 }));
Packit 6c4009
Packit 6c4009
  HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
  return dport;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
Packit 6c4009

Packit 6c4009
#include <hurd/signal.h>
Packit 6c4009
Packit 6c4009
/* We are in the child fork; the dtable lock is still held.
Packit 6c4009
   The parent has inserted send rights for all the normal io ports,
Packit 6c4009
   but we must recover ctty-special ports for ourselves.  */
Packit 6c4009
static error_t
Packit 6c4009
fork_child_dtable (void)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  err = 0;
Packit 6c4009
Packit 6c4009
  for (i = 0; !err && i < _hurd_dtablesize; ++i)
Packit 6c4009
    {
Packit 6c4009
      struct hurd_fd *d = _hurd_dtable[i];
Packit 6c4009
      if (d == NULL)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      /* No other thread is using the send rights in the child task.  */
Packit 6c4009
      d->port.users = d->ctty.users = NULL;
Packit 6c4009
Packit 6c4009
      if (d->ctty.port != MACH_PORT_NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* There was a ctty-special port in the parent.
Packit 6c4009
	     We need to get one for ourselves too.  */
Packit 6c4009
	  __mach_port_deallocate (__mach_task_self (), d->ctty.port);
Packit 6c4009
	  err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp,
Packit 6c4009
				  &d->ctty.port);
Packit 6c4009
	  if (err)
Packit 6c4009
	    d->ctty.port = MACH_PORT_NULL;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
Packit 6c4009
    }
Packit 6c4009
  return err;
Packit 6c4009
Packit 6c4009
  (void) &fork_child_dtable;	/* Avoid "defined but not used" warning.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
data_set_element (_hurd_fork_locks, _hurd_dtable_lock);	/* XXX ld bug: bss */
Packit 6c4009
text_set_element (_hurd_fork_child_hook, fork_child_dtable);
Packit 6c4009

Packit 6c4009
/* Called when our process group has changed.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
ctty_new_pgrp (void)
Packit 6c4009
{
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  HURD_CRITICAL_BEGIN;
Packit 6c4009
  __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
  if (__USEPORT (CTTYID, port == MACH_PORT_NULL))
Packit 6c4009
    {
Packit 6c4009
      /* We have no controlling terminal.  If we haven't had one recently,
Packit 6c4009
	 but our pgrp is being pointlessly diddled anyway, then we will
Packit 6c4009
	 have nothing to do in the loop below because no fd will have a
Packit 6c4009
	 ctty port at all.
Packit 6c4009
Packit 6c4009
	 More likely, a setsid call is responsible both for the change
Packit 6c4009
	 in pgrp and for clearing the cttyid port.  In that case, setsid
Packit 6c4009
	 held the dtable lock while updating the dtable to clear all the
Packit 6c4009
	 ctty ports, and ergo must have finished doing so before we run here.
Packit 6c4009
	 So we can be sure, again, that the loop below has no work to do.  */
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    for (i = 0; i < _hurd_dtablesize; ++i)
Packit 6c4009
      {
Packit 6c4009
	struct hurd_fd *const d = _hurd_dtable[i];
Packit 6c4009
	struct hurd_userlink ulink, ctty_ulink;
Packit 6c4009
	io_t port, ctty;
Packit 6c4009
Packit 6c4009
	if (d == NULL)
Packit 6c4009
	  /* Nothing to do for an unused descriptor cell.  */
Packit 6c4009
	  continue;
Packit 6c4009
Packit 6c4009
	port = _hurd_port_get (&d->port, &ulink);
Packit 6c4009
	ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
Packit 6c4009
Packit 6c4009
	if (ctty != MACH_PORT_NULL)
Packit 6c4009
	  {
Packit 6c4009
	    /* This fd has a ctty-special port.  We need a new one, to tell
Packit 6c4009
	       the io server of our different process group.  */
Packit 6c4009
	    io_t new;
Packit 6c4009
	    if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
Packit 6c4009
	      new = MACH_PORT_NULL;
Packit 6c4009
	    _hurd_port_set (&d->ctty, new);
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	_hurd_port_free (&d->port, &ulink, port);
Packit 6c4009
	_hurd_port_free (&d->ctty, &ctty_ulink, ctty);
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
  HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
  (void) &ctty_new_pgrp;	/* Avoid "defined but not used" warning.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
Packit 6c4009

Packit 6c4009
/* Called to reauthenticate the dtable when the auth port changes.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
reauth_dtable (void)
Packit 6c4009
{
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  HURD_CRITICAL_BEGIN;
Packit 6c4009
  __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
  for (i = 0; i < _hurd_dtablesize; ++i)
Packit 6c4009
    {
Packit 6c4009
      struct hurd_fd *const d = _hurd_dtable[i];
Packit 6c4009
      mach_port_t new, newctty, ref;
Packit 6c4009
Packit 6c4009
      if (d == NULL)
Packit 6c4009
	/* Nothing to do for an unused descriptor cell.  */
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      ref = __mach_reply_port ();
Packit 6c4009
Packit 6c4009
      /* Take the descriptor cell's lock.  */
Packit 6c4009
      __spin_lock (&d->port.lock);
Packit 6c4009
Packit 6c4009
      /* Reauthenticate the descriptor's port.  */
Packit 6c4009
      if (d->port.port != MACH_PORT_NULL &&
Packit 6c4009
	  ! __io_reauthenticate (d->port.port,
Packit 6c4009
				 ref, MACH_MSG_TYPE_MAKE_SEND) &&
Packit 6c4009
	  ! __USEPORT (AUTH, __auth_user_authenticate
Packit 6c4009
		       (port,
Packit 6c4009
			ref, MACH_MSG_TYPE_MAKE_SEND,
Packit 6c4009
			&new)))
Packit 6c4009
	{
Packit 6c4009
	  /* Replace the port in the descriptor cell
Packit 6c4009
	     with the newly reauthenticated port.  */
Packit 6c4009
Packit 6c4009
	  if (d->ctty.port != MACH_PORT_NULL &&
Packit 6c4009
	      ! __io_reauthenticate (d->ctty.port,
Packit 6c4009
				     ref, MACH_MSG_TYPE_MAKE_SEND) &&
Packit 6c4009
	      ! __USEPORT (AUTH, __auth_user_authenticate
Packit 6c4009
			   (port,
Packit 6c4009
			    ref, MACH_MSG_TYPE_MAKE_SEND,
Packit 6c4009
			    &newctty)))
Packit 6c4009
	    _hurd_port_set (&d->ctty, newctty);
Packit 6c4009
Packit 6c4009
	  _hurd_port_locked_set (&d->port, new);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	/* Lost.  Leave this descriptor cell alone.  */
Packit 6c4009
	__spin_unlock (&d->port.lock);
Packit 6c4009
Packit 6c4009
      __mach_port_destroy (__mach_task_self (), ref);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
  HURD_CRITICAL_END;
Packit 6c4009
Packit 6c4009
  (void) &reauth_dtable;	/* Avoid "defined but not used" warning.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
text_set_element (_hurd_reauth_hook, reauth_dtable);