Back to index

glibc  2.9
hurdioctl.c
Go to the documentation of this file.
00001 /* ioctl commands which must be done in the C library.
00002    Copyright (C) 1994,95,96,97,99,2001,02 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <hurd.h>
00021 #include <hurd/fd.h>
00022 #include <sys/ioctl.h>
00023 #include <hurd/ioctl.h>
00024 #include <string.h>
00025 
00026 
00027 /* Symbol set of ioctl handler lists.  If there are user-registered
00028    handlers, one of these lists will contain them.  The other lists are
00029    handlers built into the library.  */
00030 symbol_set_define (_hurd_ioctl_handler_lists)
00031 
00032 /* Look up REQUEST in the set of handlers.  */
00033 ioctl_handler_t
00034 _hurd_lookup_ioctl_handler (int request)
00035 {
00036   void *const *ptr;
00037   const struct ioctl_handler *h;
00038 
00039   /* Mask off the type bits, so that we see requests in a single group as a
00040      contiguous block of values.  */
00041   request = _IOC_NOTYPE (request);
00042 
00043   for (ptr = symbol_set_first_element (_hurd_ioctl_handler_lists);
00044        !symbol_set_end_p (_hurd_ioctl_handler_lists, ptr);
00045        ++ptr)
00046     for (h = *ptr; h != NULL; h = h->next)
00047       if (request >= h->first_request && request <= h->last_request)
00048        return h->handler;
00049 
00050   return NULL;
00051 }
00052 
00053 #include <fcntl.h>
00054 
00055 /* Find out how many bytes may be read from FD without blocking.  */
00056 
00057 static int
00058 fioctl (int fd,
00059        int request,
00060        int *arg)
00061 {
00062   error_t err;
00063 
00064   *(volatile int *) arg = *arg;
00065 
00066   switch (request)
00067     {
00068     default:
00069       err = ENOTTY;
00070       break;
00071 
00072     case FIONREAD:
00073       {
00074        mach_msg_type_number_t navail;
00075        err = HURD_DPORT_USE (fd, __io_readable (port, &navail));
00076        if (!err)
00077          *arg = (int) navail;
00078       }
00079       break;
00080 
00081     case FIONBIO:
00082       err = HURD_DPORT_USE (fd, (*arg ?
00083                              __io_set_some_openmodes :
00084                              __io_clear_some_openmodes)
00085                          (port, O_NONBLOCK));
00086       break;
00087 
00088     case FIOASYNC:
00089       err = HURD_DPORT_USE (fd, (*arg ?
00090                              __io_set_some_openmodes :
00091                              __io_clear_some_openmodes)
00092                          (port, O_ASYNC));
00093       break;
00094 
00095     case FIOSETOWN:
00096       err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg));
00097       break;
00098 
00099     case FIOGETOWN:
00100       err = HURD_DPORT_USE (fd, __io_get_owner (port, arg));
00101       break;
00102     }
00103 
00104   return err ? __hurd_dfail (fd, err) : 0;
00105 }
00106 
00107 _HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD);
00108 
00109 
00110 static int
00111 fioclex (int fd,
00112         int request)
00113 {
00114   int flag;
00115 
00116   switch (request)
00117     {
00118     default:
00119       return __hurd_fail (ENOTTY);
00120     case FIOCLEX:
00121       flag = FD_CLOEXEC;
00122       break;
00123     case FIONCLEX:
00124       flag = 0;
00125       break;
00126     }
00127 
00128   return __fcntl (fd, F_SETFD, flag);
00129 }
00130 _HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX);
00131 
00132 #include <hurd/term.h>
00133 #include <hurd/tioctl.h>
00134 
00135 /* Install a new CTTYID port, atomically updating the dtable appropriately.
00136    This consumes the send right passed in.  */
00137 
00138 void
00139 _hurd_locked_install_cttyid (mach_port_t cttyid)
00140 {
00141   mach_port_t old;
00142   struct hurd_port *const port = &_hurd_ports[INIT_PORT_CTTYID];
00143   struct hurd_userlink ulink;
00144   int i;
00145 
00146   /* Install the new cttyid port, and preserve it with a ulink.
00147      We unroll the _hurd_port_set + _hurd_port_get here so that
00148      there is no window where the cell is unlocked and CTTYID could
00149      be changed by another thread.  (We also delay the deallocation
00150      of the old port until the end, to minimize the duration of the
00151      critical section.)
00152 
00153      It is important that changing the cttyid port is only ever done by
00154      holding the dtable lock continuously while updating the port cell and
00155      re-ctty'ing the dtable; dtable.c assumes we do this.  Otherwise, the
00156      pgrp-change notification code in dtable.c has to worry about racing
00157      against us here in odd situations.  The one exception to this is
00158      setsid, which holds the dtable lock while changing the pgrp and
00159      clearing the cttyid port, and then unlocks the dtable lock to allow
00160 
00161 
00162   */
00163 
00164   __spin_lock (&port->lock);
00165   old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL;
00166   port->port = cttyid;
00167   cttyid = _hurd_port_locked_get (port, &ulink);
00168 
00169   for (i = 0; i < _hurd_dtablesize; ++i)
00170     {
00171       struct hurd_fd *const d = _hurd_dtable[i];
00172       mach_port_t newctty;
00173 
00174       if (d == NULL)
00175        /* Nothing to do for an unused descriptor cell.  */
00176        continue;
00177 
00178       if (cttyid == MACH_PORT_NULL)
00179        /* We now have no controlling tty at all.  */
00180        newctty = MACH_PORT_NULL;
00181       else
00182        HURD_PORT_USE (&d->port,
00183                      ({ mach_port_t id;
00184                        /* Get the io object's cttyid port.  */
00185                        if (! __term_getctty (port, &id))
00186                          {
00187                            if (id == cttyid && /* Is it ours?  */
00188                               /* Get the ctty io port.  */
00189                               __term_open_ctty (port,
00190                                               _hurd_pid, _hurd_pgrp,
00191                                               &newctty))
00192                             /* XXX it is our ctty but the call failed? */
00193                             newctty = MACH_PORT_NULL;
00194                            __mach_port_deallocate
00195                             (__mach_task_self (), (mach_port_t) id);
00196                          }
00197                        else
00198                          newctty = MACH_PORT_NULL;
00199                        0;
00200                      }));
00201 
00202       /* Install the new ctty port.  */
00203       _hurd_port_set (&d->ctty, newctty);
00204     }
00205 
00206   __mutex_unlock (&_hurd_dtable_lock);
00207 
00208   if (old != MACH_PORT_NULL)
00209     __mach_port_deallocate (__mach_task_self (), old);
00210   _hurd_port_free (port, &ulink, cttyid);
00211 }
00212 
00213 static void
00214 install_ctty (mach_port_t cttyid)
00215 {
00216   HURD_CRITICAL_BEGIN;
00217   __mutex_lock (&_hurd_dtable_lock);
00218   _hurd_locked_install_cttyid (cttyid);
00219   HURD_CRITICAL_END;
00220 }
00221 
00222 
00223 /* Called when we have received a message saying to use a new ctty ID port.  */
00224 
00225 error_t
00226 _hurd_setcttyid (mach_port_t cttyid)
00227 {
00228   error_t err;
00229 
00230   if (cttyid != MACH_PORT_NULL)
00231     {
00232       /* Give the new send right a user reference.
00233         This is a good way to check that it is valid.  */
00234       if (err = __mach_port_mod_refs (__mach_task_self (), cttyid,
00235                                   MACH_PORT_RIGHT_SEND, 1))
00236        return err;
00237     }
00238 
00239   /* Install the port, consuming the reference we just created.  */
00240   install_ctty (cttyid);
00241 
00242   return 0;
00243 }
00244 
00245 
00246 /* Make FD be the controlling terminal.
00247    This function is called for `ioctl (fd, TCIOSCTTY)'.  */
00248 
00249 static int
00250 tiocsctty (int fd,
00251           int request)             /* Always TIOCSCTTY.  */
00252 {
00253   mach_port_t cttyid;
00254   error_t err;
00255 
00256   /* Get FD's cttyid port, unless it is already ours.  */
00257   err = HURD_DPORT_USE (fd, ctty != MACH_PORT_NULL ? EADDRINUSE :
00258                      __term_getctty (port, &cttyid));
00259   if (err == EADDRINUSE)
00260     /* FD is already the ctty.  Nothing to do.  */
00261     return 0;
00262   else if (err)
00263     return __hurd_fail (err);
00264 
00265   /* Change the terminal's pgrp to ours.  */
00266   err = HURD_DPORT_USE (fd, __tioctl_tiocspgrp (port, _hurd_pgrp));
00267   if (err)
00268     return __hurd_fail (err);
00269 
00270   /* Make it our own.  */
00271   install_ctty (cttyid);
00272 
00273   return 0;
00274 }
00275 _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
00276 
00277 /* Dissociate from the controlling terminal.  */
00278 
00279 static int
00280 tiocnotty (int fd,
00281           int request)             /* Always TIOCNOTTY.  */
00282 {
00283   mach_port_t fd_cttyid;
00284   error_t err;
00285 
00286   if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid)))
00287     return __hurd_fail (err);
00288 
00289   if (__USEPORT (CTTYID, port != fd_cttyid))
00290     err = EINVAL;
00291 
00292   __mach_port_deallocate (__mach_task_self (), fd_cttyid);
00293 
00294   if (err)
00295     return __hurd_fail (err);
00296 
00297   /* Clear our cttyid port.  */
00298   install_ctty (MACH_PORT_NULL);
00299 
00300   return 0;
00301 }
00302 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
00303 
00304 #include <hurd/pfinet.h>
00305 #include <net/if.h>
00306 #include <netinet/in.h>
00307 
00308 /* Fill in the buffer IFC->IFC_BUF of length IFC->IFC_LEN with a list
00309    of ifr structures, one for each network interface.  */
00310 static int
00311 siocgifconf (int fd, int request, struct ifconf *ifc)
00312 {
00313   error_t err;
00314   size_t data_len = ifc->ifc_len;
00315   char *data = ifc->ifc_buf;
00316 
00317   if (data_len <= 0)
00318     return 0;
00319 
00320   err = HURD_DPORT_USE (fd, __pfinet_siocgifconf (port, ifc->ifc_len,
00321                                             &data, &data_len));
00322   if (data_len < ifc->ifc_len)
00323     ifc->ifc_len = data_len;
00324   if (data != ifc->ifc_buf)
00325     {
00326       memcpy (ifc->ifc_buf, data, ifc->ifc_len);
00327       __vm_deallocate (__mach_task_self (), (vm_address_t) data, data_len);
00328     }
00329   return err ? __hurd_dfail (fd, err) : 0;
00330 }
00331 _HURD_HANDLE_IOCTL (siocgifconf, SIOCGIFCONF);