Update.
[glibc.git] / hurd / hurdexec.c
blob30a27e8048541734ae8d8dd37b59c7c8608b9cc1
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.
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.
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.
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. */
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>
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[])
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;
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;
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 ())
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])))
69 while (--i > 0)
70 _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
71 goto outenv;
74 else
75 ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
78 /* Load up the ints to give the new program. */
79 for (i = 0; i < INIT_INT_MAX; ++i)
80 switch (i)
82 case INIT_UMASK:
83 ints[i] = _hurd_umask;
84 break;
86 case INIT_SIGMASK:
87 case INIT_SIGIGN:
88 case INIT_SIGPENDING:
89 /* We will set these all below. */
90 break;
92 case INIT_TRACEMASK:
93 ints[i] = _hurdsig_traced;
94 break;
96 default:
97 ints[i] = 0;
100 ss = _hurd_self_sigstate ();
102 assert (! __spin_lock_locked (&ss->critical_section_lock));
103 __spin_lock (&ss->critical_section_lock);
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);
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. */
121 __spin_unlock (&ss->lock);
123 /* Pack up the descriptor table to give the new program. */
124 __mutex_lock (&_hurd_dtable_lock);
126 dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
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;
141 if (_hurd_dtable != NULL)
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)
148 struct hurd_fd *const d = _hurd_dtable[i];
149 if (d == NULL)
151 dtable[i] = MACH_PORT_NULL;
152 continue;
154 __spin_lock (&d->port.lock);
155 if (d->flags & FD_CLOEXEC)
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)
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;
167 __spin_unlock (&d->port.lock);
169 else
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;
182 else
184 dtable = _hurd_init_dtable;
185 ulink_dtable = NULL;
186 dtable_cells = NULL;
189 /* Prune trailing null ports from the descriptor table. */
190 while (dtable[dtablesize - 1] == MACH_PORT_NULL)
191 --dtablesize;
193 /* The information is all set up now. Try to exec the file. */
196 int flags;
198 if (pdp)
200 /* Request the exec server to deallocate some ports from us if the exec
201 succeeds. The init ports and descriptor ports will arrive in the
202 new program's exec_startup message. If we failed to deallocate
203 them, the new program would have duplicate user references for them.
204 But we cannot deallocate them ourselves, because we must still have
205 them after a failed exec call. */
207 for (i = 0; i < _hurd_nports; ++i)
208 *pdp++ = ports[i];
209 for (i = 0; i < dtablesize; ++i)
210 *pdp++ = dtable[i];
213 flags = 0;
214 #ifdef EXEC_SIGTRAP
215 /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is propagated
216 through exec by INIT_TRACEMASK, so this checks if PTRACE_TRACEME has
217 been called in this process in any of its current or prior lives. */
218 if (__sigismember (&_hurdsig_traced, SIGKILL))
219 flags |= EXEC_SIGTRAP;
220 #endif
221 err = __file_exec (file, task, flags,
222 args, argslen, env, envlen,
223 dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
224 ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
225 ints, INIT_INT_MAX,
226 please_dealloc, pdp - please_dealloc,
227 &_hurd_msgport, task == __mach_task_self () ? 1 : 0);
230 /* Release references to the standard ports. */
231 for (i = 0; i < _hurd_nports; ++i)
232 if (i == INIT_PORT_PROC && task != __mach_task_self ())
233 __mach_port_deallocate (__mach_task_self (), ports[i]);
234 else
235 _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
237 if (ulink_dtable != NULL)
238 /* Release references to the file descriptor ports. */
239 for (i = 0; i < dtablesize; ++i)
240 if (dtable[i] != MACH_PORT_NULL)
241 _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
243 /* Release lock on the file descriptor table. */
244 __mutex_unlock (&_hurd_dtable_lock);
246 /* Safe to let signals happen now. */
247 _hurd_critical_section_unlock (ss);
249 outargs:
250 free (args);
251 outenv:
252 free (env);
253 return err;