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