dd46c46d55e055a6eaa835765a3a0c5c0f0f2c95
[kopensolaris-gnu/glibc.git] / hurd / dtable.c
1 /* Copyright (C) 1991, 1992, 1993 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 <gnu-stabs.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <limits.h>
26
27
28 struct _hurd_dtable _hurd_dtable;
29 struct mutex _hurd_dtable_lock;
30 int _hurd_dtable_rlimit;
31 int *_hurd_dtable_user_dealloc;
32
33 const struct _hurd_dtable_resizes _hurd_dtable_resizes;
34
35
36 /* Initialize the file descriptor table at startup.  */
37
38 static void
39 init_dtable (void)
40 {
41   register size_t i;
42
43   __mutex_init (&_hurd_dtable_lock);
44
45   _hurd_dtable_user_dealloc = NULL;
46
47   /* The initial size of the descriptor table is that of the passed-in
48      table, rounded up to a multiple of STREAM_MAX descriptors.  */
49   _hurd_dtable.size
50     = (_hurd_init_dtablesize + STREAM_MAX - 1) / STREAM_MAX * STREAM_MAX;
51   _hurd_dtable_rlimit = _hurd_dtable.size;
52
53   _hurd_dtable.d = malloc (_hurd_dtable.size * sizeof (*_hurd_dtable.d));
54   if (_hurd_dtable.d == NULL)
55     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
56
57   for (i = 0; i < _hurd_init_dtablesize; ++i)
58     {
59       struct _hurd_fd *const d = &_hurd_dtable.d[i];
60
61       _hurd_port_init (&d->port, MACH_PORT_NULL);
62       _hurd_port_init (&d->ctty, MACH_PORT_NULL);
63
64       _hurd_port2fd (d, _hurd_init_dtable[i], 0);
65     }
66
67   /* Clear out the initial descriptor table.
68      Everything must use _hurd_dtable now.  */
69   __vm_deallocate (__mach_task_self (),
70                    (vm_address_t) _hurd_init_dtable,
71                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
72   _hurd_init_dtable = NULL;
73   _hurd_init_dtablesize = 0;
74
75   /* Initialize the remaining empty slots in the table.  */
76   for (; i < _hurd_dtable.size; ++i)
77     {
78       _hurd_port_init (&_hurd_dtable.d[i].port, MACH_PORT_NULL);
79       _hurd_port_init (&_hurd_dtable.d[i].ctty, MACH_PORT_NULL);
80       _hurd_dtable.d[i].flags = 0;
81     }
82 }
83
84 text_set_element (__libc_subinit, init_dtable);
85 \f
86 /* Allocate a new file descriptor and install PORT in it.
87    FLAGS are as for `open'; only O_NOCTTY is meaningful, but all are saved.
88
89    If the descriptor table is full, set errno, and return -1.
90    If DEALLOC is nonzero, deallocate PORT first.  */
91 int
92 _hurd_intern_fd (io_t port, int flags, int dealloc)
93 {
94   int fd;
95   struct _hurd_fd *d = _hurd_alloc_fd (&fd, 0);
96
97   if (d == NULL)
98     {
99       if (dealloc)
100         __mach_port_deallocate (__mach_task_self (), port);
101       return -1;
102     }
103
104   _hurd_port2fd (d, port, flags);
105   __spin_unlock (&d->port.lock);
106   return fd;
107 }
108
109 /* Allocate a new file descriptor and return it, locked.
110    If the table is full, set errno and return NULL.  */
111 struct _hurd_fd *
112 _hurd_alloc_fd (int *fd, const int first_fd)
113 {
114   int i;
115
116   __mutex_lock (&hurd_dtable_lock);
117
118   for (i = first_fd; i < _hurd_dtable.size; ++i)
119     {
120       struct _hurd_fd *d = &_hurd_dtable.d[i];
121       __spin_lock (&d->port.lock);
122       if (d->port.port == MACH_PORT_NULL)
123         {
124           __mutex_unlock (&hurd_dtable_lock);
125           if (fd != NULL)
126             *fd = i;
127           return d;
128         }
129       else
130         __spin_unlock (&d->port.lock);
131     }
132
133   __mutex_unlock (&hurd_dtable_lock);
134
135   errno = EMFILE;
136   return NULL;
137 }
138
139 \f
140 void
141 _hurd_port2fd (struct _hurd_fd *d, io_t port, int flags)
142 {
143   io_t ctty;
144   mach_port_t cttyid;
145   int is_ctty = !(flags & O_NOCTTY) && ! __term_getctty (port, &cttyid);
146
147   if (is_ctty)
148     {
149       /* This port is capable of being a controlling tty.
150          Is it ours?  */
151       struct _hurd_port *const id = &_hurd_ports[INIT_PORT_CTTYID];
152       __spin_lock (&id->lock);
153       if (id->port == MACH_PORT_NULL)
154         /* We have no controlling tty, so make this one it.  */
155         _hurd_port_locked_set (id, cttyid);
156       else
157         {
158           if (cttyid != id->port)
159             /* We have a controlling tty and this is not it.  */
160             is_ctty = 0;
161           /* Either we don't want CTTYID, or ID->port already is it.
162              So we don't need to change ID->port, and we
163              can release the reference to CTTYID.  */
164           __spin_unlock (&id->lock);
165           __mach_port_deallocate (__mach_task_self (), cttyid);
166         }
167     }
168
169   if (is_ctty && ! __term_become_ctty (port, _hurd_pid, _hurd_pgrp,
170                                        _hurd_sigport, &ctty))
171     {
172       /* Operations on CTTY return EBACKGROUND when we are not a
173          foreground user of the tty.  */
174       d->port.port = ctty;
175       ctty = port;
176     }
177   else
178     /* XXX if IS_CTTY, then this port is our ctty, but we are
179        not doing ctty style i/o because term_become_ctty barfed.
180        What to do?  */
181     /* No ctty magic happening here.  */
182     ctty = MACH_PORT_NULL;
183
184   _hurd_port_set (&d->ctty, ctty);
185 }
186 \f
187 /* Called by `getdport' to do its work.  */
188
189 static file_t
190 get_dtable_port (int fd)
191 {
192   file_t dport;
193   int err = _HURD_DPORT_USE (fd,
194                              __mach_port_mod_refs (__mach_task_self (),
195                                                    (dport = port),
196                                                    MACH_PORT_RIGHT_SEND,
197                                                    1));
198   if (err)
199     {
200       errno = err;
201       return MACH_PORT_NULL;
202     }
203   else
204     return dport;
205 }
206
207 text_set_element (_hurd_getdport_fn, get_dtable_port);
208 \f
209 /* Called on fork to install the dtable in NEWTASK.
210    The dtable lock is held.  */
211
212 static error_t
213 fork_dtable (task_t newtask)
214 {
215   error_t err;
216   int i;
217
218   err = 0;
219
220   for (i = 0; !err && i < _hurd_dtable.size; ++i)
221     {
222       int dealloc, dealloc_ctty;
223       io_t port = _hurd_port_get (&_hurd_dtable.d[i].port, &dealloc);
224       io_t ctty = _hurd_port_get (&_hurd_dtable.d[i].ctty, &dealloc_ctty);
225
226       if (port != MACH_PORT_NULL)
227         err = __mach_port_insert_right (newtask, port, port,
228                                         MACH_PORT_TYPE_COPY_SEND);
229       if (!err && ctty != MACH_PORT_NULL)
230         err = __mach_port_insert_right (newtask, ctty, ctty,
231                                         MACH_PORT_TYPE_COPY_SEND);
232
233       _hurd_port_free (&_hurd_dtable.d[i].port, &dealloc, port);
234       _hurd_port_free (&_hurd_dtable.d[i].ctty, &dealloc_ctty, ctty);
235
236       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
237     }
238   __mutex_unlock (&_hurd_dtable_lock);
239   return err;
240 }
241
242 text_set_element (_hurd_fork_hook, fork_dtable);
243 text_set_element (_hurd_fork_locks, _hurd_dtable_lock);
244 \f
245 /* Called to reauthenticate the dtable when the auth port changes.  */
246
247 static void
248 reauth_dtable (void)
249 {
250   int d;
251
252   __mutex_lock (&_hurd_dtable_lock);
253
254   for (d = 0; d < _hurd_dtable.size; ++d)
255     {
256       struct _hurd_fd *const d = &_hurd_dtable.d[d];
257       mach_port_t new, newctty;
258       
259       /* Take the descriptor cell's lock.  */
260       __spin_lock (&cell->port.lock);
261       
262       /* Reauthenticate the descriptor's port.  */
263       if (d->port.port != MACH_PORT_NULL &&
264           ! __io_reauthenticate (d->port.port) &&
265           ! __USEPORT (AUTH, __auth_user_authenticate (port,
266                                                        d->port.port, &new)))
267         {
268           /* Replace the port in the descriptor cell
269              with the newly reauthenticated port.  */
270
271           if (cell->ctty.port != MACH_PORT_NULL &&
272               ! __io_reauthenticate (cell->ctty.port) &&
273               ! _HURD_PORT_USE (&_hurd_auth,
274                                 __auth_user_authenticate (port,
275                                                           cell->ctty.port,
276                                                           &newctty)))
277             _hurd_port_set (&d->ctty, newctty);
278
279           _hurd_port_locked_set (&d->port, new);
280         }
281       else
282         /* Lost.  Leave this descriptor cell alone.  */
283         __spin_unlock (&cell->port.lock);
284     }
285
286   __mutex_unlock (&_hurd_dtable_lock);
287 }
288
289 text_set_element (_hurd_reauth_hook, reauth_dtable);
290 \f
291 static void
292 rectty_dtable (mach_port_t cttyid)
293 {
294   int d;
295   
296   __mutex_lock (&_hurd_dtable_lock);
297
298   for (d = 0; d < _hurd_dtable.size; ++d)
299     {
300       struct _hurd_fd *const d = &_hurd_dtable.d[d];
301       mach_port_t newctty;
302
303       if (cttyid == MACH_PORT_NULL)
304         /* We now have no controlling tty at all.  */
305         newctty = MACH_PORT_NULL;
306       else
307         _HURD_PORT_USE (&d->port,
308                         ({ mach_port_t id;
309                            /* Get the io object's cttyid port.  */
310                            if (! __term_getctty (port, &id))
311                              {
312                                if (id == cttyid && /* Is it ours?  */
313                                    /* Get the ctty io port.  */
314                                    __term_become_ctty (port, _hurd_pid,
315                                                        _hurd_pgrp,
316                                                        _hurd_msgport,
317                                                        &newctty))
318                                  /* XXX it is our ctty but the call failed? */
319                                  newctty = MACH_PORT_NULL;
320                                __mach_port_deallocate (__mach_task_self, id);
321                              }
322                            else
323                              newctty = MACH_PORT_NULL;
324                            0;
325                          }));
326
327       /* Install the new ctty port.  */
328       _hurd_port_set (&d->ctty, newctty);
329     }
330
331   __mutex_unlock (&_hurd_dtable_lock);
332 }
333
334
335 /* Make FD be the controlling terminal.
336    This function is called for `ioctl (fd, TIOCSTTY)'.  */
337
338 static int
339 tiocstty (int fd,
340           int request,          /* Always TIOCSTTY.  */
341           void *arg)            /* Not used.  */
342 {
343   io_t ctty;
344   mach_port_t cttyid;
345   error_t err;
346   int i;
347
348   /* Get FD's cttyid port, unless it is already ours.  */
349   err = _HURD_DPORT_USE (fd,
350                          ctty ? EADDRINUSE : __term_getctty (port, &cttyid));
351   if (err == EADDRINUSE)
352     /* FD is already the ctty.  Nothing to do.  */
353     return 0;
354   else if (err)
355     return err;
356
357   /* Make it our own.  */
358   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); /* Consumes ref.  */
359
360   /* Reset all the ctty ports in all the descriptors.  */
361   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID], (rectty_dtable (port), 0));
362 }
363 _HURD_HANDLE_IOCTL (tiocstty, TIOCSTTY);
364
365 /* Dissociate from the controlling terminal.  */
366
367 static int
368 tiocnoctty (int fd,
369             int request,        /* Always TIONOCTTY.  */
370             void *arg)          /* Not used.  */
371 {
372   /* XXX should verify that FD is ctty and return EINVAL? */
373
374   /* Clear our cttyid port cell.  */
375   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
376
377   /* Reset all the ctty ports in all the descriptors.  */
378   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID],
379                   (rectty_dtable (MACH_PORT_NULL), 0));
380
381   return 0;
382 }
383 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);