[project @ 2005-08-01 13:23:22 by simonmar]
[ghc-base.git] / cbits / runProcess.c
1 /* ----------------------------------------------------------------------------
2    (c) The University of Glasgow 2004
3    
4    Support for System.Process
5    ------------------------------------------------------------------------- */
6
7 #include "HsBase.h"
8
9 #if defined(mingw32_HOST_OS)
10 #include <windows.h>
11 #include <stdlib.h>
12 #endif
13
14 #ifdef HAVE_VFORK_H
15 #include <vfork.h>
16 #endif
17
18 #ifdef HAVE_VFORK
19 #define fork vfork
20 #endif
21
22 #ifdef HAVE_SIGNAL_H
23 #include <signal.h>
24 #endif
25
26 #if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)
27 /* ----------------------------------------------------------------------------
28    UNIX versions
29    ------------------------------------------------------------------------- */
30
31 ProcHandle
32 runProcess (char *const args[], char *workingDirectory, char **environment, 
33             int fdStdInput, int fdStdOutput, int fdStdError,
34             int set_inthandler, long inthandler, 
35             int set_quithandler, long quithandler)
36 {
37     int pid;
38     struct sigaction dfl;
39
40     switch(pid = fork())
41     {
42     case -1:
43         return -1;
44         
45     case 0:
46     {
47         pPrPr_disableITimers();
48         
49         if (workingDirectory) {
50             if (chdir (workingDirectory) < 0) {
51                 return -1;
52             }
53         }
54         
55         /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested 
56          */
57         (void)sigemptyset(&dfl.sa_mask);
58         dfl.sa_flags = 0;
59         if (set_inthandler) {
60             dfl.sa_handler = (void *)inthandler;
61             (void)sigaction(SIGINT, &dfl, NULL);
62         }
63         if (set_quithandler) {
64             dfl.sa_handler = (void *)quithandler;
65             (void)sigaction(SIGQUIT,  &dfl, NULL);
66         }
67
68         dup2 (fdStdInput,  STDIN_FILENO);
69         dup2 (fdStdOutput, STDOUT_FILENO);
70         dup2 (fdStdError,  STDERR_FILENO);
71         
72         if (environment) {
73             execvpe(args[0], args, environment);
74         } else {
75             execvp(args[0], args);
76         }
77     }
78     _exit(127);
79     }
80     
81     return pid;
82 }
83
84 ProcHandle
85 runInteractiveProcess (char *const args[], 
86                        char *workingDirectory, char **environment,
87                        int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)
88 {
89     int pid;
90     int fdStdInput[2], fdStdOutput[2], fdStdError[2];
91
92     pipe(fdStdInput);
93     pipe(fdStdOutput);
94     pipe(fdStdError);
95
96     switch(pid = fork())
97     {
98     case -1:
99         close(fdStdInput[0]);
100         close(fdStdInput[1]);
101         close(fdStdOutput[0]);
102         close(fdStdOutput[1]);
103         close(fdStdError[0]);
104         close(fdStdError[1]);
105         return -1;
106         
107     case 0:
108     {
109         pPrPr_disableITimers();
110         
111         if (workingDirectory) {
112             if (chdir (workingDirectory) < 0) {
113                 return -1;
114             }
115         }
116         
117         if (fdStdInput[0] != STDIN_FILENO) {
118             dup2 (fdStdInput[0], STDIN_FILENO);
119             close(fdStdInput[0]);
120         }
121
122         if (fdStdOutput[1] != STDOUT_FILENO) {
123             dup2 (fdStdOutput[1], STDOUT_FILENO);
124             close(fdStdOutput[1]);
125         }
126
127         if (fdStdError[1] != STDERR_FILENO) {
128             dup2 (fdStdError[1], STDERR_FILENO);
129             close(fdStdError[1]);
130         }
131         
132         close(fdStdInput[1]);
133         close(fdStdOutput[0]);
134         close(fdStdError[0]);
135         
136         /* the child */
137         if (environment) {
138             execvpe(args[0], args, environment);
139         } else {
140             execvp(args[0], args);
141         }
142     }
143     _exit(127);
144     
145     default:
146         close(fdStdInput[0]);
147         close(fdStdOutput[1]);
148         close(fdStdError[1]);
149         
150         *pfdStdInput  = fdStdInput[1];
151         *pfdStdOutput = fdStdOutput[0];
152         *pfdStdError  = fdStdError[0];
153         break;
154     }
155     
156     return pid;
157 }
158
159 int
160 terminateProcess (ProcHandle handle)
161 {
162     return (kill(handle, SIGTERM) == 0);
163 }
164
165 int
166 getProcessExitCode (ProcHandle handle, int *pExitCode)
167 {
168     int wstat, res;
169     
170     *pExitCode = 0;
171     
172     if ((res = waitpid(handle, &wstat, WNOHANG)) > 0)
173     {
174         if (WIFEXITED(wstat))
175         {
176             *pExitCode = WEXITSTATUS(wstat);
177             return 1;
178         }
179         else
180             if (WIFSIGNALED(wstat))
181             {
182                 errno = EINTR;
183                 return -1;
184             }
185             else
186             {
187                 /* This should never happen */
188             }
189     }
190     
191     if (res == 0) return 0;
192
193     if (errno == ECHILD) 
194     {
195             *pExitCode = 0;
196             return 1;
197     }
198
199     return -1;
200 }
201
202 int waitForProcess (ProcHandle handle)
203 {
204     int wstat;
205     
206     while (waitpid(handle, &wstat, 0) < 0)
207     {
208         if (errno != EINTR)
209         {
210             return -1;
211         }
212     }
213     
214     if (WIFEXITED(wstat))
215         return WEXITSTATUS(wstat);
216     else
217         if (WIFSIGNALED(wstat))
218         {
219             errno = EINTR;
220         }
221         else
222         {
223             /* This should never happen */
224         }
225     
226     return -1;
227 }
228
229 #else
230 /* ----------------------------------------------------------------------------
231    Win32 versions
232    ------------------------------------------------------------------------- */
233
234 /* -------------------- WINDOWS VERSION --------------------- */
235
236 /* This is the error table that defines the mapping between OS error
237    codes and errno values */
238
239 struct errentry {
240         unsigned long oscode;           /* OS return value */
241         int errnocode;  /* System V error code */
242 };
243
244 static struct errentry errtable[] = {
245         {  ERROR_INVALID_FUNCTION,       EINVAL    },  /* 1 */
246         {  ERROR_FILE_NOT_FOUND,         ENOENT    },  /* 2 */
247         {  ERROR_PATH_NOT_FOUND,         ENOENT    },  /* 3 */
248         {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },  /* 4 */
249         {  ERROR_ACCESS_DENIED,          EACCES    },  /* 5 */
250         {  ERROR_INVALID_HANDLE,         EBADF     },  /* 6 */
251         {  ERROR_ARENA_TRASHED,          ENOMEM    },  /* 7 */
252         {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },  /* 8 */
253         {  ERROR_INVALID_BLOCK,          ENOMEM    },  /* 9 */
254         {  ERROR_BAD_ENVIRONMENT,        E2BIG     },  /* 10 */
255         {  ERROR_BAD_FORMAT,             ENOEXEC   },  /* 11 */
256         {  ERROR_INVALID_ACCESS,         EINVAL    },  /* 12 */
257         {  ERROR_INVALID_DATA,           EINVAL    },  /* 13 */
258         {  ERROR_INVALID_DRIVE,          ENOENT    },  /* 15 */
259         {  ERROR_CURRENT_DIRECTORY,      EACCES    },  /* 16 */
260         {  ERROR_NOT_SAME_DEVICE,        EXDEV     },  /* 17 */
261         {  ERROR_NO_MORE_FILES,          ENOENT    },  /* 18 */
262         {  ERROR_LOCK_VIOLATION,         EACCES    },  /* 33 */
263         {  ERROR_BAD_NETPATH,            ENOENT    },  /* 53 */
264         {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },  /* 65 */
265         {  ERROR_BAD_NET_NAME,           ENOENT    },  /* 67 */
266         {  ERROR_FILE_EXISTS,            EEXIST    },  /* 80 */
267         {  ERROR_CANNOT_MAKE,            EACCES    },  /* 82 */
268         {  ERROR_FAIL_I24,               EACCES    },  /* 83 */
269         {  ERROR_INVALID_PARAMETER,      EINVAL    },  /* 87 */
270         {  ERROR_NO_PROC_SLOTS,          EAGAIN    },  /* 89 */
271         {  ERROR_DRIVE_LOCKED,           EACCES    },  /* 108 */
272         {  ERROR_BROKEN_PIPE,            EPIPE     },  /* 109 */
273         {  ERROR_DISK_FULL,              ENOSPC    },  /* 112 */
274         {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },  /* 114 */
275         {  ERROR_INVALID_HANDLE,         EINVAL    },  /* 124 */
276         {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },  /* 128 */
277         {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },  /* 129 */
278         {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },  /* 130 */
279         {  ERROR_NEGATIVE_SEEK,          EINVAL    },  /* 131 */
280         {  ERROR_SEEK_ON_DEVICE,         EACCES    },  /* 132 */
281         {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },  /* 145 */
282         {  ERROR_NOT_LOCKED,             EACCES    },  /* 158 */
283         {  ERROR_BAD_PATHNAME,           ENOENT    },  /* 161 */
284         {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },  /* 164 */
285         {  ERROR_LOCK_FAILED,            EACCES    },  /* 167 */
286         {  ERROR_ALREADY_EXISTS,         EEXIST    },  /* 183 */
287         {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },  /* 206 */
288         {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },  /* 215 */
289         {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }    /* 1816 */
290 };
291
292 /* size of the table */
293 #define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
294
295 /* The following two constants must be the minimum and maximum
296    values in the (contiguous) range of Exec Failure errors. */
297 #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
298 #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
299
300 /* These are the low and high value in the range of errors that are
301    access violations */
302 #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
303 #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
304
305 static void maperrno (void)
306 {
307         int i;
308         DWORD dwErrorCode;
309
310         dwErrorCode = GetLastError();
311
312         /* check the table for the OS error code */
313         for (i = 0; i < ERRTABLESIZE; ++i)
314         {
315                 if (dwErrorCode == errtable[i].oscode)
316                 {
317                         errno = errtable[i].errnocode;
318                         return;
319                 }
320         }
321
322         /* The error code wasn't in the table.  We check for a range of */
323         /* EACCES errors or exec failure errors (ENOEXEC).  Otherwise   */
324         /* EINVAL is returned.                                          */
325
326         if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE)
327                 errno = EACCES;
328         else
329                 if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR)
330                         errno = ENOEXEC;
331                 else
332                         errno = EINVAL;
333 }
334
335 /*
336  * Function: mkAnonPipe
337  *
338  * Purpose:  create an anonymous pipe with read and write ends being
339  *           optionally (non-)inheritable.
340  */
341 static BOOL
342 mkAnonPipe (HANDLE* pHandleIn, BOOL isInheritableIn, 
343             HANDLE* pHandleOut, BOOL isInheritableOut)
344 {
345         HANDLE hTemporaryIn  = NULL;
346         HANDLE hTemporaryOut = NULL;
347         BOOL status;
348         SECURITY_ATTRIBUTES sec_attrs;
349
350         /* Create inheritable security attributes */
351         sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
352         sec_attrs.lpSecurityDescriptor = NULL;
353         sec_attrs.bInheritHandle = TRUE;
354
355         /* Create the anon pipe with both ends inheritable */
356         if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, &sec_attrs, 0))
357         {
358                 maperrno();
359                 *pHandleIn  = NULL;
360                 *pHandleOut = NULL;
361                 return FALSE;
362         }
363
364         if (isInheritableIn)
365                 *pHandleIn = hTemporaryIn;
366         else
367         {
368                 /* Make the read end non-inheritable */
369                 status = DuplicateHandle(GetCurrentProcess(), hTemporaryIn,
370                               GetCurrentProcess(), pHandleIn,
371                               0,
372                               FALSE, /* non-inheritable */
373                               DUPLICATE_SAME_ACCESS);
374                 CloseHandle(hTemporaryIn);
375                 if (!status)
376                 {
377                         maperrno();
378                         *pHandleIn  = NULL;
379                         *pHandleOut = NULL;
380                         CloseHandle(hTemporaryOut);
381                         return FALSE;
382                 }
383         }
384
385         if (isInheritableOut)
386                 *pHandleOut = hTemporaryOut;
387         else
388         {
389                 /* Make the write end non-inheritable */
390                 status = DuplicateHandle(GetCurrentProcess(), hTemporaryOut,
391                               GetCurrentProcess(), pHandleOut,
392                               0,
393                               FALSE, /* non-inheritable */
394                               DUPLICATE_SAME_ACCESS);
395                 CloseHandle(hTemporaryOut);
396                 if (!status)
397                 {
398                         maperrno();
399                         *pHandleIn  = NULL;
400                         *pHandleOut = NULL;
401                         CloseHandle(*pHandleIn);
402                 return FALSE;
403         }
404         }
405
406         return TRUE;
407 }
408
409 ProcHandle
410 runProcess (char *cmd, char *workingDirectory, void *environment,
411             int fdStdInput, int fdStdOutput, int fdStdError)
412 {
413         STARTUPINFO sInfo;
414         PROCESS_INFORMATION pInfo;
415         DWORD flags;
416         char buffer[256];
417
418         ZeroMemory(&sInfo, sizeof(sInfo));
419         sInfo.cb = sizeof(sInfo);       
420         sInfo.hStdInput = (HANDLE) _get_osfhandle(fdStdInput);
421         sInfo.hStdOutput= (HANDLE) _get_osfhandle(fdStdOutput);
422         sInfo.hStdError = (HANDLE) _get_osfhandle(fdStdError);
423
424         if (sInfo.hStdInput == INVALID_HANDLE_VALUE)
425                 sInfo.hStdInput = NULL;
426         if (sInfo.hStdOutput == INVALID_HANDLE_VALUE)
427                 sInfo.hStdOutput = NULL;
428         if (sInfo.hStdError == INVALID_HANDLE_VALUE)
429                 sInfo.hStdError = NULL;
430
431         if (sInfo.hStdInput || sInfo.hStdOutput || sInfo.hStdError)
432                 sInfo.dwFlags = STARTF_USESTDHANDLES;
433
434         if (sInfo.hStdInput  != GetStdHandle(STD_INPUT_HANDLE)  &&
435             sInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE) &&
436             sInfo.hStdError  != GetStdHandle(STD_ERROR_HANDLE))
437                 flags = CREATE_NO_WINDOW;   // Run without console window only when both output and error are redirected
438         else
439                 flags = 0;
440
441         if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, environment, workingDirectory, &sInfo, &pInfo))
442         {
443                 maperrno();
444                 return -1;
445         }
446
447         CloseHandle(pInfo.hThread);
448         return (ProcHandle)pInfo.hProcess;
449 }
450
451 ProcHandle
452 runInteractiveProcess (char *cmd, char *workingDirectory, void *environment,
453                        int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)
454 {
455         STARTUPINFO sInfo;
456         PROCESS_INFORMATION pInfo;
457         HANDLE hStdInputRead,  hStdInputWrite;
458         HANDLE hStdOutputRead, hStdOutputWrite;
459         HANDLE hStdErrorRead,  hStdErrorWrite;
460
461         if (!mkAnonPipe(&hStdInputRead,  TRUE, &hStdInputWrite,  FALSE))
462                 return -1;
463
464         if (!mkAnonPipe(&hStdOutputRead, FALSE, &hStdOutputWrite, TRUE))
465         {
466                 CloseHandle(hStdInputRead);
467                 CloseHandle(hStdInputWrite);
468                 return -1;
469         }
470
471         if (!mkAnonPipe(&hStdErrorRead,  FALSE, &hStdErrorWrite,  TRUE))
472         {
473                 CloseHandle(hStdInputRead);
474                 CloseHandle(hStdInputWrite);
475                 CloseHandle(hStdOutputRead);
476                 CloseHandle(hStdOutputWrite);
477                 return -1;
478         }
479
480         ZeroMemory(&sInfo, sizeof(sInfo));
481         sInfo.cb = sizeof(sInfo);
482         sInfo.dwFlags = STARTF_USESTDHANDLES;
483         sInfo.hStdInput = hStdInputRead;
484         sInfo.hStdOutput= hStdOutputWrite;
485         sInfo.hStdError = hStdErrorWrite;
486
487         if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, environment, workingDirectory, &sInfo, &pInfo))
488         {
489                 maperrno();
490                 CloseHandle(hStdInputRead);
491                 CloseHandle(hStdInputWrite);
492                 CloseHandle(hStdOutputRead);
493                 CloseHandle(hStdOutputWrite);
494                 CloseHandle(hStdErrorRead);
495                 CloseHandle(hStdErrorWrite);
496                 return -1;
497         }
498         CloseHandle(pInfo.hThread);
499
500         // Close the ends of the pipes that were inherited by the
501         // child process.  This is important, otherwise we won't see
502         // EOF on these pipes when the child process exits.
503         CloseHandle(hStdInputRead);
504         CloseHandle(hStdOutputWrite);
505         CloseHandle(hStdErrorWrite);
506
507         *pfdStdInput  = _open_osfhandle((intptr_t) hStdInputWrite, _O_WRONLY);
508         *pfdStdOutput = _open_osfhandle((intptr_t) hStdOutputRead, _O_RDONLY);
509         *pfdStdError  = _open_osfhandle((intptr_t) hStdErrorRead, _O_RDONLY);
510
511         return (int) pInfo.hProcess;
512 }
513
514 int
515 terminateProcess (ProcHandle handle)
516 {
517     if (!TerminateProcess((HANDLE) handle, 1)) {
518         maperrno();
519         return -1;
520     }
521
522     CloseHandle((HANDLE) handle);
523     return 0;
524 }
525
526 int
527 getProcessExitCode (ProcHandle handle, int *pExitCode)
528 {
529     *pExitCode = 0;
530
531     if (WaitForSingleObject((HANDLE) handle, 1) == WAIT_OBJECT_0)
532     {
533         if (GetExitCodeProcess((HANDLE) handle, (DWORD *) pExitCode) == 0)
534         {
535             maperrno();
536             return -1;
537         }
538         
539         CloseHandle((HANDLE) handle);
540         return 1;
541     }
542     
543     return 0;
544 }
545
546 int
547 waitForProcess (ProcHandle handle)
548 {
549     DWORD retCode;
550
551     if (WaitForSingleObject((HANDLE) handle, INFINITE) == WAIT_OBJECT_0)
552     {
553         if (GetExitCodeProcess((HANDLE) handle, &retCode) == 0)
554         {
555             maperrno();
556             return -1;
557         }
558         
559         CloseHandle((HANDLE) handle);
560         return retCode;
561     }
562     
563     maperrno();
564     return -1;
565 }
566
567 #endif /* Win32 */