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