(root)/
bison-3.8.2/
lib/
spawni.c
       1  /* Guts of POSIX spawn interface.  Generic POSIX.1 version.
       2     Copyright (C) 2000-2006, 2008-2021 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     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     This file 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
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <config.h>
      19  
      20  /* Specification.  */
      21  #include <spawn.h>
      22  #include "spawn_int.h"
      23  
      24  #include <alloca.h>
      25  #include <errno.h>
      26  
      27  #include <fcntl.h>
      28  #ifndef O_LARGEFILE
      29  # define O_LARGEFILE 0
      30  #endif
      31  
      32  #if _LIBC || HAVE_PATHS_H
      33  # include <paths.h>
      34  #else
      35  # define _PATH_BSHELL BOURNE_SHELL
      36  #endif
      37  
      38  #include <signal.h>
      39  #include <stdlib.h>
      40  #include <string.h>
      41  #include <unistd.h>
      42  
      43  #if _LIBC
      44  # include <not-cancel.h>
      45  #else
      46  # define close_not_cancel close
      47  # define open_not_cancel open
      48  #endif
      49  
      50  #if _LIBC
      51  # include <local-setxid.h>
      52  #else
      53  # if !HAVE_SETEUID
      54  #  define seteuid(id) setresuid (-1, id, -1)
      55  # endif
      56  # if !HAVE_SETEGID
      57  #  define setegid(id) setresgid (-1, id, -1)
      58  # endif
      59  # define local_seteuid(id) seteuid (id)
      60  # define local_setegid(id) setegid (id)
      61  #endif
      62  
      63  #if _LIBC
      64  # define alloca __alloca
      65  # define execve __execve
      66  # define dup2 __dup2
      67  # define fork __fork
      68  # define getgid __getgid
      69  # define getuid __getuid
      70  # define sched_setparam __sched_setparam
      71  # define sched_setscheduler __sched_setscheduler
      72  # define setpgid __setpgid
      73  # define sigaction __sigaction
      74  # define sigismember __sigismember
      75  # define sigprocmask __sigprocmask
      76  # define strchrnul __strchrnul
      77  # define vfork __vfork
      78  #endif
      79  
      80  
      81  /* The Unix standard contains a long explanation of the way to signal
      82     an error after the fork() was successful.  Since no new wait status
      83     was wanted there is no way to signal an error using one of the
      84     available methods.  The committee chose to signal an error by a
      85     normal program exit with the exit code 127.  */
      86  #define SPAWN_ERROR     127
      87  
      88  
      89  #if defined _WIN32 && ! defined __CYGWIN__
      90  /* Native Windows API.  */
      91  
      92  /* Get declarations of the native Windows API functions.  */
      93  # define WIN32_LEAN_AND_MEAN
      94  # include <windows.h>
      95  
      96  # include <stdbool.h>
      97  # include <stdio.h>
      98  
      99  # include "filename.h"
     100  # include "concat-filename.h"
     101  # include "findprog.h"
     102  # include "malloca.h"
     103  # include "windows-spawn.h"
     104  
     105  /* Don't assume that UNICODE is not defined.  */
     106  # undef CreateFile
     107  # define CreateFile CreateFileA
     108  # undef STARTUPINFO
     109  # define STARTUPINFO STARTUPINFOA
     110  # undef CreateProcess
     111  # define CreateProcess CreateProcessA
     112  
     113  /* Grows inh_handles->count so that it becomes > newfd.
     114     Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
     115   */
     116  static int
     117  grow_inheritable_handles (struct inheritable_handles *inh_handles, int newfd)
     118  {
     119    if (inh_handles->allocated <= newfd)
     120      {
     121        size_t new_allocated = 2 * inh_handles->allocated + 1;
     122        if (new_allocated <= newfd)
     123          new_allocated = newfd + 1;
     124        HANDLE *new_handles_array =
     125          (HANDLE *)
     126          realloc (inh_handles->handles, new_allocated * sizeof (HANDLE));
     127        if (new_handles_array == NULL)
     128          {
     129            errno = ENOMEM;
     130            return -1;
     131          }
     132        unsigned char *new_flags_array =
     133          (unsigned char *)
     134          realloc (inh_handles->flags, new_allocated * sizeof (unsigned char));
     135        if (new_flags_array == NULL)
     136          {
     137            free (new_handles_array);
     138            errno = ENOMEM;
     139            return -1;
     140          }
     141        inh_handles->allocated = new_allocated;
     142        inh_handles->handles = new_handles_array;
     143        inh_handles->flags = new_flags_array;
     144      }
     145  
     146    HANDLE *handles = inh_handles->handles;
     147  
     148    for (; inh_handles->count <= newfd; inh_handles->count++)
     149      handles[inh_handles->count] = INVALID_HANDLE_VALUE;
     150  
     151    return 0;
     152  }
     153  
     154  /* Reduces inh_handles->count to the minimum needed.  */
     155  static void
     156  shrink_inheritable_handles (struct inheritable_handles *inh_handles)
     157  {
     158    HANDLE *handles = inh_handles->handles;
     159  
     160    while (inh_handles->count > 3
     161           && handles[inh_handles->count - 1] == INVALID_HANDLE_VALUE)
     162      inh_handles->count--;
     163  }
     164  
     165  /* Closes all handles in inh_handles.  */
     166  static void
     167  close_inheritable_handles (struct inheritable_handles *inh_handles)
     168  {
     169    HANDLE *handles = inh_handles->handles;
     170    size_t handles_count = inh_handles->count;
     171    unsigned int fd;
     172  
     173    for (fd = 0; fd < handles_count; fd++)
     174      {
     175        HANDLE handle = handles[fd];
     176  
     177        if (handle != INVALID_HANDLE_VALUE)
     178          CloseHandle (handle);
     179      }
     180  }
     181  
     182  /* Tests whether a memory region, starting at P and N bytes long, contains only
     183     zeroes.  */
     184  static bool
     185  memiszero (const void *p, size_t n)
     186  {
     187    const char *cp = p;
     188    for (; n > 0; cp++, n--)
     189      if (*cp != 0)
     190        return 0;
     191    return 1;
     192  }
     193  
     194  /* Tests whether *S contains no signals.  */
     195  static bool
     196  sigisempty (const sigset_t *s)
     197  {
     198    return memiszero (s, sizeof (sigset_t));
     199  }
     200  
     201  /* Opens a HANDLE to a file.
     202     Upon failure, returns INVALID_HANDLE_VALUE with errno set.  */
     203  static HANDLE
     204  open_handle (const char *name, int flags, mode_t mode)
     205  {
     206    /* To ease portability.  Like in open.c.  */
     207    if (strcmp (name, "/dev/null") == 0)
     208      name = "NUL";
     209  
     210    /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
     211       specifies: "More than two leading <slash> characters shall be treated as
     212       a single <slash> character."  */
     213    if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2]))
     214      {
     215        name += 2;
     216        while (ISSLASH (name[1]))
     217          name++;
     218      }
     219  
     220    size_t len = strlen (name);
     221    size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
     222  
     223    /* Remove trailing slashes (except the very first one, at position
     224       drive_prefix_len), but remember their presence.  */
     225    size_t rlen;
     226    bool check_dir = false;
     227  
     228    rlen = len;
     229    while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
     230      {
     231        check_dir = true;
     232        if (rlen == drive_prefix_len + 1)
     233          break;
     234        rlen--;
     235      }
     236  
     237    /* Handle '' and 'C:'.  */
     238    if (!check_dir && rlen == drive_prefix_len)
     239      {
     240        errno = ENOENT;
     241        return INVALID_HANDLE_VALUE;
     242      }
     243  
     244    /* Handle '\\'.  */
     245    if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
     246      {
     247        errno = ENOENT;
     248        return INVALID_HANDLE_VALUE;
     249      }
     250  
     251    const char *rname;
     252    char *malloca_rname;
     253    if (rlen == len)
     254      {
     255        rname = name;
     256        malloca_rname = NULL;
     257      }
     258    else
     259      {
     260        malloca_rname = malloca (rlen + 1);
     261        if (malloca_rname == NULL)
     262          {
     263            errno = ENOMEM;
     264            return INVALID_HANDLE_VALUE;
     265          }
     266        memcpy (malloca_rname, name, rlen);
     267        malloca_rname[rlen] = '\0';
     268        rname = malloca_rname;
     269      }
     270  
     271    /* For the meaning of the flags, see
     272       <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-wopen>  */
     273    /* Open a handle to the file.
     274       CreateFile
     275       <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea>
     276       <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files>  */
     277    HANDLE handle =
     278      CreateFile (rname,
     279                  ((flags & (O_WRONLY | O_RDWR)) != 0
     280                   ? GENERIC_READ | GENERIC_WRITE
     281                   : GENERIC_READ),
     282                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     283                  NULL,
     284                  ((flags & O_CREAT) != 0
     285                   ? ((flags & O_EXCL) != 0
     286                      ? CREATE_NEW
     287                      : ((flags & O_TRUNC) != 0 ? CREATE_ALWAYS : OPEN_ALWAYS))
     288                   : ((flags & O_TRUNC) != 0
     289                      ? TRUNCATE_EXISTING
     290                      : OPEN_EXISTING)),
     291                  /* FILE_FLAG_BACKUP_SEMANTICS is useful for opening directories,
     292                     which is out-of-scope here.  */
     293                  /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
     294                     in case as different) makes sense only when applied to *all*
     295                     filesystem operations.  */
     296                  /* FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS */
     297                  FILE_ATTRIBUTE_NORMAL
     298                  | ((flags & O_TEMPORARY) != 0 ? FILE_FLAG_DELETE_ON_CLOSE : 0)
     299                  | ((flags & O_SEQUENTIAL ) != 0 ? FILE_FLAG_SEQUENTIAL_SCAN : 0)
     300                  | ((flags & O_RANDOM) != 0 ? FILE_FLAG_RANDOM_ACCESS : 0),
     301                  NULL);
     302    if (handle == INVALID_HANDLE_VALUE)
     303      switch (GetLastError ())
     304        {
     305        /* Some of these errors probably cannot happen with the specific flags
     306           that we pass to CreateFile.  But who knows...  */
     307        case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist.  */
     308        case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist.  */
     309        case ERROR_BAD_PATHNAME:   /* rname is such as '\\server'.  */
     310        case ERROR_BAD_NETPATH:    /* rname is such as '\\nonexistentserver\share'.  */
     311        case ERROR_BAD_NET_NAME:   /* rname is such as '\\server\nonexistentshare'.  */
     312        case ERROR_INVALID_NAME:   /* rname contains wildcards, misplaced colon, etc.  */
     313        case ERROR_DIRECTORY:
     314          errno = ENOENT;
     315          break;
     316  
     317        case ERROR_ACCESS_DENIED:  /* rname is such as 'C:\System Volume Information\foo'.  */
     318        case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys'.  */
     319                                      /* XXX map to EACCES or EPERM? */
     320          errno = EACCES;
     321          break;
     322  
     323        case ERROR_OUTOFMEMORY:
     324          errno = ENOMEM;
     325          break;
     326  
     327        case ERROR_WRITE_PROTECT:
     328          errno = EROFS;
     329          break;
     330  
     331        case ERROR_WRITE_FAULT:
     332        case ERROR_READ_FAULT:
     333        case ERROR_GEN_FAILURE:
     334          errno = EIO;
     335          break;
     336  
     337        case ERROR_BUFFER_OVERFLOW:
     338        case ERROR_FILENAME_EXCED_RANGE:
     339          errno = ENAMETOOLONG;
     340          break;
     341  
     342        case ERROR_DELETE_PENDING: /* XXX map to EACCES or EPERM? */
     343          errno = EPERM;
     344          break;
     345  
     346        default:
     347          errno = EINVAL;
     348          break;
     349        }
     350  
     351    if (malloca_rname != NULL)
     352      {
     353        int saved_errno = errno;
     354        freea (malloca_rname);
     355        errno = saved_errno;
     356      }
     357    return handle;
     358  }
     359  
     360  /* Executes an 'open' action.
     361     Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
     362   */
     363  static int
     364  do_open (struct inheritable_handles *inh_handles, int newfd,
     365           const char *filename, const char *directory,
     366           int flags, mode_t mode, HANDLE curr_process)
     367  {
     368    if (!(newfd >= 0 && newfd < _getmaxstdio ()))
     369      {
     370        errno = EBADF;
     371        return -1;
     372      }
     373    if (grow_inheritable_handles (inh_handles, newfd) < 0)
     374      return -1;
     375    if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
     376        && !CloseHandle (inh_handles->handles[newfd]))
     377      {
     378        errno = EIO;
     379        return -1;
     380      }
     381    if (filename == NULL)
     382      {
     383        errno = EINVAL;
     384        return -1;
     385      }
     386    char *filename_to_free = NULL;
     387    if (directory != NULL && IS_RELATIVE_FILE_NAME (filename))
     388      {
     389        char *real_filename = concatenated_filename (directory, filename, NULL);
     390        if (real_filename == NULL)
     391          {
     392            errno = ENOMEM;
     393            return -1;
     394          }
     395        filename = real_filename;
     396        filename_to_free = real_filename;
     397      }
     398    HANDLE handle = open_handle (filename, flags, mode);
     399    if (handle == INVALID_HANDLE_VALUE)
     400      {
     401        free (filename_to_free);
     402        return -1;
     403      }
     404    free (filename_to_free);
     405    /* Duplicate the handle, so that it becomes inheritable.  */
     406    if (!DuplicateHandle (curr_process, handle,
     407                          curr_process, &inh_handles->handles[newfd],
     408                          0, TRUE,
     409                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
     410      {
     411        errno = EBADF; /* arbitrary */
     412        return -1;
     413      }
     414    inh_handles->flags[newfd] = ((flags & O_APPEND) != 0 ? 32 : 0);
     415    return 0;
     416  }
     417  
     418  /* Executes a 'dup2' action.
     419     Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
     420   */
     421  static int
     422  do_dup2 (struct inheritable_handles *inh_handles, int oldfd, int newfd,
     423           HANDLE curr_process)
     424  {
     425    if (!(oldfd >= 0 && oldfd < inh_handles->count
     426          && inh_handles->handles[oldfd] != INVALID_HANDLE_VALUE))
     427      {
     428        errno = EBADF;
     429        return -1;
     430      }
     431    if (!(newfd >= 0 && newfd < _getmaxstdio ()))
     432      {
     433        errno = EBADF;
     434        return -1;
     435      }
     436    if (newfd != oldfd)
     437      {
     438        if (grow_inheritable_handles (inh_handles, newfd) < 0)
     439          return -1;
     440        if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
     441            && !CloseHandle (inh_handles->handles[newfd]))
     442          {
     443            errno = EIO;
     444            return -1;
     445          }
     446        /* Duplicate the handle, so that it a forthcoming do_close action on oldfd
     447           has no effect on newfd.  */
     448        if (!DuplicateHandle (curr_process, inh_handles->handles[oldfd],
     449                              curr_process, &inh_handles->handles[newfd],
     450                              0, TRUE, DUPLICATE_SAME_ACCESS))
     451          {
     452            errno = EBADF; /* arbitrary */
     453            return -1;
     454          }
     455        inh_handles->flags[newfd] = 0;
     456      }
     457    return 0;
     458  }
     459  
     460  /* Executes a 'close' action.
     461     Returns 0 upon success.  In case of failure, -1 is returned, with errno set.
     462   */
     463  static int
     464  do_close (struct inheritable_handles *inh_handles, int fd)
     465  {
     466    if (!(fd >= 0 && fd < inh_handles->count
     467          && inh_handles->handles[fd] != INVALID_HANDLE_VALUE))
     468      {
     469        errno = EBADF;
     470        return -1;
     471      }
     472    if (!CloseHandle (inh_handles->handles[fd]))
     473      {
     474        errno = EIO;
     475        return -1;
     476      }
     477    inh_handles->handles[fd] = INVALID_HANDLE_VALUE;
     478    return 0;
     479  }
     480  
     481  int
     482  __spawni (pid_t *pid, const char *prog_filename,
     483            const posix_spawn_file_actions_t *file_actions,
     484            const posix_spawnattr_t *attrp, const char *const prog_argv[],
     485            const char *const envp[], int use_path)
     486  {
     487    /* Validate the arguments.  */
     488    if (prog_filename == NULL
     489        || (attrp != NULL
     490            && ((attrp->_flags & ~POSIX_SPAWN_SETPGROUP) != 0
     491                || attrp->_pgrp != 0
     492                || ! sigisempty (&attrp->_sd)
     493                || ! sigisempty (&attrp->_ss)
     494                || attrp->_sp.sched_priority != 0
     495                || attrp->_policy != 0)))
     496      return EINVAL;
     497  
     498    /* Process group handling:
     499       Native Windows does not have the concept of process group, but it has the
     500       concept of a console attached to a process.
     501       So, we interpret the three cases as follows:
     502         - Flag POSIX_SPAWN_SETPGROUP not set: Means, the child process is in the
     503           same process group as the parent process.  We interpret this as a
     504           request to reuse the same console.
     505         - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp == 0: Means the child
     506           process starts a process group of its own.  See
     507           <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
     508           <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html>
     509           We interpret this as a request to detach from the current console.
     510         - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp != 0: Means the child
     511           process joins another, existing process group.  See
     512           <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
     513           <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html>
     514           We don't support this case; it produces error EINVAL above.  */
     515    /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags>  */
     516    DWORD process_creation_flags =
     517      (attrp != NULL && (attrp->_flags & POSIX_SPAWN_SETPGROUP) != 0 ? DETACHED_PROCESS : 0);
     518  
     519    char *argv_mem_to_free;
     520    const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
     521    if (argv == NULL)
     522      return errno; /* errno is set here */
     523    argv++;
     524  
     525    /* Compose the command.  */
     526    char *command = compose_command (argv);
     527    if (command == NULL)
     528      {
     529        free (argv_mem_to_free);
     530        return ENOMEM;
     531      }
     532  
     533    /* Copy *ENVP into a contiguous block of memory.  */
     534    char *envblock;
     535    if (envp == NULL)
     536      envblock = NULL;
     537    else
     538      {
     539        envblock = compose_envblock (envp);
     540        if (envblock == NULL)
     541          {
     542            free (command);
     543            free (argv_mem_to_free);
     544            return ENOMEM;
     545          }
     546      }
     547  
     548    /* Set up the array of handles to inherit.
     549       Duplicate each handle, so that a spawn_do_close action (below) has no
     550       effect on the file descriptors of the current process.  Alternatively,
     551       we could store, for each handle, a bit that tells whether it is shared
     552       with the current process.  But this is simpler.  */
     553    struct inheritable_handles inh_handles;
     554    if (init_inheritable_handles (&inh_handles, true) < 0)
     555      goto failed_1;
     556  
     557    /* Directory in which to execute the new process.  */
     558    const char *directory = NULL;
     559  
     560    /* Execute the file_actions, modifying the inh_handles instead of the
     561       file descriptors of the current process.  */
     562    if (file_actions != NULL)
     563      {
     564        HANDLE curr_process = GetCurrentProcess ();
     565        int cnt;
     566  
     567        for (cnt = 0; cnt < file_actions->_used; ++cnt)
     568          {
     569            struct __spawn_action *action = &file_actions->_actions[cnt];
     570  
     571            switch (action->tag)
     572              {
     573              case spawn_do_close:
     574                {
     575                  int fd = action->action.close_action.fd;
     576                  if (do_close (&inh_handles, fd) < 0)
     577                    goto failed_2;
     578                }
     579                break;
     580  
     581              case spawn_do_open:
     582                {
     583                  int newfd = action->action.open_action.fd;
     584                  const char *filename = action->action.open_action.path;
     585                  int flags = action->action.open_action.oflag;
     586                  mode_t mode = action->action.open_action.mode;
     587                  if (do_open (&inh_handles, newfd, filename, directory,
     588                               flags, mode, curr_process)
     589                      < 0)
     590                    goto failed_2;
     591                }
     592                break;
     593  
     594              case spawn_do_dup2:
     595                {
     596                  int oldfd = action->action.dup2_action.fd;
     597                  int newfd = action->action.dup2_action.newfd;
     598                  if (do_dup2 (&inh_handles, oldfd, newfd, curr_process) < 0)
     599                    goto failed_2;
     600                }
     601                break;
     602  
     603              case spawn_do_chdir:
     604                {
     605                  char *newdir = action->action.chdir_action.path;
     606                  if (directory != NULL && IS_RELATIVE_FILE_NAME (newdir))
     607                    {
     608                      newdir = concatenated_filename (directory, newdir, NULL);
     609                      if (newdir == NULL)
     610                        {
     611                          errno = ENOMEM;
     612                          goto failed_2;
     613                        }
     614                    }
     615                  directory = newdir;
     616                }
     617                break;
     618  
     619              case spawn_do_fchdir:
     620                /* Not supported in this implementation.  */
     621                errno = EINVAL;
     622                goto failed_2;
     623              }
     624          }
     625      }
     626  
     627    /* Reduce inh_handles.count to the minimum needed.  */
     628    shrink_inheritable_handles (&inh_handles);
     629  
     630    /* CreateProcess
     631       <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa>  */
     632    /* STARTUPINFO
     633       <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa>  */
     634    STARTUPINFO sinfo;
     635    sinfo.cb = sizeof (STARTUPINFO);
     636    sinfo.lpReserved = NULL;
     637    sinfo.lpDesktop = NULL;
     638    sinfo.lpTitle = NULL;
     639    if (compose_handles_block (&inh_handles, &sinfo) < 0)
     640      goto failed_2;
     641  
     642    /* Perform the PATH search now, considering the final DIRECTORY.  */
     643    char *resolved_prog_filename_to_free = NULL;
     644    {
     645      const char *resolved_prog_filename =
     646        find_in_given_path (prog_filename, use_path ? getenv ("PATH") : "",
     647                            directory, false);
     648      if (resolved_prog_filename == NULL)
     649        goto failed_3;
     650      if (resolved_prog_filename != prog_filename)
     651        resolved_prog_filename_to_free = (char *) resolved_prog_filename;
     652      prog_filename = resolved_prog_filename;
     653    }
     654  
     655    PROCESS_INFORMATION pinfo;
     656    if (!CreateProcess (prog_filename, command, NULL, NULL, TRUE,
     657                        process_creation_flags, envblock, directory, &sinfo,
     658                        &pinfo))
     659      {
     660        DWORD error = GetLastError ();
     661  
     662        free (resolved_prog_filename_to_free);
     663        free (sinfo.lpReserved2);
     664        close_inheritable_handles (&inh_handles);
     665        free_inheritable_handles (&inh_handles);
     666        free (envblock);
     667        free (command);
     668        free (argv_mem_to_free);
     669  
     670        return convert_CreateProcess_error (error);
     671      }
     672  
     673    if (pinfo.hThread)
     674      CloseHandle (pinfo.hThread);
     675  
     676    free (resolved_prog_filename_to_free);
     677    free (sinfo.lpReserved2);
     678    close_inheritable_handles (&inh_handles);
     679    free_inheritable_handles (&inh_handles);
     680    free (envblock);
     681    free (command);
     682    free (argv_mem_to_free);
     683  
     684    if (pid != NULL)
     685      *pid = (intptr_t) pinfo.hProcess;
     686    return 0;
     687  
     688   failed_3:
     689    {
     690      int saved_errno = errno;
     691      free (sinfo.lpReserved2);
     692      close_inheritable_handles (&inh_handles);
     693      free_inheritable_handles (&inh_handles);
     694      free (envblock);
     695      free (command);
     696      free (argv_mem_to_free);
     697      return saved_errno;
     698    }
     699  
     700   failed_2:
     701    {
     702      int saved_errno = errno;
     703      close_inheritable_handles (&inh_handles);
     704      free_inheritable_handles (&inh_handles);
     705      free (envblock);
     706      free (command);
     707      free (argv_mem_to_free);
     708      return saved_errno;
     709    }
     710  
     711   failed_1:
     712    free (envblock);
     713    free (command);
     714    free (argv_mem_to_free);
     715    return errno;
     716  }
     717  
     718  #else
     719  
     720  
     721  /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
     722     Before running the process perform the actions described in FILE-ACTIONS. */
     723  int
     724  __spawni (pid_t *pid, const char *file,
     725            const posix_spawn_file_actions_t *file_actions,
     726            const posix_spawnattr_t *attrp, const char *const argv[],
     727            const char *const envp[], int use_path)
     728  {
     729    pid_t new_pid;
     730    char *path, *p, *name;
     731    size_t len;
     732    size_t pathlen;
     733  
     734    /* Do this once.  */
     735    short int flags = attrp == NULL ? 0 : attrp->_flags;
     736  
     737    /* Avoid gcc warning
     738         "variable 'flags' might be clobbered by 'longjmp' or 'vfork'"  */
     739    (void) &flags;
     740  
     741    /* Generate the new process.  */
     742  #if HAVE_VFORK
     743    if ((flags & POSIX_SPAWN_USEVFORK) != 0
     744        /* If no major work is done, allow using vfork.  Note that we
     745           might perform the path searching.  But this would be done by
     746           a call to execvp(), too, and such a call must be OK according
     747           to POSIX.  */
     748        || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
     749                      | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
     750                      | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
     751            && file_actions == NULL))
     752      new_pid = vfork ();
     753    else
     754  #endif
     755      new_pid = fork ();
     756  
     757    if (new_pid != 0)
     758      {
     759        if (new_pid < 0)
     760          return errno;
     761  
     762        /* The call was successful.  Store the PID if necessary.  */
     763        if (pid != NULL)
     764          *pid = new_pid;
     765  
     766        return 0;
     767      }
     768  
     769    /* Set signal mask.  */
     770    if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
     771        && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
     772      _exit (SPAWN_ERROR);
     773  
     774    /* Set signal default action.  */
     775    if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
     776      {
     777        /* We have to iterate over all signals.  This could possibly be
     778           done better but it requires system specific solutions since
     779           the sigset_t data type can be very different on different
     780           architectures.  */
     781        int sig;
     782        struct sigaction sa;
     783  
     784        memset (&sa, '\0', sizeof (sa));
     785        sa.sa_handler = SIG_DFL;
     786  
     787        for (sig = 1; sig <= NSIG; ++sig)
     788          if (sigismember (&attrp->_sd, sig) != 0
     789              && sigaction (sig, &sa, NULL) != 0)
     790            _exit (SPAWN_ERROR);
     791  
     792      }
     793  
     794  #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
     795    /* Set the scheduling algorithm and parameters.  */
     796    if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
     797        == POSIX_SPAWN_SETSCHEDPARAM)
     798      {
     799        if (sched_setparam (0, &attrp->_sp) == -1)
     800          _exit (SPAWN_ERROR);
     801      }
     802    else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
     803      {
     804        if (sched_setscheduler (0, attrp->_policy,
     805                                (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
     806                                ? &attrp->_sp : NULL) == -1)
     807          _exit (SPAWN_ERROR);
     808      }
     809  #endif
     810  
     811    /* Set the process group ID.  */
     812    if ((flags & POSIX_SPAWN_SETPGROUP) != 0
     813        && setpgid (0, attrp->_pgrp) != 0)
     814      _exit (SPAWN_ERROR);
     815  
     816    /* Set the effective user and group IDs.  */
     817    if ((flags & POSIX_SPAWN_RESETIDS) != 0
     818        && (local_seteuid (getuid ()) != 0
     819            || local_setegid (getgid ()) != 0))
     820      _exit (SPAWN_ERROR);
     821  
     822    /* Execute the file actions.  */
     823    if (file_actions != NULL)
     824      {
     825        int cnt;
     826  
     827        for (cnt = 0; cnt < file_actions->_used; ++cnt)
     828          {
     829            struct __spawn_action *action = &file_actions->_actions[cnt];
     830  
     831            switch (action->tag)
     832              {
     833              case spawn_do_close:
     834                if (close_not_cancel (action->action.close_action.fd) != 0)
     835                  /* Signal the error.  */
     836                  _exit (SPAWN_ERROR);
     837                break;
     838  
     839              case spawn_do_open:
     840                {
     841                  int new_fd = open_not_cancel (action->action.open_action.path,
     842                                                action->action.open_action.oflag
     843                                                | O_LARGEFILE,
     844                                                action->action.open_action.mode);
     845  
     846                  if (new_fd == -1)
     847                    /* The 'open' call failed.  */
     848                    _exit (SPAWN_ERROR);
     849  
     850                  /* Make sure the desired file descriptor is used.  */
     851                  if (new_fd != action->action.open_action.fd)
     852                    {
     853                      if (dup2 (new_fd, action->action.open_action.fd)
     854                          != action->action.open_action.fd)
     855                        /* The 'dup2' call failed.  */
     856                        _exit (SPAWN_ERROR);
     857  
     858                      if (close_not_cancel (new_fd) != 0)
     859                        /* The 'close' call failed.  */
     860                        _exit (SPAWN_ERROR);
     861                    }
     862                }
     863                break;
     864  
     865              case spawn_do_dup2:
     866                if (dup2 (action->action.dup2_action.fd,
     867                          action->action.dup2_action.newfd)
     868                    != action->action.dup2_action.newfd)
     869                  /* The 'dup2' call failed.  */
     870                  _exit (SPAWN_ERROR);
     871                break;
     872  
     873              case spawn_do_chdir:
     874                if (chdir (action->action.chdir_action.path) < 0)
     875                  /* The 'chdir' call failed.  */
     876                  _exit (SPAWN_ERROR);
     877                break;
     878  
     879              case spawn_do_fchdir:
     880                if (fchdir (action->action.fchdir_action.fd) < 0)
     881                  /* The 'fchdir' call failed.  */
     882                  _exit (SPAWN_ERROR);
     883                break;
     884              }
     885          }
     886      }
     887  
     888    if (! use_path || strchr (file, '/') != NULL)
     889      {
     890        /* The FILE parameter is actually a path.  */
     891        execve (file, (char * const *) argv, (char * const *) envp);
     892  
     893        /* Oh, oh.  'execve' returns.  This is bad.  */
     894        _exit (SPAWN_ERROR);
     895      }
     896  
     897    /* We have to search for FILE on the path.  */
     898    path = getenv ("PATH");
     899    if (path == NULL)
     900      {
     901  #if HAVE_CONFSTR
     902        /* There is no 'PATH' in the environment.
     903           The default search path is the current directory
     904           followed by the path 'confstr' returns for '_CS_PATH'.  */
     905        len = confstr (_CS_PATH, (char *) NULL, 0);
     906        path = (char *) alloca (1 + len);
     907        path[0] = ':';
     908        (void) confstr (_CS_PATH, path + 1, len);
     909  #else
     910        /* Pretend that the PATH contains only the current directory.  */
     911        path = "";
     912  #endif
     913      }
     914  
     915    len = strlen (file) + 1;
     916    pathlen = strlen (path);
     917    name = alloca (pathlen + len + 1);
     918    /* Copy the file name at the top.  */
     919    name = (char *) memcpy (name + pathlen + 1, file, len);
     920    /* And add the slash.  */
     921    *--name = '/';
     922  
     923    p = path;
     924    do
     925      {
     926        char *startp;
     927  
     928        path = p;
     929        p = strchrnul (path, ':');
     930  
     931        if (p == path)
     932          /* Two adjacent colons, or a colon at the beginning or the end
     933             of 'PATH' means to search the current directory.  */
     934          startp = name + 1;
     935        else
     936          startp = (char *) memcpy (name - (p - path), path, p - path);
     937  
     938        /* Try to execute this name.  If it works, execv will not return.  */
     939        execve (startp, (char * const *) argv, (char * const *) envp);
     940  
     941        switch (errno)
     942          {
     943          case EACCES:
     944          case ENOENT:
     945          case ESTALE:
     946          case ENOTDIR:
     947            /* Those errors indicate the file is missing or not executable
     948               by us, in which case we want to just try the next path
     949               directory.  */
     950            break;
     951  
     952          default:
     953            /* Some other error means we found an executable file, but
     954               something went wrong executing it; return the error to our
     955               caller.  */
     956            _exit (SPAWN_ERROR);
     957          }
     958      }
     959    while (*p++ != '\0');
     960  
     961    /* Return with an error.  */
     962    _exit (SPAWN_ERROR);
     963  }
     964  
     965  #endif