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