1 /* ----------------------------------------------------------------------------
2 (c) The University of Glasgow 2004
4 Support for System.Process
5 ------------------------------------------------------------------------- */
9 #if defined(mingw32_HOST_OS)
26 #if !defined(mingw32_HOST_OS) && !defined(__MINGW32__)
27 /* ----------------------------------------------------------------------------
29 ------------------------------------------------------------------------- */
32 runProcess (char *const args[], char *workingDirectory, char **environment,
33 int fdStdInput, int fdStdOutput, int fdStdError,
34 int set_inthandler, long inthandler,
35 int set_quithandler, long quithandler)
47 pPrPr_disableITimers();
49 if (workingDirectory) {
50 if (chdir (workingDirectory) < 0) {
55 /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested
57 (void)sigemptyset(&dfl.sa_mask);
60 dfl.sa_handler = (void *)inthandler;
61 (void)sigaction(SIGINT, &dfl, NULL);
63 if (set_quithandler) {
64 dfl.sa_handler = (void *)quithandler;
65 (void)sigaction(SIGQUIT, &dfl, NULL);
68 dup2 (fdStdInput, STDIN_FILENO);
69 dup2 (fdStdOutput, STDOUT_FILENO);
70 dup2 (fdStdError, STDERR_FILENO);
73 execvpe(args[0], args, environment);
75 execvp(args[0], args);
85 runInteractiveProcess (char *const args[],
86 char *workingDirectory, char **environment,
87 int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)
90 int fdStdInput[2], fdStdOutput[2], fdStdError[2];
100 close(fdStdInput[1]);
101 close(fdStdOutput[0]);
102 close(fdStdOutput[1]);
103 close(fdStdError[0]);
104 close(fdStdError[1]);
109 pPrPr_disableITimers();
111 if (workingDirectory) {
112 if (chdir (workingDirectory) < 0) {
117 dup2 (fdStdInput[0], STDIN_FILENO);
118 dup2 (fdStdOutput[1], STDOUT_FILENO);
119 dup2 (fdStdError[1], STDERR_FILENO);
121 close(fdStdInput[0]);
122 close(fdStdInput[1]);
123 close(fdStdOutput[0]);
124 close(fdStdOutput[1]);
125 close(fdStdError[0]);
126 close(fdStdError[1]);
130 execvpe(args[0], args, environment);
132 execvp(args[0], args);
138 close(fdStdInput[0]);
139 close(fdStdOutput[1]);
140 close(fdStdError[1]);
142 *pfdStdInput = fdStdInput[1];
143 *pfdStdOutput = fdStdOutput[0];
144 *pfdStdError = fdStdError[0];
152 terminateProcess (ProcHandle handle)
154 return (kill(handle, SIGTERM) == 0);
158 getProcessExitCode (ProcHandle handle, int *pExitCode)
164 if ((res = waitpid(handle, &wstat, WNOHANG)) > 0)
166 if (WIFEXITED(wstat))
168 *pExitCode = WEXITSTATUS(wstat);
172 if (WIFSIGNALED(wstat))
179 /* This should never happen */
183 if (res == 0) return 0;
194 int waitForProcess (ProcHandle handle)
198 while (waitpid(handle, &wstat, 0) < 0)
206 if (WIFEXITED(wstat))
207 return WEXITSTATUS(wstat);
209 if (WIFSIGNALED(wstat))
215 /* This should never happen */
222 /* ----------------------------------------------------------------------------
224 ------------------------------------------------------------------------- */
226 /* -------------------- WINDOWS VERSION --------------------- */
228 /* This is the error table that defines the mapping between OS error
229 codes and errno values */
232 unsigned long oscode; /* OS return value */
233 int errnocode; /* System V error code */
236 static struct errentry errtable[] = {
237 { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */
238 { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */
239 { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */
240 { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */
241 { ERROR_ACCESS_DENIED, EACCES }, /* 5 */
242 { ERROR_INVALID_HANDLE, EBADF }, /* 6 */
243 { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */
244 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */
245 { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */
246 { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */
247 { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */
248 { ERROR_INVALID_ACCESS, EINVAL }, /* 12 */
249 { ERROR_INVALID_DATA, EINVAL }, /* 13 */
250 { ERROR_INVALID_DRIVE, ENOENT }, /* 15 */
251 { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
252 { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
253 { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
254 { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
255 { ERROR_BAD_NETPATH, ENOENT }, /* 53 */
256 { ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */
257 { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
258 { ERROR_FILE_EXISTS, EEXIST }, /* 80 */
259 { ERROR_CANNOT_MAKE, EACCES }, /* 82 */
260 { ERROR_FAIL_I24, EACCES }, /* 83 */
261 { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
262 { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
263 { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
264 { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
265 { ERROR_DISK_FULL, ENOSPC }, /* 112 */
266 { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
267 { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
268 { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
269 { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
270 { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
271 { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
272 { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
273 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
274 { ERROR_NOT_LOCKED, EACCES }, /* 158 */
275 { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
276 { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
277 { ERROR_LOCK_FAILED, EACCES }, /* 167 */
278 { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
279 { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
280 { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
281 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */
284 /* size of the table */
285 #define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
287 /* The following two constants must be the minimum and maximum
288 values in the (contiguous) range of Exec Failure errors. */
289 #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
290 #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
292 /* These are the low and high value in the range of errors that are
294 #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
295 #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
297 static void maperrno (void)
302 dwErrorCode = GetLastError();
304 /* check the table for the OS error code */
305 for (i = 0; i < ERRTABLESIZE; ++i)
307 if (dwErrorCode == errtable[i].oscode)
309 errno = errtable[i].errnocode;
314 /* The error code wasn't in the table. We check for a range of */
315 /* EACCES errors or exec failure errors (ENOEXEC). Otherwise */
316 /* EINVAL is returned. */
318 if (dwErrorCode >= MIN_EACCES_RANGE && dwErrorCode <= MAX_EACCES_RANGE)
321 if (dwErrorCode >= MIN_EXEC_ERROR && dwErrorCode <= MAX_EXEC_ERROR)
328 * Function: mkAnonPipe
330 * Purpose: create an anonymous pipe with read and write ends being
331 * optionally (non-)inheritable.
334 mkAnonPipe (HANDLE* pHandleIn, BOOL isInheritableIn,
335 HANDLE* pHandleOut, BOOL isInheritableOut)
337 HANDLE hTemporaryIn = NULL;
338 HANDLE hTemporaryOut = NULL;
340 SECURITY_ATTRIBUTES sec_attrs;
342 /* Create inheritable security attributes */
343 sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
344 sec_attrs.lpSecurityDescriptor = NULL;
345 sec_attrs.bInheritHandle = TRUE;
347 /* Create the anon pipe with both ends inheritable */
348 if (!CreatePipe(&hTemporaryIn, &hTemporaryOut, &sec_attrs, 0))
357 *pHandleIn = hTemporaryIn;
360 /* Make the read end non-inheritable */
361 status = DuplicateHandle(GetCurrentProcess(), hTemporaryIn,
362 GetCurrentProcess(), pHandleIn,
364 FALSE, /* non-inheritable */
365 DUPLICATE_SAME_ACCESS);
366 CloseHandle(hTemporaryIn);
372 CloseHandle(hTemporaryOut);
377 if (isInheritableOut)
378 *pHandleOut = hTemporaryOut;
381 /* Make the write end non-inheritable */
382 status = DuplicateHandle(GetCurrentProcess(), hTemporaryOut,
383 GetCurrentProcess(), pHandleOut,
385 FALSE, /* non-inheritable */
386 DUPLICATE_SAME_ACCESS);
387 CloseHandle(hTemporaryOut);
393 CloseHandle(*pHandleIn);
402 runProcess (char *cmd, char *workingDirectory, void *environment,
403 int fdStdInput, int fdStdOutput, int fdStdError)
406 PROCESS_INFORMATION pInfo;
410 ZeroMemory(&sInfo, sizeof(sInfo));
411 sInfo.cb = sizeof(sInfo);
412 sInfo.hStdInput = (HANDLE) _get_osfhandle(fdStdInput);
413 sInfo.hStdOutput= (HANDLE) _get_osfhandle(fdStdOutput);
414 sInfo.hStdError = (HANDLE) _get_osfhandle(fdStdError);
416 if (sInfo.hStdInput == INVALID_HANDLE_VALUE)
417 sInfo.hStdInput = NULL;
418 if (sInfo.hStdOutput == INVALID_HANDLE_VALUE)
419 sInfo.hStdOutput = NULL;
420 if (sInfo.hStdError == INVALID_HANDLE_VALUE)
421 sInfo.hStdError = NULL;
423 if (sInfo.hStdInput || sInfo.hStdOutput || sInfo.hStdError)
424 sInfo.dwFlags = STARTF_USESTDHANDLES;
426 if (sInfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE) &&
427 sInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE) &&
428 sInfo.hStdError != GetStdHandle(STD_ERROR_HANDLE))
429 flags = CREATE_NO_WINDOW; // Run without console window only when both output and error are redirected
433 if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, environment, workingDirectory, &sInfo, &pInfo))
439 CloseHandle(pInfo.hThread);
440 return (ProcHandle)pInfo.hProcess;
444 runInteractiveProcess (char *cmd, char *workingDirectory, void *environment,
445 int *pfdStdInput, int *pfdStdOutput, int *pfdStdError)
448 PROCESS_INFORMATION pInfo;
449 HANDLE hStdInputRead, hStdInputWrite;
450 HANDLE hStdOutputRead, hStdOutputWrite;
451 HANDLE hStdErrorRead, hStdErrorWrite;
453 if (!mkAnonPipe(&hStdInputRead, TRUE, &hStdInputWrite, FALSE))
456 if (!mkAnonPipe(&hStdOutputRead, FALSE, &hStdOutputWrite, TRUE))
458 CloseHandle(hStdInputRead);
459 CloseHandle(hStdInputWrite);
463 if (!mkAnonPipe(&hStdErrorRead, FALSE, &hStdErrorWrite, TRUE))
465 CloseHandle(hStdInputRead);
466 CloseHandle(hStdInputWrite);
467 CloseHandle(hStdOutputRead);
468 CloseHandle(hStdOutputWrite);
472 ZeroMemory(&sInfo, sizeof(sInfo));
473 sInfo.cb = sizeof(sInfo);
474 sInfo.dwFlags = STARTF_USESTDHANDLES;
475 sInfo.hStdInput = hStdInputRead;
476 sInfo.hStdOutput= hStdOutputWrite;
477 sInfo.hStdError = hStdErrorWrite;
479 if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW, environment, workingDirectory, &sInfo, &pInfo))
482 CloseHandle(hStdInputRead);
483 CloseHandle(hStdInputWrite);
484 CloseHandle(hStdOutputRead);
485 CloseHandle(hStdOutputWrite);
486 CloseHandle(hStdErrorRead);
487 CloseHandle(hStdErrorWrite);
490 CloseHandle(pInfo.hThread);
492 // Close the ends of the pipes that were inherited by the
493 // child process. This is important, otherwise we won't see
494 // EOF on these pipes when the child process exits.
495 CloseHandle(hStdInputRead);
496 CloseHandle(hStdOutputWrite);
497 CloseHandle(hStdErrorWrite);
499 *pfdStdInput = _open_osfhandle((intptr_t) hStdInputWrite, _O_WRONLY);
500 *pfdStdOutput = _open_osfhandle((intptr_t) hStdOutputRead, _O_RDONLY);
501 *pfdStdError = _open_osfhandle((intptr_t) hStdErrorRead, _O_RDONLY);
503 return (int) pInfo.hProcess;
507 terminateProcess (ProcHandle handle)
509 if (!TerminateProcess((HANDLE) handle, 1)) {
514 CloseHandle((HANDLE) handle);
519 getProcessExitCode (ProcHandle handle, int *pExitCode)
523 if (WaitForSingleObject((HANDLE) handle, 1) == WAIT_OBJECT_0)
525 if (GetExitCodeProcess((HANDLE) handle, (DWORD *) pExitCode) == 0)
531 CloseHandle((HANDLE) handle);
539 waitForProcess (ProcHandle handle)
543 if (WaitForSingleObject((HANDLE) handle, INFINITE) == WAIT_OBJECT_0)
545 if (GetExitCodeProcess((HANDLE) handle, &retCode) == 0)
551 CloseHandle((HANDLE) handle);