[project @ 2004-09-01 09:47:31 by simonmar]
[ghc-base.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       errno = EINVAL; // ToDo: wrong, caller should use GetLastError()
80       return -1;
81   }
82   WaitForSingleObject(pInfo.hProcess, INFINITE);
83   if (GetExitCodeProcess(pInfo.hProcess, &retCode) == 0) {
84       errno = EINVAL; // ToDo: wrong, caller should use GetLastError()
85       return -1;
86   }
87
88   CloseHandle(pInfo.hProcess);
89   CloseHandle(pInfo.hThread);
90   return retCode;
91 }
92
93 #else
94 /* -------------------- UNIX VERSION --------------------- */
95
96 HsInt
97 rawSystem(HsAddr cmd, HsAddr args)
98 {
99     int pid;
100     int wstat;
101
102     switch(pid = fork()) {
103     case -1:
104         {
105             return -1;
106         }
107     case 0:
108       {
109 #ifdef HAVE_SETITIMER
110         /* Reset the itimers in the child, so it doesn't get plagued
111          * by SIGVTALRM interrupts.
112          */
113         struct timeval tv_null = { 0, 0 };
114         struct itimerval itv;
115         itv.it_interval = tv_null;
116         itv.it_value = tv_null;
117         setitimer(ITIMER_REAL, &itv, NULL);
118         setitimer(ITIMER_VIRTUAL, &itv, NULL);
119         setitimer(ITIMER_PROF, &itv, NULL);
120 #endif
121
122         /* the child */
123         execvp(cmd, args);
124         _exit(127);
125       }
126     }
127
128     while (waitpid(pid, &wstat, 0) < 0) {
129         if (errno != EINTR) {
130             return -1;
131         }
132     }
133
134     if (WIFEXITED(wstat))
135         return WEXITSTATUS(wstat);
136     else if (WIFSIGNALED(wstat)) {
137         errno = EINTR;
138     }
139     else {
140         /* This should never happen */
141     }
142     return -1;
143 }
144 #endif