• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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