]>
Commit | Line | Data |
---|---|---|
dff8da6b | 1 | /* Copyright (C) 1991-2024 Free Software Foundation, Inc. |
c84142e8 UD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
c84142e8 UD |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
c84142e8 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 15 | License along with the GNU C Library; if not, see |
5a82c748 | 16 | <https://www.gnu.org/licenses/>. */ |
28f540f4 | 17 | |
28f540f4 RM |
18 | #include <hurd.h> |
19 | #include <hurd/term.h> | |
20 | #include <hurd/fd.h> | |
21 | #include <stdlib.h> | |
22 | #include <stdio.h> | |
23 | #include <fcntl.h> | |
24 | #include <limits.h> | |
9446e02b | 25 | #include <lock-intern.h> /* For `struct mutex'. */ |
28f540f4 RM |
26 | #include "set-hooks.h" |
27 | #include "hurdmalloc.h" /* XXX */ | |
28 | ||
29 | ||
30 | struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */ | |
31 | struct hurd_fd **_hurd_dtable; | |
32 | int _hurd_dtablesize; | |
33 | ||
34 | ||
35 | DEFINE_HOOK (_hurd_fd_subinit, (void)); | |
36 | ||
37 | /* Initialize the file descriptor table at startup. */ | |
38 | ||
ae49f218 | 39 | static void attribute_used_retain |
28f540f4 RM |
40 | init_dtable (void) |
41 | { | |
1e9dc039 | 42 | int i; |
28f540f4 RM |
43 | |
44 | __mutex_init (&_hurd_dtable_lock); | |
45 | ||
46 | /* The initial size of the descriptor table is that of the passed-in | |
47 | table. It will be expanded as necessary up to _hurd_dtable_rlimit. */ | |
48 | _hurd_dtablesize = _hurd_init_dtablesize; | |
49 | ||
50 | /* Allocate the vector of pointers. */ | |
51 | _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable)); | |
52 | if (_hurd_dtablesize != 0 && _hurd_dtable == NULL) | |
53 | __libc_fatal ("hurd: Can't allocate file descriptor table\n"); | |
54 | ||
55 | /* Initialize the descriptor table. */ | |
1e9dc039 | 56 | for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i) |
28f540f4 RM |
57 | { |
58 | if (_hurd_init_dtable[i] == MACH_PORT_NULL) | |
59 | /* An unused descriptor is marked by a null pointer. */ | |
60 | _hurd_dtable[i] = NULL; | |
61 | else | |
62 | { | |
e55a55ac | 63 | int copy; |
28f540f4 RM |
64 | /* Allocate a new file descriptor structure. */ |
65 | struct hurd_fd *new = malloc (sizeof (struct hurd_fd)); | |
66 | if (new == NULL) | |
67 | __libc_fatal ("hurd: Can't allocate initial file descriptors\n"); | |
68 | ||
e55a55ac SB |
69 | /* See if this file descriptor is the same as a previous one we have |
70 | already installed. In this case, we can just copy over the same | |
71 | ctty port without making any more RPCs. We only check the the | |
72 | immediately preceding fd and fd 0 -- this should be enough to | |
73 | handle the common cases while not requiring quadratic | |
74 | complexity. */ | |
75 | if (i > 0 && _hurd_init_dtable[i] == _hurd_init_dtable[i - 1]) | |
76 | copy = i - 1; | |
77 | else if (i > 0 && _hurd_init_dtable[i] == _hurd_init_dtable[0]) | |
78 | copy = 0; | |
79 | else | |
80 | copy = -1; | |
81 | ||
82 | if (copy < 0) | |
83 | { | |
84 | /* Initialize the port cells. */ | |
85 | _hurd_port_init (&new->port, MACH_PORT_NULL); | |
86 | _hurd_port_init (&new->ctty, MACH_PORT_NULL); | |
87 | ||
88 | /* Install the port in the descriptor. | |
89 | This sets up all the ctty magic. */ | |
90 | _hurd_port2fd (new, _hurd_init_dtable[i], 0); | |
91 | } | |
92 | else | |
93 | { | |
94 | /* Copy over ctty from the already set up file descriptor that | |
95 | contains the same port. We can access the contents of the | |
96 | cell without any locking since no one could have seen it | |
97 | yet. */ | |
98 | mach_port_t ctty = _hurd_dtable[copy]->ctty.port; | |
99 | ||
100 | if (MACH_PORT_VALID (ctty)) | |
101 | __mach_port_mod_refs (__mach_task_self (), ctty, | |
102 | MACH_PORT_RIGHT_SEND, +1); | |
103 | ||
104 | _hurd_port_init (&new->port, _hurd_init_dtable[i]); | |
105 | _hurd_port_init (&new->ctty, ctty); | |
106 | } | |
28f540f4 RM |
107 | |
108 | _hurd_dtable[i] = new; | |
109 | } | |
110 | } | |
111 | ||
112 | /* Clear out the initial descriptor table. | |
113 | Everything must use _hurd_dtable now. */ | |
114 | __vm_deallocate (__mach_task_self (), | |
115 | (vm_address_t) _hurd_init_dtable, | |
116 | _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0])); | |
117 | _hurd_init_dtable = NULL; | |
118 | _hurd_init_dtablesize = 0; | |
119 | ||
120 | /* Initialize the remaining empty slots in the table. */ | |
121 | for (; i < _hurd_dtablesize; ++i) | |
122 | _hurd_dtable[i] = NULL; | |
123 | ||
124 | /* Run things that want to run after the file descriptor table | |
125 | is initialized. */ | |
ae49f218 | 126 | RUN_RELHOOK (_hurd_fd_subinit, ()); |
28f540f4 RM |
127 | } |
128 | ||
ae49f218 | 129 | SET_RELHOOK (_hurd_subinit, init_dtable); |
28f540f4 RM |
130 | |
131 | /* XXX when the linker supports it, the following functions should all be | |
132 | elsewhere and just have text_set_elements here. */ | |
133 | \f | |
134 | /* Called by `getdport' to do its work. */ | |
135 | ||
136 | static file_t | |
137 | get_dtable_port (int fd) | |
138 | { | |
72e1a750 | 139 | struct hurd_fd *d = _hurd_fd_get (fd); |
28f540f4 | 140 | file_t dport; |
72e1a750 RM |
141 | |
142 | if (!d) | |
143 | return __hurd_fail (EBADF), MACH_PORT_NULL; | |
144 | ||
145 | HURD_CRITICAL_BEGIN; | |
146 | ||
147 | dport = HURD_PORT_USE (&d->port, | |
148 | ({ | |
149 | error_t err; | |
150 | mach_port_t outport; | |
151 | err = __mach_port_mod_refs (__mach_task_self (), | |
152 | port, | |
153 | MACH_PORT_RIGHT_SEND, | |
154 | 1); | |
155 | if (err) | |
156 | { | |
157 | errno = err; | |
158 | outport = MACH_PORT_NULL; | |
159 | } | |
160 | else | |
161 | outport = port; | |
162 | outport; | |
163 | })); | |
164 | ||
165 | HURD_CRITICAL_END; | |
166 | ||
167 | return dport; | |
28f540f4 RM |
168 | } |
169 | ||
170 | file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port; | |
171 | \f | |
172 | #include <hurd/signal.h> | |
173 | ||
174 | /* We are in the child fork; the dtable lock is still held. | |
175 | The parent has inserted send rights for all the normal io ports, | |
176 | but we must recover ctty-special ports for ourselves. */ | |
177 | static error_t | |
178 | fork_child_dtable (void) | |
179 | { | |
180 | error_t err; | |
181 | int i; | |
182 | ||
183 | err = 0; | |
184 | ||
185 | for (i = 0; !err && i < _hurd_dtablesize; ++i) | |
186 | { | |
187 | struct hurd_fd *d = _hurd_dtable[i]; | |
188 | if (d == NULL) | |
189 | continue; | |
190 | ||
191 | /* No other thread is using the send rights in the child task. */ | |
192 | d->port.users = d->ctty.users = NULL; | |
193 | ||
194 | if (d->ctty.port != MACH_PORT_NULL) | |
195 | { | |
196 | /* There was a ctty-special port in the parent. | |
197 | We need to get one for ourselves too. */ | |
198 | __mach_port_deallocate (__mach_task_self (), d->ctty.port); | |
199 | err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp, | |
200 | &d->ctty.port); | |
201 | if (err) | |
202 | d->ctty.port = MACH_PORT_NULL; | |
203 | } | |
204 | ||
205 | /* XXX for each fd with a cntlmap, reauth and re-map_cntl. */ | |
206 | } | |
207 | return err; | |
208 | ||
209 | (void) &fork_child_dtable; /* Avoid "defined but not used" warning. */ | |
210 | } | |
211 | ||
212 | data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */ | |
213 | text_set_element (_hurd_fork_child_hook, fork_child_dtable); | |
214 | \f | |
215 | /* Called when our process group has changed. */ | |
216 | ||
217 | static void | |
218 | ctty_new_pgrp (void) | |
219 | { | |
220 | int i; | |
8f0c527e | 221 | |
c3b287be | 222 | retry: |
28f540f4 RM |
223 | HURD_CRITICAL_BEGIN; |
224 | __mutex_lock (&_hurd_dtable_lock); | |
225 | ||
72e1a750 | 226 | if (__USEPORT (CTTYID, port == MACH_PORT_NULL)) |
28f540f4 | 227 | { |
72e1a750 RM |
228 | /* We have no controlling terminal. If we haven't had one recently, |
229 | but our pgrp is being pointlessly diddled anyway, then we will | |
230 | have nothing to do in the loop below because no fd will have a | |
231 | ctty port at all. | |
232 | ||
233 | More likely, a setsid call is responsible both for the change | |
234 | in pgrp and for clearing the cttyid port. In that case, setsid | |
235 | held the dtable lock while updating the dtable to clear all the | |
236 | ctty ports, and ergo must have finished doing so before we run here. | |
237 | So we can be sure, again, that the loop below has no work to do. */ | |
28f540f4 | 238 | } |
72e1a750 RM |
239 | else |
240 | for (i = 0; i < _hurd_dtablesize; ++i) | |
241 | { | |
242 | struct hurd_fd *const d = _hurd_dtable[i]; | |
243 | struct hurd_userlink ulink, ctty_ulink; | |
244 | io_t port, ctty; | |
245 | ||
246 | if (d == NULL) | |
247 | /* Nothing to do for an unused descriptor cell. */ | |
248 | continue; | |
249 | ||
250 | port = _hurd_port_get (&d->port, &ulink); | |
251 | ctty = _hurd_port_get (&d->ctty, &ctty_ulink); | |
252 | ||
253 | if (ctty != MACH_PORT_NULL) | |
254 | { | |
255 | /* This fd has a ctty-special port. We need a new one, to tell | |
256 | the io server of our different process group. */ | |
257 | io_t new; | |
c3b287be ST |
258 | error_t err; |
259 | if ((err = __term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))) | |
260 | { | |
261 | if (err == EINTR) | |
262 | { | |
263 | /* Got a signal while inside an RPC of the critical section, retry again */ | |
264 | __mutex_unlock (&_hurd_dtable_lock); | |
265 | HURD_CRITICAL_UNLOCK; | |
266 | goto retry; | |
267 | } | |
268 | new = MACH_PORT_NULL; | |
269 | } | |
72e1a750 RM |
270 | _hurd_port_set (&d->ctty, new); |
271 | } | |
272 | ||
273 | _hurd_port_free (&d->port, &ulink, port); | |
274 | _hurd_port_free (&d->ctty, &ctty_ulink, ctty); | |
275 | } | |
28f540f4 RM |
276 | |
277 | __mutex_unlock (&_hurd_dtable_lock); | |
278 | HURD_CRITICAL_END; | |
279 | ||
280 | (void) &ctty_new_pgrp; /* Avoid "defined but not used" warning. */ | |
281 | } | |
282 | ||
283 | text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp); | |
284 | \f | |
285 | /* Called to reauthenticate the dtable when the auth port changes. */ | |
286 | ||
287 | static void | |
288 | reauth_dtable (void) | |
289 | { | |
290 | int i; | |
291 | ||
dd858522 | 292 | retry: |
28f540f4 RM |
293 | HURD_CRITICAL_BEGIN; |
294 | __mutex_lock (&_hurd_dtable_lock); | |
295 | ||
296 | for (i = 0; i < _hurd_dtablesize; ++i) | |
297 | { | |
298 | struct hurd_fd *const d = _hurd_dtable[i]; | |
299 | mach_port_t new, newctty, ref; | |
dd858522 | 300 | error_t err = 0; |
8f0c527e | 301 | |
28f540f4 RM |
302 | if (d == NULL) |
303 | /* Nothing to do for an unused descriptor cell. */ | |
304 | continue; | |
305 | ||
306 | ref = __mach_reply_port (); | |
307 | ||
308 | /* Take the descriptor cell's lock. */ | |
309 | __spin_lock (&d->port.lock); | |
8f0c527e | 310 | |
28f540f4 | 311 | /* Reauthenticate the descriptor's port. */ |
34a5a146 | 312 | if (d->port.port != MACH_PORT_NULL |
dd858522 ST |
313 | && ! (err = __io_reauthenticate (d->port.port, |
314 | ref, MACH_MSG_TYPE_MAKE_SEND)) | |
315 | && ! (err = __USEPORT (AUTH, __auth_user_authenticate | |
316 | (port, | |
317 | ref, MACH_MSG_TYPE_MAKE_SEND, | |
318 | &new)))) | |
28f540f4 RM |
319 | { |
320 | /* Replace the port in the descriptor cell | |
321 | with the newly reauthenticated port. */ | |
322 | ||
34a5a146 | 323 | if (d->ctty.port != MACH_PORT_NULL |
dd858522 ST |
324 | && ! (err = __io_reauthenticate (d->ctty.port, |
325 | ref, MACH_MSG_TYPE_MAKE_SEND)) | |
326 | && ! (err = __USEPORT (AUTH, __auth_user_authenticate | |
327 | (port, | |
328 | ref, MACH_MSG_TYPE_MAKE_SEND, | |
329 | &newctty)))) | |
28f540f4 RM |
330 | _hurd_port_set (&d->ctty, newctty); |
331 | ||
332 | _hurd_port_locked_set (&d->port, new); | |
333 | } | |
334 | else | |
335 | /* Lost. Leave this descriptor cell alone. */ | |
336 | __spin_unlock (&d->port.lock); | |
337 | ||
338 | __mach_port_destroy (__mach_task_self (), ref); | |
dd858522 ST |
339 | |
340 | if (err == EINTR) | |
341 | { | |
342 | /* Got a signal while inside an RPC of the critical section, | |
343 | retry again */ | |
344 | __mutex_unlock (&_hurd_dtable_lock); | |
345 | HURD_CRITICAL_UNLOCK; | |
346 | goto retry; | |
347 | } | |
28f540f4 RM |
348 | } |
349 | ||
350 | __mutex_unlock (&_hurd_dtable_lock); | |
351 | HURD_CRITICAL_END; | |
352 | ||
353 | (void) &reauth_dtable; /* Avoid "defined but not used" warning. */ | |
354 | } | |
355 | ||
356 | text_set_element (_hurd_reauth_hook, reauth_dtable); |