Formerly ../hurd/dtable.c.~18~
[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 <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.
92    FLAGS are as for `open'; only O_NOCTTY 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_NOCTTY) && ! __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       struct _hurd_port *const id = &_hurd_ports[INIT_PORT_CTTYID];
157       __spin_lock (&id->lock);
158       if (id->port == MACH_PORT_NULL)
159         /* We have no controlling tty, so make this one it.  */
160         _hurd_port_locked_set (id, cttyid);
161       else
162         {
163           if (cttyid != id->port)
164             /* We have a controlling tty and this is not it.  */
165             is_ctty = 0;
166           /* Either we don't want CTTYID, or ID->port already is it.
167              So we don't need to change ID->port, and we
168              can release the reference to CTTYID.  */
169           __spin_unlock (&id->lock);
170           __mach_port_deallocate (__mach_task_self (), cttyid);
171         }
172     }
173
174   if (is_ctty && ! __term_become_ctty (port, _hurd_pid, _hurd_pgrp,
175                                        _hurd_msgport, &ctty))
176     {
177       /* Operations on CTTY return EBACKGROUND when we are not a
178          foreground user of the tty.  */
179       d->port.port = ctty;
180       ctty = port;
181     }
182   else
183     /* XXX if IS_CTTY, then this port is our ctty, but we are
184        not doing ctty style i/o because term_become_ctty barfed.
185        What to do?  */
186     /* No ctty magic happening here.  */
187     ctty = MACH_PORT_NULL;
188
189   _hurd_port_set (&d->ctty, ctty);
190 }
191 \f
192 /* Called by `getdport' to do its work.  */
193
194 static file_t
195 get_dtable_port (int fd)
196 {
197   file_t dport;
198   int err = _HURD_DPORT_USE (fd,
199                              __mach_port_mod_refs (__mach_task_self (),
200                                                    (dport = port),
201                                                    MACH_PORT_RIGHT_SEND,
202                                                    1));
203   if (err)
204     {
205       errno = err;
206       return MACH_PORT_NULL;
207     }
208   else
209     return dport;
210 }
211
212 text_set_element (_hurd_getdport_fn, get_dtable_port);
213 \f
214 /* Called on fork to install the dtable in NEWTASK.
215    The dtable lock is held.  */
216
217 static error_t
218 fork_dtable (task_t newtask)
219 {
220   error_t err;
221   int i;
222
223   err = 0;
224
225   for (i = 0; !err && i < _hurd_dtable.size; ++i)
226     {
227       int dealloc, dealloc_ctty;
228       io_t port = _hurd_port_get (&_hurd_dtable.d[i].port, &dealloc);
229       io_t ctty = _hurd_port_get (&_hurd_dtable.d[i].ctty, &dealloc_ctty);
230
231       if (port != MACH_PORT_NULL)
232         err = __mach_port_insert_right (newtask, port, port,
233                                         MACH_MSG_TYPE_COPY_SEND);
234       if (!err && ctty != MACH_PORT_NULL)
235         err = __mach_port_insert_right (newtask, ctty, ctty,
236                                         MACH_MSG_TYPE_COPY_SEND);
237
238       _hurd_port_free (&_hurd_dtable.d[i].port, &dealloc, port);
239       _hurd_port_free (&_hurd_dtable.d[i].ctty, &dealloc_ctty, ctty);
240
241       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
242     }
243   __mutex_unlock (&_hurd_dtable_lock);
244   return err;
245 }
246
247 text_set_element (_hurd_fork_hook, fork_dtable);
248 text_set_element (_hurd_fork_locks, _hurd_dtable_lock);
249 \f
250 /* Called to reauthenticate the dtable when the auth port changes.  */
251
252 static void
253 reauth_dtable (void)
254 {
255   int i;
256
257   __mutex_lock (&_hurd_dtable_lock);
258
259   for (i = 0; i < _hurd_dtable.size; ++i)
260     {
261       struct _hurd_fd *const d = &_hurd_dtable.d[i];
262       mach_port_t new, newctty;
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 static void
298 rectty_dtable (mach_port_t cttyid)
299 {
300   int i;
301   
302   __mutex_lock (&_hurd_dtable_lock);
303
304   for (i = 0; i < _hurd_dtable.size; ++i)
305     {
306       struct _hurd_fd *const d = &_hurd_dtable.d[i];
307       mach_port_t newctty;
308
309       if (cttyid == MACH_PORT_NULL)
310         /* We now have no controlling tty at all.  */
311         newctty = MACH_PORT_NULL;
312       else
313         _HURD_PORT_USE (&d->port,
314                         ({ mach_port_t id;
315                            /* Get the io object's cttyid port.  */
316                            if (! __term_getctty (port, &id))
317                              {
318                                if (id == cttyid && /* Is it ours?  */
319                                    /* Get the ctty io port.  */
320                                    __term_become_ctty (port, _hurd_pid,
321                                                        _hurd_pgrp,
322                                                        _hurd_msgport,
323                                                        &newctty))
324                                  /* XXX it is our ctty but the call failed? */
325                                  newctty = MACH_PORT_NULL;
326                                __mach_port_deallocate
327                                  (__mach_task_self (), (mach_port_t) id);
328                              }
329                            else
330                              newctty = MACH_PORT_NULL;
331                            0;
332                          }));
333
334       /* Install the new ctty port.  */
335       _hurd_port_set (&d->ctty, newctty);
336     }
337
338   __mutex_unlock (&_hurd_dtable_lock);
339 }
340 \f
341 #if 0
342
343 #include <sys/ioctl.h>
344
345
346 /* Make FD be the controlling terminal.
347    This function is called for `ioctl (fd, TCIOSCTTY)'.  */
348
349 static int
350 tiocsctty (int fd,
351            int request,         /* Always TCIOSCTTY.  */
352            void *arg)           /* Not used.  */
353 {
354   mach_port_t cttyid;
355   error_t err;
356
357   /* Get FD's cttyid port, unless it is already ours.  */
358   err = _HURD_DPORT_USE (fd,
359                          ctty ? EADDRINUSE : __term_getctty (port, &cttyid));
360   if (err == EADDRINUSE)
361     /* FD is already the ctty.  Nothing to do.  */
362     return 0;
363   else if (err)
364     return err;
365
366   /* Make it our own.  */
367   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); /* Consumes ref.  */
368
369   /* Reset all the ctty ports in all the descriptors.  */
370   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID], (rectty_dtable (port), 0));
371
372   return 0;
373 }
374 _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
375
376 #ifdef TIOCNOCTTY
377 /* Dissociate from the controlling terminal.  */
378
379 static int
380 tiocnoctty (int fd,
381             int request,        /* Always TIOCNOCTTY.  */
382             void *arg)          /* Not used.  */
383 {
384   /* XXX should verify that FD is ctty and return EINVAL? */
385
386   /* Clear our cttyid port cell.  */
387   _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
388
389   /* Reset all the ctty ports in all the descriptors.  */
390   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_CTTYID],
391                   (rectty_dtable (MACH_PORT_NULL), 0));
392
393   return 0;
394 }
395 _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
396 #endif
397
398 #endif