crash_collector.cc revision f19b518532cb2ab8fc1ed77381809f24a30ac4ca
1f70060c5e610ed0aa648dcb6aaea5d859834b8baSimon Que// Copyright (c) 2012 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.
1365b4c1efb0bca77f3a73401499adc5c39d982c18Mike Frysinger#define __STDC_FORMAT_MACROS // PRId64
1465b4c1efb0bca77f3a73401499adc5c39d982c18Mike Frysinger#include <inttypes.h>
150340316050044e0995b98fea87ed41ea77abb28bKen Mixter
16ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter#include <set>
17f70060c5e610ed0aa648dcb6aaea5d859834b8baSimon Que#include <vector>
18ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
19f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include <dbus/dbus-glib-lowlevel.h>
20f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include <glib.h>
21f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
220340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "base/file_util.h"
230340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "base/logging.h"
241a8780d309b980914a5e2403bf9addafe07386ecMike Frysinger#include "base/posix/eintr_wrapper.h"
258a68c7cb30d053de2b3008bee20422258f5e6b3cChris Masone#include "base/string_split.h"
260340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include "base/string_util.h"
2757b261cf04f45d67b02f6bea8ad2c37734da86e0Mike Frysinger#include "base/stringprintf.h"
28f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include "chromeos/cryptohome.h"
29f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include "chromeos/dbus/dbus.h"
30f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include "chromeos/dbus/service_constants.h"
31a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter#include "chromeos/process.h"
320340316050044e0995b98fea87ed41ea77abb28bKen Mixter
334fe30db1405498dd21162436eda081486f400fa8Michael Krebsstatic const char kCollectChromeFile[] =
344fe30db1405498dd21162436eda081486f400fa8Michael Krebs    "/mnt/stateful_partition/etc/collect_chrome_crashes";
354fe30db1405498dd21162436eda081486f400fa8Michael Krebsstatic const char kCrashTestInProgressPath[] = "/tmp/crash-test-in-progress";
36f70060c5e610ed0aa648dcb6aaea5d859834b8baSimon Questatic const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
370340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const char kDefaultUserName[] = "chronos";
384fe30db1405498dd21162436eda081486f400fa8Michael Krebsstatic const char kLeaveCoreFile[] = "/root/.leave_core";
39ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterstatic const char kLsbRelease[] = "/etc/lsb-release";
40c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterstatic const char kShellPath[] = "/bin/sh";
410340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const char kSystemCrashPath[] = "/var/spool/crash";
42f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// Normally this path is not used.  Unfortunately, there are a few edge cases
43f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// where we need this.  Any process that runs as kDefaultUserName that crashes
44f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// is consider a "user crash".  That includes the initial Chrome browser that
45f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// runs the login screen.  If that blows up, there is no logged in user yet,
46f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// so there is no per-user dir for us to stash things in.  Instead we fallback
47f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// to this path as it is at least encrypted on a per-system basis.
48f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger//
49f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// This also comes up when running autotests.  The GUI is sitting at the login
50f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// screen while tests are sshing in, changing users, and triggering crashes as
51f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// the user (purposefully).
52f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysingerstatic const char kFallbackUserCrashPath[] = "/home/chronos/crash";
530340316050044e0995b98fea87ed41ea77abb28bKen Mixter
540340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the user crash spool directory.
550340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const mode_t kUserCrashPathMode = 0755;
560340316050044e0995b98fea87ed41ea77abb28bKen Mixter
570340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the system crash spool directory.
580340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const mode_t kSystemCrashPathMode = 01755;
590340316050044e0995b98fea87ed41ea77abb28bKen Mixter
600340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const uid_t kRootOwner = 0;
610340316050044e0995b98fea87ed41ea77abb28bKen Mixterstatic const uid_t kRootGroup = 0;
620340316050044e0995b98fea87ed41ea77abb28bKen Mixter
63da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// Maximum crash reports per crash spool directory.  Note that this is
64da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// a separate maximum from the maximum rate at which we upload these
65da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// diagnostics.  The higher this rate is, the more space we allow for
66da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// core files, minidumps, and kcrash logs, and equivalently the more
67da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// processor and I/O bandwidth we dedicate to handling these crashes when
68da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// many occur at once.  Also note that if core files are configured to
69da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// be left on the file system, we stop adding crashes when either the
70da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// number of core files or minidumps reaches this number.
71da5db7a8304e22af6c57733460516857e9211b32Ken Mixterconst int CrashCollector::kMaxCrashDirectorySize = 32;
7204ec10fc93b08057657503559ecf511661b55c9fKen Mixter
739f90acaa4d420530d7b4ddd37112518df68e373aSimon Queusing base::FilePath;
749f90acaa4d420530d7b4ddd37112518df68e373aSimon Que
75afcf80821c57a189b53b7a66f76d13855d63821eKen MixterCrashCollector::CrashCollector()
76afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter    : forced_crash_directory_(NULL),
77acc7938ede0e3c07a2d1809f82b174b51f7ab7c5Simon Que      lsb_release_(kLsbRelease),
78acc7938ede0e3c07a2d1809f82b174b51f7ab7c5Simon Que      log_config_path_(kDefaultLogConfig) {
790340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
800340316050044e0995b98fea87ed41ea77abb28bKen Mixter
810340316050044e0995b98fea87ed41ea77abb28bKen MixterCrashCollector::~CrashCollector() {
820340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
830340316050044e0995b98fea87ed41ea77abb28bKen Mixter
840340316050044e0995b98fea87ed41ea77abb28bKen Mixtervoid CrashCollector::Initialize(
850340316050044e0995b98fea87ed41ea77abb28bKen Mixter    CrashCollector::CountCrashFunction count_crash_function,
86a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) {
870340316050044e0995b98fea87ed41ea77abb28bKen Mixter  CHECK(count_crash_function != NULL);
880340316050044e0995b98fea87ed41ea77abb28bKen Mixter  CHECK(is_feedback_allowed_function != NULL);
890340316050044e0995b98fea87ed41ea77abb28bKen Mixter
900340316050044e0995b98fea87ed41ea77abb28bKen Mixter  count_crash_function_ = count_crash_function;
910340316050044e0995b98fea87ed41ea77abb28bKen Mixter  is_feedback_allowed_function_ = is_feedback_allowed_function;
920340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
930340316050044e0995b98fea87ed41ea77abb28bKen Mixter
949b346474538a255bc7144ae358bb0ee129163d58Ken Mixterint CrashCollector::WriteNewFile(const FilePath &filename,
959b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                                 const char *data,
969b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                                 int size) {
979b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  int fd = HANDLE_EINTR(open(filename.value().c_str(),
989b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                             O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
999b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  if (fd < 0) {
1009b346474538a255bc7144ae358bb0ee129163d58Ken Mixter    return -1;
1019b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  }
1029b346474538a255bc7144ae358bb0ee129163d58Ken Mixter
1039b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  int rv = file_util::WriteFileDescriptor(fd, data, size);
1049b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  HANDLE_EINTR(close(fd));
1059b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  return rv;
1069b346474538a255bc7144ae358bb0ee129163d58Ken Mixter}
1079b346474538a255bc7144ae358bb0ee129163d58Ken Mixter
108ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterstd::string CrashCollector::Sanitize(const std::string &name) {
109ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string result = name;
110ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  for (size_t i = 0; i < name.size(); ++i) {
111ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (!isalnum(result[i]) && result[i] != '_')
112ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      result[i] = '_';
113ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
114ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  return result;
115ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
116ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
1170340316050044e0995b98fea87ed41ea77abb28bKen Mixterstd::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
1180340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                               time_t timestamp,
1190340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                               pid_t pid) {
1200340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct tm tm;
1210340316050044e0995b98fea87ed41ea77abb28bKen Mixter  localtime_r(&timestamp, &tm);
122ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string sanitized_exec_name = Sanitize(exec_name);
1230340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d",
124ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                      sanitized_exec_name.c_str(),
1250340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_year + 1900,
1260340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_mon + 1,
1270340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_mday,
1280340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_hour,
1290340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_min,
1300340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_sec,
1310340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      pid);
1320340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1330340316050044e0995b98fea87ed41ea77abb28bKen Mixter
134207694d3f491ef602a859c30cc1379584f2d61cfKen MixterFilePath CrashCollector::GetCrashPath(const FilePath &crash_directory,
135207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                      const std::string &basename,
136207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                      const std::string &extension) {
137207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter  return crash_directory.Append(StringPrintf("%s.%s",
138207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                             basename.c_str(),
139207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                             extension.c_str()));
140207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter}
141207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter
142f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysingernamespace {
143f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
144f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysingerconst char *GetGErrorMessage(const GError *error) {
145f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!error)
146f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return "Unknown error.";
147f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  return error->message;
148f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
149f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
150f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
151f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
152f19b518532cb2ab8fc1ed77381809f24a30ac4caMike FrysingerGHashTable *CrashCollector::GetActiveUserSessions(void) {
153f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  GHashTable *active_sessions = NULL;
154f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
155f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
156f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!dbus.HasConnection()) {
157f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    LOG(ERROR) << "Error connecting to system D-Bus";
158f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return active_sessions;
159f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
160f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  chromeos::dbus::Proxy proxy(dbus,
161f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                              login_manager::kSessionManagerServiceName,
162f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                              login_manager::kSessionManagerServicePath,
163f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                              login_manager::kSessionManagerInterface);
164f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!proxy) {
165f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    LOG(ERROR) << "Error creating D-Bus proxy to interface "
166f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << "'" << login_manager::kSessionManagerServiceName << "'";
167f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return active_sessions;
168f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
169f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
170f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // Request all the active sessions.
171f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  GError *gerror = NULL;
172f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!dbus_g_proxy_call(proxy.gproxy(),
173f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         login_manager::kSessionManagerRetrieveActiveSessions,
174f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         &gerror, G_TYPE_INVALID,
175f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         DBUS_TYPE_G_STRING_STRING_HASHTABLE, &active_sessions,
176f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         G_TYPE_INVALID)) {
177f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    LOG(ERROR) << "Error performing D-Bus proxy call "
178f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << "'"
179f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << login_manager::kSessionManagerRetrieveActiveSessions << "'"
180f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << ": " << GetGErrorMessage(gerror);
181f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return active_sessions;
182f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
183f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
184f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  return active_sessions;
185f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
186f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
187f19b518532cb2ab8fc1ed77381809f24a30ac4caMike FrysingerFilePath CrashCollector::GetUserCrashPath(void) {
188f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // In this multiprofile world, there is no one-specific user dir anymore.
189f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // Ask the session manager for the active ones, then just run with the
190f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // first result we get back.
191f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  FilePath user_path = FilePath(kFallbackUserCrashPath);
192f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  GHashTable *active_sessions = GetActiveUserSessions();
193f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!active_sessions)
194f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return user_path;
195f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
196f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  GList *list = g_hash_table_get_values(active_sessions);
197f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (list) {
198f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    const char *salted_path = static_cast<const char *>(list->data);
199f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    user_path = chromeos::cryptohome::home::GetHashedUserPath(salted_path);
200f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    g_list_free(list);
201f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
202f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
203f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  g_hash_table_destroy(active_sessions);
204f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
205f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  return user_path;
206f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
207f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
2080340316050044e0995b98fea87ed41ea77abb28bKen MixterFilePath CrashCollector::GetCrashDirectoryInfo(
2090340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t process_euid,
2100340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t default_user_id,
2110340316050044e0995b98fea87ed41ea77abb28bKen Mixter    gid_t default_user_group,
2120340316050044e0995b98fea87ed41ea77abb28bKen Mixter    mode_t *mode,
2130340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t *directory_owner,
2140340316050044e0995b98fea87ed41ea77abb28bKen Mixter    gid_t *directory_group) {
2154fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // TODO(mkrebs): This can go away once Chrome crashes are handled
2164fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // normally (see crosbug.com/5872).
2174fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // Check if the user crash directory should be used.  If we are
2184fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // collecting chrome crashes during autotesting, we want to put them in
2194fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // the system crash directory so they are outside the cryptohome -- in
2204fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // case we are being run during logout (see crosbug.com/18637).
2214fe30db1405498dd21162436eda081486f400fa8Michael Krebs  if (process_euid == default_user_id && IsUserSpecificDirectoryEnabled()) {
2220340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *mode = kUserCrashPathMode;
2230340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_owner = default_user_id;
2240340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_group = default_user_group;
225f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return GetUserCrashPath();
2260340316050044e0995b98fea87ed41ea77abb28bKen Mixter  } else {
2270340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *mode = kSystemCrashPathMode;
2280340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_owner = kRootOwner;
2290340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_group = kRootGroup;
2300340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return FilePath(kSystemCrashPath);
2310340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2320340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
2330340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2340340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetUserInfoFromName(const std::string &name,
2350340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                         uid_t *uid,
2360340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                         gid_t *gid) {
2370340316050044e0995b98fea87ed41ea77abb28bKen Mixter  char storage[256];
2380340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct passwd passwd_storage;
2390340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct passwd *passwd_result = NULL;
2400340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2410340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage),
2420340316050044e0995b98fea87ed41ea77abb28bKen Mixter                 &passwd_result) != 0 || passwd_result == NULL) {
243a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Cannot find user named " << name;
2440340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
2450340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2460340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2470340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *uid = passwd_result->pw_uid;
2480340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *gid = passwd_result->pw_gid;
2490340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
2500340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
2510340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2520340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
253207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                                    FilePath *crash_directory,
254207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                                    bool *out_of_capacity) {
2550340316050044e0995b98fea87ed41ea77abb28bKen Mixter  uid_t default_user_id;
2560340316050044e0995b98fea87ed41ea77abb28bKen Mixter  gid_t default_user_group;
2570340316050044e0995b98fea87ed41ea77abb28bKen Mixter
258207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter  if (out_of_capacity != NULL) *out_of_capacity = false;
259207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter
2600340316050044e0995b98fea87ed41ea77abb28bKen Mixter  // For testing.
2610340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (forced_crash_directory_ != NULL) {
2620340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *crash_directory = FilePath(forced_crash_directory_);
2630340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return true;
2640340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2650340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2660340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!GetUserInfoFromName(kDefaultUserName,
2670340316050044e0995b98fea87ed41ea77abb28bKen Mixter                           &default_user_id,
2680340316050044e0995b98fea87ed41ea77abb28bKen Mixter                           &default_user_group)) {
269a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Could not find default user info";
2700340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
2710340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2720340316050044e0995b98fea87ed41ea77abb28bKen Mixter  mode_t directory_mode;
2730340316050044e0995b98fea87ed41ea77abb28bKen Mixter  uid_t directory_owner;
2740340316050044e0995b98fea87ed41ea77abb28bKen Mixter  gid_t directory_group;
2750340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *crash_directory =
2760340316050044e0995b98fea87ed41ea77abb28bKen Mixter      GetCrashDirectoryInfo(euid,
2770340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            default_user_id,
2780340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            default_user_group,
2790340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_mode,
2800340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_owner,
2810340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_group);
2820340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2830340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!file_util::PathExists(*crash_directory)) {
2840340316050044e0995b98fea87ed41ea77abb28bKen Mixter    // Create the spool directory with the appropriate mode (regardless of
2850340316050044e0995b98fea87ed41ea77abb28bKen Mixter    // umask) and ownership.
2860340316050044e0995b98fea87ed41ea77abb28bKen Mixter    mode_t old_mask = umask(0);
2870340316050044e0995b98fea87ed41ea77abb28bKen Mixter    if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 ||
2880340316050044e0995b98fea87ed41ea77abb28bKen Mixter        chown(crash_directory->value().c_str(),
2890340316050044e0995b98fea87ed41ea77abb28bKen Mixter              directory_owner,
2900340316050044e0995b98fea87ed41ea77abb28bKen Mixter              directory_group) < 0) {
291a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(ERROR) << "Unable to create appropriate crash directory";
2920340316050044e0995b98fea87ed41ea77abb28bKen Mixter      return false;
2930340316050044e0995b98fea87ed41ea77abb28bKen Mixter    }
2940340316050044e0995b98fea87ed41ea77abb28bKen Mixter    umask(old_mask);
2950340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2960340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2970340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!file_util::PathExists(*crash_directory)) {
298a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Unable to create crash directory "
299a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter               << crash_directory->value().c_str();
3000340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
3010340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
3020340316050044e0995b98fea87ed41ea77abb28bKen Mixter
30304ec10fc93b08057657503559ecf511661b55c9fKen Mixter  if (!CheckHasCapacity(*crash_directory)) {
304207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter    if (out_of_capacity != NULL) *out_of_capacity = true;
30504ec10fc93b08057657503559ecf511661b55c9fKen Mixter    return false;
30604ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
30704ec10fc93b08057657503559ecf511661b55c9fKen Mixter
3080340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
3090340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
31004ec10fc93b08057657503559ecf511661b55c9fKen Mixter
311426fcc0bd579a87102ea50fb570dbf9834fa2962Albert ChaulkFilePath CrashCollector::GetProcessPath(pid_t pid) {
312426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  return FilePath(StringPrintf("/proc/%d", pid));
313426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk}
314426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
315426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulkbool CrashCollector::GetSymlinkTarget(const FilePath &symlink,
316426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                                     FilePath *target) {
317426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  int max_size = 32;
318426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  scoped_array<char> buffer;
319426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  while (true) {
320426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    buffer.reset(new char[max_size + 1]);
321426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size);
322426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    if (size < 0) {
323426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      int saved_errno = errno;
324426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      LOG(ERROR) << "Readlink failed on " << symlink.value() << " with "
325426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                 << saved_errno;
326426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      return false;
327426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    }
328426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    buffer[size] = 0;
329426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    if (size == max_size) {
330426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      // Avoid overflow when doubling.
331426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      if (max_size * 2 > max_size) {
332426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk        max_size *= 2;
333426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk        continue;
334426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      } else {
335426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk        return false;
336426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      }
337426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    }
338426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    break;
339426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  }
340426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
341426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  *target = FilePath(buffer.get());
342426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  return true;
343426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk}
344426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
345426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulkbool CrashCollector::GetExecutableBaseNameFromPid(pid_t pid,
346426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                                                 std::string *base_name) {
347426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  FilePath target;
348426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  FilePath process_path = GetProcessPath(pid);
349426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  FilePath exe_path = process_path.Append("exe");
350426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  if (!GetSymlinkTarget(exe_path, &target)) {
351426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value()
352426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk              << " DirectoryExists: "
353426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk              << file_util::DirectoryExists(process_path);
354426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    // Try to further diagnose exe readlink failure cause.
355426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    struct stat buf;
356426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    int stat_result = stat(exe_path.value().c_str(), &buf);
357426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    int saved_errno = errno;
358426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    if (stat_result < 0) {
359426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result
360426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                << " " << saved_errno;
361426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    } else {
362426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode="
363426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                << buf.st_mode;
364426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    }
365426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    return false;
366426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  }
367426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  *base_name = target.BaseName().value();
368426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  return true;
369426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk}
370426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
37104ec10fc93b08057657503559ecf511661b55c9fKen Mixter// Return true if the given crash directory has not already reached
37204ec10fc93b08057657503559ecf511661b55c9fKen Mixter// maximum capacity.
37304ec10fc93b08057657503559ecf511661b55c9fKen Mixterbool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
37404ec10fc93b08057657503559ecf511661b55c9fKen Mixter  DIR* dir = opendir(crash_directory.value().c_str());
37504ec10fc93b08057657503559ecf511661b55c9fKen Mixter  if (!dir) {
37604ec10fc93b08057657503559ecf511661b55c9fKen Mixter    return false;
37704ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
37804ec10fc93b08057657503559ecf511661b55c9fKen Mixter  struct dirent ent_buf;
37904ec10fc93b08057657503559ecf511661b55c9fKen Mixter  struct dirent* ent;
38004ec10fc93b08057657503559ecf511661b55c9fKen Mixter  bool full = false;
381ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::set<std::string> basenames;
38204ec10fc93b08057657503559ecf511661b55c9fKen Mixter  while (readdir_r(dir, &ent_buf, &ent) == 0 && ent != NULL) {
38304ec10fc93b08057657503559ecf511661b55c9fKen Mixter    if ((strcmp(ent->d_name, ".") == 0) ||
38404ec10fc93b08057657503559ecf511661b55c9fKen Mixter        (strcmp(ent->d_name, "..") == 0))
38504ec10fc93b08057657503559ecf511661b55c9fKen Mixter      continue;
38604ec10fc93b08057657503559ecf511661b55c9fKen Mixter
387ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string filename(ent->d_name);
388ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    size_t last_dot = filename.rfind(".");
389ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string basename;
390ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // If there is a valid looking extension, use the base part of the
391ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // name.  If the only dot is the first byte (aka a dot file), treat
392ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // it as unique to avoid allowing a directory full of dot files
393ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // from accumulating.
394ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (last_dot != std::string::npos && last_dot != 0)
395ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      basename = filename.substr(0, last_dot);
396ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    else
397ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      basename = filename;
398ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    basenames.insert(basename);
39904ec10fc93b08057657503559ecf511661b55c9fKen Mixter
400ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
401a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(WARNING) << "Crash directory " << crash_directory.value()
402a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                   << " already full with " << kMaxCrashDirectorySize
403a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                   << " pending reports";
40404ec10fc93b08057657503559ecf511661b55c9fKen Mixter      full = true;
40504ec10fc93b08057657503559ecf511661b55c9fKen Mixter      break;
40604ec10fc93b08057657503559ecf511661b55c9fKen Mixter    }
40704ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
40804ec10fc93b08057657503559ecf511661b55c9fKen Mixter  closedir(dir);
40904ec10fc93b08057657503559ecf511661b55c9fKen Mixter  return !full;
41004ec10fc93b08057657503559ecf511661b55c9fKen Mixter}
411ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
412c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterbool CrashCollector::IsCommentLine(const std::string &line) {
413c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  size_t found = line.find_first_not_of(" ");
414c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  return found != std::string::npos && line[found] == '#';
415c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter}
416c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
417ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterbool CrashCollector::ReadKeyValueFile(
418ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    const FilePath &path,
419ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    const char separator,
420ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::map<std::string, std::string> *dictionary) {
421ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string contents;
422ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  if (!file_util::ReadFileToString(path, &contents)) {
423ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    return false;
424ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
425ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  typedef std::vector<std::string> StringVector;
426ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  StringVector lines;
4273ba6c5b65778964fe3f643ca9df6a17b41181bf2Chris Masone  base::SplitString(contents, '\n', &lines);
428ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  bool any_errors = false;
429ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  for (StringVector::iterator line = lines.begin(); line != lines.end();
430ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter       ++line) {
431ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // Allow empty strings.
432ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (line->empty())
433ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      continue;
434c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    // Allow comment lines.
435c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    if (IsCommentLine(*line))
436c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter      continue;
437ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    StringVector sides;
4383ba6c5b65778964fe3f643ca9df6a17b41181bf2Chris Masone    base::SplitString(*line, separator, &sides);
439ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (sides.size() != 2) {
440ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      any_errors = true;
441ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      continue;
442ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    }
443ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    dictionary->insert(std::pair<std::string, std::string>(sides[0], sides[1]));
444ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
445ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  return !any_errors;
446ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
447ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
448c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterbool CrashCollector::GetLogContents(const FilePath &config_path,
449c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter                                    const std::string &exec_name,
450c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter                                    const FilePath &output_file) {
451c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  std::map<std::string, std::string> log_commands;
452c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  if (!ReadKeyValueFile(config_path, ':', &log_commands)) {
453a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(INFO) << "Unable to read log configuration file "
454a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter              << config_path.value();
455c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
456c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  }
457c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
458c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  if (log_commands.find(exec_name) == log_commands.end())
459c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
460c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
461a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  chromeos::ProcessImpl diag_process;
462a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.AddArg(kShellPath);
463c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  std::string shell_command = log_commands[exec_name];
464a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.AddStringOption("-c", shell_command);
465a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.RedirectOutput(output_file.value());
466c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
467a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  int result = diag_process.Run();
468a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  if (result != 0) {
469a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(INFO) << "Running shell command " << shell_command << "failed with: "
470a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter              << result;
471c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
472c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  }
473c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  return true;
474c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter}
475c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
476afcf80821c57a189b53b7a66f76d13855d63821eKen Mixtervoid CrashCollector::AddCrashMetaData(const std::string &key,
477afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                      const std::string &value) {
478afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str()));
479afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
480afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
481ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixtervoid CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
482c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                        const std::string &exec_name,
483c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                        const std::string &payload_path) {
484ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::map<std::string, std::string> contents;
485afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  if (!ReadKeyValueFile(FilePath(std::string(lsb_release_)), '=', &contents)) {
486a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Problem parsing " << lsb_release_;
487ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // Even though there was some failure, take as much as we could read.
488ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
489ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string version("unknown");
490ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::map<std::string, std::string>::iterator i;
491ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  if ((i = contents.find("CHROMEOS_RELEASE_VERSION")) != contents.end()) {
492ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    version = i->second;
493ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
494c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter  int64 payload_size = -1;
495c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter  file_util::GetFileSize(FilePath(payload_path), &payload_size);
496afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string meta_data = StringPrintf("%sexec_name=%s\n"
497ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       "ver=%s\n"
498207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                       "payload=%s\n"
49965b4c1efb0bca77f3a73401499adc5c39d982c18Mike Frysinger                                       "payload_size=%"PRId64"\n"
500ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       "done=1\n",
501afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                       extra_metadata_.c_str(),
502ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       exec_name.c_str(),
503c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       version.c_str(),
504207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                       payload_path.c_str(),
505c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       payload_size);
5069b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // We must use WriteNewFile instead of file_util::WriteFile as we
5079b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // do not want to write with root access to a symlink that an attacker
5089b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // might have created.
5099b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) {
510a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Unable to write " << meta_path.value();
511ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
512ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
5131652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le
5141652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Lebool CrashCollector::IsCrashTestInProgress() {
5151652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le  return file_util::PathExists(FilePath(kCrashTestInProgressPath));
5161652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le}
5174fe30db1405498dd21162436eda081486f400fa8Michael Krebs
5184fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::IsDeveloperImage() {
5194fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // If we're testing crash reporter itself, we don't want to special-case
5204fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // for developer images.
5214fe30db1405498dd21162436eda081486f400fa8Michael Krebs  if (IsCrashTestInProgress())
5224fe30db1405498dd21162436eda081486f400fa8Michael Krebs    return false;
5234fe30db1405498dd21162436eda081486f400fa8Michael Krebs  return file_util::PathExists(FilePath(kLeaveCoreFile));
5244fe30db1405498dd21162436eda081486f400fa8Michael Krebs}
5254fe30db1405498dd21162436eda081486f400fa8Michael Krebs
5264fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::ShouldHandleChromeCrashes() {
5274fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // If we're testing crash reporter itself, we don't want to allow an
5284fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // override for chrome crashes.  And, let's be conservative and only
5294fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // allow an override for developer images.
5304fe30db1405498dd21162436eda081486f400fa8Michael Krebs  if (!IsCrashTestInProgress() && IsDeveloperImage()) {
5314fe30db1405498dd21162436eda081486f400fa8Michael Krebs    // Check if there's an override to indicate we should indeed collect
5324fe30db1405498dd21162436eda081486f400fa8Michael Krebs    // chrome crashes.  This allows the crashes to still be tracked when
5334fe30db1405498dd21162436eda081486f400fa8Michael Krebs    // they occur in autotests.  See "crosbug.com/17987".
5344fe30db1405498dd21162436eda081486f400fa8Michael Krebs    if (file_util::PathExists(FilePath(kCollectChromeFile)))
5354fe30db1405498dd21162436eda081486f400fa8Michael Krebs      return true;
5364fe30db1405498dd21162436eda081486f400fa8Michael Krebs  }
5374fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // We default to ignoring chrome crashes.
5384fe30db1405498dd21162436eda081486f400fa8Michael Krebs  return false;
5394fe30db1405498dd21162436eda081486f400fa8Michael Krebs}
5404fe30db1405498dd21162436eda081486f400fa8Michael Krebs
5414fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::IsUserSpecificDirectoryEnabled() {
5424fe30db1405498dd21162436eda081486f400fa8Michael Krebs  return !ShouldHandleChromeCrashes();
5434fe30db1405498dd21162436eda081486f400fa8Michael Krebs}
544