Formerly ../hurd/dtable.c.~28~
[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 /* 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.userlink = d->ctty.userlink = 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       mach_port_t newctty;
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