1 /*-------------------------------------------------------------------------
2 * drawElements Utility Library
3 * ----------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Process abstraction.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deProcess.h"
25 #include "deMemory.h"
26 #include "deString.h"
27
28 #if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || \
29 (DE_OS == DE_OS_SYMBIAN) || (DE_OS == DE_OS_QNX)
30
31 #include "deCommandLine.h"
32
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <signal.h>
38 #include <fcntl.h>
39 #include <errno.h>
40
41 typedef enum ProcessState_e
42 {
43 PROCESSSTATE_NOT_STARTED = 0,
44 PROCESSSTATE_RUNNING,
45 PROCESSSTATE_FINISHED,
46
47 PROCESSSTATE_LAST
48 } ProcessState;
49
50 struct deProcess_s
51 {
52 ProcessState state;
53 int exitCode;
54 char *lastError;
55
56 pid_t pid;
57 deFile *standardIn;
58 deFile *standardOut;
59 deFile *standardErr;
60 };
61
die(int statusPipe,const char * message)62 static void die(int statusPipe, const char *message)
63 {
64 size_t msgLen = strlen(message);
65 int res = 0;
66
67 printf("Process launch failed: %s\n", message);
68 res = (int)write(statusPipe, message, msgLen + 1);
69 DE_UNREF(res); /* No need to check result. */
70 exit(-1);
71 }
72
dieLastError(int statusPipe,const char * message)73 static void dieLastError(int statusPipe, const char *message)
74 {
75 char msgBuf[256];
76 int lastErr = errno;
77 deSprintf(msgBuf, sizeof(msgBuf), "%s, error %d: %s", message, lastErr, strerror(lastErr));
78 die(statusPipe, msgBuf);
79 }
80
beginsWithPath(const char * fileName,const char * pathPrefix)81 DE_INLINE bool beginsWithPath(const char *fileName, const char *pathPrefix)
82 {
83 size_t pathLen = strlen(pathPrefix);
84
85 /* Strip trailing / */
86 while (pathLen > 0 && pathPrefix[pathLen - 1] == '/')
87 pathLen -= 1;
88
89 return pathLen > 0 && deMemoryEqual(fileName, pathPrefix, pathLen) && fileName[pathLen] == '/';
90 }
91
stripLeadingPath(char * fileName,const char * pathPrefix)92 static void stripLeadingPath(char *fileName, const char *pathPrefix)
93 {
94 size_t pathLen = strlen(pathPrefix);
95 size_t fileNameLen = strlen(fileName);
96
97 DE_ASSERT(beginsWithPath(fileName, pathPrefix));
98
99 /* Strip trailing / */
100 while (pathLen > 0 && pathPrefix[pathLen - 1] == '/')
101 pathLen -= 1;
102
103 DE_ASSERT(pathLen > 0);
104 DE_ASSERT(fileName[pathLen] == '/');
105
106 memmove(&fileName[0], &fileName[0] + pathLen + 1, fileNameLen - pathLen);
107 }
108
109 /* Doesn't return on success. */
execProcess(const char * commandLine,const char * workingDirectory,int statusPipe)110 static void execProcess(const char *commandLine, const char *workingDirectory, int statusPipe)
111 {
112 deCommandLine *cmdLine = deCommandLine_parse(commandLine);
113 char **argList = cmdLine ? (char **)deCalloc(sizeof(char *) * ((size_t)cmdLine->numArgs + 1)) : DE_NULL;
114
115 if (!cmdLine || !argList)
116 die(statusPipe, "Command line parsing failed (out of memory)");
117
118 if (workingDirectory && chdir(workingDirectory) != 0)
119 dieLastError(statusPipe, "chdir() failed");
120
121 {
122 int argNdx;
123 for (argNdx = 0; argNdx < cmdLine->numArgs; argNdx++)
124 argList[argNdx] = cmdLine->args[argNdx];
125 argList[argNdx] = DE_NULL; /* Terminate with 0. */
126 }
127
128 if (workingDirectory && beginsWithPath(argList[0], workingDirectory))
129 stripLeadingPath(argList[0], workingDirectory);
130
131 execv(argList[0], argList);
132
133 /* Failed. */
134 dieLastError(statusPipe, "execv() failed");
135 }
136
deProcess_create(void)137 deProcess *deProcess_create(void)
138 {
139 deProcess *process = (deProcess *)deCalloc(sizeof(deProcess));
140 if (!process)
141 return NULL;
142
143 process->state = PROCESSSTATE_NOT_STARTED;
144
145 return process;
146 }
147
deProcess_cleanupHandles(deProcess * process)148 static void deProcess_cleanupHandles(deProcess *process)
149 {
150 if (process->standardIn)
151 deFile_destroy(process->standardIn);
152
153 if (process->standardOut)
154 deFile_destroy(process->standardOut);
155
156 if (process->standardErr)
157 deFile_destroy(process->standardErr);
158
159 process->pid = 0;
160 process->standardIn = DE_NULL;
161 process->standardOut = DE_NULL;
162 process->standardErr = DE_NULL;
163 }
164
deProcess_destroy(deProcess * process)165 void deProcess_destroy(deProcess *process)
166 {
167 /* Never leave child processes running. Otherwise we'll have zombies. */
168 if (deProcess_isRunning(process))
169 {
170 deProcess_kill(process);
171 deProcess_waitForFinish(process);
172 }
173
174 deProcess_cleanupHandles(process);
175 deFree(process->lastError);
176 deFree(process);
177 }
178
deProcess_getLastError(const deProcess * process)179 const char *deProcess_getLastError(const deProcess *process)
180 {
181 return process->lastError ? process->lastError : "No error";
182 }
183
deProcess_getExitCode(const deProcess * process)184 int deProcess_getExitCode(const deProcess *process)
185 {
186 return process->exitCode;
187 }
188
deProcess_setError(deProcess * process,const char * error)189 static bool deProcess_setError(deProcess *process, const char *error)
190 {
191 if (process->lastError)
192 {
193 deFree(process->lastError);
194 process->lastError = DE_NULL;
195 }
196
197 process->lastError = deStrdup(error);
198 return process->lastError != DE_NULL;
199 }
200
deProcess_setErrorFromErrno(deProcess * process,const char * message)201 static bool deProcess_setErrorFromErrno(deProcess *process, const char *message)
202 {
203 char msgBuf[256];
204 int lastErr = errno;
205 deSprintf(msgBuf, sizeof(msgBuf), "%s, error %d: %s", message, lastErr, strerror(lastErr));
206 return deProcess_setError(process, message);
207 }
208
closePipe(int p[2])209 static void closePipe(int p[2])
210 {
211 if (p[0] >= 0)
212 close(p[0]);
213 if (p[1] >= 0)
214 close(p[1]);
215 }
216
deProcess_start(deProcess * process,const char * commandLine,const char * workingDirectory)217 bool deProcess_start(deProcess *process, const char *commandLine, const char *workingDirectory)
218 {
219 pid_t pid = 0;
220 int pipeIn[2] = {-1, -1};
221 int pipeOut[2] = {-1, -1};
222 int pipeErr[2] = {-1, -1};
223 int statusPipe[2] = {-1, -1};
224
225 if (process->state == PROCESSSTATE_RUNNING)
226 {
227 deProcess_setError(process, "Process already running");
228 return false;
229 }
230 else if (process->state == PROCESSSTATE_FINISHED)
231 {
232 deProcess_cleanupHandles(process);
233 process->state = PROCESSSTATE_NOT_STARTED;
234 }
235
236 if (pipe(pipeIn) < 0 || pipe(pipeOut) < 0 || pipe(pipeErr) < 0 || pipe(statusPipe) < 0)
237 {
238 deProcess_setErrorFromErrno(process, "pipe() failed");
239
240 closePipe(pipeIn);
241 closePipe(pipeOut);
242 closePipe(pipeErr);
243 closePipe(statusPipe);
244
245 return false;
246 }
247
248 pid = fork();
249
250 if (pid < 0)
251 {
252 deProcess_setErrorFromErrno(process, "fork() failed");
253
254 closePipe(pipeIn);
255 closePipe(pipeOut);
256 closePipe(pipeErr);
257 closePipe(statusPipe);
258
259 return false;
260 }
261
262 if (pid == 0)
263 {
264 /* Child process. */
265
266 /* Close unused endpoints. */
267 close(pipeIn[1]);
268 close(pipeOut[0]);
269 close(pipeErr[0]);
270 close(statusPipe[0]);
271
272 /* Set status pipe to close on exec(). That way parent will know that exec() succeeded. */
273 if (fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC) != 0)
274 dieLastError(statusPipe[1], "Failed to set FD_CLOEXEC");
275
276 /* Map stdin. */
277 if (pipeIn[0] != STDIN_FILENO && dup2(pipeIn[0], STDIN_FILENO) != STDIN_FILENO)
278 dieLastError(statusPipe[1], "dup2() failed");
279 close(pipeIn[0]);
280
281 /* Stdout. */
282 if (pipeOut[1] != STDOUT_FILENO && dup2(pipeOut[1], STDOUT_FILENO) != STDOUT_FILENO)
283 dieLastError(statusPipe[1], "dup2() failed");
284 close(pipeOut[1]);
285
286 /* Stderr. */
287 if (pipeErr[1] != STDERR_FILENO && dup2(pipeErr[1], STDERR_FILENO) != STDERR_FILENO)
288 dieLastError(statusPipe[1], "dup2() failed");
289 close(pipeErr[1]);
290
291 /* Doesn't return. */
292 execProcess(commandLine, workingDirectory, statusPipe[1]);
293 }
294 else
295 {
296 /* Parent process. */
297
298 /* Check status. */
299 {
300 char errBuf[256];
301 ssize_t result = 0;
302
303 close(statusPipe[1]);
304 while ((result = read(statusPipe[0], errBuf, 1)) == -1)
305 if (errno != EAGAIN && errno != EINTR)
306 break;
307
308 if (result > 0)
309 {
310 int procStatus = 0;
311
312 /* Read full error msg. */
313 int errPos = 1;
314 while (errPos < DE_LENGTH_OF_ARRAY(errBuf))
315 {
316 result = read(statusPipe[0], errBuf + errPos, 1);
317 if (result == -1)
318 break; /* Done. */
319
320 errPos += 1;
321 }
322
323 /* Make sure str is null-terminated. */
324 errBuf[errPos] = 0;
325
326 /* Close handles. */
327 close(statusPipe[0]);
328 closePipe(pipeIn);
329 closePipe(pipeOut);
330 closePipe(pipeErr);
331
332 /* Run waitpid to clean up zombie. */
333 waitpid(pid, &procStatus, 0);
334
335 deProcess_setError(process, errBuf);
336
337 return false;
338 }
339
340 /* Status pipe is not needed. */
341 close(statusPipe[0]);
342 }
343
344 /* Set running state. */
345 process->pid = pid;
346 process->state = PROCESSSTATE_RUNNING;
347
348 /* Stdin, stdout. */
349 close(pipeIn[0]);
350 close(pipeOut[1]);
351 close(pipeErr[1]);
352
353 process->standardIn = deFile_createFromHandle((uintptr_t)pipeIn[1]);
354 process->standardOut = deFile_createFromHandle((uintptr_t)pipeOut[0]);
355 process->standardErr = deFile_createFromHandle((uintptr_t)pipeErr[0]);
356
357 if (!process->standardIn)
358 close(pipeIn[1]);
359
360 if (!process->standardOut)
361 close(pipeOut[0]);
362
363 if (!process->standardErr)
364 close(pipeErr[0]);
365 }
366
367 return true;
368 }
369
deProcess_isRunning(deProcess * process)370 bool deProcess_isRunning(deProcess *process)
371 {
372 if (process->state == PROCESSSTATE_RUNNING)
373 {
374 int status = 0;
375
376 if (waitpid(process->pid, &status, WNOHANG) == 0)
377 return true; /* No status available. */
378
379 if (WIFEXITED(status) || WIFSIGNALED(status))
380 {
381 /* Child has finished. */
382 process->state = PROCESSSTATE_FINISHED;
383 return false;
384 }
385 else
386 return true;
387 }
388 else
389 return false;
390 }
391
deProcess_waitForFinish(deProcess * process)392 bool deProcess_waitForFinish(deProcess *process)
393 {
394 int status = 0;
395 pid_t waitResult;
396
397 if (process->state != PROCESSSTATE_RUNNING)
398 {
399 deProcess_setError(process, "Process is not running");
400 return false;
401 }
402
403 /* \note [pyry] HACK, apparently needed by some versions of OS X. */
404 while ((waitResult = waitpid(process->pid, &status, 0)) != process->pid)
405 if (errno != ENOENT)
406 break;
407
408 if (waitResult != process->pid)
409 {
410 deProcess_setErrorFromErrno(process, "waitpid() failed");
411 return false; /* waitpid() failed. */
412 }
413
414 if (!WIFEXITED(status) && !WIFSIGNALED(status))
415 {
416 deProcess_setErrorFromErrno(process, "waitpid() failed");
417 return false; /* Something strange happened. */
418 }
419
420 process->exitCode = WEXITSTATUS(status);
421 process->state = PROCESSSTATE_FINISHED;
422 return true;
423 }
424
deProcess_sendSignal(deProcess * process,int sigNum)425 static bool deProcess_sendSignal(deProcess *process, int sigNum)
426 {
427 if (process->state != PROCESSSTATE_RUNNING)
428 {
429 deProcess_setError(process, "Process is not running");
430 return false;
431 }
432
433 if (kill(process->pid, sigNum) == 0)
434 return true;
435 else
436 {
437 deProcess_setErrorFromErrno(process, "kill() failed");
438 return false;
439 }
440 }
441
deProcess_terminate(deProcess * process)442 bool deProcess_terminate(deProcess *process)
443 {
444 return deProcess_sendSignal(process, SIGTERM);
445 }
446
deProcess_kill(deProcess * process)447 bool deProcess_kill(deProcess *process)
448 {
449 return deProcess_sendSignal(process, SIGKILL);
450 }
451
deProcess_getStdIn(deProcess * process)452 deFile *deProcess_getStdIn(deProcess *process)
453 {
454 return process->standardIn;
455 }
456
deProcess_getStdOut(deProcess * process)457 deFile *deProcess_getStdOut(deProcess *process)
458 {
459 return process->standardOut;
460 }
461
deProcess_getStdErr(deProcess * process)462 deFile *deProcess_getStdErr(deProcess *process)
463 {
464 return process->standardErr;
465 }
466
deProcess_closeStdIn(deProcess * process)467 bool deProcess_closeStdIn(deProcess *process)
468 {
469 if (process->standardIn)
470 {
471 deFile_destroy(process->standardIn);
472 process->standardIn = DE_NULL;
473 return true;
474 }
475 else
476 return false;
477 }
478
deProcess_closeStdOut(deProcess * process)479 bool deProcess_closeStdOut(deProcess *process)
480 {
481 if (process->standardOut)
482 {
483 deFile_destroy(process->standardOut);
484 process->standardOut = DE_NULL;
485 return true;
486 }
487 else
488 return false;
489 }
490
deProcess_closeStdErr(deProcess * process)491 bool deProcess_closeStdErr(deProcess *process)
492 {
493 if (process->standardErr)
494 {
495 deFile_destroy(process->standardErr);
496 process->standardErr = DE_NULL;
497 return true;
498 }
499 else
500 return false;
501 }
502
503 #elif (DE_OS == DE_OS_WIN32)
504
505 #define VC_EXTRALEAN
506 #define WIN32_LEAN_AND_MEAN
507 #include <windows.h>
508 #include <strsafe.h>
509
510 typedef enum ProcessState_e
511 {
512 PROCESSSTATE_NOT_STARTED = 0,
513 PROCESSSTATE_RUNNING,
514 PROCESSSTATE_FINISHED,
515
516 PROCESSSTATE_LAST
517 } ProcessState;
518
519 struct deProcess_s
520 {
521 ProcessState state;
522 char *lastError;
523 int exitCode;
524
525 PROCESS_INFORMATION procInfo;
526 deFile *standardIn;
527 deFile *standardOut;
528 deFile *standardErr;
529 };
530
deProcess_setError(deProcess * process,const char * error)531 static bool deProcess_setError(deProcess *process, const char *error)
532 {
533 if (process->lastError)
534 {
535 deFree(process->lastError);
536 process->lastError = DE_NULL;
537 }
538
539 process->lastError = deStrdup(error);
540 return process->lastError != DE_NULL;
541 }
542
deProcess_setErrorFromWin32(deProcess * process,const char * msg)543 static bool deProcess_setErrorFromWin32(deProcess *process, const char *msg)
544 {
545 DWORD error = GetLastError();
546 LPSTR msgBuf;
547 char errBuf[256];
548
549 #if defined(UNICODE)
550 #error Unicode not supported.
551 #endif
552
553 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
554 error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msgBuf, 0, DE_NULL) > 0)
555 {
556 deSprintf(errBuf, sizeof(errBuf), "%s, error %d: %s", msg, error, msgBuf);
557 LocalFree(msgBuf);
558 return deProcess_setError(process, errBuf);
559 }
560 else
561 {
562 /* Failed to get error str. */
563 deSprintf(errBuf, sizeof(errBuf), "%s, error %d", msg, error);
564 return deProcess_setError(process, errBuf);
565 }
566 }
567
deProcess_create(void)568 deProcess *deProcess_create(void)
569 {
570 deProcess *process = (deProcess *)deCalloc(sizeof(deProcess));
571 if (!process)
572 return DE_NULL;
573
574 process->state = PROCESSSTATE_NOT_STARTED;
575
576 return process;
577 }
578
deProcess_cleanupHandles(deProcess * process)579 void deProcess_cleanupHandles(deProcess *process)
580 {
581 DE_ASSERT(!deProcess_isRunning(process));
582
583 if (process->standardErr)
584 deFile_destroy(process->standardErr);
585
586 if (process->standardOut)
587 deFile_destroy(process->standardOut);
588
589 if (process->standardIn)
590 deFile_destroy(process->standardIn);
591
592 if (process->procInfo.hProcess)
593 CloseHandle(process->procInfo.hProcess);
594
595 if (process->procInfo.hThread)
596 CloseHandle(process->procInfo.hThread);
597
598 process->standardErr = DE_NULL;
599 process->standardOut = DE_NULL;
600 process->standardIn = DE_NULL;
601 process->procInfo.hProcess = DE_NULL;
602 process->procInfo.hThread = DE_NULL;
603 }
604
deProcess_destroy(deProcess * process)605 void deProcess_destroy(deProcess *process)
606 {
607 if (deProcess_isRunning(process))
608 {
609 deProcess_kill(process);
610 deProcess_waitForFinish(process);
611 }
612
613 deProcess_cleanupHandles(process);
614 deFree(process->lastError);
615 deFree(process);
616 }
617
deProcess_getLastError(const deProcess * process)618 const char *deProcess_getLastError(const deProcess *process)
619 {
620 return process->lastError ? process->lastError : "No error";
621 }
622
deProcess_getExitCode(const deProcess * process)623 int deProcess_getExitCode(const deProcess *process)
624 {
625 return process->exitCode;
626 }
627
deProcess_start(deProcess * process,const char * commandLine,const char * workingDirectory)628 bool deProcess_start(deProcess *process, const char *commandLine, const char *workingDirectory)
629 {
630 SECURITY_ATTRIBUTES securityAttr;
631 STARTUPINFO startInfo;
632
633 /* Pipes. */
634 HANDLE stdInRead = DE_NULL;
635 HANDLE stdInWrite = DE_NULL;
636 HANDLE stdOutRead = DE_NULL;
637 HANDLE stdOutWrite = DE_NULL;
638 HANDLE stdErrRead = DE_NULL;
639 HANDLE stdErrWrite = DE_NULL;
640
641 if (process->state == PROCESSSTATE_RUNNING)
642 {
643 deProcess_setError(process, "Process already running");
644 return false;
645 }
646 else if (process->state == PROCESSSTATE_FINISHED)
647 {
648 /* Process finished, clean up old cruft. */
649 deProcess_cleanupHandles(process);
650 process->state = PROCESSSTATE_NOT_STARTED;
651 }
652
653 deMemset(&startInfo, 0, sizeof(startInfo));
654 deMemset(&securityAttr, 0, sizeof(securityAttr));
655
656 /* Security attributes for inheriting handle. */
657 securityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
658 securityAttr.bInheritHandle = TRUE;
659 securityAttr.lpSecurityDescriptor = DE_NULL;
660
661 /* Create pipes. \todo [2011-10-03 pyry] Clean up handles on error! */
662 if (!CreatePipe(&stdInRead, &stdInWrite, &securityAttr, 0) ||
663 !SetHandleInformation(stdInWrite, HANDLE_FLAG_INHERIT, 0))
664 {
665 deProcess_setErrorFromWin32(process, "CreatePipe() failed");
666 CloseHandle(stdInRead);
667 CloseHandle(stdInWrite);
668 return false;
669 }
670
671 if (!CreatePipe(&stdOutRead, &stdOutWrite, &securityAttr, 0) ||
672 !SetHandleInformation(stdOutRead, HANDLE_FLAG_INHERIT, 0))
673 {
674 deProcess_setErrorFromWin32(process, "CreatePipe() failed");
675 CloseHandle(stdInRead);
676 CloseHandle(stdInWrite);
677 CloseHandle(stdOutRead);
678 CloseHandle(stdOutWrite);
679 return false;
680 }
681
682 if (!CreatePipe(&stdErrRead, &stdErrWrite, &securityAttr, 0) ||
683 !SetHandleInformation(stdErrRead, HANDLE_FLAG_INHERIT, 0))
684 {
685 deProcess_setErrorFromWin32(process, "CreatePipe() failed");
686 CloseHandle(stdInRead);
687 CloseHandle(stdInWrite);
688 CloseHandle(stdOutRead);
689 CloseHandle(stdOutWrite);
690 CloseHandle(stdErrRead);
691 CloseHandle(stdErrWrite);
692 return false;
693 }
694
695 /* Setup startup info. */
696 startInfo.cb = sizeof(startInfo);
697 startInfo.hStdError = stdErrWrite;
698 startInfo.hStdOutput = stdOutWrite;
699 startInfo.hStdInput = stdInRead;
700 startInfo.dwFlags |= STARTF_USESTDHANDLES;
701
702 if (!CreateProcess(DE_NULL, (LPTSTR)commandLine, DE_NULL, DE_NULL, TRUE /* inherit handles */, 0, DE_NULL,
703 workingDirectory, &startInfo, &process->procInfo))
704 {
705 /* Store error info. */
706 deProcess_setErrorFromWin32(process, "CreateProcess() failed");
707
708 /* Close all handles. */
709 CloseHandle(stdInRead);
710 CloseHandle(stdInWrite);
711 CloseHandle(stdOutRead);
712 CloseHandle(stdOutWrite);
713 CloseHandle(stdErrRead);
714 CloseHandle(stdErrWrite);
715
716 return false;
717 }
718
719 process->state = PROCESSSTATE_RUNNING;
720
721 /* Close our ends of handles.*/
722 CloseHandle(stdErrWrite);
723 CloseHandle(stdOutWrite);
724 CloseHandle(stdInRead);
725
726 /* Construct stdio file objects \note May fail, not detected. */
727 process->standardIn = deFile_createFromHandle((uintptr_t)stdInWrite);
728 process->standardOut = deFile_createFromHandle((uintptr_t)stdOutRead);
729 process->standardErr = deFile_createFromHandle((uintptr_t)stdErrRead);
730
731 return true;
732 }
733
deProcess_isRunning(deProcess * process)734 bool deProcess_isRunning(deProcess *process)
735 {
736 if (process->state == PROCESSSTATE_RUNNING)
737 {
738 int exitCode;
739 BOOL result = GetExitCodeProcess(process->procInfo.hProcess, (LPDWORD)&exitCode);
740
741 if (result != TRUE)
742 {
743 deProcess_setErrorFromWin32(process, "GetExitCodeProcess() failed");
744 return false;
745 }
746
747 if (exitCode == STILL_ACTIVE)
748 return true;
749 else
750 {
751 /* Done. */
752 process->exitCode = exitCode;
753 process->state = PROCESSSTATE_FINISHED;
754 return false;
755 }
756 }
757 else
758 return false;
759 }
760
deProcess_waitForFinish(deProcess * process)761 bool deProcess_waitForFinish(deProcess *process)
762 {
763 if (process->state == PROCESSSTATE_RUNNING)
764 {
765 if (WaitForSingleObject(process->procInfo.hProcess, INFINITE) != WAIT_OBJECT_0)
766 {
767 deProcess_setErrorFromWin32(process, "WaitForSingleObject() failed");
768 return false;
769 }
770 return !deProcess_isRunning(process);
771 }
772 else
773 {
774 deProcess_setError(process, "Process is not running");
775 return false;
776 }
777 }
778
stopProcess(deProcess * process,bool kill)779 static bool stopProcess(deProcess *process, bool kill)
780 {
781 if (process->state == PROCESSSTATE_RUNNING)
782 {
783 if (!TerminateProcess(process->procInfo.hProcess, kill ? -1 : 0))
784 {
785 deProcess_setErrorFromWin32(process, "TerminateProcess() failed");
786 return false;
787 }
788 else
789 return true;
790 }
791 else
792 {
793 deProcess_setError(process, "Process is not running");
794 return false;
795 }
796 }
797
deProcess_terminate(deProcess * process)798 bool deProcess_terminate(deProcess *process)
799 {
800 return stopProcess(process, false);
801 }
802
deProcess_kill(deProcess * process)803 bool deProcess_kill(deProcess *process)
804 {
805 return stopProcess(process, true);
806 }
807
deProcess_getStdIn(deProcess * process)808 deFile *deProcess_getStdIn(deProcess *process)
809 {
810 return process->standardIn;
811 }
812
deProcess_getStdOut(deProcess * process)813 deFile *deProcess_getStdOut(deProcess *process)
814 {
815 return process->standardOut;
816 }
817
deProcess_getStdErr(deProcess * process)818 deFile *deProcess_getStdErr(deProcess *process)
819 {
820 return process->standardErr;
821 }
822
deProcess_closeStdIn(deProcess * process)823 bool deProcess_closeStdIn(deProcess *process)
824 {
825 if (process->standardIn)
826 {
827 deFile_destroy(process->standardIn);
828 process->standardIn = DE_NULL;
829 return true;
830 }
831 else
832 return false;
833 }
834
deProcess_closeStdOut(deProcess * process)835 bool deProcess_closeStdOut(deProcess *process)
836 {
837 if (process->standardOut)
838 {
839 deFile_destroy(process->standardOut);
840 process->standardOut = DE_NULL;
841 return true;
842 }
843 else
844 return false;
845 }
846
deProcess_closeStdErr(deProcess * process)847 bool deProcess_closeStdErr(deProcess *process)
848 {
849 if (process->standardErr)
850 {
851 deFile_destroy(process->standardErr);
852 process->standardErr = DE_NULL;
853 return true;
854 }
855 else
856 return false;
857 }
858
859 #else
860 #error Implement deProcess for your OS.
861 #endif
862