From: panne Date: Sun, 27 Mar 2005 13:41:19 +0000 (+0000) Subject: [project @ 2005-03-27 13:41:19 by panne] X-Git-Tag: arity-anal-branch-point~15 X-Git-Url: http://git.megacz.com/?p=ghc-base.git;a=commitdiff_plain;h=3457025838609e26918bb0cf5c16393d3bb5b69b [project @ 2005-03-27 13:41:19 by panne] * Some preprocessors don't like the C99/C++ '//' comments after a directive, so use '/* */' instead. For consistency, a lot of '//' in the include files were converted, too. * UnDOSified libraries/base/cbits/runProcess.c. * My favourite sport: Killed $Id$s. --- diff --git a/cbits/runProcess.c b/cbits/runProcess.c index b4a7557..d117e36 100644 --- a/cbits/runProcess.c +++ b/cbits/runProcess.c @@ -1,555 +1,555 @@ -/* ---------------------------------------------------------------------------- - (c) The University of Glasgow 2004 - - Support for System.Process - ------------------------------------------------------------------------- */ - -#include "HsBase.h" - -#if defined(mingw32_HOST_OS) -#include -#include -#endif - -#ifdef HAVE_VFORK_H -#include -#endif - -#ifdef HAVE_VFORK -#define fork vfork -#endif - -#ifdef HAVE_SIGNAL_H -#include -#endif - -#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__) -/* ---------------------------------------------------------------------------- - 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) { - chdir (workingDirectory); - } - - /* 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) { - chdir (workingDirectory); - } - - dup2 (fdStdInput[0], STDIN_FILENO); - dup2 (fdStdOutput[1], STDOUT_FILENO); - dup2 (fdStdError[1], STDERR_FILENO); - - close(fdStdInput[0]); - close(fdStdInput[1]); - close(fdStdOutput[0]); - close(fdStdOutput[1]); - close(fdStdError[0]); - close(fdStdError[1]); - - /* 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)) - { - errno = EINTR; - } - else - { - /* This should never happen */ - } - - return -1; -} - -#else -/* ---------------------------------------------------------------------------- - Win32 versions - ------------------------------------------------------------------------- */ - -/* -------------------- WINDOWS VERSION --------------------- */ - -/* This is the error table that defines the mapping between OS error - codes and errno values */ - -struct errentry { - unsigned long oscode; /* OS return value */ - int errnocode; /* System V error code */ -}; - -static struct errentry errtable[] = { - { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */ - { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */ - { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */ - { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */ - { ERROR_ACCESS_DENIED, EACCES }, /* 5 */ - { ERROR_INVALID_HANDLE, EBADF }, /* 6 */ - { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */ - { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */ - { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */ - { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */ - { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */ - { ERROR_INVALID_ACCESS, EINVAL }, /* 12 */ - { ERROR_INVALID_DATA, EINVAL }, /* 13 */ - { ERROR_INVALID_DRIVE, ENOENT }, /* 15 */ - { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */ - { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */ - { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */ - { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */ - { ERROR_BAD_NETPATH, ENOENT }, /* 53 */ - { ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */ - { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */ - { ERROR_FILE_EXISTS, EEXIST }, /* 80 */ - { ERROR_CANNOT_MAKE, EACCES }, /* 82 */ - { ERROR_FAIL_I24, EACCES }, /* 83 */ - { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */ - { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */ - { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */ - { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */ - { ERROR_DISK_FULL, ENOSPC }, /* 112 */ - { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */ - { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */ - { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */ - { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */ - { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */ - { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */ - { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */ - { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */ - { ERROR_NOT_LOCKED, EACCES }, /* 158 */ - { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */ - { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */ - { ERROR_LOCK_FAILED, EACCES }, /* 167 */ - { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */ - { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */ - { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */ - { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */ -}; - -/* size of the table */ -#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0])) - -/* The following two constants must be the minimum and maximum - values in the (contiguous) range of Exec Failure errors. */ -#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG -#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN - -/* These are the low and high value in the range of errors that are - access violations */ -#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT -#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED - -static void maperrno (void) -{ - int i; - DWORD dwErrorCode; - - dwErrorCode = GetLastError(); - - /* check the table for the OS error code */ - for (i = 0; i < ERRTABLESIZE; ++i) - { - if (dwErrorCode == errtable[i].oscode) - { - errno = errtable[i].errnocode; - return; - } - } - - /* The error code wasn't in the table. We check for a range of */ - /* EACCES errors or exec failure errors (ENOEXEC). Otherwise */ - /* EINVAL is returned. */ - - if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE) - errno = EACCES; - else - if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR) - errno = ENOEXEC; - else - errno = EINVAL; -} - -/* - * 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; - char buffer[256]; - - 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; - } - - CloseHandle((HANDLE) handle); - 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; - } - - CloseHandle((HANDLE) handle); - 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; - } - - CloseHandle((HANDLE) handle); - return retCode; - } - - maperrno(); - return -1; -} - -#endif // Win32 +/* ---------------------------------------------------------------------------- + (c) The University of Glasgow 2004 + + Support for System.Process + ------------------------------------------------------------------------- */ + +#include "HsBase.h" + +#if defined(mingw32_HOST_OS) +#include +#include +#endif + +#ifdef HAVE_VFORK_H +#include +#endif + +#ifdef HAVE_VFORK +#define fork vfork +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#if !defined(mingw32_HOST_OS) && !defined(__MINGW32__) +/* ---------------------------------------------------------------------------- + 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) { + chdir (workingDirectory); + } + + /* 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) { + chdir (workingDirectory); + } + + dup2 (fdStdInput[0], STDIN_FILENO); + dup2 (fdStdOutput[1], STDOUT_FILENO); + dup2 (fdStdError[1], STDERR_FILENO); + + close(fdStdInput[0]); + close(fdStdInput[1]); + close(fdStdOutput[0]); + close(fdStdOutput[1]); + close(fdStdError[0]); + close(fdStdError[1]); + + /* 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)) + { + errno = EINTR; + } + else + { + /* This should never happen */ + } + + return -1; +} + +#else +/* ---------------------------------------------------------------------------- + Win32 versions + ------------------------------------------------------------------------- */ + +/* -------------------- WINDOWS VERSION --------------------- */ + +/* This is the error table that defines the mapping between OS error + codes and errno values */ + +struct errentry { + unsigned long oscode; /* OS return value */ + int errnocode; /* System V error code */ +}; + +static struct errentry errtable[] = { + { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */ + { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */ + { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */ + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */ + { ERROR_ACCESS_DENIED, EACCES }, /* 5 */ + { ERROR_INVALID_HANDLE, EBADF }, /* 6 */ + { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */ + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */ + { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */ + { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */ + { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */ + { ERROR_INVALID_ACCESS, EINVAL }, /* 12 */ + { ERROR_INVALID_DATA, EINVAL }, /* 13 */ + { ERROR_INVALID_DRIVE, ENOENT }, /* 15 */ + { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */ + { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */ + { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */ + { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */ + { ERROR_BAD_NETPATH, ENOENT }, /* 53 */ + { ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */ + { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */ + { ERROR_FILE_EXISTS, EEXIST }, /* 80 */ + { ERROR_CANNOT_MAKE, EACCES }, /* 82 */ + { ERROR_FAIL_I24, EACCES }, /* 83 */ + { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */ + { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */ + { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */ + { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */ + { ERROR_DISK_FULL, ENOSPC }, /* 112 */ + { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */ + { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */ + { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */ + { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */ + { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */ + { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */ + { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */ + { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */ + { ERROR_NOT_LOCKED, EACCES }, /* 158 */ + { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */ + { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */ + { ERROR_LOCK_FAILED, EACCES }, /* 167 */ + { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */ + { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */ + { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */ + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */ +}; + +/* size of the table */ +#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0])) + +/* The following two constants must be the minimum and maximum + values in the (contiguous) range of Exec Failure errors. */ +#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG +#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN + +/* These are the low and high value in the range of errors that are + access violations */ +#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT +#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED + +static void maperrno (void) +{ + int i; + DWORD dwErrorCode; + + dwErrorCode = GetLastError(); + + /* check the table for the OS error code */ + for (i = 0; i < ERRTABLESIZE; ++i) + { + if (dwErrorCode == errtable[i].oscode) + { + errno = errtable[i].errnocode; + return; + } + } + + /* The error code wasn't in the table. We check for a range of */ + /* EACCES errors or exec failure errors (ENOEXEC). Otherwise */ + /* EINVAL is returned. */ + + if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE) + errno = EACCES; + else + if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR) + errno = ENOEXEC; + else + errno = EINVAL; +} + +/* + * 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; + char buffer[256]; + + 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; + } + + CloseHandle((HANDLE) handle); + 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; + } + + CloseHandle((HANDLE) handle); + 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; + } + + CloseHandle((HANDLE) handle); + return retCode; + } + + maperrno(); + return -1; +} + +#endif /* Win32 */ diff --git a/include/HsBase.h b/include/HsBase.h index 6471aa1..a105080 100644 --- a/include/HsBase.h +++ b/include/HsBase.h @@ -723,7 +723,7 @@ INLINE void setTimevalTicks(struct timeval *p, HsInt ticks) p->tv_sec = ticks / TICK_FREQ; p->tv_usec = (ticks % TICK_FREQ) * (1000000 / TICK_FREQ); } -#endif // !defined(mingw32_HOST_OS) +#endif /* !defined(mingw32_HOST_OS) */ // Directory-related