Formerly ../hurd/alloc-fd.c.~6~
[kopensolaris-gnu/glibc.git] / hurd / hurdexec.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 <errno.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <hurd.h>
26 #include <hurd/fd.h>
27
28 /* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
29    If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
30    ARGV and ENVP are terminated by NULL pointers.  */
31 error_t
32 _hurd_exec (task_t task, file_t file, 
33             char *const argv[], char *const envp[])
34 {
35   error_t err;
36   char *args, *env, *ap;
37   size_t argslen, envlen;
38   int ints[INIT_INT_MAX];
39   mach_port_t ports[_hurd_nports];
40   struct _hurd_port_userlink ulink_ports[_hurd_nports];
41   file_t *dtable;
42   int dtablesize;
43   struct _hurd_port **dtable_cells, **dtable_ctty_cells;
44   struct _hurd_port_userlink *ulink_dtable, *ulink_dtable_ctty;
45   int i;
46   char *const *p;
47   struct _hurd_sigstate *ss;
48   mach_port_t *please_dealloc, *pdp;
49
50
51   /* Pack the arguments into an array with nulls separating the elements.  */
52   argslen = 0;
53   p = argv;
54   while (*p != NULL)
55     argslen += strlen (*p++) + 1;
56   args = __alloca (argslen);
57   ap = args;
58   for (p = argv; *p != NULL; ++p)
59     ap = __memccpy (ap, *p, '\0', ULONG_MAX);
60
61   /* Pack the environment into an array with nulls separating elements.  */
62   envlen = 0;
63   p = envp;
64   while (*p != NULL)
65     envlen += strlen (*p++) + 1;
66   env = __alloca (envlen);
67   ap = env;
68   for (p = envp; *p != NULL; ++p)
69     ap = __memccpy (ap, *p, '\0', ULONG_MAX);
70
71   /* Load up the ports to give to the new program.  */
72   for (i = 0; i < _hurd_nports; ++i)
73     ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
74
75   /* Load up the ints to give the new program.  */
76   for (i = 0; i < INIT_INT_MAX; ++i)
77     switch (i)
78       {
79       case INIT_UMASK:
80         ints[i] = _hurd_umask;
81         break;
82
83       case INIT_SIGMASK:
84       case INIT_SIGIGN:
85       case INIT_SIGPENDING:
86         /* We will set these all below.  */
87         break;
88
89       default:
90         ints[i] = 0;
91       }
92
93   ss = _hurd_thread_sigstate (__mach_thread_self ());
94   ints[INIT_SIGMASK] = ss->blocked;
95   ints[INIT_SIGPENDING] = ss->pending;
96   ints[INIT_SIGIGN] = 0;
97   for (i = 1; i < NSIG; ++i)
98     if (ss->actions[i].sa_handler == SIG_IGN)
99       ints[INIT_SIGIGN] |= __sigmask (i);
100
101   /* We hold the sigstate lock until the exec has failed so that no signal
102      can arrive between when we pack the blocked and ignored signals, and
103      when the exec actually happens.  A signal handler could change what
104      signals are blocked and ignored.  Either the change will be reflected
105      in the exec, or the signal will never be delivered.  */
106   
107   /* Pack up the descriptor table to give the new program.  */
108   __mutex_lock (&_hurd_dtable_lock);
109
110   dtablesize = _hurd_dtable.d ? _hurd_dtable.size : _hurd_init_dtablesize;
111
112   /* Request the exec server to deallocate some ports from us if the exec
113      succeeds.  The init ports and descriptor ports will arrive in the
114      new program's exec_startup message.  If we failed to deallocate
115      them, the new program would have duplicate user references for them.
116      But we cannot deallocate them ourselves, because we must still have
117      them after a failed exec call.  */
118   please_dealloc = __alloca ((_hurd_nports + (2 * dtablesize)
119                              * sizeof (mach_port_t));
120   pdp = please_dealloc;
121
122   if (_hurd_dtable.d != NULL)
123     {
124       dtable = __alloca (dtablesize * sizeof (dtable[0]));
125       dtable_ctty = __alloca (dtablesize * sizeof (dtable[0]));
126       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
127       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
128       ulink_dtable_ctty = __alloca (dtablesize * sizeof (ulink_dtable[0]));
129       dtable_ctty_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
130       for (i = 0; i < dtablesize; ++i)
131         {
132           struct _hurd_fd *const d = _hurd_dtable.d[i];
133           __spin_lock (&d->port.lock);
134           if (d->port.port != MACH_PORT_NULL)
135             *pdp++ = d->port.port;
136           if (d->flags & FD_CLOEXEC)
137             {
138               /* This descriptor is marked to be closed on exec.
139                  So don't pass it to the new program.  */
140               dtable[i] = MACH_PORT_NULL;
141               __spin_unlock (&d->port.lock);
142             }
143           else
144             {
145               /* If this is a descriptor to our controlling tty,
146                  we want to give the normal port, not the foreground port.  */
147               dtable[i] = _hurd_port_get (&d->ctty, &ulink_dtable[i]);
148               if (dtable[i] == MACH_PORT_NULL)
149                 {
150                   dtable[i] = _hurd_port_locked_get (&d->port,
151                                                      &ulink_dtable[i]);
152                   dtable_cells[i] = &d->port;
153                 }
154               else
155                 {
156                   __spin_unlock (&d->port.lock);
157                   dtable_cells[i] = &d->ctty;
158                 }
159             }
160         }
161     }
162   else
163     {
164       dtable = _hurd_init_dtable;
165       ulink_dtable = NULL;
166       dtable_cells = NULL;
167     }
168
169   /* The information is all set up now.  Try to exec the file.  */
170
171   {
172     mach_port_t please_dealloc[_hurd_nports + dtablesize];
173     mach_port_t *p = please_dealloc;
174
175     /* Request the exec server to deallocate some ports from us if the exec
176        succeeds.  The init ports and descriptor ports will arrive in the
177        new program's exec_startup message.  If we failed to deallocate
178        them, the new program would have duplicate user references for them.
179        But we cannot deallocate them ourselves, because we must still have
180        them after a failed exec call.  */
181
182     for (i = 0; i < _hurd_nports; ++i)
183       *p++ = ports[i];
184     for (i = 0; i < dtablesize; ++i)
185       *p++ = dtable[i];
186
187     err = __file_exec (file, __mach_task_self (),
188                        0,
189                        args, argslen, env, envlen,
190                        dtable, dtablesize, MACH_MSG_TYPE_COPY_SEND,
191                        ports, _hurd_nports, MACH_MSG_TYPE_COPY_SEND,
192                        ints, INIT_INT_MAX,
193                        please_dealloc, p - please_dealloc,
194                        NULL, 0);
195   }
196
197   /* Safe to let signals happen now.  */
198   __mutex_unlock (&ss->lock);
199
200   /* Release references to the standard ports.  */
201   for (i = 0; i < _hurd_nports; ++i)
202     _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
203
204   if (dealloc_dtable != NULL)
205     /* Release references to the file descriptor ports.  */
206     for (i = 0; i < dtablesize; ++i)
207       if (dtable[i] != MACH_PORT_NULL)
208         _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
209
210   return err;
211 }