Fix Hurd tiocsctty change.
[platform/upstream/glibc.git] / hurd / dtable.c
1 /* Copyright (C) 1991,92,93,94,95,96,97,99 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 Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the 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    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <hurd.h>
20 #include <hurd/term.h>
21 #include <hurd/fd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <cthreads.h>           /* For `struct mutex'.  */
27 #include "set-hooks.h"
28 #include "hurdmalloc.h"         /* XXX */
29
30
31 struct mutex _hurd_dtable_lock = MUTEX_INITIALIZER; /* XXX ld bug; must init */
32 struct hurd_fd **_hurd_dtable;
33 int _hurd_dtablesize;
34
35
36 DEFINE_HOOK (_hurd_fd_subinit, (void));
37
38 /* Initialize the file descriptor table at startup.  */
39
40 static void
41 init_dtable (void)
42 {
43   int i;
44
45   __mutex_init (&_hurd_dtable_lock);
46
47   /* The initial size of the descriptor table is that of the passed-in
48      table.  It will be expanded as necessary up to _hurd_dtable_rlimit.  */
49   _hurd_dtablesize = _hurd_init_dtablesize;
50
51   /* Allocate the vector of pointers.  */
52   _hurd_dtable = malloc (_hurd_dtablesize * sizeof (*_hurd_dtable));
53   if (_hurd_dtablesize != 0 && _hurd_dtable == NULL)
54     __libc_fatal ("hurd: Can't allocate file descriptor table\n");
55
56   /* Initialize the descriptor table.  */
57   for (i = 0; (unsigned int) i < _hurd_init_dtablesize; ++i)
58     {
59       if (_hurd_init_dtable[i] == MACH_PORT_NULL)
60         /* An unused descriptor is marked by a null pointer.  */
61         _hurd_dtable[i] = NULL;
62       else
63         {
64           /* Allocate a new file descriptor structure.  */
65           struct hurd_fd *new = malloc (sizeof (struct hurd_fd));
66           if (new == NULL)
67             __libc_fatal ("hurd: Can't allocate initial file descriptors\n");
68
69           /* Initialize the port cells.  */
70           _hurd_port_init (&new->port, MACH_PORT_NULL);
71           _hurd_port_init (&new->ctty, MACH_PORT_NULL);
72
73           /* Install the port in the descriptor.
74              This sets up all the ctty magic.  */
75           _hurd_port2fd (new, _hurd_init_dtable[i], 0);
76
77           _hurd_dtable[i] = new;
78         }
79     }
80
81   /* Clear out the initial descriptor table.
82      Everything must use _hurd_dtable now.  */
83   __vm_deallocate (__mach_task_self (),
84                    (vm_address_t) _hurd_init_dtable,
85                    _hurd_init_dtablesize * sizeof (_hurd_init_dtable[0]));
86   _hurd_init_dtable = NULL;
87   _hurd_init_dtablesize = 0;
88
89   /* Initialize the remaining empty slots in the table.  */
90   for (; i < _hurd_dtablesize; ++i)
91     _hurd_dtable[i] = NULL;
92
93   /* Run things that want to run after the file descriptor table
94      is initialized.  */
95   RUN_HOOK (_hurd_fd_subinit, ());
96
97   (void) &init_dtable;          /* Avoid "defined but not used" warning.  */
98 }
99
100 text_set_element (_hurd_subinit, init_dtable);
101
102 /* XXX when the linker supports it, the following functions should all be
103    elsewhere and just have text_set_elements here.  */
104 \f
105 /* Called by `getdport' to do its work.  */
106
107 static file_t
108 get_dtable_port (int fd)
109 {
110   struct hurd_fd *d = _hurd_fd_get (fd);
111   file_t dport;
112
113   if (!d)
114     return __hurd_fail (EBADF), MACH_PORT_NULL;
115
116   HURD_CRITICAL_BEGIN;
117
118   dport = HURD_PORT_USE (&d->port,
119                          ({
120                            error_t err;
121                            mach_port_t outport;
122                            err = __mach_port_mod_refs (__mach_task_self (),
123                                                        port,
124                                                        MACH_PORT_RIGHT_SEND,
125                                                        1);
126                            if (err)
127                              {
128                                errno = err;
129                                outport = MACH_PORT_NULL;
130                              }
131                            else
132                              outport = port;
133                            outport;
134                          }));
135
136   HURD_CRITICAL_END;
137
138   return dport;
139 }
140
141 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
142 \f
143 #include <hurd/signal.h>
144
145 /* We are in the child fork; the dtable lock is still held.
146    The parent has inserted send rights for all the normal io ports,
147    but we must recover ctty-special ports for ourselves.  */
148 static error_t
149 fork_child_dtable (void)
150 {
151   error_t err;
152   int i;
153
154   err = 0;
155
156   for (i = 0; !err && i < _hurd_dtablesize; ++i)
157     {
158       struct hurd_fd *d = _hurd_dtable[i];
159       if (d == NULL)
160         continue;
161
162       /* No other thread is using the send rights in the child task.  */
163       d->port.users = d->ctty.users = NULL;
164
165       if (d->ctty.port != MACH_PORT_NULL)
166         {
167           /* There was a ctty-special port in the parent.
168              We need to get one for ourselves too.  */
169           __mach_port_deallocate (__mach_task_self (), d->ctty.port);
170           err = __term_open_ctty (d->port.port, _hurd_pid, _hurd_pgrp,
171                                   &d->ctty.port);
172           if (err)
173             d->ctty.port = MACH_PORT_NULL;
174         }
175
176       /* XXX for each fd with a cntlmap, reauth and re-map_cntl.  */
177     }
178   return err;
179
180   (void) &fork_child_dtable;    /* Avoid "defined but not used" warning.  */
181 }
182
183 data_set_element (_hurd_fork_locks, _hurd_dtable_lock); /* XXX ld bug: bss */
184 text_set_element (_hurd_fork_child_hook, fork_child_dtable);
185 \f
186 /* Called when our process group has changed.  */
187
188 static void
189 ctty_new_pgrp (void)
190 {
191   int i;
192
193   HURD_CRITICAL_BEGIN;
194   __mutex_lock (&_hurd_dtable_lock);
195
196   if (__USEPORT (CTTYID, port == MACH_PORT_NULL))
197     {
198       /* We have no controlling terminal.  If we haven't had one recently,
199          but our pgrp is being pointlessly diddled anyway, then we will
200          have nothing to do in the loop below because no fd will have a
201          ctty port at all.
202
203          More likely, a setsid call is responsible both for the change
204          in pgrp and for clearing the cttyid port.  In that case, setsid
205          held the dtable lock while updating the dtable to clear all the
206          ctty ports, and ergo must have finished doing so before we run here.
207          So we can be sure, again, that the loop below has no work to do.  */
208     }
209   else
210     for (i = 0; i < _hurd_dtablesize; ++i)
211       {
212         struct hurd_fd *const d = _hurd_dtable[i];
213         struct hurd_userlink ulink, ctty_ulink;
214         io_t port, ctty;
215
216         if (d == NULL)
217           /* Nothing to do for an unused descriptor cell.  */
218           continue;
219
220         port = _hurd_port_get (&d->port, &ulink);
221         ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
222
223         if (ctty != MACH_PORT_NULL)
224           {
225             /* This fd has a ctty-special port.  We need a new one, to tell
226                the io server of our different process group.  */
227             io_t new;
228             if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
229               new = MACH_PORT_NULL;
230             _hurd_port_set (&d->ctty, new);
231           }
232
233         _hurd_port_free (&d->port, &ulink, port);
234         _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
235       }
236
237   __mutex_unlock (&_hurd_dtable_lock);
238   HURD_CRITICAL_END;
239
240   (void) &ctty_new_pgrp;        /* Avoid "defined but not used" warning.  */
241 }
242
243 text_set_element (_hurd_pgrp_changed_hook, ctty_new_pgrp);
244 \f
245 /* Called to reauthenticate the dtable when the auth port changes.  */
246
247 static void
248 reauth_dtable (void)
249 {
250   int i;
251
252   HURD_CRITICAL_BEGIN;
253   __mutex_lock (&_hurd_dtable_lock);
254
255   for (i = 0; i < _hurd_dtablesize; ++i)
256     {
257       struct hurd_fd *const d = _hurd_dtable[i];
258       mach_port_t new, newctty, ref;
259
260       if (d == NULL)
261         /* Nothing to do for an unused descriptor cell.  */
262         continue;
263
264       ref = __mach_reply_port ();
265
266       /* Take the descriptor cell's lock.  */
267       __spin_lock (&d->port.lock);
268
269       /* Reauthenticate the descriptor's port.  */
270       if (d->port.port != MACH_PORT_NULL &&
271           ! __io_reauthenticate (d->port.port,
272                                  ref, MACH_MSG_TYPE_MAKE_SEND) &&
273           ! __USEPORT (AUTH, __auth_user_authenticate
274                        (port,
275                         ref, MACH_MSG_TYPE_MAKE_SEND,
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,
283                                      ref, MACH_MSG_TYPE_MAKE_SEND) &&
284               ! __USEPORT (AUTH, __auth_user_authenticate
285                            (port,
286                             ref, MACH_MSG_TYPE_MAKE_SEND,
287                             &newctty)))
288             _hurd_port_set (&d->ctty, newctty);
289
290           _hurd_port_locked_set (&d->port, new);
291         }
292       else
293         /* Lost.  Leave this descriptor cell alone.  */
294         __spin_unlock (&d->port.lock);
295
296       __mach_port_destroy (__mach_task_self (), ref);
297     }
298
299   __mutex_unlock (&_hurd_dtable_lock);
300   HURD_CRITICAL_END;
301
302   (void) &reauth_dtable;        /* Avoid "defined but not used" warning.  */
303 }
304
305 text_set_element (_hurd_reauth_hook, reauth_dtable);