Formerly ../hurd/dtable.c.~32~
[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 /* text_set_element (_hurd_getdport_fn, get_dtable_port); */
125 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port; /* XXX */
126 \f
127 #include <hurd/signal.h>
128
129 /* Called on fork to install the dtable in NEWTASK.  The dtable lock is
130    held now and was taken before the child was created, copying our memory.
131    Insert send rights for all of the normal io ports for fds, with the same
132    names they have in our task.  We trust that none of the ports in the
133    dtable were be changed while we have been holding the lock, so the port
134    names copied by the child are still valid in our task.  */
135
136 static error_t
137 fork_parent_dtable (task_t newtask)
138 {
139   error_t err;
140   int i;
141
142   err = 0;
143
144   for (i = 0; !err && i < _hurd_dtable.size; ++i)
145     {
146       struct hurd_userlink ulink, ctty_ulink;
147       io_t port = _hurd_port_get (&_hurd_dtable.d[i]->port, &ulink);
148       io_t ctty = _hurd_port_get (&_hurd_dtable.d[i]->ctty, &ctty_ulink);
149
150       /* If there is a ctty-special port (it will be in PORT),
151          insert only the normal io port.  The child will get a fresh
152          ctty-special port.  */
153       if (ctty != MACH_PORT_NULL)
154         err = __mach_port_insert_right (newtask, ctty, ctty,
155                                         MACH_MSG_TYPE_COPY_SEND);
156       else if (port != MACH_PORT_NULL)
157         /* There is no ctty-special port; PORT is the normal io port.  */
158         err = __mach_port_insert_right (newtask, port, port,
159                                         MACH_MSG_TYPE_COPY_SEND);
160
161       _hurd_port_free (&_hurd_dtable.d[i]->port, &ulink, port);
162       _hurd_port_free (&_hurd_dtable.d[i]->ctty, &ctty_ulink, ctty);
163     }
164   return err;
165 }
166
167 /* We are in the child fork; the dtable lock is still held.
168    The parent has inserted send rights for all the normal io ports,
169    but we must recover ctty-special ports for ourselves.  */
170 static error_t
171 fork_child_dtable (void)
172 {
173   error_t err;
174   int i;
175
176   err = 0;
177
178   for (i = 0; !err && i < _hurd_dtable.size; ++i)
179     {
180       struct hurd_fd *d = _hurd_dtable.d[i];
181
182       d->port.users = d->ctty.users = NULL;
183
184       if (d->ctty.port)
185         /* There was a ctty-special port in the parent.
186            We need to get one for ourselves too.  */
187           err = __term_become_ctty (d->ctty.port,
188                                     /* XXX no guarantee that init_pids hook
189                                        has been run BEFORE this one! */
190                                     _hurd_pid, _hurd_pgrp, _hurd_msgport,
191                                     &d->port.port);
192
193       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
194     }
195   return err;
196 }
197
198 text_set_element (_hurd_fork_locks, _hurd_dtable_lock);
199 text_set_element (_hurd_fork_setup_hook, fork_parent_dtable);
200 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
201 \f
202 /* Called when our process group has changed.  */
203
204 static void
205 ctty_new_pgrp (void)
206 {
207   int i;
208   
209   __mutex_lock (&_hurd_dtable_lock);
210
211   for (i = 0; i < _hurd_dtable.size; ++i)
212     {
213       struct hurd_fd *const d = _hurd_dtable.d[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 }
240
241 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
242 \f
243 /* Called to reauthenticate the dtable when the auth port changes.  */
244
245 static void
246 reauth_dtable (void)
247 {
248   int i;
249
250   __mutex_lock (&_hurd_dtable_lock);
251
252   for (i = 0; i < _hurd_dtable.size; ++i)
253     {
254       struct hurd_fd *const d = _hurd_dtable.d[i];
255       mach_port_t new, newctty;
256       
257       if (d == NULL)
258         /* Nothing to do for an unused descriptor cell.  */
259         continue;
260
261       /* Take the descriptor cell's lock.  */
262       __spin_lock (&d->port.lock);
263       
264       /* Reauthenticate the descriptor's port.  */
265       if (d->port.port != MACH_PORT_NULL &&
266           ! __io_reauthenticate (d->port.port, _hurd_pid) &&
267           ! __USEPORT (AUTH, __auth_user_authenticate (port,
268                                                        d->port.port, _hurd_pid,
269                                                        &new)))
270         {
271           /* Replace the port in the descriptor cell
272              with the newly reauthenticated port.  */
273
274           if (d->ctty.port != MACH_PORT_NULL &&
275               ! __io_reauthenticate (d->ctty.port, _hurd_pid) &&
276               ! __USEPORT (AUTH, __auth_user_authenticate (port,
277                                                            d->ctty.port,
278                                                            _hurd_pid,
279                                                            &newctty)))
280             _hurd_port_set (&d->ctty, newctty);
281
282           _hurd_port_locked_set (&d->port, new);
283         }
284       else
285         /* Lost.  Leave this descriptor cell alone.  */
286         __spin_unlock (&d->port.lock);
287     }
288
289   __mutex_unlock (&_hurd_dtable_lock);
290 }
291
292 text_set_element (_hurd_reauth_hook, reauth_dtable);
293 \f
294 \f
295 #if 0
296
297 #include <hurd/signal.h>
298
299 static void
300 rectty_dtable (mach_port_t cttyid)
301 {
302   int i;
303   
304   __mutex_lock (&_hurd_dtable_lock);
305
306   for (i = 0; i < _hurd_dtable.size; ++i)
307     {
308       struct hurd_fd *const d = _hurd_dtable.d[i];
309       mach_port_t newctty;
310
311       if (d == NULL)
312         /* Nothing to do for an unused descriptor cell.  */
313         continue;
314
315       if (cttyid == MACH_PORT_NULL)
316         /* We now have no controlling tty at all.  */
317         newctty = MACH_PORT_NULL;
318       else
319         HURD_PORT_USE (&d->port,
320                        ({ mach_port_t id;
321                           /* Get the io object's cttyid port.  */
322                           if (! __term_getctty (port, &id))
323                             {
324                               if (id == cttyid && /* Is it ours?  */
325                                   /* Get the ctty io port.  */
326                                   __term_become_ctty (port, _hurd_pid,
327                                                       _hurd_pgrp,
328                                                       _hurd_msgport,
329                                                       &newctty))
330                                 /* XXX it is our ctty but the call failed? */
331                                 newctty = MACH_PORT_NULL;
332                               __mach_port_deallocate
333                                 (__mach_task_self (), (mach_port_t) id);
334                             }
335                           else
336                             newctty = MACH_PORT_NULL;
337                           0;
338                         }));
339
340       /* Install the new ctty port.  */
341       _hurd_port_set (&d->ctty, newctty);
342     }
343
344   __mutex_unlock (&_hurd_dtable_lock);
345 }
346
347 #include <sys/ioctl.h>
348
349
350 /* Make FD be the controlling terminal.
351    This function is called for `ioctl (fd, TCIOSCTTY)'.  */
352
353 static int
354 tiocsctty (int fd,
355            int request,         /* Always TCIOSCTTY.  */
356            void *arg)           /* Not used.  */
357 {
358   mach_port_t cttyid;
359   error_t err;
360
361   /* Get FD's cttyid port, unless it is already ours.  */
362   err = _HURD_DPORT_USE (fd,
363                          ctty ? EADDRINUSE : __term_getctty (port, &cttyid));
364   if (err == EADDRINUSE)
365     /* FD is already the ctty.  Nothing to do.  */
366     return 0;
367   else if (err)
368     return err;
369
370   /* Make it our own.  */
371   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); /* Consumes ref.  */
372
373   /* Reset all the ctty ports in all the descriptors.  */
374   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID], (rectty_dtable (port), 0));
375
376   return 0;
377 }
378 _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
379
380 /* Dissociate from the controlling terminal.  */
381
382 static int
383 tiocnotty (int fd,
384            int request,         /* Always TIOCNOTTY.  */
385            void *arg)           /* Not used.  */
386 {
387   /* XXX should verify that FD is ctty and return EINVAL? */
388
389   /* Clear our cttyid port cell.  */
390   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
391
392   /* Reset all the ctty ports in all the descriptors.  */
393   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID],
394                   (rectty_dtable (MACH_PORT_NULL), 0));
395
396   return 0;
397 }
398 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
399
400 #endif