| Index: crash_collector.cc
|
| diff --git a/crash_collector.cc b/crash_collector.cc
|
| index f2f514694180b750240f4ea197b1673b99e66d48..e91f70a12056975a50212506ac67dd2cb807198b 100644
|
| --- a/crash_collector.cc
|
| +++ b/crash_collector.cc
|
| @@ -8,12 +8,15 @@
|
| #include <pwd.h> // For struct passwd.
|
| #include <sys/types.h> // for mode_t.
|
|
|
| +#include <set>
|
| +
|
| #include "base/file_util.h"
|
| #include "base/logging.h"
|
| #include "base/string_util.h"
|
| #include "crash-reporter/system_logging.h"
|
|
|
| static const char kDefaultUserName[] = "chronos";
|
| +static const char kLsbRelease[] = "/etc/lsb-release";
|
| static const char kSystemCrashPath[] = "/var/spool/crash";
|
| static const char kUserCrashPath[] = "/home/chronos/user/crash";
|
|
|
| @@ -55,13 +58,23 @@ void CrashCollector::Initialize(
|
| logger_ = logger;
|
| }
|
|
|
| +std::string CrashCollector::Sanitize(const std::string &name) {
|
| + std::string result = name;
|
| + for (size_t i = 0; i < name.size(); ++i) {
|
| + if (!isalnum(result[i]) && result[i] != '_')
|
| + result[i] = '_';
|
| + }
|
| + return result;
|
| +}
|
| +
|
| std::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
|
| time_t timestamp,
|
| pid_t pid) {
|
| struct tm tm;
|
| localtime_r(×tamp, &tm);
|
| + std::string sanitized_exec_name = Sanitize(exec_name);
|
| return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d",
|
| - exec_name.c_str(),
|
| + sanitized_exec_name.c_str(),
|
| tm.tm_year + 1900,
|
| tm.tm_mon + 1,
|
| tm.tm_mday,
|
| @@ -173,22 +186,27 @@ bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
|
| }
|
| struct dirent ent_buf;
|
| struct dirent* ent;
|
| - int count_non_core = 0;
|
| - int count_core = 0;
|
| bool full = false;
|
| + std::set<std::string> basenames;
|
| while (readdir_r(dir, &ent_buf, &ent) == 0 && ent != NULL) {
|
| if ((strcmp(ent->d_name, ".") == 0) ||
|
| (strcmp(ent->d_name, "..") == 0))
|
| continue;
|
|
|
| - if (strcmp(ent->d_name + strlen(ent->d_name) - 5, ".core") == 0) {
|
| - ++count_core;
|
| - } else {
|
| - ++count_non_core;
|
| - }
|
| + std::string filename(ent->d_name);
|
| + size_t last_dot = filename.rfind(".");
|
| + std::string basename;
|
| + // If there is a valid looking extension, use the base part of the
|
| + // name. If the only dot is the first byte (aka a dot file), treat
|
| + // it as unique to avoid allowing a directory full of dot files
|
| + // from accumulating.
|
| + if (last_dot != std::string::npos && last_dot != 0)
|
| + basename = filename.substr(0, last_dot);
|
| + else
|
| + basename = filename;
|
| + basenames.insert(basename);
|
|
|
| - if (count_core >= kMaxCrashDirectorySize ||
|
| - count_non_core >= kMaxCrashDirectorySize) {
|
| + if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
|
| logger_->LogWarning(
|
| "Crash directory %s already full with %d pending reports",
|
| crash_directory.value().c_str(),
|
| @@ -200,3 +218,53 @@ bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
|
| closedir(dir);
|
| return !full;
|
| }
|
| +
|
| +bool CrashCollector::ReadKeyValueFile(
|
| + const FilePath &path,
|
| + const char separator,
|
| + std::map<std::string, std::string> *dictionary) {
|
| + std::string contents;
|
| + if (!file_util::ReadFileToString(path, &contents)) {
|
| + return false;
|
| + }
|
| + typedef std::vector<std::string> StringVector;
|
| + StringVector lines;
|
| + SplitString(contents, '\n', &lines);
|
| + bool any_errors = false;
|
| + for (StringVector::iterator line = lines.begin(); line != lines.end();
|
| + ++line) {
|
| + // Allow empty strings.
|
| + if (line->empty())
|
| + continue;
|
| + StringVector sides;
|
| + SplitString(*line, separator, &sides);
|
| + if (sides.size() != 2) {
|
| + any_errors = true;
|
| + continue;
|
| + }
|
| + dictionary->insert(std::pair<std::string, std::string>(sides[0], sides[1]));
|
| + }
|
| + return !any_errors;
|
| +}
|
| +
|
| +void CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
|
| + const std::string &exec_name) {
|
| + std::map<std::string, std::string> contents;
|
| + if (!ReadKeyValueFile(FilePath(std::string(kLsbRelease)), '=', &contents)) {
|
| + logger_->LogError("Problem parsing %s", kLsbRelease);
|
| + // Even though there was some failure, take as much as we could read.
|
| + }
|
| + std::string version("unknown");
|
| + std::map<std::string, std::string>::iterator i;
|
| + if ((i = contents.find("CHROMEOS_RELEASE_VERSION")) != contents.end()) {
|
| + version = i->second;
|
| + }
|
| + std::string meta_data = StringPrintf("exec_name=%s\n"
|
| + "ver=%s\n"
|
| + "done=1\n",
|
| + exec_name.c_str(),
|
| + version.c_str());
|
| + if (!file_util::WriteFile(meta_path, meta_data.c_str(), meta_data.size())) {
|
| + logger_->LogError("Unable to write %s", meta_path.value().c_str());
|
| + }
|
| +}
|
|
|