| 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 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 size_t fd_shuffle_size = 0; | 310 size_t fd_shuffle_size = 0; |
| 311 if (options.fds_to_remap) { | 311 if (options.fds_to_remap) { |
| 312 fd_shuffle_size = options.fds_to_remap->size(); | 312 fd_shuffle_size = options.fds_to_remap->size(); |
| 313 } | 313 } |
| 314 | 314 |
| 315 InjectiveMultimap fd_shuffle1; | 315 InjectiveMultimap fd_shuffle1; |
| 316 InjectiveMultimap fd_shuffle2; | 316 InjectiveMultimap fd_shuffle2; |
| 317 fd_shuffle1.reserve(fd_shuffle_size); | 317 fd_shuffle1.reserve(fd_shuffle_size); |
| 318 fd_shuffle2.reserve(fd_shuffle_size); | 318 fd_shuffle2.reserve(fd_shuffle_size); |
| 319 | 319 |
| 320 std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]); | 320 std::vector<char*> argv_cstr; |
| 321 for (size_t i = 0; i < argv.size(); i++) { | 321 argv_cstr.reserve(argv.size() + 1); |
| 322 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 322 for (const auto& arg : argv) |
| 323 } | 323 argv_cstr.push_back(const_cast<char*>(arg.c_str())); |
| 324 argv_cstr[argv.size()] = nullptr; | 324 argv_cstr.push_back(nullptr); |
| 325 | 325 |
| 326 std::unique_ptr<char* []> new_environ; | 326 std::unique_ptr<char* []> new_environ; |
| 327 char* const empty_environ = nullptr; | 327 char* const empty_environ = nullptr; |
| 328 char* const* old_environ = GetEnvironment(); | 328 char* const* old_environ = GetEnvironment(); |
| 329 if (options.clear_environ) | 329 if (options.clear_environ) |
| 330 old_environ = &empty_environ; | 330 old_environ = &empty_environ; |
| 331 if (!options.environ.empty()) | 331 if (!options.environ.empty()) |
| 332 new_environ = AlterEnvironment(old_environ, options.environ); | 332 new_environ = AlterEnvironment(old_environ, options.environ); |
| 333 | 333 |
| 334 sigset_t full_sigset; | 334 sigset_t full_sigset; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 RAW_CHECK(chdir(current_directory) == 0); | 499 RAW_CHECK(chdir(current_directory) == 0); |
| 500 } | 500 } |
| 501 | 501 |
| 502 if (options.pre_exec_delegate != nullptr) { | 502 if (options.pre_exec_delegate != nullptr) { |
| 503 options.pre_exec_delegate->RunAsyncSafe(); | 503 options.pre_exec_delegate->RunAsyncSafe(); |
| 504 } | 504 } |
| 505 | 505 |
| 506 const char* executable_path = !options.real_path.empty() ? | 506 const char* executable_path = !options.real_path.empty() ? |
| 507 options.real_path.value().c_str() : argv_cstr[0]; | 507 options.real_path.value().c_str() : argv_cstr[0]; |
| 508 | 508 |
| 509 execvp(executable_path, argv_cstr.get()); | 509 execvp(executable_path, argv_cstr.data()); |
| 510 | 510 |
| 511 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); | 511 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); |
| 512 RAW_LOG(ERROR, argv_cstr[0]); | 512 RAW_LOG(ERROR, argv_cstr[0]); |
| 513 _exit(127); | 513 _exit(127); |
| 514 } else { | 514 } else { |
| 515 // Parent process | 515 // Parent process |
| 516 if (options.wait) { | 516 if (options.wait) { |
| 517 // While this isn't strictly disk IO, waiting for another process to | 517 // While this isn't strictly disk IO, waiting for another process to |
| 518 // finish is the sort of thing ThreadRestrictions is trying to prevent. | 518 // finish is the sort of thing ThreadRestrictions is trying to prevent. |
| 519 base::ThreadRestrictions::AssertIOAllowed(); | 519 base::ThreadRestrictions::AssertIOAllowed(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 546 bool include_stderr, | 546 bool include_stderr, |
| 547 std::string* output, | 547 std::string* output, |
| 548 bool do_search_path, | 548 bool do_search_path, |
| 549 int* exit_code) { | 549 int* exit_code) { |
| 550 // Doing a blocking wait for another command to finish counts as IO. | 550 // Doing a blocking wait for another command to finish counts as IO. |
| 551 base::ThreadRestrictions::AssertIOAllowed(); | 551 base::ThreadRestrictions::AssertIOAllowed(); |
| 552 // exit_code must be supplied so calling function can determine success. | 552 // exit_code must be supplied so calling function can determine success. |
| 553 DCHECK(exit_code); | 553 DCHECK(exit_code); |
| 554 *exit_code = EXIT_FAILURE; | 554 *exit_code = EXIT_FAILURE; |
| 555 | 555 |
| 556 int pipe_fd[2]; | 556 // Declare and call reserve() here before calling fork() because the child |
| 557 pid_t pid; | 557 // process cannot allocate memory. |
| 558 InjectiveMultimap fd_shuffle1, fd_shuffle2; | 558 std::vector<char*> argv_cstr; |
| 559 std::unique_ptr<char* []> argv_cstr(new char*[argv.size() + 1]); | 559 argv_cstr.reserve(argv.size() + 1); |
| 560 | 560 InjectiveMultimap fd_shuffle1; |
| 561 InjectiveMultimap fd_shuffle2; |
| 561 fd_shuffle1.reserve(3); | 562 fd_shuffle1.reserve(3); |
| 562 fd_shuffle2.reserve(3); | 563 fd_shuffle2.reserve(3); |
| 563 | 564 |
| 564 // Either |do_search_path| should be false or |envp| should be null, but not | 565 // Either |do_search_path| should be false or |envp| should be null, but not |
| 565 // both. | 566 // both. |
| 566 DCHECK(!do_search_path ^ !envp); | 567 DCHECK(!do_search_path ^ !envp); |
| 567 | 568 |
| 569 int pipe_fd[2]; |
| 568 if (pipe(pipe_fd) < 0) | 570 if (pipe(pipe_fd) < 0) |
| 569 return false; | 571 return false; |
| 570 | 572 |
| 571 switch (pid = fork()) { | 573 pid_t pid = fork(); |
| 572 case -1: // error | 574 switch (pid) { |
| 575 case -1: { |
| 576 // error |
| 573 close(pipe_fd[0]); | 577 close(pipe_fd[0]); |
| 574 close(pipe_fd[1]); | 578 close(pipe_fd[1]); |
| 575 return false; | 579 return false; |
| 576 case 0: // child | 580 } |
| 577 { | 581 case 0: { |
| 578 // DANGER: no calls to malloc or locks are allowed from now on: | 582 // child |
| 579 // http://crbug.com/36678 | 583 // |
| 584 // DANGER: no calls to malloc or locks are allowed from now on: |
| 585 // http://crbug.com/36678 |
| 580 | 586 |
| 581 #if defined(OS_MACOSX) | 587 #if defined(OS_MACOSX) |
| 582 RestoreDefaultExceptionHandler(); | 588 RestoreDefaultExceptionHandler(); |
| 583 #endif | 589 #endif |
| 584 | 590 |
| 585 // Obscure fork() rule: in the child, if you don't end up doing exec*(), | 591 // Obscure fork() rule: in the child, if you don't end up doing exec*(), |
| 586 // you call _exit() instead of exit(). This is because _exit() does not | 592 // you call _exit() instead of exit(). This is because _exit() does not |
| 587 // call any previously-registered (in the parent) exit handlers, which | 593 // call any previously-registered (in the parent) exit handlers, which |
| 588 // might do things like block waiting for threads that don't even exist | 594 // might do things like block waiting for threads that don't even exist |
| 589 // in the child. | 595 // in the child. |
| 590 int dev_null = open("/dev/null", O_WRONLY); | 596 int dev_null = open("/dev/null", O_WRONLY); |
| 591 if (dev_null < 0) | 597 if (dev_null < 0) |
| 592 _exit(127); | 598 _exit(127); |
| 593 | 599 |
| 594 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); | 600 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); |
| 595 fd_shuffle1.push_back(InjectionArc( | 601 fd_shuffle1.push_back(InjectionArc(include_stderr ? pipe_fd[1] : dev_null, |
| 596 include_stderr ? pipe_fd[1] : dev_null, | 602 STDERR_FILENO, true)); |
| 597 STDERR_FILENO, true)); | 603 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); |
| 598 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); | 604 // Adding another element here? Remeber to increase the argument to |
| 599 // Adding another element here? Remeber to increase the argument to | 605 // reserve(), above. |
| 600 // reserve(), above. | |
| 601 | 606 |
| 602 for (size_t i = 0; i < fd_shuffle1.size(); ++i) | 607 for (size_t i = 0; i < fd_shuffle1.size(); ++i) |
| 603 fd_shuffle2.push_back(fd_shuffle1[i]); | 608 fd_shuffle2.push_back(fd_shuffle1[i]); |
| 604 | 609 |
| 605 if (!ShuffleFileDescriptors(&fd_shuffle1)) | 610 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
| 606 _exit(127); | 611 _exit(127); |
| 607 | 612 |
| 608 CloseSuperfluousFds(fd_shuffle2); | 613 CloseSuperfluousFds(fd_shuffle2); |
| 609 | 614 |
| 610 for (size_t i = 0; i < argv.size(); i++) | 615 for (const auto& arg : argv) |
| 611 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 616 argv_cstr.push_back(const_cast<char*>(arg.c_str())); |
| 612 argv_cstr[argv.size()] = nullptr; | 617 argv_cstr.push_back(nullptr); |
| 613 if (do_search_path) | 618 |
| 614 execvp(argv_cstr[0], argv_cstr.get()); | 619 if (do_search_path) |
| 615 else | 620 execvp(argv_cstr[0], argv_cstr.data()); |
| 616 execve(argv_cstr[0], argv_cstr.get(), envp); | 621 else |
| 617 _exit(127); | 622 execve(argv_cstr[0], argv_cstr.data(), envp); |
| 623 _exit(127); |
| 624 } |
| 625 default: { |
| 626 // parent |
| 627 // |
| 628 // Close our writing end of pipe now. Otherwise later read would not |
| 629 // be able to detect end of child's output (in theory we could still |
| 630 // write to the pipe). |
| 631 close(pipe_fd[1]); |
| 632 |
| 633 output->clear(); |
| 634 |
| 635 while (true) { |
| 636 char buffer[256]; |
| 637 ssize_t bytes_read = |
| 638 HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); |
| 639 if (bytes_read <= 0) |
| 640 break; |
| 641 output->append(buffer, bytes_read); |
| 618 } | 642 } |
| 619 default: // parent | 643 close(pipe_fd[0]); |
| 620 { | |
| 621 // Close our writing end of pipe now. Otherwise later read would not | |
| 622 // be able to detect end of child's output (in theory we could still | |
| 623 // write to the pipe). | |
| 624 close(pipe_fd[1]); | |
| 625 | 644 |
| 626 output->clear(); | 645 // Always wait for exit code (even if we know we'll declare |
| 627 | 646 // GOT_MAX_OUTPUT). |
| 628 while (true) { | 647 Process process(pid); |
| 629 char buffer[256]; | 648 return process.WaitForExit(exit_code); |
| 630 ssize_t bytes_read = | 649 } |
| 631 HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); | |
| 632 if (bytes_read <= 0) | |
| 633 break; | |
| 634 output->append(buffer, bytes_read); | |
| 635 } | |
| 636 close(pipe_fd[0]); | |
| 637 | |
| 638 // Always wait for exit code (even if we know we'll declare | |
| 639 // GOT_MAX_OUTPUT). | |
| 640 Process process(pid); | |
| 641 return process.WaitForExit(exit_code); | |
| 642 } | |
| 643 } | 650 } |
| 644 } | 651 } |
| 645 | 652 |
| 646 bool GetAppOutput(const CommandLine& cl, std::string* output) { | 653 bool GetAppOutput(const CommandLine& cl, std::string* output) { |
| 647 return GetAppOutput(cl.argv(), output); | 654 return GetAppOutput(cl.argv(), output); |
| 648 } | 655 } |
| 649 | 656 |
| 650 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { | 657 bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { |
| 651 // Run |execve()| with the current environment. | 658 // Run |execve()| with the current environment. |
| 652 int exit_code; | 659 int exit_code; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 766 jmp_buf env; | 773 jmp_buf env; |
| 767 if (setjmp(env) == 0) { | 774 if (setjmp(env) == 0) { |
| 768 return CloneAndLongjmpInChild(flags, ptid, ctid, &env); | 775 return CloneAndLongjmpInChild(flags, ptid, ctid, &env); |
| 769 } | 776 } |
| 770 | 777 |
| 771 return 0; | 778 return 0; |
| 772 } | 779 } |
| 773 #endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) | 780 #endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) |
| 774 | 781 |
| 775 } // namespace base | 782 } // namespace base |
| OLD | NEW |