VirtualBox

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

Last change on this file since 2862 was 2862, checked in by bird, 8 years ago

updates

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