Formerly ../hurd/dtable.c.~38~
[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
31
32 struct mutex _hurd_dtable_lock;
33 struct hurd_fd **_hurd_dtable;
34 int _hurd_dtablesize;
35 int _hurd_dtable_rlimit;        /* Resource limit on open descriptors.  */
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   /* In lieu of a real resource limit value inherited from the parent
54      (XXX), compute a reasonable seeming limit: the size the passed-in
55      table, rounded up to a multiple of FOPEN_MAX descriptors.  */
56   _hurd_dtable_rlimit
57     = (_hurd_init_dtablesize + FOPEN_MAX - 1) / FOPEN_MAX * FOPEN_MAX;
58   if (_hurd_dtable_rlimit == 0)
59     _hurd_dtable_rlimit = FOPEN_MAX;
60
61   /* Allocate the vector of pointers.  */
62   _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
63   if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
64     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
65
66   /* Initialize the descriptor table.  */
67   for (i = 0; i < _hurd_init_dtablesize; ++i)
68     {
69       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
70         /* An unused descriptor is marked by a null pointer.  */
71         _hurd_dtable[i] = NULL;
72       else
73         {
74           /* Allocate a new file descriptor structure.  */
75           struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
76           if (new == NULL)
77             __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
78
79           /* Initialize the port cells.  */
80           _hurd_port_init (&new->port, MACH_PORT_NULL);
81           _hurd_port_init (&new->ctty, MACH_PORT_NULL);
82
83           /* Install the port in the descriptor.
84              This sets up all the ctty magic.  */
85           _hurd_port2fd (new, _hurd_init_dtable[i], 0);
86
87           _hurd_dtable[i] = new;
88         }
89     }
90
91   /* Clear out the initial descriptor table.
92      Everything must use _hurd_dtable now.  */
93   __vm_deallocate (__mach_task_self (),
94                    (vm_address_t) _hurd_init_dtable,
95                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
96   _hurd_init_dtable = NULL;
97   _hurd_init_dtablesize = 0;
98
99   /* Initialize the remaining empty slots in the table.  */
100   for (; i < _hurd_dtablesize; ++i)
101     _hurd_dtable[i] = NULL;
102
103   /* Run things that want to run after the file descriptor table
104      is initialized.  */
105   RUN_HOOK (_hurd_fd_subinit, ());
106 }
107
108 text_set_element (_hurd_subinit, init_dtable);
109
110 /* XXX when the linker supports it, the following functions should all be
111    elsewhere and just have text_set_elements here.  */
112 \f
113 /* Called by `getdport' to do its work.  */
114
115 static file_t
116 get_dtable_port (int fd)
117 {
118   file_t dport;
119   int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (),
120                                                       (dport = ctty ?: port),
121                                                       MACH_PORT_RIGHT_SEND,
122                                                       1));
123   if (err)
124     {
125       errno = err;
126       return MACH_PORT_NULL;
127     }
128   else
129     return dport;
130 }
131
132 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
133 \f
134 #include <hurd/signal.h>
135
136 /* Called on fork to install the dtable in NEWTASK.  The dtable lock is
137    held now and was taken before the child was created, copying our memory.
138    Insert send rights for all of the normal io ports for fds, with the same
139    names they have in our task.  We trust that none of the ports in the
140    dtable were be changed while we have been holding the lock, so the port
141    names copied by the child are still valid in our task.  */
142
143 static error_t
144 fork_parent_dtable (task_t newtask)
145 {
146   error_t err;
147   int i;
148
149   err = 0;
150
151   for (i = 0; !err && i < _hurd_dtablesize; ++i)
152     {
153       struct hurd_userlink ulink, ctty_ulink;
154       io_t port = _hurd_port_get (&_hurd_dtable[i]->port, &ulink);
155       io_t ctty = _hurd_port_get (&_hurd_dtable[i]->ctty, &ctty_ulink);
156
157       /* If there is a ctty-special port (it will be in PORT),
158          insert only the normal io port.  The child will get a fresh
159          ctty-special port.  */
160       if (ctty != MACH_PORT_NULL)
161         err = __mach_port_insert_right (newtask, ctty, ctty,
162                                         MACH_MSG_TYPE_COPY_SEND);
163       else if (port != MACH_PORT_NULL)
164         /* There is no ctty-special port; PORT is the normal io port.  */
165         err = __mach_port_insert_right (newtask, port, port,
166                                         MACH_MSG_TYPE_COPY_SEND);
167
168       _hurd_port_free (&_hurd_dtable[i]->port, &ulink, port);
169       _hurd_port_free (&_hurd_dtable[i]->ctty, &ctty_ulink, ctty);
170     }
171   return err;
172 }
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
189       d->port.users = d->ctty.users = NULL;
190
191       if (d->ctty.port)
192         /* There was a ctty-special port in the parent.
193            We need to get one for ourselves too.  */
194           err = __term_become_ctty (d->ctty.port,
195                                     /* XXX no guarantee that init_pids hook
196                                        has been run BEFORE this one! */
197                                     _hurd_pid, _hurd_pgrp, _hurd_msgport,
198                                     &d->port.port);
199
200       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
201     }
202   return err;
203 }
204
205 text_set_element (_hurd_fork_locks, _hurd_dtable_lock);
206 text_set_element (_hurd_fork_setup_hook, fork_parent_dtable);
207 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
208 \f
209 /* Called when our process group has changed.  */
210
211 static void
212 ctty_new_pgrp (void)
213 {
214   int i;
215   
216   HURD_CRITICAL_BEGIN;
217   __mutex_lock (&_hurd_dtable_lock);
218
219   for (i = 0; i < _hurd_dtablesize; ++i)
220     {
221       struct hurd_fd *const d = _hurd_dtable[i];
222       struct hurd_userlink ulink, ctty_ulink;
223       io_t port, ctty;
224
225       if (d == NULL)
226         /* Nothing to do for an unused descriptor cell.  */
227         continue;
228
229       port = _hurd_port_get (&d->port, &ulink);
230       ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
231
232       if (ctty)
233         {
234           /* This fd has a ctty-special port.  We need a new one, to tell
235              the io server of our different process group.  */
236           io_t new;
237           if (! __term_become_ctty (ctty, _hurd_pid, _hurd_pgrp, _hurd_msgport,
238                                     &new))
239             _hurd_port_set (&d->port, new);
240         }
241
242       _hurd_port_free (&d->port, &ulink, port);
243       _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
244     }
245
246   __mutex_unlock (&_hurd_dtable_lock);
247   HURD_CRITICAL_END;
248 }
249
250 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
251 \f
252 /* Called to reauthenticate the dtable when the auth port changes.  */
253
254 static void
255 reauth_dtable (void)
256 {
257   int i;
258
259   HURD_CRITICAL_BEGIN;
260   __mutex_lock (&_hurd_dtable_lock);
261
262   for (i = 0; i < _hurd_dtablesize; ++i)
263     {
264       struct hurd_fd *const d = _hurd_dtable[i];
265       mach_port_t new, newctty;
266       
267       if (d == NULL)
268         /* Nothing to do for an unused descriptor cell.  */
269         continue;
270
271       /* Take the descriptor cell's lock.  */
272       __spin_lock (&d->port.lock);
273       
274       /* Reauthenticate the descriptor's port.  */
275       if (d->port.port != MACH_PORT_NULL &&
276           ! __io_reauthenticate (d->port.port, _hurd_pid) &&
277           ! __USEPORT (AUTH, __auth_user_authenticate (port,
278                                                        d->port.port, _hurd_pid,
279                                                        &new)))
280         {
281           /* Replace the port in the descriptor cell
282              with the newly reauthenticated port.  */
283
284           if (d->ctty.port != MACH_PORT_NULL &&
285               ! __io_reauthenticate (d->ctty.port, _hurd_pid) &&
286               ! __USEPORT (AUTH, __auth_user_authenticate (port,
287                                                            d->ctty.port,
288                                                            _hurd_pid,
289                                                            &newctty)))
290             _hurd_port_set (&d->ctty, newctty);
291
292           _hurd_port_locked_set (&d->port, new);
293         }
294       else
295         /* Lost.  Leave this descriptor cell alone.  */
296         __spin_unlock (&d->port.lock);
297     }
298
299   __mutex_unlock (&_hurd_dtable_lock);
300   HURD_CRITICAL_END;
301 }
302
303 text_set_element (_hurd_reauth_hook, reauth_dtable);