d5d2d080e4804746b3d6c37d2ca0286ab610f97d
[kopensolaris-gnu/glibc.git] / hurd / hurdexec.c
1 /* Copyright (C) 1991, 1992, 1993, 1994, 1995 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;
43   int dtablesize;
44   struct hurd_port **dtable_cells;
45   struct hurd_userlink *ulink_dtable;
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   __spin_lock (&ss->lock);
119   ints[INIT_SIGMASK] = ss->blocked;
120   ints[INIT_SIGPENDING] = ss->pending;
121   ints[INIT_SIGIGN] = 0;
122   for (i = 1; i < NSIG; ++i)
123     if (ss->actions[i].sa_handler == SIG_IGN)
124       ints[INIT_SIGIGN] |= __sigmask (i);
125
126   /* We hold the sigstate lock until the exec has failed so that no signal
127      can arrive between when we pack the blocked and ignored signals, and
128      when the exec actually happens.  A signal handler could change what
129      signals are blocked and ignored.  Either the change will be reflected
130      in the exec, or the signal will never be delivered.  Setting the
131      critical section flag avoids anything we call trying to acquire the
132      sigstate lock.  */
133   
134   ss->critical_section = 1;
135   __spin_unlock (&ss->lock);
136
137   /* Pack up the descriptor table to give the new program.  */
138   __mutex_lock (&_hurd_dtable_lock);
139
140   dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
141
142   if (task == __mach_task_self ())
143     /* Request the exec server to deallocate some ports from us if the exec
144        succeeds.  The init ports and descriptor ports will arrive in the
145        new program's exec_startup message.  If we failed to deallocate
146        them, the new program would have duplicate user references for them.
147        But we cannot deallocate them ourselves, because we must still have
148        them after a failed exec call.  */
149     please_dealloc = __alloca ((_hurd_nports + (2 * dtablesize))
150                                 * sizeof (mach_port_t));
151   else
152     please_dealloc = NULL;
153   pdp = please_dealloc;
154
155   if (_hurd_dtable != NULL)
156     {
157       dtable = __alloca (dtablesize * sizeof (dtable[0]));
158       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
159       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
160       for (i = 0; i < dtablesize; ++i)
161         {
162           struct hurd_fd *const d = _hurd_dtable[i];
163           if (d == NULL)
164             {
165               dtable[i] = MACH_PORT_NULL;
166               continue;
167             }
168           __spin_lock (&d->port.lock);
169           if (d->flags & FD_CLOEXEC)
170             {
171               /* This descriptor is marked to be closed on exec.
172                  So don't pass it to the new program.  */
173               dtable[i] = MACH_PORT_NULL;
174               if (pdp && d->port.port != MACH_PORT_NULL)
175                 {
176                   /* We still need to deallocate the ports.  */
177                   *pdp++ = d->port.port;
178                   if (d->ctty.port != MACH_PORT_NULL)
179                     *pdp++ = d->ctty.port;
180                 }
181               __spin_unlock (&d->port.lock);
182             }
183           else
184             {
185               if (pdp && d->ctty.port != MACH_PORT_NULL)
186                 /* All the elements of DTABLE are added to PLEASE_DEALLOC
187                    below, so we needn't add the port itself.
188                    But we must deallocate the ctty port as well as
189                    the normal port that got installed in DTABLE[I].  */
190                 *pdp++ = d->ctty.port;
191               dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
192               dtable_cells[i] = &d->port;
193             }
194         }
195     }
196   else
197     {
198       dtable = _hurd_init_dtable;
199       ulink_dtable = NULL;
200       dtable_cells = NULL;
201     }
202
203   /* The information is all set up now.  Try to exec the file.  */
204
205   {
206     if (pdp)
207       {
208         /* Request the exec server to deallocate some ports from us if the exec
209            succeeds.  The init ports and descriptor ports will arrive in the
210            new program's exec_startup message.  If we failed to deallocate
211            them, the new program would have duplicate user references for them.
212            But we cannot deallocate them ourselves, because we must still have
213            them after a failed exec call.  */
214
215         for (i = 0; i < _hurd_nports; ++i)
216           *pdp++ = ports[i];
217         for (i = 0; i < dtablesize; ++i)
218           *pdp++ = dtable[i];
219       }
220
221     err = __file_exec (file, task,
222                        _hurd_exec_flags & EXEC_INHERITED,
223                        args, argslen, env, envlen,
224                        dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize, 
225                        ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports, 
226                        ints, INIT_INT_MAX,
227                        please_dealloc, pdp - please_dealloc,
228                        NULL, 0);
229   }
230
231   /* Release references to the standard ports.  */
232   for (i = 0; i < _hurd_nports; ++i)
233     if (i == INIT_PORT_PROC && task != __mach_task_self ())
234       __mach_port_deallocate (__mach_task_self (), ports[i]);
235     else
236       _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
237
238   if (ulink_dtable != NULL)
239     /* Release references to the file descriptor ports.  */
240     for (i = 0; i < dtablesize; ++i)
241       if (dtable[i] != MACH_PORT_NULL)
242         _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
243
244   /* Release lock on the file descriptor table. */
245   __mutex_unlock (&_hurd_dtable_lock);
246
247   /* Safe to let signals happen now.  */
248   {
249     sigset_t pending;
250     __spin_lock (&ss->lock);
251     ss->critical_section = 0;
252     pending = ss->pending & ~ss->blocked;
253     __spin_unlock (&ss->lock);
254     if (pending)
255       __msg_sig_post (_hurd_msgport, 0, __mach_task_self ());
256   }
257
258   return err;
259 }