~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/3rdparty/qmake/w32/subproc/sub_proc.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdlib.h>
 
2
#include <stdio.h>
 
3
#include <process.h>  /* for msvc _beginthreadex, _endthreadex */
 
4
#include <windows.h>
 
5
 
 
6
#include "sub_proc.h"
 
7
#include "proc.h"
 
8
#include "w32err.h"
 
9
#include "config.h"
 
10
 
 
11
static char *make_command_line(char *shell_name, char *exec_path, char **argv);
 
12
 
 
13
extern int debug_flag; /* from make */
 
14
 
 
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;
 
32
 
 
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;
 
37
 
 
38
/*
 
39
 * When a process has been waited for, adjust the wait state
 
40
 * array so that we don't wait for it again
 
41
 */
 
42
static void
 
43
process_adjust_wait_state(sub_process* pproc)
 
44
{
 
45
        int i;
 
46
 
 
47
        if (!proc_index)
 
48
                return;
 
49
 
 
50
        for (i = 0; i < proc_index; i++)
 
51
                if (proc_array[i]->pid == pproc->pid)
 
52
                        break;
 
53
 
 
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;
 
60
        }
 
61
}
 
62
 
 
63
/*
 
64
 * Waits for any of the registered child processes to finish.
 
65
 */
 
66
static sub_process *
 
67
process_wait_for_any_private(void)
 
68
{
 
69
        HANDLE handles[256];
 
70
        DWORD retval, which;
 
71
        int i;
 
72
 
 
73
        if (!proc_index)
 
74
                return NULL;
 
75
 
 
76
        /* build array of handles to wait for */
 
77
        for (i = 0; i < proc_index; i++) {
 
78
                handles[i] = (HANDLE) proc_array[i]->pid;
 
79
 
 
80
                if (fake_exits_pending && proc_array[i]->exit_code)
 
81
                        break;
 
82
        }
 
83
 
 
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;
 
92
        }
 
93
 
 
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;
 
101
}
 
102
 
 
103
/*
 
104
 * Terminate a process.
 
105
 */
 
106
BOOL
 
107
process_kill(HANDLE proc, int signal)
 
108
{
 
109
        sub_process* pproc = (sub_process*) proc;
 
110
        pproc->signal = signal;
 
111
        return (TerminateProcess((HANDLE) pproc->pid, signal));
 
112
}
 
113
 
 
114
/*
 
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 :-(
 
119
 */
 
120
void
 
121
process_register(HANDLE proc)
 
122
{
 
123
        proc_array[proc_index++] = (sub_process *) proc;
 
124
}
 
125
 
 
126
/*
 
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:
 
130
 *
 
131
 *      x = process_easy(...);
 
132
 *
 
133
 * or
 
134
 *
 
135
 *      x = process_init_fd();
 
136
 *      process_register(x);
 
137
 *
 
138
 * or
 
139
 *
 
140
 *      x = process_init();
 
141
 *      process_register(x);
 
142
 *
 
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.
 
146
 */
 
147
 
 
148
HANDLE
 
149
process_wait_for_any(void)
 
150
{
 
151
        sub_process* pproc = process_wait_for_any_private();
 
152
 
 
153
        if (!pproc)
 
154
                return NULL;
 
155
        else {
 
156
                /*
 
157
                 * Ouch! can't tell caller if this fails directly. Caller
 
158
                 * will have to use process_last_err()
 
159
                 */
 
160
                (void) process_file_io(pproc);
 
161
                return ((HANDLE) pproc);
 
162
        }
 
163
}
 
164
 
 
165
long
 
166
process_errno(HANDLE proc)
 
167
{
 
168
        return (((sub_process *)proc)->lerrno);
 
169
}
 
170
 
 
171
long
 
172
process_signal(HANDLE proc)
 
173
{
 
174
        return (((sub_process *)proc)->signal);
 
175
}
 
176
 
 
177
        long
 
178
process_last_err(HANDLE proc)
 
179
{
 
180
        return (((sub_process *)proc)->last_err);
 
181
}
 
182
 
 
183
        long
 
184
process_exit_code(HANDLE proc)
 
185
{
 
186
        return (((sub_process *)proc)->exit_code);
 
187
}
 
188
 
 
189
        char *
 
190
process_outbuf(HANDLE proc)
 
191
{
 
192
        return (((sub_process *)proc)->outp);
 
193
}
 
194
 
 
195
        char *
 
196
process_errbuf(HANDLE proc)
 
197
{
 
198
        return (((sub_process *)proc)->errp);
 
199
}
 
200
 
 
201
        int
 
202
process_outcnt(HANDLE proc)
 
203
{
 
204
        return (((sub_process *)proc)->outcnt);
 
205
}
 
206
 
 
207
        int
 
208
process_errcnt(HANDLE proc)
 
209
{
 
210
        return (((sub_process *)proc)->errcnt);
 
211
}
 
212
 
 
213
        void
 
214
process_pipes(HANDLE proc, int pipes[3])
 
215
{
 
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;
 
220
}
 
221
 
 
222
 
 
223
        HANDLE
 
224
process_init()
 
225
{
 
226
        sub_process *pproc;
 
227
        /*
 
228
         * open file descriptors for attaching stdin/stdout/sterr
 
229
         */
 
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];
 
235
 
 
236
        pproc = malloc(sizeof(*pproc));
 
237
        memset(pproc, 0, sizeof(*pproc));
 
238
 
 
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. */
 
243
 
 
244
        if (!InitializeSecurityDescriptor((PSECURITY_DESCRIPTOR)(&sd),
 
245
                                          SECURITY_DESCRIPTOR_REVISION)) {
 
246
                pproc->last_err = GetLastError();
 
247
                pproc->lerrno = E_SCALL;
 
248
                return((HANDLE)pproc);
 
249
        }
 
250
 
 
251
        inherit.nLength = sizeof(inherit);
 
252
        inherit.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&sd);
 
253
        inherit.bInheritHandle = TRUE;
 
254
 
 
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) {
 
261
 
 
262
                pproc->last_err = GetLastError();
 
263
                pproc->lerrno = E_SCALL;
 
264
                return((HANDLE)pproc);
 
265
        }
 
266
 
 
267
        //
 
268
        // Mark the parent sides of the pipes as non-inheritable
 
269
        //
 
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) {
 
276
 
 
277
                pproc->last_err = GetLastError();
 
278
                pproc->lerrno = E_SCALL;
 
279
                return((HANDLE)pproc);
 
280
        }
 
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];
 
287
 
 
288
        pproc->using_pipes = 1;
 
289
 
 
290
        pproc->lerrno = 0;
 
291
 
 
292
        return((HANDLE)pproc);
 
293
}
 
294
 
 
295
 
 
296
        HANDLE
 
297
process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
 
298
{
 
299
        sub_process *pproc;
 
300
 
 
301
        pproc = malloc(sizeof(*pproc));
 
302
        memset(pproc, 0, sizeof(*pproc));
 
303
 
 
304
        /*
 
305
         * Just pass the provided file handles to the 'child side' of the
 
306
         * pipe, bypassing pipes altogether.
 
307
         */
 
308
        pproc->sv_stdin[1]  = (int) stdinh;
 
309
        pproc->sv_stdout[1] = (int) stdouth;
 
310
        pproc->sv_stderr[1] = (int) stderrh;
 
311
 
 
312
        pproc->last_err = pproc->lerrno = 0;
 
313
 
 
314
        return((HANDLE)pproc);
 
315
}
 
316
 
 
317
 
 
318
static HANDLE
 
319
find_file(char *exec_path, LPOFSTRUCT file_info)
 
320
{
 
321
        HANDLE exec_handle;
 
322
        char *fname;
 
323
        char *ext;
 
324
 
 
325
        fname = malloc(strlen(exec_path) + 5);
 
326
        strcpy(fname, exec_path);
 
327
        ext = fname + strlen(fname);
 
328
 
 
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);
 
334
        }
 
335
 
 
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);
 
341
        }
 
342
 
 
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);
 
348
        }
 
349
 
 
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);
 
355
        }
 
356
 
 
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);
 
362
        }
 
363
 
 
364
        free(fname);
 
365
        return(exec_handle);
 
366
}
 
367
 
 
368
 
 
369
/*
 
370
 * Description:   Create the child process to be helped
 
371
 *
 
372
 * Returns:
 
373
 *
 
374
 * Notes/Dependencies:
 
375
 */
 
376
long
 
377
process_begin(
 
378
        HANDLE proc,
 
379
        char **argv,
 
380
        char **envp,
 
381
        char *exec_path,
 
382
        char *as_user)
 
383
{
 
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;
 
396
 
 
397
 
 
398
        /*
 
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.
 
406
         */
 
407
 
 
408
        exec_handle = find_file(exec_path, &file_info);
 
409
 
 
410
        /*
 
411
         * If we couldn't open the file, just assume that Windows32 will be able
 
412
         * to find and execute it.
 
413
         */
 
414
        if (exec_handle == (HANDLE)HFILE_ERROR) {
 
415
                file_not_found++;
 
416
        }
 
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) {
 
422
 
 
423
                        pproc->last_err = GetLastError();
 
424
                        pproc->lerrno = E_IO;
 
425
                        CloseHandle(exec_handle);
 
426
                        return(-1);
 
427
                }
 
428
                if (buf[0] == '#' && buf[1] == '!') {
 
429
                        /*
 
430
                         *  This is a shell script...  Change the command line from
 
431
                         *      exec_path args to shell_name exec_path args
 
432
                         */
 
433
                        char *p;
 
434
 
 
435
                        /*  Make sure buf is NULL terminated */
 
436
                        buf[bytes_returned] = 0;
 
437
                        /*
 
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.
 
441
                         */
 
442
                        p= strchr(buf, '\n');
 
443
                        if (p)
 
444
                                *p = 0;
 
445
                        p = strchr(buf, '\r');
 
446
                        if (p)
 
447
                                *p = 0;
 
448
 
 
449
                        /*
 
450
                         *  Find base name of shell
 
451
                         */
 
452
                        shell_name = strrchr( buf, '/');
 
453
                        if (shell_name) {
 
454
                                shell_name++;
 
455
                        } else {
 
456
                                shell_name = &buf[2];/* skipping "#!" */
 
457
                        }
 
458
 
 
459
                }
 
460
                CloseHandle(exec_handle);
 
461
        }
 
462
 
 
463
        flags = 0;
 
464
 
 
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);
 
470
 
 
471
        if ( command_line == NULL ) {
 
472
                pproc->last_err = 0;
 
473
                pproc->lerrno = E_NO_MEM;
 
474
                return(-1);
 
475
        }
 
476
 
 
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);
 
483
                }
 
484
        }
 
485
 
 
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;
 
490
        }
 
491
 
 
492
        /*
 
493
         *  Set up inherited stdin, stdout, stderr for child
 
494
         */
 
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];
 
504
 
 
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) {
 
524
 
 
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);
 
531
                }
 
532
        }
 
533
 
 
534
        pproc->pid = (int)procInfo.hProcess;
 
535
        /* Close the thread handle -- we'll just watch the process */
 
536
        CloseHandle(procInfo.hThread);
 
537
 
 
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;
 
542
        }
 
543
        if (pproc->sv_stdout) {
 
544
                CloseHandle((HANDLE)pproc->sv_stdout[1]);
 
545
                (HANDLE)pproc->sv_stdout[1] = 0;
 
546
        }
 
547
        if (pproc->sv_stderr) {
 
548
                CloseHandle((HANDLE)pproc->sv_stderr[1]);
 
549
                (HANDLE)pproc->sv_stderr[1] = 0;
 
550
        }
 
551
 
 
552
        free( command_line );
 
553
        if (envblk) free(envblk);
 
554
        pproc->lerrno=0;
 
555
        return 0;
 
556
}
 
557
 
 
558
 
 
559
 
 
560
static DWORD
 
561
proc_stdin_thread(sub_process *pproc)
 
562
{
 
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);
 
575
                }
 
576
        }
 
577
        return 0; // for compiler warnings only.. not reached
 
578
}
 
579
 
 
580
static DWORD
 
581
proc_stdout_thread(sub_process *pproc)
 
582
{
 
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;
 
590
 
 
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);
 
596
                }
 
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);
 
605
                        }
 
606
                }
 
607
                pproc->outp[pproc->outcnt++] = c;
 
608
        }
 
609
        return 0;
 
610
}
 
611
 
 
612
static DWORD
 
613
proc_stderr_thread(sub_process *pproc)
 
614
{
 
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;
 
622
 
 
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);
 
627
                }
 
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);
 
636
                        }
 
637
                }
 
638
                pproc->errp[pproc->errcnt++] = c;
 
639
        }
 
640
        return 0;
 
641
}
 
642
 
 
643
 
 
644
/*
 
645
 * Purpose: collects output from child process and returns results
 
646
 *
 
647
 * Description:
 
648
 *
 
649
 * Returns:
 
650
 *
 
651
 * Notes/Dependencies:
 
652
 */
 
653
        long
 
654
process_pipe_io(
 
655
        HANDLE proc,
 
656
        char *stdin_data,
 
657
        int stdin_data_len)
 
658
{
 
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;
 
669
 
 
670
 
 
671
        /*
 
672
         *  Create stdin thread, if needed
 
673
         */
 
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;
 
688
                }
 
689
        }
 
690
 
 
691
        /*
 
692
         *   Assume child will produce stdout and stderr
 
693
         */
 
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);
 
700
 
 
701
        if (tStdout == 0 || tStderr == 0) {
 
702
 
 
703
                pproc->last_err = GetLastError();
 
704
                pproc->lerrno = E_SCALL;
 
705
                goto done;
 
706
        }
 
707
 
 
708
 
 
709
        /*
 
710
         *  Wait for all I/O to finish and for the child process to exit
 
711
         */
 
712
 
 
713
        while (!stdin_eof || !stdout_eof || !stderr_eof || !child_dead) {
 
714
                wait_count = 0;
 
715
                if (!stdin_eof) {
 
716
                        wait_list[wait_count++] = tStdin;
 
717
                }
 
718
                if (!stdout_eof) {
 
719
                        wait_list[wait_count++] = tStdout;
 
720
                }
 
721
                if (!stderr_eof) {
 
722
                        wait_list[wait_count++] = tStderr;
 
723
                }
 
724
                if (!child_dead) {
 
725
                        wait_list[wait_count++] = childhand;
 
726
                }
 
727
 
 
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 */
 
732
 
 
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;
 
738
                }
 
739
 
 
740
                ready_hand = wait_list[wait_return - WAIT_OBJECT_0];
 
741
 
 
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;
 
748
 
 
749
                } else if (ready_hand == tStdout) {
 
750
 
 
751
                        CloseHandle((HANDLE)pproc->sv_stdout[0]);
 
752
                        (HANDLE)pproc->sv_stdout[0] = 0;
 
753
                        CloseHandle(tStdout);
 
754
                        tStdout = 0;
 
755
                        stdout_eof = TRUE;
 
756
 
 
757
                } else if (ready_hand == tStderr) {
 
758
 
 
759
                        CloseHandle((HANDLE)pproc->sv_stderr[0]);
 
760
                        (HANDLE)pproc->sv_stderr[0] = 0;
 
761
                        CloseHandle(tStderr);
 
762
                        tStderr = 0;
 
763
                        stderr_eof = TRUE;
 
764
 
 
765
                } else if (ready_hand == childhand) {
 
766
 
 
767
                        if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
 
768
                                pproc->last_err = GetLastError();
 
769
                                pproc->lerrno = E_SCALL;
 
770
                                goto done;
 
771
                        }
 
772
                        child_dead = TRUE;
 
773
 
 
774
                } else {
 
775
 
 
776
                        /* ?? Got back a handle we didn't query ?? */
 
777
                        pproc->last_err = 0;
 
778
                        pproc->lerrno = E_FAIL;
 
779
                        goto done;
 
780
                }
 
781
        }
 
782
 
 
783
 done:
 
784
        if (tStdin != 0)
 
785
                CloseHandle(tStdin);
 
786
        if (tStdout != 0)
 
787
                CloseHandle(tStdout);
 
788
        if (tStderr != 0)
 
789
                CloseHandle(tStderr);
 
790
 
 
791
        if (pproc->lerrno)
 
792
                return(-1);
 
793
        else
 
794
                return(0);
 
795
 
 
796
}
 
797
 
 
798
/*
 
799
 * Purpose: collects output from child process and returns results
 
800
 *
 
801
 * Description:
 
802
 *
 
803
 * Returns:
 
804
 *
 
805
 * Notes/Dependencies:
 
806
 */
 
807
        long
 
808
process_file_io(
 
809
        HANDLE proc)
 
810
{
 
811
        sub_process *pproc;
 
812
        HANDLE childhand;
 
813
        DWORD wait_return;
 
814
 
 
815
        if (proc == NULL)
 
816
                pproc = process_wait_for_any_private();
 
817
        else
 
818
                pproc = (sub_process *)proc;
 
819
 
 
820
        /* some sort of internal error */
 
821
        if (!pproc)
 
822
                return -1;
 
823
 
 
824
        childhand = (HANDLE) pproc->pid;
 
825
 
 
826
        /*
 
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.
 
830
         */
 
831
        if (pproc->sv_stdin[0]) {
 
832
                CloseHandle((HANDLE)pproc->sv_stdin[0]);
 
833
                pproc->sv_stdin[0] = 0;
 
834
        }
 
835
        if (pproc->sv_stdout[0]) {
 
836
                CloseHandle((HANDLE)pproc->sv_stdout[0]);
 
837
                pproc->sv_stdout[0] = 0;
 
838
        }
 
839
        if (pproc->sv_stderr[0]) {
 
840
                CloseHandle((HANDLE)pproc->sv_stderr[0]);
 
841
                pproc->sv_stderr[0] = 0;
 
842
        }
 
843
 
 
844
        /*
 
845
         *  Wait for the child process to exit
 
846
         */
 
847
 
 
848
        wait_return = WaitForSingleObject(childhand, INFINITE);
 
849
 
 
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;
 
855
        }
 
856
 
 
857
        if (GetExitCodeProcess(childhand, &pproc->exit_code) == FALSE) {
 
858
                pproc->last_err = GetLastError();
 
859
                pproc->lerrno = E_SCALL;
 
860
        }
 
861
 
 
862
done2:
 
863
        if (pproc->lerrno)
 
864
                return(-1);
 
865
        else
 
866
                return(0);
 
867
 
 
868
}
 
869
 
 
870
/*
 
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.
 
873
 */
 
874
        void
 
875
process_cleanup(
 
876
        HANDLE proc)
 
877
{
 
878
        sub_process *pproc = (sub_process *)proc;
 
879
        int i;
 
880
 
 
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]);
 
889
                }
 
890
        }
 
891
        if ((HANDLE)pproc->pid)
 
892
                CloseHandle((HANDLE)pproc->pid);
 
893
 
 
894
        free(pproc);
 
895
}
 
896
 
 
897
 
 
898
/*
 
899
 * Description:
 
900
 *       Create a command line buffer to pass to CreateProcess
 
901
 *
 
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] ...
 
905
 *
 
906
 * Notes/Dependencies:
 
907
 *   CreateProcess does not take an argv, so this command creates a
 
908
 *   command line for the executable.
 
909
 */
 
910
 
 
911
static char *
 
912
make_command_line( char *shell_name, char *full_exec_path, char **argv)
 
913
{
 
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 */
 
923
 
 
924
#ifdef HAVE_CYGWIN_SHELL
 
925
        have_sh = (shell_name != NULL || strstr(full_exec_path, "sh.exe"));
 
926
        cygwin_mode = 1;
 
927
#endif
 
928
 
 
929
        if (shell_name && full_exec_path) {
 
930
                bytes_required
 
931
                  = strlen(shell_name) + 1 + strlen(full_exec_path);
 
932
                /*
 
933
                 * Skip argv[0] if any, when shell_name is given.
 
934
                 */
 
935
                if (*argv) argv++;
 
936
                /*
 
937
                 * Add one for the intervening space.
 
938
                 */
 
939
                if (*argv) bytes_required++;
 
940
        }
 
941
 
 
942
        argvi = argv;
 
943
        while (*(argvi++)) argc++;
 
944
 
 
945
        if (argc) {
 
946
                enclose_in_quotes = (int*) calloc(1, argc * sizeof(int));
 
947
 
 
948
                if (!enclose_in_quotes) {
 
949
                        return NULL;
 
950
                }
 
951
        }
 
952
 
 
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.
 
956
         */
 
957
 
 
958
        argvi = argv;
 
959
        enclose_in_quotes_i = enclose_in_quotes;
 
960
        while(*argvi) {
 
961
                char* p = *argvi;
 
962
                unsigned int backslash_count = 0;
 
963
 
 
964
                /*
 
965
                 * We have to enclose empty arguments in ".
 
966
                 */
 
967
                if (!(*p)) *enclose_in_quotes_i = 1;
 
968
 
 
969
                while(*p) {
 
970
                        switch (*p) {
 
971
                        case '\"':
 
972
                                /*
 
973
                                 * We have to insert a backslash for each "
 
974
                                 * and each \ that precedes the ".
 
975
                                 */
 
976
                                bytes_required += (backslash_count + 1);
 
977
                                backslash_count = 0;
 
978
                                break;
 
979
 
 
980
#if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
 
981
                        case '\\':
 
982
                                backslash_count++;
 
983
                                break;
 
984
#endif
 
985
        /*
 
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 *.
 
996
         */
 
997
                        case ' ':
 
998
                        case '\t':
 
999
                                *enclose_in_quotes_i = 1;
 
1000
                                /* fall through */
 
1001
 
 
1002
                        default:
 
1003
                                backslash_count = 0;
 
1004
                                break;
 
1005
                        }
 
1006
 
 
1007
                        /*
 
1008
                         * Add one for each character in argv[i].
 
1009
                         */
 
1010
                        bytes_required++;
 
1011
 
 
1012
                        p++;
 
1013
                }
 
1014
 
 
1015
                if (*enclose_in_quotes_i) {
 
1016
                        /*
 
1017
                         * Add one for each enclosing ",
 
1018
                         * and one for each \ that precedes the
 
1019
                         * closing ".
 
1020
                         */
 
1021
                        bytes_required += (backslash_count + 2);
 
1022
                }
 
1023
 
 
1024
                /*
 
1025
                 * Add one for the intervening space.
 
1026
                 */
 
1027
                if (*(++argvi)) bytes_required++;
 
1028
                enclose_in_quotes_i++;
 
1029
        }
 
1030
 
 
1031
        /*
 
1032
         * Add one for the terminating NULL.
 
1033
         */
 
1034
        bytes_required++;
 
1035
 
 
1036
        command_line = (char*) malloc(bytes_required);
 
1037
 
 
1038
        if (!command_line) {
 
1039
                if (enclose_in_quotes) free(enclose_in_quotes);
 
1040
                return NULL;
 
1041
        }
 
1042
 
 
1043
        command_line_i = command_line;
 
1044
 
 
1045
        if (shell_name && full_exec_path) {
 
1046
                while(*shell_name) {
 
1047
                        *(command_line_i++) = *(shell_name++);
 
1048
                }
 
1049
 
 
1050
                *(command_line_i++) = ' ';
 
1051
 
 
1052
                while(*full_exec_path) {
 
1053
                        *(command_line_i++) = *(full_exec_path++);
 
1054
                }
 
1055
 
 
1056
                if (*argv) {
 
1057
                        *(command_line_i++) = ' ';
 
1058
                }
 
1059
        }
 
1060
 
 
1061
        argvi = argv;
 
1062
        enclose_in_quotes_i = enclose_in_quotes;
 
1063
 
 
1064
        while(*argvi) {
 
1065
                char* p = *argvi;
 
1066
                unsigned int backslash_count = 0;
 
1067
 
 
1068
                if (*enclose_in_quotes_i) {
 
1069
                        *(command_line_i++) = '\"';
 
1070
                }
 
1071
 
 
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 {
 
1078
 
 
1079
                                /*
 
1080
                                 * We have to insert a backslash for the "
 
1081
                                 * and each \ that precedes the ".
 
1082
                                 */
 
1083
                                backslash_count++;
 
1084
 
 
1085
                                while(backslash_count) {
 
1086
                                        *(command_line_i++) = '\\';
 
1087
                                        backslash_count--;
 
1088
                                };
 
1089
                                }
 
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
 
1096
                        }
 
1097
 
 
1098
                        /*
 
1099
                         * Copy the character.
 
1100
                         */
 
1101
                        *(command_line_i++) = *(p++);
 
1102
                }
 
1103
 
 
1104
                if (*enclose_in_quotes_i) {
 
1105
#if !defined(HAVE_MKS_SHELL) && !defined(HAVE_CYGWIN_SHELL)
 
1106
                        /*
 
1107
                         * Add one \ for each \ that precedes the
 
1108
                         * closing ".
 
1109
                         */
 
1110
                        while(backslash_count--) {
 
1111
                                *(command_line_i++) = '\\';
 
1112
                        };
 
1113
#endif
 
1114
                        *(command_line_i++) = '\"';
 
1115
                }
 
1116
 
 
1117
                /*
 
1118
                 * Append an intervening space.
 
1119
                 */
 
1120
                if (*(++argvi)) {
 
1121
                        *(command_line_i++) = ' ';
 
1122
                }
 
1123
 
 
1124
                enclose_in_quotes_i++;
 
1125
        }
 
1126
 
 
1127
        /*
 
1128
         * Append the terminating NULL.
 
1129
         */
 
1130
        *command_line_i = '\0';
 
1131
 
 
1132
        if (enclose_in_quotes) free(enclose_in_quotes);
 
1133
        return command_line;
 
1134
}
 
1135
 
 
1136
/*
 
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().
 
1142
 *
 
1143
 * Returns:
 
1144
 *
 
1145
 * Notes/Dependencies:
 
1146
 */
 
1147
HANDLE
 
1148
process_easy(
 
1149
        char **argv,
 
1150
        char **envp)
 
1151
{
 
1152
  HANDLE hIn;
 
1153
  HANDLE hOut;
 
1154
  HANDLE hErr;
 
1155
  HANDLE hProcess;
 
1156
 
 
1157
  if (DuplicateHandle(GetCurrentProcess(),
 
1158
                      GetStdHandle(STD_INPUT_HANDLE),
 
1159
                      GetCurrentProcess(),
 
1160
                      &hIn,
 
1161
                      0,
 
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;
 
1168
  }
 
1169
  if (DuplicateHandle(GetCurrentProcess(),
 
1170
                      GetStdHandle(STD_OUTPUT_HANDLE),
 
1171
                      GetCurrentProcess(),
 
1172
                      &hOut,
 
1173
                      0,
 
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;
 
1180
  }
 
1181
  if (DuplicateHandle(GetCurrentProcess(),
 
1182
                      GetStdHandle(STD_ERROR_HANDLE),
 
1183
                      GetCurrentProcess(),
 
1184
                      &hErr,
 
1185
                      0,
 
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;
 
1192
  }
 
1193
 
 
1194
  hProcess = process_init_fd(hIn, hOut, hErr);
 
1195
 
 
1196
  if (process_begin(hProcess, argv, envp, argv[0], NULL)) {
 
1197
    fake_exits_pending++;
 
1198
    ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
 
1199
 
 
1200
    /* close up unused handles */
 
1201
    CloseHandle(hIn);
 
1202
    CloseHandle(hOut);
 
1203
    CloseHandle(hErr);
 
1204
  }
 
1205
 
 
1206
  process_register(hProcess);
 
1207
 
 
1208
  return hProcess;
 
1209
}