Home | History | Annotate | Download | only in deutil
      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 
     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 
     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 
     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 
     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. */
    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 
    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 
    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 
    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 
    178 const char* deProcess_getLastError (const deProcess* process)
    179 {
    180 	return process->lastError ? process->lastError : "No error";
    181 }
    182 
    183 int deProcess_getExitCode (const deProcess* process)
    184 {
    185 	return process->exitCode;
    186 }
    187 
    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 
    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 
    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 
    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 
    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 
    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] HACK, apparently needed by some versions of OS X. */
    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 
    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 
    442 deBool deProcess_terminate (deProcess* process)
    443 {
    444 	return deProcess_sendSignal(process, SIGTERM);
    445 }
    446 
    447 deBool deProcess_kill (deProcess* process)
    448 {
    449 	return deProcess_sendSignal(process, SIGKILL);
    450 }
    451 
    452 deFile* deProcess_getStdIn (deProcess* process)
    453 {
    454 	return process->standardIn;
    455 }
    456 
    457 deFile* deProcess_getStdOut (deProcess* process)
    458 {
    459 	return process->standardOut;
    460 }
    461 
    462 deFile* deProcess_getStdErr (deProcess* process)
    463 {
    464 	return process->standardErr;
    465 }
    466 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    618 const char* deProcess_getLastError (const deProcess* process)
    619 {
    620 	return process->lastError ? process->lastError : "No error";
    621 }
    622 
    623 int deProcess_getExitCode (const deProcess* process)
    624 {
    625 	return process->exitCode;
    626 }
    627 
    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 
    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 
    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 
    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 
    797 deBool deProcess_terminate (deProcess* process)
    798 {
    799 	return stopProcess(process, DE_FALSE);
    800 }
    801 
    802 deBool deProcess_kill (deProcess* process)
    803 {
    804 	return stopProcess(process, DE_TRUE);
    805 }
    806 
    807 deFile* deProcess_getStdIn (deProcess* process)
    808 {
    809 	return process->standardIn;
    810 }
    811 
    812 deFile* deProcess_getStdOut (deProcess* process)
    813 {
    814 	return process->standardOut;
    815 }
    816 
    817 deFile* deProcess_getStdErr (deProcess* process)
    818 {
    819 	return process->standardErr;
    820 }
    821 
    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 
    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 
    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