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