Thu Feb 15 13:57:08 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
[platform/upstream/glibc.git] / hurd / hurdioctl.c
1 /* ioctl commands which must be done in the C library.
2 Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #include <hurd.h>
21 #include <hurd/fd.h>
22 #include <sys/ioctl.h>
23 #include <hurd/ioctl.h>
24
25
26
27 /* Symbol set of ioctl handler lists.  If there are user-registered
28    handlers, one of these lists will contain them.  The other lists are
29    handlers built into the library.  */
30 symbol_set_define (_hurd_ioctl_handler_lists)
31
32 /* Look up REQUEST in the set of handlers.  */
33 ioctl_handler_t
34 _hurd_lookup_ioctl_handler (int request)
35 {
36   void *const *ptr;
37   const struct ioctl_handler *h;
38
39   /* Mask off the type bits, so that we see requests in a single group as a
40      contiguous block of values.  */
41   request = _IOC_NOTYPE (request);
42
43   for (ptr = symbol_set_first_element (_hurd_ioctl_handler_lists);
44        !symbol_set_end_p (_hurd_ioctl_handler_lists, ptr);
45        ++ptr)
46     for (h = *ptr; h != NULL; h = h->next)
47       if (request >= h->first_request && request <= h->last_request)
48         return h->handler;
49
50   return NULL;
51 }
52 \f
53 #include <fcntl.h>
54
55 /* Find out how many bytes may be read from FD without blocking.  */
56
57 static int
58 fioctl (int fd,
59         int request,
60         int *arg)
61 {
62   error_t err;
63
64   *(volatile int *) arg = *arg;
65
66   switch (request)
67     {
68     default:
69       err = ENOTTY;
70       break;
71
72     case FIONREAD:
73       {
74         mach_msg_type_number_t navail;
75         err = HURD_DPORT_USE (fd, __io_readable (port, &navail));
76         if (!err)
77           *arg = (int) navail;
78       }
79       break;
80
81     case FIONBIO:
82       err = HURD_DPORT_USE (fd, (*arg ?
83                                  __io_set_some_openmodes :
84                                  __io_clear_some_openmodes)
85                             (port, O_NONBLOCK));
86       break;
87
88     case FIOASYNC:
89       err = HURD_DPORT_USE (fd, (*arg ?
90                                  __io_set_some_openmodes :
91                                  __io_clear_some_openmodes)
92                             (port, O_ASYNC));
93       break;
94
95     case FIOSETOWN:
96       err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg));
97       break;
98
99     case FIOGETOWN:
100       err = HURD_DPORT_USE (fd, __io_get_owner (port, arg));
101       break;
102     }
103
104   return err ? __hurd_dfail (fd, err) : 0;
105 }
106
107 _HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD);
108
109
110 static int
111 fioclex (int fd,
112          int request)
113 {
114   int flag;
115
116   switch (request)
117     {
118     default:
119       return __hurd_fail (ENOTTY);
120     case FIOCLEX:
121       flag = FD_CLOEXEC;
122       break;
123     case FIONCLEX:
124       flag = 0;
125       break;
126     }
127
128   return __fcntl (fd, F_SETFD, flag);
129 }
130 _HURD_HANDLE_IOCTL (fioclex, FIOCLEX, FIONCLEX);
131 \f
132 #include <hurd/term.h>
133 #include <hurd/tioctl.h>
134
135 static void
136 rectty_dtable (mach_port_t cttyid)
137 {
138   int i;
139
140   HURD_CRITICAL_BEGIN;
141   __mutex_lock (&_hurd_dtable_lock);
142
143   for (i = 0; i < _hurd_dtablesize; ++i)
144     {
145       struct hurd_fd *const d = _hurd_dtable[i];
146       mach_port_t newctty;
147
148       if (d == NULL)
149         /* Nothing to do for an unused descriptor cell.  */
150         continue;
151
152       if (cttyid == MACH_PORT_NULL)
153         /* We now have no controlling tty at all.  */
154         newctty = MACH_PORT_NULL;
155       else
156         HURD_PORT_USE (&d->port,
157                        ({ mach_port_t id;
158                           /* Get the io object's cttyid port.  */
159                           if (! __term_getctty (port, &id))
160                             {
161                               if (id == cttyid && /* Is it ours?  */
162                                   /* Get the ctty io port.  */
163                                   __term_open_ctty (port,
164                                                     _hurd_pid, _hurd_pgrp,
165                                                     &newctty))
166                                 /* XXX it is our ctty but the call failed? */
167                                 newctty = MACH_PORT_NULL;
168                               __mach_port_deallocate
169                                 (__mach_task_self (), (mach_port_t) id);
170                             }
171                           else
172                             newctty = MACH_PORT_NULL;
173                           0;
174                         }));
175
176       /* Install the new ctty port.  */
177       _hurd_port_set (&d->ctty, newctty);
178     }
179
180   __mutex_unlock (&_hurd_dtable_lock);
181   HURD_CRITICAL_END;
182 }
183
184
185 /* Called when we have received a message saying to use a new ctty ID port.  */
186
187 error_t
188 _hurd_setcttyid (mach_port_t cttyid)
189 {
190   error_t err;
191
192   if (cttyid != MACH_PORT_NULL)
193     {
194       /* Give the new send right a user reference.
195          This is a good way to check that it is valid.  */
196       if (err = __mach_port_mod_refs (__mach_task_self (), cttyid,
197                                       MACH_PORT_RIGHT_SEND, 1))
198         return err;
199     }
200
201   /* Install the port, consuming the reference we just created.  */
202   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid);
203
204   /* Reset all the ctty ports in all the descriptors.  */
205   __USEPORT (CTTYID, (rectty_dtable (cttyid), 0));
206
207   return 0;
208 }
209
210
211 /* Make FD be the controlling terminal.
212    This function is called for `ioctl (fd, TCIOSCTTY)'.  */
213
214 static int
215 tiocsctty (int fd,
216            int request)         /* Always TIOCSCTTY.  */
217 {
218   mach_port_t cttyid;
219   error_t err;
220
221   /* Get FD's cttyid port, unless it is already ours.  */
222   err = HURD_DPORT_USE (fd, ctty != MACH_PORT_NULL ? EADDRINUSE :
223                         __term_getctty (port, &cttyid));
224   if (err == EADDRINUSE)
225     /* FD is already the ctty.  Nothing to do.  */
226     return 0;
227   else if (err)
228     return __hurd_fail (err);
229
230   /* Change the terminal's pgrp to ours.  */
231   err = HURD_DPORT_USE (fd, __tioctl_tiocspgrp (port, _hurd_pgrp));
232   if (err)
233     return __hurd_fail (err);
234
235   /* Make it our own.  */
236   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid);
237
238   /* Reset all the ctty ports in all the descriptors.  */
239   __USEPORT (CTTYID, (rectty_dtable (cttyid), 0));
240
241   return 0;
242 }
243 _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
244
245 /* Dissociate from the controlling terminal.  */
246
247 static int
248 tiocnotty (int fd,
249            int request)         /* Always TIOCNOTTY.  */
250 {
251   mach_port_t fd_cttyid;
252   error_t err;
253
254   if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid)))
255     return __hurd_fail (err);
256
257   if (__USEPORT (CTTYID, port != fd_cttyid))
258     err = EINVAL;
259
260   __mach_port_deallocate (__mach_task_self (), fd_cttyid);
261
262   if (err)
263     return __hurd_fail (err);
264
265   /* Clear our cttyid port cell.  */
266   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
267
268   /* Reset all the ctty ports in all the descriptors.  */
269
270   __USEPORT (CTTYID, (rectty_dtable (MACH_PORT_NULL), 0));
271
272   return 0;
273 }
274 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);