Formerly ../hurd/hurdkill.c.~5~
[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 #include <hurd/signal.h>
28
29 /* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
30    If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
31    ARGV and ENVP are terminated by NULL pointers.  */
32 error_t
33 _hurd_exec (task_t task, file_t file, 
34             char *const argv[], char *const envp[])
35 {
36   error_t err;
37   char *args, *env, *ap;
38   size_t argslen, envlen;
39   int ints[INIT_INT_MAX];
40   mach_port_t ports[_hurd_nports];
41   struct hurd_userlink ulink_ports[_hurd_nports];
42   file_t *dtable, *dtable_ctty;
43   int dtablesize;
44   struct hurd_port **dtable_cells, **dtable_ctty_cells;
45   struct hurd_userlink *ulink_dtable, *ulink_dtable_ctty;
46   int i;
47   char *const *p;
48   struct hurd_sigstate *ss;
49   mach_port_t *please_dealloc, *pdp;
50
51
52   /* Pack the arguments into an array with nulls separating the elements.  */
53   argslen = 0;
54   if (argv != NULL)
55     {
56       p = argv;
57       while (*p != NULL)
58         argslen += strlen (*p++) + 1;
59       args = __alloca (argslen);
60       ap = args;
61       for (p = argv; *p != NULL; ++p)
62         ap = __memccpy (ap, *p, '\0', ULONG_MAX);
63     }
64   else
65     args = NULL;
66
67   /* Pack the environment into an array with nulls separating elements.  */
68   envlen = 0;
69   if (envp != NULL)
70     {
71       p = envp;
72       while (*p != NULL)
73         envlen += strlen (*p++) + 1;
74       env = __alloca (envlen);
75       ap = env;
76       for (p = envp; *p != NULL; ++p)
77         ap = __memccpy (ap, *p, '\0', ULONG_MAX);
78     }
79   else
80     env = NULL;
81
82   /* Load up the ports to give to the new program.  */
83   for (i = 0; i < _hurd_nports; ++i)
84     if (i == INIT_PORT_PROC && task != __mach_task_self ())
85       {
86         /* This is another task, so we need to ask the proc server
87            for the right proc server port for it.  */
88         if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
89           {
90             while (--i > 0)
91               _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
92             return err;
93           }
94       }
95     else
96       ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
97
98
99   /* Load up the ints to give the new program.  */
100   for (i = 0; i < INIT_INT_MAX; ++i)
101     switch (i)
102       {
103       case INIT_UMASK:
104         ints[i] = _hurd_umask;
105         break;
106
107       case INIT_SIGMASK:
108       case INIT_SIGIGN:
109       case INIT_SIGPENDING:
110         /* We will set these all below.  */
111         break;
112
113       default:
114         ints[i] = 0;
115       }
116
117   ss = _hurd_self_sigstate ();
118   ints[INIT_SIGMASK] = ss->blocked;
119   ints[INIT_SIGPENDING] = ss->pending;
120   ints[INIT_SIGIGN] = 0;
121   for (i = 1; i < NSIG; ++i)
122     if (ss->actions[i].sa_handler == SIG_IGN)
123       ints[INIT_SIGIGN] |= __sigmask (i);
124
125   /* We hold the sigstate lock until the exec has failed so that no signal
126      can arrive between when we pack the blocked and ignored signals, and
127      when the exec actually happens.  A signal handler could change what
128      signals are blocked and ignored.  Either the change will be reflected
129      in the exec, or the signal will never be delivered.  Setting the
130      critical section flag avoids anything we call trying to acquire the
131      sigstate lock.  */
132   
133   ss->critical_section = 1;
134
135   /* Pack up the descriptor table to give the new program.  */
136   __mutex_lock (&_hurd_dtable_lock);
137
138   dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
139
140   if (task == __mach_task_self ())
141     /* Request the exec server to deallocate some ports from us if the exec
142        succeeds.  The init ports and descriptor ports will arrive in the
143        new program's exec_startup message.  If we failed to deallocate
144        them, the new program would have duplicate user references for them.
145        But we cannot deallocate them ourselves, because we must still have
146        them after a failed exec call.  */
147     please_dealloc = __alloca ((_hurd_nports + (2 * dtablesize))
148                                 * sizeof (mach_port_t));
149   else
150     please_dealloc = NULL;
151   pdp = please_dealloc;
152
153   if (_hurd_dtable != NULL)
154     {
155       dtable = __alloca (dtablesize * sizeof (dtable[0]));
156       dtable_ctty = __alloca (dtablesize * sizeof (dtable[0]));
157       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
158       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
159       ulink_dtable_ctty = __alloca (dtablesize * sizeof (ulink_dtable[0]));
160       dtable_ctty_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
161       for (i = 0; i < dtablesize; ++i)
162         {
163           struct hurd_fd *const d = _hurd_dtable[i];
164           if (d == NULL)
165             {
166               dtable[i] = MACH_PORT_NULL;
167               continue;
168             }
169           __spin_lock (&d->port.lock);
170           if (d->flags & FD_CLOEXEC)
171             {
172               /* This descriptor is marked to be closed on exec.
173                  So don't pass it to the new program.  */
174               dtable[i] = MACH_PORT_NULL;
175               if (pdp && d->port.port != MACH_PORT_NULL)
176                 {
177                   /* We still need to deallocate the ports.  */
178                   *pdp++ = d->port.port;
179                   if (d->ctty.port != MACH_PORT_NULL)
180                     *pdp++ = d->ctty.port;
181                 }
182               __spin_unlock (&d->port.lock);
183             }
184           else
185             {
186               /* If this is a descriptor to our controlling tty,
187                  we want to give the normal port, not the foreground port.  */
188               dtable[i] = _hurd_port_get (&d->ctty, &ulink_dtable[i]);
189               if (dtable[i] == MACH_PORT_NULL)
190                 {
191                   dtable[i] = _hurd_port_locked_get (&d->port,
192                                                      &ulink_dtable[i]);
193                   dtable_cells[i] = &d->port;
194                 }
195               else
196                 {
197                   if (pdp)
198                     /* All the elements of DTABLE are added to PLEASE_DEALLOC
199                        below, so we needn't add the port in the branch above.
200                        But we must deallocate the foreground port as well as
201                        the normal port that got installed in DTABLE[I].  */
202                     *pdp++ = d->port.port;
203                   __spin_unlock (&d->port.lock);
204                   dtable_cells[i] = &d->ctty;
205                 }
206             }
207         }
208     }
209   else
210     {
211       dtable = _hurd_init_dtable;
212       ulink_dtable = NULL;
213       dtable_cells = NULL;
214     }
215
216   /* The information is all set up now.  Try to exec the file.  */
217
218   {
219     if (pdp)
220       {
221         /* Request the exec server to deallocate some ports from us if the exec
222            succeeds.  The init ports and descriptor ports will arrive in the
223            new program's exec_startup message.  If we failed to deallocate
224            them, the new program would have duplicate user references for them.
225            But we cannot deallocate them ourselves, because we must still have
226            them after a failed exec call.  */
227
228         for (i = 0; i < _hurd_nports; ++i)
229           *pdp++ = ports[i];
230         for (i = 0; i < dtablesize; ++i)
231           *pdp++ = dtable[i];
232       }
233
234     err = __file_exec (file, task,
235                        0,       /* No particular flags.  */
236                        args, argslen, env, envlen,
237                        dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize, 
238                        ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports, 
239                        ints, INIT_INT_MAX,
240                        please_dealloc, pdp - please_dealloc,
241                        NULL, 0);
242   }
243
244   /* Release references to the standard ports.  */
245   for (i = 0; i < _hurd_nports; ++i)
246     if (i == INIT_PORT_PROC && task != __mach_task_self ())
247       __mach_port_deallocate (__mach_task_self (), ports[i]);
248     else
249       _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
250
251   if (ulink_dtable != NULL)
252     /* Release references to the file descriptor ports.  */
253     for (i = 0; i < dtablesize; ++i)
254       if (dtable[i] != MACH_PORT_NULL)
255         _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
256
257   /* Release lock on the file descriptor table. */
258   __mutex_unlock (&_hurd_dtable_lock);
259
260   /* Safe to let signals happen now.  */
261   ss->critical_section = 0;
262   __mutex_unlock (&ss->lock);
263
264   return err;
265 }