(root)/
make-4.4/
src/
w32/
subproc/
sub_proc.c
       1  /* Process handling for Windows.
       2  Copyright (C) 1996-2022 Free Software Foundation, Inc.
       3  This file is part of GNU Make.
       4  
       5  GNU Make is free software; you can redistribute it and/or modify it under the
       6  terms of the GNU General Public License as published by the Free Software
       7  Foundation; either version 3 of the License, or (at your option) any later
       8  version.
       9  
      10  GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
      11  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      12  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      13  
      14  You should have received a copy of the GNU General Public License along with
      15  this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include "makeint.h"
      18  
      19  #include <assert.h>
      20  #include <stdlib.h>
      21  #include <stdio.h>
      22  #include <io.h>         /* for _get_osfhandle */
      23  #ifdef _MSC_VER
      24  # include <stddef.h>    /* for intptr_t */
      25  #else
      26  # include <stdint.h>
      27  #endif
      28  #include <string.h>
      29  #include <process.h>  /* for msvc _beginthreadex, _endthreadex */
      30  #include <signal.h>
      31  #include <windows.h>
      32  
      33  #include "filedef.h"
      34  #include "variable.h"
      35  #include "sub_proc.h"
      36  #include "proc.h"
      37  #include "w32err.h"
      38  #include "debug.h"
      39  #include "os.h"
      40  
      41  #define GMAKE_MAXIMUM_WAIT_OBJECTS (MAXIMUM_WAIT_OBJECTS * MAXIMUM_WAIT_OBJECTS)
      42  
      43  /* We need to move these special-case return codes out-of-band */
      44  #define GMAKE_WAIT_TIMEOUT      0xFFFF0102L
      45  #define GMAKE_WAIT_ABANDONED_0  0x00080000L
      46  
      47  static char *make_command_line(char *shell_name, char *exec_path, char **argv);
      48  
      49  typedef struct sub_process_t {
      50          intptr_t sv_stdin[2];
      51          intptr_t sv_stdout[2];
      52          intptr_t sv_stderr[2];
      53          int using_pipes;
      54          char *inp;
      55          DWORD incnt;
      56          char * volatile outp;
      57          volatile DWORD outcnt;
      58          char * volatile errp;
      59          volatile DWORD errcnt;
      60          pid_t pid;
      61          int exit_code;
      62          int signal;
      63          long last_err;
      64          long lerrno;
      65  } sub_process;
      66  
      67  /* keep track of children so we can implement a waitpid-like routine */
      68  static sub_process *proc_array[GMAKE_MAXIMUM_WAIT_OBJECTS];
      69  static unsigned int proc_index = 0;
      70  static unsigned int fake_exits_pending = 0;
      71  
      72  /*
      73   * Address the scalability limit intrisic to WaitForMultipleOjects by
      74   * calling WaitForMultipleObjects on 64 element chunks of the input
      75   * array with 0 timeout.  Exit with an appropriately conditioned result
      76   * or repeat again every 10 ms if no handle has signaled and the
      77   * requested timeout was not zero.
      78   */
      79  DWORD process_wait_for_multiple_objects(
      80    DWORD nCount,
      81    const HANDLE *lpHandles,
      82    BOOL bWaitAll,
      83    DWORD dwMilliseconds
      84  )
      85  {
      86    assert(nCount <= GMAKE_MAXIMUM_WAIT_OBJECTS);
      87  
      88    if (nCount <= MAXIMUM_WAIT_OBJECTS) {
      89      DWORD retVal =  WaitForMultipleObjects(nCount, lpHandles, bWaitAll, dwMilliseconds);
      90      return (retVal == WAIT_TIMEOUT) ? GMAKE_WAIT_TIMEOUT : retVal;
      91    } else {
      92      for (;;) {
      93        DWORD objectCount = nCount;
      94        int blockCount  = 0;
      95        DWORD retVal = 0;
      96  
      97        assert(bWaitAll == FALSE); /* This logic only works for this use case */
      98        assert(dwMilliseconds == 0 || dwMilliseconds == INFINITE); /* No support for timeouts */
      99  
     100        for (; objectCount > 0; blockCount++) {
     101          DWORD n = objectCount <= MAXIMUM_WAIT_OBJECTS ? objectCount : MAXIMUM_WAIT_OBJECTS;
     102          objectCount -= n;
     103          retVal = WaitForMultipleObjects(n, &lpHandles[blockCount * MAXIMUM_WAIT_OBJECTS],
     104                                              FALSE, 0);
     105          switch (retVal) {
     106            case WAIT_TIMEOUT:
     107              retVal = GMAKE_WAIT_TIMEOUT;
     108              continue;
     109              break;
     110            case WAIT_FAILED:
     111              fprintf(stderr,"WaitForMultipleOjbects failed waiting with error %lu\n", GetLastError());
     112              break;
     113            default:
     114              if (retVal >= WAIT_ABANDONED_0) {
     115                assert(retVal < WAIT_ABANDONED_0 + MAXIMUM_WAIT_OBJECTS);
     116                retVal += blockCount * MAXIMUM_WAIT_OBJECTS - WAIT_ABANDONED_0 + GMAKE_WAIT_ABANDONED_0;
     117              } else {
     118                assert(retVal < WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS);
     119                retVal += blockCount * MAXIMUM_WAIT_OBJECTS;
     120              }
     121              break;
     122          }
     123  
     124          return retVal;
     125  
     126        }
     127  
     128        if (dwMilliseconds == 0) return retVal;
     129  
     130        Sleep(10);  /* Sleep for 10 ms */
     131      }
     132    }
     133  }
     134  
     135  /*
     136   * Fill a HANDLE list with handles to wait for.
     137   */
     138  DWORD
     139  process_set_handles(HANDLE *handles)
     140  {
     141      DWORD count = 0;
     142      unsigned int i;
     143  
     144      /* Build array of handles to wait for */
     145      for (i = 0; i < proc_index; i++) {
     146          /* Don't wait on child processes that have already finished */
     147          if (fake_exits_pending && proc_array[i]->exit_code)
     148              continue;
     149  
     150          handles[count++] = (HANDLE) proc_array[i]->pid;
     151      }
     152  
     153      return count;
     154  }
     155  
     156  /*
     157   * When a process has been waited for, adjust the wait state
     158   * array so that we don't wait for it again
     159   */
     160  static void
     161  process_adjust_wait_state(sub_process* pproc)
     162  {
     163          unsigned int i;
     164  
     165          if (!proc_index)
     166                  return;
     167  
     168          for (i = 0; i < proc_index; i++)
     169                  if (proc_array[i]->pid == pproc->pid)
     170                          break;
     171  
     172          if (i < proc_index) {
     173                  proc_index--;
     174                  if (i != proc_index)
     175                          memmove(&proc_array[i], &proc_array[i+1],
     176                                  (proc_index-i) * sizeof(sub_process*));
     177                  proc_array[proc_index] = NULL;
     178          }
     179  }
     180  
     181  /*
     182   * Waits for any of the registered child processes to finish.
     183   */
     184  static sub_process *
     185  process_wait_for_any_private(int block, DWORD* pdwWaitStatus)
     186  {
     187          HANDLE handles[GMAKE_MAXIMUM_WAIT_OBJECTS];
     188          DWORD retval, which;
     189          unsigned int i;
     190  
     191          if (!proc_index)
     192                  return NULL;
     193  
     194          /* build array of handles to wait for */
     195          for (i = 0; i < proc_index; i++) {
     196                  handles[i] = (HANDLE) proc_array[i]->pid;
     197  
     198                  if (fake_exits_pending && proc_array[i]->exit_code)
     199                          break;
     200          }
     201  
     202          /* wait for someone to exit */
     203          if (!fake_exits_pending) {
     204                  retval = process_wait_for_multiple_objects(proc_index, handles, FALSE, (block ? INFINITE : 0));
     205                  which = retval - WAIT_OBJECT_0;
     206          } else {
     207                  fake_exits_pending--;
     208                  retval = !WAIT_FAILED;
     209                  which = i;
     210          }
     211  
     212          /* If the pointer is not NULL, set the wait status result variable. */
     213          if (pdwWaitStatus)
     214                  *pdwWaitStatus = (retval == GMAKE_WAIT_TIMEOUT) ? WAIT_TIMEOUT : retval;
     215  
     216          /* return pointer to process */
     217          if ((retval == GMAKE_WAIT_TIMEOUT) || (retval == WAIT_FAILED)) {
     218                  return NULL;
     219          }
     220          else {
     221                  sub_process* pproc = proc_array[which];
     222                  process_adjust_wait_state(pproc);
     223                  return pproc;
     224          }
     225  }
     226  
     227  /*
     228   * Terminate a process.
     229   */
     230  BOOL
     231  process_kill(HANDLE proc, int signal)
     232  {
     233          sub_process* pproc = (sub_process*) proc;
     234          pproc->signal = signal;
     235          return (TerminateProcess((HANDLE) pproc->pid, signal));
     236  }
     237  
     238  /*
     239   * Returns true when we have no more available slots in our process table.
     240   */
     241  BOOL
     242  process_table_full()
     243  {
     244    extern int shell_function_pid;
     245  
     246    /* Reserve slots for jobserver_semaphore if we have one and the shell function if not active */
     247    return(proc_index >= GMAKE_MAXIMUM_WAIT_OBJECTS - jobserver_enabled() - (shell_function_pid == 0));
     248  }
     249  
     250  /*
     251   * Returns the maximum number of job slots we can support when using the jobserver.
     252   */
     253  int
     254  process_table_usable_size()
     255  {
     256    /* Reserve slots for jobserver_semaphore and shell function */
     257    return(GMAKE_MAXIMUM_WAIT_OBJECTS - 2);
     258  }
     259  
     260  /*
     261   * Returns the actual size of the process table.
     262   */
     263  int
     264  process_table_actual_size()
     265  {
     266    return(GMAKE_MAXIMUM_WAIT_OBJECTS);
     267  }
     268  
     269  /*
     270   * Use this function to register processes you wish to wait for by
     271   * calling process_file_io(NULL) or process_wait_any(). This must be done
     272   * because it is possible for callers of this library to reuse the same
     273   * handle for multiple processes launches :-(
     274   */
     275  void
     276  process_register(HANDLE proc)
     277  {
     278    assert(proc_index < GMAKE_MAXIMUM_WAIT_OBJECTS);
     279    proc_array[proc_index++] = (sub_process *) proc;
     280  }
     281  
     282  /*
     283   * Public function which works kind of like waitpid(). Wait for any
     284   * of the children to die and return results. To call this function,
     285   * you must do 1 of things:
     286   *
     287   *      x = process_easy(...);
     288   *
     289   * or
     290   *
     291   *      x = process_init_fd();
     292   *      process_register(x);
     293   *
     294   * or
     295   *
     296   *      x = process_init();
     297   *      process_register(x);
     298   *
     299   * You must NOT then call process_pipe_io() because this function is
     300   * not capable of handling automatic notification of any child
     301   * death.
     302   */
     303  
     304  HANDLE
     305  process_wait_for_any(int block, DWORD* pdwWaitStatus)
     306  {
     307          sub_process* pproc = process_wait_for_any_private(block, pdwWaitStatus);
     308  
     309          if (!pproc)
     310                  return NULL;
     311          else {
     312                  /*
     313                   * Ouch! can't tell caller if this fails directly. Caller
     314                   * will have to use process_last_err()
     315                   */
     316                  (void) process_file_io(pproc);
     317                  return ((HANDLE) pproc);
     318          }
     319  }
     320  
     321  long
     322  process_signal(HANDLE proc)
     323  {
     324          if (proc == INVALID_HANDLE_VALUE) return 0;
     325          return (((sub_process *)proc)->signal);
     326  }
     327  
     328  long
     329  process_last_err(HANDLE proc)
     330  {
     331          if (proc == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
     332          return (((sub_process *)proc)->last_err);
     333  }
     334  
     335  long
     336  process_exit_code(HANDLE proc)
     337  {
     338          if (proc == INVALID_HANDLE_VALUE) return EXIT_FAILURE;
     339          return (((sub_process *)proc)->exit_code);
     340  }
     341  
     342  /*
     343  2006-02:
     344  All the following functions are currently unused.
     345  All of them would crash gmake if called with argument INVALID_HANDLE_VALUE.
     346  Hence whoever wants to use one of this functions must invent and implement
     347  a reasonable error handling for this function.
     348  
     349  char *
     350  process_outbuf(HANDLE proc)
     351  {
     352          return (((sub_process *)proc)->outp);
     353  }
     354  
     355  char *
     356  process_errbuf(HANDLE proc)
     357  {
     358          return (((sub_process *)proc)->errp);
     359  }
     360  
     361  int
     362  process_outcnt(HANDLE proc)
     363  {
     364          return (((sub_process *)proc)->outcnt);
     365  }
     366  
     367  int
     368  process_errcnt(HANDLE proc)
     369  {
     370          return (((sub_process *)proc)->errcnt);
     371  }
     372  
     373  void
     374  process_pipes(HANDLE proc, int pipes[3])
     375  {
     376          pipes[0] = ((sub_process *)proc)->sv_stdin[0];
     377          pipes[1] = ((sub_process *)proc)->sv_stdout[0];
     378          pipes[2] = ((sub_process *)proc)->sv_stderr[0];
     379          return;
     380  }
     381  */
     382  
     383          HANDLE
     384  process_init()
     385  {
     386          sub_process *pproc;
     387          /*
     388           * open file descriptors for attaching stdin/stdout/sterr
     389           */
     390          HANDLE stdin_pipes[2];
     391          HANDLE stdout_pipes[2];
     392          HANDLE stderr_pipes[2];
     393          SECURITY_ATTRIBUTES inherit;
     394          BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
     395  
     396          pproc = malloc(sizeof(*pproc));
     397          memset(pproc, 0, sizeof(*pproc));
     398  
     399          /* We can't use NULL for lpSecurityDescriptor because that
     400             uses the default security descriptor of the calling process.
     401             Instead we use a security descriptor with no DACL.  This
     402             allows nonrestricted access to the associated objects. */
     403  
     404          if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
     405                                            SECURITY_DESCRIPTOR_REVISION)) {
     406                  pproc->last_err = GetLastError();
     407                  pproc->lerrno = E_SCALL;
     408                  return((HANDLE)pproc);
     409          }
     410  
     411          inherit.nLength = sizeof(inherit);
     412          inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
     413          inherit.bInheritHandle = TRUE;
     414  
     415          /* By convention, parent gets pipe[0], and child gets pipe[1].
     416             This means the READ side of stdin pipe goes into pipe[1] and the
     417             WRITE side of the stdout and stderr pipes go into pipe[1].  */
     418          if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE ||
     419          CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE ||
     420          CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) {
     421  
     422                  pproc->last_err = GetLastError();
     423                  pproc->lerrno = E_SCALL;
     424                  return((HANDLE)pproc);
     425          }
     426  
     427          /* Mark the parent sides of the pipes as non-inheritable.  */
     428          if (SetHandleInformation(stdin_pipes[0],
     429                                  HANDLE_FLAG_INHERIT, 0) == FALSE ||
     430                  SetHandleInformation(stdout_pipes[0],
     431                                  HANDLE_FLAG_INHERIT, 0) == FALSE ||
     432                  SetHandleInformation(stderr_pipes[0],
     433                                  HANDLE_FLAG_INHERIT, 0) == FALSE) {
     434  
     435                  pproc->last_err = GetLastError();
     436                  pproc->lerrno = E_SCALL;
     437                  return((HANDLE)pproc);
     438          }
     439          pproc->sv_stdin[0]  = (intptr_t) stdin_pipes[0];
     440          pproc->sv_stdin[1]  = (intptr_t) stdin_pipes[1];
     441          pproc->sv_stdout[0] = (intptr_t) stdout_pipes[0];
     442          pproc->sv_stdout[1] = (intptr_t) stdout_pipes[1];
     443          pproc->sv_stderr[0] = (intptr_t) stderr_pipes[0];
     444          pproc->sv_stderr[1] = (intptr_t) stderr_pipes[1];
     445  
     446          pproc->using_pipes = 1;
     447  
     448          pproc->lerrno = 0;
     449  
     450          return((HANDLE)pproc);
     451  }
     452  
     453  
     454          HANDLE
     455  process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
     456  {
     457          sub_process *pproc;
     458  
     459          pproc = malloc(sizeof(*pproc));
     460          if (pproc) {
     461                  memset(pproc, 0, sizeof(*pproc));
     462  
     463                  /*
     464                   * Just pass the provided file handles to the 'child
     465                   * side' of the pipe, bypassing pipes altogether.
     466                   */
     467                  pproc->sv_stdin[1]  = (intptr_t) stdinh;
     468                  pproc->sv_stdout[1] = (intptr_t) stdouth;
     469                  pproc->sv_stderr[1] = (intptr_t) stderrh;
     470  
     471                  pproc->last_err = pproc->lerrno = 0;
     472          }
     473  
     474          return((HANDLE)pproc);
     475  }
     476  
     477  
     478  static HANDLE
     479  find_file(const char *exec_path, const char *path_var,
     480            char *full_fname, DWORD full_len)
     481  {
     482          HANDLE exec_handle;
     483          char *fname;
     484          char *ext;
     485          DWORD req_len;
     486          int i;
     487          static const char *extensions[] =
     488            /* Should .com come before no-extension case?  */
     489            { ".exe", ".cmd", ".bat", "", ".com", NULL };
     490  
     491          fname = xmalloc(strlen(exec_path) + 5);
     492          strcpy(fname, exec_path);
     493          ext = fname + strlen(fname);
     494  
     495          for (i = 0; extensions[i]; i++) {
     496                  strcpy(ext, extensions[i]);
     497                  if (((req_len = SearchPath (path_var, fname, NULL, full_len,
     498                                              full_fname, NULL)) > 0
     499                       /* For compatibility with previous code, which
     500                          used OpenFile, and with Windows operation in
     501                          general, also look in various default
     502                          locations, such as Windows directory and
     503                          Windows System directory.  Warning: this also
     504                          searches PATH in the Make's environment, which
     505                          might not be what the Makefile wants, but it
     506                          seems to be OK as a fallback, after the
     507                          previous SearchPath failed to find on child's
     508                          PATH.  */
     509                       || (req_len = SearchPath (NULL, fname, NULL, full_len,
     510                                                 full_fname, NULL)) > 0)
     511                      && req_len <= full_len
     512                      && (exec_handle =
     513                                  CreateFile(full_fname,
     514                                             GENERIC_READ,
     515                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
     516                                             NULL,
     517                                             OPEN_EXISTING,
     518                                             FILE_ATTRIBUTE_NORMAL,
     519                                             NULL)) != INVALID_HANDLE_VALUE) {
     520                          free(fname);
     521                          return(exec_handle);
     522                  }
     523          }
     524  
     525          free(fname);
     526          return INVALID_HANDLE_VALUE;
     527  }
     528  
     529  /*
     530   * Return non-zero of FNAME specifies a batch file and its name
     531   * includes embedded whitespace.
     532   */
     533  
     534  static int
     535  batch_file_with_spaces(const char *fname)
     536  {
     537          size_t fnlen = strlen(fname);
     538  
     539          return (fnlen > 4
     540                  && (_strnicmp(fname + fnlen - 4, ".bat", 4) == 0
     541                      || _strnicmp(fname + fnlen - 4, ".cmd", 4) == 0)
     542                  /* The set of characters in the 2nd arg to strpbrk
     543                     should be the same one used by make_command_line
     544                     below to decide whether an argv[] element needs
     545                     quoting.  */
     546                  && strpbrk(fname, " \t") != NULL);
     547  }
     548  
     549  
     550  /*
     551   * Description:   Create the child process to be helped
     552   *
     553   * Returns: success <=> 0
     554   *
     555   * Notes/Dependencies:
     556   */
     557  long
     558  process_begin(
     559          HANDLE proc,
     560          char **argv,
     561          char **envp,
     562          char *exec_path,
     563          char *as_user)
     564  {
     565          sub_process *pproc = (sub_process *)proc;
     566          char *shell_name = 0;
     567          int file_not_found=0;
     568          HANDLE exec_handle;
     569          char exec_fname[MAX_PATH];
     570          const char *path_var = NULL;
     571          char **ep;
     572          char buf[MAX_PATH];
     573          DWORD bytes_returned;
     574          DWORD flags;
     575          char *command_line;
     576          STARTUPINFO startInfo;
     577          PROCESS_INFORMATION procInfo;
     578          char *envblk=NULL;
     579          size_t envsize_needed = 0;
     580          int pass_null_exec_path = 0;
     581  
     582          /*
     583           *  Shell script detection...  if the exec_path starts with #! then
     584           *  we want to exec shell-script-name exec-path, not just exec-path
     585           *  NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl.  We do not
     586           *  hard-code the path to the shell or perl or whatever:  Instead, we
     587           *  assume it's in the path somewhere (generally, the NT tools
     588           *  bin directory)
     589           */
     590  
     591          /* Use the Makefile's value of PATH to look for the program to
     592             execute, because it could be different from Make's PATH
     593             (e.g., if the target sets its own value.  */
     594          if (envp)
     595                  for (ep = envp; *ep; ep++) {
     596                          if (strncmp (*ep, "PATH=", 5) == 0
     597                              || strncmp (*ep, "Path=", 5) == 0) {
     598                                  path_var = *ep + 5;
     599                                  break;
     600                          }
     601                  }
     602          exec_handle = find_file(exec_path, path_var,
     603                                  exec_fname, sizeof(exec_fname));
     604  
     605          /*
     606           * If we couldn't open the file, just assume that Windows will be
     607           * somehow able to find and execute it.  If the first character
     608           * of the command is '/', assume they set SHELL to a Unixy shell
     609           * that have some magic mounts known only to it, and run the whole
     610           * command via $SHELL -c "COMMAND" instead.
     611           */
     612          if (exec_handle == INVALID_HANDLE_VALUE) {
     613                  if (exec_path[0] == '/') {
     614                          char *new_argv0;
     615                          char **argvi = argv;
     616                          size_t arglen = 0;
     617  
     618                          strcpy(buf, variable_expand ("$(SHELL)"));
     619                          shell_name = &buf[0];
     620                          strcpy(exec_fname, "-c");
     621                          /* Construct a single command string in argv[0].  */
     622                          while (*argvi) {
     623                                  arglen += strlen(*argvi) + 1;
     624                                  argvi++;
     625                          }
     626                          new_argv0 = xmalloc(arglen + 1);
     627                          new_argv0[0] = '\0';
     628                          for (argvi = argv; *argvi; argvi++) {
     629                                  strcat(new_argv0, *argvi);
     630                                  strcat(new_argv0, " ");
     631                          }
     632                          /* Remove the extra blank at the end.  */
     633                          new_argv0[arglen-1] = '\0';
     634                          free(argv[0]);
     635                          argv[0] = new_argv0;
     636                          argv[1] = NULL;
     637                  }
     638                  else
     639                          file_not_found++;
     640          }
     641          else {
     642                  /* Attempt to read the first line of the file */
     643                  if (ReadFile( exec_handle,
     644                                  buf, sizeof(buf) - 1, /* leave room for trailing NULL */
     645                                  &bytes_returned, 0) == FALSE || bytes_returned < 2) {
     646  
     647                          pproc->last_err = GetLastError();
     648                          pproc->lerrno = E_IO;
     649                          CloseHandle(exec_handle);
     650                          return(-1);
     651                  }
     652                  if (buf[0] == '#' && buf[1] == '!') {
     653                          /*
     654                           *  This is a shell script...  Change the command line from
     655                           *      exec_path args to shell_name exec_path args
     656                           */
     657                          char *p;
     658  
     659                          /*  Make sure buf is NULL terminated */
     660                          buf[bytes_returned] = 0;
     661                          /*
     662                           * Depending on the file system type, etc. the first line
     663                           * of the shell script may end with newline or newline-carriage-return
     664                           * Whatever it ends with, cut it off.
     665                           */
     666                          p= strchr(buf, '\n');
     667                          if (p)
     668                                  *p = 0;
     669                          p = strchr(buf, '\r');
     670                          if (p)
     671                                  *p = 0;
     672  
     673                          /*
     674                           *  Find base name of shell
     675                           */
     676                          shell_name = strrchr( buf, '/');
     677                          if (shell_name) {
     678                                  shell_name++;
     679                          } else {
     680                                  shell_name = &buf[2];/* skipping "#!" */
     681                          }
     682  
     683                  }
     684                  CloseHandle(exec_handle);
     685          }
     686  
     687          flags = 0;
     688  
     689          if (file_not_found)
     690                  command_line = make_command_line( shell_name, exec_path, argv);
     691          else {
     692                  /* If exec_fname includes whitespace, CreateProcess
     693                     behaves erratically and unreliably, and often fails
     694                     if argv[0] also includes whitespace (and thus will
     695                     be quoted by make_command_line below).  So in that
     696                     case, we don't pass exec_fname as the 1st arg to
     697                     CreateProcess, but instead replace argv[0] with
     698                     exec_fname (to keep its leading directories and
     699                     extension as found by find_file), and pass NULL to
     700                     CreateProcess as its 1st arg.  This works around
     701                     the bugs in CreateProcess, which are probably
     702                     caused by its passing the command to cmd.exe with
     703                     some incorrect quoting.  */
     704                  if (!shell_name
     705                      && batch_file_with_spaces(exec_fname)
     706                      && _stricmp(exec_path, argv[0]) == 0) {
     707                          char *new_argv, *p;
     708                          char **argvi;
     709                          size_t arglen;
     710                          int i;
     711                          pass_null_exec_path = 1;
     712                          /* Rewrite argv[] replacing argv[0] with exec_fname.  */
     713                          for (argvi = argv + 1, arglen = strlen(exec_fname) + 1;
     714                               *argvi;
     715                               argvi++) {
     716                                  arglen += strlen(*argvi) + 1;
     717                          }
     718                          new_argv = xmalloc(arglen);
     719                          p = strcpy(new_argv, exec_fname) + strlen(exec_fname) + 1;
     720                          for (argvi = argv + 1, i = 1; *argvi; argvi++, i++) {
     721                                  strcpy(p, *argvi);
     722                                  argv[i] = p;
     723                                  p += strlen(*argvi) + 1;
     724                          }
     725                          argv[i] = NULL;
     726                          free (argv[0]);
     727                          argv[0] = new_argv;
     728                  }
     729                  command_line = make_command_line( shell_name, exec_fname, argv);
     730          }
     731  
     732          if ( command_line == NULL ) {
     733                  pproc->last_err = 0;
     734                  pproc->lerrno = E_NO_MEM;
     735                  return(-1);
     736          }
     737  
     738          if (envp) {
     739                  if (arr2envblk(envp, &envblk, &envsize_needed) == FALSE) {
     740                          pproc->lerrno = E_NO_MEM;
     741                          free( command_line );
     742                          if ((pproc->last_err == ERROR_INVALID_PARAMETER
     743                               || pproc->last_err == ERROR_MORE_DATA)
     744                              && envsize_needed > 32*1024) {
     745                                  fprintf (stderr, "CreateProcess failed, probably because environment is too large (%Iu bytes).\n",
     746                                           envsize_needed);
     747                          }
     748                          pproc->last_err = 0;
     749                          return(-1);
     750                  }
     751          }
     752  
     753          if (shell_name || file_not_found || pass_null_exec_path) {
     754                  exec_path = 0;  /* Search for the program in %Path% */
     755          } else {
     756                  exec_path = exec_fname;
     757          }
     758  
     759          /*
     760           *  Set up inherited stdin, stdout, stderr for child
     761           */
     762          memset(&startInfo, '\0', sizeof(startInfo));
     763          GetStartupInfo(&startInfo);
     764          startInfo.dwFlags = STARTF_USESTDHANDLES;
     765          startInfo.lpReserved = 0;
     766          startInfo.cbReserved2 = 0;
     767          startInfo.lpReserved2 = 0;
     768          startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1];
     769          startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1];
     770          startInfo.hStdError = (HANDLE)pproc->sv_stderr[1];
     771  
     772          if (as_user) {
     773                  free(envblk);
     774                  return -1;
     775          } else {
     776                  DB (DB_JOBS, ("CreateProcess(%s,%s,...)\n",
     777                          exec_path ? exec_path : "NULL",
     778                          command_line ? command_line : "NULL"));
     779                  if (CreateProcess(
     780                          exec_path,
     781                          command_line,
     782                          NULL,
     783                          0, /* default security attributes for thread */
     784                          TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
     785                          flags,
     786                          envblk,
     787                          0, /* default starting directory */
     788                          &startInfo,
     789                          &procInfo) == FALSE) {
     790  
     791                          pproc->last_err = GetLastError();
     792                          pproc->lerrno = E_FORK;
     793                          fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n",
     794                                  exec_path ? exec_path : "NULL", command_line);
     795                          free(envblk);
     796                          free( command_line );
     797                          return(-1);
     798                  }
     799          }
     800  
     801          pproc->pid = (pid_t)procInfo.hProcess;
     802          /* Close the thread handle -- we'll just watch the process */
     803          CloseHandle(procInfo.hThread);
     804  
     805          /* Close the halves of the pipes we don't need */
     806          if ((HANDLE)pproc->sv_stdin[1] != INVALID_HANDLE_VALUE)
     807            CloseHandle((HANDLE)pproc->sv_stdin[1]);
     808          if ((HANDLE)pproc->sv_stdout[1] != INVALID_HANDLE_VALUE)
     809            CloseHandle((HANDLE)pproc->sv_stdout[1]);
     810          if ((HANDLE)pproc->sv_stderr[1] != INVALID_HANDLE_VALUE)
     811            CloseHandle((HANDLE)pproc->sv_stderr[1]);
     812          pproc->sv_stdin[1] = 0;
     813          pproc->sv_stdout[1] = 0;
     814          pproc->sv_stderr[1] = 0;
     815  
     816          free( command_line );
     817          free(envblk);
     818          pproc->lerrno=0;
     819          return 0;
     820  }
     821  
     822  
     823  
     824  #if 0   /* unused */
     825  static DWORD
     826  proc_stdin_thread(sub_process *pproc)
     827  {
     828          DWORD in_done;
     829          for (;;) {
     830                  if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
     831                                           &in_done, NULL) == FALSE)
     832                          _endthreadex(0);
     833                  /* This if should never be true for anonymous pipes, but gives
     834                     us a chance to change I/O mechanisms later.  */
     835                  if (in_done < pproc->incnt) {
     836                          pproc->incnt -= in_done;
     837                          pproc->inp += in_done;
     838                  } else {
     839                          _endthreadex(0);
     840                  }
     841          }
     842          return 0; /* for compiler warnings only.. not reached.  */
     843  }
     844  
     845  static DWORD
     846  proc_stdout_thread(sub_process *pproc)
     847  {
     848          DWORD bufsize = 1024;
     849          char c;
     850          DWORD nread;
     851          pproc->outp = malloc(bufsize);
     852          if (pproc->outp == NULL)
     853                  _endthreadex(0);
     854          pproc->outcnt = 0;
     855  
     856          for (;;) {
     857                  if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
     858                                          == FALSE) {
     859  /*                      map_windows32_error_to_string(GetLastError());*/
     860                          _endthreadex(0);
     861                  }
     862                  if (nread == 0)
     863                          _endthreadex(0);
     864                  if (pproc->outcnt + nread > bufsize) {
     865                          bufsize += nread + 512;
     866                          pproc->outp = realloc(pproc->outp, bufsize);
     867                          if (pproc->outp == NULL) {
     868                                  pproc->outcnt = 0;
     869                                  _endthreadex(0);
     870                          }
     871                  }
     872                  pproc->outp[pproc->outcnt++] = c;
     873          }
     874          return 0;
     875  }
     876  
     877  static DWORD
     878  proc_stderr_thread(sub_process *pproc)
     879  {
     880          DWORD bufsize = 1024;
     881          char c;
     882          DWORD nread;
     883          pproc->errp = malloc(bufsize);
     884          if (pproc->errp == NULL)
     885                  _endthreadex(0);
     886          pproc->errcnt = 0;
     887  
     888          for (;;) {
     889                  if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
     890                          map_windows32_error_to_string(GetLastError());
     891                          _endthreadex(0);
     892                  }
     893                  if (nread == 0)
     894                          _endthreadex(0);
     895                  if (pproc->errcnt + nread > bufsize) {
     896                          bufsize += nread + 512;
     897                          pproc->errp = realloc(pproc->errp, bufsize);
     898                          if (pproc->errp == NULL) {
     899                                  pproc->errcnt = 0;
     900                                  _endthreadex(0);
     901                          }
     902                  }
     903                  pproc->errp[pproc->errcnt++] = c;
     904          }
     905          return 0;
     906  }
     907  
     908  
     909  /*
     910   * Purpose: collects output from child process and returns results
     911   *
     912   * Description:
     913   *
     914   * Returns:
     915   *
     916   * Notes/Dependencies:
     917   */
     918          long
     919  process_pipe_io(
     920          HANDLE proc,
     921          char *stdin_data,
     922          int stdin_data_len)
     923  {
     924          sub_process *pproc = (sub_process *)proc;
     925          bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE;
     926          HANDLE childhand = (HANDLE) pproc->pid;
     927          HANDLE tStdin = NULL, tStdout = NULL, tStderr = NULL;
     928          unsigned int dwStdin, dwStdout, dwStderr;
     929          HANDLE wait_list[4];
     930          DWORD wait_count;
     931          DWORD wait_return;
     932          HANDLE ready_hand;
     933          bool_t child_dead = FALSE;
     934          BOOL GetExitCodeResult;
     935  
     936          /*
     937           *  Create stdin thread, if needed
     938           */
     939          pproc->inp = stdin_data;
     940          pproc->incnt = stdin_data_len;
     941          if (!pproc->inp) {
     942                  stdin_eof = TRUE;
     943                  CloseHandle((HANDLE)pproc->sv_stdin[0]);
     944                  pproc->sv_stdin[0] = 0;
     945          } else {
     946                  tStdin = (HANDLE) _beginthreadex( 0, 1024,
     947                          (unsigned (__stdcall *) (void *))proc_stdin_thread,
     948                                                    pproc, 0, &dwStdin);
     949                  if (tStdin == 0) {
     950                          pproc->last_err = GetLastError();
     951                          pproc->lerrno = E_SCALL;
     952                          goto done;
     953                  }
     954          }
     955  
     956          /*
     957           *   Assume child will produce stdout and stderr
     958           */
     959          tStdout = (HANDLE) _beginthreadex( 0, 1024,
     960                  (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0,
     961                  &dwStdout);
     962          tStderr = (HANDLE) _beginthreadex( 0, 1024,
     963                  (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0,
     964                  &dwStderr);
     965  
     966          if (tStdout == 0 || tStderr == 0) {
     967  
     968                  pproc->last_err = GetLastError();
     969                  pproc->lerrno = E_SCALL;
     970                  goto done;
     971          }
     972  
     973  
     974          /*
     975           *  Wait for all I/O to finish and for the child process to exit
     976           */
     977  
     978          while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
     979                  wait_count = 0;
     980                  if (!stdin_eof) {
     981                          wait_list[wait_count++] = tStdin;
     982                  }
     983                  if (!stdout_eof) {
     984                          wait_list[wait_count++] = tStdout;
     985                  }
     986                  if (!stderr_eof) {
     987                          wait_list[wait_count++] = tStderr;
     988                  }
     989                  if (!child_dead) {
     990                          wait_list[wait_count++] = childhand;
     991                  }
     992  
     993                  wait_return = WaitForMultipleObjects(wait_count, wait_list,
     994                           FALSE, /* don't wait for all: one ready will do */
     995                           child_dead? 1000 :INFINITE); /* after the child dies, subthreads have
     996                                  one second to collect all remaining output */
     997  
     998                  if (wait_return == WAIT_FAILED) {
     999  /*                      map_windows32_error_to_string(GetLastError());*/
    1000                          pproc->last_err = GetLastError();
    1001                          pproc->lerrno = E_SCALL;
    1002                          goto done;
    1003                  }
    1004  
    1005                  ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
    1006  
    1007                  if (ready_hand == tStdin) {
    1008                          CloseHandle((HANDLE)pproc->sv_stdin[0]);
    1009                          pproc->sv_stdin[0] = 0;
    1010                          CloseHandle(tStdin);
    1011                          tStdin = 0;
    1012                          stdin_eof = TRUE;
    1013  
    1014                  } else if (ready_hand == tStdout) {
    1015  
    1016                          CloseHandle((HANDLE)pproc->sv_stdout[0]);
    1017                          pproc->sv_stdout[0] = 0;
    1018                          CloseHandle(tStdout);
    1019                          tStdout = 0;
    1020                          stdout_eof = TRUE;
    1021  
    1022                  } else if (ready_hand == tStderr) {
    1023  
    1024                          CloseHandle((HANDLE)pproc->sv_stderr[0]);
    1025                          pproc->sv_stderr[0] = 0;
    1026                          CloseHandle(tStderr);
    1027                          tStderr = 0;
    1028                          stderr_eof = TRUE;
    1029  
    1030                  } else if (ready_hand == childhand) {
    1031  
    1032                          DWORD ierr;
    1033                          GetExitCodeResult = GetExitCodeProcess(childhand, &ierr);
    1034                          if (ierr == CONTROL_C_EXIT) {
    1035                                  pproc->signal = SIGINT;
    1036                          } else {
    1037                                  pproc->exit_code = ierr;
    1038                          }
    1039                          if (GetExitCodeResult == FALSE) {
    1040                                  pproc->last_err = GetLastError();
    1041                                  pproc->lerrno = E_SCALL;
    1042                                  goto done;
    1043                          }
    1044                          child_dead = TRUE;
    1045  
    1046                  } else {
    1047  
    1048                          /* ?? Got back a handle we didn't query ?? */
    1049                          pproc->last_err = 0;
    1050                          pproc->lerrno = E_FAIL;
    1051                          goto done;
    1052                  }
    1053          }
    1054  
    1055   done:
    1056          if (tStdin != 0)
    1057                  CloseHandle(tStdin);
    1058          if (tStdout != 0)
    1059                  CloseHandle(tStdout);
    1060          if (tStderr != 0)
    1061                  CloseHandle(tStderr);
    1062  
    1063          if (pproc->lerrno)
    1064                  return(-1);
    1065          else
    1066                  return(0);
    1067  
    1068  }
    1069  #endif  /* unused */
    1070  
    1071  /*
    1072   * Purpose: collects output from child process and returns results
    1073   *
    1074   * Description:
    1075   *
    1076   * Returns:
    1077   *
    1078   * Notes/Dependencies:
    1079   */
    1080          long
    1081  process_file_io(
    1082          HANDLE proc)
    1083  {
    1084          sub_process *pproc;
    1085          HANDLE childhand;
    1086          DWORD wait_return;
    1087          BOOL GetExitCodeResult;
    1088          DWORD ierr;
    1089  
    1090          if (proc == NULL)
    1091                  pproc = process_wait_for_any_private(1, 0);
    1092          else
    1093                  pproc = (sub_process *)proc;
    1094  
    1095          /* some sort of internal error */
    1096          if (!pproc)
    1097                  return -1;
    1098  
    1099          childhand = (HANDLE) pproc->pid;
    1100  
    1101          /*
    1102           * This function is poorly named, and could also be used just to wait
    1103           * for child death if you're doing your own pipe I/O.  If that is
    1104           * the case, close the pipe handles here.
    1105           */
    1106          if (pproc->sv_stdin[0]) {
    1107                  CloseHandle((HANDLE)pproc->sv_stdin[0]);
    1108                  pproc->sv_stdin[0] = 0;
    1109          }
    1110          if (pproc->sv_stdout[0]) {
    1111                  CloseHandle((HANDLE)pproc->sv_stdout[0]);
    1112                  pproc->sv_stdout[0] = 0;
    1113          }
    1114          if (pproc->sv_stderr[0]) {
    1115                  CloseHandle((HANDLE)pproc->sv_stderr[0]);
    1116                  pproc->sv_stderr[0] = 0;
    1117          }
    1118  
    1119          /*
    1120           *  Wait for the child process to exit
    1121           */
    1122  
    1123          wait_return = WaitForSingleObject(childhand, INFINITE);
    1124  
    1125          if (wait_return != WAIT_OBJECT_0) {
    1126  /*              map_windows32_error_to_string(GetLastError());*/
    1127                  pproc->last_err = GetLastError();
    1128                  pproc->lerrno = E_SCALL;
    1129                  goto done2;
    1130          }
    1131  
    1132          GetExitCodeResult = GetExitCodeProcess(childhand, &ierr);
    1133          if (ierr == CONTROL_C_EXIT) {
    1134                  pproc->signal = SIGINT;
    1135          } else {
    1136                  pproc->exit_code = ierr;
    1137          }
    1138          if (GetExitCodeResult == FALSE) {
    1139                  pproc->last_err = GetLastError();
    1140                  pproc->lerrno = E_SCALL;
    1141          }
    1142  
    1143  done2:
    1144          if (pproc->lerrno)
    1145                  return(-1);
    1146          else
    1147                  return(0);
    1148  
    1149  }
    1150  
    1151  /*
    1152   * Description:  Clean up any leftover handles, etc.  It is up to the
    1153   * caller to manage and free the input, output, and stderr buffers.
    1154   */
    1155          void
    1156  process_cleanup(
    1157          HANDLE proc)
    1158  {
    1159          sub_process *pproc = (sub_process *)proc;
    1160          int i;
    1161  
    1162          if (pproc->using_pipes) {
    1163                  for (i= 0; i <= 1; i++) {
    1164                          if ((HANDLE)pproc->sv_stdin[i]
    1165                              && (HANDLE)pproc->sv_stdin[i] != INVALID_HANDLE_VALUE)
    1166                                  CloseHandle((HANDLE)pproc->sv_stdin[i]);
    1167                          if ((HANDLE)pproc->sv_stdout[i]
    1168                              && (HANDLE)pproc->sv_stdout[i] != INVALID_HANDLE_VALUE)
    1169                                  CloseHandle((HANDLE)pproc->sv_stdout[i]);
    1170                          if ((HANDLE)pproc->sv_stderr[i]
    1171                              && (HANDLE)pproc->sv_stderr[i] != INVALID_HANDLE_VALUE)
    1172                                  CloseHandle((HANDLE)pproc->sv_stderr[i]);
    1173                  }
    1174          }
    1175          if ((HANDLE)pproc->pid)
    1176                  CloseHandle((HANDLE)pproc->pid);
    1177  
    1178          free(pproc);
    1179  }
    1180  
    1181  
    1182  /*
    1183   * Description:
    1184   *       Create a command line buffer to pass to CreateProcess
    1185   *
    1186   * Returns:  the buffer or NULL for failure
    1187   *      Shell case:  sh_name a:/full/path/to/script argv[1] argv[2] ...
    1188   *      Otherwise:   argv[0] argv[1] argv[2] ...
    1189   *
    1190   * Notes/Dependencies:
    1191   *   CreateProcess does not take an argv, so this command creates a
    1192   *   command line for the executable.
    1193   */
    1194  
    1195  static char *
    1196  make_command_line( char *shell_name, char *full_exec_path, char **argv)
    1197  {
    1198          int    argc = 0;
    1199          char** argvi;
    1200          int*   enclose_in_quotes = NULL;
    1201          int*   enclose_in_quotes_i;
    1202          size_t bytes_required = 0;
    1203          char*  command_line;
    1204          char*  command_line_i;
    1205          int have_sh = 0; /* HAVE_CYGWIN_SHELL */
    1206          int cygwin_mode = 0; /* HAVE_CYGWIN_SHELL */
    1207  
    1208  #ifdef HAVE_CYGWIN_SHELL
    1209          cygwin_mode = 1;
    1210  #endif
    1211  
    1212          if (shell_name && full_exec_path) {
    1213                  have_sh = cygwin_mode && strstr(full_exec_path, "sh.exe");
    1214                  bytes_required
    1215                    = strlen(shell_name) + 1 + strlen(full_exec_path);
    1216                  /*
    1217                   * Skip argv[0] if any, when shell_name is given.
    1218                   * The special case of "-c" in full_exec_path means
    1219                   * argv[0] is not the shell name, but the command string
    1220                   * to pass to the shell.
    1221                   */
    1222                  if (*argv && strcmp(full_exec_path, "-c")) argv++;
    1223                  /*
    1224                   * Add one for the intervening space.
    1225                   */
    1226                  if (*argv) bytes_required++;
    1227          }
    1228  
    1229          argvi = argv;
    1230          while (*(argvi++)) argc++;
    1231  
    1232          if (argc) {
    1233                  enclose_in_quotes = (int*) calloc(1, argc * sizeof(int));
    1234  
    1235                  if (!enclose_in_quotes) {
    1236                          return NULL;
    1237                  }
    1238          }
    1239  
    1240          /* We have to make one pass through each argv[i] to see if we need
    1241           * to enclose it in ", so we might as well figure out how much
    1242           * memory we'll need on the same pass.
    1243           */
    1244  
    1245          argvi = argv;
    1246          enclose_in_quotes_i = enclose_in_quotes;
    1247          while(*argvi) {
    1248                  char* p = *argvi;
    1249                  unsigned int backslash_count = 0;
    1250  
    1251                  /*
    1252                   * We have to enclose empty arguments in ".
    1253                   */
    1254                  if (!(*p)) *enclose_in_quotes_i = 1;
    1255  
    1256                  while(*p) {
    1257                          switch (*p) {
    1258                          case '\"':
    1259                                  /*
    1260                                   * We have to insert a backslash for each "
    1261                                   * and each \ that precedes the ".
    1262                                   */
    1263                                  bytes_required += (backslash_count + 1);
    1264                                  backslash_count = 0;
    1265                                  break;
    1266  
    1267  #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
    1268                          case '\\':
    1269                                  backslash_count++;
    1270                                  break;
    1271  #endif
    1272          /*
    1273           * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress
    1274           * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so
    1275           * that argv in always equals argv out. This was removed.  Say you have
    1276           * such a program named glob.exe.  You enter
    1277           * glob '*'
    1278           * at the sh command prompt.  Obviously the intent is to make glob do the
    1279           * wildcarding instead of sh.  If we set *enclose_in_quotes_i for '*' or '?',
    1280           * then the command line that glob would see would be
    1281           * glob "*"
    1282           * and the _setargv in SETARGV.OBJ would _not_ expand the *.
    1283           */
    1284                          case ' ':
    1285                          case '\t':
    1286                                  *enclose_in_quotes_i = 1;
    1287                                  /* fall through */
    1288  
    1289                          default:
    1290                                  backslash_count = 0;
    1291                                  break;
    1292                          }
    1293  
    1294                          /*
    1295                           * Add one for each character in argv[i].
    1296                           */
    1297                          bytes_required++;
    1298  
    1299                          p++;
    1300                  }
    1301  
    1302                  if (*enclose_in_quotes_i) {
    1303                          /*
    1304                           * Add one for each enclosing ",
    1305                           * and one for each \ that precedes the
    1306                           * closing ".
    1307                           */
    1308                          bytes_required += (backslash_count + 2);
    1309                  }
    1310  
    1311                  /*
    1312                   * Add one for the intervening space.
    1313                   */
    1314                  if (*(++argvi)) bytes_required++;
    1315                  enclose_in_quotes_i++;
    1316          }
    1317  
    1318          /*
    1319           * Add one for the terminating NULL.
    1320           */
    1321          bytes_required++;
    1322  
    1323          command_line = (char*) malloc(bytes_required);
    1324  
    1325          if (!command_line) {
    1326                  free(enclose_in_quotes);
    1327                  return NULL;
    1328          }
    1329  
    1330          command_line_i = command_line;
    1331  
    1332          if (shell_name && full_exec_path) {
    1333                  while(*shell_name) {
    1334                          *(command_line_i++) = *(shell_name++);
    1335                  }
    1336  
    1337                  *(command_line_i++) = ' ';
    1338  
    1339                  while(*full_exec_path) {
    1340                          *(command_line_i++) = *(full_exec_path++);
    1341                  }
    1342  
    1343                  if (*argv) {
    1344                          *(command_line_i++) = ' ';
    1345                  }
    1346          }
    1347  
    1348          argvi = argv;
    1349          enclose_in_quotes_i = enclose_in_quotes;
    1350  
    1351          while(*argvi) {
    1352                  char* p = *argvi;
    1353                  unsigned int backslash_count = 0;
    1354  
    1355                  if (*enclose_in_quotes_i) {
    1356                          *(command_line_i++) = '\"';
    1357                  }
    1358  
    1359                  while(*p) {
    1360                          if (*p == '\"') {
    1361                                  if (cygwin_mode && have_sh) { /* HAVE_CYGWIN_SHELL */
    1362                                          /* instead of a \", cygwin likes "" */
    1363                                          *(command_line_i++) = '\"';
    1364                                  } else {
    1365  
    1366                                  /*
    1367                                   * We have to insert a backslash for the "
    1368                                   * and each \ that precedes the ".
    1369                                   */
    1370                                  backslash_count++;
    1371  
    1372                                  while(backslash_count) {
    1373                                          *(command_line_i++) = '\\';
    1374                                          backslash_count--;
    1375                                  };
    1376                                  }
    1377  #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
    1378                          } else if (*p == '\\') {
    1379                                  backslash_count++;
    1380                          } else {
    1381                                  backslash_count = 0;
    1382  #endif
    1383                          }
    1384  
    1385                          /*
    1386                           * Copy the character.
    1387                           */
    1388                          *(command_line_i++) = *(p++);
    1389                  }
    1390  
    1391                  if (*enclose_in_quotes_i) {
    1392  #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
    1393                          /*
    1394                           * Add one \ for each \ that precedes the
    1395                           * closing ".
    1396                           */
    1397                          while(backslash_count--) {
    1398                                  *(command_line_i++) = '\\';
    1399                          };
    1400  #endif
    1401                          *(command_line_i++) = '\"';
    1402                  }
    1403  
    1404                  /*
    1405                   * Append an intervening space.
    1406                   */
    1407                  if (*(++argvi)) {
    1408                          *(command_line_i++) = ' ';
    1409                  }
    1410  
    1411                  enclose_in_quotes_i++;
    1412          }
    1413  
    1414          /*
    1415           * Append the terminating NULL.
    1416           */
    1417          *command_line_i = '\0';
    1418  
    1419          free(enclose_in_quotes);
    1420          return command_line;
    1421  }
    1422  
    1423  /*
    1424   * Description: Given an argv and optional envp, launch the process
    1425   *              using the default stdin, stdout, and stderr handles.
    1426   *              Also, register process so that process_wait_for_any_private()
    1427   *              can be used via process_file_io(NULL) or
    1428   *              process_wait_for_any().
    1429   *
    1430   * Returns:
    1431   *
    1432   * Notes/Dependencies:
    1433   */
    1434  HANDLE
    1435  process_easy(
    1436          char **argv,
    1437          char **envp,
    1438          int outfd,
    1439          int errfd)
    1440  {
    1441    HANDLE hIn = INVALID_HANDLE_VALUE;
    1442    HANDLE hOut = INVALID_HANDLE_VALUE;
    1443    HANDLE hErr = INVALID_HANDLE_VALUE;
    1444    HANDLE hProcess, tmpIn, tmpOut, tmpErr;
    1445    DWORD e;
    1446  
    1447    if (process_table_full()) {
    1448          DB (DB_JOBS, ("process_easy: All process slots used up\n"));
    1449          return INVALID_HANDLE_VALUE;
    1450    }
    1451    /* Standard handles returned by GetStdHandle can be NULL or
    1452       INVALID_HANDLE_VALUE if the parent process closed them.  If that
    1453       happens, we open the null device and pass its handle to
    1454       CreateProcess as the corresponding handle to inherit.  */
    1455    tmpIn = GetStdHandle(STD_INPUT_HANDLE);
    1456    if (DuplicateHandle(GetCurrentProcess(),
    1457                        tmpIn,
    1458                        GetCurrentProcess(),
    1459                        &hIn,
    1460                        0,
    1461                        TRUE,
    1462                        DUPLICATE_SAME_ACCESS) == FALSE) {
    1463      if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
    1464        tmpIn = CreateFile("NUL", GENERIC_READ,
    1465                           FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    1466                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    1467        if (tmpIn != INVALID_HANDLE_VALUE
    1468            && DuplicateHandle(GetCurrentProcess(),
    1469                               tmpIn,
    1470                               GetCurrentProcess(),
    1471                               &hIn,
    1472                               0,
    1473                               TRUE,
    1474                               DUPLICATE_SAME_ACCESS) == FALSE)
    1475          CloseHandle(tmpIn);
    1476      }
    1477      if (hIn == INVALID_HANDLE_VALUE) {
    1478        fprintf(stderr, "process_easy: DuplicateHandle(In) failed (e=%ld)\n", e);
    1479        return INVALID_HANDLE_VALUE;
    1480      }
    1481    }
    1482    if (outfd >= 0)
    1483      tmpOut = (HANDLE)_get_osfhandle (outfd);
    1484    else
    1485      tmpOut = GetStdHandle (STD_OUTPUT_HANDLE);
    1486    if (DuplicateHandle(GetCurrentProcess(),
    1487                        tmpOut,
    1488                        GetCurrentProcess(),
    1489                        &hOut,
    1490                        0,
    1491                        TRUE,
    1492                        DUPLICATE_SAME_ACCESS) == FALSE) {
    1493      if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
    1494        tmpOut = CreateFile("NUL", GENERIC_WRITE,
    1495                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    1496                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    1497        if (tmpOut != INVALID_HANDLE_VALUE
    1498            && DuplicateHandle(GetCurrentProcess(),
    1499                               tmpOut,
    1500                               GetCurrentProcess(),
    1501                               &hOut,
    1502                               0,
    1503                               TRUE,
    1504                               DUPLICATE_SAME_ACCESS) == FALSE)
    1505          CloseHandle(tmpOut);
    1506      }
    1507      if (hOut == INVALID_HANDLE_VALUE) {
    1508        fprintf(stderr, "process_easy: DuplicateHandle(Out) failed (e=%ld)\n", e);
    1509        return INVALID_HANDLE_VALUE;
    1510      }
    1511    }
    1512    if (errfd >= 0)
    1513      tmpErr = (HANDLE)_get_osfhandle (errfd);
    1514    else
    1515      tmpErr = GetStdHandle(STD_ERROR_HANDLE);
    1516    if (DuplicateHandle(GetCurrentProcess(),
    1517                        tmpErr,
    1518                        GetCurrentProcess(),
    1519                        &hErr,
    1520                        0,
    1521                        TRUE,
    1522                        DUPLICATE_SAME_ACCESS) == FALSE) {
    1523      if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
    1524        tmpErr = CreateFile("NUL", GENERIC_WRITE,
    1525                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    1526                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    1527        if (tmpErr != INVALID_HANDLE_VALUE
    1528            && DuplicateHandle(GetCurrentProcess(),
    1529                               tmpErr,
    1530                               GetCurrentProcess(),
    1531                               &hErr,
    1532                               0,
    1533                               TRUE,
    1534                               DUPLICATE_SAME_ACCESS) == FALSE)
    1535          CloseHandle(tmpErr);
    1536      }
    1537      if (hErr == INVALID_HANDLE_VALUE) {
    1538        fprintf(stderr, "process_easy: DuplicateHandle(Err) failed (e=%ld)\n", e);
    1539        return INVALID_HANDLE_VALUE;
    1540      }
    1541    }
    1542  
    1543    hProcess = process_init_fd(hIn, hOut, hErr);
    1544  
    1545    if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
    1546      fake_exits_pending++;
    1547      /* process_begin() failed: make a note of that.  */
    1548      if (!((sub_process*) hProcess)->last_err)
    1549        ((sub_process*) hProcess)->last_err = -1;
    1550      ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
    1551  
    1552      /* close up unused handles */
    1553      if (hIn != INVALID_HANDLE_VALUE)
    1554        CloseHandle(hIn);
    1555      if (hOut != INVALID_HANDLE_VALUE)
    1556        CloseHandle(hOut);
    1557      if (hErr != INVALID_HANDLE_VALUE)
    1558        CloseHandle(hErr);
    1559    }
    1560  
    1561    process_register(hProcess);
    1562  
    1563    return hProcess;
    1564  }