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