~ubuntu-branches/ubuntu/precise/ghc/precise

« back to all changes in this revision

Viewing changes to libraries/process/cbits/runProcess.c

  • Committer: Bazaar Package Importer
  • Author(s): Joachim Breitner
  • Date: 2011-01-17 12:49:24 UTC
  • Revision ID: james.westby@ubuntu.com-20110117124924-do1pym1jlf5o636m
Tags: upstream-7.0.1
ImportĀ upstreamĀ versionĀ 7.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ----------------------------------------------------------------------------
 
2
   (c) The University of Glasgow 2004
 
3
   
 
4
   Support for System.Process
 
5
   ------------------------------------------------------------------------- */
 
6
 
 
7
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32)
 
8
#define UNICODE
 
9
#endif
 
10
 
 
11
/* XXX This is a nasty hack; should put everything necessary in this package */
 
12
#include "HsBase.h"
 
13
#include "Rts.h"
 
14
 
 
15
#include "runProcess.h"
 
16
 
 
17
#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32))
 
18
 
 
19
#include "execvpe.h"
 
20
 
 
21
/* ----------------------------------------------------------------------------
 
22
   UNIX versions
 
23
   ------------------------------------------------------------------------- */
 
24
 
 
25
static long max_fd = 0;
 
26
 
 
27
// Rts internal API, not exposed in a public header file:
 
28
extern void blockUserSignals(void);
 
29
extern void unblockUserSignals(void);
 
30
 
 
31
ProcHandle
 
32
runInteractiveProcess (char *const args[], 
 
33
                       char *workingDirectory, char **environment,
 
34
                       int fdStdIn, int fdStdOut, int fdStdErr,
 
35
                       int *pfdStdInput, int *pfdStdOutput, int *pfdStdError,
 
36
                       int set_inthandler, long inthandler, 
 
37
                       int set_quithandler, long quithandler,
 
38
                       int close_fds)
 
39
{
 
40
    int pid;
 
41
    int fdStdInput[2], fdStdOutput[2], fdStdError[2];
 
42
    int r;
 
43
    struct sigaction dfl;
 
44
 
 
45
    // Ordering matters here, see below [Note #431].
 
46
    if (fdStdIn == -1) {
 
47
        r = pipe(fdStdInput);
 
48
        if (r == -1) { 
 
49
            sysErrorBelch("runInteractiveProcess: pipe");
 
50
            return -1;
 
51
        }
 
52
        
 
53
    }
 
54
    if (fdStdOut == -1) {
 
55
        r = pipe(fdStdOutput);
 
56
        if (r == -1) { 
 
57
            sysErrorBelch("runInteractiveProcess: pipe");
 
58
            return -1;
 
59
        }
 
60
    }
 
61
    if (fdStdErr == -1) {
 
62
        r = pipe(fdStdError);
 
63
        if (r == -1) { 
 
64
            sysErrorBelch("runInteractiveProcess: pipe");
 
65
            return -1;
 
66
        }
 
67
    }
 
68
 
 
69
    // Block signals with Haskell handlers.  The danger here is that
 
70
    // with the threaded RTS, a signal arrives in the child process,
 
71
    // the RTS writes the signal information into the pipe (which is
 
72
    // shared between parent and child), and the parent behaves as if
 
73
    // the signal had been raised.
 
74
    blockUserSignals();
 
75
 
 
76
    // See #4074.  Sometimes fork() gets interrupted by the timer
 
77
    // signal and keeps restarting indefinitely.
 
78
    stopTimer();
 
79
 
 
80
    switch(pid = fork())
 
81
    {
 
82
    case -1:
 
83
        unblockUserSignals();
 
84
#if __GLASGOW_HASKELL__ > 612
 
85
        startTimer();
 
86
#endif
 
87
        if (fdStdIn == -1) {
 
88
            close(fdStdInput[0]);
 
89
            close(fdStdInput[1]);
 
90
        }
 
91
        if (fdStdOut == -1) {
 
92
            close(fdStdOutput[0]);
 
93
            close(fdStdOutput[1]);
 
94
        }
 
95
        if (fdStdErr == -1) {
 
96
            close(fdStdError[0]);
 
97
            close(fdStdError[1]);
 
98
        }
 
99
        return -1;
 
100
        
 
101
    case 0:
 
102
    {
 
103
        // WARNING!  we are now in the child of vfork(), so any memory
 
104
        // we modify below will also be seen in the parent process.
 
105
 
 
106
        unblockUserSignals();
 
107
 
 
108
        if (workingDirectory) {
 
109
            if (chdir (workingDirectory) < 0) {
 
110
                // See #1593.  The convention for the exit code when
 
111
                // exec() fails seems to be 127 (gleened from C's
 
112
                // system()), but there's no equivalent convention for
 
113
                // chdir(), so I'm picking 126 --SimonM.
 
114
                _exit(126);
 
115
            }
 
116
        }
 
117
        
 
118
        // [Note #431]: Ordering matters here.  If any of the FDs
 
119
        // 0,1,2 were initially closed, then our pipes may have used
 
120
        // these FDs.  So when we dup2 the pipe FDs down to 0,1,2, we
 
121
        // must do it in that order, otherwise we could overwrite an
 
122
        // FD that we need later.
 
123
 
 
124
        if (fdStdIn == -1) {
 
125
            if (fdStdInput[0] != STDIN_FILENO) {
 
126
                dup2 (fdStdInput[0], STDIN_FILENO);
 
127
                close(fdStdInput[0]);
 
128
            }
 
129
            close(fdStdInput[1]);
 
130
        } else {
 
131
            dup2(fdStdIn,  STDIN_FILENO);
 
132
        }
 
133
 
 
134
        if (fdStdOut == -1) {
 
135
            if (fdStdOutput[1] != STDOUT_FILENO) {
 
136
                dup2 (fdStdOutput[1], STDOUT_FILENO);
 
137
                close(fdStdOutput[1]);
 
138
            }
 
139
            close(fdStdOutput[0]);
 
140
        } else {
 
141
            dup2(fdStdOut,  STDOUT_FILENO);
 
142
        }
 
143
 
 
144
        if (fdStdErr == -1) {
 
145
            if (fdStdError[1] != STDERR_FILENO) {
 
146
                dup2 (fdStdError[1], STDERR_FILENO);
 
147
                close(fdStdError[1]);
 
148
            }
 
149
            close(fdStdError[0]);
 
150
        } else {
 
151
            dup2(fdStdErr,  STDERR_FILENO);
 
152
        }
 
153
            
 
154
        if (close_fds) {
 
155
            int i;
 
156
            if (max_fd == 0) {
 
157
#if HAVE_SYSCONF
 
158
                max_fd = sysconf(_SC_OPEN_MAX);
 
159
                if (max_fd == -1) {
 
160
                    max_fd = 256;
 
161
                }
 
162
#else
 
163
                max_fd = 256;
 
164
#endif
 
165
            }
 
166
            for (i = 3; i < max_fd; i++) {
 
167
                close(i);
 
168
            }
 
169
        }
 
170
 
 
171
        /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested 
 
172
         */
 
173
        (void)sigemptyset(&dfl.sa_mask);
 
174
        dfl.sa_flags = 0;
 
175
        if (set_inthandler) {
 
176
            dfl.sa_handler = (void *)inthandler;
 
177
            (void)sigaction(SIGINT, &dfl, NULL);
 
178
        }
 
179
        if (set_quithandler) {
 
180
            dfl.sa_handler = (void *)quithandler;
 
181
            (void)sigaction(SIGQUIT,  &dfl, NULL);
 
182
        }
 
183
 
 
184
        /* the child */
 
185
        if (environment) {
 
186
            execvpe(args[0], args, environment);
 
187
        } else {
 
188
            execvp(args[0], args);
 
189
        }
 
190
    }
 
191
    _exit(127);
 
192
    
 
193
    default:
 
194
        if (fdStdIn  == -1) {
 
195
            close(fdStdInput[0]);
 
196
            fcntl(fdStdInput[1], F_SETFD, FD_CLOEXEC);
 
197
            *pfdStdInput  = fdStdInput[1];
 
198
        }
 
199
        if (fdStdOut == -1) {
 
200
            close(fdStdOutput[1]);
 
201
            fcntl(fdStdOutput[0], F_SETFD, FD_CLOEXEC);
 
202
            *pfdStdOutput = fdStdOutput[0];
 
203
        }
 
204
        if (fdStdErr == -1) {
 
205
            close(fdStdError[1]);
 
206
            fcntl(fdStdError[0], F_SETFD, FD_CLOEXEC);
 
207
            *pfdStdError  = fdStdError[0];
 
208
        }
 
209
        break;
 
210
    }
 
211
    unblockUserSignals();
 
212
    startTimer();
 
213
    
 
214
    return pid;
 
215
}
 
216
 
 
217
int
 
218
terminateProcess (ProcHandle handle)
 
219
{
 
220
    return (kill(handle, SIGTERM) == 0);
 
221
}
 
222
 
 
223
int
 
224
getProcessExitCode (ProcHandle handle, int *pExitCode)
 
225
{
 
226
    int wstat, res;
 
227
    
 
228
    *pExitCode = 0;
 
229
    
 
230
    if ((res = waitpid(handle, &wstat, WNOHANG)) > 0)
 
231
    {
 
232
        if (WIFEXITED(wstat))
 
233
        {
 
234
            *pExitCode = WEXITSTATUS(wstat);
 
235
            return 1;
 
236
        }
 
237
        else
 
238
            if (WIFSIGNALED(wstat))
 
239
            {
 
240
                errno = EINTR;
 
241
                return -1;
 
242
            }
 
243
            else
 
244
            {
 
245
                /* This should never happen */
 
246
            }
 
247
    }
 
248
    
 
249
    if (res == 0) return 0;
 
250
 
 
251
    if (errno == ECHILD) 
 
252
    {
 
253
            *pExitCode = 0;
 
254
            return 1;
 
255
    }
 
256
 
 
257
    return -1;
 
258
}
 
259
 
 
260
int waitForProcess (ProcHandle handle, int *pret)
 
261
{
 
262
    int wstat;
 
263
    
 
264
    while (waitpid(handle, &wstat, 0) < 0)
 
265
    {
 
266
        if (errno != EINTR)
 
267
        {
 
268
            return -1;
 
269
        }
 
270
    }
 
271
    
 
272
    if (WIFEXITED(wstat)) {
 
273
        *pret = WEXITSTATUS(wstat);
 
274
        return 0;
 
275
    }
 
276
    else
 
277
        if (WIFSIGNALED(wstat))
 
278
        {
 
279
            *pret = wstat;
 
280
            return 0;
 
281
        }
 
282
        else
 
283
        {
 
284
            /* This should never happen */
 
285
        }
 
286
    
 
287
    return -1;
 
288
}
 
289
 
 
290
#else
 
291
/* ----------------------------------------------------------------------------
 
292
   Win32 versions
 
293
   ------------------------------------------------------------------------- */
 
294
 
 
295
/* -------------------- WINDOWS VERSION --------------------- */
 
296
 
 
297
/*
 
298
 * Function: mkAnonPipe
 
299
 *
 
300
 * Purpose:  create an anonymous pipe with read and write ends being
 
301
 *           optionally (non-)inheritable.
 
302
 */
 
303
static BOOL
 
304
mkAnonPipe (HANDLE* pHandleIn, BOOL isInheritableIn, 
 
305
            HANDLE* pHandleOut, BOOL isInheritableOut)
 
306
{
 
307
        HANDLE hTemporaryIn  = NULL;
 
308
        HANDLE hTemporaryOut = NULL;
 
309
 
 
310
        /* Create the anon pipe with both ends inheritable */
 
311
        if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, NULL, 0))
 
312
        {
 
313
                maperrno();
 
314
                *pHandleIn  = NULL;
 
315
                *pHandleOut = NULL;
 
316
                return FALSE;
 
317
        }
 
318
 
 
319
        if (isInheritableIn) {
 
320
            // SetHandleInformation requires at least Win2k
 
321
            if (!SetHandleInformation(hTemporaryIn,
 
322
                                      HANDLE_FLAG_INHERIT, 
 
323
                                      HANDLE_FLAG_INHERIT))
 
324
            {
 
325
                maperrno();
 
326
                *pHandleIn  = NULL;
 
327
                *pHandleOut = NULL;
 
328
                CloseHandle(hTemporaryIn);
 
329
                CloseHandle(hTemporaryOut);
 
330
                return FALSE;
 
331
            }
 
332
        }
 
333
        *pHandleIn = hTemporaryIn;
 
334
 
 
335
        if (isInheritableOut) {
 
336
            if (!SetHandleInformation(hTemporaryOut,
 
337
                                      HANDLE_FLAG_INHERIT, 
 
338
                                      HANDLE_FLAG_INHERIT))
 
339
            {
 
340
                maperrno();
 
341
                *pHandleIn  = NULL;
 
342
                *pHandleOut = NULL;
 
343
                CloseHandle(hTemporaryIn);
 
344
                CloseHandle(hTemporaryOut);
 
345
                return FALSE;
 
346
            }
 
347
        }
 
348
        *pHandleOut = hTemporaryOut;
 
349
        
 
350
        return TRUE;
 
351
}
 
352
 
 
353
ProcHandle
 
354
runInteractiveProcess (wchar_t *cmd, wchar_t *workingDirectory, 
 
355
                       void *environment,
 
356
                       int fdStdIn, int fdStdOut, int fdStdErr,
 
357
                       int *pfdStdInput, int *pfdStdOutput, int *pfdStdError,
 
358
                       int close_fds)
 
359
{
 
360
        STARTUPINFO sInfo;
 
361
        PROCESS_INFORMATION pInfo;
 
362
        HANDLE hStdInputRead   = INVALID_HANDLE_VALUE;
 
363
        HANDLE hStdInputWrite  = INVALID_HANDLE_VALUE;
 
364
        HANDLE hStdOutputRead  = INVALID_HANDLE_VALUE;
 
365
        HANDLE hStdOutputWrite = INVALID_HANDLE_VALUE;
 
366
        HANDLE hStdErrorRead   = INVALID_HANDLE_VALUE;
 
367
        HANDLE hStdErrorWrite  = INVALID_HANDLE_VALUE;
 
368
        DWORD flags;
 
369
        BOOL status;
 
370
        BOOL inherit;
 
371
 
 
372
        ZeroMemory(&sInfo, sizeof(sInfo));
 
373
        sInfo.cb = sizeof(sInfo);
 
374
        sInfo.dwFlags = STARTF_USESTDHANDLES;
 
375
 
 
376
        if (fdStdIn == -1) {
 
377
            if (!mkAnonPipe(&hStdInputRead,  TRUE, &hStdInputWrite,  FALSE))
 
378
                goto cleanup_err;
 
379
            sInfo.hStdInput = hStdInputRead;
 
380
        } else if (fdStdIn == 0) {
 
381
            // Don't duplicate stdin, as console handles cannot be
 
382
            // duplicated and inherited. urg.
 
383
            sInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
 
384
        } else {
 
385
            // The handle might not be inheritable, so duplicate it
 
386
            status = DuplicateHandle(GetCurrentProcess(), 
 
387
                                     (HANDLE) _get_osfhandle(fdStdIn),
 
388
                                     GetCurrentProcess(), &hStdInputRead,
 
389
                                     0,
 
390
                                     TRUE, /* inheritable */
 
391
                                     DUPLICATE_SAME_ACCESS);
 
392
            if (!status) goto cleanup_err;
 
393
            sInfo.hStdInput = hStdInputRead;
 
394
        }
 
395
 
 
396
        if (fdStdOut == -1) {
 
397
            if (!mkAnonPipe(&hStdOutputRead,  FALSE, &hStdOutputWrite,  TRUE))
 
398
                goto cleanup_err;
 
399
            sInfo.hStdOutput = hStdOutputWrite;
 
400
        } else if (fdStdOut == 1) {
 
401
            // Don't duplicate stdout, as console handles cannot be
 
402
            // duplicated and inherited. urg.
 
403
            sInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 
404
        } else {
 
405
            // The handle might not be inheritable, so duplicate it
 
406
            status = DuplicateHandle(GetCurrentProcess(), 
 
407
                                     (HANDLE) _get_osfhandle(fdStdOut),
 
408
                                     GetCurrentProcess(), &hStdOutputWrite,
 
409
                                     0,
 
410
                                     TRUE, /* inheritable */
 
411
                                     DUPLICATE_SAME_ACCESS);
 
412
            if (!status) goto cleanup_err;
 
413
            sInfo.hStdOutput = hStdOutputWrite;
 
414
        }
 
415
 
 
416
        if (fdStdErr == -1) {
 
417
            if (!mkAnonPipe(&hStdErrorRead,  TRUE, &hStdErrorWrite,  TRUE))
 
418
                goto cleanup_err;
 
419
            sInfo.hStdError = hStdErrorWrite;
 
420
        } else if (fdStdErr == 2) {
 
421
            // Don't duplicate stderr, as console handles cannot be
 
422
            // duplicated and inherited. urg.
 
423
            sInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 
424
        } else {
 
425
            /* The handle might not be inheritable, so duplicate it */
 
426
            status = DuplicateHandle(GetCurrentProcess(), 
 
427
                                     (HANDLE) _get_osfhandle(fdStdErr),
 
428
                                     GetCurrentProcess(), &hStdErrorWrite,
 
429
                                     0,
 
430
                                     TRUE, /* inheritable */
 
431
                                     DUPLICATE_SAME_ACCESS);
 
432
            if (!status) goto cleanup_err;
 
433
            sInfo.hStdError = hStdErrorWrite;
 
434
        }
 
435
 
 
436
        if (sInfo.hStdInput  != GetStdHandle(STD_INPUT_HANDLE)  &&
 
437
            sInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE) &&
 
438
            sInfo.hStdError  != GetStdHandle(STD_ERROR_HANDLE))
 
439
                flags = CREATE_NO_WINDOW;   // Run without console window only when both output and error are redirected
 
440
        else
 
441
                flags = 0;
 
442
 
 
443
        // See #3231
 
444
        if (close_fds && fdStdIn == 0 && fdStdOut == 1 && fdStdErr == 2) {
 
445
            inherit = FALSE;
 
446
        } else {
 
447
            inherit = TRUE;
 
448
        }
 
449
 
 
450
        if (!CreateProcess(NULL, cmd, NULL, NULL, inherit, flags, environment, workingDirectory, &sInfo, &pInfo))
 
451
        {
 
452
                goto cleanup_err;
 
453
        }
 
454
        CloseHandle(pInfo.hThread);
 
455
 
 
456
        // Close the ends of the pipes that were inherited by the
 
457
        // child process.  This is important, otherwise we won't see
 
458
        // EOF on these pipes when the child process exits.
 
459
        if (hStdInputRead   != INVALID_HANDLE_VALUE) CloseHandle(hStdInputRead);
 
460
        if (hStdOutputWrite != INVALID_HANDLE_VALUE) CloseHandle(hStdOutputWrite);
 
461
        if (hStdErrorWrite  != INVALID_HANDLE_VALUE) CloseHandle(hStdErrorWrite);
 
462
 
 
463
        *pfdStdInput  = _open_osfhandle((intptr_t) hStdInputWrite, _O_WRONLY);
 
464
        *pfdStdOutput = _open_osfhandle((intptr_t) hStdOutputRead, _O_RDONLY);
 
465
        *pfdStdError  = _open_osfhandle((intptr_t) hStdErrorRead,  _O_RDONLY);
 
466
 
 
467
        return (int) pInfo.hProcess;
 
468
 
 
469
cleanup_err:
 
470
        if (hStdInputRead   != INVALID_HANDLE_VALUE) CloseHandle(hStdInputRead);
 
471
        if (hStdInputWrite  != INVALID_HANDLE_VALUE) CloseHandle(hStdInputWrite);
 
472
        if (hStdOutputRead  != INVALID_HANDLE_VALUE) CloseHandle(hStdOutputRead);
 
473
        if (hStdOutputWrite != INVALID_HANDLE_VALUE) CloseHandle(hStdOutputWrite);
 
474
        if (hStdErrorRead   != INVALID_HANDLE_VALUE) CloseHandle(hStdErrorRead);
 
475
        if (hStdErrorWrite  != INVALID_HANDLE_VALUE) CloseHandle(hStdErrorWrite);
 
476
        maperrno();
 
477
        return -1;
 
478
}
 
479
 
 
480
int
 
481
terminateProcess (ProcHandle handle)
 
482
{
 
483
    if (!TerminateProcess((HANDLE) handle, 1)) {
 
484
        maperrno();
 
485
        return -1;
 
486
    }
 
487
    return 0;
 
488
}
 
489
 
 
490
int
 
491
getProcessExitCode (ProcHandle handle, int *pExitCode)
 
492
{
 
493
    *pExitCode = 0;
 
494
 
 
495
    if (WaitForSingleObject((HANDLE) handle, 1) == WAIT_OBJECT_0)
 
496
    {
 
497
        if (GetExitCodeProcess((HANDLE) handle, (DWORD *) pExitCode) == 0)
 
498
        {
 
499
            maperrno();
 
500
            return -1;
 
501
        }
 
502
        return 1;
 
503
    }
 
504
    
 
505
    return 0;
 
506
}
 
507
 
 
508
int
 
509
waitForProcess (ProcHandle handle, int *pret)
 
510
{
 
511
    DWORD retCode;
 
512
 
 
513
    if (WaitForSingleObject((HANDLE) handle, INFINITE) == WAIT_OBJECT_0)
 
514
    {
 
515
        if (GetExitCodeProcess((HANDLE) handle, &retCode) == 0)
 
516
        {
 
517
            maperrno();
 
518
            return -1;
 
519
        }
 
520
        *pret = retCode;
 
521
        return 0;
 
522
    }
 
523
    
 
524
    maperrno();
 
525
    return -1;
 
526
}
 
527
 
 
528
#endif /* Win32 */