Formerly ../hurd/dtable.c.~33~
[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 <mutex.h>
29
30
31 struct mutex _hurd_dtable_lock;
32 struct hurd_dtable _hurd_dtable;
33 int _hurd_dtable_rlimit;
34 struct hurd_userlink *_hurd_dtable_users;
35
36 void (*_hurd_dtable_deallocate) (void *);
37
38
39 /* Initialize the file descriptor table at startup.  */
40
41 static void
42 init_dtable (void)
43 {
44   register size_t i;
45   struct hurd_fd **dt;
46
47   __mutex_init (&_hurd_dtable_lock);
48
49   _hurd_dtable_users = NULL;
50
51   /* The initial size of the descriptor table is that of the passed-in
52      table, rounded up to a multiple of FOPEN_MAX descriptors.  */
53   _hurd_dtable.size
54     = (_hurd_init_dtablesize + FOPEN_MAX - 1) / FOPEN_MAX * FOPEN_MAX;
55   _hurd_dtable_rlimit = _hurd_dtable.size;
56
57   /* Allocate the vector of pointers.  */
58   dt = _hurd_dtable.d = malloc (_hurd_dtable.size * sizeof (*_hurd_dtable.d));
59   if (dt == NULL)
60     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
61
62   /* Initialize the descriptor table.  */
63   for (i = 0; i < _hurd_init_dtablesize; ++i)
64     {
65       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
66         /* An unused descriptor is marked by a null pointer.  */
67         dt[i] = NULL;
68       else
69         {
70           /* Allocate a new file descriptor structure.  */
71           struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
72           if (new == NULL)
73             __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
74
75           /* Initialize the port cells.  */
76           _hurd_port_init (&new->port, MACH_PORT_NULL);
77           _hurd_port_init (&new->ctty, MACH_PORT_NULL);
78
79           /* Install the port in the descriptor.
80              This sets up all the ctty magic.  */
81           _hurd_port2fd (new, _hurd_init_dtable[i], 0);
82
83           dt[i] = new;
84         }
85     }
86
87   /* Clear out the initial descriptor table.
88      Everything must use _hurd_dtable now.  */
89   __vm_deallocate (__mach_task_self (),
90                    (vm_address_t) _hurd_init_dtable,
91                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
92   _hurd_init_dtable = NULL;
93   _hurd_init_dtablesize = 0;
94
95   /* Initialize the remaining empty slots in the table.  */
96   for (; i < _hurd_dtable.size; ++i)
97     dt[i] = NULL;
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 /* 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_dtable.size; ++i)
144     {
145       struct hurd_userlink ulink, ctty_ulink;
146       io_t port = _hurd_port_get (&_hurd_dtable.d[i]->port, &ulink);
147       io_t ctty = _hurd_port_get (&_hurd_dtable.d[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.d[i]->port, &ulink, port);
161       _hurd_port_free (&_hurd_dtable.d[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_dtable.size; ++i)
178     {
179       struct hurd_fd *d = _hurd_dtable.d[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   __mutex_lock (&_hurd_dtable_lock);
209
210   for (i = 0; i < _hurd_dtable.size; ++i)
211     {
212       struct hurd_fd *const d = _hurd_dtable.d[i];
213       struct hurd_userlink ulink, ctty_ulink;
214       io_t port, ctty;
215
216       if (d == NULL)
217         /* Nothing to do for an unused descriptor cell.  */
218         continue;
219
220       port = _hurd_port_get (&d->port, &ulink);
221       ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
222
223       if (ctty)
224         {
225           /* This fd has a ctty-special port.  We need a new one, to tell
226              the io server of our different process group.  */
227           io_t new;
228           if (! __term_become_ctty (ctty, _hurd_pid, _hurd_pgrp, _hurd_msgport,
229                                     &new))
230             _hurd_port_set (&d->port, new);
231         }
232
233       _hurd_port_free (&d->port, &ulink, port);
234       _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
235     }
236
237   __mutex_unlock (&_hurd_dtable_lock);
238 }
239
240 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
241 \f
242 /* Called to reauthenticate the dtable when the auth port changes.  */
243
244 static void
245 reauth_dtable (void)
246 {
247   int i;
248
249   __mutex_lock (&_hurd_dtable_lock);
250
251   for (i = 0; i < _hurd_dtable.size; ++i)
252     {
253       struct hurd_fd *const d = _hurd_dtable.d[i];
254       mach_port_t new, newctty;
255       
256       if (d == NULL)
257         /* Nothing to do for an unused descriptor cell.  */
258         continue;
259
260       /* Take the descriptor cell's lock.  */
261       __spin_lock (&d->port.lock);
262       
263       /* Reauthenticate the descriptor's port.  */
264       if (d->port.port != MACH_PORT_NULL &&
265           ! __io_reauthenticate (d->port.port, _hurd_pid) &&
266           ! __USEPORT (AUTH, __auth_user_authenticate (port,
267                                                        d->port.port, _hurd_pid,
268                                                        &new)))
269         {
270           /* Replace the port in the descriptor cell
271              with the newly reauthenticated port.  */
272
273           if (d->ctty.port != MACH_PORT_NULL &&
274               ! __io_reauthenticate (d->ctty.port, _hurd_pid) &&
275               ! __USEPORT (AUTH, __auth_user_authenticate (port,
276                                                            d->ctty.port,
277                                                            _hurd_pid,
278                                                            &newctty)))
279             _hurd_port_set (&d->ctty, newctty);
280
281           _hurd_port_locked_set (&d->port, new);
282         }
283       else
284         /* Lost.  Leave this descriptor cell alone.  */
285         __spin_unlock (&d->port.lock);
286     }
287
288   __mutex_unlock (&_hurd_dtable_lock);
289 }
290
291 text_set_element (_hurd_reauth_hook, reauth_dtable);
292 \f
293 \f
294 #if 0
295
296 #include <hurd/signal.h>
297
298 static void
299 rectty_dtable (mach_port_t cttyid)
300 {
301   int i;
302   
303   __mutex_lock (&_hurd_dtable_lock);
304
305   for (i = 0; i < _hurd_dtable.size; ++i)
306     {
307       struct hurd_fd *const d = _hurd_dtable.d[i];
308       mach_port_t newctty;
309
310       if (d == NULL)
311         /* Nothing to do for an unused descriptor cell.  */
312         continue;
313
314       if (cttyid == MACH_PORT_NULL)
315         /* We now have no controlling tty at all.  */
316         newctty = MACH_PORT_NULL;
317       else
318         HURD_PORT_USE (&d->port,
319                        ({ mach_port_t id;
320                           /* Get the io object's cttyid port.  */
321                           if (! __term_getctty (port, &id))
322                             {
323                               if (id == cttyid && /* Is it ours?  */
324                                   /* Get the ctty io port.  */
325                                   __term_become_ctty (port, _hurd_pid,
326                                                       _hurd_pgrp,
327                                                       _hurd_msgport,
328                                                       &newctty))
329                                 /* XXX it is our ctty but the call failed? */
330                                 newctty = MACH_PORT_NULL;
331                               __mach_port_deallocate
332                                 (__mach_task_self (), (mach_port_t) id);
333                             }
334                           else
335                             newctty = MACH_PORT_NULL;
336                           0;
337                         }));
338
339       /* Install the new ctty port.  */
340       _hurd_port_set (&d->ctty, newctty);
341     }
342
343   __mutex_unlock (&_hurd_dtable_lock);
344 }
345
346 #include <sys/ioctl.h>
347
348
349 /* Make FD be the controlling terminal.
350    This function is called for `ioctl (fd, TCIOSCTTY)'.  */
351
352 static int
353 tiocsctty (int fd,
354            int request,         /* Always TCIOSCTTY.  */
355            void *arg)           /* Not used.  */
356 {
357   mach_port_t cttyid;
358   error_t err;
359
360   /* Get FD's cttyid port, unless it is already ours.  */
361   err = HURD_DPORT_USE (fd,
362                         ctty ? EADDRINUSE : __term_getctty (port, &cttyid));
363   if (err == EADDRINUSE)
364     /* FD is already the ctty.  Nothing to do.  */
365     return 0;
366   else if (err)
367     return __hurd_fail (err);
368
369   /* Make it our own.  */
370   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); /* Consumes ref.  */
371
372   /* Reset all the ctty ports in all the descriptors.  */
373   __USEPORT (CTTYID, (rectty_dtable (port), 0));
374
375   return 0;
376 }
377 _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
378
379 /* Dissociate from the controlling terminal.  */
380
381 static int
382 tiocnotty (int fd,
383            int request,         /* Always TIOCNOTTY.  */
384            void *arg)           /* Not used.  */
385 {
386   mach_port_t fd_cttyid;
387   error_t err;
388
389   if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid)))
390     return __hurd_fail (err);
391
392   if (__USEPORT (CTTYID, port != fd_cttyid))
393     err = EINVAL;
394
395   __mach_port_deallocate (__mach_task_+self (), fd_cttyid);
396
397   if (err)
398     return __hurd_fail (err);
399
400   /* Clear our cttyid port cell.  */
401   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
402
403   /* Reset all the ctty ports in all the descriptors.  */
404                                 
405   __USEPORT (CTTYID, (rectty_dtable (MACH_PORT_NULL), 0));
406
407   return 0;
408 }
409 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
410
411 #endif