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) || (DE_OS == DE_OS_SYMBIAN)
29
30 #include "deCommandLine.h"
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <errno.h>
39
40 typedef enum ProcessState_e
41 {
42 PROCESSSTATE_NOT_STARTED = 0,
43 PROCESSSTATE_RUNNING,
44 PROCESSSTATE_FINISHED,
45
46 PROCESSSTATE_LAST
47 } ProcessState;
48
49 struct deProcess_s
50 {
51 ProcessState state;
52 int exitCode;
53 char* lastError;
54
55 pid_t pid;
56 deFile* standardIn;
57 deFile* standardOut;
58 deFile* standardErr;
59 };
60
die(int statusPipe,const char * message)61 static void die (int statusPipe, const char* message)
62 {
63 size_t msgLen = strlen(message);
64 int res = 0;
65
66 printf("Process launch failed: %s\n", message);
67 res = (int)write(statusPipe, message, msgLen+1);
68 DE_UNREF(res); /* No need to check result. */
69 exit(-1);
70 }
71
dieLastError(int statusPipe,const char * message)72 static void dieLastError (int statusPipe, const char* message)
73 {
74 char msgBuf[256];
75 int lastErr = errno;
76 deSprintf(msgBuf, sizeof(msgBuf), "%s, error %d: %s", message, lastErr, strerror(lastErr));
77 die(statusPipe, msgBuf);
78 }
79
beginsWithPath(const char * fileName,const char * pathPrefix)80 DE_INLINE deBool beginsWithPath (const char* fileName, const char* pathPrefix)
81 {
82 size_t pathLen = strlen(pathPrefix);
83
84 /* Strip trailing / */
85 while (pathLen > 0 && pathPrefix[pathLen-1] == '/')
86 pathLen -= 1;
87
88 return pathLen > 0 && deMemoryEqual(fileName, pathPrefix, pathLen) && fileName[pathLen] == '/';
89 }
90
stripLeadingPath(char * fileName,const char * pathPrefix)91 static void stripLeadingPath (char* fileName, const char* pathPrefix)
92 {
93 size_t pathLen = strlen(pathPrefix);
94 size_t fileNameLen = strlen(fileName);
95
96 DE_ASSERT(beginsWithPath(fileName, pathPrefix));
97
98 /* Strip trailing / */
99 while (pathLen > 0 && pathPrefix[pathLen-1] == '/')
100 pathLen -= 1;
101
102 DE_ASSERT(pathLen > 0);
103 DE_ASSERT(fileName[pathLen] == '/');
104
105 memmove(&fileName[0], &fileName[0]+pathLen+1, fileNameLen-pathLen);
106 }
107
108 /* Doesn't return on success. */
execProcess(const char * commandLine,const char * workingDirectory,int statusPipe)109 static void execProcess (const char* commandLine, const char* workingDirectory, int statusPipe)
110 {
111 deCommandLine* cmdLine = deCommandLine_parse(commandLine);
112 char** argList = cmdLine ? (char**)deCalloc(sizeof(char*)*((size_t)cmdLine->numArgs+1)) : DE_NULL;
113
114 if (!cmdLine || !argList)
115 die(statusPipe, "Command line parsing failed (out of memory)");
116
117 if (workingDirectory && chdir(workingDirectory) != 0)
118 dieLastError(statusPipe, "chdir() failed");
119
120 {
121 int argNdx;
122 for (argNdx = 0; argNdx < cmdLine->numArgs; argNdx++)
123 argList[argNdx] = cmdLine->args[argNdx];
124 argList[argNdx] = DE_NULL; /* Terminate with 0. */
125 }
126
127 if (workingDirectory && beginsWithPath(argList[0], workingDirectory))
128 stripLeadingPath(argList[0], workingDirectory);
129
130 execv(argList[0], argList);
131
132 /* Failed. */
133 dieLastError(statusPipe, "execv() failed");
134 }
135
deProcess_create(void)136 deProcess* deProcess_create (void)
137 {
138 deProcess* process = (deProcess*)deCalloc(sizeof(deProcess));
139 if (!process)
140 return DE_FALSE;
141
142 process->state = PROCESSSTATE_NOT_STARTED;
143
144 return process;
145 }
146
deProcess_cleanupHandles(deProcess * process)147 static void deProcess_cleanupHandles (deProcess* process)
148 {
149 if (process->standardIn)
150 deFile_destroy(process->standardIn);
151
152 if (process->standardOut)
153 deFile_destroy(process->standardOut);
154
155 if (process->standardErr)
156 deFile_destroy(process->standardErr);
157
158 process->pid = 0;
159 process->standardIn = DE_NULL;
160 process->standardOut = DE_NULL;
161 process->standardErr = DE_NULL;
162 }
163
deProcess_destroy(deProcess * process)164 void deProcess_destroy (deProcess* process)
165 {
166 /* Never leave child processes running. Otherwise we'll have zombies. */
167 if (deProcess_isRunning(process))
168 {
169 deProcess_kill(process);
170 deProcess_waitForFinish(process);
171 }
172
173 deProcess_cleanupHandles(process);
174 deFree(process->lastError);
175 deFree(process);
176 }
177
deProcess_getLastError(const deProcess * process)178 const char* deProcess_getLastError (const deProcess* process)
179 {
180 return process->lastError ? process->lastError : "No error";
181 }
182
deProcess_getExitCode(const deProcess * process)183 int deProcess_getExitCode (const deProcess* process)
184 {
185 return process->exitCode;
186 }
187
deProcess_setError(deProcess * process,const char * error)188 static deBool deProcess_setError (deProcess* process, const char* error)
189 {
190 if (process->lastError)
191 {
192 deFree(process->lastError);
193 process->lastError = DE_NULL;
194 }
195
196 process->lastError = deStrdup(error);
197 return process->lastError != DE_NULL;
198 }
199
deProcess_setErrorFromErrno(deProcess * process,const char * message)200 static deBool deProcess_setErrorFromErrno (deProcess* process, const char* message)
201 {
202 char msgBuf[256];
203 int lastErr = errno;
204 deSprintf(msgBuf, sizeof(msgBuf), "%s, error %d: %s", message, lastErr, strerror(lastErr));
205 return deProcess_setError(process, message);
206 }
207
closePipe(int p[2])208 static void closePipe (int p[2])
209 {
210 if (p[0] >= 0)
211 close(p[0]);
212 if (p[1] >= 0)
213 close(p[1]);
214 }
215
deProcess_start(deProcess * process,const char * commandLine,const char * workingDirectory)216 deBool deProcess_start (deProcess* process, const char* commandLine, const char* workingDirectory)
217 {
218 pid_t pid = 0;
219 int pipeIn[2] = { -1, -1 };
220 int pipeOut[2] = { -1, -1 };
221 int pipeErr[2] = { -1, -1 };
222 int statusPipe[2] = { -1, -1 };
223
224 if (process->state == PROCESSSTATE_RUNNING)
225 {
226 deProcess_setError(process, "Process already running");
227 return DE_FALSE;
228 }
229 else if (process->state == PROCESSSTATE_FINISHED)
230 {
231 deProcess_cleanupHandles(process);
232 process->state = PROCESSSTATE_NOT_STARTED;
233 }
234
235 if (pipe(pipeIn) < 0 || pipe(pipeOut) < 0 || pipe(pipeErr) < 0 || pipe(statusPipe) < 0)
236 {
237 deProcess_setErrorFromErrno(process, "pipe() failed");
238
239 closePipe(pipeIn);
240 closePipe(pipeOut);
241 closePipe(pipeErr);
242 closePipe(statusPipe);
243
244 return DE_FALSE;
245 }
246
247 pid = fork();
248
249 if (pid < 0)
250 {
251 deProcess_setErrorFromErrno(process, "fork() failed");
252
253 closePipe(pipeIn);
254 closePipe(pipeOut);
255 closePipe(pipeErr);
256 closePipe(statusPipe);
257
258 return DE_FALSE;
259 }
260
261 if (pid == 0)
262 {
263 /* Child process. */
264
265 /* Close unused endpoints. */
266 close(pipeIn[1]);
267 close(pipeOut[0]);
268 close(pipeErr[0]);
269 close(statusPipe[0]);
270
271 /* Set status pipe to close on exec(). That way parent will know that exec() succeeded. */
272 if (fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC) != 0)
273 dieLastError(statusPipe[1], "Failed to set FD_CLOEXEC");
274
275 /* Map stdin. */
276 if (pipeIn[0] != STDIN_FILENO &&
277 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 &&
283 dup2(pipeOut[1], STDOUT_FILENO) != STDOUT_FILENO)
284 dieLastError(statusPipe[1], "dup2() failed");
285 close(pipeOut[1]);
286
287 /* Stderr. */
288 if (pipeErr[1] != STDERR_FILENO &&
289 dup2(pipeErr[1], STDERR_FILENO) != STDERR_FILENO)
290 dieLastError(statusPipe[1], "dup2() failed");
291 close(pipeErr[1]);
292
293 /* Doesn't return. */
294 execProcess(commandLine, workingDirectory, statusPipe[1]);
295 }
296 else
297 {
298 /* Parent process. */
299
300 /* Check status. */
301 {
302 char errBuf[256];
303 ssize_t result = 0;
304
305 close(statusPipe[1]);
306 while ((result = read(statusPipe[0], errBuf, 1)) == -1)
307 if (errno != EAGAIN && errno != EINTR) break;
308
309 if (result > 0)
310 {
311 int procStatus = 0;
312
313 /* Read full error msg. */
314 int errPos = 1;
315 while (errPos < DE_LENGTH_OF_ARRAY(errBuf))
316 {
317 result = read(statusPipe[0], errBuf+errPos, 1);
318 if (result == -1)
319 break; /* Done. */
320
321 errPos += 1;
322 }
323
324 /* Make sure str is null-terminated. */
325 errBuf[errPos] = 0;
326
327 /* Close handles. */
328 close(statusPipe[0]);
329 closePipe(pipeIn);
330 closePipe(pipeOut);
331 closePipe(pipeErr);
332
333 /* Run waitpid to clean up zombie. */
334 waitpid(pid, &procStatus, 0);
335
336 deProcess_setError(process, errBuf);
337
338 return DE_FALSE;
339 }
340
341 /* Status pipe is not needed. */
342 close(statusPipe[0]);
343 }
344
345 /* Set running state. */
346 process->pid = pid;
347 process->state = PROCESSSTATE_RUNNING;
348
349 /* Stdin, stdout. */
350 close(pipeIn[0]);
351 close(pipeOut[1]);
352 close(pipeErr[1]);
353
354 process->standardIn = deFile_createFromHandle((deUintptr)pipeIn[1]);
355 process->standardOut = deFile_createFromHandle((deUintptr)pipeOut[0]);
356 process->standardErr = deFile_createFromHandle((deUintptr)pipeErr[0]);
357
358 if (!process->standardIn)
359 close(pipeIn[1]);
360
361 if (!process->standardOut)
362 close(pipeOut[0]);
363
364 if (!process->standardErr)
365 close(pipeErr[0]);
366 }
367
368 return DE_TRUE;
369 }
370
deProcess_isRunning(deProcess * process)371 deBool deProcess_isRunning (deProcess* process)
372 {
373 if (process->state == PROCESSSTATE_RUNNING)
374 {
375 int status = 0;
376
377 if (waitpid(process->pid, &status, WNOHANG) == 0)
378 return DE_TRUE; /* No status available. */
379
380 if (WIFEXITED(status) || WIFSIGNALED(status))
381 {
382 /* Child has finished. */
383 process->state = PROCESSSTATE_FINISHED;
384 return DE_FALSE;
385 }
386 else
387 return DE_TRUE;
388 }
389 else
390 return DE_FALSE;
391 }
392
deProcess_waitForFinish(deProcess * process)393 deBool deProcess_waitForFinish (deProcess* process)
394 {
395 int status = 0;
396 pid_t waitResult;
397
398 if (process->state != PROCESSSTATE_RUNNING)
399 {
400 deProcess_setError(process, "Process is not running");
401 return DE_FALSE;
402 }
403
404 /* \note [pyry] Crazy hack for OS X Lion. Stupid Apple. */
405 while ((waitResult = waitpid(process->pid, &status, 0)) != process->pid)
406 if (errno != ENOENT) break;
407
408 if (waitResult != process->pid)
409 {
410 deProcess_setErrorFromErrno(process, "waitpid() failed");
411 return DE_FALSE; /* waitpid() failed. */
412 }
413
414 if (!WIFEXITED(status) && !WIFSIGNALED(status))
415 {
416 deProcess_setErrorFromErrno(process, "waitpid() failed");
417 return DE_FALSE; /* Something strange happened. */
418 }
419
420 process->exitCode = WEXITSTATUS(status);
421 process->state = PROCESSSTATE_FINISHED;
422 return DE_TRUE;
423 }
424
deProcess_sendSignal(deProcess * process,int sigNum)425 static deBool deProcess_sendSignal (deProcess* process, int sigNum)
426 {
427 if (process->state != PROCESSSTATE_RUNNING)
428 {
429 deProcess_setError(process, "Process is not running");
430 return DE_FALSE;
431 }
432
433 if (kill(process->pid, sigNum) == 0)
434 return DE_TRUE;
435 else
436 {
437 deProcess_setErrorFromErrno(process, "kill() failed");
438 return DE_FALSE;
439 }
440 }
441
deProcess_terminate(deProcess * process)442 deBool deProcess_terminate (deProcess* process)
443 {
444 return deProcess_sendSignal(process, SIGTERM);
445 }
446
deProcess_kill(deProcess * process)447 deBool 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 deBool deProcess_closeStdIn (deProcess* process)
468 {
469 if (process->standardIn)
470 {
471 deFile_destroy(process->standardIn);
472 process->standardIn = DE_NULL;
473 return DE_TRUE;
474 }
475 else
476 return DE_FALSE;
477 }
478
deProcess_closeStdOut(deProcess * process)479 deBool deProcess_closeStdOut (deProcess* process)
480 {
481 if (process->standardOut)
482 {
483 deFile_destroy(process->standardOut);
484 process->standardOut = DE_NULL;
485 return DE_TRUE;
486 }
487 else
488 return DE_FALSE;
489 }
490
deProcess_closeStdErr(deProcess * process)491 deBool deProcess_closeStdErr (deProcess* process)
492 {
493 if (process->standardErr)
494 {
495 deFile_destroy(process->standardErr);
496 process->standardErr = DE_NULL;
497 return DE_TRUE;
498 }
499 else
500 return DE_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 deBool 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 deBool 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,
554 NULL, 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 deBool 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 DE_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 DE_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 DE_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 DE_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, workingDirectory, &startInfo, &process->procInfo))
703 {
704 /* Store error info. */
705 deProcess_setErrorFromWin32(process, "CreateProcess() failed");
706
707 /* Close all handles. */
708 CloseHandle(stdInRead);
709 CloseHandle(stdInWrite);
710 CloseHandle(stdOutRead);
711 CloseHandle(stdOutWrite);
712 CloseHandle(stdErrRead);
713 CloseHandle(stdErrWrite);
714
715 return DE_FALSE;
716 }
717
718 process->state = PROCESSSTATE_RUNNING;
719
720 /* Close our ends of handles.*/
721 CloseHandle(stdErrWrite);
722 CloseHandle(stdOutWrite);
723 CloseHandle(stdInRead);
724
725 /* Construct stdio file objects \note May fail, not detected. */
726 process->standardIn = deFile_createFromHandle((deUintptr)stdInWrite);
727 process->standardOut = deFile_createFromHandle((deUintptr)stdOutRead);
728 process->standardErr = deFile_createFromHandle((deUintptr)stdErrRead);
729
730 return DE_TRUE;
731 }
732
deProcess_isRunning(deProcess * process)733 deBool deProcess_isRunning (deProcess* process)
734 {
735 if (process->state == PROCESSSTATE_RUNNING)
736 {
737 int exitCode;
738 BOOL result = GetExitCodeProcess(process->procInfo.hProcess, (LPDWORD)&exitCode);
739
740 if (result != TRUE)
741 {
742 deProcess_setErrorFromWin32(process, "GetExitCodeProcess() failed");
743 return DE_FALSE;
744 }
745
746 if (exitCode == STILL_ACTIVE)
747 return DE_TRUE;
748 else
749 {
750 /* Done. */
751 process->exitCode = exitCode;
752 process->state = PROCESSSTATE_FINISHED;
753 return DE_FALSE;
754 }
755 }
756 else
757 return DE_FALSE;
758 }
759
deProcess_waitForFinish(deProcess * process)760 deBool deProcess_waitForFinish (deProcess* process)
761 {
762 if (process->state == PROCESSSTATE_RUNNING)
763 {
764 if (WaitForSingleObject(process->procInfo.hProcess, INFINITE) != WAIT_OBJECT_0)
765 {
766 deProcess_setErrorFromWin32(process, "WaitForSingleObject() failed");
767 return DE_FALSE;
768 }
769 return !deProcess_isRunning(process);
770 }
771 else
772 {
773 deProcess_setError(process, "Process is not running");
774 return DE_FALSE;
775 }
776 }
777
stopProcess(deProcess * process,deBool kill)778 static deBool stopProcess (deProcess* process, deBool kill)
779 {
780 if (process->state == PROCESSSTATE_RUNNING)
781 {
782 if (!TerminateProcess(process->procInfo.hProcess, kill ? -1 : 0))
783 {
784 deProcess_setErrorFromWin32(process, "TerminateProcess() failed");
785 return DE_FALSE;
786 }
787 else
788 return DE_TRUE;
789 }
790 else
791 {
792 deProcess_setError(process, "Process is not running");
793 return DE_FALSE;
794 }
795 }
796
deProcess_terminate(deProcess * process)797 deBool deProcess_terminate (deProcess* process)
798 {
799 return stopProcess(process, DE_FALSE);
800 }
801
deProcess_kill(deProcess * process)802 deBool deProcess_kill (deProcess* process)
803 {
804 return stopProcess(process, DE_TRUE);
805 }
806
deProcess_getStdIn(deProcess * process)807 deFile* deProcess_getStdIn (deProcess* process)
808 {
809 return process->standardIn;
810 }
811
deProcess_getStdOut(deProcess * process)812 deFile* deProcess_getStdOut (deProcess* process)
813 {
814 return process->standardOut;
815 }
816
deProcess_getStdErr(deProcess * process)817 deFile* deProcess_getStdErr (deProcess* process)
818 {
819 return process->standardErr;
820 }
821
deProcess_closeStdIn(deProcess * process)822 deBool deProcess_closeStdIn (deProcess* process)
823 {
824 if (process->standardIn)
825 {
826 deFile_destroy(process->standardIn);
827 process->standardIn = DE_NULL;
828 return DE_TRUE;
829 }
830 else
831 return DE_FALSE;
832 }
833
deProcess_closeStdOut(deProcess * process)834 deBool deProcess_closeStdOut (deProcess* process)
835 {
836 if (process->standardOut)
837 {
838 deFile_destroy(process->standardOut);
839 process->standardOut = DE_NULL;
840 return DE_TRUE;
841 }
842 else
843 return DE_FALSE;
844 }
845
deProcess_closeStdErr(deProcess * process)846 deBool deProcess_closeStdErr (deProcess* process)
847 {
848 if (process->standardErr)
849 {
850 deFile_destroy(process->standardErr);
851 process->standardErr = DE_NULL;
852 return DE_TRUE;
853 }
854 else
855 return DE_FALSE;
856 }
857
858 #else
859 # error Implement deProcess for your OS.
860 #endif
861