| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <dirent.h> | 5 #include <dirent.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <poll.h> | |
| 9 #include <signal.h> | 8 #include <signal.h> |
| 10 #include <stdlib.h> | 9 #include <stdlib.h> |
| 11 #include <sys/resource.h> | 10 #include <sys/resource.h> |
| 12 #include <sys/time.h> | 11 #include <sys/time.h> |
| 13 #include <sys/types.h> | 12 #include <sys/types.h> |
| 14 #include <sys/wait.h> | 13 #include <sys/wait.h> |
| 15 #include <unistd.h> | 14 #include <unistd.h> |
| 16 | 15 |
| 17 #include <limits> | 16 #include <limits> |
| 18 #include <set> | 17 #include <set> |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 } | 730 } |
| 732 | 731 |
| 733 int64 TimeValToMicroseconds(const struct timeval& tv) { | 732 int64 TimeValToMicroseconds(const struct timeval& tv) { |
| 734 static const int kMicrosecondsPerSecond = 1000000; | 733 static const int kMicrosecondsPerSecond = 1000000; |
| 735 int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow. | 734 int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow. |
| 736 ret *= kMicrosecondsPerSecond; | 735 ret *= kMicrosecondsPerSecond; |
| 737 ret += tv.tv_usec; | 736 ret += tv.tv_usec; |
| 738 return ret; | 737 return ret; |
| 739 } | 738 } |
| 740 | 739 |
| 741 // Executes the application specified by |cl| and waits for it to exit, but | 740 // Executes the application specified by |cl| and wait for it to exit. Stores |
| 742 // at most |timeout_milliseconds| (use kNoTimeout for no timeout). Stores | 741 // the output (stdout) in |output|. If |do_search_path| is set, it searches the |
| 743 // the output (stdout) in |output|, and whether or not the timeout | |
| 744 // triggered in |timed_out|. If |do_search_path| is set, it searches the | |
| 745 // path for the application; in that case, |envp| must be null, and it will use | 742 // path for the application; in that case, |envp| must be null, and it will use |
| 746 // the current environment. If |do_search_path| is false, |cl| should fully | 743 // the current environment. If |do_search_path| is false, |cl| should fully |
| 747 // specify the path of the application, and |envp| will be used as the | 744 // specify the path of the application, and |envp| will be used as the |
| 748 // environment. Redirects stderr to /dev/null. Returns true on success | 745 // environment. Redirects stderr to /dev/null. Returns true on success |
| 749 // (application launched and exited cleanly, with exit code indicating success). | 746 // (application launched and exited cleanly, with exit code indicating success). |
| 750 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], | 747 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], |
| 751 std::string* output, size_t max_output, | 748 std::string* output, size_t max_output, |
| 752 bool do_search_path, bool* timed_out, | 749 bool do_search_path) { |
| 753 int timeout_milliseconds) { | |
| 754 int pipe_fd[2]; | 750 int pipe_fd[2]; |
| 755 pid_t pid; | 751 pid_t pid; |
| 756 InjectiveMultimap fd_shuffle1, fd_shuffle2; | 752 InjectiveMultimap fd_shuffle1, fd_shuffle2; |
| 757 const std::vector<std::string>& argv = cl.argv(); | 753 const std::vector<std::string>& argv = cl.argv(); |
| 758 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); | 754 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); |
| 759 | 755 |
| 760 fd_shuffle1.reserve(3); | 756 fd_shuffle1.reserve(3); |
| 761 fd_shuffle2.reserve(3); | 757 fd_shuffle2.reserve(3); |
| 762 | 758 |
| 763 // Either |do_search_path| should be false or |envp| should be null, but not | 759 // Either |do_search_path| should be false or |envp| should be null, but not |
| (...skipping 21 matching lines...) Expand all Loading... |
| 785 // call any previously-registered (in the parent) exit handlers, which | 781 // call any previously-registered (in the parent) exit handlers, which |
| 786 // might do things like block waiting for threads that don't even exist | 782 // might do things like block waiting for threads that don't even exist |
| 787 // in the child. | 783 // in the child. |
| 788 int dev_null = open("/dev/null", O_WRONLY); | 784 int dev_null = open("/dev/null", O_WRONLY); |
| 789 if (dev_null < 0) | 785 if (dev_null < 0) |
| 790 _exit(127); | 786 _exit(127); |
| 791 | 787 |
| 792 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); | 788 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); |
| 793 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); | 789 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); |
| 794 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); | 790 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); |
| 795 // Adding another element here? Remember to increase the argument to | 791 // Adding another element here? Remeber to increase the argument to |
| 796 // reserve(), above. | 792 // reserve(), above. |
| 797 | 793 |
| 798 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), | 794 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), |
| 799 std::back_inserter(fd_shuffle2)); | 795 std::back_inserter(fd_shuffle2)); |
| 800 | 796 |
| 801 if (!ShuffleFileDescriptors(&fd_shuffle1)) | 797 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
| 802 _exit(127); | 798 _exit(127); |
| 803 | 799 |
| 804 CloseSuperfluousFds(fd_shuffle2); | 800 CloseSuperfluousFds(fd_shuffle2); |
| 805 | 801 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 818 // be able to detect end of child's output (in theory we could still | 814 // be able to detect end of child's output (in theory we could still |
| 819 // write to the pipe). | 815 // write to the pipe). |
| 820 close(pipe_fd[1]); | 816 close(pipe_fd[1]); |
| 821 | 817 |
| 822 output->clear(); | 818 output->clear(); |
| 823 char buffer[256]; | 819 char buffer[256]; |
| 824 size_t output_buf_left = max_output; | 820 size_t output_buf_left = max_output; |
| 825 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| | 821 ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| |
| 826 // case in the logic below. | 822 // case in the logic below. |
| 827 | 823 |
| 828 *timed_out = false; | |
| 829 const Time timeout_time = Time::Now() + | |
| 830 TimeDelta::FromMilliseconds(timeout_milliseconds); | |
| 831 int remaining_ms = timeout_milliseconds; | |
| 832 while (output_buf_left > 0) { | 824 while (output_buf_left > 0) { |
| 833 struct pollfd poll_struct = { pipe_fd[0], POLLIN, 0 }; | |
| 834 const int poll_ret_code = poll(&poll_struct, 1, remaining_ms); | |
| 835 | |
| 836 // poll() should only fail due to interrupt. | |
| 837 DCHECK(poll_ret_code != -1 || errno == EINTR); | |
| 838 if (poll_ret_code == 0) { | |
| 839 *timed_out = true; | |
| 840 break; | |
| 841 } | |
| 842 | |
| 843 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, | 825 bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, |
| 844 std::min(output_buf_left, sizeof(buffer)))); | 826 std::min(output_buf_left, sizeof(buffer)))); |
| 845 if (bytes_read <= 0) | 827 if (bytes_read <= 0) |
| 846 break; | 828 break; |
| 847 output->append(buffer, bytes_read); | 829 output->append(buffer, bytes_read); |
| 848 output_buf_left -= static_cast<size_t>(bytes_read); | 830 output_buf_left -= static_cast<size_t>(bytes_read); |
| 849 | |
| 850 // Update remaining_ms if we're not using an infinite timeout. | |
| 851 if (timeout_milliseconds >= 0) { | |
| 852 remaining_ms = (timeout_time - Time::Now()).InMilliseconds(); | |
| 853 if (remaining_ms < 0) { | |
| 854 *timed_out = true; | |
| 855 break; | |
| 856 } | |
| 857 } | |
| 858 } | 831 } |
| 859 close(pipe_fd[0]); | 832 close(pipe_fd[0]); |
| 860 | 833 |
| 861 bool success = false; | 834 // Always wait for exit code (even if we know we'll declare success). |
| 862 int exit_code = PROCESS_END_PROCESS_WAS_HUNG; | 835 int exit_code = EXIT_FAILURE; |
| 863 if (*timed_out) { | 836 bool success = WaitForExitCode(pid, &exit_code); |
| 864 KillProcess(pid, exit_code, true); | |
| 865 // This waits up to 60 seconds for process to actually be dead | |
| 866 // which means this may overrun the timeout. | |
| 867 LOG(ERROR) << "Process "<< pid << " killed by timeout (waited " | |
| 868 << timeout_milliseconds << " ms)."; | |
| 869 } else { | |
| 870 success = WaitForExitCode(pid, &exit_code); | |
| 871 } | |
| 872 | 837 |
| 873 // If we stopped because we read as much as we wanted, we always declare | 838 // If we stopped because we read as much as we wanted, we always declare |
| 874 // success (because the child may exit due to |SIGPIPE|). | 839 // success (because the child may exit due to |SIGPIPE|). |
| 875 if (output_buf_left || bytes_read <= 0) { | 840 if (output_buf_left || bytes_read <= 0) { |
| 876 if (!success || exit_code != EXIT_SUCCESS) | 841 if (!success || exit_code != EXIT_SUCCESS) |
| 877 return false; | 842 return false; |
| 878 } | 843 } |
| 879 | 844 |
| 880 return true; | 845 return true; |
| 881 } | 846 } |
| 882 } | 847 } |
| 883 } | 848 } |
| 884 | 849 |
| 885 bool GetAppOutput(const CommandLine& cl, std::string* output) { | 850 bool GetAppOutput(const CommandLine& cl, std::string* output) { |
| 886 // Run |execve()| with the current environment and store "unlimited" data. | 851 // Run |execve()| with the current environment and store "unlimited" data. |
| 887 bool timed_out; | |
| 888 return GetAppOutputInternal(cl, NULL, output, | 852 return GetAppOutputInternal(cl, NULL, output, |
| 889 std::numeric_limits<std::size_t>::max(), true, | 853 std::numeric_limits<std::size_t>::max(), true); |
| 890 &timed_out, base::kNoTimeout); | |
| 891 } | 854 } |
| 892 | 855 |
| 893 bool GetAppOutputWithTimeout(const CommandLine& cl, std::string* output, | 856 // TODO(viettrungluu): Conceivably, we should have a timeout as well, so we |
| 894 bool* timed_out, int timeout_milliseconds) { | 857 // don't hang if what we're calling hangs. |
| 895 return GetAppOutputInternal(cl, NULL, output, | |
| 896 std::numeric_limits<std::size_t>::max(), true, | |
| 897 timed_out, timeout_milliseconds); | |
| 898 } | |
| 899 | |
| 900 bool GetAppOutputRestricted(const CommandLine& cl, | 858 bool GetAppOutputRestricted(const CommandLine& cl, |
| 901 std::string* output, size_t max_output) { | 859 std::string* output, size_t max_output) { |
| 902 // Run |execve()| with the empty environment. | 860 // Run |execve()| with the empty environment. |
| 903 char* const empty_environ = NULL; | 861 char* const empty_environ = NULL; |
| 904 bool timed_out; | 862 return GetAppOutputInternal(cl, &empty_environ, output, max_output, false); |
| 905 return GetAppOutputInternal(cl, &empty_environ, output, max_output, false, | |
| 906 &timed_out, base::kNoTimeout); | |
| 907 } | 863 } |
| 908 | 864 |
| 909 bool WaitForProcessesToExit(const std::wstring& executable_name, | 865 bool WaitForProcessesToExit(const std::wstring& executable_name, |
| 910 int64 wait_milliseconds, | 866 int64 wait_milliseconds, |
| 911 const ProcessFilter* filter) { | 867 const ProcessFilter* filter) { |
| 912 bool result = false; | 868 bool result = false; |
| 913 | 869 |
| 914 // TODO(port): This is inefficient, but works if there are multiple procs. | 870 // TODO(port): This is inefficient, but works if there are multiple procs. |
| 915 // TODO(port): use waitpid to avoid leaving zombies around | 871 // TODO(port): use waitpid to avoid leaving zombies around |
| 916 | 872 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 934 const ProcessFilter* filter) { | 890 const ProcessFilter* filter) { |
| 935 bool exited_cleanly = | 891 bool exited_cleanly = |
| 936 WaitForProcessesToExit(executable_name, wait_milliseconds, | 892 WaitForProcessesToExit(executable_name, wait_milliseconds, |
| 937 filter); | 893 filter); |
| 938 if (!exited_cleanly) | 894 if (!exited_cleanly) |
| 939 KillProcesses(executable_name, exit_code, filter); | 895 KillProcesses(executable_name, exit_code, filter); |
| 940 return exited_cleanly; | 896 return exited_cleanly; |
| 941 } | 897 } |
| 942 | 898 |
| 943 } // namespace base | 899 } // namespace base |
| OLD | NEW |