VirtualBox

source: kBuild/vendor/gnumake/3.82-cvs/w32/subproc/sub_proc.c

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

Importing the make-3-82 CVS tag with --auto-props but no keywords.

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