root/maint/gnulib/lib/windows-spawn.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. quoted_arg_length
  2. quoted_arg_string
  3. prepare_spawn
  4. compose_command
  5. compose_envblock
  6. init_inheritable_handles
  7. compose_handles_block
  8. free_inheritable_handles
  9. convert_CreateProcess_error
  10. spawnpvech

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

/* [previous][next][first][last][top][bottom][index][help] */