Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/process/launch.h" | 5 #include "base/process/launch.h" |
| 6 | 6 |
| 7 #include <dirent.h> | 7 #include <dirent.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <sched.h> | 10 #include <sched.h> |
| (...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 } | 504 } |
| 505 | 505 |
| 506 return Process(pid); | 506 return Process(pid); |
| 507 } | 507 } |
| 508 | 508 |
| 509 void RaiseProcessToHighPriority() { | 509 void RaiseProcessToHighPriority() { |
| 510 // On POSIX, we don't actually do anything here. We could try to nice() or | 510 // On POSIX, we don't actually do anything here. We could try to nice() or |
| 511 // setpriority() or sched_getscheduler, but these all require extra rights. | 511 // setpriority() or sched_getscheduler, but these all require extra rights. |
| 512 } | 512 } |
| 513 | 513 |
| 514 // Return value used by GetAppOutputInternal to encapsulate the various exit | |
| 515 // scenarios from the function. | |
| 516 enum GetAppOutputInternalResult { | |
| 517 EXECUTE_FAILURE, | |
| 518 EXECUTE_SUCCESS, | |
| 519 GOT_MAX_OUTPUT, | |
| 520 }; | |
| 521 | |
| 522 // Executes the application specified by |argv| and wait for it to exit. Stores | 514 // Executes the application specified by |argv| and wait for it to exit. Stores |
| 523 // the output (stdout) in |output|. If |do_search_path| is set, it searches the | 515 // the output (stdout) in |output|. If |do_search_path| is set, it searches the |
| 524 // path for the application; in that case, |envp| must be null, and it will use | 516 // path for the application; in that case, |envp| must be null, and it will use |
| 525 // the current environment. If |do_search_path| is false, |argv[0]| should fully | 517 // the current environment. If |do_search_path| is false, |argv[0]| should fully |
| 526 // specify the path of the application, and |envp| will be used as the | 518 // specify the path of the application, and |envp| will be used as the |
| 527 // environment. If |include_stderr| is true, includes stderr otherwise redirects | 519 // environment. If |include_stderr| is true, includes stderr otherwise redirects |
| 528 // it to /dev/null. | 520 // it to /dev/null. |
| 529 // If we successfully start the application and get all requested output, we | 521 // The return value of the function indicates success or failure. In the case of |
| 530 // return GOT_MAX_OUTPUT, or if there is a problem starting or exiting | 522 // success, the application exit code will be returned in |*exit_code|, which |
| 531 // the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS. | 523 // should be checked to determine if the application ran successfully. |
| 532 // The GOT_MAX_OUTPUT return value exists so a caller that asks for limited | 524 static bool GetAppOutputInternal( |
| 533 // output can treat this as a success, despite having an exit code of SIG_PIPE | |
| 534 // due to us closing the output pipe. | |
| 535 // In the case of EXECUTE_SUCCESS, the application exit code will be returned | |
| 536 // in |*exit_code|, which should be checked to determine if the application | |
| 537 // ran successfully. | |
| 538 static GetAppOutputInternalResult GetAppOutputInternal( | |
| 539 const std::vector<std::string>& argv, | 525 const std::vector<std::string>& argv, |
| 540 char* const envp[], | 526 char* const envp[], |
| 541 bool include_stderr, | 527 bool include_stderr, |
| 542 std::string* output, | 528 std::string* output, |
| 543 size_t max_output, | |
| 544 bool do_search_path, | 529 bool do_search_path, |
| 545 int* exit_code) { | 530 int* exit_code) { |
| 546 // Doing a blocking wait for another command to finish counts as IO. | 531 // Doing a blocking wait for another command to finish counts as IO. |
| 547 base::ThreadRestrictions::AssertIOAllowed(); | 532 base::ThreadRestrictions::AssertIOAllowed(); |
| 548 // exit_code must be supplied so calling function can determine success. | 533 // exit_code must be supplied so calling function can determine success. |
| 549 DCHECK(exit_code); | 534 DCHECK(exit_code); |
| 550 *exit_code = EXIT_FAILURE; | 535 *exit_code = EXIT_FAILURE; |
| 551 | 536 |
| 552 int pipe_fd[2]; | 537 int pipe_fd[2]; |
| 553 pid_t pid; | 538 pid_t pid; |
| 554 InjectiveMultimap fd_shuffle1, fd_shuffle2; | 539 InjectiveMultimap fd_shuffle1, fd_shuffle2; |
| 555 std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]); | 540 std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]); |
| 556 | 541 |
| 557 fd_shuffle1.reserve(3); | 542 fd_shuffle1.reserve(3); |
| 558 fd_shuffle2.reserve(3); | 543 fd_shuffle2.reserve(3); |
| 559 | 544 |
| 560 // Either |do_search_path| should be false or |envp| should be null, but not | 545 // Either |do_search_path| should be false or |envp| should be null, but not |
| 561 // both. | 546 // both. |
| 562 DCHECK(!do_search_path ^ !envp); | 547 DCHECK(!do_search_path ^ !envp); |
| 563 | 548 |
| 564 if (pipe(pipe_fd) < 0) | 549 if (pipe(pipe_fd) < 0) |
| 565 return EXECUTE_FAILURE; | 550 return false; |
| 566 | 551 |
| 567 switch (pid = fork()) { | 552 switch (pid = fork()) { |
| 568 case -1: // error | 553 case -1: // error |
| 569 close(pipe_fd[0]); | 554 close(pipe_fd[0]); |
| 570 close(pipe_fd[1]); | 555 close(pipe_fd[1]); |
| 571 return EXECUTE_FAILURE; | 556 return false; |
| 572 case 0: // child | 557 case 0: // child |
| 573 { | 558 { |
| 574 // DANGER: no calls to malloc or locks are allowed from now on: | 559 // DANGER: no calls to malloc or locks are allowed from now on: |
| 575 // http://crbug.com/36678 | 560 // http://crbug.com/36678 |
| 576 | 561 |
| 577 #if defined(OS_MACOSX) | 562 #if defined(OS_MACOSX) |
| 578 RestoreDefaultExceptionHandler(); | 563 RestoreDefaultExceptionHandler(); |
| 579 #endif | 564 #endif |
| 580 | 565 |
| 581 // Obscure fork() rule: in the child, if you don't end up doing exec*(), | 566 // Obscure fork() rule: in the child, if you don't end up doing exec*(), |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 } | 599 } |
| 615 default: // parent | 600 default: // parent |
| 616 { | 601 { |
| 617 // Close our writing end of pipe now. Otherwise later read would not | 602 // Close our writing end of pipe now. Otherwise later read would not |
| 618 // be able to detect end of child's output (in theory we could still | 603 // be able to detect end of child's output (in theory we could still |
| 619 // write to the pipe). | 604 // write to the pipe). |
| 620 close(pipe_fd[1]); | 605 close(pipe_fd[1]); |
| 621 | 606 |
| 622 output->clear(); | 607 output->clear(); |
| 623 char buffer[256]; | 608 char buffer[256]; |
| 624 size_t output_buf_left = max_output; | 609 ssize_t bytes_read = 0; |
|
Lei Zhang
2016/07/04 20:33:04
This can be declared in the while loop now.
benwells
2016/07/05 03:48:38
Done.
| |
| 625 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| | |
| 626 // case in the logic below. | |
| 627 | 610 |
| 628 while (output_buf_left > 0) { | 611 while (true) { |
| 629 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, | 612 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); |
| 630 std::min(output_buf_left, sizeof(buffer)))); | |
| 631 if (bytes_read <= 0) | 613 if (bytes_read <= 0) |
| 632 break; | 614 break; |
| 633 output->append(buffer, bytes_read); | 615 output->append(buffer, bytes_read); |
| 634 output_buf_left -= static_cast<size_t>(bytes_read); | |
| 635 } | 616 } |
| 636 close(pipe_fd[0]); | 617 close(pipe_fd[0]); |
| 637 | 618 |
| 638 // Always wait for exit code (even if we know we'll declare | 619 // Always wait for exit code (even if we know we'll declare |
| 639 // GOT_MAX_OUTPUT). | 620 // GOT_MAX_OUTPUT). |
| 640 Process process(pid); | 621 Process process(pid); |
| 641 bool success = process.WaitForExit(exit_code); | 622 bool success = process.WaitForExit(exit_code); |
|
Lei Zhang
2016/07/04 20:33:04
No need for a success variable. Just return.
benwells
2016/07/05 03:48:38
Done.
| |
| 642 | 623 |
| 643 // If we stopped because we read as much as we wanted, we return | 624 if (success) |
| 644 // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|). | 625 return true; |
| 645 if (!output_buf_left && bytes_read > 0) | 626 return false; |
| 646 return GOT_MAX_OUTPUT; | |
| 647 else if (success) | |
| 648 return EXECUTE_SUCCESS; | |
| 649 return EXECUTE_FAILURE; | |
| 650 } | 627 } |
| 651 } | 628 } |
| 652 } | 629 } |
| 653 | 630 |
| 654 bool GetAppOutput(const CommandLine& cl, std::string* output) { | 631 bool GetAppOutput(const CommandLine& cl, std::string* output) { |
| 655 return GetAppOutput(cl.argv(), output); | 632 return GetAppOutput(cl.argv(), output); |
| 656 } | 633 } |
| 657 | 634 |
| 658 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { | 635 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { |
| 659 // Run |execve()| with the current environment and store "unlimited" data. | 636 // Run |execve()| with the current environment and store "unlimited" data. |
| 660 int exit_code; | 637 int exit_code; |
| 661 GetAppOutputInternalResult result = GetAppOutputInternal( | 638 bool result = |
| 662 argv, NULL, false, output, std::numeric_limits<std::size_t>::max(), true, | 639 GetAppOutputInternal(argv, NULL, false, output, true, &exit_code); |
|
Lei Zhang
2016/07/04 20:33:04
Might as well s/NULL/nullptr/ while we are here.
benwells
2016/07/05 03:48:38
Done.
| |
| 663 &exit_code); | 640 return result && exit_code == EXIT_SUCCESS; |
| 664 return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; | |
| 665 } | 641 } |
| 666 | 642 |
| 667 bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { | 643 bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { |
| 668 // Run |execve()| with the current environment and store "unlimited" data. | 644 // Run |execve()| with the current environment and store "unlimited" data. |
| 669 int exit_code; | 645 int exit_code; |
| 670 GetAppOutputInternalResult result = GetAppOutputInternal( | 646 bool result = |
| 671 cl.argv(), NULL, true, output, std::numeric_limits<std::size_t>::max(), | 647 GetAppOutputInternal(cl.argv(), NULL, true, output, true, &exit_code); |
| 672 true, &exit_code); | 648 return result && exit_code == EXIT_SUCCESS; |
| 673 return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; | |
| 674 } | |
| 675 | |
| 676 // TODO(viettrungluu): Conceivably, we should have a timeout as well, so we | |
| 677 // don't hang if what we're calling hangs. | |
| 678 bool GetAppOutputRestricted(const CommandLine& cl, | |
| 679 std::string* output, size_t max_output) { | |
| 680 // Run |execve()| with the empty environment. | |
| 681 char* const empty_environ = NULL; | |
| 682 int exit_code; | |
| 683 GetAppOutputInternalResult result = GetAppOutputInternal( | |
| 684 cl.argv(), &empty_environ, false, output, max_output, false, &exit_code); | |
| 685 return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS && | |
| 686 exit_code == EXIT_SUCCESS); | |
| 687 } | 649 } |
| 688 | 650 |
| 689 bool GetAppOutputWithExitCode(const CommandLine& cl, | 651 bool GetAppOutputWithExitCode(const CommandLine& cl, |
| 690 std::string* output, | 652 std::string* output, |
| 691 int* exit_code) { | 653 int* exit_code) { |
| 692 // Run |execve()| with the current environment and store "unlimited" data. | 654 // Run |execve()| with the current environment and store "unlimited" data. |
| 693 GetAppOutputInternalResult result = GetAppOutputInternal( | 655 return GetAppOutputInternal(cl.argv(), NULL, false, output, true, exit_code); |
| 694 cl.argv(), NULL, false, output, std::numeric_limits<std::size_t>::max(), | |
| 695 true, exit_code); | |
| 696 return result == EXECUTE_SUCCESS; | |
| 697 } | 656 } |
| 698 | 657 |
| 699 #endif // !defined(OS_NACL_NONSFI) | 658 #endif // !defined(OS_NACL_NONSFI) |
| 700 | 659 |
| 701 #if defined(OS_LINUX) || defined(OS_NACL_NONSFI) | 660 #if defined(OS_LINUX) || defined(OS_NACL_NONSFI) |
| 702 namespace { | 661 namespace { |
| 703 | 662 |
| 704 bool IsRunningOnValgrind() { | 663 bool IsRunningOnValgrind() { |
| 705 return RUNNING_ON_VALGRIND; | 664 return RUNNING_ON_VALGRIND; |
| 706 } | 665 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 783 jmp_buf env; | 742 jmp_buf env; |
| 784 if (setjmp(env) == 0) { | 743 if (setjmp(env) == 0) { |
| 785 return CloneAndLongjmpInChild(flags, ptid, ctid, &env); | 744 return CloneAndLongjmpInChild(flags, ptid, ctid, &env); |
| 786 } | 745 } |
| 787 | 746 |
| 788 return 0; | 747 return 0; |
| 789 } | 748 } |
| 790 #endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) | 749 #endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) |
| 791 | 750 |
| 792 } // namespace base | 751 } // namespace base |
| OLD | NEW |