Blame hurd/hurdioctl.c

Packit 6c4009
/* ioctl commands which must be done in the C library.
Packit 6c4009
   Copyright (C) 1994-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/fd.h>
Packit 6c4009
#include <sys/ioctl.h>
Packit 6c4009
#include <hurd/ioctl.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Symbol set of ioctl handler lists.  If there are user-registered
Packit 6c4009
   handlers, one of these lists will contain them.  The other lists are
Packit 6c4009
   handlers built into the library.  */
Packit 6c4009
symbol_set_define (_hurd_ioctl_handler_lists)
Packit 6c4009
Packit 6c4009
/* Look up REQUEST in the set of handlers.  */
Packit 6c4009
ioctl_handler_t
Packit 6c4009
_hurd_lookup_ioctl_handler (int request)
Packit 6c4009
{
Packit 6c4009
  void *const *ptr;
Packit 6c4009
  const struct ioctl_handler *h;
Packit 6c4009
Packit 6c4009
  /* Mask off the type bits, so that we see requests in a single group as a
Packit 6c4009
     contiguous block of values.  */
Packit 6c4009
  request = _IOC_NOTYPE (request);
Packit 6c4009
Packit 6c4009
  for (ptr = symbol_set_first_element (_hurd_ioctl_handler_lists);
Packit 6c4009
       !symbol_set_end_p (_hurd_ioctl_handler_lists, ptr);
Packit 6c4009
       ++ptr)
Packit 6c4009
    for (h = *ptr; h != NULL; h = h->next)
Packit 6c4009
      if (request >= h->first_request && request <= h->last_request)
Packit 6c4009
	return h->handler;
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
#include <fcntl.h>
Packit 6c4009
Packit 6c4009
/* Find out how many bytes may be read from FD without blocking.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
fioctl (int fd,
Packit 6c4009
	int request,
Packit 6c4009
	int *arg)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
Packit 6c4009
  *(volatile int *) arg = *arg;
Packit 6c4009
Packit 6c4009
  switch (request)
Packit 6c4009
    {
Packit 6c4009
    default:
Packit 6c4009
      err = ENOTTY;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case FIONREAD:
Packit 6c4009
      {
Packit 6c4009
	mach_msg_type_number_t navail;
Packit 6c4009
	err = HURD_DPORT_USE (fd, __io_readable (port, &navail));
Packit 6c4009
	if (!err)
Packit 6c4009
	  *arg = (int) navail;
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case FIONBIO:
Packit 6c4009
      err = HURD_DPORT_USE (fd, (*arg ?
Packit 6c4009
				 __io_set_some_openmodes :
Packit 6c4009
				 __io_clear_some_openmodes)
Packit 6c4009
			    (port, O_NONBLOCK));
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case FIOASYNC:
Packit 6c4009
      err = HURD_DPORT_USE (fd, (*arg ?
Packit 6c4009
				 __io_set_some_openmodes :
Packit 6c4009
				 __io_clear_some_openmodes)
Packit 6c4009
			    (port, O_ASYNC));
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case FIOSETOWN:
Packit 6c4009
      err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg));
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case FIOGETOWN:
Packit 6c4009
      err = HURD_DPORT_USE (fd, __io_get_owner (port, arg));
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return err ? __hurd_dfail (fd, err) : 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
_HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD);
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
fioclex (int fd,
Packit 6c4009
	 int request)
Packit 6c4009
{
Packit 6c4009
  int flag;
Packit 6c4009
Packit 6c4009
  switch (request)
Packit 6c4009
    {
Packit 6c4009
    default:
Packit 6c4009
      return __hurd_fail (ENOTTY);
Packit 6c4009
    case FIOCLEX:
Packit 6c4009
      flag = FD_CLOEXEC;
Packit 6c4009
      break;
Packit 6c4009
    case FIONCLEX:
Packit 6c4009
      flag = 0;
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return __fcntl (fd, F_SETFD, flag);
Packit 6c4009
}
Packit 6c4009
_HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX);
Packit 6c4009

Packit 6c4009
#include <hurd/term.h>
Packit 6c4009
#include <hurd/tioctl.h>
Packit 6c4009
Packit 6c4009
/* Install a new CTTYID port, atomically updating the dtable appropriately.
Packit 6c4009
   This consumes the send right passed in.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_hurd_locked_install_cttyid (mach_port_t cttyid)
Packit 6c4009
{
Packit 6c4009
  mach_port_t old;
Packit 6c4009
  struct hurd_port *const port = &_hurd_ports[INIT_PORT_CTTYID];
Packit 6c4009
  struct hurd_userlink ulink;
Packit 6c4009
  int i;
Packit 6c4009
Packit 6c4009
  /* Install the new cttyid port, and preserve it with a ulink.
Packit 6c4009
     We unroll the _hurd_port_set + _hurd_port_get here so that
Packit 6c4009
     there is no window where the cell is unlocked and CTTYID could
Packit 6c4009
     be changed by another thread.  (We also delay the deallocation
Packit 6c4009
     of the old port until the end, to minimize the duration of the
Packit 6c4009
     critical section.)
Packit 6c4009
Packit 6c4009
     It is important that changing the cttyid port is only ever done by
Packit 6c4009
     holding the dtable lock continuously while updating the port cell and
Packit 6c4009
     re-ctty'ing the dtable; dtable.c assumes we do this.  Otherwise, the
Packit 6c4009
     pgrp-change notification code in dtable.c has to worry about racing
Packit 6c4009
     against us here in odd situations.  The one exception to this is
Packit 6c4009
     setsid, which holds the dtable lock while changing the pgrp and
Packit 6c4009
     clearing the cttyid port, and then unlocks the dtable lock to allow
Packit 6c4009
Packit 6c4009
Packit 6c4009
  */
Packit 6c4009
Packit 6c4009
  __spin_lock (&port->lock);
Packit 6c4009
  old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL;
Packit 6c4009
  port->port = cttyid;
Packit 6c4009
  cttyid = _hurd_port_locked_get (port, &ulink);
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 newctty = MACH_PORT_NULL;
Packit 6c4009
Packit 6c4009
      if (d == NULL)
Packit 6c4009
	/* Nothing to do for an unused descriptor cell.  */
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      if (cttyid != MACH_PORT_NULL)
Packit 6c4009
	/* We do have some controlling tty.  */
Packit 6c4009
	HURD_PORT_USE (&d->port,
Packit 6c4009
		       ({ mach_port_t id;
Packit 6c4009
			  /* Get the io object's cttyid port.  */
Packit 6c4009
			  if (! __term_getctty (port, &id))
Packit 6c4009
			    {
Packit 6c4009
			      if (id == cttyid /* Is it ours?  */
Packit 6c4009
				  /* Get the ctty io port.  */
Packit 6c4009
				  && __term_open_ctty (port,
Packit 6c4009
						       _hurd_pid, _hurd_pgrp,
Packit 6c4009
						       &newctty))
Packit 6c4009
				/* XXX it is our ctty but the call failed? */
Packit 6c4009
				newctty = MACH_PORT_NULL;
Packit 6c4009
			      __mach_port_deallocate (__mach_task_self (), id);
Packit 6c4009
			    }
Packit 6c4009
			  0;
Packit 6c4009
			}));
Packit 6c4009
Packit 6c4009
      /* Install the new ctty port.  */
Packit 6c4009
      _hurd_port_set (&d->ctty, newctty);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
Packit 6c4009
  if (old != MACH_PORT_NULL)
Packit 6c4009
    __mach_port_deallocate (__mach_task_self (), old);
Packit 6c4009
  _hurd_port_free (port, &ulink, cttyid);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
install_ctty (mach_port_t cttyid)
Packit 6c4009
{
Packit 6c4009
  HURD_CRITICAL_BEGIN;
Packit 6c4009
  __mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
  _hurd_locked_install_cttyid (cttyid);
Packit 6c4009
  HURD_CRITICAL_END;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Called when we have received a message saying to use a new ctty ID port.  */
Packit 6c4009
Packit 6c4009
error_t
Packit 6c4009
_hurd_setcttyid (mach_port_t cttyid)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
Packit 6c4009
  if (cttyid != MACH_PORT_NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Give the new send right a user reference.
Packit 6c4009
	 This is a good way to check that it is valid.  */
Packit 6c4009
      if (err = __mach_port_mod_refs (__mach_task_self (), cttyid,
Packit 6c4009
				      MACH_PORT_RIGHT_SEND, 1))
Packit 6c4009
	return err;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Install the port, consuming the reference we just created.  */
Packit 6c4009
  install_ctty (cttyid);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline error_t
Packit 6c4009
do_tiocsctty (io_t port, io_t ctty)
Packit 6c4009
{
Packit 6c4009
  mach_port_t cttyid;
Packit 6c4009
  error_t err;
Packit 6c4009
Packit 6c4009
  if (ctty != MACH_PORT_NULL)
Packit 6c4009
    /* PORT is already the ctty.  Nothing to do.  */
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* Get PORT's cttyid port.  */
Packit 6c4009
  err = __term_getctty (port, &cttyid);
Packit 6c4009
  if (err)
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  /* Change the terminal's pgrp to ours.  */
Packit 6c4009
  err = __tioctl_tiocspgrp (port, _hurd_pgrp);
Packit 6c4009
  if (err)
Packit 6c4009
    __mach_port_deallocate (__mach_task_self (), cttyid);
Packit 6c4009
  else
Packit 6c4009
    /* Make it our own.  */
Packit 6c4009
    install_ctty (cttyid);
Packit 6c4009
Packit 6c4009
  return err;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Make FD be the controlling terminal.
Packit 6c4009
   This function is called for `ioctl (fd, TCIOSCTTY)'.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
tiocsctty (int fd,
Packit 6c4009
	   int request)		/* Always TIOCSCTTY.  */
Packit 6c4009
{
Packit 6c4009
  return __hurd_fail (HURD_DPORT_USE (fd, do_tiocsctty (port, ctty)));
Packit 6c4009
}
Packit 6c4009
_HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
Packit 6c4009
Packit 6c4009
/* Dissociate from the controlling terminal.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
tiocnotty (int fd,
Packit 6c4009
	   int request)		/* Always TIOCNOTTY.  */
Packit 6c4009
{
Packit 6c4009
  mach_port_t fd_cttyid;
Packit 6c4009
  error_t err;
Packit 6c4009
Packit 6c4009
  if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid)))
Packit 6c4009
    return __hurd_fail (err);
Packit 6c4009
Packit 6c4009
  if (__USEPORT (CTTYID, port != fd_cttyid))
Packit 6c4009
    err = EINVAL;
Packit 6c4009
Packit 6c4009
  __mach_port_deallocate (__mach_task_self (), fd_cttyid);
Packit 6c4009
Packit 6c4009
  if (err)
Packit 6c4009
    return __hurd_fail (err);
Packit 6c4009
Packit 6c4009
  /* Clear our cttyid port.  */
Packit 6c4009
  install_ctty (MACH_PORT_NULL);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
_HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
Packit 6c4009

Packit 6c4009
#include <hurd/pfinet.h>
Packit 6c4009
#include <net/if.h>
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
Packit 6c4009
/* Fill in the buffer IFC->IFC_BUF of length IFC->IFC_LEN with a list
Packit 6c4009
   of ifr structures, one for each network interface.  */
Packit 6c4009
static int
Packit 6c4009
siocgifconf (int fd, int request, struct ifconf *ifc)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  size_t data_len = ifc->ifc_len;
Packit 6c4009
  char *data = ifc->ifc_buf;
Packit 6c4009
Packit 6c4009
  if (data_len <= 0)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  err = HURD_DPORT_USE (fd, __pfinet_siocgifconf (port, ifc->ifc_len,
Packit 6c4009
						  &data, &data_len));
Packit 6c4009
  if (data_len < ifc->ifc_len)
Packit 6c4009
    ifc->ifc_len = data_len;
Packit 6c4009
  if (data != ifc->ifc_buf)
Packit 6c4009
    {
Packit 6c4009
      memcpy (ifc->ifc_buf, data, ifc->ifc_len);
Packit 6c4009
      __vm_deallocate (__mach_task_self (), (vm_address_t) data, data_len);
Packit 6c4009
    }
Packit 6c4009
  return err ? __hurd_dfail (fd, err) : 0;
Packit 6c4009
}
Packit 6c4009
_HURD_HANDLE_IOCTL (siocgifconf, SIOCGIFCONF);