f437c14cc439d3a949ba2d8c0c5bad75b4cfc022
[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
29
30 #ifdef noteven
31 struct mutex _hurd_dtable_lock;
32 #endif
33 struct hurd_dtable _hurd_dtable;
34 int _hurd_dtable_rlimit;
35 struct hurd_userlink *_hurd_dtable_users;
36
37 void (*_hurd_dtable_deallocate) (void *);
38
39
40 /* Initialize the file descriptor table at startup.  */
41
42 static void
43 init_dtable (void)
44 {
45   register size_t i;
46   struct hurd_fd **dt;
47
48 #ifdef noteven
49   __mutex_init (&_hurd_dtable_lock);
50 #endif
51
52   _hurd_dtable_users = NULL;
53
54   /* The initial size of the descriptor table is that of the passed-in
55      table, rounded up to a multiple of FOPEN_MAX descriptors.  */
56   _hurd_dtable.size
57     = (_hurd_init_dtablesize + FOPEN_MAX - 1) / FOPEN_MAX * FOPEN_MAX;
58   _hurd_dtable_rlimit = _hurd_dtable.size;
59
60   /* Allocate the vector of pointers.  */
61   dt = _hurd_dtable.d = malloc (_hurd_dtable.size * sizeof (*_hurd_dtable.d));
62   if (dt == NULL)
63     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
64
65   /* Initialize the descriptor table.  */
66   for (i = 0; i < _hurd_init_dtablesize; ++i)
67     {
68       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
69         /* An unused descriptor is marked by a null pointer.  */
70         dt[i] = NULL;
71       else
72         {
73           /* Allocate a new file descriptor structure.  */
74           struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
75           if (new == NULL)
76             __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
77
78           /* Initialize the port cells.  */
79           _hurd_port_init (&new->port, MACH_PORT_NULL);
80           _hurd_port_init (&new->ctty, MACH_PORT_NULL);
81
82           /* Install the port in the descriptor.
83              This sets up all the ctty magic.  */
84           _hurd_port2fd (new, _hurd_init_dtable[i], 0);
85         }
86     }
87
88   /* Clear out the initial descriptor table.
89      Everything must use _hurd_dtable now.  */
90   __vm_deallocate (__mach_task_self (),
91                    (vm_address_t) _hurd_init_dtable,
92                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
93   _hurd_init_dtable = NULL;
94   _hurd_init_dtablesize = 0;
95
96   /* Initialize the remaining empty slots in the table.  */
97   for (; i < _hurd_dtable.size; ++i)
98     dt[i] = NULL;
99 }
100
101 text_set_element (__libc_subinit, init_dtable);
102
103 /* XXX when the linker supports it, the following functions should all be
104    elsewhere and just have text_set_elements here.  */
105 \f
106 /* Called by `getdport' to do its work.  */
107
108 static file_t
109 get_dtable_port (int fd)
110 {
111   file_t dport;
112   int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (),
113                                                       (dport = port),
114                                                       MACH_PORT_RIGHT_SEND,
115                                                       1));
116   if (err)
117     {
118       errno = err;
119       return MACH_PORT_NULL;
120     }
121   else
122     return dport;
123 }
124
125 /* text_set_element (_hurd_getdport_fn, get_dtable_port); */
126 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port; /* XXX */
127 \f
128 #include <hurd/signal.h>
129
130 /* Called on fork to install the dtable in NEWTASK.  The dtable lock is
131    held now and was taken before the child was created, copying our memory.
132    Insert send rights for all of the normal io ports for fds, with the same
133    names they have in our task.  We trust that none of the ports in the
134    dtable were be changed while we have been holding the lock, so the port
135    names copied by the child are still valid in our task.  */
136
137 static error_t
138 fork_parent_dtable (task_t newtask)
139 {
140   error_t err;
141   int i;
142
143   err = 0;
144
145   for (i = 0; !err && i < _hurd_dtable.size; ++i)
146     {
147       struct hurd_userlink ulink, ctty_ulink;
148       io_t port = _hurd_port_get (&_hurd_dtable.d[i]->port, &ulink);
149       io_t ctty = _hurd_port_get (&_hurd_dtable.d[i]->ctty, &ctty_ulink);
150
151       /* If there is a ctty-special port (it will be in PORT),
152          insert only the normal io port.  The child will get a fresh
153          ctty-special port.  */
154       if (ctty != MACH_PORT_NULL)
155         err = __mach_port_insert_right (newtask, ctty, ctty,
156                                         MACH_MSG_TYPE_COPY_SEND);
157       else if (port != MACH_PORT_NULL)
158         /* There is no ctty-special port; PORT is the normal io port.  */
159         err = __mach_port_insert_right (newtask, port, port,
160                                         MACH_MSG_TYPE_COPY_SEND);
161
162       _hurd_port_free (&_hurd_dtable.d[i]->port, &ulink, port);
163       _hurd_port_free (&_hurd_dtable.d[i]->ctty, &ctty_ulink, ctty);
164     }
165   return err;
166 }
167
168 /* We are in the child fork; the dtable lock is still held.
169    The parent has inserted send rights for all the normal io ports,
170    but we must recover ctty-special ports for ourselves.  */
171 static error_t
172 fork_child_dtable (void)
173 {
174   error_t err;
175   int i;
176
177   err = 0;
178
179   for (i = 0; !err && i < _hurd_dtable.size; ++i)
180     {
181       struct hurd_fd *d = _hurd_dtable.d[i];
182
183       d->port.users = d->ctty.users = NULL;
184
185       if (d->ctty.port)
186         /* There was a ctty-special port in the parent.
187            We need to get one for ourselves too.  */
188           err = __term_become_ctty (d->ctty.port,
189                                     /* XXX no guarantee that init_pids hook
190                                        has been run BEFORE this one! */
191                                     _hurd_pid, _hurd_pgrp, _hurd_msgport,
192                                     &d->port.port);
193
194       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
195     }
196   return err;
197 }
198
199 text_set_element (_hurd_fork_locks, _hurd_dtable_lock);
200 text_set_element (_hurd_fork_setup_hook, fork_parent_dtable);
201 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
202 \f
203 /* Called when our process group has changed.  */
204
205 static void
206 ctty_new_pgrp (void)
207 {
208   int i;
209   
210   __mutex_lock (&_hurd_dtable_lock);
211
212   for (i = 0; i < _hurd_dtable.size; ++i)
213     {
214       struct hurd_fd *const d = _hurd_dtable.d[i];
215       struct hurd_userlink ulink, ctty_ulink;
216       io_t port, ctty;
217
218       if (d == NULL)
219         /* Nothing to do for an unused descriptor cell.  */
220         continue;
221
222       port = _hurd_port_get (&d->port, &ulink);
223       ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
224
225       if (ctty)
226         {
227           /* This fd has a ctty-special port.  We need a new one, to tell
228              the io server of our different process group.  */
229           io_t new;
230           if (! __term_become_ctty (ctty, _hurd_pid, _hurd_pgrp, _hurd_msgport,
231                                     &new))
232             _hurd_port_set (&d->port, new);
233         }
234
235       _hurd_port_free (&d->port, &ulink, port);
236       _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
237     }
238
239   __mutex_unlock (&_hurd_dtable_lock);
240 }
241
242 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
243 \f
244 /* Called to reauthenticate the dtable when the auth port changes.  */
245
246 static void
247 reauth_dtable (void)
248 {
249   int i;
250
251   __mutex_lock (&_hurd_dtable_lock);
252
253   for (i = 0; i < _hurd_dtable.size; ++i)
254     {
255       struct hurd_fd *const d = _hurd_dtable.d[i];
256       mach_port_t new, newctty;
257       
258       if (d == NULL)
259         /* Nothing to do for an unused descriptor cell.  */
260         continue;
261
262       /* Take the descriptor cell's lock.  */
263       __spin_lock (&d->port.lock);
264       
265       /* Reauthenticate the descriptor's port.  */
266       if (d->port.port != MACH_PORT_NULL &&
267           ! __io_reauthenticate (d->port.port, _hurd_pid) &&
268           ! __USEPORT (AUTH, __auth_user_authenticate (port,
269                                                        d->port.port, _hurd_pid,
270                                                        &new)))
271         {
272           /* Replace the port in the descriptor cell
273              with the newly reauthenticated port.  */
274
275           if (d->ctty.port != MACH_PORT_NULL &&
276               ! __io_reauthenticate (d->ctty.port, _hurd_pid) &&
277               ! __USEPORT (AUTH, __auth_user_authenticate (port,
278                                                            d->ctty.port,
279                                                            _hurd_pid,
280                                                            &newctty)))
281             _hurd_port_set (&d->ctty, newctty);
282
283           _hurd_port_locked_set (&d->port, new);
284         }
285       else
286         /* Lost.  Leave this descriptor cell alone.  */
287         __spin_unlock (&d->port.lock);
288     }
289
290   __mutex_unlock (&_hurd_dtable_lock);
291 }
292
293 text_set_element (_hurd_reauth_hook, reauth_dtable);
294 \f
295 \f
296 #if 0
297
298 #include <hurd/signal.h>
299
300 static void
301 rectty_dtable (mach_port_t cttyid)
302 {
303   int i;
304   
305   __mutex_lock (&_hurd_dtable_lock);
306
307   for (i = 0; i < _hurd_dtable.size; ++i)
308     {
309       struct hurd_fd *const d = _hurd_dtable.d[i];
310       mach_port_t newctty;
311
312       if (d == NULL)
313         /* Nothing to do for an unused descriptor cell.  */
314         continue;
315
316       if (cttyid == MACH_PORT_NULL)
317         /* We now have no controlling tty at all.  */
318         newctty = MACH_PORT_NULL;
319       else
320         HURD_PORT_USE (&d->port,
321                        ({ mach_port_t id;
322                           /* Get the io object's cttyid port.  */
323                           if (! __term_getctty (port, &id))
324                             {
325                               if (id == cttyid && /* Is it ours?  */
326                                   /* Get the ctty io port.  */
327                                   __term_become_ctty (port, _hurd_pid,
328                                                       _hurd_pgrp,
329                                                       _hurd_msgport,
330                                                       &newctty))
331                                 /* XXX it is our ctty but the call failed? */
332                                 newctty = MACH_PORT_NULL;
333                               __mach_port_deallocate
334                                 (__mach_task_self (), (mach_port_t) id);
335                             }
336                           else
337                             newctty = MACH_PORT_NULL;
338                           0;
339                         }));
340
341       /* Install the new ctty port.  */
342       _hurd_port_set (&d->ctty, newctty);
343     }
344
345   __mutex_unlock (&_hurd_dtable_lock);
346 }
347
348 #include <sys/ioctl.h>
349
350
351 /* Make FD be the controlling terminal.
352    This function is called for `ioctl (fd, TCIOSCTTY)'.  */
353
354 static int
355 tiocsctty (int fd,
356            int request,         /* Always TCIOSCTTY.  */
357            void *arg)           /* Not used.  */
358 {
359   mach_port_t cttyid;
360   error_t err;
361
362   /* Get FD's cttyid port, unless it is already ours.  */
363   err = _HURD_DPORT_USE (fd,
364                          ctty ? EADDRINUSE : __term_getctty (port, &cttyid));
365   if (err == EADDRINUSE)
366     /* FD is already the ctty.  Nothing to do.  */
367     return 0;
368   else if (err)
369     return err;
370
371   /* Make it our own.  */
372   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); /* Consumes ref.  */
373
374   /* Reset all the ctty ports in all the descriptors.  */
375   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID], (rectty_dtable (port), 0));
376
377   return 0;
378 }
379 _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
380
381 /* Dissociate from the controlling terminal.  */
382
383 static int
384 tiocnotty (int fd,
385            int request,         /* Always TIOCNOTTY.  */
386            void *arg)           /* Not used.  */
387 {
388   /* XXX should verify that FD is ctty and return EINVAL? */
389
390   /* Clear our cttyid port cell.  */
391   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
392
393   /* Reset all the ctty ports in all the descriptors.  */
394   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID],
395                   (rectty_dtable (MACH_PORT_NULL), 0));
396
397   return 0;
398 }
399 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
400
401 #endif