* Large file support for AIX, HP-UX, and IRIX.
[make.git] / w32 / subproc / sub_proc.c
blob1cf3beaf3de04dc54d069c133b933520d417f907
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <process.h> /* for msvc _beginthreadex, _endthreadex */
4 #include <windows.h>
6 #include "sub_proc.h"
7 #include "proc.h"
8 #include "w32err.h"
9 #include "config.h"
11 static char *make_command_line(char *shell_name, char *exec_path, char **argv);
13 extern int debug_flag; /* from make */
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[256];
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[256];
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 proc_array[proc_index++] = (sub_process *) proc;
127 * Public function which works kind of like waitpid(). Wait for any
128 * of the children to die and return results. To call this function,
129 * you must do 1 of things:
131 * x = process_easy(...);
133 * or
135 * x = process_init_fd();
136 * process_register(x);
138 * or
140 * x = process_init();
141 * process_register(x);
143 * You must NOT then call process_pipe_io() because this function is
144 * not capable of handling automatic notification of any child
145 * death.
148 HANDLE
149 process_wait_for_any(void)
151 sub_process* pproc = process_wait_for_any_private();
153 if (!pproc)
154 return NULL;
155 else {
157 * Ouch! can't tell caller if this fails directly. Caller
158 * will have to use process_last_err()
160 (void) process_file_io(pproc);
161 return ((HANDLE) pproc);
165 long
166 process_errno(HANDLE proc)
168 return (((sub_process *)proc)->lerrno);
171 long
172 process_signal(HANDLE proc)
174 return (((sub_process *)proc)->signal);
177 long
178 process_last_err(HANDLE proc)
180 return (((sub_process *)proc)->last_err);
183 long
184 process_exit_code(HANDLE proc)
186 return (((sub_process *)proc)->exit_code);
189 char *
190 process_outbuf(HANDLE proc)
192 return (((sub_process *)proc)->outp);
195 char *
196 process_errbuf(HANDLE proc)
198 return (((sub_process *)proc)->errp);
202 process_outcnt(HANDLE proc)
204 return (((sub_process *)proc)->outcnt);
208 process_errcnt(HANDLE proc)
210 return (((sub_process *)proc)->errcnt);
213 void
214 process_pipes(HANDLE proc, int pipes[3])
216 pipes[0] = ((sub_process *)proc)->sv_stdin[0];
217 pipes[1] = ((sub_process *)proc)->sv_stdout[0];
218 pipes[2] = ((sub_process *)proc)->sv_stderr[0];
219 return;
223 HANDLE
224 process_init()
226 sub_process *pproc;
228 * open file descriptors for attaching stdin/stdout/sterr
230 HANDLE stdin_pipes[2];
231 HANDLE stdout_pipes[2];
232 HANDLE stderr_pipes[2];
233 SECURITY_ATTRIBUTES inherit;
234 BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
236 pproc = malloc(sizeof(*pproc));
237 memset(pproc, 0, sizeof(*pproc));
239 /* We can't use NULL for lpSecurityDescriptor because that
240 uses the default security descriptor of the calling process.
241 Instead we use a security descriptor with no DACL. This
242 allows nonrestricted access to the associated objects. */
244 if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
245 SECURITY_DESCRIPTOR_REVISION)) {
246 pproc->last_err = GetLastError();
247 pproc->lerrno = E_SCALL;
248 return((HANDLE)pproc);
251 inherit.nLength = sizeof(inherit);
252 inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
253 inherit.bInheritHandle = TRUE;
255 // By convention, parent gets pipe[0], and child gets pipe[1]
256 // This means the READ side of stdin pipe goes into pipe[1]
257 // and the WRITE side of the stdout and stderr pipes go into pipe[1]
258 if (CreatePipe( &stdin_pipes[1], &stdin_pipes[0], &inherit, 0) == FALSE ||
259 CreatePipe( &stdout_pipes[0], &stdout_pipes[1], &inherit, 0) == FALSE ||
260 CreatePipe( &stderr_pipes[0], &stderr_pipes[1], &inherit, 0) == FALSE) {
262 pproc->last_err = GetLastError();
263 pproc->lerrno = E_SCALL;
264 return((HANDLE)pproc);
268 // Mark the parent sides of the pipes as non-inheritable
270 if (SetHandleInformation(stdin_pipes[0],
271 HANDLE_FLAG_INHERIT, 0) == FALSE ||
272 SetHandleInformation(stdout_pipes[0],
273 HANDLE_FLAG_INHERIT, 0) == FALSE ||
274 SetHandleInformation(stderr_pipes[0],
275 HANDLE_FLAG_INHERIT, 0) == FALSE) {
277 pproc->last_err = GetLastError();
278 pproc->lerrno = E_SCALL;
279 return((HANDLE)pproc);
281 pproc->sv_stdin[0] = (int) stdin_pipes[0];
282 pproc->sv_stdin[1] = (int) stdin_pipes[1];
283 pproc->sv_stdout[0] = (int) stdout_pipes[0];
284 pproc->sv_stdout[1] = (int) stdout_pipes[1];
285 pproc->sv_stderr[0] = (int) stderr_pipes[0];
286 pproc->sv_stderr[1] = (int) stderr_pipes[1];
288 pproc->using_pipes = 1;
290 pproc->lerrno = 0;
292 return((HANDLE)pproc);
296 HANDLE
297 process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
299 sub_process *pproc;
301 pproc = malloc(sizeof(*pproc));
302 memset(pproc, 0, sizeof(*pproc));
305 * Just pass the provided file handles to the 'child side' of the
306 * pipe, bypassing pipes altogether.
308 pproc->sv_stdin[1] = (int) stdinh;
309 pproc->sv_stdout[1] = (int) stdouth;
310 pproc->sv_stderr[1] = (int) stderrh;
312 pproc->last_err = pproc->lerrno = 0;
314 return((HANDLE)pproc);
318 static HANDLE
319 find_file(char *exec_path, LPOFSTRUCT file_info)
321 HANDLE exec_handle;
322 char *fname;
323 char *ext;
325 fname = malloc(strlen(exec_path) + 5);
326 strcpy(fname, exec_path);
327 ext = fname + strlen(fname);
329 strcpy(ext, ".exe");
330 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
331 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
332 free(fname);
333 return(exec_handle);
336 strcpy(ext, ".cmd");
337 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
338 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
339 free(fname);
340 return(exec_handle);
343 strcpy(ext, ".bat");
344 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
345 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
346 free(fname);
347 return(exec_handle);
350 /* should .com come before this case? */
351 if ((exec_handle = (HANDLE)OpenFile(exec_path, file_info,
352 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
353 free(fname);
354 return(exec_handle);
357 strcpy(ext, ".com");
358 if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
359 OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
360 free(fname);
361 return(exec_handle);
364 free(fname);
365 return(exec_handle);
370 * Description: Create the child process to be helped
372 * Returns:
374 * Notes/Dependencies:
376 long
377 process_begin(
378 HANDLE proc,
379 char **argv,
380 char **envp,
381 char *exec_path,
382 char *as_user)
384 sub_process *pproc = (sub_process *)proc;
385 char *shell_name = 0;
386 int file_not_found=0;
387 HANDLE exec_handle;
388 char buf[256];
389 DWORD bytes_returned;
390 DWORD flags;
391 char *command_line;
392 STARTUPINFO startInfo;
393 PROCESS_INFORMATION procInfo;
394 char *envblk=NULL;
395 OFSTRUCT file_info;
399 * Shell script detection... if the exec_path starts with #! then
400 * we want to exec shell-script-name exec-path, not just exec-path
401 * NT doesn't recognize #!/bin/sh or #!/etc/Tivoli/bin/perl. We do not
402 * hard-code the path to the shell or perl or whatever: Instead, we
403 * assume it's in the path somewhere (generally, the NT tools
404 * bin directory)
405 * We use OpenFile here because it is capable of searching the Path.
408 exec_handle = find_file(exec_path, &file_info);
411 * If we couldn't open the file, just assume that Windows32 will be able
412 * to find and execute it.
414 if (exec_handle == (HANDLE)HFILE_ERROR) {
415 file_not_found++;
417 else {
418 /* Attempt to read the first line of the file */
419 if (ReadFile( exec_handle,
420 buf, sizeof(buf) - 1, /* leave room for trailing NULL */
421 &bytes_returned, 0) == FALSE || bytes_returned < 2) {
423 pproc->last_err = GetLastError();
424 pproc->lerrno = E_IO;
425 CloseHandle(exec_handle);
426 return(-1);
428 if (buf[0] == '#' && buf[1] == '!') {
430 * This is a shell script... Change the command line from
431 * exec_path args to shell_name exec_path args
433 char *p;
435 /* Make sure buf is NULL terminated */
436 buf[bytes_returned] = 0;
438 * Depending on the file system type, etc. the first line
439 * of the shell script may end with newline or newline-carriage-return
440 * Whatever it ends with, cut it off.
442 p= strchr(buf, '\n');
443 if (p)
444 *p = 0;
445 p = strchr(buf, '\r');
446 if (p)
447 *p = 0;
450 * Find base name of shell
452 shell_name = strrchr( buf, '/');
453 if (shell_name) {
454 shell_name++;
455 } else {
456 shell_name = &buf[2];/* skipping "#!" */
460 CloseHandle(exec_handle);
463 flags = 0;
465 if (file_not_found)
466 command_line = make_command_line( shell_name, exec_path, argv);
467 else
468 command_line = make_command_line( shell_name, file_info.szPathName,
469 argv);
471 if ( command_line == NULL ) {
472 pproc->last_err = 0;
473 pproc->lerrno = E_NO_MEM;
474 return(-1);
477 if (envp) {
478 if (arr2envblk(envp, &envblk) ==FALSE) {
479 pproc->last_err = 0;
480 pproc->lerrno = E_NO_MEM;
481 free( command_line );
482 return(-1);
486 if ((shell_name) || (file_not_found)) {
487 exec_path = 0; /* Search for the program in %Path% */
488 } else {
489 exec_path = file_info.szPathName;
493 * Set up inherited stdin, stdout, stderr for child
495 GetStartupInfo(&startInfo);
496 startInfo.dwFlags = STARTF_USESTDHANDLES;
497 startInfo.lpReserved = 0;
498 startInfo.cbReserved2 = 0;
499 startInfo.lpReserved2 = 0;
500 startInfo.lpTitle = shell_name ? shell_name : exec_path;
501 startInfo.hStdInput = (HANDLE)pproc->sv_stdin[1];
502 startInfo.hStdOutput = (HANDLE)pproc->sv_stdout[1];
503 startInfo.hStdError = (HANDLE)pproc->sv_stderr[1];
505 if (as_user) {
506 if (envblk) free(envblk);
507 return -1;
508 } else {
509 if (debug_flag)
510 printf("CreateProcess(%s,%s,...)\n",
511 exec_path ? exec_path : "NULL",
512 command_line ? command_line : "NULL");
513 if (CreateProcess(
514 exec_path,
515 command_line,
516 NULL,
517 0, /* default security attributes for thread */
518 TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
519 flags,
520 envblk,
521 0, /* default starting directory */
522 &startInfo,
523 &procInfo) == FALSE) {
525 pproc->last_err = GetLastError();
526 pproc->lerrno = E_FORK;
527 fprintf(stderr, "process_begin: CreateProcess(%s, %s, ...) failed.\n", exec_path, command_line);
528 if (envblk) free(envblk);
529 free( command_line );
530 return(-1);
534 pproc->pid = (int)procInfo.hProcess;
535 /* Close the thread handle -- we'll just watch the process */
536 CloseHandle(procInfo.hThread);
538 /* Close the halves of the pipes we don't need */
539 if (pproc->sv_stdin) {
540 CloseHandle((HANDLE)pproc->sv_stdin[1]);
541 (HANDLE)pproc->sv_stdin[1] = 0;
543 if (pproc->sv_stdout) {
544 CloseHandle((HANDLE)pproc->sv_stdout[1]);
545 (HANDLE)pproc->sv_stdout[1] = 0;
547 if (pproc->sv_stderr) {
548 CloseHandle((HANDLE)pproc->sv_stderr[1]);
549 (HANDLE)pproc->sv_stderr[1] = 0;
552 free( command_line );
553 if (envblk) free(envblk);
554 pproc->lerrno=0;
555 return 0;
560 static DWORD
561 proc_stdin_thread(sub_process *pproc)
563 DWORD in_done;
564 for (;;) {
565 if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
566 &in_done, NULL) == FALSE)
567 _endthreadex(0);
568 // This if should never be true for anonymous pipes, but gives
569 // us a chance to change I/O mechanisms later
570 if (in_done < pproc->incnt) {
571 pproc->incnt -= in_done;
572 pproc->inp += in_done;
573 } else {
574 _endthreadex(0);
577 return 0; // for compiler warnings only.. not reached
580 static DWORD
581 proc_stdout_thread(sub_process *pproc)
583 DWORD bufsize = 1024;
584 char c;
585 DWORD nread;
586 pproc->outp = malloc(bufsize);
587 if (pproc->outp == NULL)
588 _endthreadex(0);
589 pproc->outcnt = 0;
591 for (;;) {
592 if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
593 == FALSE) {
594 /* map_windows32_error_to_string(GetLastError());*/
595 _endthreadex(0);
597 if (nread == 0)
598 _endthreadex(0);
599 if (pproc->outcnt + nread > bufsize) {
600 bufsize += nread + 512;
601 pproc->outp = realloc(pproc->outp, bufsize);
602 if (pproc->outp == NULL) {
603 pproc->outcnt = 0;
604 _endthreadex(0);
607 pproc->outp[pproc->outcnt++] = c;
609 return 0;
612 static DWORD
613 proc_stderr_thread(sub_process *pproc)
615 DWORD bufsize = 1024;
616 char c;
617 DWORD nread;
618 pproc->errp = malloc(bufsize);
619 if (pproc->errp == NULL)
620 _endthreadex(0);
621 pproc->errcnt = 0;
623 for (;;) {
624 if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
625 map_windows32_error_to_string(GetLastError());
626 _endthreadex(0);
628 if (nread == 0)
629 _endthreadex(0);
630 if (pproc->errcnt + nread > bufsize) {
631 bufsize += nread + 512;
632 pproc->errp = realloc(pproc->errp, bufsize);
633 if (pproc->errp == NULL) {
634 pproc->errcnt = 0;
635 _endthreadex(0);
638 pproc->errp[pproc->errcnt++] = c;
640 return 0;
645 * Purpose: collects output from child process and returns results
647 * Description:
649 * Returns:
651 * Notes/Dependencies:
653 long
654 process_pipe_io(
655 HANDLE proc,
656 char *stdin_data,
657 int stdin_data_len)
659 sub_process *pproc = (sub_process *)proc;
660 bool_t stdin_eof = FALSE, stdout_eof = FALSE, stderr_eof = FALSE;
661 HANDLE childhand = (HANDLE) pproc->pid;
662 HANDLE tStdin, tStdout, tStderr;
663 DWORD dwStdin, dwStdout, dwStderr;
664 HANDLE wait_list[4];
665 DWORD wait_count;
666 DWORD wait_return;
667 HANDLE ready_hand;
668 bool_t child_dead = FALSE;
672 * Create stdin thread, if needed
674 pproc->inp = stdin_data;
675 pproc->incnt = stdin_data_len;
676 if (!pproc->inp) {
677 stdin_eof = TRUE;
678 CloseHandle((HANDLE)pproc->sv_stdin[0]);
679 (HANDLE)pproc->sv_stdin[0] = 0;
680 } else {
681 tStdin = (HANDLE) _beginthreadex( 0, 1024,
682 (unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0,
683 (unsigned int *) &dwStdin);
684 if (tStdin == 0) {
685 pproc->last_err = GetLastError();
686 pproc->lerrno = E_SCALL;
687 goto done;
692 * Assume child will produce stdout and stderr
694 tStdout = (HANDLE) _beginthreadex( 0, 1024,
695 (unsigned (__stdcall *) (void *))proc_stdout_thread, pproc, 0,
696 (unsigned int *) &dwStdout);
697 tStderr = (HANDLE) _beginthreadex( 0, 1024,
698 (unsigned (__stdcall *) (void *))proc_stderr_thread, pproc, 0,
699 (unsigned int *) &dwStderr);
701 if (tStdout == 0 || tStderr == 0) {
703 pproc->last_err = GetLastError();
704 pproc->lerrno = E_SCALL;
705 goto done;
710 * Wait for all I/O to finish and for the child process to exit
713 while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
714 wait_count = 0;
715 if (!stdin_eof) {
716 wait_list[wait_count++] = tStdin;
718 if (!stdout_eof) {
719 wait_list[wait_count++] = tStdout;
721 if (!stderr_eof) {
722 wait_list[wait_count++] = tStderr;
724 if (!child_dead) {
725 wait_list[wait_count++] = childhand;
728 wait_return = WaitForMultipleObjects(wait_count, wait_list,
729 FALSE, /* don't wait for all: one ready will do */
730 child_dead? 1000 :INFINITE); /* after the child dies, subthreads have
731 one second to collect all remaining output */
733 if (wait_return == WAIT_FAILED) {
734 /* map_windows32_error_to_string(GetLastError());*/
735 pproc->last_err = GetLastError();
736 pproc->lerrno = E_SCALL;
737 goto done;
740 ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
742 if (ready_hand == tStdin) {
743 CloseHandle((HANDLE)pproc->sv_stdin[0]);
744 (HANDLE)pproc->sv_stdin[0] = 0;
745 CloseHandle(tStdin);
746 tStdin = 0;
747 stdin_eof = TRUE;
749 } else if (ready_hand == tStdout) {
751 CloseHandle((HANDLE)pproc->sv_stdout[0]);
752 (HANDLE)pproc->sv_stdout[0] = 0;
753 CloseHandle(tStdout);
754 tStdout = 0;
755 stdout_eof = TRUE;
757 } else if (ready_hand == tStderr) {
759 CloseHandle((HANDLE)pproc->sv_stderr[0]);
760 (HANDLE)pproc->sv_stderr[0] = 0;
761 CloseHandle(tStderr);
762 tStderr = 0;
763 stderr_eof = TRUE;
765 } else if (ready_hand == childhand) {
767 if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
768 pproc->last_err = GetLastError();
769 pproc->lerrno = E_SCALL;
770 goto done;
772 child_dead = TRUE;
774 } else {
776 /* ?? Got back a handle we didn't query ?? */
777 pproc->last_err = 0;
778 pproc->lerrno = E_FAIL;
779 goto done;
783 done:
784 if (tStdin != 0)
785 CloseHandle(tStdin);
786 if (tStdout != 0)
787 CloseHandle(tStdout);
788 if (tStderr != 0)
789 CloseHandle(tStderr);
791 if (pproc->lerrno)
792 return(-1);
793 else
794 return(0);
799 * Purpose: collects output from child process and returns results
801 * Description:
803 * Returns:
805 * Notes/Dependencies:
807 long
808 process_file_io(
809 HANDLE proc)
811 sub_process *pproc;
812 HANDLE childhand;
813 DWORD wait_return;
815 if (proc == NULL)
816 pproc = process_wait_for_any_private();
817 else
818 pproc = (sub_process *)proc;
820 /* some sort of internal error */
821 if (!pproc)
822 return -1;
824 childhand = (HANDLE) pproc->pid;
827 * This function is poorly named, and could also be used just to wait
828 * for child death if you're doing your own pipe I/O. If that is
829 * the case, close the pipe handles here.
831 if (pproc->sv_stdin[0]) {
832 CloseHandle((HANDLE)pproc->sv_stdin[0]);
833 pproc->sv_stdin[0] = 0;
835 if (pproc->sv_stdout[0]) {
836 CloseHandle((HANDLE)pproc->sv_stdout[0]);
837 pproc->sv_stdout[0] = 0;
839 if (pproc->sv_stderr[0]) {
840 CloseHandle((HANDLE)pproc->sv_stderr[0]);
841 pproc->sv_stderr[0] = 0;
845 * Wait for the child process to exit
848 wait_return = WaitForSingleObject(childhand, INFINITE);
850 if (wait_return != WAIT_OBJECT_0) {
851 /* map_windows32_error_to_string(GetLastError());*/
852 pproc->last_err = GetLastError();
853 pproc->lerrno = E_SCALL;
854 goto done2;
857 if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
858 pproc->last_err = GetLastError();
859 pproc->lerrno = E_SCALL;
862 done2:
863 if (pproc->lerrno)
864 return(-1);
865 else
866 return(0);
871 * Description: Clean up any leftover handles, etc. It is up to the
872 * caller to manage and free the input, ouput, and stderr buffers.
874 void
875 process_cleanup(
876 HANDLE proc)
878 sub_process *pproc = (sub_process *)proc;
879 int i;
881 if (pproc->using_pipes) {
882 for (i= 0; i <= 1; i++) {
883 if ((HANDLE)pproc->sv_stdin[i])
884 CloseHandle((HANDLE)pproc->sv_stdin[i]);
885 if ((HANDLE)pproc->sv_stdout[i])
886 CloseHandle((HANDLE)pproc->sv_stdout[i]);
887 if ((HANDLE)pproc->sv_stderr[i])
888 CloseHandle((HANDLE)pproc->sv_stderr[i]);
891 if ((HANDLE)pproc->pid)
892 CloseHandle((HANDLE)pproc->pid);
894 free(pproc);
899 * Description:
900 * Create a command line buffer to pass to CreateProcess
902 * Returns: the buffer or NULL for failure
903 * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
904 * Otherwise: argv[0] argv[1] argv[2] ...
906 * Notes/Dependencies:
907 * CreateProcess does not take an argv, so this command creates a
908 * command line for the executable.
911 static char *
912 make_command_line( char *shell_name, char *full_exec_path, char **argv)
914 int argc = 0;
915 char** argvi;
916 int* enclose_in_quotes = NULL;
917 int* enclose_in_quotes_i;
918 unsigned int bytes_required = 0;
919 char* command_line;
920 char* command_line_i;
921 int cygwin_mode = 0; /* HAVE_CYGWIN_SHELL */
922 int have_sh = 0; /* HAVE_CYGWIN_SHELL */
924 #ifdef HAVE_CYGWIN_SHELL
925 have_sh = (shell_name != NULL || strstr(full_exec_path, "sh.exe"));
926 cygwin_mode = 1;
927 #endif
929 if (shell_name && full_exec_path) {
930 bytes_required
931 = strlen(shell_name) + 1 + strlen(full_exec_path);
933 * Skip argv[0] if any, when shell_name is given.
935 if (*argv) argv++;
937 * Add one for the intervening space.
939 if (*argv) bytes_required++;
942 argvi = argv;
943 while (*(argvi++)) argc++;
945 if (argc) {
946 enclose_in_quotes = (int*) calloc(1, argc * sizeof(int));
948 if (!enclose_in_quotes) {
949 return NULL;
953 /* We have to make one pass through each argv[i] to see if we need
954 * to enclose it in ", so we might as well figure out how much
955 * memory we'll need on the same pass.
958 argvi = argv;
959 enclose_in_quotes_i = enclose_in_quotes;
960 while(*argvi) {
961 char* p = *argvi;
962 unsigned int backslash_count = 0;
965 * We have to enclose empty arguments in ".
967 if (!(*p)) *enclose_in_quotes_i = 1;
969 while(*p) {
970 switch (*p) {
971 case '\"':
973 * We have to insert a backslash for each "
974 * and each \ that precedes the ".
976 bytes_required += (backslash_count + 1);
977 backslash_count = 0;
978 break;
980 #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
981 case '\\':
982 backslash_count++;
983 break;
984 #endif
986 * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress
987 * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so
988 * that argv in always equals argv out. This was removed. Say you have
989 * such a program named glob.exe. You enter
990 * glob '*'
991 * at the sh command prompt. Obviously the intent is to make glob do the
992 * wildcarding instead of sh. If we set *enclose_in_quotes_i for '*' or '?',
993 * then the command line that glob would see would be
994 * glob "*"
995 * and the _setargv in SETARGV.OBJ would _not_ expand the *.
997 case ' ':
998 case '\t':
999 *enclose_in_quotes_i = 1;
1000 /* fall through */
1002 default:
1003 backslash_count = 0;
1004 break;
1008 * Add one for each character in argv[i].
1010 bytes_required++;
1012 p++;
1015 if (*enclose_in_quotes_i) {
1017 * Add one for each enclosing ",
1018 * and one for each \ that precedes the
1019 * closing ".
1021 bytes_required += (backslash_count + 2);
1025 * Add one for the intervening space.
1027 if (*(++argvi)) bytes_required++;
1028 enclose_in_quotes_i++;
1032 * Add one for the terminating NULL.
1034 bytes_required++;
1036 command_line = (char*) malloc(bytes_required);
1038 if (!command_line) {
1039 if (enclose_in_quotes) free(enclose_in_quotes);
1040 return NULL;
1043 command_line_i = command_line;
1045 if (shell_name && full_exec_path) {
1046 while(*shell_name) {
1047 *(command_line_i++) = *(shell_name++);
1050 *(command_line_i++) = ' ';
1052 while(*full_exec_path) {
1053 *(command_line_i++) = *(full_exec_path++);
1056 if (*argv) {
1057 *(command_line_i++) = ' ';
1061 argvi = argv;
1062 enclose_in_quotes_i = enclose_in_quotes;
1064 while(*argvi) {
1065 char* p = *argvi;
1066 unsigned int backslash_count = 0;
1068 if (*enclose_in_quotes_i) {
1069 *(command_line_i++) = '\"';
1072 while(*p) {
1073 if (*p == '\"') {
1074 if (cygwin_mode && have_sh) { /* HAVE_CYGWIN_SHELL */
1075 /* instead of a \", cygwin likes "" */
1076 *(command_line_i++) = '\"';
1077 } else {
1080 * We have to insert a backslash for the "
1081 * and each \ that precedes the ".
1083 backslash_count++;
1085 while(backslash_count) {
1086 *(command_line_i++) = '\\';
1087 backslash_count--;
1090 #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
1091 } else if (*p == '\\') {
1092 backslash_count++;
1093 } else {
1094 backslash_count = 0;
1095 #endif
1099 * Copy the character.
1101 *(command_line_i++) = *(p++);
1104 if (*enclose_in_quotes_i) {
1105 #if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
1107 * Add one \ for each \ that precedes the
1108 * closing ".
1110 while(backslash_count--) {
1111 *(command_line_i++) = '\\';
1113 #endif
1114 *(command_line_i++) = '\"';
1118 * Append an intervening space.
1120 if (*(++argvi)) {
1121 *(command_line_i++) = ' ';
1124 enclose_in_quotes_i++;
1128 * Append the terminating NULL.
1130 *command_line_i = '\0';
1132 if (enclose_in_quotes) free(enclose_in_quotes);
1133 return command_line;
1137 * Description: Given an argv and optional envp, launch the process
1138 * using the default stdin, stdout, and stderr handles.
1139 * Also, register process so that process_wait_for_any_private()
1140 * can be used via process_file_io(NULL) or
1141 * process_wait_for_any().
1143 * Returns:
1145 * Notes/Dependencies:
1147 HANDLE
1148 process_easy(
1149 char **argv,
1150 char **envp)
1152 HANDLE hIn;
1153 HANDLE hOut;
1154 HANDLE hErr;
1155 HANDLE hProcess;
1157 if (DuplicateHandle(GetCurrentProcess(),
1158 GetStdHandle(STD_INPUT_HANDLE),
1159 GetCurrentProcess(),
1160 &hIn,
1162 TRUE,
1163 DUPLICATE_SAME_ACCESS) == FALSE) {
1164 fprintf(stderr,
1165 "process_easy: DuplicateHandle(In) failed (e=%d)\n",
1166 GetLastError());
1167 return INVALID_HANDLE_VALUE;
1169 if (DuplicateHandle(GetCurrentProcess(),
1170 GetStdHandle(STD_OUTPUT_HANDLE),
1171 GetCurrentProcess(),
1172 &hOut,
1174 TRUE,
1175 DUPLICATE_SAME_ACCESS) == FALSE) {
1176 fprintf(stderr,
1177 "process_easy: DuplicateHandle(Out) failed (e=%d)\n",
1178 GetLastError());
1179 return INVALID_HANDLE_VALUE;
1181 if (DuplicateHandle(GetCurrentProcess(),
1182 GetStdHandle(STD_ERROR_HANDLE),
1183 GetCurrentProcess(),
1184 &hErr,
1186 TRUE,
1187 DUPLICATE_SAME_ACCESS) == FALSE) {
1188 fprintf(stderr,
1189 "process_easy: DuplicateHandle(Err) failed (e=%d)\n",
1190 GetLastError());
1191 return INVALID_HANDLE_VALUE;
1194 hProcess = process_init_fd(hIn, hOut, hErr);
1196 if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
1197 fake_exits_pending++;
1198 ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
1200 /* close up unused handles */
1201 CloseHandle(hIn);
1202 CloseHandle(hOut);
1203 CloseHandle(hErr);
1206 process_register(hProcess);
1208 return hProcess;