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