VirtualBox

source: kBuild/vendor/gnumake/current/w32/subproc/sub_proc.c

Last change on this file was 3138, checked in by bird, 7 years ago

Imported make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6) from https://git.savannah.gnu.org/git/make.git.

  • Property svn:eol-style set to native
File size: 48.5 KB
Line 
1/* Process handling for Windows.
2Copyright (C) 1996-2016 Free Software Foundation, Inc.
3This file is part of GNU Make.
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 3 of the License, or (at your option) any later
8version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this 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
39static char *make_command_line(char *shell_name, char *exec_path, char **argv);
40
41typedef 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 */
60static sub_process *proc_array[MAXIMUM_WAIT_OBJECTS];
61static int proc_index = 0;
62static int fake_exits_pending = 0;
63
64
65/*
66 * Fill a HANDLE list with handles to wait for.
67 */
68DWORD
69process_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 */
90static void
91process_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 */
114static sub_process *
115process_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 */
160BOOL
161process_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 */
174void
175process_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 */
184int
185process_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
212HANDLE
213process_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
229long
230process_signal(HANDLE proc)
231{
232 if (proc == INVALID_HANDLE_VALUE) return 0;
233 return (((sub_process *)proc)->signal);
234}
235
236long
237process_last_err(HANDLE proc)
238{
239 if (proc == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
240 return (((sub_process *)proc)->last_err);
241}
242
243long
244process_exit_code(HANDLE proc)
245{
246 if (proc == INVALID_HANDLE_VALUE) return EXIT_FAILURE;
247 return (((sub_process *)proc)->exit_code);
248}
249
250void
251process_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/*
2602006-02:
261All the following functions are currently unused.
262All of them would crash gmake if called with argument INVALID_HANDLE_VALUE.
263Hence whoever wants to use one of this functions must invent and implement
264a reasonable error handling for this function.
265
266char *
267process_outbuf(HANDLE proc)
268{
269 return (((sub_process *)proc)->outp);
270}
271
272char *
273process_errbuf(HANDLE proc)
274{
275 return (((sub_process *)proc)->errp);
276}
277
278int
279process_outcnt(HANDLE proc)
280{
281 return (((sub_process *)proc)->outcnt);
282}
283
284int
285process_errcnt(HANDLE proc)
286{
287 return (((sub_process *)proc)->errcnt);
288}
289
290void
291process_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
301process_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
374process_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
397static HANDLE
398find_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
453static int
454batch_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 */
476long
477process_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 */
743static DWORD
744proc_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
763static DWORD
764proc_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
795static DWORD
796proc_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
837process_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
999process_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
1061done2:
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
1074process_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
1113static char *
1114make_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 */
1352HANDLE
1353process_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}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette