VirtualBox

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

Last change on this file since 2636 was 2636, checked in by bird, 12 years ago

kmk: experimental executable image cache for windows.

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