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