VirtualBox

source: kBuild/trunk/src/kmk/w32/subproc/sub_proc.c@ 2591

Last change on this file since 2591 was 2591, checked in by bird, 13 years ago

kmk: Merged in changes from GNU make 3.82. Previous GNU make base version was gnumake-2008-10-28-CVS.

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