Blame hurd/hurdioctl.c

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