[project @ 2004-01-06 12:40:00 by simonmar]
[haskell-directory.git] / cbits / rawSystem.c
1 /* 
2  * (c) The University of Glasgow 1994-2003
3  *
4  * shell-less system Runtime Support (see System.Cmd.rawSystem).
5  */
6
7 /* The itimer stuff in this module is non-posix */
8 /* #include "PosixSource.h" */
9
10 #include "config.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #ifdef HAVE_ERRNO_H
19 #include <errno.h>
20 #endif
21 #ifdef HAVE_SYS_WAIT_H
22 #include <sys/wait.h>
23 #endif
24
25 # ifdef TIME_WITH_SYS_TIME
26 #  include <sys/time.h>
27 #  include <time.h>
28 # else
29 #  ifdef HAVE_SYS_TIME_H
30 #   include <sys/time.h>
31 #  else
32 #   include <time.h>
33 #  endif
34 # endif
35
36 #include "HsFFI.h"
37
38 #if defined(mingw32_TARGET_OS)
39 #include <windows.h>
40 #endif
41
42 #ifdef HAVE_VFORK_H
43 #include <vfork.h>
44 #endif
45
46 #ifdef HAVE_VFORK
47 #define fork vfork
48 #endif
49
50 #if defined(mingw32_TARGET_OS)
51 /* -------------------- WINDOWS VERSION --------------------- */
52
53 HsInt
54 rawSystem(HsAddr cmd)
55 {
56   STARTUPINFO sInfo;
57   PROCESS_INFORMATION pInfo;
58   DWORD retCode;
59
60   ZeroMemory(&sInfo, sizeof(sInfo));
61   sInfo.cb = sizeof(sInfo);
62
63   if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &sInfo, &pInfo)) {
64     /* The 'TRUE' says that the created process should share
65        handles with the current process.  This is vital to ensure
66        that error messages sent to stderr actually appear on the screen.
67        Since we are going to wait for the process to terminate anyway,
68        there is no problem with such sharing. */
69
70       return -1;
71   }
72   WaitForSingleObject(pInfo.hProcess, INFINITE);
73   if (GetExitCodeProcess(pInfo.hProcess, &retCode) == 0) return -1;
74
75   CloseHandle(pInfo.hProcess);
76   CloseHandle(pInfo.hThread);
77   return retCode;
78 }
79
80 #else
81 /* -------------------- UNIX VERSION --------------------- */
82
83 HsInt
84 rawSystem(HsAddr cmd, HsAddr args)
85 {
86     int pid;
87     int wstat;
88
89     switch(pid = fork()) {
90     case -1:
91         {
92             return -1;
93         }
94     case 0:
95       {
96 #ifdef HAVE_SETITIMER
97         /* Reset the itimers in the child, so it doesn't get plagued
98          * by SIGVTALRM interrupts.
99          */
100         struct timeval tv_null = { 0, 0 };
101         struct itimerval itv;
102         itv.it_interval = tv_null;
103         itv.it_value = tv_null;
104         setitimer(ITIMER_REAL, &itv, NULL);
105         setitimer(ITIMER_VIRTUAL, &itv, NULL);
106         setitimer(ITIMER_PROF, &itv, NULL);
107 #endif
108
109         /* the child */
110         execvp(cmd, args);
111         _exit(127);
112       }
113     }
114
115     while (waitpid(pid, &wstat, 0) < 0) {
116         if (errno != EINTR) {
117             return -1;
118         }
119     }
120
121     if (WIFEXITED(wstat))
122         return WEXITSTATUS(wstat);
123     else if (WIFSIGNALED(wstat)) {
124         errno = EINTR;
125     }
126     else {
127         /* This should never happen */
128     }
129     return -1;
130 }
131 #endif