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