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