xref: /aosp_15_r20/external/deqp/framework/delibs/deutil/deProcess.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
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