[project @ 2004-08-13 13:29:00 by simonmar]
[ghc.git] / libraries / base / 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 "ghcconfig.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