Various updates, mainly to the Windows port, from Eli Zaretskii and
[make.git] / w32 / subproc / sub_proc.c
blob6af33bc7a5e2afbd699167e08070c07cc76e814f
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <process.h> /* for msvc _beginthreadex, _endthreadex */
4 #include <signal.h>
5 #include <windows.h>
7 #include "sub_proc.h"
8 #include "proc.h"
9 #include "w32err.h"
10 #include "config.h"
11 #include "debug.h"
13 static char *make_command_line(char *shell_name, char *exec_path, char **argv);
15 typedef struct sub_process_t {
16 int sv_stdin[2];
17 int sv_stdout[2];
18 int sv_stderr[2];
19 int using_pipes;
20 char *inp;
21 DWORD incnt;
22 char * volatile outp;
23 volatile DWORD outcnt;
24 char * volatile errp;
25 volatile DWORD errcnt;
26 int pid;
27 int exit_code;
28 int signal;
29 long last_err;
30 long lerrno;
31 } sub_process;
33 /* keep track of children so we can implement a waitpid-like routine */
34 static sub_process *proc_array[MAXIMUM_WAIT_OBJECTS];
35 static int proc_index = 0;
36 static int fake_exits_pending = 0;
39 * When a process has been waited for, adjust the wait state
40 * array so that we don't wait for it again
42 static void
43 process_adjust_wait_state(sub_process* pproc)
45 int i;
47 if (!proc_index)
48 return;
50 for (i = 0; i < proc_index; i++)
51 if (proc_array[i]->pid == pproc->pid)
52 break;
54 if (i < proc_index) {
55 proc_index--;
56 if (i != proc_index)
57 memmove(&proc_array[i], &proc_array[i+1],
58 (proc_index-i) * sizeof(sub_process*));
59 proc_array[proc_index] = NULL;
64 * Waits for any of the registered child processes to finish.
66 static sub_process *
67 process_wait_for_any_private(void)
69 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
70 DWORD retval, which;
71 int i;
73 if (!proc_index)
74 return NULL;
76 /* build array of handles to wait for */
77 for (i = 0; i < proc_index; i++) {
78 handles[i] = (HANDLE) proc_array[i]->pid;
80 if (fake_exits_pending && proc_array[i]->exit_code)
81 break;
84 /* wait for someone to exit */
85 if (!fake_exits_pending) {
86 retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE);
87 which = retval - WAIT_OBJECT_0;
88 } else {
89 fake_exits_pending--;
90 retval = !WAIT_FAILED;
91 which = i;
94 /* return pointer to process */
95 if (retval != WAIT_FAILED) {
96 sub_process* pproc = proc_array[which];
97 process_adjust_wait_state(pproc);
98 return pproc;
99 } else
100 return NULL;
104 * Terminate a process.
106 BOOL
107 process_kill(HANDLE proc, int signal)
109 sub_process* pproc = (sub_process*) proc;
110 pproc->signal = signal;
111 return (TerminateProcess((HANDLE) pproc->pid, signal));
115 * Use this function to register processes you wish to wait for by
116 * calling process_file_io(NULL) or process_wait_any(). This must be done
117 * because it is possible for callers of this library to reuse the same
118 * handle for multiple processes launches :-(
120 void
121 process_register(HANDLE proc)
123 if (proc_index < MAXIMUM_WAIT_OBJECTS)
124 proc_array[proc_index++] = (sub_process *) proc;
128 * Return the number of processes that we are still waiting for.
131 process_used_slots(void)
133 return proc_index;
137 * Public function which works kind of like waitpid(). Wait for any
138 * of the children to die and return results. To call this function,
139 * you must do 1 of things:
141 * x = process_easy(...);
143 * or
145 * x = process_init_fd();
146 * process_register(x);
148 * or
150 * x = process_init();
151 * process_register(x);
153 * You must NOT then call process_pipe_io() because this function is
154 * not capable of handling automatic notification of any child
155 * death.
158 HANDLE
159 process_wait_for_any(void)
161 sub_process* pproc = process_wait_for_any_private();
163 if (!pproc)
164 return NULL;
165 else {
167 * Ouch! can't tell caller if this fails directly. Caller
168 * will have to use process_last_err()
170 (void) process_file_io(pproc);
171 return ((HANDLE) pproc);
175 long
176 process_errno(HANDLE proc)
178 return (((sub_process *)proc)->lerrno);
181 long
182 process_signal(HANDLE proc)
184 return (((sub_process *)proc)->signal);
187 long
188 process_last_err(HANDLE proc)
190 return (((sub_process *)proc)->last_err);
193 long
194 process_exit_code(HANDLE proc)
196 return (((sub_process *)proc)->exit_code);
199 char *
200 process_outbuf(HANDLE proc)
202 return (((sub_process *)proc)->outp);
205 char *
206 process_errbuf(HANDLE proc)
208 return (((sub_process *)proc)->errp);
212 process_outcnt(HANDLE proc)
214 return (((sub_process *)proc)->outcnt);
218 process_errcnt(HANDLE proc)
220 return (((sub_process *)proc)->errcnt);
223 void
224 process_pipes(HANDLE proc, int pipes[3])
226 pipes[0] = ((sub_process *)proc)->sv_stdin[0];
227 pipes[1] = ((sub_process *)proc)->sv_stdout[0];
228 pipes[2] = ((sub_process *)proc)->sv_stderr[0];
229 return;
233 HANDLE
234 process_init()
236 sub_process *pproc;
238 * open file descriptors for attaching stdin/stdout/sterr
240 HANDLE stdin_pipes[2];
241 HANDLE stdout_pipes[2];
242 HANDLE stderr_pipes[2];
243 SECURITY_ATTRIBUTES inherit;
244 BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
246 pproc = malloc(sizeof(*pproc));
247 memset(pproc, 0, sizeof(*pproc));
249 /* We can't use NULL for lpSecurityDescriptor because that
250 uses the default security descriptor of the calling process.
251 Instead we use a security descriptor with no DACL. This
252 allows nonrestricted access to the associated objects. */
254 if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
255 SECURITY_DESCRIPTOR_REVISION)) {
256 pproc->last_err = GetLastError();
257 pproc->lerrno = E_SCALL;
258 return((HANDLE)pproc);
261 inherit.nLength = sizeof(inherit);
262 inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
263 inherit.bInheritHandle = TRUE;
265 // By convention, parent gets pipe[0], and child gets pipe[1]
266 // This means the READ side of stdin pipe goes into pipe[1]
267 // and the WRITE side of the stdout and stderr pipes go into pipe[1]
268 if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE ||
269 CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE ||
270 CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) {
272 pproc->last_err = GetLastError();
273 pproc->lerrno = E_SCALL;
274 return((HANDLE)pproc);
278 // Mark the parent sides of the pipes as non-inheritable
280 if (SetHandleInformation(stdin_pipes[0],
281 HANDLE_FLAG_INHERIT, 0) == FALSE ||
282 SetHandleInformation(stdout_pipes[0],
283 HANDLE_FLAG_INHERIT, 0) == FALSE ||
284 SetHandleInformation(stderr_pipes[0],
285 HANDLE_FLAG_INHERIT, 0) == FALSE) {
287 pproc->last_err = GetLastError();
288 pproc->lerrno = E_SCALL;
289 return((HANDLE)pproc);
291 pproc->sv_stdin[0] = (int) stdin_pipes[0];
292 pproc->sv_stdin[1] = (int) stdin_pipes[1];
293 pproc->sv_stdout[0] = (int) stdout_pipes[0];
294 pproc->sv_stdout[1] = (int) stdout_pipes[1];
295 pproc->sv_stderr[0] = (int) stderr_pipes[0];
296 pproc->sv_stderr[1] = (int) stderr_pipes[1];
298 pproc->using_pipes = 1;
300 pproc->lerrno = 0;
302 return((HANDLE)pproc);
306 HANDLE
307 process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
309 sub_process *pproc;
311 pproc = malloc(sizeof(*pproc));
312 memset(pproc, 0, sizeof(*pproc));
315 * Just pass the provided file handles to the 'child side' of the
316 * pipe, bypassing pipes altogether.
318 pproc->sv_stdin[1] = (int) stdinh;
319 pproc->sv_stdout[1] = (int) stdouth;
320 pproc->sv_stderr[1] = (int) stderrh;
322 pproc->last_err = pproc->lerrno = 0;
324 return((HANDLE)pproc);
328 static HANDLE
329 find_file(char *exec_path, LPOFSTRUCT file_info)
331 HANDLE exec_handle;
332 char *fname;
333 char *ext;
335 fname = malloc(strlen(exec_path) + 5);
336 strcpy(fname, exec_path);
337 ext = fname + strlen(fname);
339 strcpy(ext, ".exe");
340 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
341 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
342 free(fname);
343 return(exec_handle);
346 strcpy(ext, ".cmd");
347 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
348 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
349 free(fname);
350 return(exec_handle);
353 strcpy(ext, ".bat");
354 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
355 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
356 free(fname);
357 return(exec_handle);
360 /* should .com come before this case? */
361 if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info,
362 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
363 free(fname);
364 return(exec_handle);
367 strcpy(ext, ".com");
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);
374 free(fname);
375 return(exec_handle);
380 * Description: Create the child process to be helped
382 * Returns:
384 * Notes/Dependencies:
386 long
387 process_begin(
388 HANDLE proc,
389 char **argv,
390 char **envp,
391 char *exec_path,
392 char *as_user)
394 sub_process *pproc = (sub_process *)proc;
395 char *shell_name = 0;
396 int file_not_found=0;
397 HANDLE exec_handle;
398 char buf[256];
399 DWORD bytes_returned;
400 DWORD flags;
401 char *command_line;
402 STARTUPINFO startInfo;
403 PROCESS_INFORMATION procInfo;
404 char *envblk=NULL;
405 OFSTRUCT file_info;
409 * Shell script detection... if the exec_path starts with #! then
410 * we want to exec shell-script-name exec-path, not just exec-path
411 * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not
412 * hard-code the path to the shell or perl or whatever: Instead, we
413 * assume it's in the path somewhere (generally, the NT tools
414 * bin directory)
415 * We use OpenFile here because it is capable of searching the Path.
418 exec_handle = find_file(exec_path, &file_info);
421 * If we couldn't open the file, just assume that Windows32 will be able
422 * to find and execute it.
424 if (exec_handle == (HANDLE)HFILE_ERROR) {
425 file_not_found++;
427 else {
428 /* Attempt to read the first line of the file */
429 if (ReadFile( exec_handle,
430 buf, sizeof(buf) - 1, /* leave room for trailing NULL */
431 &bytes_returned, 0) == FALSE || bytes_returned < 2) {
433 pproc->last_err = GetLastError();
434 pproc->lerrno = E_IO;
435 CloseHandle(exec_handle);
436 return(-1);
438 if (buf[0] == '#' && buf[1] == '!') {
440 * This is a shell script... Change the command line from
441 * exec_path args to shell_name exec_path args
443 char *p;
445 /* Make sure buf is NULL terminated */
446 buf[bytes_returned] = 0;
448 * Depending on the file system type, etc. the first line
449 * of the shell script may end with newline or newline-carriage-return
450 * Whatever it ends with, cut it off.
452 p= strchr(buf, '\n');
453 if (p)
454 *p = 0;
455 p = strchr(buf, '\r');
456 if (p)
457 *p = 0;
460 * Find base name of shell
462 shell_name = strrchr( buf, '/');
463 if (shell_name) {
464 shell_name++;
465 } else {
466 shell_name = &buf[2];/* skipping "#!" */
470 CloseHandle(exec_handle);
473 flags = 0;
475 if (file_not_found)
476 command_line = make_command_line( shell_name, exec_path, argv);
477 else
478 command_line = make_command_line( shell_name, file_info.szPathName,
479 argv);
481 if ( command_line == NULL ) {
482 pproc->last_err = 0;
483 pproc->lerrno = E_NO_MEM;
484 return(-1);
487 if (envp) {
488 if (arr2envblk(envp, &envblk) ==FALSE) {
489 pproc->last_err = 0;
490 pproc->lerrno = E_NO_MEM;
491 free( command_line );
492 return(-1);
496 if ((shell_name) || (file_not_found)) {
497 exec_path = 0; /* Search for the program in %Path% */
498 } else {
499 exec_path = file_info.szPathName;
503 * Set up inherited stdin, stdout, stderr for child
505 GetStartupInfo(&startInfo);
506 startInfo.dwFlags = STARTF_USESTDHANDLES;
507 startInfo.lpReserved = 0;
508 startInfo.cbReserved2 = 0;
509 startInfo.lpReserved2 = 0;
510 startInfo.lpTitle = shell_name ? shell_name : exec_path;
511 startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1];
512 startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1];
513 startInfo.hStdError = (HANDLE)pproc->sv_stderr[1];
515 if (as_user) {
516 if (envblk) free(envblk);
517 return -1;
518 } else {
519 DB (DB_JOBS, ("CreateProcess(%s,%s,...)\n",
520 exec_path ? exec_path : "NULL",
521 command_line ? command_line : "NULL"));
522 if (CreateProcess(
523 exec_path,
524 command_line,
525 NULL,
526 0, /* default security attributes for thread */
527 TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
528 flags,
529 envblk,
530 0, /* default starting directory */
531 &startInfo,
532 &procInfo) == FALSE) {
534 pproc->last_err = GetLastError();
535 pproc->lerrno = E_FORK;
536 fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n",
537 exec_path ? exec_path : "NULL", command_line);
538 if (envblk) free(envblk);
539 free( command_line );
540 return(-1);
544 pproc->pid = (int)procInfo.hProcess;
545 /* Close the thread handle -- we'll just watch the process */
546 CloseHandle(procInfo.hThread);
548 /* Close the halves of the pipes we don't need */
549 if (pproc->sv_stdin) {
550 CloseHandle((HANDLE)pproc->sv_stdin[1]);
551 pproc->sv_stdin[1] = 0;
553 if (pproc->sv_stdout) {
554 CloseHandle((HANDLE)pproc->sv_stdout[1]);
555 pproc->sv_stdout[1] = 0;
557 if (pproc->sv_stderr) {
558 CloseHandle((HANDLE)pproc->sv_stderr[1]);
559 pproc->sv_stderr[1] = 0;
562 free( command_line );
563 if (envblk) free(envblk);
564 pproc->lerrno=0;
565 return 0;
570 static DWORD
571 proc_stdin_thread(sub_process *pproc)
573 DWORD in_done;
574 for (;;) {
575 if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
576 &in_done, NULL) == FALSE)
577 _endthreadex(0);
578 // This if should never be true for anonymous pipes, but gives
579 // us a chance to change I/O mechanisms later
580 if (in_done < pproc->incnt) {
581 pproc->incnt -= in_done;
582 pproc->inp += in_done;
583 } else {
584 _endthreadex(0);
587 return 0; // for compiler warnings only.. not reached
590 static DWORD
591 proc_stdout_thread(sub_process *pproc)
593 DWORD bufsize = 1024;
594 char c;
595 DWORD nread;
596 pproc->outp = malloc(bufsize);
597 if (pproc->outp == NULL)
598 _endthreadex(0);
599 pproc->outcnt = 0;
601 for (;;) {
602 if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
603 == FALSE) {
604 /* map_windows32_error_to_string(GetLastError());*/
605 _endthreadex(0);
607 if (nread == 0)
608 _endthreadex(0);
609 if (pproc->outcnt + nread > bufsize) {
610 bufsize += nread + 512;
611 pproc->outp = realloc(pproc->outp, bufsize);
612 if (pproc->outp == NULL) {
613 pproc->outcnt = 0;
614 _endthreadex(0);
617 pproc->outp[pproc->outcnt++] = c;
619 return 0;
622 static DWORD
623 proc_stderr_thread(sub_process *pproc)
625 DWORD bufsize = 1024;
626 char c;
627 DWORD nread;
628 pproc->errp = malloc(bufsize);
629 if (pproc->errp == NULL)
630 _endthreadex(0);
631 pproc->errcnt = 0;
633 for (;;) {
634 if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
635 map_windows32_error_to_string(GetLastError());
636 _endthreadex(0);
638 if (nread == 0)
639 _endthreadex(0);
640 if (pproc->errcnt + nread > bufsize) {
641 bufsize += nread + 512;
642 pproc->errp = realloc(pproc->errp, bufsize);
643 if (pproc->errp == NULL) {
644 pproc->errcnt = 0;
645 _endthreadex(0);
648 pproc->errp[pproc->errcnt++] = c;
650 return 0;
655 * Purpose: collects output from child process and returns results
657 * Description:
659 * Returns:
661 * Notes/Dependencies:
663 long
664 process_pipe_io(
665 HANDLE proc,
666 char *stdin_data,
667 int stdin_data_len)
669 sub_process *pproc = (sub_process *)proc;
670 bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE;
671 HANDLE childhand = (HANDLE) pproc->pid;
672 HANDLE tStdin = NULL, tStdout = NULL, tStderr = NULL;
673 DWORD dwStdin, dwStdout, dwStderr;
674 HANDLE wait_list[4];
675 DWORD wait_count;
676 DWORD wait_return;
677 HANDLE ready_hand;
678 bool_t child_dead = FALSE;
679 BOOL GetExitCodeResult;
682 * Create stdin thread, if needed
684 pproc->inp = stdin_data;
685 pproc->incnt = stdin_data_len;
686 if (!pproc->inp) {
687 stdin_eof = TRUE;
688 CloseHandle((HANDLE)pproc->sv_stdin[0]);
689 pproc->sv_stdin[0] = 0;
690 } else {
691 tStdin = (HANDLE) _beginthreadex( 0, 1024,
692 (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0,
693 (unsigned int *) &dwStdin);
694 if (tStdin == 0) {
695 pproc->last_err = GetLastError();
696 pproc->lerrno = E_SCALL;
697 goto done;
702 * Assume child will produce stdout and stderr
704 tStdout = (HANDLE) _beginthreadex( 0, 1024,
705 (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0,
706 (unsigned int *) &dwStdout);
707 tStderr = (HANDLE) _beginthreadex( 0, 1024,
708 (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0,
709 (unsigned int *) &dwStderr);
711 if (tStdout == 0 || tStderr == 0) {
713 pproc->last_err = GetLastError();
714 pproc->lerrno = E_SCALL;
715 goto done;
720 * Wait for all I/O to finish and for the child process to exit
723 while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
724 wait_count = 0;
725 if (!stdin_eof) {
726 wait_list[wait_count++] = tStdin;
728 if (!stdout_eof) {
729 wait_list[wait_count++] = tStdout;
731 if (!stderr_eof) {
732 wait_list[wait_count++] = tStderr;
734 if (!child_dead) {
735 wait_list[wait_count++] = childhand;
738 wait_return = WaitForMultipleObjects(wait_count, wait_list,
739 FALSE, /* don't wait for all: one ready will do */
740 child_dead? 1000 :INFINITE); /* after the child dies, subthreads have
741 one second to collect all remaining output */
743 if (wait_return == WAIT_FAILED) {
744 /* map_windows32_error_to_string(GetLastError());*/
745 pproc->last_err = GetLastError();
746 pproc->lerrno = E_SCALL;
747 goto done;
750 ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
752 if (ready_hand == tStdin) {
753 CloseHandle((HANDLE)pproc->sv_stdin[0]);
754 pproc->sv_stdin[0] = 0;
755 CloseHandle(tStdin);
756 tStdin = 0;
757 stdin_eof = TRUE;
759 } else if (ready_hand == tStdout) {
761 CloseHandle((HANDLE)pproc->sv_stdout[0]);
762 pproc->sv_stdout[0] = 0;
763 CloseHandle(tStdout);
764 tStdout = 0;
765 stdout_eof = TRUE;
767 } else if (ready_hand == tStderr) {
769 CloseHandle((HANDLE)pproc->sv_stderr[0]);
770 pproc->sv_stderr[0] = 0;
771 CloseHandle(tStderr);
772 tStderr = 0;
773 stderr_eof = TRUE;
775 } else if (ready_hand == childhand) {
777 DWORD ierr;
778 GetExitCodeResult = GetExitCodeProcess(childhand, &ierr);
779 if (ierr == CONTROL_C_EXIT) {
780 pproc->signal = SIGINT;
781 } else {
782 pproc->exit_code = ierr;
784 if (GetExitCodeResult == FALSE) {
785 pproc->last_err = GetLastError();
786 pproc->lerrno = E_SCALL;
787 goto done;
789 child_dead = TRUE;
791 } else {
793 /* ?? Got back a handle we didn't query ?? */
794 pproc->last_err = 0;
795 pproc->lerrno = E_FAIL;
796 goto done;
800 done:
801 if (tStdin != 0)
802 CloseHandle(tStdin);
803 if (tStdout != 0)
804 CloseHandle(tStdout);
805 if (tStderr != 0)
806 CloseHandle(tStderr);
808 if (pproc->lerrno)
809 return(-1);
810 else
811 return(0);
816 * Purpose: collects output from child process and returns results
818 * Description:
820 * Returns:
822 * Notes/Dependencies:
824 long
825 process_file_io(
826 HANDLE proc)
828 sub_process *pproc;
829 HANDLE childhand;
830 DWORD wait_return;
831 BOOL GetExitCodeResult;
832 DWORD ierr;
834 if (proc == NULL)
835 pproc = process_wait_for_any_private();
836 else
837 pproc = (sub_process *)proc;
839 /* some sort of internal error */
840 if (!pproc)
841 return -1;
843 childhand = (HANDLE) pproc->pid;
846 * This function is poorly named, and could also be used just to wait
847 * for child death if you're doing your own pipe I/O. If that is
848 * the case, close the pipe handles here.
850 if (pproc->sv_stdin[0]) {
851 CloseHandle((HANDLE)pproc->sv_stdin[0]);
852 pproc->sv_stdin[0] = 0;
854 if (pproc->sv_stdout[0]) {
855 CloseHandle((HANDLE)pproc->sv_stdout[0]);
856 pproc->sv_stdout[0] = 0;
858 if (pproc->sv_stderr[0]) {
859 CloseHandle((HANDLE)pproc->sv_stderr[0]);
860 pproc->sv_stderr[0] = 0;
864 * Wait for the child process to exit
867 wait_return = WaitForSingleObject(childhand, INFINITE);
869 if (wait_return != WAIT_OBJECT_0) {
870 /* map_windows32_error_to_string(GetLastError());*/
871 pproc->last_err = GetLastError();
872 pproc->lerrno = E_SCALL;
873 goto done2;
876 GetExitCodeResult = GetExitCodeProcess(childhand, &ierr);
877 if (ierr == CONTROL_C_EXIT) {
878 pproc->signal = SIGINT;
879 } else {
880 pproc->exit_code = ierr;
882 if (GetExitCodeResult == FALSE) {
883 pproc->last_err = GetLastError();
884 pproc->lerrno = E_SCALL;
887 done2:
888 if (pproc->lerrno)
889 return(-1);
890 else
891 return(0);
896 * Description: Clean up any leftover handles, etc. It is up to the
897 * caller to manage and free the input, ouput, and stderr buffers.
899 void
900 process_cleanup(
901 HANDLE proc)
903 sub_process *pproc = (sub_process *)proc;
904 int i;
906 if (pproc->using_pipes) {
907 for (i= 0; i <= 1; i++) {
908 if ((HANDLE)pproc->sv_stdin[i])
909 CloseHandle((HANDLE)pproc->sv_stdin[i]);
910 if ((HANDLE)pproc->sv_stdout[i])
911 CloseHandle((HANDLE)pproc->sv_stdout[i]);
912 if ((HANDLE)pproc->sv_stderr[i])
913 CloseHandle((HANDLE)pproc->sv_stderr[i]);
916 if ((HANDLE)pproc->pid)
917 CloseHandle((HANDLE)pproc->pid);
919 free(pproc);
924 * Description:
925 * Create a command line buffer to pass to CreateProcess
927 * Returns: the buffer or NULL for failure
928 * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
929 * Otherwise: argv[0] argv[1] argv[2] ...
931 * Notes/Dependencies:
932 * CreateProcess does not take an argv, so this command creates a
933 * command line for the executable.
936 static char *
937 make_command_line( char *shell_name, char *full_exec_path, char **argv)
939 int argc = 0;
940 char** argvi;
941 int* enclose_in_quotes = NULL;
942 int* enclose_in_quotes_i;
943 unsigned int bytes_required = 0;
944 char* command_line;
945 char* command_line_i;
946 int cygwin_mode = 0; /* HAVE_CYGWIN_SHELL */
947 int have_sh = 0; /* HAVE_CYGWIN_SHELL */
949 #ifdef HAVE_CYGWIN_SHELL
950 have_sh = (shell_name != NULL || strstr(full_exec_path, "sh.exe"));
951 cygwin_mode = 1;
952 #endif
954 if (shell_name && full_exec_path) {
955 bytes_required
956 = strlen(shell_name) + 1 + strlen(full_exec_path);
958 * Skip argv[0] if any, when shell_name is given.
960 if (*argv) argv++;
962 * Add one for the intervening space.
964 if (*argv) bytes_required++;
967 argvi = argv;
968 while (*(argvi++)) argc++;
970 if (argc) {
971 enclose_in_quotes = (int*) calloc(1, argc * sizeof(int));
973 if (!enclose_in_quotes) {
974 return NULL;
978 /* We have to make one pass through each argv[i] to see if we need
979 * to enclose it in ", so we might as well figure out how much
980 * memory we'll need on the same pass.
983 argvi = argv;
984 enclose_in_quotes_i = enclose_in_quotes;
985 while(*argvi) {
986 char* p = *argvi;
987 unsigned int backslash_count = 0;
990 * We have to enclose empty arguments in ".
992 if (!(*p)) *enclose_in_quotes_i = 1;
994 while(*p) {
995 switch (*p) {
996 case '\"':
998 * We have to insert a backslash for each "
999 * and each \ that precedes the ".
1001 bytes_required += (backslash_count + 1);
1002 backslash_count = 0;
1003 break;
1005 #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
1006 case '\\':
1007 backslash_count++;
1008 break;
1009 #endif
1011 * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress
1012 * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so
1013 * that argv in always equals argv out. This was removed. Say you have
1014 * such a program named glob.exe. You enter
1015 * glob '*'
1016 * at the sh command prompt. Obviously the intent is to make glob do the
1017 * wildcarding instead of sh. If we set *enclose_in_quotes_i for '*' or '?',
1018 * then the command line that glob would see would be
1019 * glob "*"
1020 * and the _setargv in SETARGV.OBJ would _not_ expand the *.
1022 case ' ':
1023 case '\t':
1024 *enclose_in_quotes_i = 1;
1025 /* fall through */
1027 default:
1028 backslash_count = 0;
1029 break;
1033 * Add one for each character in argv[i].
1035 bytes_required++;
1037 p++;
1040 if (*enclose_in_quotes_i) {
1042 * Add one for each enclosing ",
1043 * and one for each \ that precedes the
1044 * closing ".
1046 bytes_required += (backslash_count + 2);
1050 * Add one for the intervening space.
1052 if (*(++argvi)) bytes_required++;
1053 enclose_in_quotes_i++;
1057 * Add one for the terminating NULL.
1059 bytes_required++;
1061 command_line = (char*) malloc(bytes_required);
1063 if (!command_line) {
1064 if (enclose_in_quotes) free(enclose_in_quotes);
1065 return NULL;
1068 command_line_i = command_line;
1070 if (shell_name && full_exec_path) {
1071 while(*shell_name) {
1072 *(command_line_i++) = *(shell_name++);
1075 *(command_line_i++) = ' ';
1077 while(*full_exec_path) {
1078 *(command_line_i++) = *(full_exec_path++);
1081 if (*argv) {
1082 *(command_line_i++) = ' ';
1086 argvi = argv;
1087 enclose_in_quotes_i = enclose_in_quotes;
1089 while(*argvi) {
1090 char* p = *argvi;
1091 unsigned int backslash_count = 0;
1093 if (*enclose_in_quotes_i) {
1094 *(command_line_i++) = '\"';
1097 while(*p) {
1098 if (*p == '\"') {
1099 if (cygwin_mode && have_sh) { /* HAVE_CYGWIN_SHELL */
1100 /* instead of a \", cygwin likes "" */
1101 *(command_line_i++) = '\"';
1102 } else {
1105 * We have to insert a backslash for the "
1106 * and each \ that precedes the ".
1108 backslash_count++;
1110 while(backslash_count) {
1111 *(command_line_i++) = '\\';
1112 backslash_count--;
1115 #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
1116 } else if (*p == '\\') {
1117 backslash_count++;
1118 } else {
1119 backslash_count = 0;
1120 #endif
1124 * Copy the character.
1126 *(command_line_i++) = *(p++);
1129 if (*enclose_in_quotes_i) {
1130 #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
1132 * Add one \ for each \ that precedes the
1133 * closing ".
1135 while(backslash_count--) {
1136 *(command_line_i++) = '\\';
1138 #endif
1139 *(command_line_i++) = '\"';
1143 * Append an intervening space.
1145 if (*(++argvi)) {
1146 *(command_line_i++) = ' ';
1149 enclose_in_quotes_i++;
1153 * Append the terminating NULL.
1155 *command_line_i = '\0';
1157 if (enclose_in_quotes) free(enclose_in_quotes);
1158 return command_line;
1162 * Description: Given an argv and optional envp, launch the process
1163 * using the default stdin, stdout, and stderr handles.
1164 * Also, register process so that process_wait_for_any_private()
1165 * can be used via process_file_io(NULL) or
1166 * process_wait_for_any().
1168 * Returns:
1170 * Notes/Dependencies:
1172 HANDLE
1173 process_easy(
1174 char **argv,
1175 char **envp)
1177 HANDLE hIn;
1178 HANDLE hOut;
1179 HANDLE hErr;
1180 HANDLE hProcess;
1182 if (proc_index >= MAXIMUM_WAIT_OBJECTS) {
1183 DB (DB_JOBS, ("process_easy: All process slots used up\n"));
1184 return INVALID_HANDLE_VALUE;
1186 if (DuplicateHandle(GetCurrentProcess(),
1187 GetStdHandle(STD_INPUT_HANDLE),
1188 GetCurrentProcess(),
1189 &hIn,
1191 TRUE,
1192 DUPLICATE_SAME_ACCESS) == FALSE) {
1193 fprintf(stderr,
1194 "process_easy: DuplicateHandle(In) failed (e=%ld)\n",
1195 GetLastError());
1196 return INVALID_HANDLE_VALUE;
1198 if (DuplicateHandle(GetCurrentProcess(),
1199 GetStdHandle(STD_OUTPUT_HANDLE),
1200 GetCurrentProcess(),
1201 &hOut,
1203 TRUE,
1204 DUPLICATE_SAME_ACCESS) == FALSE) {
1205 fprintf(stderr,
1206 "process_easy: DuplicateHandle(Out) failed (e=%ld)\n",
1207 GetLastError());
1208 return INVALID_HANDLE_VALUE;
1210 if (DuplicateHandle(GetCurrentProcess(),
1211 GetStdHandle(STD_ERROR_HANDLE),
1212 GetCurrentProcess(),
1213 &hErr,
1215 TRUE,
1216 DUPLICATE_SAME_ACCESS) == FALSE) {
1217 fprintf(stderr,
1218 "process_easy: DuplicateHandle(Err) failed (e=%ld)\n",
1219 GetLastError());
1220 return INVALID_HANDLE_VALUE;
1223 hProcess = process_init_fd(hIn, hOut, hErr);
1225 if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
1226 fake_exits_pending++;
1227 /* process_begin() failed: make a note of that. */
1228 if (!((sub_process*) hProcess)->last_err)
1229 ((sub_process*) hProcess)->last_err = -1;
1230 ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
1232 /* close up unused handles */
1233 CloseHandle(hIn);
1234 CloseHandle(hOut);
1235 CloseHandle(hErr);
1238 process_register(hProcess);
1240 return hProcess;