Imported Upstream version 4.4
[platform/upstream/make.git] / 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 }