[project @ 2002-12-13 14:23:42 by simonmar]
[haskell-directory.git] / cbits / rawSystem.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: rawSystem.c,v 1.1 2002/08/28 13:59:19 simonmar Exp $
5  *
6  * shell-less system Runtime Support
7  */
8
9 /* The itimer stuff in this module is non-posix */
10 /* #include "PosixSource.h" */
11
12 #include "config.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #ifdef HAVE_ERRNO_H
21 #include <errno.h>
22 #endif
23 #ifdef HAVE_SYS_WAIT_H
24 #include <sys/wait.h>
25 #endif
26
27 # ifdef TIME_WITH_SYS_TIME
28 #  include <sys/time.h>
29 #  include <time.h>
30 # else
31 #  ifdef HAVE_SYS_TIME_H
32 #   include <sys/time.h>
33 #  else
34 #   include <time.h>
35 #  endif
36 # endif
37
38 #include "HsFFI.h"
39
40 #if defined(mingw32_TARGET_OS)
41 #include <windows.h>
42 #endif
43
44 HsInt
45 rawSystemCmd(HsAddr cmd)
46 {
47   /* -------------------- WINDOWS VERSION --------------------- */
48 #if defined(mingw32_TARGET_OS)
49   STARTUPINFO sInfo;
50   PROCESS_INFORMATION pInfo;
51   DWORD retCode;
52
53   sInfo.cb              = sizeof(STARTUPINFO);
54   sInfo.lpReserved      = NULL;
55   sInfo.lpReserved2     = NULL;
56   sInfo.cbReserved2     = 0;
57   sInfo.lpDesktop       = NULL;
58   sInfo.lpTitle         = NULL;
59   sInfo.dwFlags         = 0;
60
61   if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &sInfo, &pInfo))
62     /* The 'TRUE' says that the created process should share
63        handles with the current process.  This is vital to ensure
64        that error messages sent to stderr actually appear on the screen.
65        Since we are going to wait for the process to terminate anyway,
66        there is no problem with such sharing. */
67
68     return -1;
69   WaitForSingleObject(pInfo.hProcess, INFINITE);
70   if (GetExitCodeProcess(pInfo.hProcess, &retCode) == 0) return -1;
71   CloseHandle(pInfo.hProcess);
72   CloseHandle(pInfo.hThread);
73   return retCode;
74
75 #else
76   /* -------------------- UNIX VERSION --------------------- */
77     int pid;
78     int wstat;
79
80     switch(pid = fork()) {
81     case -1:
82         if (errno != EINTR) {
83             return -1;
84         }
85     case 0:
86       {
87 #ifdef HAVE_SETITIMER
88         /* Reset the itimers in the child, so it doesn't get plagued
89          * by SIGVTALRM interrupts.
90          */
91         struct timeval tv_null = { 0, 0 };
92         struct itimerval itv;
93         itv.it_interval = tv_null;
94         itv.it_value = tv_null;
95         setitimer(ITIMER_REAL, &itv, NULL);
96         setitimer(ITIMER_VIRTUAL, &itv, NULL);
97         setitimer(ITIMER_PROF, &itv, NULL);
98 #endif
99
100         /* the child */
101         execl(cmd, NULL);
102         _exit(127);
103       }
104     }
105
106     while (waitpid(pid, &wstat, 0) < 0) {
107         if (errno != EINTR) {
108             return -1;
109         }
110     }
111
112     if (WIFEXITED(wstat))
113         return WEXITSTATUS(wstat);
114     else if (WIFSIGNALED(wstat)) {
115         errno = EINTR;
116     }
117     else {
118         /* This should never happen */
119     }
120     return -1;
121 #endif
122 }