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