/* * 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; /* Create the anon pipe with both ends inheritable */ if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, NULL, 0)) { maperrno(); *pHandleIn = NULL; *pHandleOut = NULL; return FALSE; } if (isInheritableIn) { // SetHandleInformation requires at least Win2k if (!SetHandleInformation(hTemporaryIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { maperrno(); *pHandleIn = NULL; *pHandleOut = NULL; CloseHandle(hTemporaryIn); CloseHandle(hTemporaryOut); return FALSE; } } *pHandleIn = hTemporaryIn; if (isInheritableOut) { if (!SetHandleInformation(hTemporaryOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { maperrno(); *pHandleIn = NULL; *pHandleOut = NULL; CloseHandle(hTemporaryIn); CloseHandle(hTemporaryOut); return FALSE; } } *pHandleOut = hTemporaryOut; return TRUE; }
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; }
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; }
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 (wchar_t *cmd, wchar_t *workingDirectory, void *environment, int fdStdIn, int fdStdOut, int fdStdErr, int *pfdStdInput, int *pfdStdOutput, int *pfdStdError, int close_fds) { STARTUPINFO sInfo; PROCESS_INFORMATION pInfo; HANDLE hStdInputRead = INVALID_HANDLE_VALUE; HANDLE hStdInputWrite = INVALID_HANDLE_VALUE; HANDLE hStdOutputRead = INVALID_HANDLE_VALUE; HANDLE hStdOutputWrite = INVALID_HANDLE_VALUE; HANDLE hStdErrorRead = INVALID_HANDLE_VALUE; HANDLE hStdErrorWrite = INVALID_HANDLE_VALUE; DWORD flags; BOOL status; BOOL inherit; ZeroMemory(&sInfo, sizeof(sInfo)); sInfo.cb = sizeof(sInfo); sInfo.dwFlags = STARTF_USESTDHANDLES; if (fdStdIn == -1) { if (!mkAnonPipe(&hStdInputRead, TRUE, &hStdInputWrite, FALSE)) goto cleanup_err; sInfo.hStdInput = hStdInputRead; } else if (fdStdIn == 0) { // Don't duplicate stdin, as console handles cannot be // duplicated and inherited. urg. sInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } else { // The handle might not be inheritable, so duplicate it status = DuplicateHandle(GetCurrentProcess(), (HANDLE) _get_osfhandle(fdStdIn), GetCurrentProcess(), &hStdInputRead, 0, TRUE, /* inheritable */ DUPLICATE_SAME_ACCESS); if (!status) goto cleanup_err; sInfo.hStdInput = hStdInputRead; } if (fdStdOut == -1) { if (!mkAnonPipe(&hStdOutputRead, FALSE, &hStdOutputWrite, TRUE)) goto cleanup_err; sInfo.hStdOutput = hStdOutputWrite; } else if (fdStdOut == 1) { // Don't duplicate stdout, as console handles cannot be // duplicated and inherited. urg. sInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); } else { // The handle might not be inheritable, so duplicate it status = DuplicateHandle(GetCurrentProcess(), (HANDLE) _get_osfhandle(fdStdOut), GetCurrentProcess(), &hStdOutputWrite, 0, TRUE, /* inheritable */ DUPLICATE_SAME_ACCESS); if (!status) goto cleanup_err; sInfo.hStdOutput = hStdOutputWrite; } if (fdStdErr == -1) { if (!mkAnonPipe(&hStdErrorRead, TRUE, &hStdErrorWrite, TRUE)) goto cleanup_err; sInfo.hStdError = hStdErrorWrite; } else if (fdStdErr == 2) { // Don't duplicate stderr, as console handles cannot be // duplicated and inherited. urg. sInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); } else { /* The handle might not be inheritable, so duplicate it */ status = DuplicateHandle(GetCurrentProcess(), (HANDLE) _get_osfhandle(fdStdErr), GetCurrentProcess(), &hStdErrorWrite, 0, TRUE, /* inheritable */ DUPLICATE_SAME_ACCESS); if (!status) goto cleanup_err; sInfo.hStdError = hStdErrorWrite; } 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; // See #3231 if (close_fds && fdStdIn == 0 && fdStdOut == 1 && fdStdErr == 2) { inherit = FALSE; } else { inherit = TRUE; } if (!CreateProcess(NULL, cmd, NULL, NULL, inherit, flags, environment, workingDirectory, &sInfo, &pInfo)) { goto cleanup_err; } 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. if (hStdInputRead != INVALID_HANDLE_VALUE) CloseHandle(hStdInputRead); if (hStdOutputWrite != INVALID_HANDLE_VALUE) CloseHandle(hStdOutputWrite); if (hStdErrorWrite != INVALID_HANDLE_VALUE) 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; cleanup_err: if (hStdInputRead != INVALID_HANDLE_VALUE) CloseHandle(hStdInputRead); if (hStdInputWrite != INVALID_HANDLE_VALUE) CloseHandle(hStdInputWrite); if (hStdOutputRead != INVALID_HANDLE_VALUE) CloseHandle(hStdOutputRead); if (hStdOutputWrite != INVALID_HANDLE_VALUE) CloseHandle(hStdOutputWrite); if (hStdErrorRead != INVALID_HANDLE_VALUE) CloseHandle(hStdErrorRead); if (hStdErrorWrite != INVALID_HANDLE_VALUE) CloseHandle(hStdErrorWrite); maperrno(); return -1; }
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; }
/* * 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; }