VirtualBox

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

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

kmk: kSubmit is mostly done.

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