]>
Commit | Line | Data |
---|---|---|
28f540f4 | 1 | /* ioctl commands which must be done in the C library. |
951ca0c5 | 2 | Copyright (C) 1994,95,96,97,99,2001,2002,2009,2010 |
e87e2f48 | 3 | Free Software Foundation, Inc. |
c84142e8 UD |
4 | This file is part of the GNU C Library. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
c84142e8 UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
c84142e8 | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
28f540f4 RM |
20 | |
21 | #include <hurd.h> | |
22 | #include <hurd/fd.h> | |
23 | #include <sys/ioctl.h> | |
24 | #include <hurd/ioctl.h> | |
f41c998d | 25 | #include <string.h> |
28f540f4 RM |
26 | |
27 | ||
28 | /* Symbol set of ioctl handler lists. If there are user-registered | |
29 | handlers, one of these lists will contain them. The other lists are | |
30 | handlers built into the library. */ | |
31 | symbol_set_define (_hurd_ioctl_handler_lists) | |
32 | ||
33 | /* Look up REQUEST in the set of handlers. */ | |
34 | ioctl_handler_t | |
35 | _hurd_lookup_ioctl_handler (int request) | |
36 | { | |
37 | void *const *ptr; | |
38 | const struct ioctl_handler *h; | |
39 | ||
9e3db9cd RM |
40 | /* Mask off the type bits, so that we see requests in a single group as a |
41 | contiguous block of values. */ | |
42 | request = _IOC_NOTYPE (request); | |
43 | ||
28f540f4 RM |
44 | for (ptr = symbol_set_first_element (_hurd_ioctl_handler_lists); |
45 | !symbol_set_end_p (_hurd_ioctl_handler_lists, ptr); | |
46 | ++ptr) | |
47 | for (h = *ptr; h != NULL; h = h->next) | |
48 | if (request >= h->first_request && request <= h->last_request) | |
49 | return h->handler; | |
50 | ||
51 | return NULL; | |
52 | } | |
53 | \f | |
54 | #include <fcntl.h> | |
55 | ||
56 | /* Find out how many bytes may be read from FD without blocking. */ | |
57 | ||
58 | static int | |
59 | fioctl (int fd, | |
60 | int request, | |
61 | int *arg) | |
62 | { | |
63 | error_t err; | |
64 | ||
65 | *(volatile int *) arg = *arg; | |
66 | ||
67 | switch (request) | |
68 | { | |
69 | default: | |
9e3db9cd | 70 | err = ENOTTY; |
28f540f4 RM |
71 | break; |
72 | ||
73 | case FIONREAD: | |
74 | { | |
75 | mach_msg_type_number_t navail; | |
76 | err = HURD_DPORT_USE (fd, __io_readable (port, &navail)); | |
77 | if (!err) | |
78 | *arg = (int) navail; | |
79 | } | |
80 | break; | |
81 | ||
82 | case FIONBIO: | |
83 | err = HURD_DPORT_USE (fd, (*arg ? | |
84 | __io_set_some_openmodes : | |
85 | __io_clear_some_openmodes) | |
86 | (port, O_NONBLOCK)); | |
87 | break; | |
88 | ||
89 | case FIOASYNC: | |
90 | err = HURD_DPORT_USE (fd, (*arg ? | |
91 | __io_set_some_openmodes : | |
92 | __io_clear_some_openmodes) | |
93 | (port, O_ASYNC)); | |
94 | break; | |
95 | ||
96 | case FIOSETOWN: | |
97 | err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg)); | |
98 | break; | |
99 | ||
100 | case FIOGETOWN: | |
101 | err = HURD_DPORT_USE (fd, __io_get_owner (port, arg)); | |
102 | break; | |
103 | } | |
104 | ||
9e3db9cd | 105 | return err ? __hurd_dfail (fd, err) : 0; |
28f540f4 RM |
106 | } |
107 | ||
108 | _HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD); | |
109 | ||
110 | ||
111 | static int | |
112 | fioclex (int fd, | |
113 | int request) | |
114 | { | |
115 | int flag; | |
116 | ||
117 | switch (request) | |
118 | { | |
119 | default: | |
9e3db9cd | 120 | return __hurd_fail (ENOTTY); |
28f540f4 RM |
121 | case FIOCLEX: |
122 | flag = FD_CLOEXEC; | |
123 | break; | |
124 | case FIONCLEX: | |
125 | flag = 0; | |
126 | break; | |
127 | } | |
128 | ||
129 | return __fcntl (fd, F_SETFD, flag); | |
130 | } | |
7c97bb09 | 131 | _HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX); |
28f540f4 RM |
132 | \f |
133 | #include <hurd/term.h> | |
56f778c9 | 134 | #include <hurd/tioctl.h> |
28f540f4 | 135 | |
72e1a750 RM |
136 | /* Install a new CTTYID port, atomically updating the dtable appropriately. |
137 | This consumes the send right passed in. */ | |
138 | ||
139 | void | |
140 | _hurd_locked_install_cttyid (mach_port_t cttyid) | |
28f540f4 | 141 | { |
72e1a750 RM |
142 | mach_port_t old; |
143 | struct hurd_port *const port = &_hurd_ports[INIT_PORT_CTTYID]; | |
144 | struct hurd_userlink ulink; | |
28f540f4 | 145 | int i; |
56f778c9 | 146 | |
72e1a750 RM |
147 | /* Install the new cttyid port, and preserve it with a ulink. |
148 | We unroll the _hurd_port_set + _hurd_port_get here so that | |
149 | there is no window where the cell is unlocked and CTTYID could | |
150 | be changed by another thread. (We also delay the deallocation | |
151 | of the old port until the end, to minimize the duration of the | |
152 | critical section.) | |
153 | ||
154 | It is important that changing the cttyid port is only ever done by | |
155 | holding the dtable lock continuously while updating the port cell and | |
156 | re-ctty'ing the dtable; dtable.c assumes we do this. Otherwise, the | |
157 | pgrp-change notification code in dtable.c has to worry about racing | |
158 | against us here in odd situations. The one exception to this is | |
159 | setsid, which holds the dtable lock while changing the pgrp and | |
160 | clearing the cttyid port, and then unlocks the dtable lock to allow | |
161 | ||
162 | ||
163 | */ | |
164 | ||
165 | __spin_lock (&port->lock); | |
166 | old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL; | |
167 | port->port = cttyid; | |
168 | cttyid = _hurd_port_locked_get (port, &ulink); | |
28f540f4 RM |
169 | |
170 | for (i = 0; i < _hurd_dtablesize; ++i) | |
171 | { | |
172 | struct hurd_fd *const d = _hurd_dtable[i]; | |
e87e2f48 | 173 | mach_port_t newctty = MACH_PORT_NULL; |
28f540f4 RM |
174 | |
175 | if (d == NULL) | |
176 | /* Nothing to do for an unused descriptor cell. */ | |
177 | continue; | |
178 | ||
e87e2f48 ST |
179 | if (cttyid != MACH_PORT_NULL) |
180 | /* We do have some controlling tty. */ | |
28f540f4 RM |
181 | HURD_PORT_USE (&d->port, |
182 | ({ mach_port_t id; | |
183 | /* Get the io object's cttyid port. */ | |
184 | if (! __term_getctty (port, &id)) | |
185 | { | |
e87e2f48 | 186 | if (id == cttyid /* Is it ours? */ |
28f540f4 | 187 | /* Get the ctty io port. */ |
e87e2f48 ST |
188 | && __term_open_ctty (port, |
189 | _hurd_pid, _hurd_pgrp, | |
190 | &newctty)) | |
28f540f4 RM |
191 | /* XXX it is our ctty but the call failed? */ |
192 | newctty = MACH_PORT_NULL; | |
e87e2f48 | 193 | __mach_port_deallocate (__mach_task_self (), id); |
28f540f4 | 194 | } |
28f540f4 RM |
195 | 0; |
196 | })); | |
197 | ||
198 | /* Install the new ctty port. */ | |
199 | _hurd_port_set (&d->ctty, newctty); | |
200 | } | |
201 | ||
202 | __mutex_unlock (&_hurd_dtable_lock); | |
72e1a750 RM |
203 | |
204 | if (old != MACH_PORT_NULL) | |
205 | __mach_port_deallocate (__mach_task_self (), old); | |
206 | _hurd_port_free (port, &ulink, cttyid); | |
207 | } | |
208 | ||
209 | static void | |
210 | install_ctty (mach_port_t cttyid) | |
211 | { | |
212 | HURD_CRITICAL_BEGIN; | |
213 | __mutex_lock (&_hurd_dtable_lock); | |
214 | _hurd_locked_install_cttyid (cttyid); | |
28f540f4 RM |
215 | HURD_CRITICAL_END; |
216 | } | |
217 | ||
218 | ||
219 | /* Called when we have received a message saying to use a new ctty ID port. */ | |
220 | ||
221 | error_t | |
222 | _hurd_setcttyid (mach_port_t cttyid) | |
223 | { | |
224 | error_t err; | |
225 | ||
226 | if (cttyid != MACH_PORT_NULL) | |
227 | { | |
228 | /* Give the new send right a user reference. | |
229 | This is a good way to check that it is valid. */ | |
230 | if (err = __mach_port_mod_refs (__mach_task_self (), cttyid, | |
231 | MACH_PORT_RIGHT_SEND, 1)) | |
232 | return err; | |
233 | } | |
234 | ||
235 | /* Install the port, consuming the reference we just created. */ | |
72e1a750 | 236 | install_ctty (cttyid); |
28f540f4 RM |
237 | |
238 | return 0; | |
239 | } | |
240 | ||
241 | ||
951ca0c5 CFH |
242 | static inline error_t |
243 | do_tiocsctty (io_t port, io_t ctty) | |
28f540f4 RM |
244 | { |
245 | mach_port_t cttyid; | |
246 | error_t err; | |
247 | ||
951ca0c5 CFH |
248 | if (ctty != MACH_PORT_NULL) |
249 | /* PORT is already the ctty. Nothing to do. */ | |
28f540f4 | 250 | return 0; |
951ca0c5 CFH |
251 | |
252 | /* Get PORT's cttyid port. */ | |
253 | err = __term_getctty (port, &cttyid); | |
254 | if (err) | |
255 | return err; | |
28f540f4 | 256 | |
56f778c9 | 257 | /* Change the terminal's pgrp to ours. */ |
951ca0c5 | 258 | err = __tioctl_tiocspgrp (port, _hurd_pgrp); |
56f778c9 | 259 | if (err) |
951ca0c5 CFH |
260 | __mach_port_deallocate (__mach_task_self (), cttyid); |
261 | else | |
262 | /* Make it our own. */ | |
263 | install_ctty (cttyid); | |
56f778c9 | 264 | |
951ca0c5 CFH |
265 | return err; |
266 | } | |
28f540f4 | 267 | |
951ca0c5 CFH |
268 | /* Make FD be the controlling terminal. |
269 | This function is called for `ioctl (fd, TCIOSCTTY)'. */ | |
270 | ||
271 | static int | |
272 | tiocsctty (int fd, | |
273 | int request) /* Always TIOCSCTTY. */ | |
274 | { | |
199428c1 | 275 | return __hurd_fail (HURD_DPORT_USE (fd, do_tiocsctty (port, ctty))); |
28f540f4 RM |
276 | } |
277 | _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY); | |
278 | ||
279 | /* Dissociate from the controlling terminal. */ | |
280 | ||
281 | static int | |
282 | tiocnotty (int fd, | |
283 | int request) /* Always TIOCNOTTY. */ | |
284 | { | |
285 | mach_port_t fd_cttyid; | |
286 | error_t err; | |
287 | ||
288 | if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid))) | |
289 | return __hurd_fail (err); | |
290 | ||
291 | if (__USEPORT (CTTYID, port != fd_cttyid)) | |
292 | err = EINVAL; | |
293 | ||
294 | __mach_port_deallocate (__mach_task_self (), fd_cttyid); | |
295 | ||
296 | if (err) | |
297 | return __hurd_fail (err); | |
298 | ||
72e1a750 RM |
299 | /* Clear our cttyid port. */ |
300 | install_ctty (MACH_PORT_NULL); | |
28f540f4 RM |
301 | |
302 | return 0; | |
303 | } | |
304 | _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY); | |
7facfddd MK |
305 | \f |
306 | #include <hurd/pfinet.h> | |
307 | #include <net/if.h> | |
308 | #include <netinet/in.h> | |
309 | ||
310 | /* Fill in the buffer IFC->IFC_BUF of length IFC->IFC_LEN with a list | |
311 | of ifr structures, one for each network interface. */ | |
312 | static int | |
313 | siocgifconf (int fd, int request, struct ifconf *ifc) | |
314 | { | |
315 | error_t err; | |
b62b62ac | 316 | size_t data_len = ifc->ifc_len; |
7facfddd MK |
317 | char *data = ifc->ifc_buf; |
318 | ||
319 | if (data_len <= 0) | |
320 | return 0; | |
321 | ||
322 | err = HURD_DPORT_USE (fd, __pfinet_siocgifconf (port, ifc->ifc_len, | |
323 | &data, &data_len)); | |
324 | if (data_len < ifc->ifc_len) | |
325 | ifc->ifc_len = data_len; | |
326 | if (data != ifc->ifc_buf) | |
327 | { | |
328 | memcpy (ifc->ifc_buf, data, ifc->ifc_len); | |
329 | __vm_deallocate (__mach_task_self (), (vm_address_t) data, data_len); | |
330 | } | |
331 | return err ? __hurd_dfail (fd, err) : 0; | |
332 | } | |
333 | _HURD_HANDLE_IOCTL (siocgifconf, SIOCGIFCONF); |