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] 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 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