VirtualBox

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

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

kmk: Added $(dircache-ctl cmd,...) function for controlling the directory content cache on windows. Some other optimizations.

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