blob: a6dd091e770349587bc052a924fe790ed372cf8f [file] [log] [blame]
Chris Sosae4a86032010-06-16 17:08:34 -07001// 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
3// found in the LICENSE file.
4
Ken Mixter03403162010-08-18 15:23:16 -07005#include "crash-reporter/user_collector.h"
6
Ken Mixter777484c2010-07-23 16:22:44 -07007#include <grp.h> // For struct group.
Ken Mixter1b8fe012011-01-25 13:33:05 -08008#include <pcrecpp.h>
9#include <pcrecpp.h>
Ken Mixter777484c2010-07-23 16:22:44 -070010#include <pwd.h> // For struct passwd.
Ken Mixter2953c3a2010-10-18 14:42:20 -070011#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
Ken Mixter777484c2010-07-23 16:22:44 -070012
Chris Sosae4a86032010-06-16 17:08:34 -070013#include <string>
Ken Mixter2953c3a2010-10-18 14:42:20 -070014#include <vector>
Chris Sosae4a86032010-06-16 17:08:34 -070015
16#include "base/file_util.h"
17#include "base/logging.h"
18#include "base/string_util.h"
Ken Mixter03403162010-08-18 15:23:16 -070019#include "crash-reporter/system_logging.h"
Ken Mixter207694d2010-10-28 15:42:37 -070020#include "gflags/gflags.h"
Chris Sosae4a86032010-06-16 17:08:34 -070021
Ken Mixterc6a58e02010-11-01 18:05:30 -070022#pragma GCC diagnostic ignored "-Wstrict-aliasing"
Ken Mixter1b8fe012011-01-25 13:33:05 -080023DEFINE_bool(core2md_failure, false, "Core2md failure test");
24DEFINE_bool(directory_failure, false, "Spool directory failure test");
Ken Mixterc6a58e02010-11-01 18:05:30 -070025DEFINE_string(filter_in, "",
26 "Ignore all crashes but this for testing");
27#pragma GCC diagnostic error "-Wstrict-aliasing"
Ken Mixter207694d2010-10-28 15:42:37 -070028
29static const char kCollectionErrorSignature[] =
30 "crash_reporter-user-collection";
Chris Sosae4a86032010-06-16 17:08:34 -070031// This procfs file is used to cause kernel core file writing to
32// instead pipe the core file into a user space process. See
33// core(5) man page.
34static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern";
Ken Mixterc49dbd42010-12-14 17:44:11 -080035static const char kCorePipeLimitFile[] = "/proc/sys/kernel/core_pipe_limit";
36// Set core_pipe_limit to 4 so that we can catch a few unrelated concurrent
37// crashes, but finite to avoid infinitely recursing on crash handling.
38static const char kCorePipeLimit[] = "4";
Ken Mixter777484c2010-07-23 16:22:44 -070039static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md";
Ken Mixter7ac7a702010-08-13 15:43:34 -070040static const char kLeaveCoreFile[] = "/root/.leave_core";
Ken Mixter777484c2010-07-23 16:22:44 -070041
Ken Mixterc49dbd42010-12-14 17:44:11 -080042static const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
43
Ken Mixter777484c2010-07-23 16:22:44 -070044const char *UserCollector::kUserId = "Uid:\t";
45const char *UserCollector::kGroupId = "Gid:\t";
Chris Sosae4a86032010-06-16 17:08:34 -070046
47UserCollector::UserCollector()
Ken Mixter777484c2010-07-23 16:22:44 -070048 : generate_diagnostics_(false),
49 core_pattern_file_(kCorePatternFile),
Ken Mixterc49dbd42010-12-14 17:44:11 -080050 core_pipe_limit_file_(kCorePipeLimitFile),
Ken Mixter03403162010-08-18 15:23:16 -070051 initialized_(false) {
Chris Sosae4a86032010-06-16 17:08:34 -070052}
53
54void UserCollector::Initialize(
55 UserCollector::CountCrashFunction count_crash_function,
56 const std::string &our_path,
57 UserCollector::IsFeedbackAllowedFunction is_feedback_allowed_function,
Ken Mixter777484c2010-07-23 16:22:44 -070058 SystemLogging *logger,
59 bool generate_diagnostics) {
Ken Mixter03403162010-08-18 15:23:16 -070060 CrashCollector::Initialize(count_crash_function,
61 is_feedback_allowed_function,
62 logger);
Chris Sosae4a86032010-06-16 17:08:34 -070063 our_path_ = our_path;
Chris Sosae4a86032010-06-16 17:08:34 -070064 initialized_ = true;
Ken Mixter777484c2010-07-23 16:22:44 -070065 generate_diagnostics_ = generate_diagnostics;
Chris Sosae4a86032010-06-16 17:08:34 -070066}
67
68UserCollector::~UserCollector() {
69}
70
71std::string UserCollector::GetPattern(bool enabled) const {
72 if (enabled) {
Ken Mixter1b8fe012011-01-25 13:33:05 -080073 // 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
75 // has a fixed-sized (128B) buffer that it will truncate into. Note that
76 // the kernel does not support quoted arguments in core_pattern.
77 return StringPrintf("|%s --user=%%p:%%s:%%e", our_path_.c_str());
Chris Sosae4a86032010-06-16 17:08:34 -070078 } else {
79 return "core";
80 }
81}
82
83bool UserCollector::SetUpInternal(bool enabled) {
84 CHECK(initialized_);
Ken Mixter03403162010-08-18 15:23:16 -070085 logger_->LogInfo("%s user crash handling",
86 enabled ? "Enabling" : "Disabling");
Ken Mixterc49dbd42010-12-14 17:44:11 -080087 if (file_util::WriteFile(FilePath(core_pipe_limit_file_),
88 kCorePipeLimit,
89 strlen(kCorePipeLimit)) !=
90 static_cast<int>(strlen(kCorePipeLimit))) {
91 logger_->LogError("Unable to write %s", core_pipe_limit_file_.c_str());
92 return false;
93 }
Chris Sosae4a86032010-06-16 17:08:34 -070094 std::string pattern = GetPattern(enabled);
95 if (file_util::WriteFile(FilePath(core_pattern_file_),
96 pattern.c_str(),
97 pattern.length()) !=
98 static_cast<int>(pattern.length())) {
99 logger_->LogError("Unable to write %s", core_pattern_file_.c_str());
100 return false;
101 }
102 return true;
103}
104
Ken Mixter777484c2010-07-23 16:22:44 -0700105FilePath UserCollector::GetProcessPath(pid_t pid) {
106 return FilePath(StringPrintf("/proc/%d", pid));
107}
108
109bool UserCollector::GetSymlinkTarget(const FilePath &symlink,
110 FilePath *target) {
111 int max_size = 32;
112 scoped_array<char> buffer;
113 while (true) {
114 buffer.reset(new char[max_size + 1]);
115 ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size);
116 if (size < 0) {
117 return false;
118 }
119 buffer[size] = 0;
120 if (size == max_size) {
121 // Avoid overflow when doubling.
122 if (max_size * 2 > max_size) {
123 max_size *= 2;
124 continue;
125 } else {
126 return false;
127 }
128 }
129 break;
130 }
131
132 *target = FilePath(buffer.get());
133 return true;
134}
135
136bool UserCollector::GetExecutableBaseNameFromPid(uid_t pid,
137 std::string *base_name) {
138 FilePath target;
139 if (!GetSymlinkTarget(GetProcessPath(pid).Append("exe"), &target))
140 return false;
141 *base_name = target.BaseName().value();
142 return true;
143}
144
145bool UserCollector::GetIdFromStatus(const char *prefix,
146 IdKind kind,
147 const std::string &status_contents,
148 int *id) {
149 // From fs/proc/array.c:task_state(), this file contains:
150 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n
151 std::vector<std::string> status_lines;
152 SplitString(status_contents, '\n', &status_lines);
153 std::vector<std::string>::iterator line_iterator;
154 for (line_iterator = status_lines.begin();
155 line_iterator != status_lines.end();
156 ++line_iterator) {
157 if (line_iterator->find(prefix) == 0)
158 break;
159 }
160 if (line_iterator == status_lines.end()) {
161 return false;
162 }
163 std::string id_substring = line_iterator->substr(strlen(prefix),
164 std::string::npos);
165 std::vector<std::string> ids;
166 SplitString(id_substring, '\t', &ids);
167 if (ids.size() != kIdMax || kind < 0 || kind >= kIdMax) {
168 return false;
169 }
170 const char *number = ids[kind].c_str();
171 char *end_number = NULL;
172 *id = strtol(number, &end_number, 10);
173 if (*end_number != '\0')
174 return false;
175 return true;
176}
177
Ken Mixter207694d2010-10-28 15:42:37 -0700178void UserCollector::EnqueueCollectionErrorLog(pid_t pid,
179 const std::string &exec) {
180 FilePath crash_path;
181 logger_->LogInfo("Writing conversion problems as separate crash report.");
182 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) {
183 logger_->LogError("Could not even get log directory; out of space?");
184 return;
185 }
186 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800187 std::string error_log = logger_->get_accumulator();
188 FilePath diag_log_path = GetCrashPath(crash_path, dump_basename, "diaglog");
189 if (GetLogContents(FilePath(kDefaultLogConfig), kCollectionErrorSignature,
190 diag_log_path)) {
191 // We load the contents of diag_log into memory and append it to
192 // the error log. We cannot just append to files because we need
193 // to always create new files to prevent attack.
194 std::string diag_log_contents;
195 file_util::ReadFileToString(diag_log_path, &diag_log_contents);
196 error_log.append(diag_log_contents);
197 file_util::Delete(diag_log_path, false);
198 }
Ken Mixter207694d2010-10-28 15:42:37 -0700199 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
200 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
Ken Mixter9b346472010-11-07 13:45:45 -0800201 // We must use WriteNewFile instead of file_util::WriteFile as we do
202 // not want to write with root access to a symlink that an attacker
203 // might have created.
Ken Mixter1b8fe012011-01-25 13:33:05 -0800204 WriteNewFile(log_path, error_log.data(), error_log.length());
Ken Mixter207694d2010-10-28 15:42:37 -0700205 AddCrashMetaData("sig", kCollectionErrorSignature);
206 WriteCrashMetaData(meta_path, exec, log_path.value());
207}
208
Ken Mixter777484c2010-07-23 16:22:44 -0700209bool UserCollector::CopyOffProcFiles(pid_t pid,
210 const FilePath &container_dir) {
211 if (!file_util::CreateDirectory(container_dir)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800212 logger_->LogError("Could not create %s",
213 container_dir.value().c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700214 return false;
215 }
216 FilePath process_path = GetProcessPath(pid);
217 if (!file_util::PathExists(process_path)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800218 logger_->LogError("Path %s does not exist", process_path.value().c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700219 return false;
220 }
221 static const char *proc_files[] = {
222 "auxv",
223 "cmdline",
224 "environ",
225 "maps",
226 "status"
227 };
228 for (unsigned i = 0; i < arraysize(proc_files); ++i) {
229 if (!file_util::CopyFile(process_path.Append(proc_files[i]),
230 container_dir.Append(proc_files[i]))) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800231 logger_->LogError("Could not copy %s file", proc_files[i]);
Ken Mixter777484c2010-07-23 16:22:44 -0700232 return false;
233 }
234 }
235 return true;
236}
237
Ken Mixter777484c2010-07-23 16:22:44 -0700238bool UserCollector::GetCreatedCrashDirectory(pid_t pid,
Ken Mixter207694d2010-10-28 15:42:37 -0700239 FilePath *crash_file_path,
240 bool *out_of_capacity) {
Ken Mixter777484c2010-07-23 16:22:44 -0700241 FilePath process_path = GetProcessPath(pid);
242 std::string status;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800243 if (FLAGS_directory_failure) {
244 logger_->LogError("Purposefully failing to create spool directory");
Ken Mixter207694d2010-10-28 15:42:37 -0700245 return false;
246 }
Ken Mixter777484c2010-07-23 16:22:44 -0700247 if (!file_util::ReadFileToString(process_path.Append("status"),
248 &status)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800249 logger_->LogError("Could not read status file");
250 logger_->LogInfo("Path %s FileExists: %d",
251 process_path.value().c_str(),
252 file_util::DirectoryExists(process_path));
Ken Mixter777484c2010-07-23 16:22:44 -0700253 return false;
254 }
255 int process_euid;
256 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800257 logger_->LogError("Could not find euid in status file");
Ken Mixter777484c2010-07-23 16:22:44 -0700258 return false;
259 }
Ken Mixter207694d2010-10-28 15:42:37 -0700260 if (!GetCreatedCrashDirectoryByEuid(process_euid,
261 crash_file_path,
262 out_of_capacity)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800263 logger_->LogError("Could not create crash directory");
Ken Mixter207694d2010-10-28 15:42:37 -0700264 return false;
265 }
266 return true;
Ken Mixter777484c2010-07-23 16:22:44 -0700267}
268
269bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
270 // Copy off all stdin to a core file.
271 FilePath stdin_path("/dev/fd/0");
272 if (file_util::CopyFile(stdin_path, core_path)) {
273 return true;
274 }
275
Ken Mixter1b8fe012011-01-25 13:33:05 -0800276 logger_->LogError("Could not write core file");
Ken Mixter777484c2010-07-23 16:22:44 -0700277 // If the file system was full, make sure we remove any remnants.
278 file_util::Delete(core_path, false);
279 return false;
280}
281
Ken Mixter207694d2010-10-28 15:42:37 -0700282bool UserCollector::RunCoreToMinidump(const FilePath &core_path,
283 const FilePath &procfs_directory,
284 const FilePath &minidump_path,
285 const FilePath &temp_directory) {
Ken Mixter777484c2010-07-23 16:22:44 -0700286 FilePath output_path = temp_directory.Append("output");
Ken Mixter2953c3a2010-10-18 14:42:20 -0700287 std::vector<const char *> core2md_arguments;
288 core2md_arguments.push_back(kCoreToMinidumpConverterPath);
289 core2md_arguments.push_back(core_path.value().c_str());
290 core2md_arguments.push_back(procfs_directory.value().c_str());
291 core2md_arguments.push_back(minidump_path.value().c_str());
292
Ken Mixter1b8fe012011-01-25 13:33:05 -0800293 if (FLAGS_core2md_failure) {
Ken Mixter207694d2010-10-28 15:42:37 -0700294 // To test how core2md errors are propagaged, cause an error
295 // by forgetting a required argument.
296 core2md_arguments.pop_back();
297 }
298
Ken Mixter2953c3a2010-10-18 14:42:20 -0700299 int errorlevel = ForkExecAndPipe(core2md_arguments,
300 output_path.value().c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700301
302 std::string output;
303 file_util::ReadFileToString(output_path, &output);
304 if (errorlevel != 0) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800305 logger_->LogError("Problem during %s [result=%d]: %s",
306 kCoreToMinidumpConverterPath,
307 errorlevel,
308 output.c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700309 return false;
310 }
311
312 if (!file_util::PathExists(minidump_path)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800313 logger_->LogError("Minidump file %s was not created",
314 minidump_path.value().c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700315 return false;
316 }
317 return true;
318}
319
Ken Mixter207694d2010-10-28 15:42:37 -0700320bool UserCollector::ConvertCoreToMinidump(pid_t pid,
321 const FilePath &container_dir,
322 const FilePath &core_path,
323 const FilePath &minidump_path) {
Ken Mixter777484c2010-07-23 16:22:44 -0700324 if (!CopyOffProcFiles(pid, container_dir)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700325 return false;
326 }
327
Ken Mixter777484c2010-07-23 16:22:44 -0700328 if (!CopyStdinToCoreFile(core_path)) {
Ken Mixter777484c2010-07-23 16:22:44 -0700329 return false;
330 }
331
Ken Mixter207694d2010-10-28 15:42:37 -0700332 bool conversion_result = RunCoreToMinidump(
333 core_path,
334 container_dir, // procfs directory
335 minidump_path,
336 container_dir); // temporary directory
Ken Mixteree849c52010-09-30 15:30:10 -0700337
Ken Mixter777484c2010-07-23 16:22:44 -0700338 if (conversion_result) {
339 logger_->LogInfo("Stored minidump to %s", minidump_path.value().c_str());
340 }
341
Ken Mixter207694d2010-10-28 15:42:37 -0700342 return conversion_result;
343}
344
345bool UserCollector::ConvertAndEnqueueCrash(int pid,
346 const std::string &exec,
347 bool *out_of_capacity) {
348 FilePath crash_path;
349 if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800350 logger_->LogError("Unable to find/create process-specific crash path");
Ken Mixter207694d2010-10-28 15:42:37 -0700351 return false;
352 }
353
354 // Directory like /tmp/crash_reporter.1234 which contains the
355 // procfs entries and other temporary files used during conversion.
356 FilePath container_dir = FilePath("/tmp").Append(
357 StringPrintf("crash_reporter.%d", pid));
Ken Mixter1b8fe012011-01-25 13:33:05 -0800358 // Delete a pre-existing directory from crash reporter that may have
359 // been left around for diagnostics from a failed conversion attempt.
360 // If we don't, existing files can cause forking to fail.
361 file_util::Delete(container_dir, true);
Ken Mixter207694d2010-10-28 15:42:37 -0700362 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid);
363 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core");
364 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta");
365 FilePath minidump_path = GetCrashPath(crash_path, dump_basename, "dmp");
Ken Mixterc49dbd42010-12-14 17:44:11 -0800366 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log");
367
368 if (GetLogContents(FilePath(kDefaultLogConfig), exec, log_path))
369 AddCrashMetaData("log", log_path.value());
Ken Mixter207694d2010-10-28 15:42:37 -0700370
371 if (!ConvertCoreToMinidump(pid, container_dir, core_path,
372 minidump_path)) {
373 logger_->LogInfo("Leaving core file at %s due to conversion error",
374 core_path.value().c_str());
375 return false;
376 }
377
378 // Here we commit to sending this file. We must not return false
379 // after this point or we will generate a log report as well as a
380 // crash report.
381 WriteCrashMetaData(meta_path,
382 exec,
383 minidump_path.value());
384
Ken Mixter777484c2010-07-23 16:22:44 -0700385 if (!file_util::PathExists(FilePath(kLeaveCoreFile))) {
386 file_util::Delete(core_path, false);
387 } else {
Ken Mixter207694d2010-10-28 15:42:37 -0700388 logger_->LogInfo("Leaving core file at %s due to developer image",
389 core_path.value().c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700390 }
391
Ken Mixter207694d2010-10-28 15:42:37 -0700392 file_util::Delete(container_dir, true);
393 return true;
Ken Mixter777484c2010-07-23 16:22:44 -0700394}
395
Ken Mixter1b8fe012011-01-25 13:33:05 -0800396bool UserCollector::ParseCrashAttributes(const std::string &crash_attributes,
397 pid_t *pid, int *signal,
398 std::string *kernel_supplied_name) {
399 pcrecpp::RE re("(\\d+):(\\d+):(.*)");
400 return re.FullMatch(crash_attributes, pid, signal, kernel_supplied_name);
401}
402
403bool UserCollector::HandleCrash(const std::string &crash_attributes,
404 const char *force_exec) {
Chris Sosae4a86032010-06-16 17:08:34 -0700405 CHECK(initialized_);
Ken Mixter1b8fe012011-01-25 13:33:05 -0800406 int pid = 0;
407 int signal = 0;
408 std::string kernel_supplied_name;
409
410 if (!ParseCrashAttributes(crash_attributes, &pid, &signal,
411 &kernel_supplied_name)) {
412 logger_->LogError("Invalid parameter: --user=%s", crash_attributes.c_str());
413 return false;
414 }
415
Ken Mixter777484c2010-07-23 16:22:44 -0700416 std::string exec;
417 if (force_exec) {
418 exec.assign(force_exec);
419 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) {
Ken Mixter1b8fe012011-01-25 13:33:05 -0800420 // If we cannot find the exec name, use the kernel supplied name.
421 // We don't always use the kernel's since it truncates the name to
422 // 16 characters.
423 exec = StringPrintf("supplied_%s", kernel_supplied_name.c_str());
Ken Mixter777484c2010-07-23 16:22:44 -0700424 }
Ken Mixterc6a58e02010-11-01 18:05:30 -0700425
426 // Allow us to test the crash reporting mechanism successfully even if
427 // other parts of the system crash.
428 if (!FLAGS_filter_in.empty() &&
429 (FLAGS_filter_in == "none" ||
430 FLAGS_filter_in != exec)) {
431 // We use a different format message to make it more obvious in tests
432 // which crashes are test generated and which are real.
Ken Mixter1b8fe012011-01-25 13:33:05 -0800433 logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s.",
Ken Mixterc6a58e02010-11-01 18:05:30 -0700434 exec.c_str(), pid, FLAGS_filter_in.c_str());
435 return true;
436 }
437
Ken Mixteree849c52010-09-30 15:30:10 -0700438 bool feedback = is_feedback_allowed_function_();
Ken Mixter2105b492010-11-09 16:14:38 -0800439 const char *handling_string = "handling";
440 if (!feedback) {
441 handling_string = "ignoring - no consent";
442 }
443
444 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome
445 // crashes towards user crashes, so user crashes really mean non-Chrome
446 // user-space crashes.
447 if (exec == "chrome") {
448 feedback = false;
449 handling_string = "ignoring - chrome crash";
450 }
451
Ken Mixteree849c52010-09-30 15:30:10 -0700452 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)",
Ken Mixter2105b492010-11-09 16:14:38 -0800453 exec.c_str(), pid, signal, handling_string);
Chris Sosae4a86032010-06-16 17:08:34 -0700454
Ken Mixteree849c52010-09-30 15:30:10 -0700455 if (feedback) {
Chris Sosae4a86032010-06-16 17:08:34 -0700456 count_crash_function_();
Ken Mixter777484c2010-07-23 16:22:44 -0700457
Ken Mixter03403162010-08-18 15:23:16 -0700458 if (generate_diagnostics_) {
Ken Mixter207694d2010-10-28 15:42:37 -0700459 bool out_of_capacity = false;
Ken Mixter1b8fe012011-01-25 13:33:05 -0800460 logger_->set_accumulating(true);
461 bool convert_and_enqueue_result =
462 ConvertAndEnqueueCrash(pid, exec, &out_of_capacity);
463 logger_->set_accumulating(false);
464 if (!convert_and_enqueue_result) {
Ken Mixter207694d2010-10-28 15:42:37 -0700465 if (!out_of_capacity)
466 EnqueueCollectionErrorLog(pid, exec);
467 return false;
468 }
Ken Mixter03403162010-08-18 15:23:16 -0700469 }
Ken Mixter777484c2010-07-23 16:22:44 -0700470 }
Ken Mixter207694d2010-10-28 15:42:37 -0700471
Ken Mixter777484c2010-07-23 16:22:44 -0700472 return true;
Chris Sosae4a86032010-06-16 17:08:34 -0700473}