Back to index

glibc  2.9
spawni.c
Go to the documentation of this file.
00001 /* spawn a new process running an executable.  Hurd version.
00002    Copyright (C) 2001,02,04 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public License as
00007    published by the Free Software Foundation; either version 2.1 of the
00008    License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00017    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.  */
00019 
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <paths.h>
00023 #include <spawn.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <hurd.h>
00028 #include <hurd/signal.h>
00029 #include <hurd/fd.h>
00030 #include <hurd/id.h>
00031 #include <hurd/lookup.h>
00032 #include <hurd/resource.h>
00033 #include <assert.h>
00034 #include <argz.h>
00035 #include "spawn_int.h"
00036 
00037 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
00038    Before running the process perform the actions described in FILE-ACTIONS. */
00039 int
00040 __spawni (pid_t *pid, const char *file,
00041          const posix_spawn_file_actions_t *file_actions,
00042          const posix_spawnattr_t *attrp,
00043          char *const argv[], char *const envp[],
00044          int use_path)
00045 {
00046   pid_t new_pid;
00047   char *path, *p, *name;
00048   size_t len;
00049   size_t pathlen;
00050   short int flags;
00051 
00052   /* The generic POSIX.1 implementation of posix_spawn uses fork and exec.
00053      In traditional POSIX systems (Unix, Linux, etc), the only way to
00054      create a new process is by fork, which also copies all the things from
00055      the parent process that will be immediately wiped and replaced by the
00056      exec.
00057 
00058      This Hurd implementation works by doing an exec on a fresh task,
00059      without ever doing all the work of fork.  The only work done by fork
00060      that remains visible after an exec is registration with the proc
00061      server, and the inheritance of various values and ports.  All those
00062      inherited values and ports are what get collected up and passed in the
00063      file_exec RPC by an exec call.  So we do the proc server registration
00064      here, following the model of fork (see fork.c).  We then collect up
00065      the inherited values and ports from this (parent) process following
00066      the model of exec (see hurd/hurdexec.c), modify or replace each value
00067      that fork would (plus the specific changes demanded by ATTRP and
00068      FILE_ACTIONS), and make the file_exec RPC on the requested executable
00069      file with the child process's task port rather than our own.  This
00070      should be indistinguishable from the fork + exec implementation,
00071      except that all errors will be detected here (in the parent process)
00072      and return proper errno codes rather than the child dying with 127.
00073 
00074      XXX The one exception to this supposed indistinguishableness is that
00075      when posix_spawn_file_actions_addopen has been used, the parent
00076      process can do various filesystem RPCs on the child's behalf, rather
00077      than the child process doing it.  If these block due to a broken or
00078      malicious filesystem server or just a blocked network fs or a serial
00079      port waiting for carrier detect (!!), the parent's posix_spawn call
00080      can block arbitrarily rather than just the child blocking.  Possible
00081      solutions include:
00082      * punt to plain fork + exec implementation if addopen was used
00083      ** easy to do
00084      ** gives up all benefits of this implementation in that case
00085      * if addopen was used, don't do any file actions at all here;
00086        instead, exec an installed helper program e.g.:
00087        /libexec/spawn-helper close 3 dup2 1 2 open 0 /file 0x123 0666 exec /bin/foo foo a1 a2
00088      ** extra exec might be more or less overhead than fork
00089      * could do some weird half-fork thing where the child would inherit
00090        our vm and run some code here, but not do the full work of fork
00091 
00092      XXX Actually, the parent opens the executable file on behalf of
00093      the child, and that has all the same issues.
00094 
00095      I am favoring the half-fork solution.  That is, we do task_create with
00096      vm inheritance, and we setjmp/longjmp the child like fork does.  But
00097      rather than all the fork hair, the parent just packs up init/dtable
00098      ports and does a single IPC to a receive right inserted in the child.  */
00099 
00100   error_t err;
00101   task_t task;
00102   file_t execfile;
00103   process_t proc;
00104   auth_t auth;
00105   int ints[INIT_INT_MAX];
00106   file_t *dtable;
00107   unsigned int dtablesize, orig_dtablesize, i;
00108   struct hurd_port **dtable_cells;
00109   char *dtable_cloexec;
00110   struct hurd_userlink *ulink_dtable = NULL;
00111   struct hurd_sigstate *ss;
00112 
00113   /* For POSIX_SPAWN_RESETIDS, this reauthenticates our root/current
00114      directory ports with the new AUTH port.  */
00115   file_t rcrdir = MACH_PORT_NULL, rcwdir = MACH_PORT_NULL;
00116   error_t reauthenticate (int which, file_t *result)
00117     {
00118       error_t err;
00119       mach_port_t ref;
00120       if (*result != MACH_PORT_NULL)
00121        return 0;
00122       ref = __mach_reply_port ();
00123       err = HURD_PORT_USE
00124        (&_hurd_ports[which],
00125         ({
00126           err = __io_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND);
00127           if (!err)
00128             err = __auth_user_authenticate (auth,
00129                                         ref, MACH_MSG_TYPE_MAKE_SEND,
00130                                         result);
00131           err;
00132         }));
00133       __mach_port_destroy (__mach_task_self (), ref);
00134       return err;
00135     }
00136 
00137   /* Reauthenticate one of our file descriptors for the child.  A null
00138      element of DTABLE_CELLS indicates a descriptor that was already
00139      reauthenticated, or was newly opened on behalf of the child.  */
00140   error_t reauthenticate_fd (int fd)
00141     {
00142       if (dtable_cells[fd] != NULL)
00143        {
00144          file_t newfile;
00145          mach_port_t ref = __mach_reply_port ();
00146          error_t err = __io_reauthenticate (dtable[fd],
00147                                         ref, MACH_MSG_TYPE_MAKE_SEND);
00148          if (!err)
00149            err = __auth_user_authenticate (auth,
00150                                        ref, MACH_MSG_TYPE_MAKE_SEND,
00151                                        &newfile);
00152          __mach_port_destroy (__mach_task_self (), ref);
00153          if (err)
00154            return err;
00155          _hurd_port_free (dtable_cells[fd], &ulink_dtable[fd], dtable[fd]);
00156          dtable_cells[fd] = NULL;
00157          dtable[fd] = newfile;
00158        }
00159       return 0;
00160     }
00161 
00162   /* These callbacks are for looking up file names on behalf of the child.  */
00163   error_t child_init_port (int which, error_t (*operate) (mach_port_t))
00164     {
00165       if (flags & POSIX_SPAWN_RESETIDS)
00166        switch (which)
00167          {
00168          case INIT_PORT_AUTH:
00169            return (*operate) (auth);
00170          case INIT_PORT_CRDIR:
00171            return (reauthenticate (INIT_PORT_CRDIR, &rcrdir)
00172                   ?: (*operate) (rcrdir));
00173          case INIT_PORT_CWDIR:
00174            return (reauthenticate (INIT_PORT_CWDIR, &rcwdir)
00175                   ?: (*operate) (rcwdir));
00176          }
00177       assert (which != INIT_PORT_PROC);
00178       return _hurd_ports_use (which, operate);
00179     }
00180   file_t child_fd (int fd)
00181     {
00182       if ((unsigned int) fd < dtablesize && dtable[fd] != MACH_PORT_NULL)
00183        {
00184          if (flags & POSIX_SPAWN_RESETIDS)
00185            {
00186              /* Reauthenticate this descriptor right now,
00187                since it is going to be used on behalf of the child.  */
00188              errno = reauthenticate_fd (fd);
00189              if (errno)
00190               return MACH_PORT_NULL;
00191            }
00192          __mach_port_mod_refs (__mach_task_self (), dtable[fd],
00193                             MACH_PORT_RIGHT_SEND, +1);
00194          return dtable[fd];
00195        }
00196       errno = EBADF;
00197       return MACH_PORT_NULL;
00198     }
00199   inline error_t child_lookup (const char *file, int oflag, mode_t mode,
00200                             file_t *result)
00201     {
00202       return __hurd_file_name_lookup (&child_init_port, &child_fd, 0,
00203                                   file, oflag, mode, result);
00204     }
00205 
00206 
00207   /* Do this once.  */
00208   flags = attrp == NULL ? 0 : attrp->__flags;
00209 
00210   /* Generate the new process.  We create a task that does not inherit our
00211      memory, and then register it as our child like fork does.  See fork.c
00212      for comments about the sequencing of these proc operations.  */
00213 
00214   err = __task_create (__mach_task_self (),
00215 #ifdef KERN_INVALID_LEDGER
00216                      NULL, 0,      /* OSF Mach */
00217 #endif
00218                      0, &task);
00219   if (err)
00220     return __hurd_fail (err);
00221   // From here down we must deallocate TASK and PROC before returning.
00222   proc = MACH_PORT_NULL;
00223   auth = MACH_PORT_NULL;
00224   err = __USEPORT (PROC, __proc_task2pid (port, task, &new_pid));
00225   if (!err)
00226     err = __USEPORT (PROC, __proc_task2proc (port, task, &proc));
00227   if (!err)
00228     err = __USEPORT (PROC, __proc_child (port, task));
00229   if (err)
00230     goto out;
00231 
00232   /* Load up the ints to give the new program.  */
00233   memset (ints, 0, sizeof ints);
00234   ints[INIT_UMASK] = _hurd_umask;
00235   ints[INIT_TRACEMASK] = _hurdsig_traced;
00236 
00237   ss = _hurd_self_sigstate ();
00238 
00239   assert (! __spin_lock_locked (&ss->critical_section_lock));
00240   __spin_lock (&ss->critical_section_lock);
00241 
00242   __spin_lock (&ss->lock);
00243   ints[INIT_SIGMASK] = ss->blocked;
00244   ints[INIT_SIGPENDING] = ss->pending;
00245   ints[INIT_SIGIGN] = 0;
00246   /* Unless we were asked to reset all handlers to SIG_DFL,
00247      pass down the set of signals that were set to SIG_IGN.  */
00248   if ((flags & POSIX_SPAWN_SETSIGDEF) == 0)
00249     for (i = 1; i < NSIG; ++i)
00250       if (ss->actions[i].sa_handler == SIG_IGN)
00251        ints[INIT_SIGIGN] |= __sigmask (i);
00252 
00253   /* We hold the sigstate lock until the exec has failed so that no signal
00254      can arrive between when we pack the blocked and ignored signals, and
00255      when the exec actually happens.  A signal handler could change what
00256      signals are blocked and ignored.  Either the change will be reflected
00257      in the exec, or the signal will never be delivered.  Setting the
00258      critical section flag avoids anything we call trying to acquire the
00259      sigstate lock.  */
00260 
00261   __spin_unlock (&ss->lock);
00262 
00263   /* Set signal mask.  */
00264   if ((flags & POSIX_SPAWN_SETSIGMASK) != 0)
00265     ints[INIT_SIGMASK] = attrp->__ss;
00266 
00267 #ifdef _POSIX_PRIORITY_SCHEDULING
00268   /* Set the scheduling algorithm and parameters.  */
00269 # error implement me
00270   if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
00271       == POSIX_SPAWN_SETSCHEDPARAM)
00272     {
00273       if (__sched_setparam (0, &attrp->__sp) == -1)
00274        _exit (SPAWN_ERROR);
00275     }
00276   else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
00277     {
00278       if (__sched_setscheduler (0, attrp->__policy,
00279                             (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
00280                             ? &attrp->__sp : NULL) == -1)
00281        _exit (SPAWN_ERROR);
00282     }
00283 #endif
00284 
00285   /* Set the process group ID.  */
00286   if (!err && (flags & POSIX_SPAWN_SETPGROUP) != 0)
00287     err = __proc_setpgrp (proc, new_pid, attrp->__pgrp);
00288 
00289   /* Set the effective user and group IDs.  */
00290   if (!err && (flags & POSIX_SPAWN_RESETIDS) != 0)
00291     {
00292       /* We need a different auth port for the child.  */
00293 
00294       __mutex_lock (&_hurd_id.lock);
00295       err = _hurd_check_ids (); /* Get _hurd_id up to date.  */
00296       if (!err && _hurd_id.rid_auth == MACH_PORT_NULL)
00297        {
00298          /* Set up _hurd_id.rid_auth.  This is a special auth server port
00299             which uses the real uid and gid (the first aux uid and gid) as
00300             the only effective uid and gid.  */
00301 
00302          if (_hurd_id.aux.nuids < 1 || _hurd_id.aux.ngids < 1)
00303            /* We do not have a real UID and GID.  Lose, lose, lose!  */
00304            err = EGRATUITOUS;
00305 
00306          /* Create a new auth port using our real UID and GID (the first
00307             auxiliary UID and GID) as the only effective IDs.  */
00308          if (!err)
00309            err = __USEPORT (AUTH,
00310                           __auth_makeauth (port,
00311                                          NULL, MACH_MSG_TYPE_COPY_SEND, 0,
00312                                          _hurd_id.aux.uids, 1,
00313                                          _hurd_id.aux.uids,
00314                                          _hurd_id.aux.nuids,
00315                                          _hurd_id.aux.gids, 1,
00316                                          _hurd_id.aux.gids,
00317                                          _hurd_id.aux.ngids,
00318                                          &_hurd_id.rid_auth));
00319        }
00320       if (!err)
00321        {
00322          /* Use the real-ID auth port in place of the normal one.  */
00323          assert (_hurd_id.rid_auth != MACH_PORT_NULL);
00324          auth = _hurd_id.rid_auth;
00325          __mach_port_mod_refs (__mach_task_self (), auth,
00326                             MACH_PORT_RIGHT_SEND, +1);
00327        }
00328       __mutex_unlock (&_hurd_id.lock);
00329     }
00330   else
00331     /* Copy our existing auth port.  */
00332     err = __USEPORT (AUTH, __mach_port_mod_refs (__mach_task_self (),
00333                                            (auth = port),
00334                                            MACH_PORT_RIGHT_SEND, +1));
00335 
00336   if (err)
00337     goto out;
00338 
00339   /* Pack up the descriptor table to give the new program.
00340      These descriptors will need to be reauthenticated below
00341      if POSIX_SPAWN_RESETIDS is set.  */
00342   __mutex_lock (&_hurd_dtable_lock);
00343   dtablesize = _hurd_dtablesize;
00344   orig_dtablesize = _hurd_dtablesize;
00345   dtable = __alloca (dtablesize * sizeof (dtable[0]));
00346   ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
00347   dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
00348   dtable_cloexec = __alloca (dtablesize);
00349   for (i = 0; i < dtablesize; ++i)
00350     {
00351       struct hurd_fd *const d = _hurd_dtable[i];
00352       if (d == NULL)
00353        {
00354          dtable[i] = MACH_PORT_NULL;
00355          dtable_cells[i] = NULL;
00356          continue;
00357        }
00358       /* Note that this might return MACH_PORT_NULL.  */
00359       dtable[i] = _hurd_port_get (&d->port, &ulink_dtable[i]);
00360       dtable_cells[i] = &d->port;
00361       dtable_cloexec[i] = (d->flags & FD_CLOEXEC) != 0;
00362     }
00363   __mutex_unlock (&_hurd_dtable_lock);
00364 
00365   /* Safe to let signals happen now.  */
00366   _hurd_critical_section_unlock (ss);
00367 
00368   /* Execute the file actions.  */
00369   if (file_actions != NULL)
00370     for (i = 0; i < file_actions->__used; ++i)
00371       {
00372        /* Close a file descriptor in the child.  */
00373        error_t do_close (int fd)
00374          {
00375            if ((unsigned int)fd < dtablesize
00376               && dtable[fd] != MACH_PORT_NULL)
00377              {
00378               if (dtable_cells[fd] == NULL)
00379                 __mach_port_deallocate (__mach_task_self (), dtable[fd]);
00380               else
00381                 {
00382                   _hurd_port_free (dtable_cells[fd],
00383                                  &ulink_dtable[fd], dtable[fd]);
00384                 }
00385               dtable_cells[fd] = NULL;
00386               dtable[fd] = MACH_PORT_NULL;
00387               return 0;
00388              }
00389            return EBADF;
00390          }
00391 
00392        /* Make sure the dtable can hold NEWFD.  */
00393 #define EXPAND_DTABLE(newfd)                                                \
00394        ({                                                            \
00395          if ((unsigned int)newfd >= dtablesize                              \
00396              && newfd < _hurd_rlimits[RLIMIT_OFILE].rlim_cur)               \
00397            {                                                         \
00398              /* We need to expand the dtable for the child.  */             \
00399              NEW_TABLE (dtable, newfd);                              \
00400              NEW_TABLE (ulink_dtable, newfd);                               \
00401              NEW_TABLE (dtable_cells, newfd);                               \
00402              dtablesize = newfd + 1;                                                      \
00403            }                                                         \
00404          ((unsigned int)newfd < dtablesize ? 0 : EMFILE);                   \
00405        })
00406 #define NEW_TABLE(x, newfd) \
00407   do { __typeof (x) new_##x = __alloca ((newfd + 1) * sizeof (x[0]));       \
00408   memcpy (new_##x, x, dtablesize * sizeof (x[0]));                          \
00409   memset (&new_##x[dtablesize], 0, (newfd + 1 - dtablesize) * sizeof (x[0])); \
00410   x = new_##x; } while (0)
00411 
00412        struct __spawn_action *action = &file_actions->__actions[i];
00413 
00414        switch (action->tag)
00415          {
00416          case spawn_do_close:
00417            err = do_close (action->action.close_action.fd);
00418            break;
00419 
00420          case spawn_do_dup2:
00421            if ((unsigned int)action->action.dup2_action.fd < dtablesize
00422               && dtable[action->action.dup2_action.fd] != MACH_PORT_NULL)
00423              {
00424               const int fd = action->action.dup2_action.fd;
00425               const int newfd = action->action.dup2_action.newfd;
00426               // dup2 always clears any old FD_CLOEXEC flag on the new fd.
00427               if (newfd < orig_dtablesize)
00428                 dtable_cloexec[newfd] = 0;
00429               if (fd == newfd)
00430                 // Same is same as same was.
00431                 break;
00432               err = EXPAND_DTABLE (newfd);
00433               if (!err)
00434                 {
00435                   /* Close the old NEWFD and replace it with FD's
00436                      contents, which can be either an original
00437                      descriptor (DTABLE_CELLS[FD] != 0) or a new
00438                      right that we acquired in this function.  */
00439                   do_close (newfd);
00440                   dtable_cells[newfd] = dtable_cells[fd];
00441                   if (dtable_cells[newfd] != NULL)
00442                     dtable[newfd] = _hurd_port_get (dtable_cells[newfd],
00443                                                 &ulink_dtable[newfd]);
00444                   else
00445                     {
00446                      dtable[newfd] = dtable[fd];
00447                      err = __mach_port_mod_refs (__mach_task_self (),
00448                                               dtable[fd],
00449                                               MACH_PORT_RIGHT_SEND, +1);
00450                     }
00451                 }
00452              }
00453            else
00454              // The old FD specified was bogus.
00455              err = EBADF;
00456            break;
00457 
00458          case spawn_do_open:
00459            /* Open a file on behalf of the child.
00460 
00461               XXX note that this can subject the parent to arbitrary
00462               delays waiting for the files to open.  I don't know what the
00463               spec says about this.  If it's not permissible, then this
00464               whole forkless implementation is probably untenable.  */
00465            {
00466              const int fd = action->action.open_action.fd;
00467 
00468              do_close (fd);
00469              if (fd < orig_dtablesize)
00470               dtable_cloexec[fd] = 0;
00471              err = EXPAND_DTABLE (fd);
00472              if (err)
00473               break;
00474 
00475              err = child_lookup (action->action.open_action.path,
00476                               action->action.open_action.oflag,
00477                               action->action.open_action.mode,
00478                               &dtable[fd]);
00479              dtable_cells[fd] = NULL;
00480              break;
00481            }
00482          }
00483 
00484        if (err)
00485          goto out;
00486       }
00487 
00488   /* Only now can we perform FD_CLOEXEC.  We had to leave the descriptors
00489      unmolested for the file actions to use.  Note that the DTABLE_CLOEXEC
00490      array is never expanded by file actions, so it might now have fewer
00491      than DTABLESIZE elements.  */
00492   for (i = 0; i < orig_dtablesize; ++i)
00493     if (dtable[i] != MACH_PORT_NULL && dtable_cloexec[i])
00494       {
00495        assert (dtable_cells[i] != NULL);
00496        _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
00497        dtable[i] = MACH_PORT_NULL;
00498       }
00499 
00500   /* Prune trailing null ports from the descriptor table.  */
00501   while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
00502     --dtablesize;
00503 
00504   if (flags & POSIX_SPAWN_RESETIDS)
00505     {
00506       /* Reauthenticate all the child's ports with its new auth handle.  */
00507 
00508       mach_port_t ref;
00509       process_t newproc;
00510 
00511       /* Reauthenticate with the proc server.  */
00512       ref = __mach_reply_port ();
00513       err = __proc_reauthenticate (proc, ref, MACH_MSG_TYPE_MAKE_SEND);
00514       if (!err)
00515        err = __auth_user_authenticate (auth,
00516                                    ref, MACH_MSG_TYPE_MAKE_SEND,
00517                                    &newproc);
00518       __mach_port_destroy (__mach_task_self (), ref);
00519       if (!err)
00520        {
00521          __mach_port_deallocate (__mach_task_self (), proc);
00522          proc = newproc;
00523        }
00524 
00525       if (!err)
00526        err = reauthenticate (INIT_PORT_CRDIR, &rcrdir);
00527       if (!err)
00528        err = reauthenticate (INIT_PORT_CWDIR, &rcwdir);
00529 
00530       /* We must reauthenticate all the fds except those that came from
00531         `spawn_do_open' file actions, which were opened using the child's
00532         auth port to begin with.  */
00533       for (i = 0; !err && i < dtablesize; ++i)
00534        err = reauthenticate_fd (i);
00535     }
00536   if (err)
00537     goto out;
00538 
00539   /* Now we are ready to open the executable file using the child's ports.
00540      We do this after performing all the file actions so the order of
00541      events is the same as for a fork, exec sequence.  This affects things
00542      like the meaning of a /dev/fd file name, as well as which error
00543      conditions are diagnosed first and what side effects (file creation,
00544      etc) can be observed before what errors.  */
00545 
00546   if (! use_path || strchr (file, '/') != NULL)
00547     /* The FILE parameter is actually a path.  */
00548     err = child_lookup (file, O_EXEC, 0, &execfile);
00549   else
00550     {
00551       /* We have to search for FILE on the path.  */
00552       path = getenv ("PATH");
00553       if (path == NULL)
00554        {
00555          /* There is no `PATH' in the environment.
00556             The default search path is the current directory
00557             followed by the path `confstr' returns for `_CS_PATH'.  */
00558          len = confstr (_CS_PATH, (char *) NULL, 0);
00559          path = (char *) __alloca (1 + len);
00560          path[0] = ':';
00561          (void) confstr (_CS_PATH, path + 1, len);
00562        }
00563 
00564       len = strlen (file) + 1;
00565       pathlen = strlen (path);
00566       name = __alloca (pathlen + len + 1);
00567       /* Copy the file name at the top.  */
00568       name = (char *) memcpy (name + pathlen + 1, file, len);
00569       /* And add the slash.  */
00570       *--name = '/';
00571 
00572       p = path;
00573       do
00574        {
00575          char *startp;
00576 
00577          path = p;
00578          p = __strchrnul (path, ':');
00579 
00580          if (p == path)
00581            /* Two adjacent colons, or a colon at the beginning or the end
00582               of `PATH' means to search the current directory.  */
00583            startp = name + 1;
00584          else
00585            startp = (char *) memcpy (name - (p - path), path, p - path);
00586 
00587          /* Try to open this file name.  */
00588          err = child_lookup (startp, O_EXEC, 0, &execfile);
00589          switch (err)
00590            {
00591            case EACCES:
00592            case ENOENT:
00593            case ESTALE:
00594            case ENOTDIR:
00595              /* Those errors indicate the file is missing or not executable
00596                by us, in which case we want to just try the next path
00597                directory.  */
00598              continue;
00599 
00600            case 0:          /* Success! */
00601            default:
00602              /* Some other error means we found an executable file, but
00603                something went wrong executing it; return the error to our
00604                caller.  */
00605              break;
00606            }
00607 
00608          // We only get here when we are done looking for the file.
00609          break;
00610        }
00611       while (*p++ != '\0');
00612     }
00613   if (err)
00614     goto out;
00615 
00616   /* Almost there!  */
00617   {
00618     mach_port_t ports[_hurd_nports];
00619     struct hurd_userlink ulink_ports[_hurd_nports];
00620     char *args = NULL, *env = NULL;
00621     size_t argslen = 0, envlen = 0;
00622 
00623     inline error_t exec (file_t file)
00624       {
00625        return __file_exec (file, task,
00626                          (__sigismember (&_hurdsig_traced, SIGKILL)
00627                           ? EXEC_SIGTRAP : 0),
00628                          args, argslen, env, envlen,
00629                          dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
00630                          ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
00631                          ints, INIT_INT_MAX,
00632                          NULL, 0, NULL, 0);
00633       }
00634 
00635     /* Now we are out of things that can fail before the file_exec RPC,
00636        for which everything else must be prepared.  The only thing left
00637        to do is packing up the argument and environment strings,
00638        and the array of init ports.  */
00639 
00640     if (argv != NULL)
00641       err = __argz_create (argv, &args, &argslen);
00642     if (!err && envp != NULL)
00643       err = __argz_create (envp, &env, &envlen);
00644 
00645     /* Load up the ports to give to the new program.
00646        Note the loop/switch below must parallel exactly to release refs.  */
00647     for (i = 0; i < _hurd_nports; ++i)
00648       {
00649        switch (i)
00650          {
00651          case INIT_PORT_AUTH:
00652            ports[i] = auth;
00653            continue;
00654          case INIT_PORT_PROC:
00655            ports[i] = proc;
00656            continue;
00657          case INIT_PORT_CRDIR:
00658            if (flags & POSIX_SPAWN_RESETIDS)
00659              {
00660               ports[i] = rcrdir;
00661               continue;
00662              }
00663            break;
00664          case INIT_PORT_CWDIR:
00665            if (flags & POSIX_SPAWN_RESETIDS)
00666              {
00667               ports[i] = rcwdir;
00668               continue;
00669              }
00670            break;
00671          }
00672        ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
00673       }
00674 
00675     /* Finally, try executing the file we opened.  */
00676     if (!err)
00677       err = exec (execfile);
00678     __mach_port_deallocate (__mach_task_self (), execfile);
00679 
00680     if (err == ENOEXEC)
00681       {
00682        /* The file is accessible but it is not an executable file.
00683           Invoke the shell to interpret it as a script.  */
00684        err = __argz_insert (&args, &argslen, args, _PATH_BSHELL);
00685        if (!err)
00686          err = child_lookup (_PATH_BSHELL, O_EXEC, 0, &execfile);
00687        if (!err)
00688          {
00689            err = exec (execfile);
00690            __mach_port_deallocate (__mach_task_self (), execfile);
00691          }
00692       }
00693 
00694     /* Release the references just packed up in PORTS.
00695        This switch must always parallel the one above that fills PORTS.  */
00696     for (i = 0; i < _hurd_nports; ++i)
00697       {
00698        switch (i)
00699          {
00700          case INIT_PORT_AUTH:
00701          case INIT_PORT_PROC:
00702            continue;
00703          case INIT_PORT_CRDIR:
00704            if (flags & POSIX_SPAWN_RESETIDS)
00705              continue;
00706            break;
00707          case INIT_PORT_CWDIR:
00708            if (flags & POSIX_SPAWN_RESETIDS)
00709              continue;
00710            break;
00711          }
00712        _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
00713       }
00714 
00715     free (args);
00716     free (env);
00717   }
00718 
00719   /* We did it!  We have a child!  */
00720   if (pid != NULL)
00721     *pid = new_pid;
00722 
00723  out:
00724   /* Clean up all the references we are now holding.  */
00725 
00726   if (task != MACH_PORT_NULL)
00727     {
00728       if (err)
00729        /* We failed after creating the task, so kill it.  */
00730        __task_terminate (task);
00731       __mach_port_deallocate (__mach_task_self (), task);
00732     }
00733   __mach_port_deallocate (__mach_task_self (), auth);
00734   __mach_port_deallocate (__mach_task_self (), proc);
00735   if (rcrdir != MACH_PORT_NULL)
00736     __mach_port_deallocate (__mach_task_self (), rcrdir);
00737   if (rcwdir != MACH_PORT_NULL)
00738     __mach_port_deallocate (__mach_task_self (), rcwdir);
00739 
00740   if (ulink_dtable)
00741     /* Release references to the file descriptor ports.  */
00742     for (i = 0; i < dtablesize; ++i)
00743       if (dtable[i] != MACH_PORT_NULL)
00744        {
00745          if (dtable_cells[i] == NULL)
00746            __mach_port_deallocate (__mach_task_self (), dtable[i]);
00747          else
00748            _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
00749        }
00750 
00751   if (err)
00752     /* This hack canonicalizes the error code that we return.  */
00753     err = (__hurd_fail (err), errno);
00754 
00755   return err;
00756 }