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 }