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