1999-03-04 Roland McGrath <roland@baalperazim.frob.com>
[kopensolaris-gnu/glibc.git] / hurd / dtable.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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 not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <hurd.h>
20 #include <hurd/term.h>
21 #include <hurd/fd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <cthreads.h>           /* For `struct mutex'.  */
27 #include "set-hooks.h"
28 #include "hurdmalloc.h"         /* XXX */
29
30
31 struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */
32 struct hurd_fd **_hurd_dtable;
33 int _hurd_dtablesize;
34
35
36 DEFINE_HOOK (_hurd_fd_subinit, (void));
37
38 /* Initialize the file descriptor table at startup.  */
39
40 static void
41 init_dtable (void)
42 {
43   int i;
44
45   __mutex_init (&_hurd_dtable_lock);
46
47   /* The initial size of the descriptor table is that of the passed-in
48      table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
49   _hurd_dtablesize = _hurd_init_dtablesize;
50
51   /* Allocate the vector of pointers.  */
52   _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
53   if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
54     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
55
56   /* Initialize the descriptor table.  */
57   for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i)
58     {
59       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
60         /* An unused descriptor is marked by a null pointer.  */
61         _hurd_dtable[i] = NULL;
62       else
63         {
64           /* Allocate a new file descriptor structure.  */
65           struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
66           if (new == NULL)
67             __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
68
69           /* Initialize the port cells.  */
70           _hurd_port_init (&new->port, MACH_PORT_NULL);
71           _hurd_port_init (&new->ctty, MACH_PORT_NULL);
72
73           /* Install the port in the descriptor.
74              This sets up all the ctty magic.  */
75           _hurd_port2fd (new, _hurd_init_dtable[i], 0);
76
77           _hurd_dtable[i] = new;
78         }
79     }
80
81   /* Clear out the initial descriptor table.
82      Everything must use _hurd_dtable now.  */
83   __vm_deallocate (__mach_task_self (),
84                    (vm_address_t) _hurd_init_dtable,
85                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
86   _hurd_init_dtable = NULL;
87   _hurd_init_dtablesize = 0;
88
89   /* Initialize the remaining empty slots in the table.  */
90   for (; i < _hurd_dtablesize; ++i)
91     _hurd_dtable[i] = NULL;
92
93   /* Run things that want to run after the file descriptor table
94      is initialized.  */
95   RUN_HOOK (_hurd_fd_subinit, ());
96
97   (void) &init_dtable;          /* Avoid "defined but not used" warning.  */
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 = 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 /* We are in the child fork; the dtable lock is still held.
129    The parent has inserted send rights for all the normal io ports,
130    but we must recover ctty-special ports for ourselves.  */
131 static error_t
132 fork_child_dtable (void)
133 {
134   error_t err;
135   int i;
136
137   err = 0;
138
139   for (i = 0; !err && i < _hurd_dtablesize; ++i)
140     {
141       struct hurd_fd *d = _hurd_dtable[i];
142       if (d == NULL)
143         continue;
144
145       /* No other thread is using the send rights in the child task.  */
146       d->port.users = d->ctty.users = NULL;
147
148       if (d->ctty.port != MACH_PORT_NULL)
149         {
150           /* There was a ctty-special port in the parent.
151              We need to get one for ourselves too.  */
152           __mach_port_deallocate (__mach_task_self (), d->ctty.port);
153           err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp,
154                                   &d->ctty.port);
155           if (err)
156             d->ctty.port = MACH_PORT_NULL;
157         }
158
159       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
160     }
161   return err;
162
163   (void) &fork_child_dtable;    /* Avoid "defined but not used" warning.  */
164 }
165
166 data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */
167 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
168 \f
169 /* Called when our process group has changed.  */
170
171 static void
172 ctty_new_pgrp (void)
173 {
174   int i;
175
176   HURD_CRITICAL_BEGIN;
177   __mutex_lock (&_hurd_dtable_lock);
178
179   for (i = 0; i < _hurd_dtablesize; ++i)
180     {
181       struct hurd_fd *const d = _hurd_dtable[i];
182       struct hurd_userlink ulink, ctty_ulink;
183       io_t port, ctty;
184
185       if (d == NULL)
186         /* Nothing to do for an unused descriptor cell.  */
187         continue;
188
189       port = _hurd_port_get (&d->port, &ulink);
190       ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
191
192       if (ctty != MACH_PORT_NULL)
193         {
194           /* This fd has a ctty-special port.  We need a new one, to tell
195              the io server of our different process group.  */
196           io_t new;
197           if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
198             new = MACH_PORT_NULL;
199           _hurd_port_set (&d->ctty, new);
200         }
201
202       _hurd_port_free (&d->port, &ulink, port);
203       _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
204     }
205
206   __mutex_unlock (&_hurd_dtable_lock);
207   HURD_CRITICAL_END;
208
209   (void) &ctty_new_pgrp;        /* Avoid "defined but not used" warning.  */
210 }
211
212 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
213 \f
214 /* Called to reauthenticate the dtable when the auth port changes.  */
215
216 static void
217 reauth_dtable (void)
218 {
219   int i;
220
221   HURD_CRITICAL_BEGIN;
222   __mutex_lock (&_hurd_dtable_lock);
223
224   for (i = 0; i < _hurd_dtablesize; ++i)
225     {
226       struct hurd_fd *const d = _hurd_dtable[i];
227       mach_port_t new, newctty, ref;
228
229       if (d == NULL)
230         /* Nothing to do for an unused descriptor cell.  */
231         continue;
232
233       ref = __mach_reply_port ();
234
235       /* Take the descriptor cell's lock.  */
236       __spin_lock (&d->port.lock);
237
238       /* Reauthenticate the descriptor's port.  */
239       if (d->port.port != MACH_PORT_NULL &&
240           ! __io_reauthenticate (d->port.port,
241                                  ref, MACH_MSG_TYPE_MAKE_SEND) &&
242           ! __USEPORT (AUTH, __auth_user_authenticate
243                        (port,
244                         ref, MACH_MSG_TYPE_MAKE_SEND,
245                         &new)))
246         {
247           /* Replace the port in the descriptor cell
248              with the newly reauthenticated port.  */
249
250           if (d->ctty.port != MACH_PORT_NULL &&
251               ! __io_reauthenticate (d->ctty.port,
252                                      ref, MACH_MSG_TYPE_MAKE_SEND) &&
253               ! __USEPORT (AUTH, __auth_user_authenticate
254                            (port,
255                             ref, MACH_MSG_TYPE_MAKE_SEND,
256                             &newctty)))
257             _hurd_port_set (&d->ctty, newctty);
258
259           _hurd_port_locked_set (&d->port, new);
260         }
261       else
262         /* Lost.  Leave this descriptor cell alone.  */
263         __spin_unlock (&d->port.lock);
264
265       __mach_port_destroy (__mach_task_self (), ref);
266     }
267
268   __mutex_unlock (&_hurd_dtable_lock);
269   HURD_CRITICAL_END;
270
271   (void) &reauth_dtable;        /* Avoid "defined but not used" warning.  */
272 }
273
274 text_set_element (_hurd_reauth_hook, reauth_dtable);