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