7929a7be5710a9e564062f7516e255216ed6d080
[kopensolaris-gnu/glibc.git] / hurd / hurd.h
1 /* Copyright (C) 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 #ifndef _HURD_H
20
21 #define _HURD_H 1
22
23 /* This is here because this file includes some other headers
24    and expects some non-ANSI, non-POSIX symbols to be defined.  */
25 #ifndef _GNU_SOURCE
26 #define _GNU_SOURCE
27 #endif
28 #include <features.h>
29
30
31 /* Get types, macros, constants and function declarations
32    for all Mach microkernel interaction.  */
33 #include <mach.h>
34 #include <mach/mig_errors.h>
35
36 /* Get types and constants necessary for Hurd interfaces.  */
37 #include <hurd/hurd_types.h>
38
39 /* Get MiG stub declarations for commonly used Hurd interfaces.  */
40 #include <hurd/auth.h>
41 #include <hurd/process.h>
42 #include <hurd/fs.h>
43 #include <hurd/io.h>
44 #include <hurd/msg.h>
45
46 #include <errno.h>
47 #define __hurd_fail(err)        (errno = (err), -1)
48
49 #define __spin_lock(lockaddr) /* no-op XXX */
50 #define __spin_unlock(lockaddr) /* no-op XXX */
51
52 #define __mutex_lock(lockaddr) /* no-op XXX */
53 #define __mutex_unlock(lockaddr) /* no-op XXX */
54
55 \f
56 /* Lightweight user references for ports.  */
57
58 /* Structure describing a cell containing a port.  With the lock held, a
59    user extracts PORT, and attaches his own link (in local storage) to the
60    USERS chain.  PORT can then safely be used.  When PORT is no longer
61    needed, with the lock held, the user removes his link from the chain.
62    If his link is the last, and PORT has changed since he fetched it, the
63    user deallocates the port he used.  */
64 struct _hurd_port
65   {
66 #ifdef noteven
67     spin_lock_t lock;           /* Locks rest.  */
68 #endif
69     struct _hurd_port_userlink *users; /* Chain of users; see below.  */
70     mach_port_t port;           /* Port. */
71   };
72
73 /* This structure is simply a doubly-linked list.
74    Users of a port cell are recorded by their presence in the list.  */   
75 struct _hurd_port_userlink
76   {
77     struct _hurd_port_userlink *next, **prevp;
78   };
79
80 /* Evaluate EXPR with the variable `port' bound to the port in PORTCELL.  */
81 #define _HURD_PORT_USE(portcell, expr)                                        \
82   ({ struct _hurd_port *const __p = (portcell);                               \
83      struct _hurd_port_userlink __link;                                       \
84      const mach_port_t port = _hurd_port_get (__p, &__link);                  \
85      __typeof(expr) __result = (expr);                                        \
86      _hurd_port_free (__p, &__link, port);                                    \
87      __result; })
88
89 /* Initialize *PORT to INIT.  */
90 static inline void
91 _hurd_port_init (struct _hurd_port *port, mach_port_t init)
92 {
93 #ifdef noteven
94   __spin_lock_init (&port->lock);
95 #endif
96   port->users = NULL;
97   port->port = init;
98 }
99
100 /* Get a reference to *PORT, which is locked.
101    Pass return value and LINK to _hurd_port_free when done.  */
102 static inline mach_port_t
103 _hurd_port_locked_get (struct _hurd_port *port,
104                        struct _hurd_port_userlink *link)
105 {
106   mach_port_t result;
107   result = port->port;
108   if (result != MACH_PORT_NULL)
109     {
110       link->next = port->users;
111       if (link->next)
112         link->next->prevp = &link->next;
113       link->prevp = &port->users;
114       port->users = link;
115     }
116   __spin_unlock (&port->lock);
117   return result;
118 }
119
120 /* Same, but locks PORT first.  */
121 static inline mach_port_t
122 _hurd_port_get (struct _hurd_port *port,
123                 struct _hurd_port_userlink *link)
124 {
125   __spin_lock (&port->lock);
126   return _hurd_port_locked_get (port, link);
127 }
128
129 /* Free a reference gotten with
130    `USED_PORT = _hurd_port_get (PORT, LINK);' */
131 static inline void
132 _hurd_port_free (struct _hurd_port *port,
133                  struct _hurd_port_userlink *link,
134                  mach_port_t used_port)
135 {
136   int dealloc;
137   __spin_lock (&port->lock);
138   /* We should deallocate USED_PORT if our chain has been detached from the
139      cell (and thus has a nil `prevp'), and there is no next link
140      representing another user reference to the same port we fetched.  */
141   dealloc = ! link->next && ! link->prevp;
142   /* Remove our link from the chain of current users.  */
143   if (link->prevp)
144     *link->prevp = link->next;
145   if (link->next)
146     link->next->prevp = link->prevp;
147   __spin_unlock (&port->lock);
148   if (dealloc)
149     __mach_port_deallocate (__mach_task_self (), used_port);
150 }
151
152 /* Set *PORT's port to NEWPORT.  NEWPORT's reference is consumed by PORT->port.
153    PORT->lock is locked.  */
154 static inline void
155 _hurd_port_locked_set (struct _hurd_port *port, mach_port_t newport)
156 {
157   mach_port_t old;
158   if (port->users == NULL)
159     old = port->port;
160   else
161     {
162       old = MACH_PORT_NULL;
163       /* Detach the chain of current users from the cell.  The last user to
164          remove his link from that chain will deallocate the old port.  */
165       port->users->prevp = NULL;
166       port->users = NULL;
167     }
168   port->port = newport;
169   __spin_unlock (&port->lock);
170   if (old != MACH_PORT_NULL)
171     __mach_port_deallocate (__mach_task_self (), old);
172 }
173
174 /* Same, but locks PORT first.  */
175 static inline void
176 _hurd_port_set (struct _hurd_port *port, mach_port_t newport)
177 {
178   __spin_lock (&port->lock);
179   return _hurd_port_locked_set (port, newport);
180 }
181 \f
182 /* Basic ports and info, initialized by startup.  */
183 extern struct _hurd_port *_hurd_ports;
184 extern unsigned int _hurd_nports;
185 extern volatile mode_t _hurd_umask;
186
187 /* Shorthand macro for referencing _hurd_ports.  */
188 #define __USEPORT(which, expr) \
189   _HURD_PORT_USE (&_hurd_ports[INIT_PORT_##which], (expr))
190
191 /* Base address and size of the initial stack set up by the exec server.
192    If using cthreads, this stack is deallocated in startup.
193    Not locked.  */
194 extern vm_address_t _hurd_stack_base;
195 extern vm_size_t _hurd_stack_size;
196
197 extern thread_t _hurd_msgport_thread;
198 extern mach_port_t _hurd_msgport; /* Locked by _hurd_siglock.  */
199
200 /* Not locked.  If we are using a real dtable, these are turned into that
201    and then cleared at startup.  If not, these are never changed after
202    startup.  */
203 extern mach_port_t *_hurd_init_dtable;
204 extern mach_msg_type_number_t _hurd_init_dtablesize;
205 \f
206 /* File descriptor table.  */
207
208
209 /* File descriptor structure.  */
210 struct _hurd_fd
211   {
212     struct _hurd_port port;     /* io server port.  */
213     int flags;                  /* fcntl flags; locked by port.lock.  */
214
215     /* Normal port to the ctty.  When `port' is our ctty, this is a port to
216        the same io object but which never returns EBACKGROUND; when not,
217        this is nil.  */
218     struct _hurd_port ctty;
219   };
220
221 /* Set up *FD to have PORT its server port, doing appropriate ctty magic.
222    Does no locking or unlocking.  */
223 extern void _hurd_port2fd (struct _hurd_fd *fd, io_t port, int flags);
224
225 /* Allocate a new file descriptor and install PORT in it (doing any
226    appropriate ctty magic); consumes a user reference on PORT.  FLAGS are
227    as for `open'; only O_NOCTTY is meaningful, but all are saved.
228
229    If the descriptor table is full, set errno, and return -1.
230    If DEALLOC is nonzero, deallocate PORT first.  */
231 extern int _hurd_intern_fd (io_t port, int flags, int dealloc);
232
233 /* Allocate a new file descriptor and return it, locked.
234    The new descriptor will not be less than FIRST_FD.  */
235 extern struct _hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd);
236
237
238 struct _hurd_dtable
239   {
240     int size;                   /* Number of elts in `d' array.  */
241
242     /* Uses of individual descriptors are not locked.  It is up to the user
243        to synchronize descriptor operations on a single descriptor.  */
244
245     struct _hurd_fd *d;
246   };
247
248 #ifdef noteven
249 extern struct mutex _hurd_dtable_lock; /* Locks next two.  */
250 #endif
251 extern struct _hurd_dtable _hurd_dtable;
252 extern int _hurd_dtable_rlimit; /* RLIM_OFILES: number of file descriptors.  */
253
254 /* If not NULL, pointed-to word is set when _hurd_dtable.d changes.
255    User who set `user_dealloc' should free the _hurd_dtable.d value
256    he used if his word is set when he is finished.
257    If NULL, the old value of _hurd_dtable.d is freed by the setter.  */
258 int *_hurd_dtable_user_dealloc;
259
260 static inline struct _hurd_dtable
261 _hurd_dtable_use (int *dealloc)
262 {
263   struct _hurd_dtable dtable;
264   __mutex_lock (&_hurd_dtable_lock);
265   _hurd_dtable_user_dealloc = dealloc;
266   dtable = _hurd_dtable;
267   __mutex_unlock (&_hurd_dtable_lock);
268   return dtable;
269 }
270
271 struct _hurd_dtable_resizes
272   {
273     size_t n;
274     void (*free) (void *);
275     void *terminator;
276   };
277 extern const struct _hurd_dtable_resizes _hurd_dtable_resizes;
278
279 static inline void
280 _hurd_dtable_done (struct _hurd_dtable dtable, int *dealloc)
281 {
282   __mutex_lock (&_hurd_dtable_lock);
283   if (_hurd_dtable_user_dealloc == dealloc)
284     _hurd_dtable_user_dealloc = NULL;
285   __mutex_unlock (&_hurd_dtable_lock);
286   if (*dealloc)
287     /* _hurd_dtable_resizes is a symbol set.
288        setrlimit.c gives it one element: free.
289        If setrlimit is not linked in, *DEALLOC
290        will never get set, so we will never get here.
291        This hair avoids linking in free if we don't need it.  */
292     (*_hurd_dtable_resizes.free) (dtable.d);
293 }
294
295 /* Return the descriptor cell for FD in DTABLE, locked.  */
296 static inline struct _hurd_fd *
297 _hurd_dtable_fd (int fd, struct _hurd_dtable dtable)
298 {
299   if (fd < 0 || fd >= dtable.size)
300     return NULL;
301   else
302     {
303       struct _hurd_fd *cell = &dtable.d[fd];
304       __spin_lock (&cell->port.lock);
305       if (cell->port.port == MACH_PORT_NULL)
306         {
307           __spin_unlock (&cell->port.lock);
308           return NULL;
309         }
310       return cell;
311     }
312 }
313
314 struct _hurd_fd_user
315   {
316     struct _hurd_dtable dtable;
317     struct _hurd_fd *d;
318   };
319
320 /* Returns the descriptor cell for FD, locked.  The passed DEALLOC word and
321    returned structure hold onto the descriptor table to it doesn't move
322    while you might be using a pointer into it.  */
323 static inline struct _hurd_fd_user
324 _hurd_fd (int fd, int *dealloc)
325 {
326   struct _hurd_fd_user d;
327   d.dtable = _hurd_dtable_use (dealloc);
328   d.d = _hurd_dtable_fd (fd, d.dtable);
329   if (d.d == NULL)
330     _hurd_dtable_done (d.dtable, dealloc);
331   return d;
332 }
333
334 static inline void
335 _hurd_fd_done (struct _hurd_fd_user d, int *dealloc)
336 {
337   _hurd_dtable_done (d.dtable, dealloc);
338 }
339
340 /* Evaluate EXPR with the variable `port' bound to the port to FD,
341    and `ctty' bound to the ctty port.  */
342    
343 #define _HURD_DPORT_USE(fd, expr)                                             \
344   ({ int __dealloc_dt;                                                        \
345      error_t __result;                                                        \
346      struct _hurd_fd_user __d = _hurd_fd (fd, &__dealloc_dt);                 \
347      if (__d.d == NULL)                                                       \
348        __result = EBADF;                                                      \
349      else                                                                     \
350        {                                                                      \
351          struct _hurd_port_userlink __ulink, __ctty_ulink;                    \
352          io_t port = _hurd_port_locked_get (&__d.d->port, &__ulink);          \
353          io_t ctty = _hurd_port_locked_get (&__d.d->ctty, &__ctty_ulink);     \
354          __result = (expr);                                                   \
355          _hurd_port_free (&__d.d->port, &__ulink, port);                      \
356          if (ctty != MACH_PORT_NULL)                                          \
357            _hurd_port_free (&__d.d->ctty, &__ctty_ulink, ctty);               \
358          _hurd_fd_done (__d, &__dealloc_dt);                                  \
359        }                                                                      \
360       __result;                                                               \
361    })                                                                         \
362
363 static inline int
364 __hurd_dfail (int fd, error_t err)
365 {
366   switch (err)
367     {
368     case MACH_SEND_INVALID_DEST: /* The server has disappeared!  */
369 #ifdef notyet
370       _hurd_raise_signal (NULL, SIGLOST, fd);
371 #else
372       abort ();
373 #endif
374       break;
375     case EPIPE:
376 #ifdef notyet
377       _hurd_raise_signal (NULL, SIGPIPE, fd);
378 #else
379       abort ();
380 #endif
381       break;
382     default:
383       return __hurd_fail (err);
384     }
385 }
386
387 extern io_t __getdport (int);
388 extern io_t getdport (int);
389 \f
390 /* Return the socket server for sockaddr domain DOMAIN.  */
391 extern socket_t _hurd_socket_server (int domain);
392
393
394 /* Current process IDs.  */
395 extern pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp;
396 extern int _hurd_orphaned;
397 #ifdef noteven
398 extern struct mutex _hurd_pid_lock; /* Locks above.  */
399 #endif
400
401
402 /* User and group IDs.  */
403 struct _hurd_id_data
404   {
405 #ifdef noteven
406     mutex_t lock;
407 #endif
408
409     int valid;                  /* If following data are up to date.  */
410
411     struct
412       {
413         uid_t *uids;
414         gid_t *gids;
415         unsigned int nuids, ngids;
416       } gen, aux;
417
418     auth_t rid_auth;            /* Cache used by access.  */
419   };
420 extern struct _hurd_id_data _hurd_id;
421 /* Update _hurd_id (caller should be holding the lock).  */
422 extern error_t _hurd_check_ids (void);
423
424
425 /* Unix `data break', for brk and sbrk.
426    If brk and sbrk are not used, this info will not be initialized or used.  */
427 extern vm_address_t _hurd_brk;  /* Data break.  */
428 extern vm_address_t _hurd_data_end; /* End of allocated space.  */
429 #ifdef noteven
430 extern struct mutex _hurd_brk_lock; /* Locks brk and data_end.  */
431 #endif
432 extern int _hurd_set_data_limit (const struct rlimit *);
433
434 /* Set the data break; the brk lock must
435    be held, and is released on return.  */
436 extern int _hurd_set_brk (vm_address_t newbrk);
437
438 /* Resource limit on core file size.  Enforced by hurdsig.c.  */
439 extern int _hurd_core_limit;
440 \f
441 #include <signal.h>
442
443 /* Per-thread signal state.  */
444 struct _hurd_sigstate
445   {
446     /* XXX should be in cthread variable (?) */
447     thread_t thread;
448     struct _hurd_sigstate *next; /* Linked-list of thread sigstates.  */
449
450 #ifdef noteven
451     struct mutex lock;          /* Locks the rest of this structure.  */
452 #endif
453     sigset_t blocked;
454     sigset_t pending;
455     struct sigaction actions[NSIG];
456     struct sigaltstack sigaltstack;
457     int sigcodes[NSIG];         /* Codes for pending signals.  */
458
459     int suspended;              /* If nonzero, sig_post signals `arrived'.  */
460 #ifdef noteven
461     struct condition arrived;
462 #endif
463
464 #if 0
465     int vforked;                /* Nonzero if this thread is a vfork child.  */
466     struct
467       {
468         process_t proc;
469         file_t ccdir, cwdir, crdir, auth;
470         mode_t umask;
471         int ctty_fstype;
472         fsid_t ctty_fsid;
473         ino_t ctty_fileid;
474         struct _hurd_dtable *dtable;
475         jmp_buf continuation;
476       } *vfork_saved;
477 #endif
478
479     /* Not locked.  Used only by this thread,
480        or by signal thread with this thread suspended.  */
481     volatile mach_port_t intr_port; /* Port interruptible RPC was sent on.  */
482     volatile int intr_restart;  /* If nonzero, restart interrupted RPC.  */
483   };
484 /* Linked list of states of all threads
485    whose state has been inquired about.  */
486 extern struct _hurd_sigstate *_hurd_sigstates;
487 extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */
488 /* Get the sigstate of a given thread, taking its lock.  */
489 extern struct _hurd_sigstate *_hurd_thread_sigstate (thread_t);
490
491 /* Thread to receive process-global signals.  */
492 extern thread_t _hurd_sigthread;
493
494 /* Called by the machine-dependent exception handler.  */
495 extern void _hurd_exc_post_signal (thread_t, int sig, int code);
496
497 /* SS->lock is held on entry, and released before return.  */
498 extern void _hurd_internal_post_signal (struct _hurd_sigstate *ss,
499                                         int signo, int sigcode,
500                                         sigset_t *restore_blocked);
501
502 /* Function run by the signal thread to receive from the signal port.  */
503 extern void _hurd_msgport_receive (void);
504
505
506 #ifdef notyet
507 /* Perform interruptible RPC CALL on PORT.
508    The args in CALL should be constant or local variable refs.
509    They may be evaluated many times, and must not change.
510    PORT must not be deallocated before this RPC is finished.  */
511 #define HURD_EINTR_RPC(port, call) \
512   ({
513     error_t __err;
514     struct _hurd_sigstate *__ss
515       = _hurd_thread_sigstate (__mach_thread_self ());
516     __mutex_unlock (&__ss->lock); /* Lock not needed.  */
517     /* If we get a signal and should return EINTR, the signal thread will
518        clear this.  The RPC might return EINTR when some other thread gets
519        a signal, in which case we want to restart our call.  */
520     __ss->intr_restart = 1;
521     /* This one needs to be last.  A signal can arrive before here,
522        and if intr_port were set before intr_restart is
523        initialized, the signal thread would get confused.  */
524     __ss->intr_port = (port);
525     /* A signal may arrive here, after intr_port is set,
526        but before the mach_msg system call.  The signal handler might do an
527        interruptible RPC, and clobber intr_port; then it would not be set
528        properly when we actually did send the RPC, and a later signal
529        wouldn't interrupt that RPC.  So, _hurd_run_sighandler saves
530        intr_port in the sigcontext, and sigreturn restores it.  */
531   __do_call:
532     switch (__err = (call))
533       {
534       case EINTR:               /* RPC went out and was interrupted.  */
535       case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
536         if (__ss->intr_restart)
537           /* Restart the interrupted call.  */
538           goto __do_call;
539         /* FALLTHROUGH */
540       case MACH_RCV_PORT_DIED:
541         /* Server didn't respond to interrupt_operation,
542            so the signal thread destroyed the reply port.  */
543         __err = EINTR;
544         break;
545       }
546     __ss->intr_port = MACH_PORT_NULL;
547     __err;
548   })
549
550 #endif /* notyet */
551
552 /* Mask of signals that cannot be caught, blocked, or ignored.  */
553 #define _SIG_CANT_MASK  (__sigmask (SIGSTOP) | __sigmask (SIGKILL))
554
555 /* Do an RPC to a process's message port.
556
557    Each argument is an expression which returns an error code; each
558    expression may be evaluated several times.  FETCH_MSGPORT_EXPR should
559    fetch the appropriate message port and store it in the local variable
560    `msgport'.  FETCH_REFPORT_EXPR should fetch the appropriate message port
561    and store it in the local variable `refport' (if no reference port is
562    needed in the call, then FETCH_REFPORT_EXPR should be simply
563    KERN_SUCCESS or 0).  Both of these are assumed to create user
564    references, which this macro deallocates.  RPC_EXPR should perform the
565    desired RPC operation using `msgport' and `refport'.
566
567    The reason for the complexity is that a process's message port and
568    reference port may change between fetching those ports and completing an
569    RPC using them (usually they change only when a process execs).  The RPC
570    will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can
571    send the RPC request; or with MIG_SERVER_DIED if the msgport was
572    destroyed after we sent the RPC request but before it was serviced.  In
573    either of these cases, we retry the entire operation, discarding the old
574    message and reference ports and fetch them anew.  */
575
576 #define _HURD_MSGPORT_RPC(fetch_msgport_expr, fetch_refport_expr, rpc_expr)   \
577 ({                                                                            \
578     error_t __err;                                                            \
579     mach_port_t msgport, refport = MACH_PORT_NULL;                            \
580     do                                                                        \
581       {                                                                       \
582         /* Get the message port.  */                                          \
583         if (__err = (fetch_msgport_expr))                                     \
584           break;                                                              \
585         /* Get the reference port.  */                                        \
586         if (__err = (fetch_refport_expr))                                     \
587           {                                                                   \
588             /* Couldn't get it; deallocate MSGPORT and fail.  */              \
589             mach_port_deallocate (__mach_task_self (), msgport);              \
590             break;                                                            \
591           }                                                                   \
592         __err = (rpc_expr);                                                   \
593         mach_port_deallocate (__mach_task_self (), msgport);                  \
594         if (refport != MACH_PORT_NULL)                                        \
595           mach_port_deallocate (__mach_task_self (), refport);                \
596       } while (__err != MACH_SEND_INVALID_DEST &&                             \
597                __err != MIG_SERVER_DIED);                                     \
598     __err;                                                                    \
599 })
600 \f
601 /* Calls to get and set basic ports.  */
602 extern process_t getproc (void);
603 extern file_t getccdir (void), getcwdir (void), getcrdir (void);
604 extern auth_t getauth (void);
605 extern int setproc (process_t);
606 extern int setcwdir (file_t), setcrdir (file_t);
607
608 /* Does reauth with the proc server and fd io servers.  */
609 extern int __setauth (auth_t), setauth (auth_t);
610
611
612 extern error_t __hurd_path_split (file_t crdir, file_t cwdir,
613                                   const char *file,
614                                   file_t *dir, char **name);
615 extern error_t hurd_path_split (file_t crdir, file_t cwdir,
616                                 const char *file,
617                                 file_t *dir, char **name);
618 extern error_t __hurd_path_lookup (file_t crdir, file_t cwdir,
619                                    const char *file,
620                                    int flags, mode_t mode,
621                                    file_t *port);
622 extern error_t hurd_path_lookup (file_t crdir, file_t cwdir,
623                                  const char *filename,
624                                  int flags, mode_t mode,
625                                  file_t *port);
626
627 /* Returns a port to the directory, and sets *NAME to the file name.  */
628 extern file_t __path_split (const char *file, char **name);
629 extern file_t path_split (const char *file, char **name);
630
631 /* Looks up FILE with the given FLAGS and MODE (as for dir_pathtrans).  */
632 extern file_t __path_lookup (const char *file, int flags, mode_t mode);
633 extern file_t path_lookup (const char *file, int flags, mode_t mode);
634
635 /* Open a file descriptor on a port.  */
636 extern int openport (io_t port, int flags);
637
638 /* Execute a file, replacing the current program image.  */
639 extern error_t _hurd_exec (file_t file,
640                            char *const argv[],
641                            char *const envp[]);
642
643 /* Inform the proc server we have exitted with STATUS, and kill the
644    task thoroughly.  This function never returns, no matter what.  */
645 extern volatile void _hurd_exit (int status);
646
647 /* Initialize the library data structures from the
648    ints and ports passed to us by the exec server.
649    Then vm_deallocate PORTARRAY and INTARRAY.  */
650 extern void _hurd_init (int flags, char **argv,
651                         mach_port_t *portarray, size_t portarraysize,
652                         int *intarray, size_t intarraysize);
653
654 /* Do startup handshaking with the proc server.  */
655 extern void _hurd_proc_init (char **argv);
656
657 /* Fetch the host privileged port and device master port from the proc
658    server.  They are fetched only once and then cached in the variables
659    below.  A special program that gets them from somewhere other than the
660    proc server (such as a bootstrap filesystem) can set these variables at
661    startup to install the ports.  */
662 extern kern_return_t get_privileged_ports (host_priv_t *host_priv_ptr,
663                                            device_t *device_master_ptr);
664 extern mach_port_t _hurd_host_priv, _hurd_device_master;
665
666 /* Convert between PIDs and task ports.  */
667 extern pid_t __task2pid (task_t), task2pid (task_t);
668 extern task_t __pid2task (pid_t), pid2task (pid_t);
669 \f
670 /* User-registered handlers for specific `ioctl' requests.  */
671
672 struct ioctl_handler
673   {
674     int first_request, last_request; /* Range of handled request values.  */
675
676     int (*handler) (int fd, int request, void *arg);
677
678     struct ioctl_handler *next; /* Next handler.  */
679   };
680
681 /* Define a library-internal handler for ioctl commands
682    between FIRST and LAST inclusive.  */
683
684 #define _HURD_HANDLE_IOCTLS(handler, first, last)                             \
685   static const struct ioctl_handler handler##_ioctl_handler =                 \
686     { first, last, handler, NULL };                                           \
687   text_set_element (_hurd_ioctl_handler_lists, ##handler##_ioctl_handler)
688
689 /* Define a library-internal handler for a single ioctl command.  */
690 #define _HURD_HANDLE_IOCTL(handler, ioctl) \
691   _HURD_HANDLE_IOCTLS (handler, (ioctl), (ioctl))
692
693
694 #endif  /* hurd.h */