]> git.ipfire.org Git - thirdparty/glibc.git/blame - hurd/dtable.c
contrib.texi: update
[thirdparty/glibc.git] / hurd / dtable.c
CommitLineData
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
30struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */
31struct hurd_fd **_hurd_dtable;
32int _hurd_dtablesize;
33
34
35DEFINE_HOOK (_hurd_fd_subinit, (void));
36
37/* Initialize the file descriptor table at startup. */
38
ae49f218 39static void attribute_used_retain
28f540f4
RM
40init_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 129SET_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
136static file_t
137get_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
170file_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. */
177static error_t
178fork_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
212data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */
213text_set_element (_hurd_fork_child_hook, fork_child_dtable);
214\f
215/* Called when our process group has changed. */
216
217static void
218ctty_new_pgrp (void)
219{
220 int i;
8f0c527e 221
c3b287be 222retry:
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
283text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
284\f
285/* Called to reauthenticate the dtable when the auth port changes. */
286
287static void
288reauth_dtable (void)
289{
290 int i;
291
dd858522 292retry:
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
356text_set_element (_hurd_reauth_hook, reauth_dtable);