(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
windows-spawn.c
       1  /* Auxiliary functions for the creation of subprocesses.  Native Windows API.
       2     Copyright (C) 2001, 2003-2023 Free Software Foundation, Inc.
       3     Written by Bruno Haible <bruno@clisp.org>, 2003.
       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 "windows-spawn.h"
      22  
      23  /* Get declarations of the native Windows API functions.  */
      24  #define WIN32_LEAN_AND_MEAN
      25  #include <windows.h>
      26  
      27  #include <stdio.h>
      28  #include <stdlib.h>
      29  #include <string.h>
      30  #include <errno.h>
      31  
      32  /* Get _get_osfhandle().  */
      33  #if GNULIB_MSVC_NOTHROW
      34  # include "msvc-nothrow.h"
      35  #else
      36  # include <io.h>
      37  #endif
      38  #include <process.h>
      39  
      40  #include "findprog.h"
      41  
      42  /* Don't assume that UNICODE is not defined.  */
      43  #undef STARTUPINFO
      44  #define STARTUPINFO STARTUPINFOA
      45  #undef CreateProcess
      46  #define CreateProcess CreateProcessA
      47  
      48  #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?"
      49  #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
      50  
      51  /* Returns the length of a quoted argument string.  */
      52  static size_t
      53  quoted_arg_length (const char *string)
      54  {
      55    bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
      56    size_t length;
      57    unsigned int backslashes;
      58    const char *s;
      59  
      60    length = 0;
      61    backslashes = 0;
      62    if (quote_around)
      63      length++;
      64    for (s = string; *s != '\0'; s++)
      65      {
      66        char c = *s;
      67        if (c == '"')
      68          length += backslashes + 1;
      69        length++;
      70        if (c == '\\')
      71          backslashes++;
      72        else
      73          backslashes = 0;
      74      }
      75    if (quote_around)
      76      length += backslashes + 1;
      77  
      78    return length;
      79  }
      80  
      81  /* Produces a quoted argument string.
      82     Stores exactly quoted_arg_length (STRING) + 1 bytes, including the final
      83     NUL byte, at MEM.
      84     Returns a pointer past the stored quoted argument string.  */
      85  static char *
      86  quoted_arg_string (const char *string, char *mem)
      87  {
      88    bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
      89    char *p;
      90    unsigned int backslashes;
      91    const char *s;
      92  
      93    p = mem;
      94    backslashes = 0;
      95    if (quote_around)
      96      *p++ = '"';
      97    for (s = string; *s != '\0'; s++)
      98      {
      99        char c = *s;
     100        if (c == '"')
     101          {
     102            unsigned int j;
     103            for (j = backslashes + 1; j > 0; j--)
     104              *p++ = '\\';
     105          }
     106        *p++ = c;
     107        if (c == '\\')
     108          backslashes++;
     109        else
     110          backslashes = 0;
     111      }
     112    if (quote_around)
     113      {
     114        unsigned int j;
     115        for (j = backslashes; j > 0; j--)
     116          *p++ = '\\';
     117        *p++ = '"';
     118      }
     119    *p++ = '\0';
     120  
     121    return p;
     122  }
     123  
     124  const char **
     125  prepare_spawn (const char * const *argv, char **mem_to_free)
     126  {
     127    size_t argc;
     128    const char **new_argv;
     129    size_t i;
     130  
     131    /* Count number of arguments.  */
     132    for (argc = 0; argv[argc] != NULL; argc++)
     133      ;
     134  
     135    /* Allocate new argument vector.  */
     136    new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
     137  
     138    /* Add an element upfront that can be used when argv[0] turns out to be a
     139       script, not a program.
     140       On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
     141       "sh.exe".  We have to omit the directory part and rely on the search in
     142       PATH, because the mingw "mount points" are not visible inside Windows
     143       CreateProcess().  */
     144    new_argv[0] = "sh.exe";
     145  
     146    /* Put quoted arguments into the new argument vector.  */
     147    size_t needed_size = 0;
     148    for (i = 0; i < argc; i++)
     149      {
     150        const char *string = argv[i];
     151        size_t length;
     152  
     153        if (string[0] == '\0')
     154          length = strlen ("\"\"");
     155        else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
     156          length = quoted_arg_length (string);
     157        else
     158          length = strlen (string);
     159        needed_size += length + 1;
     160      }
     161  
     162    char *mem;
     163    if (needed_size == 0)
     164      mem = NULL;
     165    else
     166      {
     167        mem = (char *) malloc (needed_size);
     168        if (mem == NULL)
     169          {
     170            /* Memory allocation failure.  */
     171            free (new_argv);
     172            errno = ENOMEM;
     173            return NULL;
     174          }
     175      }
     176    *mem_to_free = mem;
     177  
     178    for (i = 0; i < argc; i++)
     179      {
     180        const char *string = argv[i];
     181  
     182        new_argv[1 + i] = mem;
     183        if (string[0] == '\0')
     184          {
     185            size_t length = strlen ("\"\"");
     186            memcpy (mem, "\"\"", length + 1);
     187            mem += length + 1;
     188          }
     189        else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
     190          {
     191            mem = quoted_arg_string (string, mem);
     192          }
     193        else
     194          {
     195            size_t length = strlen (string);
     196            memcpy (mem, string, length + 1);
     197            mem += length + 1;
     198          }
     199      }
     200    new_argv[1 + argc] = NULL;
     201  
     202    return new_argv;
     203  }
     204  
     205  char *
     206  compose_command (const char * const *argv)
     207  {
     208    /* Just concatenate the argv[] strings, separated by spaces.  */
     209    char *command;
     210  
     211    /* Determine the size of the needed block of memory.  */
     212    size_t total_size = 0;
     213    const char * const *ap;
     214    const char *p;
     215    for (ap = argv; (p = *ap) != NULL; ap++)
     216      total_size += strlen (p) + 1;
     217    size_t command_size = (total_size > 0 ? total_size : 1);
     218  
     219    /* Allocate the block of memory.  */
     220    command = (char *) malloc (command_size);
     221    if (command == NULL)
     222      {
     223        errno = ENOMEM;
     224        return NULL;
     225      }
     226  
     227    /* Fill it.  */
     228    if (total_size > 0)
     229      {
     230        char *cp = command;
     231        for (ap = argv; (p = *ap) != NULL; ap++)
     232          {
     233            size_t size = strlen (p) + 1;
     234            memcpy (cp, p, size - 1);
     235            cp += size;
     236            cp[-1] = ' ';
     237          }
     238        cp[-1] = '\0';
     239      }
     240    else
     241      *command = '\0';
     242  
     243    return command;
     244  }
     245  
     246  char *
     247  compose_envblock (const char * const *envp)
     248  {
     249    /* This is a bit hairy, because we don't have a lock that would prevent other
     250       threads from making modifications in ENVP.  So, just make sure we don't
     251       crash; but if other threads are making modifications, part of the result
     252       may be wrong.  */
     253   retry:
     254    {
     255      /* Guess the size of the needed block of memory.
     256         The guess will be exact if other threads don't make modifications.  */
     257      size_t total_size = 0;
     258      const char * const *ep;
     259      const char *p;
     260      for (ep = envp; (p = *ep) != NULL; ep++)
     261        total_size += strlen (p) + 1;
     262      size_t envblock_size = total_size;
     263  
     264      /* Allocate the block of memory.  */
     265      char *envblock = (char *) malloc (envblock_size + 1);
     266      if (envblock == NULL)
     267        {
     268          errno = ENOMEM;
     269          return NULL;
     270        }
     271      size_t envblock_used = 0;
     272      for (ep = envp; (p = *ep) != NULL; ep++)
     273        {
     274          size_t size = strlen (p) + 1;
     275          if (envblock_used + size > envblock_size)
     276            {
     277              /* Other threads did modifications.  Need more memory.  */
     278              envblock_size += envblock_size / 2;
     279              if (envblock_used + size > envblock_size)
     280                envblock_size = envblock_used + size;
     281  
     282              char *new_envblock = (char *) realloc (envblock, envblock_size + 1);
     283              if (new_envblock == NULL)
     284                {
     285                  free (envblock);
     286                  errno = ENOMEM;
     287                  return NULL;
     288                }
     289              envblock = new_envblock;
     290            }
     291          memcpy (envblock + envblock_used, p, size);
     292          envblock_used += size;
     293          if (envblock[envblock_used - 1] != '\0')
     294            {
     295              /* Other threads did modifications.  Restart.  */
     296              free (envblock);
     297              goto retry;
     298            }
     299        }
     300      envblock[envblock_used] = '\0';
     301      return envblock;
     302    }
     303  }
     304  
     305  int
     306  init_inheritable_handles (struct inheritable_handles *inh_handles,
     307                            bool duplicate)
     308  {
     309    /* Determine the minimal count of handles we need to care about.  */
     310    size_t handles_count;
     311    {
     312      /* _getmaxstdio
     313         <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
     314         Default value is 512.  */
     315      unsigned int fdmax = _getmaxstdio ();
     316      if (fdmax < 3)
     317        fdmax = 3;
     318      for (; fdmax > 3; fdmax--)
     319        {
     320          unsigned int fd = fdmax - 1;
     321          /* _get_osfhandle
     322             <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle>  */
     323          HANDLE handle = (HANDLE) _get_osfhandle (fd);
     324          if (handle != INVALID_HANDLE_VALUE)
     325            {
     326              if (duplicate)
     327                /* We will add fd to the array, regardless of whether it is
     328                   inheritable or not.  */
     329                break;
     330              else
     331                {
     332                  DWORD hflags;
     333                  /* GetHandleInformation
     334                     <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation>  */
     335                  if (GetHandleInformation (handle, &hflags))
     336                    {
     337                      if ((hflags & HANDLE_FLAG_INHERIT) != 0)
     338                        /* fd denotes an inheritable descriptor.  */
     339                        break;
     340                    }
     341                }
     342            }
     343        }
     344      handles_count = fdmax;
     345    }
     346    /* Note: handles_count >= 3.  */
     347  
     348    /* Allocate the array.  */
     349    size_t handles_allocated = handles_count;
     350    struct IHANDLE *ih =
     351      (struct IHANDLE *) malloc (handles_allocated * sizeof (struct IHANDLE));
     352    if (ih == NULL)
     353      {
     354        errno = ENOMEM;
     355        return -1;
     356      }
     357  
     358    /* Fill in the array.  */
     359    {
     360      HANDLE curr_process = (duplicate ? GetCurrentProcess () : INVALID_HANDLE_VALUE);
     361      unsigned int fd;
     362      for (fd = 0; fd < handles_count; fd++)
     363        {
     364          ih[fd].handle = INVALID_HANDLE_VALUE;
     365          /* _get_osfhandle
     366             <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle>  */
     367          HANDLE handle = (HANDLE) _get_osfhandle (fd);
     368          if (handle != INVALID_HANDLE_VALUE)
     369            {
     370              DWORD hflags;
     371              /* GetHandleInformation
     372                 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation>  */
     373              if (GetHandleInformation (handle, &hflags))
     374                {
     375                  if (duplicate)
     376                    {
     377                      /* Add fd to the array, regardless of whether it is
     378                         inheritable or not.  */
     379                      if ((hflags & HANDLE_FLAG_INHERIT) != 0)
     380                        {
     381                          /* Instead of duplicating it, just mark it as shared.  */
     382                          ih[fd].handle = handle;
     383                          ih[fd].flags = KEEP_OPEN_IN_PARENT | KEEP_OPEN_IN_CHILD;
     384                        }
     385                      else
     386                        {
     387                          if (!DuplicateHandle (curr_process, handle,
     388                                                curr_process, &ih[fd].handle,
     389                                                0, TRUE, DUPLICATE_SAME_ACCESS))
     390                            {
     391                              unsigned int i;
     392                              for (i = 0; i < fd; i++)
     393                                if (ih[i].handle != INVALID_HANDLE_VALUE
     394                                    && !(ih[i].flags & KEEP_OPEN_IN_PARENT))
     395                                  CloseHandle (ih[i].handle);
     396                              free (ih);
     397                              errno = EBADF; /* arbitrary */
     398                              return -1;
     399                            }
     400                          ih[fd].flags = 0;
     401                        }
     402                    }
     403                  else
     404                    {
     405                      if ((hflags & HANDLE_FLAG_INHERIT) != 0)
     406                        {
     407                          /* fd denotes an inheritable descriptor.  */
     408                          ih[fd].handle = handle;
     409                          ih[fd].flags = KEEP_OPEN_IN_CHILD;
     410                        }
     411                    }
     412                }
     413            }
     414        }
     415    }
     416  
     417    /* Return the result.  */
     418    inh_handles->count = handles_count;
     419    inh_handles->allocated = handles_allocated;
     420    inh_handles->ih = ih;
     421    return 0;
     422  }
     423  
     424  int
     425  compose_handles_block (const struct inheritable_handles *inh_handles,
     426                         STARTUPINFO *sinfo)
     427  {
     428    /* STARTUPINFO
     429       <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa>  */
     430    sinfo->dwFlags = STARTF_USESTDHANDLES;
     431    sinfo->hStdInput  = inh_handles->ih[0].handle;
     432    sinfo->hStdOutput = inh_handles->ih[1].handle;
     433    sinfo->hStdError  = inh_handles->ih[2].handle;
     434  
     435    /* On newer versions of Windows, more file descriptors / handles than the
     436       first three can be passed.
     437       The format is as follows: Let N be an exclusive upper bound for the file
     438       descriptors to be passed. Two arrays are constructed in memory:
     439         - flags[0..N-1], of element type 'unsigned char',
     440         - handles[0..N-1], of element type 'HANDLE' or 'intptr_t'.
     441       For used entries, handles[i] is the handle, and flags[i] is a set of flags,
     442       a combination of:
     443          1 for open file descriptors,
     444         64 for handles of type FILE_TYPE_CHAR,
     445          8 for handles of type FILE_TYPE_PIPE,
     446         32 for O_APPEND.
     447       For unused entries - this may include any of the first three, since they
     448       are already passed above -, handles[i] is INVALID_HANDLE_VALUE and flags[i]
     449       is zero.
     450       lpReserved2 now is a pointer to the concatenation (without padding) of:
     451         - an 'unsigned int' whose value is N,
     452         - the contents of the flags[0..N-1] array,
     453         - the contents of the handles[0..N-1] array.
     454       cbReserved2 is the size (in bytes) of the object at lpReserved2.  */
     455  
     456    size_t handles_count = inh_handles->count;
     457  
     458    sinfo->cbReserved2 =
     459      sizeof (unsigned int)
     460      + handles_count * sizeof (unsigned char)
     461      + handles_count * sizeof (HANDLE);
     462    /* Add some padding, so that we can work with a properly aligned HANDLE
     463       array.  */
     464    char *hblock = (char *) malloc (sinfo->cbReserved2 + (sizeof (HANDLE) - 1));
     465    if (hblock == NULL)
     466      {
     467        errno = ENOMEM;
     468        return -1;
     469      }
     470    unsigned char *flags = (unsigned char *) (hblock + sizeof (unsigned int));
     471    char *handles = (char *) (flags + handles_count);
     472    HANDLE *handles_aligned =
     473      (HANDLE *) (((uintptr_t) handles + (sizeof (HANDLE) - 1))
     474                  & - (uintptr_t) sizeof (HANDLE));
     475  
     476    * (unsigned int *) hblock = handles_count;
     477    {
     478      unsigned int fd;
     479      for (fd = 0; fd < handles_count; fd++)
     480        {
     481          handles_aligned[fd] = INVALID_HANDLE_VALUE;
     482          flags[fd] = 0;
     483  
     484          HANDLE handle = inh_handles->ih[fd].handle;
     485          if (handle != INVALID_HANDLE_VALUE
     486              /* The first three are possibly already passed above.
     487                 But they need to passed here as well, if they have some flags.  */
     488              && (fd >= 3 || (unsigned char) inh_handles->ih[fd].flags != 0))
     489            {
     490              DWORD hflags;
     491              /* GetHandleInformation
     492                 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation>  */
     493              if (GetHandleInformation (handle, &hflags))
     494                {
     495                  if ((hflags & HANDLE_FLAG_INHERIT) != 0)
     496                    {
     497                      /* fd denotes an inheritable descriptor.  */
     498                      handles_aligned[fd] = handle;
     499                      /* On Microsoft Windows, it would be sufficient to set
     500                         flags[fd] = 1.  But on ReactOS or Wine, adding the bit
     501                         that indicates the handle type may be necessary.  So,
     502                         just do it everywhere.  */
     503                      flags[fd] = 1 | (unsigned char) inh_handles->ih[fd].flags;
     504                      switch (GetFileType (handle))
     505                        {
     506                        case FILE_TYPE_CHAR:
     507                          flags[fd] |= 64;
     508                          break;
     509                        case FILE_TYPE_PIPE:
     510                          flags[fd] |= 8;
     511                          break;
     512                        default:
     513                          break;
     514                        }
     515                    }
     516                  else
     517                    /* We shouldn't have any non-inheritable handles in
     518                       inh_handles->handles.  */
     519                    abort ();
     520                }
     521            }
     522        }
     523    }
     524    if (handles != (char *) handles_aligned)
     525      memmove (handles, (char *) handles_aligned, handles_count * sizeof (HANDLE));
     526  
     527    sinfo->lpReserved2 = (BYTE *) hblock;
     528  
     529    return 0;
     530  }
     531  
     532  void
     533  free_inheritable_handles (struct inheritable_handles *inh_handles)
     534  {
     535    free (inh_handles->ih);
     536  }
     537  
     538  int
     539  convert_CreateProcess_error (DWORD error)
     540  {
     541    /* Some of these errors probably cannot happen.  But who knows...  */
     542    switch (error)
     543      {
     544      case ERROR_FILE_NOT_FOUND:
     545      case ERROR_PATH_NOT_FOUND:
     546      case ERROR_BAD_PATHNAME:
     547      case ERROR_BAD_NET_NAME:
     548      case ERROR_INVALID_NAME:
     549      case ERROR_DIRECTORY:
     550        return ENOENT;
     551        break;
     552  
     553      case ERROR_ACCESS_DENIED:
     554      case ERROR_SHARING_VIOLATION:
     555        return EACCES;
     556        break;
     557  
     558      case ERROR_OUTOFMEMORY:
     559        return ENOMEM;
     560        break;
     561  
     562      case ERROR_BUFFER_OVERFLOW:
     563      case ERROR_FILENAME_EXCED_RANGE:
     564        return ENAMETOOLONG;
     565        break;
     566  
     567      case ERROR_BAD_FORMAT:
     568      case ERROR_BAD_EXE_FORMAT:
     569        return ENOEXEC;
     570        break;
     571  
     572      default:
     573        return EINVAL;
     574        break;
     575      }
     576  }
     577  
     578  intptr_t
     579  spawnpvech (int mode,
     580              const char *progname, const char * const *argv,
     581              const char * const *envp,
     582              const char *currdir,
     583              HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
     584  {
     585    /* Validate the arguments.  */
     586    if (!(mode == P_WAIT
     587          || mode == P_NOWAIT
     588          || mode == P_DETACH
     589          || mode == P_OVERLAY)
     590        || progname == NULL || argv == NULL)
     591      {
     592        errno = EINVAL;
     593        return -1;
     594      }
     595  
     596    /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH").  */
     597    const char *resolved_progname =
     598      find_in_given_path (progname, getenv ("PATH"), NULL, false);
     599    if (resolved_progname == NULL)
     600      return -1;
     601  
     602    /* Compose the command.  */
     603    char *command = compose_command (argv);
     604    if (command == NULL)
     605      goto out_of_memory_1;
     606  
     607    /* Copy *ENVP into a contiguous block of memory.  */
     608    char *envblock;
     609    if (envp == NULL)
     610      envblock = NULL;
     611    else
     612      {
     613        envblock = compose_envblock (envp);
     614        if (envblock == NULL)
     615          goto out_of_memory_2;
     616      }
     617  
     618    /* Collect the inheritable handles.  */
     619    struct inheritable_handles inh_handles;
     620    if (init_inheritable_handles (&inh_handles, false) < 0)
     621      {
     622        int saved_errno = errno;
     623        if (envblock != NULL)
     624          free (envblock);
     625        free (command);
     626        if (resolved_progname != progname)
     627          free ((char *) resolved_progname);
     628        errno = saved_errno;
     629        return -1;
     630      }
     631    inh_handles.ih[0].handle = stdin_handle;
     632    inh_handles.ih[0].flags = KEEP_OPEN_IN_CHILD;
     633    inh_handles.ih[1].handle = stdout_handle;
     634    inh_handles.ih[1].flags = KEEP_OPEN_IN_CHILD;
     635    inh_handles.ih[2].handle = stderr_handle;
     636    inh_handles.ih[2].flags = KEEP_OPEN_IN_CHILD;
     637  
     638    /* CreateProcess
     639       <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa>  */
     640    /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags>  */
     641    DWORD process_creation_flags = (mode == P_DETACH ? DETACHED_PROCESS : 0);
     642    /* STARTUPINFO
     643       <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa>  */
     644    STARTUPINFO sinfo;
     645    sinfo.cb = sizeof (STARTUPINFO);
     646    sinfo.lpReserved = NULL;
     647    sinfo.lpDesktop = NULL;
     648    sinfo.lpTitle = NULL;
     649    if (compose_handles_block (&inh_handles, &sinfo) < 0)
     650      {
     651        int saved_errno = errno;
     652        free_inheritable_handles (&inh_handles);
     653        if (envblock != NULL)
     654          free (envblock);
     655        free (command);
     656        if (resolved_progname != progname)
     657          free ((char *) resolved_progname);
     658        errno = saved_errno;
     659        return -1;
     660      }
     661  
     662    PROCESS_INFORMATION pinfo;
     663    if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
     664                        process_creation_flags, envblock, currdir, &sinfo,
     665                        &pinfo))
     666      {
     667        DWORD error = GetLastError ();
     668  
     669        free (sinfo.lpReserved2);
     670        free_inheritable_handles (&inh_handles);
     671        if (envblock != NULL)
     672          free (envblock);
     673        free (command);
     674        if (resolved_progname != progname)
     675          free ((char *) resolved_progname);
     676  
     677        errno = convert_CreateProcess_error (error);
     678        return -1;
     679      }
     680  
     681    if (pinfo.hThread)
     682      CloseHandle (pinfo.hThread);
     683    free (sinfo.lpReserved2);
     684    free_inheritable_handles (&inh_handles);
     685    if (envblock != NULL)
     686      free (envblock);
     687    free (command);
     688    if (resolved_progname != progname)
     689      free ((char *) resolved_progname);
     690  
     691    switch (mode)
     692      {
     693      case P_WAIT:
     694        {
     695          /* Wait until it terminates.  Then get its exit status code.  */
     696          switch (WaitForSingleObject (pinfo.hProcess, INFINITE))
     697            {
     698            case WAIT_OBJECT_0:
     699              break;
     700            case WAIT_FAILED:
     701              errno = ECHILD;
     702              return -1;
     703            default:
     704              abort ();
     705            }
     706  
     707          DWORD exit_code;
     708          if (!GetExitCodeProcess (pinfo.hProcess, &exit_code))
     709            {
     710              errno = ECHILD;
     711              return -1;
     712            }
     713          CloseHandle (pinfo.hProcess);
     714          return exit_code;
     715        }
     716  
     717      case P_NOWAIT:
     718        /* Return pinfo.hProcess, not pinfo.dwProcessId.  */
     719        return (intptr_t) pinfo.hProcess;
     720  
     721      case P_DETACH:
     722      case P_OVERLAY:
     723        CloseHandle (pinfo.hProcess);
     724        return 0;
     725  
     726      default:
     727        /* Already checked above.  */
     728        abort ();
     729      }
     730  
     731    /*NOTREACHED*/
     732   out_of_memory_2:
     733    free (command);
     734   out_of_memory_1:
     735    if (resolved_progname != progname)
     736      free ((char *) resolved_progname);
     737    errno = ENOMEM;
     738    return -1;
     739  }