VirtualBox

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

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

fixes

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