chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / mach / hurd / spawni.c
1 /* spawn a new process running an executable.  Hurd version.
2    Copyright (C) 2001,02,04 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License as
7    published by the Free Software Foundation; either version 2.1 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <paths.h>
23 #include <spawn.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <hurd.h>
28 #include <hurd/signal.h>
29 #include <hurd/fd.h>
30 #include <hurd/id.h>
31 #include <hurd/lookup.h>
32 #include <hurd/resource.h>
33 #include <assert.h>
34 #include <argz.h>
35 #include "spawn_int.h"
36
37 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
38    Before running the process perform the actions described in FILE-ACTIONS. */
39 int
40 __spawni (pid_t *pid, const char *file,
41           const posix_spawn_file_actions_t *file_actions,
42           const posix_spawnattr_t *attrp,
43           char *const argv[], char *const envp[],
44           int use_path)
45 {
46   pid_t new_pid;
47   char *path, *p, *name;
48   size_t len;
49   size_t pathlen;
50   short int flags;
51
52   /* The generic POSIX.1 implementation of posix_spawn uses fork and exec.
53      In traditional POSIX systems (Unix, Linux, etc), the only way to
54      create a new process is by fork, which also copies all the things from
55      the parent process that will be immediately wiped and replaced by the
56      exec.
57
58      This Hurd implementation works by doing an exec on a fresh task,
59      without ever doing all the work of fork.  The only work done by fork
60      that remains visible after an exec is registration with the proc
61      server, and the inheritance of various values and ports.  All those
62      inherited values and ports are what get collected up and passed in the
63      file_exec RPC by an exec call.  So we do the proc server registration
64      here, following the model of fork (see fork.c).  We then collect up
65      the inherited values and ports from this (parent) process following
66      the model of exec (see hurd/hurdexec.c), modify or replace each value
67      that fork would (plus the specific changes demanded by ATTRP and
68      FILE_ACTIONS), and make the file_exec RPC on the requested executable
69      file with the child process's task port rather than our own.  This
70      should be indistinguishable from the fork + exec implementation,
71      except that all errors will be detected here (in the parent process)
72      and return proper errno codes rather than the child dying with 127.
73
74      XXX The one exception to this supposed indistinguishableness is that
75      when posix_spawn_file_actions_addopen has been used, the parent
76      process can do various filesystem RPCs on the child's behalf, rather
77      than the child process doing it.  If these block due to a broken or
78      malicious filesystem server or just a blocked network fs or a serial
79      port waiting for carrier detect (!!), the parent's posix_spawn call
80      can block arbitrarily rather than just the child blocking.  Possible
81      solutions include:
82      * punt to plain fork + exec implementation if addopen was used
83      ** easy to do
84      ** gives up all benefits of this implementation in that case
85      * if addopen was used, don't do any file actions at all here;
86        instead, exec an installed helper program e.g.:
87         /libexec/spawn-helper close 3 dup2 1 2 open 0 /file 0x123 0666 exec /bin/foo foo a1 a2
88      ** extra exec might be more or less overhead than fork
89      * could do some weird half-fork thing where the child would inherit
90        our vm and run some code here, but not do the full work of fork
91
92      XXX Actually, the parent opens the executable file on behalf of
93      the child, and that has all the same issues.
94
95      I am favoring the half-fork solution.  That is, we do task_create with
96      vm inheritance, and we setjmp/longjmp the child like fork does.  But
97      rather than all the fork hair, the parent just packs up init/dtable
98      ports and does a single IPC to a receive right inserted in the child.  */
99
100   error_t err;
101   task_t task;
102   file_t execfile;
103   process_t proc;
104   auth_t auth;
105   int ints[INIT_INT_MAX];
106   file_t *dtable;
107   unsigned int dtablesize, orig_dtablesize, i;
108   struct hurd_port **dtable_cells;
109   char *dtable_cloexec;
110   struct hurd_userlink *ulink_dtable = NULL;
111   struct hurd_sigstate *ss;
112
113   /* For POSIX_SPAWN_RESETIDS, this reauthenticates our root/current
114      directory ports with the new AUTH port.  */
115   file_t rcrdir = MACH_PORT_NULL, rcwdir = MACH_PORT_NULL;
116   error_t reauthenticate (int which, file_t *result)
117     {
118       error_t err;
119       mach_port_t ref;
120       if (*result != MACH_PORT_NULL)
121         return 0;
122       ref = __mach_reply_port ();
123       err = HURD_PORT_USE
124         (&_hurd_ports[which],
125          ({
126            err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
127            if (!err)
128              err = __auth_user_authenticate (auth,
129                                              ref, MACH_MSG_TYPE_MAKE_SEND,
130                                              result);
131            err;
132          }));
133       __mach_port_destroy (__mach_task_self (), ref);
134       return err;
135     }
136
137   /* Reauthenticate one of our file descriptors for the child.  A null
138      element of DTABLE_CELLS indicates a descriptor that was already
139      reauthenticated, or was newly opened on behalf of the child.  */
140   error_t reauthenticate_fd (int fd)
141     {
142       if (dtable_cells[fd] != NULL)
143         {
144           file_t newfile;
145           mach_port_t ref = __mach_reply_port ();
146           error_t err = __io_reauthenticate (dtable[fd],
147                                              ref, MACH_MSG_TYPE_MAKE_SEND);
148           if (!err)
149             err = __auth_user_authenticate (auth,
150                                             ref, MACH_MSG_TYPE_MAKE_SEND,
151                                             &newfile);
152           __mach_port_destroy (__mach_task_self (), ref);
153           if (err)
154             return err;
155           _hurd_port_free (dtable_cells[fd], &ulink_dtable[fd], dtable[fd]);
156           dtable_cells[fd] = NULL;
157           dtable[fd] = newfile;
158         }
159       return 0;
160     }
161
162   /* These callbacks are for looking up file names on behalf of the child.  */
163   error_t child_init_port (int which, error_t (*operate) (mach_port_t))
164     {
165       if (flags & POSIX_SPAWN_RESETIDS)
166         switch (which)
167           {
168           case INIT_PORT_AUTH:
169             return (*operate) (auth);
170           case INIT_PORT_CRDIR:
171             return (reauthenticate (INIT_PORT_CRDIR, &rcrdir)
172                     ?: (*operate) (rcrdir));
173           case INIT_PORT_CWDIR:
174             return (reauthenticate (INIT_PORT_CWDIR, &rcwdir)
175                     ?: (*operate) (rcwdir));
176           }
177       assert (which != INIT_PORT_PROC);
178       return _hurd_ports_use (which, operate);
179     }
180   file_t child_fd (int fd)
181     {
182       if ((unsigned int) fd < dtablesize && dtable[fd] != MACH_PORT_NULL)
183         {
184           if (flags & POSIX_SPAWN_RESETIDS)
185             {
186               /* Reauthenticate this descriptor right now,
187                  since it is going to be used on behalf of the child.  */
188               errno = reauthenticate_fd (fd);
189               if (errno)
190                 return MACH_PORT_NULL;
191             }
192           __mach_port_mod_refs (__mach_task_self (), dtable[fd],
193                                 MACH_PORT_RIGHT_SEND, +1);
194           return dtable[fd];
195         }
196       errno = EBADF;
197       return MACH_PORT_NULL;
198     }
199   inline error_t child_lookup (const char *file, int oflag, mode_t mode,
200                                file_t *result)
201     {
202       return __hurd_file_name_lookup (&child_init_port, &child_fd, 0,
203                                       file, oflag, mode, result);
204     }
205
206
207   /* Do this once.  */
208   flags = attrp == NULL ? 0 : attrp->__flags;
209
210   /* Generate the new process.  We create a task that does not inherit our
211      memory, and then register it as our child like fork does.  See fork.c
212      for comments about the sequencing of these proc operations.  */
213
214   err = __task_create (__mach_task_self (),
215 #ifdef KERN_INVALID_LEDGER
216                        NULL, 0, /* OSF Mach */
217 #endif
218                        0, &task);
219   if (err)
220     return __hurd_fail (err);
221   // From here down we must deallocate TASK and PROC before returning.
222   proc = MACH_PORT_NULL;
223   auth = MACH_PORT_NULL;
224   err = __USEPORT (PROC, __proc_task2pid (port, task, &new_pid));
225   if (!err)
226     err = __USEPORT (PROC, __proc_task2proc (port, task, &proc));
227   if (!err)
228     err = __USEPORT (PROC, __proc_child (port, task));
229   if (err)
230     goto out;
231
232   /* Load up the ints to give the new program.  */
233   memset (ints, 0, sizeof ints);
234   ints[INIT_UMASK] = _hurd_umask;
235   ints[INIT_TRACEMASK] = _hurdsig_traced;
236
237   ss = _hurd_self_sigstate ();
238
239   assert (! __spin_lock_locked (&ss->critical_section_lock));
240   __spin_lock (&ss->critical_section_lock);
241
242   __spin_lock (&ss->lock);
243   ints[INIT_SIGMASK] = ss->blocked;
244   ints[INIT_SIGPENDING] = ss->pending;
245   ints[INIT_SIGIGN] = 0;
246   /* Unless we were asked to reset all handlers to SIG_DFL,
247      pass down the set of signals that were set to SIG_IGN.  */
248   if ((flags & POSIX_SPAWN_SETSIGDEF) == 0)
249     for (i = 1; i < NSIG; ++i)
250       if (ss->actions[i].sa_handler == SIG_IGN)
251         ints[INIT_SIGIGN] |= __sigmask (i);
252
253   /* We hold the sigstate lock until the exec has failed so that no signal
254      can arrive between when we pack the blocked and ignored signals, and
255      when the exec actually happens.  A signal handler could change what
256      signals are blocked and ignored.  Either the change will be reflected
257      in the exec, or the signal will never be delivered.  Setting the
258      critical section flag avoids anything we call trying to acquire the
259      sigstate lock.  */
260
261   __spin_unlock (&ss->lock);
262
263   /* Set signal mask.  */
264   if ((flags & POSIX_SPAWN_SETSIGMASK) != 0)
265     ints[INIT_SIGMASK] = attrp->__ss;
266
267 #ifdef _POSIX_PRIORITY_SCHEDULING
268   /* Set the scheduling algorithm and parameters.  */
269 # error implement me
270   if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
271       == POSIX_SPAWN_SETSCHEDPARAM)
272     {
273       if (__sched_setparam (0, &attrp->__sp) == -1)
274         _exit (SPAWN_ERROR);
275     }
276   else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
277     {
278       if (__sched_setscheduler (0, attrp->__policy,
279                                 (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
280                                 ? &attrp->__sp : NULL) == -1)
281         _exit (SPAWN_ERROR);
282     }
283 #endif
284
285   /* Set the process group ID.  */
286   if (!err && (flags & POSIX_SPAWN_SETPGROUP) != 0)
287     err = __proc_setpgrp (proc, new_pid, attrp->__pgrp);
288
289   /* Set the effective user and group IDs.  */
290   if (!err && (flags & POSIX_SPAWN_RESETIDS) != 0)
291     {
292       /* We need a different auth port for the child.  */
293
294       __mutex_lock (&_hurd_id.lock);
295       err = _hurd_check_ids (); /* Get _hurd_id up to date.  */
296       if (!err && _hurd_id.rid_auth == MACH_PORT_NULL)
297         {
298           /* Set up _hurd_id.rid_auth.  This is a special auth server port
299              which uses the real uid and gid (the first aux uid and gid) as
300              the only effective uid and gid.  */
301
302           if (_hurd_id.aux.nuids < 1 || _hurd_id.aux.ngids < 1)
303             /* We do not have a real UID and GID.  Lose, lose, lose!  */
304             err = EGRATUITOUS;
305
306           /* Create a new auth port using our real UID and GID (the first
307              auxiliary UID and GID) as the only effective IDs.  */
308           if (!err)
309             err = __USEPORT (AUTH,
310                              __auth_makeauth (port,
311                                               NULL, MACH_MSG_TYPE_COPY_SEND, 0,
312                                               _hurd_id.aux.uids, 1,
313                                               _hurd_id.aux.uids,
314                                               _hurd_id.aux.nuids,
315                                               _hurd_id.aux.gids, 1,
316                                               _hurd_id.aux.gids,
317                                               _hurd_id.aux.ngids,
318                                               &_hurd_id.rid_auth));
319         }
320       if (!err)
321         {
322           /* Use the real-ID auth port in place of the normal one.  */
323           assert (_hurd_id.rid_auth != MACH_PORT_NULL);
324           auth = _hurd_id.rid_auth;
325           __mach_port_mod_refs (__mach_task_self (), auth,
326                                 MACH_PORT_RIGHT_SEND, +1);
327         }
328       __mutex_unlock (&_hurd_id.lock);
329     }
330   else
331     /* Copy our existing auth port.  */
332     err = __USEPORT (AUTH, __mach_port_mod_refs (__mach_task_self (),
333                                                  (auth = port),
334                                                  MACH_PORT_RIGHT_SEND, +1));
335
336   if (err)
337     goto out;
338
339   /* Pack up the descriptor table to give the new program.
340      These descriptors will need to be reauthenticated below
341      if POSIX_SPAWN_RESETIDS is set.  */
342   __mutex_lock (&_hurd_dtable_lock);
343   dtablesize = _hurd_dtablesize;
344   orig_dtablesize = _hurd_dtablesize;
345   dtable = __alloca (dtablesize * sizeof (dtable[0]));
346   ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
347   dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
348   dtable_cloexec = __alloca (dtablesize);
349   for (i = 0; i < dtablesize; ++i)
350     {
351       struct hurd_fd *const d = _hurd_dtable[i];
352       if (d == NULL)
353         {
354           dtable[i] = MACH_PORT_NULL;
355           dtable_cells[i] = NULL;
356           continue;
357         }
358       /* Note that this might return MACH_PORT_NULL.  */
359       dtable[i] = _hurd_port_get (&d->port, &ulink_dtable[i]);
360       dtable_cells[i] = &d->port;
361       dtable_cloexec[i] = (d->flags & FD_CLOEXEC) != 0;
362     }
363   __mutex_unlock (&_hurd_dtable_lock);
364
365   /* Safe to let signals happen now.  */
366   _hurd_critical_section_unlock (ss);
367
368   /* Execute the file actions.  */
369   if (file_actions != NULL)
370     for (i = 0; i < file_actions->__used; ++i)
371       {
372         /* Close a file descriptor in the child.  */
373         error_t do_close (int fd)
374           {
375             if ((unsigned int)fd < dtablesize
376                 && dtable[fd] != MACH_PORT_NULL)
377               {
378                 if (dtable_cells[fd] == NULL)
379                   __mach_port_deallocate (__mach_task_self (), dtable[fd]);
380                 else
381                   {
382                     _hurd_port_free (dtable_cells[fd],
383                                      &ulink_dtable[fd], dtable[fd]);
384                   }
385                 dtable_cells[fd] = NULL;
386                 dtable[fd] = MACH_PORT_NULL;
387                 return 0;
388               }
389             return EBADF;
390           }
391
392         /* Make sure the dtable can hold NEWFD.  */
393 #define EXPAND_DTABLE(newfd)                                                  \
394         ({                                                                    \
395           if ((unsigned int)newfd >= dtablesize                               \
396               && newfd < _hurd_rlimits[RLIMIT_OFILE].rlim_cur)                \
397             {                                                                 \
398               /* We need to expand the dtable for the child.  */              \
399               NEW_TABLE (dtable, newfd);                                      \
400               NEW_TABLE (ulink_dtable, newfd);                                \
401               NEW_TABLE (dtable_cells, newfd);                                \
402               dtablesize = newfd + 1;                                         \
403             }                                                                 \
404           ((unsigned int)newfd < dtablesize ? 0 : EMFILE);                    \
405         })
406 #define NEW_TABLE(x, newfd) \
407   do { __typeof (x) new_##x = __alloca ((newfd + 1) * sizeof (x[0]));         \
408   memcpy (new_##x, x, dtablesize * sizeof (x[0]));                            \
409   memset (&new_##x[dtablesize], 0, (newfd + 1 - dtablesize) * sizeof (x[0])); \
410   x = new_##x; } while (0)
411
412         struct __spawn_action *action = &file_actions->__actions[i];
413
414         switch (action->tag)
415           {
416           case spawn_do_close:
417             err = do_close (action->action.close_action.fd);
418             break;
419
420           case spawn_do_dup2:
421             if ((unsigned int)action->action.dup2_action.fd < dtablesize
422                 && dtable[action->action.dup2_action.fd] != MACH_PORT_NULL)
423               {
424                 const int fd = action->action.dup2_action.fd;
425                 const int newfd = action->action.dup2_action.newfd;
426                 // dup2 always clears any old FD_CLOEXEC flag on the new fd.
427                 if (newfd < orig_dtablesize)
428                   dtable_cloexec[newfd] = 0;
429                 if (fd == newfd)
430                   // Same is same as same was.
431                   break;
432                 err = EXPAND_DTABLE (newfd);
433                 if (!err)
434                   {
435                     /* Close the old NEWFD and replace it with FD's
436                        contents, which can be either an original
437                        descriptor (DTABLE_CELLS[FD] != 0) or a new
438                        right that we acquired in this function.  */
439                     do_close (newfd);
440                     dtable_cells[newfd] = dtable_cells[fd];
441                     if (dtable_cells[newfd] != NULL)
442                       dtable[newfd] = _hurd_port_get (dtable_cells[newfd],
443                                                       &ulink_dtable[newfd]);
444                     else
445                       {
446                         dtable[newfd] = dtable[fd];
447                         err = __mach_port_mod_refs (__mach_task_self (),
448                                                     dtable[fd],
449                                                     MACH_PORT_RIGHT_SEND, +1);
450                       }
451                   }
452               }
453             else
454               // The old FD specified was bogus.
455               err = EBADF;
456             break;
457
458           case spawn_do_open:
459             /* Open a file on behalf of the child.
460
461                XXX note that this can subject the parent to arbitrary
462                delays waiting for the files to open.  I don't know what the
463                spec says about this.  If it's not permissible, then this
464                whole forkless implementation is probably untenable.  */
465             {
466               const int fd = action->action.open_action.fd;
467
468               do_close (fd);
469               if (fd < orig_dtablesize)
470                 dtable_cloexec[fd] = 0;
471               err = EXPAND_DTABLE (fd);
472               if (err)
473                 break;
474
475               err = child_lookup (action->action.open_action.path,
476                                   action->action.open_action.oflag,
477                                   action->action.open_action.mode,
478                                   &dtable[fd]);
479               dtable_cells[fd] = NULL;
480               break;
481             }
482           }
483
484         if (err)
485           goto out;
486       }
487
488   /* Only now can we perform FD_CLOEXEC.  We had to leave the descriptors
489      unmolested for the file actions to use.  Note that the DTABLE_CLOEXEC
490      array is never expanded by file actions, so it might now have fewer
491      than DTABLESIZE elements.  */
492   for (i = 0; i < orig_dtablesize; ++i)
493     if (dtable[i] != MACH_PORT_NULL && dtable_cloexec[i])
494       {
495         assert (dtable_cells[i] != NULL);
496         _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
497         dtable[i] = MACH_PORT_NULL;
498       }
499
500   /* Prune trailing null ports from the descriptor table.  */
501   while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
502     --dtablesize;
503
504   if (flags & POSIX_SPAWN_RESETIDS)
505     {
506       /* Reauthenticate all the child's ports with its new auth handle.  */
507
508       mach_port_t ref;
509       process_t newproc;
510
511       /* Reauthenticate with the proc server.  */
512       ref = __mach_reply_port ();
513       err = __proc_reauthenticate (proc, ref, MACH_MSG_TYPE_MAKE_SEND);
514       if (!err)
515         err = __auth_user_authenticate (auth,
516                                         ref, MACH_MSG_TYPE_MAKE_SEND,
517                                         &newproc);
518       __mach_port_destroy (__mach_task_self (), ref);
519       if (!err)
520         {
521           __mach_port_deallocate (__mach_task_self (), proc);
522           proc = newproc;
523         }
524
525       if (!err)
526         err = reauthenticate (INIT_PORT_CRDIR, &rcrdir);
527       if (!err)
528         err = reauthenticate (INIT_PORT_CWDIR, &rcwdir);
529
530       /* We must reauthenticate all the fds except those that came from
531          `spawn_do_open' file actions, which were opened using the child's
532          auth port to begin with.  */
533       for (i = 0; !err && i < dtablesize; ++i)
534         err = reauthenticate_fd (i);
535     }
536   if (err)
537     goto out;
538
539   /* Now we are ready to open the executable file using the child's ports.
540      We do this after performing all the file actions so the order of
541      events is the same as for a fork, exec sequence.  This affects things
542      like the meaning of a /dev/fd file name, as well as which error
543      conditions are diagnosed first and what side effects (file creation,
544      etc) can be observed before what errors.  */
545
546   if (! use_path || strchr (file, '/') != NULL)
547     /* The FILE parameter is actually a path.  */
548     err = child_lookup (file, O_EXEC, 0, &execfile);
549   else
550     {
551       /* We have to search for FILE on the path.  */
552       path = getenv ("PATH");
553       if (path == NULL)
554         {
555           /* There is no `PATH' in the environment.
556              The default search path is the current directory
557              followed by the path `confstr' returns for `_CS_PATH'.  */
558           len = confstr (_CS_PATH, (char *) NULL, 0);
559           path = (char *) __alloca (1 + len);
560           path[0] = ':';
561           (void) confstr (_CS_PATH, path + 1, len);
562         }
563
564       len = strlen (file) + 1;
565       pathlen = strlen (path);
566       name = __alloca (pathlen + len + 1);
567       /* Copy the file name at the top.  */
568       name = (char *) memcpy (name + pathlen + 1, file, len);
569       /* And add the slash.  */
570       *--name = '/';
571
572       p = path;
573       do
574         {
575           char *startp;
576
577           path = p;
578           p = __strchrnul (path, ':');
579
580           if (p == path)
581             /* Two adjacent colons, or a colon at the beginning or the end
582                of `PATH' means to search the current directory.  */
583             startp = name + 1;
584           else
585             startp = (char *) memcpy (name - (p - path), path, p - path);
586
587           /* Try to open this file name.  */
588           err = child_lookup (startp, O_EXEC, 0, &execfile);
589           switch (err)
590             {
591             case EACCES:
592             case ENOENT:
593             case ESTALE:
594             case ENOTDIR:
595               /* Those errors indicate the file is missing or not executable
596                  by us, in which case we want to just try the next path
597                  directory.  */
598               continue;
599
600             case 0:             /* Success! */
601             default:
602               /* Some other error means we found an executable file, but
603                  something went wrong executing it; return the error to our
604                  caller.  */
605               break;
606             }
607
608           // We only get here when we are done looking for the file.
609           break;
610         }
611       while (*p++ != '\0');
612     }
613   if (err)
614     goto out;
615
616   /* Almost there!  */
617   {
618     mach_port_t ports[_hurd_nports];
619     struct hurd_userlink ulink_ports[_hurd_nports];
620     char *args = NULL, *env = NULL;
621     size_t argslen = 0, envlen = 0;
622
623     inline error_t exec (file_t file)
624       {
625         return __file_exec (file, task,
626                             (__sigismember (&_hurdsig_traced, SIGKILL)
627                              ? EXEC_SIGTRAP : 0),
628                             args, argslen, env, envlen,
629                             dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
630                             ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
631                             ints, INIT_INT_MAX,
632                             NULL, 0, NULL, 0);
633       }
634
635     /* Now we are out of things that can fail before the file_exec RPC,
636        for which everything else must be prepared.  The only thing left
637        to do is packing up the argument and environment strings,
638        and the array of init ports.  */
639
640     if (argv != NULL)
641       err = __argz_create (argv, &args, &argslen);
642     if (!err && envp != NULL)
643       err = __argz_create (envp, &env, &envlen);
644
645     /* Load up the ports to give to the new program.
646        Note the loop/switch below must parallel exactly to release refs.  */
647     for (i = 0; i < _hurd_nports; ++i)
648       {
649         switch (i)
650           {
651           case INIT_PORT_AUTH:
652             ports[i] = auth;
653             continue;
654           case INIT_PORT_PROC:
655             ports[i] = proc;
656             continue;
657           case INIT_PORT_CRDIR:
658             if (flags & POSIX_SPAWN_RESETIDS)
659               {
660                 ports[i] = rcrdir;
661                 continue;
662               }
663             break;
664           case INIT_PORT_CWDIR:
665             if (flags & POSIX_SPAWN_RESETIDS)
666               {
667                 ports[i] = rcwdir;
668                 continue;
669               }
670             break;
671           }
672         ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
673       }
674
675     /* Finally, try executing the file we opened.  */
676     if (!err)
677       err = exec (execfile);
678     __mach_port_deallocate (__mach_task_self (), execfile);
679
680     if (err == ENOEXEC)
681       {
682         /* The file is accessible but it is not an executable file.
683            Invoke the shell to interpret it as a script.  */
684         err = __argz_insert (&args, &argslen, args, _PATH_BSHELL);
685         if (!err)
686           err = child_lookup (_PATH_BSHELL, O_EXEC, 0, &execfile);
687         if (!err)
688           {
689             err = exec (execfile);
690             __mach_port_deallocate (__mach_task_self (), execfile);
691           }
692       }
693
694     /* Release the references just packed up in PORTS.
695        This switch must always parallel the one above that fills PORTS.  */
696     for (i = 0; i < _hurd_nports; ++i)
697       {
698         switch (i)
699           {
700           case INIT_PORT_AUTH:
701           case INIT_PORT_PROC:
702             continue;
703           case INIT_PORT_CRDIR:
704             if (flags & POSIX_SPAWN_RESETIDS)
705               continue;
706             break;
707           case INIT_PORT_CWDIR:
708             if (flags & POSIX_SPAWN_RESETIDS)
709               continue;
710             break;
711           }
712         _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
713       }
714
715     free (args);
716     free (env);
717   }
718
719   /* We did it!  We have a child!  */
720   if (pid != NULL)
721     *pid = new_pid;
722
723  out:
724   /* Clean up all the references we are now holding.  */
725
726   if (task != MACH_PORT_NULL)
727     {
728       if (err)
729         /* We failed after creating the task, so kill it.  */
730         __task_terminate (task);
731       __mach_port_deallocate (__mach_task_self (), task);
732     }
733   __mach_port_deallocate (__mach_task_self (), auth);
734   __mach_port_deallocate (__mach_task_self (), proc);
735   if (rcrdir != MACH_PORT_NULL)
736     __mach_port_deallocate (__mach_task_self (), rcrdir);
737   if (rcwdir != MACH_PORT_NULL)
738     __mach_port_deallocate (__mach_task_self (), rcwdir);
739
740   if (ulink_dtable)
741     /* Release references to the file descriptor ports.  */
742     for (i = 0; i < dtablesize; ++i)
743       if (dtable[i] != MACH_PORT_NULL)
744         {
745           if (dtable_cells[i] == NULL)
746             __mach_port_deallocate (__mach_task_self (), dtable[i]);
747           else
748             _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
749         }
750
751   if (err)
752     /* This hack canonicalizes the error code that we return.  */
753     err = (__hurd_fail (err), errno);
754
755   return err;
756 }