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 	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 
     71 static 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 
     79 DE_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 
     90 static 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. */
    108 static 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 
    135 deProcess* 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 
    146 static 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 
    163 void 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 
    177 const char* deProcess_getLastError (const deProcess* process)
    178 {
    179 	return process->lastError ? process->lastError : "No error";
    180 }
    181 
    182 int deProcess_getExitCode (const deProcess* process)
    183 {
    184 	return process->exitCode;
    185 }
    186 
    187 static 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 
    199 static 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 
    207 static 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 
    215 deBool 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 
    368 deBool 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 
    390 deBool 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 
    422 static 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 
    439 deBool deProcess_terminate (deProcess* process)
    440 {
    441 	return deProcess_sendSignal(process, SIGTERM);
    442 }
    443 
    444 deBool deProcess_kill (deProcess* process)
    445 {
    446 	return deProcess_sendSignal(process, SIGKILL);
    447 }
    448 
    449 deFile* deProcess_getStdIn (deProcess* process)
    450 {
    451 	return process->standardIn;
    452 }
    453 
    454 deFile* deProcess_getStdOut (deProcess* process)
    455 {
    456 	return process->standardOut;
    457 }
    458 
    459 deFile* deProcess_getStdErr (deProcess* process)
    460 {
    461 	return process->standardErr;
    462 }
    463 
    464 deBool 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 
    476 deBool 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 
    488 deBool 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 
    507 typedef enum ProcessState_e
    508 {
    509 	PROCESSSTATE_NOT_STARTED = 0,
    510 	PROCESSSTATE_RUNNING,
    511 	PROCESSSTATE_FINISHED,
    512 
    513 	PROCESSSTATE_LAST
    514 } ProcessState;
    515 
    516 struct 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 
    528 static 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 
    540 static 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 
    565 deProcess* 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 
    576 void 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 
    602 void 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 
    615 const char* deProcess_getLastError (const deProcess* process)
    616 {
    617 	return process->lastError ? process->lastError : "No error";
    618 }
    619 
    620 int deProcess_getExitCode (const deProcess* process)
    621 {
    622 	return process->exitCode;
    623 }
    624 
    625 deBool 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 
    730 deBool 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 
    757 deBool 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 
    775 static 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 
    794 deBool deProcess_terminate (deProcess* process)
    795 {
    796 	return stopProcess(process, DE_FALSE);
    797 }
    798 
    799 deBool deProcess_kill (deProcess* process)
    800 {
    801 	return stopProcess(process, DE_TRUE);
    802 }
    803 
    804 deFile* deProcess_getStdIn (deProcess* process)
    805 {
    806 	return process->standardIn;
    807 }
    808 
    809 deFile* deProcess_getStdOut (deProcess* process)
    810 {
    811 	return process->standardOut;
    812 }
    813 
    814 deFile* deProcess_getStdErr (deProcess* process)
    815 {
    816 	return process->standardErr;
    817 }
    818 
    819 deBool 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 
    831 deBool 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 
    843 deBool 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