add install-includes: field
[packages/pretty.git] / cbits / runProcess.c
index 8358605..93aa8c4 100644 (file)
-/* ----------------------------------------------------------------------------\r
-   (c) The University of Glasgow 2004\r
-   \r
-   Support for System.Process\r
-   ------------------------------------------------------------------------- */\r
-\r
-#include "HsBase.h"\r
-\r
-#if defined(mingw32_HOST_OS)\r
-#include <windows.h>\r
-#include <stdlib.h>\r
-#endif\r
-\r
-#ifdef HAVE_VFORK_H\r
-#include <vfork.h>\r
-#endif\r
-\r
-#ifdef HAVE_VFORK\r
-#define fork vfork\r
-#endif\r
-\r
-#ifdef HAVE_SIGNAL_H\r
-#include <signal.h>\r
-#endif\r
-\r
-#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)\r
-/* ----------------------------------------------------------------------------\r
-   UNIX versions\r
-   ------------------------------------------------------------------------- */\r
-\r
-ProcHandle\r
-runProcess (char *const args[], char *workingDirectory, char **environment, \r
-           int fdStdInput, int fdStdOutput, int fdStdError,\r
-           int set_inthandler, long inthandler, \r
-           int set_quithandler, long quithandler)\r
-{\r
-    int pid;\r
-    struct sigaction dfl;\r
-\r
-    switch(pid = fork())\r
-    {\r
-    case -1:\r
-       return -1;\r
-       \r
-    case 0:\r
-    {\r
-       pPrPr_disableITimers();\r
-       \r
-       if (workingDirectory) {\r
-           chdir (workingDirectory);\r
-       }\r
-       \r
-       /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested \r
-        */\r
-        (void)sigemptyset(&dfl.sa_mask);\r
-        dfl.sa_flags = 0;\r
-       if (set_inthandler) {\r
-           dfl.sa_handler = (void *)inthandler;\r
-           (void)sigaction(SIGINT, &dfl, NULL);\r
-       }\r
-       if (set_quithandler) {\r
-           dfl.sa_handler = (void *)quithandler;\r
-           (void)sigaction(SIGQUIT,  &dfl, NULL);\r
-       }\r
-\r
-       dup2 (fdStdInput,  STDIN_FILENO);\r
-       dup2 (fdStdOutput, STDOUT_FILENO);\r
-       dup2 (fdStdError,  STDERR_FILENO);\r
-       \r
-       if (environment) {\r
-           execvpe(args[0], args, environment);\r
-       } else {\r
-           execvp(args[0], args);\r
-       }\r
-    }\r
-    _exit(127);\r
-    }\r
-    \r
-    return pid;\r
-}\r
-\r
-ProcHandle\r
-runInteractiveProcess (char *const args[], \r
-                      char *workingDirectory, char **environment,\r
-                      int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)\r
-{\r
-    int pid;\r
-    int fdStdInput[2], fdStdOutput[2], fdStdError[2];\r
-\r
-    pipe(fdStdInput);\r
-    pipe(fdStdOutput);\r
-    pipe(fdStdError);\r
-\r
-    switch(pid = fork())\r
-    {\r
-    case -1:\r
-       close(fdStdInput[0]);\r
-       close(fdStdInput[1]);\r
-       close(fdStdOutput[0]);\r
-       close(fdStdOutput[1]);\r
-       close(fdStdError[0]);\r
-       close(fdStdError[1]);\r
-       return -1;\r
-       \r
-    case 0:\r
-    {\r
-       pPrPr_disableITimers();\r
-       \r
-       if (workingDirectory) {\r
-           chdir (workingDirectory);\r
-       }\r
-       \r
-       dup2 (fdStdInput[0], STDIN_FILENO);\r
-       dup2 (fdStdOutput[1], STDOUT_FILENO);\r
-       dup2 (fdStdError[1], STDERR_FILENO);\r
-       \r
-       close(fdStdInput[0]);\r
-       close(fdStdInput[1]);\r
-       close(fdStdOutput[0]);\r
-       close(fdStdOutput[1]);\r
-       close(fdStdError[0]);\r
-       close(fdStdError[1]);\r
-       \r
-       /* the child */\r
-       if (environment) {\r
-           execvpe(args[0], args, environment);\r
-       } else {\r
-           execvp(args[0], args);\r
-       }\r
-    }\r
-    _exit(127);\r
-    \r
-    default:\r
-       close(fdStdInput[0]);\r
-       close(fdStdOutput[1]);\r
-       close(fdStdError[1]);\r
-       \r
-       *pfdStdInput  = fdStdInput[1];\r
-       *pfdStdOutput = fdStdOutput[0];\r
-       *pfdStdError  = fdStdError[0];\r
-       break;\r
-    }\r
-    \r
-    return pid;\r
-}\r
-\r
-int\r
-terminateProcess (ProcHandle handle)\r
-{\r
-    return (kill(handle, SIGTERM) == 0);\r
-}\r
-\r
-int\r
-getProcessExitCode (ProcHandle handle, int *pExitCode)\r
-{\r
-    int wstat;\r
-    \r
-    *pExitCode = 0;\r
-    \r
-    if (waitpid(handle, &wstat, WNOHANG) > 0)\r
-    {\r
-       if (WIFEXITED(wstat))\r
-       {\r
-           *pExitCode = WEXITSTATUS(wstat);\r
-           return 1;\r
-       }\r
-       else\r
-           if (WIFSIGNALED(wstat))\r
-           {\r
-               errno = EINTR;\r
-               return -1;\r
-           }\r
-           else\r
-           {\r
-               /* This should never happen */\r
-           }\r
-    }\r
-    \r
-    return 0;\r
-}\r
-\r
-int waitForProcess (ProcHandle handle)\r
-{\r
-    int wstat;\r
-    \r
-    while (waitpid(handle, &wstat, 0) < 0)\r
-    {\r
-       if (errno != EINTR)\r
-       {\r
-           return -1;\r
-       }\r
-    }\r
-    \r
-    if (WIFEXITED(wstat))\r
-       return WEXITSTATUS(wstat);\r
-    else\r
-       if (WIFSIGNALED(wstat))\r
-       {\r
-           errno = EINTR;\r
-       }\r
-       else\r
-       {\r
-           /* This should never happen */\r
-       }\r
-    \r
-    return -1;\r
-}\r
-\r
-#else\r
-/* ----------------------------------------------------------------------------\r
-   Win32 versions\r
-   ------------------------------------------------------------------------- */\r
-\r
-/* -------------------- WINDOWS VERSION --------------------- */\r
-\r
-/* This is the error table that defines the mapping between OS error\r
-   codes and errno values */\r
-\r
-struct errentry {\r
-        unsigned long oscode;           /* OS return value */\r
-        int errnocode;  /* System V error code */\r
-};\r
-\r
-static struct errentry errtable[] = {\r
-        {  ERROR_INVALID_FUNCTION,       EINVAL    },  /* 1 */\r
-        {  ERROR_FILE_NOT_FOUND,         ENOENT    },  /* 2 */\r
-        {  ERROR_PATH_NOT_FOUND,         ENOENT    },  /* 3 */\r
-        {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },  /* 4 */\r
-        {  ERROR_ACCESS_DENIED,          EACCES    },  /* 5 */\r
-        {  ERROR_INVALID_HANDLE,         EBADF     },  /* 6 */\r
-        {  ERROR_ARENA_TRASHED,          ENOMEM    },  /* 7 */\r
-        {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },  /* 8 */\r
-        {  ERROR_INVALID_BLOCK,          ENOMEM    },  /* 9 */\r
-        {  ERROR_BAD_ENVIRONMENT,        E2BIG     },  /* 10 */\r
-        {  ERROR_BAD_FORMAT,             ENOEXEC   },  /* 11 */\r
-        {  ERROR_INVALID_ACCESS,         EINVAL    },  /* 12 */\r
-        {  ERROR_INVALID_DATA,           EINVAL    },  /* 13 */\r
-        {  ERROR_INVALID_DRIVE,          ENOENT    },  /* 15 */\r
-        {  ERROR_CURRENT_DIRECTORY,      EACCES    },  /* 16 */\r
-        {  ERROR_NOT_SAME_DEVICE,        EXDEV     },  /* 17 */\r
-        {  ERROR_NO_MORE_FILES,          ENOENT    },  /* 18 */\r
-        {  ERROR_LOCK_VIOLATION,         EACCES    },  /* 33 */\r
-        {  ERROR_BAD_NETPATH,            ENOENT    },  /* 53 */\r
-        {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },  /* 65 */\r
-        {  ERROR_BAD_NET_NAME,           ENOENT    },  /* 67 */\r
-        {  ERROR_FILE_EXISTS,            EEXIST    },  /* 80 */\r
-        {  ERROR_CANNOT_MAKE,            EACCES    },  /* 82 */\r
-        {  ERROR_FAIL_I24,               EACCES    },  /* 83 */\r
-        {  ERROR_INVALID_PARAMETER,      EINVAL    },  /* 87 */\r
-        {  ERROR_NO_PROC_SLOTS,          EAGAIN    },  /* 89 */\r
-        {  ERROR_DRIVE_LOCKED,           EACCES    },  /* 108 */\r
-        {  ERROR_BROKEN_PIPE,            EPIPE     },  /* 109 */\r
-        {  ERROR_DISK_FULL,              ENOSPC    },  /* 112 */\r
-        {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },  /* 114 */\r
-        {  ERROR_INVALID_HANDLE,         EINVAL    },  /* 124 */\r
-        {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },  /* 128 */\r
-        {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },  /* 129 */\r
-        {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },  /* 130 */\r
-        {  ERROR_NEGATIVE_SEEK,          EINVAL    },  /* 131 */\r
-        {  ERROR_SEEK_ON_DEVICE,         EACCES    },  /* 132 */\r
-        {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },  /* 145 */\r
-        {  ERROR_NOT_LOCKED,             EACCES    },  /* 158 */\r
-        {  ERROR_BAD_PATHNAME,           ENOENT    },  /* 161 */\r
-        {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },  /* 164 */\r
-        {  ERROR_LOCK_FAILED,            EACCES    },  /* 167 */\r
-        {  ERROR_ALREADY_EXISTS,         EEXIST    },  /* 183 */\r
-        {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },  /* 206 */\r
-        {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },  /* 215 */\r
-        {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }    /* 1816 */\r
-};\r
-\r
-/* size of the table */\r
-#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))\r
-\r
-/* The following two constants must be the minimum and maximum\r
-   values in the (contiguous) range of Exec Failure errors. */\r
-#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG\r
-#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN\r
-\r
-/* These are the low and high value in the range of errors that are\r
-   access violations */\r
-#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT\r
-#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED\r
-\r
-static void maperrno (void)\r
-{\r
-       int i;\r
-       DWORD dwErrorCode;\r
-\r
-       dwErrorCode = GetLastError();\r
-\r
-       /* check the table for the OS error code */\r
-       for (i = 0; i < ERRTABLESIZE; ++i)\r
-       {\r
-               if (dwErrorCode == errtable[i].oscode)\r
-               {\r
-                       errno = errtable[i].errnocode;\r
-                       return;\r
-               }\r
-       }\r
-\r
-       /* The error code wasn't in the table.  We check for a range of */\r
-       /* EACCES errors or exec failure errors (ENOEXEC).  Otherwise   */\r
-       /* EINVAL is returned.                                          */\r
-\r
-       if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE)\r
-               errno = EACCES;\r
-       else\r
-               if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR)\r
-                       errno = ENOEXEC;\r
-               else\r
-                       errno = EINVAL;\r
-}\r
-\r
-/*\r
- * Function: mkAnonPipe\r
- *\r
- * Purpose:  create an anonymous pipe with read and write ends being\r
- *           optionally (non-)inheritable.\r
- */\r
-static BOOL\r
-mkAnonPipe (HANDLE* pHandleIn, BOOL isInheritableIn, \r
-           HANDLE* pHandleOut, BOOL isInheritableOut)\r
-{\r
-       HANDLE hTemporaryIn  = NULL;\r
-       HANDLE hTemporaryOut = NULL;\r
-       BOOL status;\r
-       SECURITY_ATTRIBUTES sec_attrs;\r
-\r
-       /* Create inheritable security attributes */\r
-       sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);\r
-       sec_attrs.lpSecurityDescriptor = NULL;\r
-       sec_attrs.bInheritHandle = TRUE;\r
-\r
-       /* Create the anon pipe with both ends inheritable */\r
-       if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, &sec_attrs, 0))\r
-       {\r
-               maperrno();\r
-               *pHandleIn  = NULL;\r
-               *pHandleOut = NULL;\r
-               return FALSE;\r
-       }\r
-\r
-       if (isInheritableIn)\r
-               *pHandleIn = hTemporaryIn;\r
-       else\r
-       {\r
-               /* Make the read end non-inheritable */\r
-               status = DuplicateHandle(GetCurrentProcess(), hTemporaryIn,\r
-                             GetCurrentProcess(), pHandleIn,\r
-                             0,\r
-                             FALSE, /* non-inheritable */\r
-                             DUPLICATE_SAME_ACCESS);\r
-               CloseHandle(hTemporaryIn);\r
-               if (!status)\r
-               {\r
-                       maperrno();\r
-                       *pHandleIn  = NULL;\r
-                       *pHandleOut = NULL;\r
-                       CloseHandle(hTemporaryOut);\r
-                       return FALSE;\r
-               }\r
-       }\r
-\r
-       if (isInheritableOut)\r
-               *pHandleOut = hTemporaryOut;\r
-       else\r
-       {\r
-               /* Make the write end non-inheritable */\r
-               status = DuplicateHandle(GetCurrentProcess(), hTemporaryOut,\r
-                             GetCurrentProcess(), pHandleOut,\r
-                             0,\r
-                             FALSE, /* non-inheritable */\r
-                             DUPLICATE_SAME_ACCESS);\r
-               CloseHandle(hTemporaryOut);\r
-               if (!status)\r
-               {\r
-                       maperrno();\r
-                       *pHandleIn  = NULL;\r
-                       *pHandleOut = NULL;\r
-                       CloseHandle(*pHandleIn);\r
-               return FALSE;\r
-       }\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-ProcHandle\r
-runProcess (char *cmd, char *workingDirectory, void *environment,\r
-           int fdStdInput, int fdStdOutput, int fdStdError)\r
-{\r
-       STARTUPINFO sInfo;\r
-       PROCESS_INFORMATION pInfo;\r
-       DWORD flags;\r
-\r
-       ZeroMemory(&sInfo, sizeof(sInfo));\r
-       sInfo.cb = sizeof(sInfo);\r
-       sInfo.dwFlags = STARTF_USESTDHANDLES;\r
-       sInfo.hStdInput = (HANDLE) _get_osfhandle(fdStdInput);\r
-       sInfo.hStdOutput= (HANDLE) _get_osfhandle(fdStdOutput);\r
-       sInfo.hStdError = (HANDLE) _get_osfhandle(fdStdError);\r
-\r
-       if (sInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE) &&\r
-           sInfo.hStdError  != GetStdHandle(STD_ERROR_HANDLE))\r
-               flags = CREATE_NO_WINDOW;   // Run without console window only when both output and error are redirected\r
-       else\r
-               flags = 0;\r
-\r
-       if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, environment, workingDirectory, &sInfo, &pInfo))\r
-       {\r
-               maperrno();\r
-               return -1;\r
-       }\r
-\r
-       CloseHandle(pInfo.hThread);\r
-       return (ProcHandle)pInfo.hProcess;\r
-}\r
-\r
-ProcHandle\r
-runInteractiveProcess (char *cmd, char *workingDirectory, void *environment,\r
-                      int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)\r
-{\r
-       STARTUPINFO sInfo;\r
-       PROCESS_INFORMATION pInfo;\r
-       HANDLE hStdInputRead,  hStdInputWrite;\r
-       HANDLE hStdOutputRead, hStdOutputWrite;\r
-       HANDLE hStdErrorRead,  hStdErrorWrite;\r
-\r
-       if (!mkAnonPipe(&hStdInputRead,  TRUE, &hStdInputWrite,  FALSE))\r
-               return -1;\r
-\r
-       if (!mkAnonPipe(&hStdOutputRead, FALSE, &hStdOutputWrite, TRUE))\r
-       {\r
-               CloseHandle(hStdInputRead);\r
-               CloseHandle(hStdInputWrite);\r
-               return -1;\r
-       }\r
-\r
-       if (!mkAnonPipe(&hStdErrorRead,  FALSE, &hStdErrorWrite,  TRUE))\r
-       {\r
-               CloseHandle(hStdInputRead);\r
-               CloseHandle(hStdInputWrite);\r
-               CloseHandle(hStdOutputRead);\r
-               CloseHandle(hStdOutputWrite);\r
-               return -1;\r
-       }\r
-\r
-       ZeroMemory(&sInfo, sizeof(sInfo));\r
-       sInfo.cb = sizeof(sInfo);\r
-       sInfo.dwFlags = STARTF_USESTDHANDLES;\r
-       sInfo.hStdInput = hStdInputRead;\r
-       sInfo.hStdOutput= hStdOutputWrite;\r
-       sInfo.hStdError = hStdErrorWrite;\r
-\r
-       if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, environment, workingDirectory, &sInfo, &pInfo))\r
-       {\r
-               maperrno();\r
-               CloseHandle(hStdInputRead);\r
-               CloseHandle(hStdInputWrite);\r
-               CloseHandle(hStdOutputRead);\r
-               CloseHandle(hStdOutputWrite);\r
-               CloseHandle(hStdErrorRead);\r
-               CloseHandle(hStdErrorWrite);\r
-               return -1;\r
-       }\r
-       CloseHandle(pInfo.hThread);\r
-\r
-       // Close the ends of the pipes that were inherited by the\r
-       // child process.  This is important, otherwise we won't see\r
-       // EOF on these pipes when the child process exits.\r
-       CloseHandle(hStdInputRead);\r
-       CloseHandle(hStdOutputWrite);\r
-       CloseHandle(hStdErrorWrite);\r
-\r
-       *pfdStdInput  = _open_osfhandle((intptr_t) hStdInputWrite, _O_WRONLY);\r
-       *pfdStdOutput = _open_osfhandle((intptr_t) hStdOutputRead, _O_RDONLY);\r
-       *pfdStdError  = _open_osfhandle((intptr_t) hStdErrorRead, _O_RDONLY);\r
-\r
-       return (int) pInfo.hProcess;\r
-}\r
-\r
-int\r
-terminateProcess (ProcHandle handle)\r
-{\r
-    if (!TerminateProcess((HANDLE) handle, 1)) {\r
-       maperrno();\r
-       return -1;\r
-    }\r
-\r
-    CloseHandle((HANDLE) handle);\r
-    return 0;\r
-}\r
-\r
-int\r
-getProcessExitCode (ProcHandle handle, int *pExitCode)\r
-{\r
-    *pExitCode = 0;\r
-\r
-    if (WaitForSingleObject((HANDLE) handle, 1) == WAIT_OBJECT_0)\r
-    {\r
-       if (GetExitCodeProcess((HANDLE) handle, (DWORD *) pExitCode) == 0)\r
-       {\r
-           maperrno();\r
-           return -1;\r
-       }\r
-       \r
-       CloseHandle((HANDLE) handle);\r
-       return 1;\r
-    }\r
-    \r
-    return 0;\r
-}\r
-\r
-int\r
-waitForProcess (ProcHandle handle)\r
-{\r
-    DWORD retCode;\r
-\r
-    if (WaitForSingleObject((HANDLE) handle, INFINITE) == WAIT_OBJECT_0)\r
-    {\r
-       if (GetExitCodeProcess((HANDLE) handle, &retCode) == 0)\r
-       {\r
-           maperrno();\r
-           return -1;\r
-       }\r
-       \r
-       CloseHandle((HANDLE) handle);\r
-       return retCode;\r
-    }\r
-    \r
-    maperrno();\r
-    return -1;\r
-}\r
-\r
-#endif // Win32\r
+/* ----------------------------------------------------------------------------
+   (c) The University of Glasgow 2004
+   
+   Support for System.Process
+   ------------------------------------------------------------------------- */
+
+#include "HsBase.h"
+
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32)
+#include <windows.h>
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#ifdef HAVE_VFORK
+#define fork vfork
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32))
+/* ----------------------------------------------------------------------------
+   UNIX versions
+   ------------------------------------------------------------------------- */
+
+ProcHandle
+runProcess (char *const args[], char *workingDirectory, char **environment, 
+           int fdStdInput, int fdStdOutput, int fdStdError,
+           int set_inthandler, long inthandler, 
+           int set_quithandler, long quithandler)
+{
+    int pid;
+    struct sigaction dfl;
+
+    switch(pid = fork())
+    {
+    case -1:
+       return -1;
+       
+    case 0:
+    {
+       pPrPr_disableITimers();
+       
+       if (workingDirectory) {
+           if (chdir (workingDirectory) < 0) {
+               return -1;
+           }
+       }
+       
+       /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested 
+        */
+        (void)sigemptyset(&dfl.sa_mask);
+        dfl.sa_flags = 0;
+       if (set_inthandler) {
+           dfl.sa_handler = (void *)inthandler;
+           (void)sigaction(SIGINT, &dfl, NULL);
+       }
+       if (set_quithandler) {
+           dfl.sa_handler = (void *)quithandler;
+           (void)sigaction(SIGQUIT,  &dfl, NULL);
+       }
+
+       dup2 (fdStdInput,  STDIN_FILENO);
+       dup2 (fdStdOutput, STDOUT_FILENO);
+       dup2 (fdStdError,  STDERR_FILENO);
+       
+       if (environment) {
+           execvpe(args[0], args, environment);
+       } else {
+           execvp(args[0], args);
+       }
+    }
+    _exit(127);
+    }
+    
+    return pid;
+}
+
+ProcHandle
+runInteractiveProcess (char *const args[], 
+                      char *workingDirectory, char **environment,
+                      int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)
+{
+    int pid;
+    int fdStdInput[2], fdStdOutput[2], fdStdError[2];
+
+    pipe(fdStdInput);
+    pipe(fdStdOutput);
+    pipe(fdStdError);
+
+    switch(pid = fork())
+    {
+    case -1:
+       close(fdStdInput[0]);
+       close(fdStdInput[1]);
+       close(fdStdOutput[0]);
+       close(fdStdOutput[1]);
+       close(fdStdError[0]);
+       close(fdStdError[1]);
+       return -1;
+       
+    case 0:
+    {
+       pPrPr_disableITimers();
+       
+       if (workingDirectory) {
+           if (chdir (workingDirectory) < 0) {
+               return -1;
+           }
+       }
+       
+       if (fdStdInput[0] != STDIN_FILENO) {
+           dup2 (fdStdInput[0], STDIN_FILENO);
+           close(fdStdInput[0]);
+       }
+
+       if (fdStdOutput[1] != STDOUT_FILENO) {
+           dup2 (fdStdOutput[1], STDOUT_FILENO);
+           close(fdStdOutput[1]);
+       }
+
+       if (fdStdError[1] != STDERR_FILENO) {
+           dup2 (fdStdError[1], STDERR_FILENO);
+           close(fdStdError[1]);
+       }
+       
+       close(fdStdInput[1]);
+       close(fdStdOutput[0]);
+       close(fdStdError[0]);
+       
+       /* the child */
+       if (environment) {
+           execvpe(args[0], args, environment);
+       } else {
+           execvp(args[0], args);
+       }
+    }
+    _exit(127);
+    
+    default:
+       close(fdStdInput[0]);
+       close(fdStdOutput[1]);
+       close(fdStdError[1]);
+       
+       *pfdStdInput  = fdStdInput[1];
+       *pfdStdOutput = fdStdOutput[0];
+       *pfdStdError  = fdStdError[0];
+       break;
+    }
+    
+    return pid;
+}
+
+int
+terminateProcess (ProcHandle handle)
+{
+    return (kill(handle, SIGTERM) == 0);
+}
+
+int
+getProcessExitCode (ProcHandle handle, int *pExitCode)
+{
+    int wstat, res;
+    
+    *pExitCode = 0;
+    
+    if ((res = waitpid(handle, &wstat, WNOHANG)) > 0)
+    {
+       if (WIFEXITED(wstat))
+       {
+           *pExitCode = WEXITSTATUS(wstat);
+           return 1;
+       }
+       else
+           if (WIFSIGNALED(wstat))
+           {
+               errno = EINTR;
+               return -1;
+           }
+           else
+           {
+               /* This should never happen */
+           }
+    }
+    
+    if (res == 0) return 0;
+
+    if (errno == ECHILD) 
+    {
+           *pExitCode = 0;
+           return 1;
+    }
+
+    return -1;
+}
+
+int waitForProcess (ProcHandle handle)
+{
+    int wstat;
+    
+    while (waitpid(handle, &wstat, 0) < 0)
+    {
+       if (errno != EINTR)
+       {
+           return -1;
+       }
+    }
+    
+    if (WIFEXITED(wstat))
+       return WEXITSTATUS(wstat);
+    else
+       if (WIFSIGNALED(wstat))
+       {
+           return wstat;
+       }
+       else
+       {
+           /* This should never happen */
+       }
+    
+    return -1;
+}
+
+#else
+/* ----------------------------------------------------------------------------
+   Win32 versions
+   ------------------------------------------------------------------------- */
+
+/* -------------------- WINDOWS VERSION --------------------- */
+
+/*
+ * Function: mkAnonPipe
+ *
+ * Purpose:  create an anonymous pipe with read and write ends being
+ *           optionally (non-)inheritable.
+ */
+static BOOL
+mkAnonPipe (HANDLE* pHandleIn, BOOL isInheritableIn, 
+           HANDLE* pHandleOut, BOOL isInheritableOut)
+{
+       HANDLE hTemporaryIn  = NULL;
+       HANDLE hTemporaryOut = NULL;
+       BOOL status;
+       SECURITY_ATTRIBUTES sec_attrs;
+
+       /* Create inheritable security attributes */
+       sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
+       sec_attrs.lpSecurityDescriptor = NULL;
+       sec_attrs.bInheritHandle = TRUE;
+
+       /* Create the anon pipe with both ends inheritable */
+       if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, &sec_attrs, 0))
+       {
+               maperrno();
+               *pHandleIn  = NULL;
+               *pHandleOut = NULL;
+               return FALSE;
+       }
+
+       if (isInheritableIn)
+               *pHandleIn = hTemporaryIn;
+       else
+       {
+               /* Make the read end non-inheritable */
+               status = DuplicateHandle(GetCurrentProcess(), hTemporaryIn,
+                             GetCurrentProcess(), pHandleIn,
+                             0,
+                             FALSE, /* non-inheritable */
+                             DUPLICATE_SAME_ACCESS);
+               CloseHandle(hTemporaryIn);
+               if (!status)
+               {
+                       maperrno();
+                       *pHandleIn  = NULL;
+                       *pHandleOut = NULL;
+                       CloseHandle(hTemporaryOut);
+                       return FALSE;
+               }
+       }
+
+       if (isInheritableOut)
+               *pHandleOut = hTemporaryOut;
+       else
+       {
+               /* Make the write end non-inheritable */
+               status = DuplicateHandle(GetCurrentProcess(), hTemporaryOut,
+                             GetCurrentProcess(), pHandleOut,
+                             0,
+                             FALSE, /* non-inheritable */
+                             DUPLICATE_SAME_ACCESS);
+               CloseHandle(hTemporaryOut);
+               if (!status)
+               {
+                       maperrno();
+                       *pHandleIn  = NULL;
+                       *pHandleOut = NULL;
+                       CloseHandle(*pHandleIn);
+               return FALSE;
+       }
+       }
+
+       return TRUE;
+}
+
+ProcHandle
+runProcess (char *cmd, char *workingDirectory, void *environment,
+           int fdStdInput, int fdStdOutput, int fdStdError)
+{
+       STARTUPINFO sInfo;
+       PROCESS_INFORMATION pInfo;
+       DWORD flags;
+
+       ZeroMemory(&sInfo, sizeof(sInfo));
+       sInfo.cb = sizeof(sInfo);       
+       sInfo.hStdInput = (HANDLE) _get_osfhandle(fdStdInput);
+       sInfo.hStdOutput= (HANDLE) _get_osfhandle(fdStdOutput);
+       sInfo.hStdError = (HANDLE) _get_osfhandle(fdStdError);
+
+       if (sInfo.hStdInput == INVALID_HANDLE_VALUE)
+               sInfo.hStdInput = NULL;
+       if (sInfo.hStdOutput == INVALID_HANDLE_VALUE)
+               sInfo.hStdOutput = NULL;
+       if (sInfo.hStdError == INVALID_HANDLE_VALUE)
+               sInfo.hStdError = NULL;
+
+       if (sInfo.hStdInput || sInfo.hStdOutput || sInfo.hStdError)
+               sInfo.dwFlags = STARTF_USESTDHANDLES;
+
+       if (sInfo.hStdInput  != GetStdHandle(STD_INPUT_HANDLE)  &&
+           sInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE) &&
+           sInfo.hStdError  != GetStdHandle(STD_ERROR_HANDLE))
+               flags = CREATE_NO_WINDOW;   // Run without console window only when both output and error are redirected
+       else
+               flags = 0;
+
+       if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, environment, workingDirectory, &sInfo, &pInfo))
+       {
+               maperrno();
+               return -1;
+       }
+
+       CloseHandle(pInfo.hThread);
+       return (ProcHandle)pInfo.hProcess;
+}
+
+ProcHandle
+runInteractiveProcess (char *cmd, char *workingDirectory, void *environment,
+                      int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)
+{
+       STARTUPINFO sInfo;
+       PROCESS_INFORMATION pInfo;
+       HANDLE hStdInputRead,  hStdInputWrite;
+       HANDLE hStdOutputRead, hStdOutputWrite;
+       HANDLE hStdErrorRead,  hStdErrorWrite;
+
+       if (!mkAnonPipe(&hStdInputRead,  TRUE, &hStdInputWrite,  FALSE))
+               return -1;
+
+       if (!mkAnonPipe(&hStdOutputRead, FALSE, &hStdOutputWrite, TRUE))
+       {
+               CloseHandle(hStdInputRead);
+               CloseHandle(hStdInputWrite);
+               return -1;
+       }
+
+       if (!mkAnonPipe(&hStdErrorRead,  FALSE, &hStdErrorWrite,  TRUE))
+       {
+               CloseHandle(hStdInputRead);
+               CloseHandle(hStdInputWrite);
+               CloseHandle(hStdOutputRead);
+               CloseHandle(hStdOutputWrite);
+               return -1;
+       }
+
+       ZeroMemory(&sInfo, sizeof(sInfo));
+       sInfo.cb = sizeof(sInfo);
+       sInfo.dwFlags = STARTF_USESTDHANDLES;
+       sInfo.hStdInput = hStdInputRead;
+       sInfo.hStdOutput= hStdOutputWrite;
+       sInfo.hStdError = hStdErrorWrite;
+
+       if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, environment, workingDirectory, &sInfo, &pInfo))
+       {
+               maperrno();
+               CloseHandle(hStdInputRead);
+               CloseHandle(hStdInputWrite);
+               CloseHandle(hStdOutputRead);
+               CloseHandle(hStdOutputWrite);
+               CloseHandle(hStdErrorRead);
+               CloseHandle(hStdErrorWrite);
+               return -1;
+       }
+       CloseHandle(pInfo.hThread);
+
+       // Close the ends of the pipes that were inherited by the
+       // child process.  This is important, otherwise we won't see
+       // EOF on these pipes when the child process exits.
+       CloseHandle(hStdInputRead);
+       CloseHandle(hStdOutputWrite);
+       CloseHandle(hStdErrorWrite);
+
+       *pfdStdInput  = _open_osfhandle((intptr_t) hStdInputWrite, _O_WRONLY);
+       *pfdStdOutput = _open_osfhandle((intptr_t) hStdOutputRead, _O_RDONLY);
+       *pfdStdError  = _open_osfhandle((intptr_t) hStdErrorRead, _O_RDONLY);
+
+       return (int) pInfo.hProcess;
+}
+
+int
+terminateProcess (ProcHandle handle)
+{
+    if (!TerminateProcess((HANDLE) handle, 1)) {
+       maperrno();
+       return -1;
+    }
+    return 0;
+}
+
+int
+getProcessExitCode (ProcHandle handle, int *pExitCode)
+{
+    *pExitCode = 0;
+
+    if (WaitForSingleObject((HANDLE) handle, 1) == WAIT_OBJECT_0)
+    {
+       if (GetExitCodeProcess((HANDLE) handle, (DWORD *) pExitCode) == 0)
+       {
+           maperrno();
+           return -1;
+       }
+       return 1;
+    }
+    
+    return 0;
+}
+
+int
+waitForProcess (ProcHandle handle)
+{
+    DWORD retCode;
+
+    if (WaitForSingleObject((HANDLE) handle, INFINITE) == WAIT_OBJECT_0)
+    {
+       if (GetExitCodeProcess((HANDLE) handle, &retCode) == 0)
+       {
+           maperrno();
+           return -1;
+       }
+       return retCode;
+    }
+    
+    maperrno();
+    return -1;
+}
+
+#endif /* Win32 */