3
#include <process.h> /* for msvc _beginthreadex, _endthreadex */
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 {
23
volatile DWORD outcnt;
25
volatile DWORD errcnt;
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
43
process_adjust_wait_state(sub_process* pproc)
50
for (i = 0; i < proc_index; i++)
51
if (proc_array[i]->pid == pproc->pid)
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.
67
process_wait_for_any_private(void)
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)
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;
90
retval = !WAIT_FAILED;
94
/* return pointer to process */
95
if (retval != WAIT_FAILED) {
96
sub_process* pproc = proc_array[which];
97
process_adjust_wait_state(pproc);
104
* Terminate a process.
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 :-(
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(...);
135
* x = process_init_fd();
136
* process_register(x);
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
149
process_wait_for_any(void)
151
sub_process* pproc = process_wait_for_any_private();
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);
166
process_errno(HANDLE proc)
168
return (((sub_process *)proc)->lerrno);
172
process_signal(HANDLE proc)
174
return (((sub_process *)proc)->signal);
178
process_last_err(HANDLE proc)
180
return (((sub_process *)proc)->last_err);
184
process_exit_code(HANDLE proc)
186
return (((sub_process *)proc)->exit_code);
190
process_outbuf(HANDLE proc)
192
return (((sub_process *)proc)->outp);
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);
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];
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;
292
return((HANDLE)pproc);
297
process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
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);
319
find_file(char *exec_path, LPOFSTRUCT file_info)
325
fname = malloc(strlen(exec_path) + 5);
326
strcpy(fname, exec_path);
327
ext = fname + strlen(fname);
330
if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
331
OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
337
if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
338
OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
344
if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
345
OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
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) {
358
if ((exec_handle = (HANDLE)OpenFile(fname, file_info,
359
OF_READ | OF_SHARE_COMPAT)) != (HANDLE)HFILE_ERROR) {
370
* Description: Create the child process to be helped
374
* Notes/Dependencies:
384
sub_process *pproc = (sub_process *)proc;
385
char *shell_name = 0;
386
int file_not_found=0;
389
DWORD bytes_returned;
392
STARTUPINFO startInfo;
393
PROCESS_INFORMATION procInfo;
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
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) {
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);
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
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');
445
p = strchr(buf, '\r');
450
* Find base name of shell
452
shell_name = strrchr( buf, '/');
456
shell_name = &buf[2];/* skipping "#!" */
460
CloseHandle(exec_handle);
466
command_line = make_command_line( shell_name, exec_path, argv);
468
command_line = make_command_line( shell_name, file_info.szPathName,
471
if ( command_line == NULL ) {
473
pproc->lerrno = E_NO_MEM;
478
if (arr2envblk(envp, &envblk) ==FALSE) {
480
pproc->lerrno = E_NO_MEM;
481
free( command_line );
486
if ((shell_name) || (file_not_found)) {
487
exec_path = 0; /* Search for the program in %Path% */
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];
506
if (envblk) free(envblk);
510
printf("CreateProcess(%s,%s,...)\n",
511
exec_path ? exec_path : "NULL",
512
command_line ? command_line : "NULL");
517
0, /* default security attributes for thread */
518
TRUE, /* inherit handles (e.g. helper pipes, oserv socket) */
521
0, /* default starting directory */
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 );
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);
561
proc_stdin_thread(sub_process *pproc)
565
if (WriteFile( (HANDLE) pproc->sv_stdin[0], pproc->inp, pproc->incnt,
566
&in_done, NULL) == FALSE)
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;
577
return 0; // for compiler warnings only.. not reached
581
proc_stdout_thread(sub_process *pproc)
583
DWORD bufsize = 1024;
586
pproc->outp = malloc(bufsize);
587
if (pproc->outp == NULL)
592
if (ReadFile( (HANDLE)pproc->sv_stdout[0], &c, 1, &nread, NULL)
594
/* map_windows32_error_to_string(GetLastError());*/
599
if (pproc->outcnt + nread > bufsize) {
600
bufsize += nread + 512;
601
pproc->outp = realloc(pproc->outp, bufsize);
602
if (pproc->outp == NULL) {
607
pproc->outp[pproc->outcnt++] = c;
613
proc_stderr_thread(sub_process *pproc)
615
DWORD bufsize = 1024;
618
pproc->errp = malloc(bufsize);
619
if (pproc->errp == NULL)
624
if (ReadFile( (HANDLE)pproc->sv_stderr[0], &c, 1, &nread, NULL) == FALSE) {
625
map_windows32_error_to_string(GetLastError());
630
if (pproc->errcnt + nread > bufsize) {
631
bufsize += nread + 512;
632
pproc->errp = realloc(pproc->errp, bufsize);
633
if (pproc->errp == NULL) {
638
pproc->errp[pproc->errcnt++] = c;
645
* Purpose: collects output from child process and returns results
651
* Notes/Dependencies:
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;
668
bool_t child_dead = FALSE;
672
* Create stdin thread, if needed
674
pproc->inp = stdin_data;
675
pproc->incnt = stdin_data_len;
678
CloseHandle((HANDLE)pproc->sv_stdin[0]);
679
(HANDLE)pproc->sv_stdin[0] = 0;
681
tStdin = (HANDLE) _beginthreadex( 0, 1024,
682
(unsigned (__stdcall *) (void *))proc_stdin_thread, pproc, 0,
683
(unsigned int *) &dwStdin);
685
pproc->last_err = GetLastError();
686
pproc->lerrno = E_SCALL;
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;
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) {
716
wait_list[wait_count++] = tStdin;
719
wait_list[wait_count++] = tStdout;
722
wait_list[wait_count++] = tStderr;
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;
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;
749
} else if (ready_hand == tStdout) {
751
CloseHandle((HANDLE)pproc->sv_stdout[0]);
752
(HANDLE)pproc->sv_stdout[0] = 0;
753
CloseHandle(tStdout);
757
} else if (ready_hand == tStderr) {
759
CloseHandle((HANDLE)pproc->sv_stderr[0]);
760
(HANDLE)pproc->sv_stderr[0] = 0;
761
CloseHandle(tStderr);
765
} else if (ready_hand == childhand) {
767
if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
768
pproc->last_err = GetLastError();
769
pproc->lerrno = E_SCALL;
776
/* ?? Got back a handle we didn't query ?? */
778
pproc->lerrno = E_FAIL;
787
CloseHandle(tStdout);
789
CloseHandle(tStderr);
799
* Purpose: collects output from child process and returns results
805
* Notes/Dependencies:
816
pproc = process_wait_for_any_private();
818
pproc = (sub_process *)proc;
820
/* some sort of internal error */
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;
857
if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
858
pproc->last_err = GetLastError();
859
pproc->lerrno = E_SCALL;
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.
878
sub_process *pproc = (sub_process *)proc;
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);
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.
912
make_command_line( char *shell_name, char *full_exec_path, char **argv)
916
int* enclose_in_quotes = NULL;
917
int* enclose_in_quotes_i;
918
unsigned int bytes_required = 0;
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"));
929
if (shell_name && full_exec_path) {
931
= strlen(shell_name) + 1 + strlen(full_exec_path);
933
* Skip argv[0] if any, when shell_name is given.
937
* Add one for the intervening space.
939
if (*argv) bytes_required++;
943
while (*(argvi++)) argc++;
946
enclose_in_quotes = (int*) calloc(1, argc * sizeof(int));
948
if (!enclose_in_quotes) {
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.
959
enclose_in_quotes_i = enclose_in_quotes;
962
unsigned int backslash_count = 0;
965
* We have to enclose empty arguments in ".
967
if (!(*p)) *enclose_in_quotes_i = 1;
973
* We have to insert a backslash for each "
974
* and each \ that precedes the ".
976
bytes_required += (backslash_count + 1);
980
#if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
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
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
995
* and the _setargv in SETARGV.OBJ would _not_ expand the *.
999
*enclose_in_quotes_i = 1;
1003
backslash_count = 0;
1008
* Add one for each character in argv[i].
1015
if (*enclose_in_quotes_i) {
1017
* Add one for each enclosing ",
1018
* and one for each \ that precedes the
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.
1036
command_line = (char*) malloc(bytes_required);
1038
if (!command_line) {
1039
if (enclose_in_quotes) free(enclose_in_quotes);
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++);
1057
*(command_line_i++) = ' ';
1062
enclose_in_quotes_i = enclose_in_quotes;
1066
unsigned int backslash_count = 0;
1068
if (*enclose_in_quotes_i) {
1069
*(command_line_i++) = '\"';
1074
if (cygwin_mode && have_sh) { /* HAVE_CYGWIN_SHELL */
1075
/* instead of a \", cygwin likes "" */
1076
*(command_line_i++) = '\"';
1080
* We have to insert a backslash for the "
1081
* and each \ that precedes the ".
1085
while(backslash_count) {
1086
*(command_line_i++) = '\\';
1090
#if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
1091
} else if (*p == '\\') {
1094
backslash_count = 0;
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
1110
while(backslash_count--) {
1111
*(command_line_i++) = '\\';
1114
*(command_line_i++) = '\"';
1118
* Append an intervening space.
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().
1145
* Notes/Dependencies:
1157
if (DuplicateHandle(GetCurrentProcess(),
1158
GetStdHandle(STD_INPUT_HANDLE),
1159
GetCurrentProcess(),
1163
DUPLICATE_SAME_ACCESS) == FALSE) {
1165
"process_easy: DuplicateHandle(In) failed (e=%d)\n",
1167
return INVALID_HANDLE_VALUE;
1169
if (DuplicateHandle(GetCurrentProcess(),
1170
GetStdHandle(STD_OUTPUT_HANDLE),
1171
GetCurrentProcess(),
1175
DUPLICATE_SAME_ACCESS) == FALSE) {
1177
"process_easy: DuplicateHandle(Out) failed (e=%d)\n",
1179
return INVALID_HANDLE_VALUE;
1181
if (DuplicateHandle(GetCurrentProcess(),
1182
GetStdHandle(STD_ERROR_HANDLE),
1183
GetCurrentProcess(),
1187
DUPLICATE_SAME_ACCESS) == FALSE) {
1189
"process_easy: DuplicateHandle(Err) failed (e=%d)\n",
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 */
1206
process_register(hProcess);