]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 1991-2014 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 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://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> | |
25 | #include <cthreads.h> /* For `struct mutex'. */ | |
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 | ||
39 | static void | |
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 | { | |
63 | /* Allocate a new file descriptor structure. */ | |
64 | struct hurd_fd *new = malloc (sizeof (struct hurd_fd)); | |
65 | if (new == NULL) | |
66 | __libc_fatal ("hurd: Can't allocate initial file descriptors\n"); | |
67 | ||
68 | /* Initialize the port cells. */ | |
69 | _hurd_port_init (&new->port, MACH_PORT_NULL); | |
70 | _hurd_port_init (&new->ctty, MACH_PORT_NULL); | |
71 | ||
72 | /* Install the port in the descriptor. | |
73 | This sets up all the ctty magic. */ | |
74 | _hurd_port2fd (new, _hurd_init_dtable[i], 0); | |
75 | ||
76 | _hurd_dtable[i] = new; | |
77 | } | |
78 | } | |
79 | ||
80 | /* Clear out the initial descriptor table. | |
81 | Everything must use _hurd_dtable now. */ | |
82 | __vm_deallocate (__mach_task_self (), | |
83 | (vm_address_t) _hurd_init_dtable, | |
84 | _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0])); | |
85 | _hurd_init_dtable = NULL; | |
86 | _hurd_init_dtablesize = 0; | |
87 | ||
88 | /* Initialize the remaining empty slots in the table. */ | |
89 | for (; i < _hurd_dtablesize; ++i) | |
90 | _hurd_dtable[i] = NULL; | |
91 | ||
92 | /* Run things that want to run after the file descriptor table | |
93 | is initialized. */ | |
94 | RUN_HOOK (_hurd_fd_subinit, ()); | |
95 | ||
96 | (void) &init_dtable; /* Avoid "defined but not used" warning. */ | |
97 | } | |
98 | ||
99 | text_set_element (_hurd_subinit, init_dtable); | |
100 | ||
101 | /* XXX when the linker supports it, the following functions should all be | |
102 | elsewhere and just have text_set_elements here. */ | |
103 | \f | |
104 | /* Called by `getdport' to do its work. */ | |
105 | ||
106 | static file_t | |
107 | get_dtable_port (int fd) | |
108 | { | |
72e1a750 | 109 | struct hurd_fd *d = _hurd_fd_get (fd); |
28f540f4 | 110 | file_t dport; |
72e1a750 RM |
111 | |
112 | if (!d) | |
113 | return __hurd_fail (EBADF), MACH_PORT_NULL; | |
114 | ||
115 | HURD_CRITICAL_BEGIN; | |
116 | ||
117 | dport = HURD_PORT_USE (&d->port, | |
118 | ({ | |
119 | error_t err; | |
120 | mach_port_t outport; | |
121 | err = __mach_port_mod_refs (__mach_task_self (), | |
122 | port, | |
123 | MACH_PORT_RIGHT_SEND, | |
124 | 1); | |
125 | if (err) | |
126 | { | |
127 | errno = err; | |
128 | outport = MACH_PORT_NULL; | |
129 | } | |
130 | else | |
131 | outport = port; | |
132 | outport; | |
133 | })); | |
134 | ||
135 | HURD_CRITICAL_END; | |
136 | ||
137 | return dport; | |
28f540f4 RM |
138 | } |
139 | ||
140 | file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port; | |
141 | \f | |
142 | #include <hurd/signal.h> | |
143 | ||
144 | /* We are in the child fork; the dtable lock is still held. | |
145 | The parent has inserted send rights for all the normal io ports, | |
146 | but we must recover ctty-special ports for ourselves. */ | |
147 | static error_t | |
148 | fork_child_dtable (void) | |
149 | { | |
150 | error_t err; | |
151 | int i; | |
152 | ||
153 | err = 0; | |
154 | ||
155 | for (i = 0; !err && i < _hurd_dtablesize; ++i) | |
156 | { | |
157 | struct hurd_fd *d = _hurd_dtable[i]; | |
158 | if (d == NULL) | |
159 | continue; | |
160 | ||
161 | /* No other thread is using the send rights in the child task. */ | |
162 | d->port.users = d->ctty.users = NULL; | |
163 | ||
164 | if (d->ctty.port != MACH_PORT_NULL) | |
165 | { | |
166 | /* There was a ctty-special port in the parent. | |
167 | We need to get one for ourselves too. */ | |
168 | __mach_port_deallocate (__mach_task_self (), d->ctty.port); | |
169 | err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp, | |
170 | &d->ctty.port); | |
171 | if (err) | |
172 | d->ctty.port = MACH_PORT_NULL; | |
173 | } | |
174 | ||
175 | /* XXX for each fd with a cntlmap, reauth and re-map_cntl. */ | |
176 | } | |
177 | return err; | |
178 | ||
179 | (void) &fork_child_dtable; /* Avoid "defined but not used" warning. */ | |
180 | } | |
181 | ||
182 | data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */ | |
183 | text_set_element (_hurd_fork_child_hook, fork_child_dtable); | |
184 | \f | |
185 | /* Called when our process group has changed. */ | |
186 | ||
187 | static void | |
188 | ctty_new_pgrp (void) | |
189 | { | |
190 | int i; | |
8f0c527e | 191 | |
28f540f4 RM |
192 | HURD_CRITICAL_BEGIN; |
193 | __mutex_lock (&_hurd_dtable_lock); | |
194 | ||
72e1a750 | 195 | if (__USEPORT (CTTYID, port == MACH_PORT_NULL)) |
28f540f4 | 196 | { |
72e1a750 RM |
197 | /* We have no controlling terminal. If we haven't had one recently, |
198 | but our pgrp is being pointlessly diddled anyway, then we will | |
199 | have nothing to do in the loop below because no fd will have a | |
200 | ctty port at all. | |
201 | ||
202 | More likely, a setsid call is responsible both for the change | |
203 | in pgrp and for clearing the cttyid port. In that case, setsid | |
204 | held the dtable lock while updating the dtable to clear all the | |
205 | ctty ports, and ergo must have finished doing so before we run here. | |
206 | So we can be sure, again, that the loop below has no work to do. */ | |
28f540f4 | 207 | } |
72e1a750 RM |
208 | else |
209 | for (i = 0; i < _hurd_dtablesize; ++i) | |
210 | { | |
211 | struct hurd_fd *const d = _hurd_dtable[i]; | |
212 | struct hurd_userlink ulink, ctty_ulink; | |
213 | io_t port, ctty; | |
214 | ||
215 | if (d == NULL) | |
216 | /* Nothing to do for an unused descriptor cell. */ | |
217 | continue; | |
218 | ||
219 | port = _hurd_port_get (&d->port, &ulink); | |
220 | ctty = _hurd_port_get (&d->ctty, &ctty_ulink); | |
221 | ||
222 | if (ctty != MACH_PORT_NULL) | |
223 | { | |
224 | /* This fd has a ctty-special port. We need a new one, to tell | |
225 | the io server of our different process group. */ | |
226 | io_t new; | |
227 | if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new)) | |
228 | new = MACH_PORT_NULL; | |
229 | _hurd_port_set (&d->ctty, new); | |
230 | } | |
231 | ||
232 | _hurd_port_free (&d->port, &ulink, port); | |
233 | _hurd_port_free (&d->ctty, &ctty_ulink, ctty); | |
234 | } | |
28f540f4 RM |
235 | |
236 | __mutex_unlock (&_hurd_dtable_lock); | |
237 | HURD_CRITICAL_END; | |
238 | ||
239 | (void) &ctty_new_pgrp; /* Avoid "defined but not used" warning. */ | |
240 | } | |
241 | ||
242 | text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp); | |
243 | \f | |
244 | /* Called to reauthenticate the dtable when the auth port changes. */ | |
245 | ||
246 | static void | |
247 | reauth_dtable (void) | |
248 | { | |
249 | int i; | |
250 | ||
251 | HURD_CRITICAL_BEGIN; | |
252 | __mutex_lock (&_hurd_dtable_lock); | |
253 | ||
254 | for (i = 0; i < _hurd_dtablesize; ++i) | |
255 | { | |
256 | struct hurd_fd *const d = _hurd_dtable[i]; | |
257 | mach_port_t new, newctty, ref; | |
8f0c527e | 258 | |
28f540f4 RM |
259 | if (d == NULL) |
260 | /* Nothing to do for an unused descriptor cell. */ | |
261 | continue; | |
262 | ||
263 | ref = __mach_reply_port (); | |
264 | ||
265 | /* Take the descriptor cell's lock. */ | |
266 | __spin_lock (&d->port.lock); | |
8f0c527e | 267 | |
28f540f4 RM |
268 | /* Reauthenticate the descriptor's port. */ |
269 | if (d->port.port != MACH_PORT_NULL && | |
270 | ! __io_reauthenticate (d->port.port, | |
271 | ref, MACH_MSG_TYPE_MAKE_SEND) && | |
272 | ! __USEPORT (AUTH, __auth_user_authenticate | |
273 | (port, | |
28f540f4 RM |
274 | ref, MACH_MSG_TYPE_MAKE_SEND, |
275 | &new))) | |
276 | { | |
277 | /* Replace the port in the descriptor cell | |
278 | with the newly reauthenticated port. */ | |
279 | ||
280 | if (d->ctty.port != MACH_PORT_NULL && | |
281 | ! __io_reauthenticate (d->ctty.port, | |
282 | ref, MACH_MSG_TYPE_MAKE_SEND) && | |
283 | ! __USEPORT (AUTH, __auth_user_authenticate | |
284 | (port, | |
28f540f4 RM |
285 | ref, MACH_MSG_TYPE_MAKE_SEND, |
286 | &newctty))) | |
287 | _hurd_port_set (&d->ctty, newctty); | |
288 | ||
289 | _hurd_port_locked_set (&d->port, new); | |
290 | } | |
291 | else | |
292 | /* Lost. Leave this descriptor cell alone. */ | |
293 | __spin_unlock (&d->port.lock); | |
294 | ||
295 | __mach_port_destroy (__mach_task_self (), ref); | |
296 | } | |
297 | ||
298 | __mutex_unlock (&_hurd_dtable_lock); | |
299 | HURD_CRITICAL_END; | |
300 | ||
301 | (void) &reauth_dtable; /* Avoid "defined but not used" warning. */ | |
302 | } | |
303 | ||
304 | text_set_element (_hurd_reauth_hook, reauth_dtable); |