Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(413)

Side by Side Diff: user_collector.cc

Issue 6517001: crash-reporter: Use standard logging and new libchromeos Process code (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crash-reporter.git@master
Patch Set: More comments Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « user_collector.h ('k') | user_collector_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <grp.h> // For struct group. 7 #include <grp.h> // For struct group.
8 #include <pcrecpp.h> 8 #include <pcrecpp.h>
9 #include <pcrecpp.h> 9 #include <pcrecpp.h>
10 #include <pwd.h> // For struct passwd. 10 #include <pwd.h> // For struct passwd.
11 #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. 11 #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
12 12
13 #include <string> 13 #include <string>
14 #include <vector> 14 #include <vector>
15 15
16 #include "base/file_util.h" 16 #include "base/file_util.h"
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/string_util.h" 18 #include "base/string_util.h"
19 #include "crash-reporter/system_logging.h" 19 #include "chromeos/process.h"
20 #include "chromeos/syslog_logging.h"
20 #include "gflags/gflags.h" 21 #include "gflags/gflags.h"
21 22
22 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 23 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
23 DEFINE_bool(core2md_failure, false, "Core2md failure test"); 24 DEFINE_bool(core2md_failure, false, "Core2md failure test");
24 DEFINE_bool(directory_failure, false, "Spool directory failure test"); 25 DEFINE_bool(directory_failure, false, "Spool directory failure test");
25 DEFINE_string(filter_in, "", 26 DEFINE_string(filter_in, "",
26 "Ignore all crashes but this for testing"); 27 "Ignore all crashes but this for testing");
27 #pragma GCC diagnostic error "-Wstrict-aliasing" 28 #pragma GCC diagnostic error "-Wstrict-aliasing"
28 29
29 static const char kCollectionErrorSignature[] = 30 static const char kCollectionErrorSignature[] =
(...skipping 18 matching lines...) Expand all
48 : generate_diagnostics_(false), 49 : generate_diagnostics_(false),
49 core_pattern_file_(kCorePatternFile), 50 core_pattern_file_(kCorePatternFile),
50 core_pipe_limit_file_(kCorePipeLimitFile), 51 core_pipe_limit_file_(kCorePipeLimitFile),
51 initialized_(false) { 52 initialized_(false) {
52 } 53 }
53 54
54 void UserCollector::Initialize( 55 void UserCollector::Initialize(
55 UserCollector::CountCrashFunction count_crash_function, 56 UserCollector::CountCrashFunction count_crash_function,
56 const std::string &our_path, 57 const std::string &our_path,
57 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function, 58 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function,
58 SystemLogging *logger,
59 bool generate_diagnostics) { 59 bool generate_diagnostics) {
60 CrashCollector::Initialize(count_crash_function, 60 CrashCollector::Initialize(count_crash_function,
61 is_feedback_allowed_function, 61 is_feedback_allowed_function);
62 logger);
63 our_path_ = our_path; 62 our_path_ = our_path;
64 initialized_ = true; 63 initialized_ = true;
65 generate_diagnostics_ = generate_diagnostics; 64 generate_diagnostics_ = generate_diagnostics;
66 } 65 }
67 66
68 UserCollector::~UserCollector() { 67 UserCollector::~UserCollector() {
69 } 68 }
70 69
71 std::string UserCollector::GetPattern(bool enabled) const { 70 std::string UserCollector::GetPattern(bool enabled) const {
72 if (enabled) { 71 if (enabled) {
73 // Combine the three crash attributes into one parameter to try to reduce 72 // Combine the three crash attributes into one parameter to try to reduce
74 // the size of the invocation line for crash_reporter since the kernel 73 // the size of the invocation line for crash_reporter since the kernel
75 // has a fixed-sized (128B) buffer that it will truncate into. Note that 74 // has a fixed-sized (128B) buffer that it will truncate into. Note that
76 // the kernel does not support quoted arguments in core_pattern. 75 // the kernel does not support quoted arguments in core_pattern.
77 return StringPrintf("|%s --user=%%p:%%s:%%e", our_path_.c_str()); 76 return StringPrintf("|%s --user=%%p:%%s:%%e", our_path_.c_str());
78 } else { 77 } else {
79 return "core"; 78 return "core";
80 } 79 }
81 } 80 }
82 81
83 bool UserCollector::SetUpInternal(bool enabled) { 82 bool UserCollector::SetUpInternal(bool enabled) {
84 CHECK(initialized_); 83 CHECK(initialized_);
85 logger_->LogInfo("%s user crash handling", 84 LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
86 enabled ? "Enabling" : "Disabling"); 85
87 if (file_util::WriteFile(FilePath(core_pipe_limit_file_), 86 if (file_util::WriteFile(FilePath(core_pipe_limit_file_),
88 kCorePipeLimit, 87 kCorePipeLimit,
89 strlen(kCorePipeLimit)) != 88 strlen(kCorePipeLimit)) !=
90 static_cast<int>(strlen(kCorePipeLimit))) { 89 static_cast<int>(strlen(kCorePipeLimit))) {
91 logger_->LogError("Unable to write %s", core_pipe_limit_file_.c_str()); 90 LOG(ERROR) << "Unable to write " << core_pipe_limit_file_;
92 return false; 91 return false;
93 } 92 }
94 std::string pattern = GetPattern(enabled); 93 std::string pattern = GetPattern(enabled);
95 if (file_util::WriteFile(FilePath(core_pattern_file_), 94 if (file_util::WriteFile(FilePath(core_pattern_file_),
96 pattern.c_str(), 95 pattern.c_str(),
97 pattern.length()) != 96 pattern.length()) !=
98 static_cast<int>(pattern.length())) { 97 static_cast<int>(pattern.length())) {
99 logger_->LogError("Unable to write %s", core_pattern_file_.c_str()); 98 LOG(ERROR) << "Unable to write " << core_pattern_file_;
100 return false; 99 return false;
101 } 100 }
102 return true; 101 return true;
103 } 102 }
104 103
105 FilePath UserCollector::GetProcessPath(pid_t pid) { 104 FilePath UserCollector::GetProcessPath(pid_t pid) {
106 return FilePath(StringPrintf("/proc/%d", pid)); 105 return FilePath(StringPrintf("/proc/%d", pid));
107 } 106 }
108 107
109 bool UserCollector::GetSymlinkTarget(const FilePath &symlink, 108 bool UserCollector::GetSymlinkTarget(const FilePath &symlink,
110 FilePath *target) { 109 FilePath *target) {
111 int max_size = 32; 110 int max_size = 32;
112 scoped_array<char> buffer; 111 scoped_array<char> buffer;
113 while (true) { 112 while (true) {
114 buffer.reset(new char[max_size + 1]); 113 buffer.reset(new char[max_size + 1]);
115 ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size); 114 ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size);
116 if (size < 0) { 115 if (size < 0) {
117 int saved_errno = errno; 116 int saved_errno = errno;
118 logger_->LogError("Readlink failed on %s with %d", 117 LOG(ERROR) << "Readlink failed on " << symlink.value() << " with "
119 symlink.value().c_str(), saved_errno); 118 << saved_errno;
120 return false; 119 return false;
121 } 120 }
122 buffer[size] = 0; 121 buffer[size] = 0;
123 if (size == max_size) { 122 if (size == max_size) {
124 // Avoid overflow when doubling. 123 // Avoid overflow when doubling.
125 if (max_size * 2 > max_size) { 124 if (max_size * 2 > max_size) {
126 max_size *= 2; 125 max_size *= 2;
127 continue; 126 continue;
128 } else { 127 } else {
129 return false; 128 return false;
130 } 129 }
131 } 130 }
132 break; 131 break;
133 } 132 }
134 133
135 *target = FilePath(buffer.get()); 134 *target = FilePath(buffer.get());
136 return true; 135 return true;
137 } 136 }
138 137
139 bool UserCollector::GetExecutableBaseNameFromPid(uid_t pid, 138 bool UserCollector::GetExecutableBaseNameFromPid(uid_t pid,
140 std::string *base_name) { 139 std::string *base_name) {
141 FilePath target; 140 FilePath target;
142 FilePath process_path = GetProcessPath(pid); 141 FilePath process_path = GetProcessPath(pid);
143 FilePath exe_path = process_path.Append("exe"); 142 FilePath exe_path = process_path.Append("exe");
144 if (!GetSymlinkTarget(exe_path, &target)) { 143 if (!GetSymlinkTarget(exe_path, &target)) {
145 logger_->LogInfo("GetSymlinkTarget failed - Path %s DirectoryExists: %d", 144 LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value()
146 process_path.value().c_str(), 145 << " DirectoryExists: "
147 file_util::DirectoryExists(process_path)); 146 << file_util::DirectoryExists(process_path);
148 // Try to further diagnose exe readlink failure cause. 147 // Try to further diagnose exe readlink failure cause.
149 struct stat buf; 148 struct stat buf;
150 int stat_result = stat(exe_path.value().c_str(), &buf); 149 int stat_result = stat(exe_path.value().c_str(), &buf);
151 int saved_errno = errno; 150 int saved_errno = errno;
152 if (stat_result < 0) { 151 if (stat_result < 0) {
153 logger_->LogInfo("stat %s failed: %d %d", exe_path.value().c_str(), 152 LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result
154 stat_result, saved_errno); 153 << " " << saved_errno;
155 } else { 154 } else {
156 logger_->LogInfo("stat %s succeeded: st_mode=%d", 155 LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode="
157 exe_path.value().c_str(), buf.st_mode); 156 << buf.st_mode;
158 } 157 }
159 return false; 158 return false;
160 } 159 }
161 *base_name = target.BaseName().value(); 160 *base_name = target.BaseName().value();
162 return true; 161 return true;
163 } 162 }
164 163
165 bool UserCollector::GetIdFromStatus(const char *prefix, 164 bool UserCollector::GetIdFromStatus(const char *prefix,
166 IdKind kind, 165 IdKind kind,
167 const std::string &status_contents, 166 const std::string &status_contents,
(...skipping 23 matching lines...) Expand all
191 char *end_number = NULL; 190 char *end_number = NULL;
192 *id = strtol(number, &end_number, 10); 191 *id = strtol(number, &end_number, 10);
193 if (*end_number != '\0') 192 if (*end_number != '\0')
194 return false; 193 return false;
195 return true; 194 return true;
196 } 195 }
197 196
198 void UserCollector::EnqueueCollectionErrorLog(pid_t pid, 197 void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
199 const std::string &exec) { 198 const std::string &exec) {
200 FilePath crash_path; 199 FilePath crash_path;
201 logger_->LogInfo("Writing conversion problems as separate crash report."); 200 LOG(INFO) << "Writing conversion problems as separate crash report.";
202 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) { 201 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) {
203 logger_->LogError("Could not even get log directory; out of space?"); 202 LOG(ERROR) << "Could not even get log directory; out of space?";
204 return; 203 return;
205 } 204 }
206 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); 205 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid);
207 std::string error_log = logger_->get_accumulator(); 206 std::string error_log = chromeos::GetLog();
208 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog"); 207 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
209 if (GetLogContents(FilePath(kDefaultLogConfig), kCollectionErrorSignature, 208 if (GetLogContents(FilePath(kDefaultLogConfig), kCollectionErrorSignature,
210 diag_log_path)) { 209 diag_log_path)) {
211 // We load the contents of diag_log into memory and append it to 210 // We load the contents of diag_log into memory and append it to
212 // the error log. We cannot just append to files because we need 211 // the error log. We cannot just append to files because we need
213 // to always create new files to prevent attack. 212 // to always create new files to prevent attack.
214 std::string diag_log_contents; 213 std::string diag_log_contents;
215 file_util::ReadFileToString(diag_log_path, &diag_log_contents); 214 file_util::ReadFileToString(diag_log_path, &diag_log_contents);
216 error_log.append(diag_log_contents); 215 error_log.append(diag_log_contents);
217 file_util::Delete(diag_log_path, false); 216 file_util::Delete(diag_log_path, false);
218 } 217 }
219 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); 218 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
220 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); 219 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
221 // We must use WriteNewFile instead of file_util::WriteFile as we do 220 // We must use WriteNewFile instead of file_util::WriteFile as we do
222 // not want to write with root access to a symlink that an attacker 221 // not want to write with root access to a symlink that an attacker
223 // might have created. 222 // might have created.
224 WriteNewFile(log_path, error_log.data(), error_log.length()); 223 WriteNewFile(log_path, error_log.data(), error_log.length());
225 AddCrashMetaData("sig", kCollectionErrorSignature); 224 AddCrashMetaData("sig", kCollectionErrorSignature);
226 WriteCrashMetaData(meta_path, exec, log_path.value()); 225 WriteCrashMetaData(meta_path, exec, log_path.value());
227 } 226 }
228 227
229 bool UserCollector::CopyOffProcFiles(pid_t pid, 228 bool UserCollector::CopyOffProcFiles(pid_t pid,
230 const FilePath &container_dir) { 229 const FilePath &container_dir) {
231 if (!file_util::CreateDirectory(container_dir)) { 230 if (!file_util::CreateDirectory(container_dir)) {
232 logger_->LogError("Could not create %s", 231 LOG(ERROR) << "Could not create " << container_dir.value().c_str();
233 container_dir.value().c_str());
234 return false; 232 return false;
235 } 233 }
236 FilePath process_path = GetProcessPath(pid); 234 FilePath process_path = GetProcessPath(pid);
237 if (!file_util::PathExists(process_path)) { 235 if (!file_util::PathExists(process_path)) {
238 logger_->LogError("Path %s does not exist", process_path.value().c_str()); 236 LOG(ERROR) << "Path " << process_path.value() << " does not exist";
239 return false; 237 return false;
240 } 238 }
241 static const char *proc_files[] = { 239 static const char *proc_files[] = {
242 "auxv", 240 "auxv",
243 "cmdline", 241 "cmdline",
244 "environ", 242 "environ",
245 "maps", 243 "maps",
246 "status" 244 "status"
247 }; 245 };
248 for (unsigned i = 0; i < arraysize(proc_files); ++i) { 246 for (unsigned i = 0; i < arraysize(proc_files); ++i) {
249 if (!file_util::CopyFile(process_path.Append(proc_files[i]), 247 if (!file_util::CopyFile(process_path.Append(proc_files[i]),
250 container_dir.Append(proc_files[i]))) { 248 container_dir.Append(proc_files[i]))) {
251 logger_->LogError("Could not copy %s file", proc_files[i]); 249 LOG(ERROR) << "Could not copy " << proc_files[i] << " file";
252 return false; 250 return false;
253 } 251 }
254 } 252 }
255 return true; 253 return true;
256 } 254 }
257 255
258 bool UserCollector::GetCreatedCrashDirectory(pid_t pid, 256 bool UserCollector::GetCreatedCrashDirectory(pid_t pid,
259 FilePath *crash_file_path, 257 FilePath *crash_file_path,
260 bool *out_of_capacity) { 258 bool *out_of_capacity) {
261 FilePath process_path = GetProcessPath(pid); 259 FilePath process_path = GetProcessPath(pid);
262 std::string status; 260 std::string status;
263 if (FLAGS_directory_failure) { 261 if (FLAGS_directory_failure) {
264 logger_->LogError("Purposefully failing to create spool directory"); 262 LOG(ERROR) << "Purposefully failing to create spool directory";
265 return false; 263 return false;
266 } 264 }
267 if (!file_util::ReadFileToString(process_path.Append("status"), 265 if (!file_util::ReadFileToString(process_path.Append("status"),
268 &status)) { 266 &status)) {
269 logger_->LogError("Could not read status file"); 267 LOG(ERROR) << "Could not read status file";
270 logger_->LogInfo("Path %s DirectoryExists: %d", 268 LOG(INFO) << "Path " << process_path.value() << " DirectoryExists: "
271 process_path.value().c_str(), 269 << file_util::DirectoryExists(process_path);
272 file_util::DirectoryExists(process_path));
273 return false; 270 return false;
274 } 271 }
275 int process_euid; 272 int process_euid;
276 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) { 273 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) {
277 logger_->LogError("Could not find euid in status file"); 274 LOG(ERROR) << "Could not find euid in status file";
278 return false; 275 return false;
279 } 276 }
280 if (!GetCreatedCrashDirectoryByEuid(process_euid, 277 if (!GetCreatedCrashDirectoryByEuid(process_euid,
281 crash_file_path, 278 crash_file_path,
282 out_of_capacity)) { 279 out_of_capacity)) {
283 logger_->LogError("Could not create crash directory"); 280 LOG(ERROR) << "Could not create crash directory";
284 return false; 281 return false;
285 } 282 }
286 return true; 283 return true;
287 } 284 }
288 285
289 bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { 286 bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
290 // Copy off all stdin to a core file. 287 // Copy off all stdin to a core file.
291 FilePath stdin_path("/dev/fd/0"); 288 FilePath stdin_path("/dev/fd/0");
292 if (file_util::CopyFile(stdin_path, core_path)) { 289 if (file_util::CopyFile(stdin_path, core_path)) {
293 return true; 290 return true;
294 } 291 }
295 292
296 logger_->LogError("Could not write core file"); 293 LOG(ERROR) << "Could not write core file";
297 // If the file system was full, make sure we remove any remnants. 294 // If the file system was full, make sure we remove any remnants.
298 file_util::Delete(core_path, false); 295 file_util::Delete(core_path, false);
299 return false; 296 return false;
300 } 297 }
301 298
302 bool UserCollector::RunCoreToMinidump(const FilePath &core_path, 299 bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
303 const FilePath &procfs_directory, 300 const FilePath &procfs_directory,
304 const FilePath &minidump_path, 301 const FilePath &minidump_path,
305 const FilePath &temp_directory) { 302 const FilePath &temp_directory) {
306 FilePath output_path = temp_directory.Append("output"); 303 FilePath output_path = temp_directory.Append("output");
307 std::vector<const char *> core2md_arguments; 304 chromeos::ProcessImpl core2md;
308 core2md_arguments.push_back(kCoreToMinidumpConverterPath); 305 core2md.RedirectOutput(output_path.value());
309 core2md_arguments.push_back(core_path.value().c_str()); 306 core2md.AddArg(kCoreToMinidumpConverterPath);
310 core2md_arguments.push_back(procfs_directory.value().c_str()); 307 core2md.AddArg(core_path.value());
311 core2md_arguments.push_back(minidump_path.value().c_str()); 308 core2md.AddArg(procfs_directory.value());
312 309
313 if (FLAGS_core2md_failure) { 310 if (!FLAGS_core2md_failure) {
311 core2md.AddArg(minidump_path.value());
312 } else {
314 // To test how core2md errors are propagaged, cause an error 313 // To test how core2md errors are propagaged, cause an error
315 // by forgetting a required argument. 314 // by forgetting a required argument.
316 core2md_arguments.pop_back();
317 } 315 }
318 316
319 int errorlevel = ForkExecAndPipe(core2md_arguments, 317 int errorlevel = core2md.Run();
320 output_path.value().c_str());
321 318
322 std::string output; 319 std::string output;
323 file_util::ReadFileToString(output_path, &output); 320 file_util::ReadFileToString(output_path, &output);
324 if (errorlevel != 0) { 321 if (errorlevel != 0) {
325 logger_->LogError("Problem during %s [result=%d]: %s", 322 LOG(ERROR) << "Problem during " << kCoreToMinidumpConverterPath
326 kCoreToMinidumpConverterPath, 323 << " [result=" << errorlevel << "]: " << output;
327 errorlevel,
328 output.c_str());
329 return false; 324 return false;
330 } 325 }
331 326
332 if (!file_util::PathExists(minidump_path)) { 327 if (!file_util::PathExists(minidump_path)) {
333 logger_->LogError("Minidump file %s was not created", 328 LOG(ERROR) << "Minidump file " << minidump_path.value()
334 minidump_path.value().c_str()); 329 << " was not created";
335 return false; 330 return false;
336 } 331 }
337 return true; 332 return true;
338 } 333 }
339 334
340 bool UserCollector::ConvertCoreToMinidump(pid_t pid, 335 bool UserCollector::ConvertCoreToMinidump(pid_t pid,
341 const FilePath &container_dir, 336 const FilePath &container_dir,
342 const FilePath &core_path, 337 const FilePath &core_path,
343 const FilePath &minidump_path) { 338 const FilePath &minidump_path) {
344 if (!CopyOffProcFiles(pid, container_dir)) { 339 if (!CopyOffProcFiles(pid, container_dir)) {
345 return false; 340 return false;
346 } 341 }
347 342
348 if (!CopyStdinToCoreFile(core_path)) { 343 if (!CopyStdinToCoreFile(core_path)) {
349 return false; 344 return false;
350 } 345 }
351 346
352 bool conversion_result = RunCoreToMinidump( 347 bool conversion_result = RunCoreToMinidump(
353 core_path, 348 core_path,
354 container_dir, // procfs directory 349 container_dir, // procfs directory
355 minidump_path, 350 minidump_path,
356 container_dir); // temporary directory 351 container_dir); // temporary directory
357 352
358 if (conversion_result) { 353 if (conversion_result) {
359 logger_->LogInfo("Stored minidump to %s", minidump_path.value().c_str()); 354 LOG(INFO) << "Stored minidump to " << minidump_path.value();
360 } 355 }
361 356
362 return conversion_result; 357 return conversion_result;
363 } 358 }
364 359
365 bool UserCollector::ConvertAndEnqueueCrash(int pid, 360 bool UserCollector::ConvertAndEnqueueCrash(int pid,
366 const std::string &exec, 361 const std::string &exec,
367 bool *out_of_capacity) { 362 bool *out_of_capacity) {
368 FilePath crash_path; 363 FilePath crash_path;
369 if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) { 364 if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) {
370 logger_->LogError("Unable to find/create process-specific crash path"); 365 LOG(ERROR) << "Unable to find/create process-specific crash path";
371 return false; 366 return false;
372 } 367 }
373 368
374 // Directory like /tmp/crash_reporter.1234 which contains the 369 // Directory like /tmp/crash_reporter.1234 which contains the
375 // procfs entries and other temporary files used during conversion. 370 // procfs entries and other temporary files used during conversion.
376 FilePath container_dir = FilePath("/tmp").Append( 371 FilePath container_dir = FilePath("/tmp").Append(
377 StringPrintf("crash_reporter.%d", pid)); 372 StringPrintf("crash_reporter.%d", pid));
378 // Delete a pre-existing directory from crash reporter that may have 373 // Delete a pre-existing directory from crash reporter that may have
379 // been left around for diagnostics from a failed conversion attempt. 374 // been left around for diagnostics from a failed conversion attempt.
380 // If we don't, existing files can cause forking to fail. 375 // If we don't, existing files can cause forking to fail.
381 file_util::Delete(container_dir, true); 376 file_util::Delete(container_dir, true);
382 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); 377 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid);
383 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core"); 378 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
384 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); 379 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
385 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp"); 380 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp");
386 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); 381 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
387 382
388 if (GetLogContents(FilePath(kDefaultLogConfig), exec, log_path)) 383 if (GetLogContents(FilePath(kDefaultLogConfig), exec, log_path))
389 AddCrashMetaData("log", log_path.value()); 384 AddCrashMetaData("log", log_path.value());
390 385
391 if (!ConvertCoreToMinidump(pid, container_dir, core_path, 386 if (!ConvertCoreToMinidump(pid, container_dir, core_path,
392 minidump_path)) { 387 minidump_path)) {
393 logger_->LogInfo("Leaving core file at %s due to conversion error", 388 LOG(INFO) << "Leaving core file at " << core_path.value()
394 core_path.value().c_str()); 389 << " due to conversion error";
395 return false; 390 return false;
396 } 391 }
397 392
398 // Here we commit to sending this file. We must not return false 393 // Here we commit to sending this file. We must not return false
399 // after this point or we will generate a log report as well as a 394 // after this point or we will generate a log report as well as a
400 // crash report. 395 // crash report.
401 WriteCrashMetaData(meta_path, 396 WriteCrashMetaData(meta_path,
402 exec, 397 exec,
403 minidump_path.value()); 398 minidump_path.value());
404 399
405 if (!file_util::PathExists(FilePath(kLeaveCoreFile))) { 400 if (!file_util::PathExists(FilePath(kLeaveCoreFile))) {
406 file_util::Delete(core_path, false); 401 file_util::Delete(core_path, false);
407 } else { 402 } else {
408 logger_->LogInfo("Leaving core file at %s due to developer image", 403 LOG(INFO) << "Leaving core file at " << core_path.value()
409 core_path.value().c_str()); 404 << " due to developer image";
410 } 405 }
411 406
412 file_util::Delete(container_dir, true); 407 file_util::Delete(container_dir, true);
413 return true; 408 return true;
414 } 409 }
415 410
416 bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes, 411 bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
417 pid_t *pid, int *signal, 412 pid_t *pid, int *signal,
418 std::string *kernel_supplied_name) { 413 std::string *kernel_supplied_name) {
419 pcrecpp::RE re("(\\d+):(\\d+):(.*)"); 414 pcrecpp::RE re("(\\d+):(\\d+):(.*)");
420 return re.FullMatch(crash_attributes, pid, signal, kernel_supplied_name); 415 return re.FullMatch(crash_attributes, pid, signal, kernel_supplied_name);
421 } 416 }
422 417
423 bool UserCollector::HandleCrash(const std::string &crash_attributes, 418 bool UserCollector::HandleCrash(const std::string &crash_attributes,
424 const char *force_exec) { 419 const char *force_exec) {
425 CHECK(initialized_); 420 CHECK(initialized_);
426 int pid = 0; 421 int pid = 0;
427 int signal = 0; 422 int signal = 0;
428 std::string kernel_supplied_name; 423 std::string kernel_supplied_name;
429 424
430 if (!ParseCrashAttributes(crash_attributes, &pid, &signal, 425 if (!ParseCrashAttributes(crash_attributes, &pid, &signal,
431 &kernel_supplied_name)) { 426 &kernel_supplied_name)) {
432 logger_->LogError("Invalid parameter: --user=%s", crash_attributes.c_str()); 427 LOG(ERROR) << "Invalid parameter: --user=" << crash_attributes;
433 return false; 428 return false;
434 } 429 }
435 430
436 std::string exec; 431 std::string exec;
437 if (force_exec) { 432 if (force_exec) {
438 exec.assign(force_exec); 433 exec.assign(force_exec);
439 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { 434 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
440 // If we cannot find the exec name, use the kernel supplied name. 435 // If we cannot find the exec name, use the kernel supplied name.
441 // We don't always use the kernel's since it truncates the name to 436 // We don't always use the kernel's since it truncates the name to
442 // 16 characters. 437 // 16 characters.
443 exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str()); 438 exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
444 } 439 }
445 440
446 // Allow us to test the crash reporting mechanism successfully even if 441 // Allow us to test the crash reporting mechanism successfully even if
447 // other parts of the system crash. 442 // other parts of the system crash.
448 if (!FLAGS_filter_in.empty() && 443 if (!FLAGS_filter_in.empty() &&
449 (FLAGS_filter_in == "none" || 444 (FLAGS_filter_in == "none" ||
450 FLAGS_filter_in != exec)) { 445 FLAGS_filter_in != exec)) {
451 // We use a different format message to make it more obvious in tests 446 // We use a different format message to make it more obvious in tests
452 // which crashes are test generated and which are real. 447 // which crashes are test generated and which are real.
453 logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s.", 448 LOG(WARNING) << "Ignoring crash from " << exec << "[" << pid << "] while "
454 exec.c_str(), pid, FLAGS_filter_in.c_str()); 449 << "filter_in=" << FLAGS_filter_in << ".";
455 return true; 450 return true;
456 } 451 }
457 452
458 bool feedback = is_feedback_allowed_function_(); 453 bool feedback = is_feedback_allowed_function_();
459 const char *handling_string = "handling"; 454 const char *handling_string = "handling";
460 if (!feedback) { 455 if (!feedback) {
461 handling_string = "ignoring - no consent"; 456 handling_string = "ignoring - no consent";
462 } 457 }
463 458
464 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome 459 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome
465 // crashes towards user crashes, so user crashes really mean non-Chrome 460 // crashes towards user crashes, so user crashes really mean non-Chrome
466 // user-space crashes. 461 // user-space crashes.
467 if (exec == "chrome" || exec == "supplied_chrome") { 462 if (exec == "chrome" || exec == "supplied_chrome") {
468 feedback = false; 463 feedback = false;
469 handling_string = "ignoring - chrome crash"; 464 handling_string = "ignoring - chrome crash";
470 } 465 }
471 466
472 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)", 467 LOG(WARNING) << "Received crash notification for " << exec << "[" << pid
473 exec.c_str(), pid, signal, handling_string); 468 << "] sig " << signal << " (" << handling_string << ")";
474 469
475 if (feedback) { 470 if (feedback) {
476 count_crash_function_(); 471 count_crash_function_();
477 472
478 if (generate_diagnostics_) { 473 if (generate_diagnostics_) {
479 bool out_of_capacity = false; 474 bool out_of_capacity = false;
480 bool convert_and_enqueue_result = 475 bool convert_and_enqueue_result =
481 ConvertAndEnqueueCrash(pid, exec, &out_of_capacity); 476 ConvertAndEnqueueCrash(pid, exec, &out_of_capacity);
482 if (!convert_and_enqueue_result) { 477 if (!convert_and_enqueue_result) {
483 if (!out_of_capacity) 478 if (!out_of_capacity)
484 EnqueueCollectionErrorLog(pid, exec); 479 EnqueueCollectionErrorLog(pid, exec);
485 return false; 480 return false;
486 } 481 }
487 } 482 }
488 } 483 }
489 484
490 return true; 485 return true;
491 } 486 }
OLDNEW
« no previous file with comments | « user_collector.h ('k') | user_collector_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698