1 /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
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.
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
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
19 #include <hurd/term.h>
25 #include <lock-intern.h> /* For `struct mutex'. */
26 #include "set-hooks.h"
27 #include "hurdmalloc.h" /* XXX */
30 struct mutex _hurd_dtable_lock
= MUTEX_INITIALIZER
; /* XXX ld bug; must init */
31 struct hurd_fd
**_hurd_dtable
;
35 DEFINE_HOOK (_hurd_fd_subinit
, (void));
37 /* Initialize the file descriptor table at startup. */
39 static void attribute_used_retain
44 __mutex_init (&_hurd_dtable_lock
);
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
;
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");
55 /* Initialize the descriptor table. */
56 for (i
= 0; (unsigned int) i
< _hurd_init_dtablesize
; ++i
)
58 if (_hurd_init_dtable
[i
] == MACH_PORT_NULL
)
59 /* An unused descriptor is marked by a null pointer. */
60 _hurd_dtable
[i
] = NULL
;
64 /* Allocate a new file descriptor structure. */
65 struct hurd_fd
*new = malloc (sizeof (struct hurd_fd
));
67 __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
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
75 if (i
> 0 && _hurd_init_dtable
[i
] == _hurd_init_dtable
[i
- 1])
77 else if (i
> 0 && _hurd_init_dtable
[i
] == _hurd_init_dtable
[0])
84 /* Initialize the port cells. */
85 _hurd_port_init (&new->port
, MACH_PORT_NULL
);
86 _hurd_port_init (&new->ctty
, MACH_PORT_NULL
);
88 /* Install the port in the descriptor.
89 This sets up all the ctty magic. */
90 _hurd_port2fd (new, _hurd_init_dtable
[i
], 0);
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
98 mach_port_t ctty
= _hurd_dtable
[copy
]->ctty
.port
;
100 if (MACH_PORT_VALID (ctty
))
101 __mach_port_mod_refs (__mach_task_self (), ctty
,
102 MACH_PORT_RIGHT_SEND
, +1);
104 _hurd_port_init (&new->port
, _hurd_init_dtable
[i
]);
105 _hurd_port_init (&new->ctty
, ctty
);
108 _hurd_dtable
[i
] = new;
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;
120 /* Initialize the remaining empty slots in the table. */
121 for (; i
< _hurd_dtablesize
; ++i
)
122 _hurd_dtable
[i
] = NULL
;
124 /* Run things that want to run after the file descriptor table
126 RUN_RELHOOK (_hurd_fd_subinit
, ());
129 SET_RELHOOK (_hurd_subinit
, init_dtable
);
131 /* XXX when the linker supports it, the following functions should all be
132 elsewhere and just have text_set_elements here. */
134 /* Called by `getdport' to do its work. */
137 get_dtable_port (int fd
)
139 struct hurd_fd
*d
= _hurd_fd_get (fd
);
143 return __hurd_fail (EBADF
), MACH_PORT_NULL
;
147 dport
= HURD_PORT_USE (&d
->port
,
151 err
= __mach_port_mod_refs (__mach_task_self (),
153 MACH_PORT_RIGHT_SEND
,
158 outport
= MACH_PORT_NULL
;
170 file_t (*_hurd_getdport_fn
) (int fd
) = get_dtable_port
;
172 #include <hurd/signal.h>
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. */
178 fork_child_dtable (void)
185 for (i
= 0; !err
&& i
< _hurd_dtablesize
; ++i
)
187 struct hurd_fd
*d
= _hurd_dtable
[i
];
191 /* No other thread is using the send rights in the child task. */
192 d
->port
.users
= d
->ctty
.users
= NULL
;
194 if (d
->ctty
.port
!= MACH_PORT_NULL
)
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
,
202 d
->ctty
.port
= MACH_PORT_NULL
;
205 /* XXX for each fd with a cntlmap, reauth and re-map_cntl. */
209 (void) &fork_child_dtable
; /* Avoid "defined but not used" warning. */
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
);
215 /* Called when our process group has changed. */
224 __mutex_lock (&_hurd_dtable_lock
);
226 if (__USEPORT (CTTYID
, port
== MACH_PORT_NULL
))
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
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. */
240 for (i
= 0; i
< _hurd_dtablesize
; ++i
)
242 struct hurd_fd
*const d
= _hurd_dtable
[i
];
243 struct hurd_userlink ulink
, ctty_ulink
;
247 /* Nothing to do for an unused descriptor cell. */
250 port
= _hurd_port_get (&d
->port
, &ulink
);
251 ctty
= _hurd_port_get (&d
->ctty
, &ctty_ulink
);
253 if (ctty
!= MACH_PORT_NULL
)
255 /* This fd has a ctty-special port. We need a new one, to tell
256 the io server of our different process group. */
259 if ((err
= __term_open_ctty (port
, _hurd_pid
, _hurd_pgrp
, &new)))
263 /* Got a signal while inside an RPC of the critical section, retry again */
264 __mutex_unlock (&_hurd_dtable_lock
);
265 HURD_CRITICAL_UNLOCK
;
268 new = MACH_PORT_NULL
;
270 _hurd_port_set (&d
->ctty
, new);
273 _hurd_port_free (&d
->port
, &ulink
, port
);
274 _hurd_port_free (&d
->ctty
, &ctty_ulink
, ctty
);
277 __mutex_unlock (&_hurd_dtable_lock
);
280 (void) &ctty_new_pgrp
; /* Avoid "defined but not used" warning. */
283 text_set_element (_hurd_pgrp_changed_hook
, ctty_new_pgrp
);
285 /* Called to reauthenticate the dtable when the auth port changes. */
294 __mutex_lock (&_hurd_dtable_lock
);
296 for (i
= 0; i
< _hurd_dtablesize
; ++i
)
298 struct hurd_fd
*const d
= _hurd_dtable
[i
];
299 mach_port_t
new, newctty
, ref
;
303 /* Nothing to do for an unused descriptor cell. */
306 ref
= __mach_reply_port ();
308 /* Take the descriptor cell's lock. */
309 __spin_lock (&d
->port
.lock
);
311 /* Reauthenticate the descriptor's port. */
312 if (d
->port
.port
!= MACH_PORT_NULL
313 && ! (err
= __io_reauthenticate (d
->port
.port
,
314 ref
, MACH_MSG_TYPE_MAKE_SEND
))
315 && ! (err
= __USEPORT (AUTH
, __auth_user_authenticate
317 ref
, MACH_MSG_TYPE_MAKE_SEND
,
320 /* Replace the port in the descriptor cell
321 with the newly reauthenticated port. */
323 if (d
->ctty
.port
!= MACH_PORT_NULL
324 && ! (err
= __io_reauthenticate (d
->ctty
.port
,
325 ref
, MACH_MSG_TYPE_MAKE_SEND
))
326 && ! (err
= __USEPORT (AUTH
, __auth_user_authenticate
328 ref
, MACH_MSG_TYPE_MAKE_SEND
,
330 _hurd_port_set (&d
->ctty
, newctty
);
332 _hurd_port_locked_set (&d
->port
, new);
335 /* Lost. Leave this descriptor cell alone. */
336 __spin_unlock (&d
->port
.lock
);
338 __mach_port_destroy (__mach_task_self (), ref
);
342 /* Got a signal while inside an RPC of the critical section,
344 __mutex_unlock (&_hurd_dtable_lock
);
345 HURD_CRITICAL_UNLOCK
;
350 __mutex_unlock (&_hurd_dtable_lock
);
353 (void) &reauth_dtable
; /* Avoid "defined but not used" warning. */
356 text_set_element (_hurd_reauth_hook
, reauth_dtable
);