OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <chromeos/process.h> | |
6 | |
7 #include <sys/stat.h> | |
8 #include <sys/types.h> | |
9 #include <sys/wait.h> | |
10 #include <fcntl.h> | |
11 | |
12 #include <map> | |
13 | |
14 #include <base/eintr_wrapper.h> | |
15 #include <base/file_util.h> | |
16 #include <base/logging.h> | |
17 #include <base/string_number_conversions.h> | |
18 #include <base/string_util.h> | |
19 #include <base/time.h> | |
20 | |
21 namespace chromeos { | |
22 | |
23 Process::Process() { | |
24 } | |
25 | |
26 Process::~Process() { | |
27 } | |
28 | |
29 bool Process::ProcessExists(pid_t pid) { | |
30 return file_util::DirectoryExists(FilePath(StringPrintf("/proc/%d", pid))); | |
31 } | |
32 | |
33 ProcessImpl::ProcessImpl() : pid_(0) { | |
34 } | |
35 | |
36 ProcessImpl::~ProcessImpl() { | |
37 Reset(0); | |
38 } | |
39 | |
40 void ProcessImpl::AddArg(const std::string& arg) { | |
41 arguments_.push_back(arg); | |
42 } | |
43 | |
44 void ProcessImpl::RedirectOutput(const std::string& output_file) { | |
45 output_file_ = output_file; | |
46 } | |
47 | |
48 bool ProcessImpl::Start() { | |
49 // Copy off a writeable version of arguments. Exec wants to be able | |
50 // to write both the array and the strings. | |
51 int total_args_size = 0; | |
52 | |
53 for (size_t i = 0; i < arguments_.size(); ++i) { | |
54 total_args_size += arguments_[i].size() + 1; | |
55 } | |
56 | |
57 scoped_array<char> buffer(new char[total_args_size]); | |
58 scoped_array<char*> argv(new char*[arguments_.size() + 1]); | |
59 | |
60 char* buffer_pointer = &buffer[0]; | |
61 for (size_t i = 0; i < arguments_.size(); ++i) { | |
62 argv[i] = buffer_pointer; | |
63 strcpy(buffer_pointer, arguments_[i].c_str()); | |
64 buffer_pointer += arguments_[i].size() + 1; | |
65 } | |
66 argv[arguments_.size()] = NULL; | |
67 | |
68 pid_t pid = fork(); | |
69 int saved_errno = errno; | |
70 if (pid < 0) { | |
71 LOG(ERROR) << "Fork failed: " << saved_errno; | |
72 return false; | |
73 } | |
74 | |
75 if (pid == 0) { | |
76 if (!output_file_.empty()) { | |
77 int output_handle = HANDLE_EINTR( | |
78 open(output_file_.c_str(), | |
79 O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666)); | |
80 int saved_errno = errno; | |
81 if (output_handle < 0) { | |
82 LOG(ERROR) << "Could not create " << output_file_ | |
83 << ": " << saved_errno; | |
84 // Avoid exit() to avoid atexit handlers from parent. | |
85 _exit(127); | |
86 } | |
87 dup2(output_handle, STDOUT_FILENO); | |
88 dup2(output_handle, STDERR_FILENO); | |
89 // Only close output_handle if it does not happen to be one of | |
90 // the two standard file descriptors we are trying to redirect. | |
91 if (output_handle != STDOUT_FILENO && output_handle != STDERR_FILENO) | |
92 close(output_handle); | |
93 } | |
94 execv(argv[0], &argv[0]); | |
95 saved_errno = errno; | |
96 LOG(ERROR) << "Exec of " << argv[0] << " failed: " << saved_errno; | |
97 _exit(127); | |
98 } else { | |
99 Reset(pid); | |
100 } | |
101 return true; | |
102 } | |
103 | |
104 int ProcessImpl::Wait() { | |
105 int status = 0; | |
106 if (pid_ == 0) { | |
107 LOG(ERROR) << "Process not running"; | |
108 return -1; | |
109 } | |
110 if (HANDLE_EINTR(waitpid(pid_, &status, 0)) < 0) { | |
111 int saved_errno = errno; | |
112 LOG(ERROR) << "Problem waiting for pid " << pid_ << ": " << saved_errno; | |
113 return -1; | |
114 } | |
115 pid_t old_pid = pid_; | |
116 // Update the pid to 0 - do not Reset as we do not want to try to | |
117 // kill the process that has just exited. | |
118 UpdatePid(0); | |
119 if (!WIFEXITED(status)) { | |
120 LOG(ERROR) << "Process " << old_pid << " did not exit normally: " | |
121 << status; | |
122 return -1; | |
123 } | |
124 return WEXITSTATUS(status); | |
125 } | |
126 | |
127 int ProcessImpl::Run() { | |
128 if (!Start()) { | |
129 return -1; | |
130 } | |
131 return Wait(); | |
132 } | |
133 | |
134 pid_t ProcessImpl::pid() { | |
135 return pid_; | |
136 } | |
137 | |
138 bool ProcessImpl::Kill(int signal, int timeout) { | |
139 if (pid_ == 0) { | |
140 // Passing pid == 0 to kill is committing suicide. Check specifically. | |
141 LOG(ERROR) << "Process not running"; | |
142 return false; | |
143 } | |
144 if (kill(pid_, signal) < 0) { | |
145 int saved_errno = errno; | |
146 LOG(ERROR) << "Unable to send signal to " << pid_ << " error " | |
147 << saved_errno; | |
148 return false; | |
149 } | |
150 base::TimeTicks start_signal = base::TimeTicks::Now(); | |
151 do { | |
152 int status = 0; | |
153 pid_t w = waitpid(pid_, &status, WNOHANG); | |
154 int saved_errno = errno; | |
155 if (w < 0) { | |
156 if (saved_errno == ECHILD) | |
157 return true; | |
158 LOG(ERROR) << "Waitpid returned " << w << ", errno " << saved_errno; | |
159 return false; | |
160 } | |
161 if (w > 0) { | |
162 Reset(0); | |
163 return true; | |
164 } | |
165 usleep(100); | |
166 } while ((base::TimeTicks::Now() - start_signal).InSecondsF() <= timeout); | |
167 LOG(INFO) << "process " << pid_ << " did not exit from signal " << signal | |
168 << " in " << timeout << " seconds"; | |
169 return false; | |
170 } | |
171 | |
172 void ProcessImpl::UpdatePid(pid_t new_pid) { | |
173 pid_ = new_pid; | |
174 } | |
175 | |
176 void ProcessImpl::Reset(pid_t new_pid) { | |
177 arguments_.clear(); | |
178 if (pid_) | |
179 Kill(SIGKILL, 0); | |
180 UpdatePid(new_pid); | |
181 } | |
182 | |
183 bool ProcessImpl::ResetPidByFile(const std::string& pid_file) { | |
184 std::string contents; | |
185 if (!file_util::ReadFileToString(FilePath(pid_file), &contents)) { | |
186 LOG(ERROR) << "Could not read pid file" << pid_file; | |
187 return false; | |
188 } | |
189 TrimWhitespaceASCII(contents, TRIM_TRAILING, &contents); | |
190 int64 pid_int64 = 0; | |
191 if (!base::StringToInt64(contents, &pid_int64)) { | |
192 LOG(ERROR) << "Unexpected pid file contents"; | |
193 return false; | |
194 } | |
195 Reset(pid_int64); | |
196 return true; | |
197 } | |
198 | |
199 pid_t ProcessImpl::Release() { | |
200 pid_t old_pid = pid_; | |
201 pid_ = 0; | |
202 return old_pid; | |
203 } | |
204 | |
205 } // namespace chromeos | |
OLD | NEW |