crash_collector.cc revision a324932e066ccb7ed9d62db9c409ee2c10052554
10340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
20340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Use of this source code is governed by a BSD-style license that can be
30340316050044e0995b98fea87ed41ea77abb28bKen Mixter// found in the LICENSE file.
40340316050044e0995b98fea87ed41ea77abb28bKen Mixter
50340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "crash-reporter/crash_collector.h"
60340316050044e0995b98fea87ed41ea77abb28bKen Mixter
704ec10fc93b08057657503559ecf511661b55c9fKen Mixter#include <dirent.h>
89b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <fcntl.h>  // For file creation modes.
90340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include <pwd.h>  // For struct passwd.
100340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include <sys/types.h>  // for mode_t.
119b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <sys/wait.h>  // For waitpid.
129b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <unistd.h>  // For execv and fork.
130340316050044e0995b98fea87ed41ea77abb28bKen Mixter
14ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter#include <set>
15ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
169b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include "base/eintr_wrapper.h"
170340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "base/file_util.h"
180340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "base/logging.h"
190340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "base/string_util.h"
20a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter#include "chromeos/process.h"
210340316050044e0995b98fea87ed41ea77abb28bKen Mixter
220340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const char kDefaultUserName[] = "chronos";
23ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterstatic const char kLsbRelease[] = "/etc/lsb-release";
24c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterstatic const char kShellPath[] = "/bin/sh";
250340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const char kSystemCrashPath[] = "/var/spool/crash";
260340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const char kUserCrashPath[] = "/home/chronos/user/crash";
270340316050044e0995b98fea87ed41ea77abb28bKen Mixter
280340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the user crash spool directory.
290340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const mode_t kUserCrashPathMode = 0755;
300340316050044e0995b98fea87ed41ea77abb28bKen Mixter
310340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the system crash spool directory.
320340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const mode_t kSystemCrashPathMode = 01755;
330340316050044e0995b98fea87ed41ea77abb28bKen Mixter
340340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const uid_t kRootOwner = 0;
350340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const uid_t kRootGroup = 0;
360340316050044e0995b98fea87ed41ea77abb28bKen Mixter
37da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// Maximum crash reports per crash spool directory.  Note that this is
38da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// a separate maximum from the maximum rate at which we upload these
39da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// diagnostics.  The higher this rate is, the more space we allow for
40da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// core files, minidumps, and kcrash logs, and equivalently the more
41da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// processor and I/O bandwidth we dedicate to handling these crashes when
42da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// many occur at once.  Also note that if core files are configured to
43da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// be left on the file system, we stop adding crashes when either the
44da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// number of core files or minidumps reaches this number.
45da5db7a8304e22af6c57733460516857e9211b32Ken Mixterconst int CrashCollector::kMaxCrashDirectorySize = 32;
4604ec10fc93b08057657503559ecf511661b55c9fKen Mixter
47afcf80821c57a189b53b7a66f76d13855d63821eKen MixterCrashCollector::CrashCollector()
48afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    : forced_crash_directory_(NULL),
49afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter      lsb_release_(kLsbRelease) {
500340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
510340316050044e0995b98fea87ed41ea77abb28bKen Mixter
520340316050044e0995b98fea87ed41ea77abb28bKen MixterCrashCollector::~CrashCollector() {
530340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
540340316050044e0995b98fea87ed41ea77abb28bKen Mixter
550340316050044e0995b98fea87ed41ea77abb28bKen Mixtervoid CrashCollector::Initialize(
560340316050044e0995b98fea87ed41ea77abb28bKen Mixter    CrashCollector::CountCrashFunction count_crash_function,
57a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) {
580340316050044e0995b98fea87ed41ea77abb28bKen Mixter  CHECK(count_crash_function != NULL);
590340316050044e0995b98fea87ed41ea77abb28bKen Mixter  CHECK(is_feedback_allowed_function != NULL);
600340316050044e0995b98fea87ed41ea77abb28bKen Mixter
610340316050044e0995b98fea87ed41ea77abb28bKen Mixter  count_crash_function_ = count_crash_function;
620340316050044e0995b98fea87ed41ea77abb28bKen Mixter  is_feedback_allowed_function_ = is_feedback_allowed_function;
630340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
640340316050044e0995b98fea87ed41ea77abb28bKen Mixter
659b346474538a255bc7144ae358bb0ee129163d58Ken Mixterint CrashCollector::WriteNewFile(const FilePath &filename,
669b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                                 const char *data,
679b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                                 int size) {
689b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  int fd = HANDLE_EINTR(open(filename.value().c_str(),
699b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                             O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
709b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  if (fd < 0) {
719b346474538a255bc7144ae358bb0ee129163d58Ken Mixter    return -1;
729b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  }
739b346474538a255bc7144ae358bb0ee129163d58Ken Mixter
749b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  int rv = file_util::WriteFileDescriptor(fd, data, size);
759b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  HANDLE_EINTR(close(fd));
769b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  return rv;
779b346474538a255bc7144ae358bb0ee129163d58Ken Mixter}
789b346474538a255bc7144ae358bb0ee129163d58Ken Mixter
79ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterstd::string CrashCollector::Sanitize(const std::string &name) {
80ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string result = name;
81ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  for (size_t i = 0; i < name.size(); ++i) {
82ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (!isalnum(result[i]) && result[i] != '_')
83ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      result[i] = '_';
84ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
85ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  return result;
86ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
87ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
880340316050044e0995b98fea87ed41ea77abb28bKen Mixterstd::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
890340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                               time_t timestamp,
900340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                               pid_t pid) {
910340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct tm tm;
920340316050044e0995b98fea87ed41ea77abb28bKen Mixter  localtime_r(&timestamp, &tm);
93ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string sanitized_exec_name = Sanitize(exec_name);
940340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d",
95ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                      sanitized_exec_name.c_str(),
960340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_year + 1900,
970340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_mon + 1,
980340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_mday,
990340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_hour,
1000340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_min,
1010340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_sec,
1020340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      pid);
1030340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1040340316050044e0995b98fea87ed41ea77abb28bKen Mixter
105207694d3f491ef602a859c30cc1379584f2d61cfKen MixterFilePath CrashCollector::GetCrashPath(const FilePath &crash_directory,
106207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                      const std::string &basename,
107207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                      const std::string &extension) {
108207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter  return crash_directory.Append(StringPrintf("%s.%s",
109207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                             basename.c_str(),
110207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                             extension.c_str()));
111207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter}
112207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter
1130340316050044e0995b98fea87ed41ea77abb28bKen MixterFilePath CrashCollector::GetCrashDirectoryInfo(
1140340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t process_euid,
1150340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t default_user_id,
1160340316050044e0995b98fea87ed41ea77abb28bKen Mixter    gid_t default_user_group,
1170340316050044e0995b98fea87ed41ea77abb28bKen Mixter    mode_t *mode,
1180340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t *directory_owner,
1190340316050044e0995b98fea87ed41ea77abb28bKen Mixter    gid_t *directory_group) {
1200340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (process_euid == default_user_id) {
1210340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *mode = kUserCrashPathMode;
1220340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_owner = default_user_id;
1230340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_group = default_user_group;
1240340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return FilePath(kUserCrashPath);
1250340316050044e0995b98fea87ed41ea77abb28bKen Mixter  } else {
1260340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *mode = kSystemCrashPathMode;
1270340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_owner = kRootOwner;
1280340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_group = kRootGroup;
1290340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return FilePath(kSystemCrashPath);
1300340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
1310340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1320340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1330340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetUserInfoFromName(const std::string &name,
1340340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                         uid_t *uid,
1350340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                         gid_t *gid) {
1360340316050044e0995b98fea87ed41ea77abb28bKen Mixter  char storage[256];
1370340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct passwd passwd_storage;
1380340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct passwd *passwd_result = NULL;
1390340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1400340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage),
1410340316050044e0995b98fea87ed41ea77abb28bKen Mixter                 &passwd_result) != 0 || passwd_result == NULL) {
142a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Cannot find user named " << name;
1430340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
1440340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
1450340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1460340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *uid = passwd_result->pw_uid;
1470340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *gid = passwd_result->pw_gid;
1480340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
1490340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1500340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1510340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
152207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                                    FilePath *crash_directory,
153207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                                    bool *out_of_capacity) {
1540340316050044e0995b98fea87ed41ea77abb28bKen Mixter  uid_t default_user_id;
1550340316050044e0995b98fea87ed41ea77abb28bKen Mixter  gid_t default_user_group;
1560340316050044e0995b98fea87ed41ea77abb28bKen Mixter
157207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter  if (out_of_capacity != NULL) *out_of_capacity = false;
158207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter
1590340316050044e0995b98fea87ed41ea77abb28bKen Mixter  // For testing.
1600340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (forced_crash_directory_ != NULL) {
1610340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *crash_directory = FilePath(forced_crash_directory_);
1620340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return true;
1630340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
1640340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1650340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!GetUserInfoFromName(kDefaultUserName,
1660340316050044e0995b98fea87ed41ea77abb28bKen Mixter                           &default_user_id,
1670340316050044e0995b98fea87ed41ea77abb28bKen Mixter                           &default_user_group)) {
168a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Could not find default user info";
1690340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
1700340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
1710340316050044e0995b98fea87ed41ea77abb28bKen Mixter  mode_t directory_mode;
1720340316050044e0995b98fea87ed41ea77abb28bKen Mixter  uid_t directory_owner;
1730340316050044e0995b98fea87ed41ea77abb28bKen Mixter  gid_t directory_group;
1740340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *crash_directory =
1750340316050044e0995b98fea87ed41ea77abb28bKen Mixter      GetCrashDirectoryInfo(euid,
1760340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            default_user_id,
1770340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            default_user_group,
1780340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_mode,
1790340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_owner,
1800340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_group);
1810340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1820340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!file_util::PathExists(*crash_directory)) {
1830340316050044e0995b98fea87ed41ea77abb28bKen Mixter    // Create the spool directory with the appropriate mode (regardless of
1840340316050044e0995b98fea87ed41ea77abb28bKen Mixter    // umask) and ownership.
1850340316050044e0995b98fea87ed41ea77abb28bKen Mixter    mode_t old_mask = umask(0);
1860340316050044e0995b98fea87ed41ea77abb28bKen Mixter    if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 ||
1870340316050044e0995b98fea87ed41ea77abb28bKen Mixter        chown(crash_directory->value().c_str(),
1880340316050044e0995b98fea87ed41ea77abb28bKen Mixter              directory_owner,
1890340316050044e0995b98fea87ed41ea77abb28bKen Mixter              directory_group) < 0) {
190a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(ERROR) << "Unable to create appropriate crash directory";
1910340316050044e0995b98fea87ed41ea77abb28bKen Mixter      return false;
1920340316050044e0995b98fea87ed41ea77abb28bKen Mixter    }
1930340316050044e0995b98fea87ed41ea77abb28bKen Mixter    umask(old_mask);
1940340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
1950340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1960340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!file_util::PathExists(*crash_directory)) {
197a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Unable to create crash directory "
198a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter               << crash_directory->value().c_str();
1990340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
2000340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2010340316050044e0995b98fea87ed41ea77abb28bKen Mixter
20204ec10fc93b08057657503559ecf511661b55c9fKen Mixter  if (!CheckHasCapacity(*crash_directory)) {
203207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter    if (out_of_capacity != NULL) *out_of_capacity = true;
20404ec10fc93b08057657503559ecf511661b55c9fKen Mixter    return false;
20504ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
20604ec10fc93b08057657503559ecf511661b55c9fKen Mixter
2070340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
2080340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
20904ec10fc93b08057657503559ecf511661b55c9fKen Mixter
21004ec10fc93b08057657503559ecf511661b55c9fKen Mixter// Return true if the given crash directory has not already reached
21104ec10fc93b08057657503559ecf511661b55c9fKen Mixter// maximum capacity.
21204ec10fc93b08057657503559ecf511661b55c9fKen Mixterbool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
21304ec10fc93b08057657503559ecf511661b55c9fKen Mixter  DIR* dir = opendir(crash_directory.value().c_str());
21404ec10fc93b08057657503559ecf511661b55c9fKen Mixter  if (!dir) {
21504ec10fc93b08057657503559ecf511661b55c9fKen Mixter    return false;
21604ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
21704ec10fc93b08057657503559ecf511661b55c9fKen Mixter  struct dirent ent_buf;
21804ec10fc93b08057657503559ecf511661b55c9fKen Mixter  struct dirent* ent;
21904ec10fc93b08057657503559ecf511661b55c9fKen Mixter  bool full = false;
220ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::set<std::string> basenames;
22104ec10fc93b08057657503559ecf511661b55c9fKen Mixter  while (readdir_r(dir, &ent_buf, &ent) == 0 && ent != NULL) {
22204ec10fc93b08057657503559ecf511661b55c9fKen Mixter    if ((strcmp(ent->d_name, ".") == 0) ||
22304ec10fc93b08057657503559ecf511661b55c9fKen Mixter        (strcmp(ent->d_name, "..") == 0))
22404ec10fc93b08057657503559ecf511661b55c9fKen Mixter      continue;
22504ec10fc93b08057657503559ecf511661b55c9fKen Mixter
226ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string filename(ent->d_name);
227ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    size_t last_dot = filename.rfind(".");
228ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string basename;
229ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // If there is a valid looking extension, use the base part of the
230ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // name.  If the only dot is the first byte (aka a dot file), treat
231ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // it as unique to avoid allowing a directory full of dot files
232ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // from accumulating.
233ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (last_dot != std::string::npos && last_dot != 0)
234ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      basename = filename.substr(0, last_dot);
235ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    else
236ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      basename = filename;
237ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    basenames.insert(basename);
23804ec10fc93b08057657503559ecf511661b55c9fKen Mixter
239ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
240a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(WARNING) << "Crash directory " << crash_directory.value()
241a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                   << " already full with " << kMaxCrashDirectorySize
242a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                   << " pending reports";
24304ec10fc93b08057657503559ecf511661b55c9fKen Mixter      full = true;
24404ec10fc93b08057657503559ecf511661b55c9fKen Mixter      break;
24504ec10fc93b08057657503559ecf511661b55c9fKen Mixter    }
24604ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
24704ec10fc93b08057657503559ecf511661b55c9fKen Mixter  closedir(dir);
24804ec10fc93b08057657503559ecf511661b55c9fKen Mixter  return !full;
24904ec10fc93b08057657503559ecf511661b55c9fKen Mixter}
250ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
251c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterbool CrashCollector::IsCommentLine(const std::string &line) {
252c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  size_t found = line.find_first_not_of(" ");
253c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  return found != std::string::npos && line[found] == '#';
254c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter}
255c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
256ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterbool CrashCollector::ReadKeyValueFile(
257ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    const FilePath &path,
258ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    const char separator,
259ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::map<std::string, std::string> *dictionary) {
260ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string contents;
261ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  if (!file_util::ReadFileToString(path, &contents)) {
262ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    return false;
263ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
264ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  typedef std::vector<std::string> StringVector;
265ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  StringVector lines;
266ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  SplitString(contents, '\n', &lines);
267ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  bool any_errors = false;
268ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  for (StringVector::iterator line = lines.begin(); line != lines.end();
269ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter       ++line) {
270ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // Allow empty strings.
271ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (line->empty())
272ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      continue;
273c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    // Allow comment lines.
274c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    if (IsCommentLine(*line))
275c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter      continue;
276ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    StringVector sides;
277ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    SplitString(*line, separator, &sides);
278ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (sides.size() != 2) {
279ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      any_errors = true;
280ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      continue;
281ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    }
282ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    dictionary->insert(std::pair<std::string, std::string>(sides[0], sides[1]));
283ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
284ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  return !any_errors;
285ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
286ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
287c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterbool CrashCollector::GetLogContents(const FilePath &config_path,
288c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter                                    const std::string &exec_name,
289c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter                                    const FilePath &output_file) {
290c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  std::map<std::string, std::string> log_commands;
291c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  if (!ReadKeyValueFile(config_path, ':', &log_commands)) {
292a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(INFO) << "Unable to read log configuration file "
293a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter              << config_path.value();
294c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
295c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  }
296c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
297c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  if (log_commands.find(exec_name) == log_commands.end())
298c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
299c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
300a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  chromeos::ProcessImpl diag_process;
301a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.AddArg(kShellPath);
302c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  std::string shell_command = log_commands[exec_name];
303a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.AddStringOption("-c", shell_command);
304a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.RedirectOutput(output_file.value());
305c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
306a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  int result = diag_process.Run();
307a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  if (result != 0) {
308a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(INFO) << "Running shell command " << shell_command << "failed with: "
309a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter              << result;
310c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
311c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  }
312c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  return true;
313c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter}
314c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
315afcf80821c57a189b53b7a66f76d13855d63821eKen Mixtervoid CrashCollector::AddCrashMetaData(const std::string &key,
316afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                      const std::string &value) {
317afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str()));
318afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
319afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
320ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixtervoid CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
321c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                        const std::string &exec_name,
322c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                        const std::string &payload_path) {
323ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::map<std::string, std::string> contents;
324afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (!ReadKeyValueFile(FilePath(std::string(lsb_release_)), '=', &contents)) {
325a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Problem parsing " << lsb_release_;
326ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // Even though there was some failure, take as much as we could read.
327ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
328ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string version("unknown");
329ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::map<std::string, std::string>::iterator i;
330ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  if ((i = contents.find("CHROMEOS_RELEASE_VERSION")) != contents.end()) {
331ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    version = i->second;
332ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
333c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter  int64 payload_size = -1;
334c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter  file_util::GetFileSize(FilePath(payload_path), &payload_size);
335afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string meta_data = StringPrintf("%sexec_name=%s\n"
336ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       "ver=%s\n"
337207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                       "payload=%s\n"
338c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       "payload_size=%lld\n"
339ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       "done=1\n",
340afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                       extra_metadata_.c_str(),
341ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       exec_name.c_str(),
342c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       version.c_str(),
343207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                       payload_path.c_str(),
344c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       payload_size);
3459b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // We must use WriteNewFile instead of file_util::WriteFile as we
3469b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // do not want to write with root access to a symlink that an attacker
3479b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // might have created.
3489b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) {
349a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Unable to write " << meta_path.value();
350ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
351ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
352