OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS 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 "crash-reporter/user_collector.h" | 5 #include "crash-reporter/user_collector.h" |
6 | 6 |
| 7 #include <fcntl.h> // For creat. |
7 #include <grp.h> // For struct group. | 8 #include <grp.h> // For struct group. |
8 #include <pwd.h> // For struct passwd. | 9 #include <pwd.h> // For struct passwd. |
9 #include <sys/types.h> // For getpwuid_r and getgrnam_r. | 10 #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. |
| 11 #include <sys/wait.h> // For waitpid. |
| 12 #include <unistd.h> // For execv and fork. |
10 | 13 |
11 #include <string> | 14 #include <string> |
| 15 #include <vector> |
12 | 16 |
| 17 #include "base/eintr_wrapper.h" |
13 #include "base/file_util.h" | 18 #include "base/file_util.h" |
14 #include "base/logging.h" | 19 #include "base/logging.h" |
15 #include "base/string_util.h" | 20 #include "base/string_util.h" |
16 #include "crash-reporter/system_logging.h" | 21 #include "crash-reporter/system_logging.h" |
17 | 22 |
18 // This procfs file is used to cause kernel core file writing to | 23 // This procfs file is used to cause kernel core file writing to |
19 // instead pipe the core file into a user space process. See | 24 // instead pipe the core file into a user space process. See |
20 // core(5) man page. | 25 // core(5) man page. |
21 static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern"; | 26 static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern"; |
22 static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md"; | 27 static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md"; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 if (file_util::CopyFile(stdin_path, core_path)) { | 202 if (file_util::CopyFile(stdin_path, core_path)) { |
198 return true; | 203 return true; |
199 } | 204 } |
200 | 205 |
201 logger_->LogError("Could not write core file"); | 206 logger_->LogError("Could not write core file"); |
202 // If the file system was full, make sure we remove any remnants. | 207 // If the file system was full, make sure we remove any remnants. |
203 file_util::Delete(core_path, false); | 208 file_util::Delete(core_path, false); |
204 return false; | 209 return false; |
205 } | 210 } |
206 | 211 |
| 212 int UserCollector::ForkExecAndPipe(std::vector<const char *> &arguments, |
| 213 const char *output_file) { |
| 214 // Copy off a writeable version of arguments. |
| 215 scoped_array<char*> argv(new char *[arguments.size() + 1]); |
| 216 int total_args_size = 0; |
| 217 for (size_t i = 0; i < arguments.size(); ++i) { |
| 218 if (arguments[i] == NULL) { |
| 219 logger_->LogError("Bad parameter"); |
| 220 return -1; |
| 221 } |
| 222 total_args_size += strlen(arguments[i]) + 1; |
| 223 } |
| 224 scoped_array<char> buffer(new char[total_args_size]); |
| 225 char *buffer_pointer = &buffer[0]; |
| 226 |
| 227 for (size_t i = 0; i < arguments.size(); ++i) { |
| 228 argv[i] = buffer_pointer; |
| 229 strcpy(buffer_pointer, arguments[i]); |
| 230 buffer_pointer += strlen(arguments[i]); |
| 231 *buffer_pointer = '\0'; |
| 232 ++buffer_pointer; |
| 233 } |
| 234 argv[arguments.size()] = NULL; |
| 235 |
| 236 int pid = fork(); |
| 237 if (pid < 0) { |
| 238 logger_->LogError("Fork failed: %d", errno); |
| 239 return -1; |
| 240 } |
| 241 |
| 242 if (pid == 0) { |
| 243 int output_handle = creat(output_file, 0700); |
| 244 if (output_handle < 0) { |
| 245 logger_->LogError("Could not create %s: %d", output_file, errno); |
| 246 // Avoid exit() to avoid atexit handlers from parent. |
| 247 _exit(127); |
| 248 } |
| 249 dup2(output_handle, 1); |
| 250 dup2(output_handle, 2); |
| 251 execv(argv[0], &argv[0]); |
| 252 logger_->LogError("Exec failed: %d", errno); |
| 253 _exit(127); |
| 254 } |
| 255 |
| 256 int status = 0; |
| 257 if (HANDLE_EINTR(waitpid(pid, &status, 0)) < 0) { |
| 258 logger_->LogError("Problem waiting for pid: %d", errno); |
| 259 return -1; |
| 260 } |
| 261 if (!WIFEXITED(status)) { |
| 262 logger_->LogError("Process did not exit normally: %x", status); |
| 263 return -1; |
| 264 } |
| 265 return WEXITSTATUS(status); |
| 266 } |
| 267 |
207 bool UserCollector::ConvertCoreToMinidump(const FilePath &core_path, | 268 bool UserCollector::ConvertCoreToMinidump(const FilePath &core_path, |
208 const FilePath &procfs_directory, | 269 const FilePath &procfs_directory, |
209 const FilePath &minidump_path, | 270 const FilePath &minidump_path, |
210 const FilePath &temp_directory) { | 271 const FilePath &temp_directory) { |
211 // TODO(kmixter): Rewrite to use process_util once it's included in | |
212 // libchrome. | |
213 FilePath output_path = temp_directory.Append("output"); | 272 FilePath output_path = temp_directory.Append("output"); |
214 std::string core2md_command = | 273 std::vector<const char *> core2md_arguments; |
215 StringPrintf("\"%s\" \"%s\" \"%s\" \"%s\" > \"%s\" 2>&1", | 274 core2md_arguments.push_back(kCoreToMinidumpConverterPath); |
216 kCoreToMinidumpConverterPath, | 275 core2md_arguments.push_back(core_path.value().c_str()); |
217 core_path.value().c_str(), | 276 core2md_arguments.push_back(procfs_directory.value().c_str()); |
218 procfs_directory.value().c_str(), | 277 core2md_arguments.push_back(minidump_path.value().c_str()); |
219 minidump_path.value().c_str(), | 278 |
220 output_path.value().c_str()); | 279 int errorlevel = ForkExecAndPipe(core2md_arguments, |
221 int errorlevel = system(core2md_command.c_str()); | 280 output_path.value().c_str()); |
222 | 281 |
223 std::string output; | 282 std::string output; |
224 file_util::ReadFileToString(output_path, &output); | 283 file_util::ReadFileToString(output_path, &output); |
225 if (errorlevel != 0) { | 284 if (errorlevel != 0) { |
226 logger_->LogInfo("Problem during %s [result=%d]: %s", | 285 logger_->LogInfo("Problem during %s [result=%d]: %s", |
227 core2md_command.c_str(), | 286 kCoreToMinidumpConverterPath, |
228 errorlevel, | 287 errorlevel, |
229 output.c_str()); | 288 output.c_str()); |
230 return false; | 289 return false; |
231 } | 290 } |
232 | 291 |
233 if (!file_util::PathExists(minidump_path)) { | 292 if (!file_util::PathExists(minidump_path)) { |
234 logger_->LogError("Minidump file %s was not created", | 293 logger_->LogError("Minidump file %s was not created", |
235 minidump_path.value().c_str()); | 294 minidump_path.value().c_str()); |
236 return false; | 295 return false; |
237 } | 296 } |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 | 369 |
311 if (feedback) { | 370 if (feedback) { |
312 count_crash_function_(); | 371 count_crash_function_(); |
313 | 372 |
314 if (generate_diagnostics_) { | 373 if (generate_diagnostics_) { |
315 return GenerateDiagnostics(pid, exec); | 374 return GenerateDiagnostics(pid, exec); |
316 } | 375 } |
317 } | 376 } |
318 return true; | 377 return true; |
319 } | 378 } |
OLD | NEW |