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