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