Formerly ../hurd/dtable.c.~40~
[kopensolaris-gnu/glibc.git] / hurd / dtable.c
1 /* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
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
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
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
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <hurd.h>
21 #include <hurd/term.h>
22 #include <hurd/fd.h>
23 #include <gnu-stabs.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <cthreads.h>           /* For `struct mutex'.  */
29 #include "set-hooks.h"
30 #include "hurdmalloc.h"         /* XXX */
31
32
33 struct mutex _hurd_dtable_lock;
34 struct hurd_fd **_hurd_dtable;
35 int _hurd_dtablesize;
36
37
38 DEFINE_HOOK (_hurd_fd_subinit, (void));
39
40 /* Initialize the file descriptor table at startup.  */
41
42 static void
43 init_dtable (void)
44 {
45   register size_t i;
46
47   __mutex_init (&_hurd_dtable_lock);
48
49   /* The initial size of the descriptor table is that of the passed-in
50      table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
51   _hurd_dtablesize = _hurd_init_dtablesize;
52
53   /* Allocate the vector of pointers.  */
54   _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
55   if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
56     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
57
58   /* Initialize the descriptor table.  */
59   for (i = 0; i < _hurd_init_dtablesize; ++i)
60     {
61       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
62         /* An unused descriptor is marked by a null pointer.  */
63         _hurd_dtable[i] = NULL;
64       else
65         {
66           /* Allocate a new file descriptor structure.  */
67           struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
68           if (new == NULL)
69             __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
70
71           /* Initialize the port cells.  */
72           _hurd_port_init (&new->port, MACH_PORT_NULL);
73           _hurd_port_init (&new->ctty, MACH_PORT_NULL);
74
75           /* Install the port in the descriptor.
76              This sets up all the ctty magic.  */
77           _hurd_port2fd (new, _hurd_init_dtable[i], 0);
78
79           _hurd_dtable[i] = new;
80         }
81     }
82
83   /* Clear out the initial descriptor table.
84      Everything must use _hurd_dtable now.  */
85   __vm_deallocate (__mach_task_self (),
86                    (vm_address_t) _hurd_init_dtable,
87                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
88   _hurd_init_dtable = NULL;
89   _hurd_init_dtablesize = 0;
90
91   /* Initialize the remaining empty slots in the table.  */
92   for (; i < _hurd_dtablesize; ++i)
93     _hurd_dtable[i] = NULL;
94
95   /* Run things that want to run after the file descriptor table
96      is initialized.  */
97   RUN_HOOK (_hurd_fd_subinit, ());
98 }
99
100 text_set_element (_hurd_subinit, init_dtable);
101
102 /* XXX when the linker supports it, the following functions should all be
103    elsewhere and just have text_set_elements here.  */
104 \f
105 /* Called by `getdport' to do its work.  */
106
107 static file_t
108 get_dtable_port (int fd)
109 {
110   file_t dport;
111   int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (),
112                                                       (dport = ctty ?: port),
113                                                       MACH_PORT_RIGHT_SEND,
114                                                       1));
115   if (err)
116     {
117       errno = err;
118       return MACH_PORT_NULL;
119     }
120   else
121     return dport;
122 }
123
124 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
125 \f
126 #include <hurd/signal.h>
127
128 /* Called on fork to install the dtable in NEWTASK.  The dtable lock is
129    held now and was taken before the child was created, copying our memory.
130    Insert send rights for all of the normal io ports for fds, with the same
131    names they have in our task.  We trust that none of the ports in the
132    dtable were be changed while we have been holding the lock, so the port
133    names copied by the child are still valid in our task.  */
134
135 static error_t
136 fork_parent_dtable (task_t newtask)
137 {
138   error_t err;
139   int i;
140
141   err = 0;
142
143   for (i = 0; !err && i < _hurd_dtablesize; ++i)
144     {
145       struct hurd_userlink ulink, ctty_ulink;
146       io_t port = _hurd_port_get (&_hurd_dtable[i]->port, &ulink);
147       io_t ctty = _hurd_port_get (&_hurd_dtable[i]->ctty, &ctty_ulink);
148
149       /* If there is a ctty-special port (it will be in PORT),
150          insert only the normal io port.  The child will get a fresh
151          ctty-special port.  */
152       if (ctty != MACH_PORT_NULL)
153         err = __mach_port_insert_right (newtask, ctty, ctty,
154                                         MACH_MSG_TYPE_COPY_SEND);
155       else if (port != MACH_PORT_NULL)
156         /* There is no ctty-special port; PORT is the normal io port.  */
157         err = __mach_port_insert_right (newtask, port, port,
158                                         MACH_MSG_TYPE_COPY_SEND);
159
160       _hurd_port_free (&_hurd_dtable[i]->port, &ulink, port);
161       _hurd_port_free (&_hurd_dtable[i]->ctty, &ctty_ulink, ctty);
162     }
163   return err;
164 }
165
166 /* We are in the child fork; the dtable lock is still held.
167    The parent has inserted send rights for all the normal io ports,
168    but we must recover ctty-special ports for ourselves.  */
169 static error_t
170 fork_child_dtable (void)
171 {
172   error_t err;
173   int i;
174
175   err = 0;
176
177   for (i = 0; !err && i < _hurd_dtablesize; ++i)
178     {
179       struct hurd_fd *d = _hurd_dtable[i];
180
181       d->port.users = d->ctty.users = NULL;
182
183       if (d->ctty.port)
184         /* There was a ctty-special port in the parent.
185            We need to get one for ourselves too.  */
186           err = __term_become_ctty (d->ctty.port,
187                                     /* XXX no guarantee that init_pids hook
188                                        has been run BEFORE this one! */
189                                     _hurd_pid, _hurd_pgrp, _hurd_msgport,
190                                     &d->port.port);
191
192       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
193     }
194   return err;
195 }
196
197 text_set_element (_hurd_fork_locks, _hurd_dtable_lock);
198 text_set_element (_hurd_fork_setup_hook, fork_parent_dtable);
199 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
200 \f
201 /* Called when our process group has changed.  */
202
203 static void
204 ctty_new_pgrp (void)
205 {
206   int i;
207   
208   HURD_CRITICAL_BEGIN;
209   __mutex_lock (&_hurd_dtable_lock);
210
211   for (i = 0; i < _hurd_dtablesize; ++i)
212     {
213       struct hurd_fd *const d = _hurd_dtable[i];
214       struct hurd_userlink ulink, ctty_ulink;
215       io_t port, ctty;
216
217       if (d == NULL)
218         /* Nothing to do for an unused descriptor cell.  */
219         continue;
220
221       port = _hurd_port_get (&d->port, &ulink);
222       ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
223
224       if (ctty)
225         {
226           /* This fd has a ctty-special port.  We need a new one, to tell
227              the io server of our different process group.  */
228           io_t new;
229           if (! __term_become_ctty (ctty, _hurd_pid, _hurd_pgrp, _hurd_msgport,
230                                     &new))
231             _hurd_port_set (&d->port, new);
232         }
233
234       _hurd_port_free (&d->port, &ulink, port);
235       _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
236     }
237
238   __mutex_unlock (&_hurd_dtable_lock);
239   HURD_CRITICAL_END;
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;
258       
259       if (d == NULL)
260         /* Nothing to do for an unused descriptor cell.  */
261         continue;
262
263       /* Take the descriptor cell's lock.  */
264       __spin_lock (&d->port.lock);
265       
266       /* Reauthenticate the descriptor's port.  */
267       if (d->port.port != MACH_PORT_NULL &&
268           ! __io_reauthenticate (d->port.port, _hurd_pid) &&
269           ! __USEPORT (AUTH, __auth_user_authenticate (port,
270                                                        d->port.port, _hurd_pid,
271                                                        &new)))
272         {
273           /* Replace the port in the descriptor cell
274              with the newly reauthenticated port.  */
275
276           if (d->ctty.port != MACH_PORT_NULL &&
277               ! __io_reauthenticate (d->ctty.port, _hurd_pid) &&
278               ! __USEPORT (AUTH, __auth_user_authenticate (port,
279                                                            d->ctty.port,
280                                                            _hurd_pid,
281                                                            &newctty)))
282             _hurd_port_set (&d->ctty, newctty);
283
284           _hurd_port_locked_set (&d->port, new);
285         }
286       else
287         /* Lost.  Leave this descriptor cell alone.  */
288         __spin_unlock (&d->port.lock);
289     }
290
291   __mutex_unlock (&_hurd_dtable_lock);
292   HURD_CRITICAL_END;
293 }
294
295 text_set_element (_hurd_reauth_hook, reauth_dtable);