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