crash_collector.cc revision 731da3379bd7ead7222b1a7add45e307bec7c865
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.
97589aff9f0410512168914bda2d7640649858066Alex Vakulenko#define __STDC_FORMAT_MACROS  // PRId64
107589aff9f0410512168914bda2d7640649858066Alex Vakulenko#include <inttypes.h>
11f3811f50c8783b24607c776844a3cf66c15c439fBen Chan#include <linux/limits.h>  // PATH_MAX
120340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include <pwd.h>  // For struct passwd.
130340316050044e0995b98fea87ed41ea77abb28bKen Mixter#include <sys/types.h>  // for mode_t.
149b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <sys/wait.h>  // For waitpid.
159b346474538a255bc7144ae358bb0ee129163d58Ken Mixter#include <unistd.h>  // For execv and fork.
160340316050044e0995b98fea87ed41ea77abb28bKen Mixter
17ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter#include <set>
187e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <utility>
19f70060c5e610ed0aa648dcb6aaea5d859834b8baSimon Que#include <vector>
20ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
21f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include <dbus/dbus-glib-lowlevel.h>
22f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger#include <glib.h>
23f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
24ab6cc90503ca2db976a3cb9c9382a9da85c4b5a2Ben Chan#include <base/files/file_util.h>
257e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/logging.h>
267e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/posix/eintr_wrapper.h>
277e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/string_split.h>
287e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/string_util.h>
297e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <base/strings/stringprintf.h>
307e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <chromeos/cryptohome.h>
317e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <chromeos/dbus/dbus.h>
327e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <chromeos/dbus/service_constants.h>
33731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat#include <chromeos/key_value_store.h>
347e77690375bc8a896a8de318d69d515e67c7aefeBen Chan#include <chromeos/process.h>
350340316050044e0995b98fea87ed41ea77abb28bKen Mixter
36731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratnamespace {
37731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat
38731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kCollectChromeFile[] =
394fe30db1405498dd21162436eda081486f400fa8Michael Krebs    "/mnt/stateful_partition/etc/collect_chrome_crashes";
40731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kCrashTestInProgressPath[] = "/tmp/crash-test-in-progress";
41731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
42731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kDefaultUserName[] = "chronos";
43731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kLeaveCoreFile[] = "/root/.leave_core";
44731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kLsbRelease[] = "/etc/lsb-release";
45731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kShellPath[] = "/bin/sh";
46731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kSystemCrashPath[] = "/var/spool/crash";
47731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kUploadVarPrefix[] = "upload_var_";
48731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kUploadFilePrefix[] = "upload_file_";
49731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat
50731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat// Key of the lsb-release entry containing the OS version.
51731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kLsbVersionKey[] = "CHROMEOS_RELEASE_VERSION";
52731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat
53f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// Normally this path is not used.  Unfortunately, there are a few edge cases
54f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// where we need this.  Any process that runs as kDefaultUserName that crashes
55f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// is consider a "user crash".  That includes the initial Chrome browser that
56f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// runs the login screen.  If that blows up, there is no logged in user yet,
57f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// so there is no per-user dir for us to stash things in.  Instead we fallback
58f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// to this path as it is at least encrypted on a per-system basis.
59f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger//
60f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// This also comes up when running autotests.  The GUI is sitting at the login
61f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// screen while tests are sshing in, changing users, and triggering crashes as
62f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger// the user (purposefully).
63731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst char kFallbackUserCrashPath[] = "/home/chronos/crash";
640340316050044e0995b98fea87ed41ea77abb28bKen Mixter
650340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the user crash spool directory.
66731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst mode_t kUserCrashPathMode = 0755;
670340316050044e0995b98fea87ed41ea77abb28bKen Mixter
680340316050044e0995b98fea87ed41ea77abb28bKen Mixter// Directory mode of the system crash spool directory.
69731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst mode_t kSystemCrashPathMode = 01755;
70731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat
71731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst uid_t kRootOwner = 0;
72731da3379bd7ead7222b1a7add45e307bec7c865Daniel Eratconst uid_t kRootGroup = 0;
730340316050044e0995b98fea87ed41ea77abb28bKen Mixter
74731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat}  // namespace
750340316050044e0995b98fea87ed41ea77abb28bKen Mixter
76da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// Maximum crash reports per crash spool directory.  Note that this is
77da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// a separate maximum from the maximum rate at which we upload these
78da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// diagnostics.  The higher this rate is, the more space we allow for
79da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// core files, minidumps, and kcrash logs, and equivalently the more
80da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// processor and I/O bandwidth we dedicate to handling these crashes when
81da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// many occur at once.  Also note that if core files are configured to
82da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// be left on the file system, we stop adding crashes when either the
83da5db7a8304e22af6c57733460516857e9211b32Ken Mixter// number of core files or minidumps reaches this number.
84da5db7a8304e22af6c57733460516857e9211b32Ken Mixterconst int CrashCollector::kMaxCrashDirectorySize = 32;
8504ec10fc93b08057657503559ecf511661b55c9fKen Mixter
869f90acaa4d420530d7b4ddd37112518df68e373aSimon Queusing base::FilePath;
87a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysingerusing base::StringPrintf;
889f90acaa4d420530d7b4ddd37112518df68e373aSimon Que
89afcf80821c57a189b53b7a66f76d13855d63821eKen MixterCrashCollector::CrashCollector()
909b1f300139689eb9c7b7a35e91a4fbc1eab93b4eLei Zhang    : lsb_release_(kLsbRelease),
91acc7938ede0e3c07a2d1809f82b174b51f7ab7c5Simon Que      log_config_path_(kDefaultLogConfig) {
920340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
930340316050044e0995b98fea87ed41ea77abb28bKen Mixter
940340316050044e0995b98fea87ed41ea77abb28bKen MixterCrashCollector::~CrashCollector() {
950340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
960340316050044e0995b98fea87ed41ea77abb28bKen Mixter
970340316050044e0995b98fea87ed41ea77abb28bKen Mixtervoid CrashCollector::Initialize(
980340316050044e0995b98fea87ed41ea77abb28bKen Mixter    CrashCollector::CountCrashFunction count_crash_function,
99a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) {
100262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  CHECK(count_crash_function);
101262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  CHECK(is_feedback_allowed_function);
1020340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1030340316050044e0995b98fea87ed41ea77abb28bKen Mixter  count_crash_function_ = count_crash_function;
1040340316050044e0995b98fea87ed41ea77abb28bKen Mixter  is_feedback_allowed_function_ = is_feedback_allowed_function;
1050340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1060340316050044e0995b98fea87ed41ea77abb28bKen Mixter
1079b346474538a255bc7144ae358bb0ee129163d58Ken Mixterint CrashCollector::WriteNewFile(const FilePath &filename,
1089b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                                 const char *data,
1099b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                                 int size) {
1109b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  int fd = HANDLE_EINTR(open(filename.value().c_str(),
1119b346474538a255bc7144ae358bb0ee129163d58Ken Mixter                             O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
1129b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  if (fd < 0) {
1139b346474538a255bc7144ae358bb0ee129163d58Ken Mixter    return -1;
1149b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  }
1159b346474538a255bc7144ae358bb0ee129163d58Ken Mixter
116859ee45cd2d9feb5e937c0c06f9e6c230979136eAlex Vakulenko  int rv = base::WriteFileDescriptor(fd, data, size) ? size : -1;
117f1a5014637180457af21cc40a5ca64ab18a6947bMike Frysinger  IGNORE_EINTR(close(fd));
1189b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  return rv;
1199b346474538a255bc7144ae358bb0ee129163d58Ken Mixter}
1209b346474538a255bc7144ae358bb0ee129163d58Ken Mixter
121ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixterstd::string CrashCollector::Sanitize(const std::string &name) {
1229895096f8b8046456bec96292f9c547b11913248Thiemo Nagel  // Make sure the sanitized name does not include any periods.
1239895096f8b8046456bec96292f9c547b11913248Thiemo Nagel  // The logic in crash_sender relies on this.
124ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string result = name;
125ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  for (size_t i = 0; i < name.size(); ++i) {
126ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (!isalnum(result[i]) && result[i] != '_')
127ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      result[i] = '_';
128ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
129ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  return result;
130ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
131ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
1320340316050044e0995b98fea87ed41ea77abb28bKen Mixterstd::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
1330340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                               time_t timestamp,
1340340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                               pid_t pid) {
1350340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct tm tm;
1360340316050044e0995b98fea87ed41ea77abb28bKen Mixter  localtime_r(&timestamp, &tm);
137ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string sanitized_exec_name = Sanitize(exec_name);
1380340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d",
139ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                      sanitized_exec_name.c_str(),
1400340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_year + 1900,
1410340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_mon + 1,
1420340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_mday,
1430340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_hour,
1440340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_min,
1450340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      tm.tm_sec,
1460340316050044e0995b98fea87ed41ea77abb28bKen Mixter                      pid);
1470340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
1480340316050044e0995b98fea87ed41ea77abb28bKen Mixter
149207694d3f491ef602a859c30cc1379584f2d61cfKen MixterFilePath CrashCollector::GetCrashPath(const FilePath &crash_directory,
150207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                      const std::string &basename,
151207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                      const std::string &extension) {
152207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter  return crash_directory.Append(StringPrintf("%s.%s",
153207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                             basename.c_str(),
154207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                             extension.c_str()));
155207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter}
156207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter
157f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysingernamespace {
158f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
159f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysingerconst char *GetGErrorMessage(const GError *error) {
160f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!error)
161f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return "Unknown error.";
162f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  return error->message;
163f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
164f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
165f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
166f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
167efec0b3625f447995d2ed79b946d2929039313c9Ben ChanGHashTable *CrashCollector::GetActiveUserSessions() {
168262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  GHashTable *active_sessions = nullptr;
169f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
170f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
171f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!dbus.HasConnection()) {
172f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    LOG(ERROR) << "Error connecting to system D-Bus";
173f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return active_sessions;
174f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
175f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  chromeos::dbus::Proxy proxy(dbus,
176f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                              login_manager::kSessionManagerServiceName,
177f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                              login_manager::kSessionManagerServicePath,
178f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                              login_manager::kSessionManagerInterface);
179f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!proxy) {
180f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    LOG(ERROR) << "Error creating D-Bus proxy to interface "
181f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << "'" << login_manager::kSessionManagerServiceName << "'";
182f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return active_sessions;
183f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
184f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
185f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // Request all the active sessions.
186262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  GError *gerror = nullptr;
187f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!dbus_g_proxy_call(proxy.gproxy(),
188f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         login_manager::kSessionManagerRetrieveActiveSessions,
189f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         &gerror, G_TYPE_INVALID,
190f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         DBUS_TYPE_G_STRING_STRING_HASHTABLE, &active_sessions,
191f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger                         G_TYPE_INVALID)) {
192f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    LOG(ERROR) << "Error performing D-Bus proxy call "
193f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << "'"
194f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << login_manager::kSessionManagerRetrieveActiveSessions << "'"
195f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger               << ": " << GetGErrorMessage(gerror);
196f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return active_sessions;
197f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
198f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
199f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  return active_sessions;
200f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
201f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
202efec0b3625f447995d2ed79b946d2929039313c9Ben ChanFilePath CrashCollector::GetUserCrashPath() {
203f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // In this multiprofile world, there is no one-specific user dir anymore.
204f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // Ask the session manager for the active ones, then just run with the
205f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  // first result we get back.
206f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  FilePath user_path = FilePath(kFallbackUserCrashPath);
207f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  GHashTable *active_sessions = GetActiveUserSessions();
208f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (!active_sessions)
209f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return user_path;
210f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
211f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  GList *list = g_hash_table_get_values(active_sessions);
212f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  if (list) {
213f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    const char *salted_path = static_cast<const char *>(list->data);
21437843a9f8a46cd5afa57505bdb6d75aa1a75c9d2Mike Frysinger    user_path = chromeos::cryptohome::home::GetHashedUserPath(salted_path)
21537843a9f8a46cd5afa57505bdb6d75aa1a75c9d2Mike Frysinger        .Append("crash");
216f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    g_list_free(list);
217f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  }
218f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
219f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  g_hash_table_destroy(active_sessions);
220f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
221f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger  return user_path;
222f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger}
223f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger
2240340316050044e0995b98fea87ed41ea77abb28bKen MixterFilePath CrashCollector::GetCrashDirectoryInfo(
2250340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t process_euid,
2260340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t default_user_id,
2270340316050044e0995b98fea87ed41ea77abb28bKen Mixter    gid_t default_user_group,
2280340316050044e0995b98fea87ed41ea77abb28bKen Mixter    mode_t *mode,
2290340316050044e0995b98fea87ed41ea77abb28bKen Mixter    uid_t *directory_owner,
2300340316050044e0995b98fea87ed41ea77abb28bKen Mixter    gid_t *directory_group) {
2314fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // TODO(mkrebs): This can go away once Chrome crashes are handled
2324fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // normally (see crosbug.com/5872).
2334fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // Check if the user crash directory should be used.  If we are
2344fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // collecting chrome crashes during autotesting, we want to put them in
2354fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // the system crash directory so they are outside the cryptohome -- in
2364fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // case we are being run during logout (see crosbug.com/18637).
2374fe30db1405498dd21162436eda081486f400fa8Michael Krebs  if (process_euid == default_user_id && IsUserSpecificDirectoryEnabled()) {
2380340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *mode = kUserCrashPathMode;
2390340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_owner = default_user_id;
2400340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_group = default_user_group;
241f19b518532cb2ab8fc1ed77381809f24a30ac4caMike Frysinger    return GetUserCrashPath();
2420340316050044e0995b98fea87ed41ea77abb28bKen Mixter  } else {
2430340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *mode = kSystemCrashPathMode;
2440340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_owner = kRootOwner;
2450340316050044e0995b98fea87ed41ea77abb28bKen Mixter    *directory_group = kRootGroup;
2460340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return FilePath(kSystemCrashPath);
2470340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2480340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
2490340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2500340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetUserInfoFromName(const std::string &name,
2510340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                         uid_t *uid,
2520340316050044e0995b98fea87ed41ea77abb28bKen Mixter                                         gid_t *gid) {
2530340316050044e0995b98fea87ed41ea77abb28bKen Mixter  char storage[256];
2540340316050044e0995b98fea87ed41ea77abb28bKen Mixter  struct passwd passwd_storage;
255262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  struct passwd *passwd_result = nullptr;
2560340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2570340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage),
258262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan                 &passwd_result) != 0 || passwd_result == nullptr) {
259a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Cannot find user named " << name;
2600340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
2610340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2620340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2630340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *uid = passwd_result->pw_uid;
2640340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *gid = passwd_result->pw_gid;
2650340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
2660340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
2670340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2680340316050044e0995b98fea87ed41ea77abb28bKen Mixterbool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
269207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                                    FilePath *crash_directory,
270207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                                    bool *out_of_capacity) {
2710340316050044e0995b98fea87ed41ea77abb28bKen Mixter  uid_t default_user_id;
2720340316050044e0995b98fea87ed41ea77abb28bKen Mixter  gid_t default_user_group;
2730340316050044e0995b98fea87ed41ea77abb28bKen Mixter
274262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  if (out_of_capacity) *out_of_capacity = false;
275207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter
2760340316050044e0995b98fea87ed41ea77abb28bKen Mixter  // For testing.
2779b1f300139689eb9c7b7a35e91a4fbc1eab93b4eLei Zhang  if (!forced_crash_directory_.empty()) {
2789b1f300139689eb9c7b7a35e91a4fbc1eab93b4eLei Zhang    *crash_directory = forced_crash_directory_;
2790340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return true;
2800340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2810340316050044e0995b98fea87ed41ea77abb28bKen Mixter
2820340316050044e0995b98fea87ed41ea77abb28bKen Mixter  if (!GetUserInfoFromName(kDefaultUserName,
2830340316050044e0995b98fea87ed41ea77abb28bKen Mixter                           &default_user_id,
2840340316050044e0995b98fea87ed41ea77abb28bKen Mixter                           &default_user_group)) {
285a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Could not find default user info";
2860340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
2870340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
2880340316050044e0995b98fea87ed41ea77abb28bKen Mixter  mode_t directory_mode;
2890340316050044e0995b98fea87ed41ea77abb28bKen Mixter  uid_t directory_owner;
2900340316050044e0995b98fea87ed41ea77abb28bKen Mixter  gid_t directory_group;
2910340316050044e0995b98fea87ed41ea77abb28bKen Mixter  *crash_directory =
2920340316050044e0995b98fea87ed41ea77abb28bKen Mixter      GetCrashDirectoryInfo(euid,
2930340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            default_user_id,
2940340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            default_user_group,
2950340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_mode,
2960340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_owner,
2970340316050044e0995b98fea87ed41ea77abb28bKen Mixter                            &directory_group);
2980340316050044e0995b98fea87ed41ea77abb28bKen Mixter
299a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger  if (!base::PathExists(*crash_directory)) {
3000340316050044e0995b98fea87ed41ea77abb28bKen Mixter    // Create the spool directory with the appropriate mode (regardless of
3010340316050044e0995b98fea87ed41ea77abb28bKen Mixter    // umask) and ownership.
3020340316050044e0995b98fea87ed41ea77abb28bKen Mixter    mode_t old_mask = umask(0);
3030340316050044e0995b98fea87ed41ea77abb28bKen Mixter    if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 ||
3040340316050044e0995b98fea87ed41ea77abb28bKen Mixter        chown(crash_directory->value().c_str(),
3050340316050044e0995b98fea87ed41ea77abb28bKen Mixter              directory_owner,
3060340316050044e0995b98fea87ed41ea77abb28bKen Mixter              directory_group) < 0) {
307a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(ERROR) << "Unable to create appropriate crash directory";
3080340316050044e0995b98fea87ed41ea77abb28bKen Mixter      return false;
3090340316050044e0995b98fea87ed41ea77abb28bKen Mixter    }
3100340316050044e0995b98fea87ed41ea77abb28bKen Mixter    umask(old_mask);
3110340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
3120340316050044e0995b98fea87ed41ea77abb28bKen Mixter
313a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger  if (!base::PathExists(*crash_directory)) {
314a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Unable to create crash directory "
315a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter               << crash_directory->value().c_str();
3160340316050044e0995b98fea87ed41ea77abb28bKen Mixter    return false;
3170340316050044e0995b98fea87ed41ea77abb28bKen Mixter  }
3180340316050044e0995b98fea87ed41ea77abb28bKen Mixter
31904ec10fc93b08057657503559ecf511661b55c9fKen Mixter  if (!CheckHasCapacity(*crash_directory)) {
320262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan    if (out_of_capacity) *out_of_capacity = true;
32104ec10fc93b08057657503559ecf511661b55c9fKen Mixter    return false;
32204ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
32304ec10fc93b08057657503559ecf511661b55c9fKen Mixter
3240340316050044e0995b98fea87ed41ea77abb28bKen Mixter  return true;
3250340316050044e0995b98fea87ed41ea77abb28bKen Mixter}
32604ec10fc93b08057657503559ecf511661b55c9fKen Mixter
327426fcc0bd579a87102ea50fb570dbf9834fa2962Albert ChaulkFilePath CrashCollector::GetProcessPath(pid_t pid) {
328426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  return FilePath(StringPrintf("/proc/%d", pid));
329426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk}
330426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
331426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulkbool CrashCollector::GetSymlinkTarget(const FilePath &symlink,
3328563d20e108c3801f107d640c9b161f1099e6bebBen Chan                                      FilePath *target) {
333f3811f50c8783b24607c776844a3cf66c15c439fBen Chan  ssize_t max_size = 64;
334f3811f50c8783b24607c776844a3cf66c15c439fBen Chan  std::vector<char> buffer;
335f3811f50c8783b24607c776844a3cf66c15c439fBen Chan
336426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  while (true) {
337f3811f50c8783b24607c776844a3cf66c15c439fBen Chan    buffer.resize(max_size + 1);
338f3811f50c8783b24607c776844a3cf66c15c439fBen Chan    ssize_t size = readlink(symlink.value().c_str(), buffer.data(), max_size);
339426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    if (size < 0) {
340426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      int saved_errno = errno;
341426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      LOG(ERROR) << "Readlink failed on " << symlink.value() << " with "
342426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                 << saved_errno;
343426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      return false;
344426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    }
345f3811f50c8783b24607c776844a3cf66c15c439fBen Chan
346426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    buffer[size] = 0;
347426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    if (size == max_size) {
348f3811f50c8783b24607c776844a3cf66c15c439fBen Chan      max_size *= 2;
349f3811f50c8783b24607c776844a3cf66c15c439fBen Chan      if (max_size > PATH_MAX) {
350426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk        return false;
351426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      }
352f3811f50c8783b24607c776844a3cf66c15c439fBen Chan      continue;
353426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    }
354426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    break;
355426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  }
356426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
357f3811f50c8783b24607c776844a3cf66c15c439fBen Chan  *target = FilePath(buffer.data());
358426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  return true;
359426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk}
360426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
361426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulkbool CrashCollector::GetExecutableBaseNameFromPid(pid_t pid,
362426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                                                 std::string *base_name) {
363426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  FilePath target;
364426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  FilePath process_path = GetProcessPath(pid);
365426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  FilePath exe_path = process_path.Append("exe");
366426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  if (!GetSymlinkTarget(exe_path, &target)) {
367426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value()
368426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk              << " DirectoryExists: "
369a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger              << base::DirectoryExists(process_path);
370426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    // Try to further diagnose exe readlink failure cause.
371426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    struct stat buf;
372426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    int stat_result = stat(exe_path.value().c_str(), &buf);
373426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    int saved_errno = errno;
374426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    if (stat_result < 0) {
375426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result
376426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                << " " << saved_errno;
377426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    } else {
378426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk      LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode="
379426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk                << buf.st_mode;
380426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    }
381426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk    return false;
382426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  }
383426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  *base_name = target.BaseName().value();
384426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk  return true;
385426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk}
386426fcc0bd579a87102ea50fb570dbf9834fa2962Albert Chaulk
38704ec10fc93b08057657503559ecf511661b55c9fKen Mixter// Return true if the given crash directory has not already reached
38804ec10fc93b08057657503559ecf511661b55c9fKen Mixter// maximum capacity.
38904ec10fc93b08057657503559ecf511661b55c9fKen Mixterbool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
39004ec10fc93b08057657503559ecf511661b55c9fKen Mixter  DIR* dir = opendir(crash_directory.value().c_str());
39104ec10fc93b08057657503559ecf511661b55c9fKen Mixter  if (!dir) {
39204ec10fc93b08057657503559ecf511661b55c9fKen Mixter    return false;
39304ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
39404ec10fc93b08057657503559ecf511661b55c9fKen Mixter  struct dirent ent_buf;
39504ec10fc93b08057657503559ecf511661b55c9fKen Mixter  struct dirent* ent;
39604ec10fc93b08057657503559ecf511661b55c9fKen Mixter  bool full = false;
397ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::set<std::string> basenames;
398262d798b380a59ef691ede4c6a32aa71ff191295Ben Chan  while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
39904ec10fc93b08057657503559ecf511661b55c9fKen Mixter    if ((strcmp(ent->d_name, ".") == 0) ||
40004ec10fc93b08057657503559ecf511661b55c9fKen Mixter        (strcmp(ent->d_name, "..") == 0))
40104ec10fc93b08057657503559ecf511661b55c9fKen Mixter      continue;
40204ec10fc93b08057657503559ecf511661b55c9fKen Mixter
403ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string filename(ent->d_name);
404ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    size_t last_dot = filename.rfind(".");
405ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    std::string basename;
406ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // If there is a valid looking extension, use the base part of the
407ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // name.  If the only dot is the first byte (aka a dot file), treat
408ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // it as unique to avoid allowing a directory full of dot files
409ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // from accumulating.
410ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (last_dot != std::string::npos && last_dot != 0)
411ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      basename = filename.substr(0, last_dot);
412ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    else
413ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter      basename = filename;
414ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    basenames.insert(basename);
41504ec10fc93b08057657503559ecf511661b55c9fKen Mixter
416ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
417a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter      LOG(WARNING) << "Crash directory " << crash_directory.value()
418a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                   << " already full with " << kMaxCrashDirectorySize
419a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter                   << " pending reports";
42004ec10fc93b08057657503559ecf511661b55c9fKen Mixter      full = true;
42104ec10fc93b08057657503559ecf511661b55c9fKen Mixter      break;
42204ec10fc93b08057657503559ecf511661b55c9fKen Mixter    }
42304ec10fc93b08057657503559ecf511661b55c9fKen Mixter  }
42404ec10fc93b08057657503559ecf511661b55c9fKen Mixter  closedir(dir);
42504ec10fc93b08057657503559ecf511661b55c9fKen Mixter  return !full;
42604ec10fc93b08057657503559ecf511661b55c9fKen Mixter}
427ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter
428c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixterbool CrashCollector::GetLogContents(const FilePath &config_path,
429c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter                                    const std::string &exec_name,
430c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter                                    const FilePath &output_file) {
431731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  chromeos::KeyValueStore store;
432731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  if (!store.Load(config_path)) {
433a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(INFO) << "Unable to read log configuration file "
434a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter              << config_path.value();
435c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
436c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  }
437c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
438731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  std::string command;
439731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  if (!store.GetString(exec_name, &command))
440c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
441c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
442a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  chromeos::ProcessImpl diag_process;
443a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.AddArg(kShellPath);
444731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  diag_process.AddStringOption("-c", command);
445a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  diag_process.RedirectOutput(output_file.value());
446c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
447731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  const int result = diag_process.Run();
448a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter  if (result != 0) {
449731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat    LOG(INFO) << "Log command \"" << command << "\" exited with " << result;
450c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter    return false;
451c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  }
452c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter  return true;
453c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter}
454c49dbd4775986f32b2f09659595f9f28ef7f6b44Ken Mixter
455afcf80821c57a189b53b7a66f76d13855d63821eKen Mixtervoid CrashCollector::AddCrashMetaData(const std::string &key,
456afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                      const std::string &value) {
457afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str()));
458afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter}
459afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter
46033dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulkvoid CrashCollector::AddCrashMetaUploadFile(const std::string &key,
46133dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk                                            const std::string &path) {
46233dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk  if (!path.empty())
46333dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk    AddCrashMetaData(kUploadFilePrefix + key, path);
46433dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk}
46533dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk
46633dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulkvoid CrashCollector::AddCrashMetaUploadData(const std::string &key,
46733dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk                                            const std::string &value) {
46833dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk  if (!value.empty())
46933dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk    AddCrashMetaData(kUploadVarPrefix + key, value);
47033dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk}
47133dfd47146c14bbdf57494051fe1c1c50949305fAlbert Chaulk
472ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixtervoid CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
473c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                        const std::string &exec_name,
474c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                        const std::string &payload_path) {
475731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  chromeos::KeyValueStore store;
476731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  if (!store.Load(FilePath(lsb_release_))) {
477a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Problem parsing " << lsb_release_;
478ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter    // Even though there was some failure, take as much as we could read.
479ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
480731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat
481ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  std::string version("unknown");
482731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat  if (!store.GetString(kLsbVersionKey, &version)) {
483731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat    LOG(ERROR) << "Unable to read " << kLsbVersionKey << " from "
484731da3379bd7ead7222b1a7add45e307bec7c865Daniel Erat               << lsb_release_;
485ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
486f84ea21aab3c1c6ef1f358534e5c437878675d74Ben Chan  int64_t payload_size = -1;
487a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger  base::GetFileSize(FilePath(payload_path), &payload_size);
488afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter  std::string meta_data = StringPrintf("%sexec_name=%s\n"
489ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       "ver=%s\n"
490207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                       "payload=%s\n"
491eaf060c265f4cd84eb718b625b3670987e155a1bAlex Vakulenko                                       "payload_size=%" PRId64 "\n"
492ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       "done=1\n",
493afcf80821c57a189b53b7a66f76d13855d63821eKen Mixter                                       extra_metadata_.c_str(),
494ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter                                       exec_name.c_str(),
495c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       version.c_str(),
496207694d3f491ef602a859c30cc1379584f2d61cfKen Mixter                                       payload_path.c_str(),
497c909b6944602bd6c1eb6d3c54ec41b1a4fc57b07Ken Mixter                                       payload_size);
498f30c641225e55055641ffe3fd679a96e44f34af6Ben Chan  // We must use WriteNewFile instead of base::WriteFile as we
4999b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // do not want to write with root access to a symlink that an attacker
5009b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  // might have created.
5019b346474538a255bc7144ae358bb0ee129163d58Ken Mixter  if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) {
502a324932e066ccb7ed9d62db9c409ee2c10052554Ken Mixter    LOG(ERROR) << "Unable to write " << meta_path.value();
503ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter  }
504ee849c5ef4c416cb0321483fa10c92f8aada3179Ken Mixter}
5051652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le
5061652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Lebool CrashCollector::IsCrashTestInProgress() {
507a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger  return base::PathExists(FilePath(kCrashTestInProgressPath));
5081652fb2cc2bc6d08ac3719fd3d90b43485d539feThieu Le}
5094fe30db1405498dd21162436eda081486f400fa8Michael Krebs
5104fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::IsDeveloperImage() {
5114fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // If we're testing crash reporter itself, we don't want to special-case
5124fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // for developer images.
5134fe30db1405498dd21162436eda081486f400fa8Michael Krebs  if (IsCrashTestInProgress())
5144fe30db1405498dd21162436eda081486f400fa8Michael Krebs    return false;
515a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger  return base::PathExists(FilePath(kLeaveCoreFile));
5164fe30db1405498dd21162436eda081486f400fa8Michael Krebs}
5174fe30db1405498dd21162436eda081486f400fa8Michael Krebs
5184fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::ShouldHandleChromeCrashes() {
5194fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // If we're testing crash reporter itself, we don't want to allow an
5204fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // override for chrome crashes.  And, let's be conservative and only
5214fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // allow an override for developer images.
5224fe30db1405498dd21162436eda081486f400fa8Michael Krebs  if (!IsCrashTestInProgress() && IsDeveloperImage()) {
5234fe30db1405498dd21162436eda081486f400fa8Michael Krebs    // Check if there's an override to indicate we should indeed collect
5244fe30db1405498dd21162436eda081486f400fa8Michael Krebs    // chrome crashes.  This allows the crashes to still be tracked when
5254fe30db1405498dd21162436eda081486f400fa8Michael Krebs    // they occur in autotests.  See "crosbug.com/17987".
526a557c1187ff19d422db2a9c951ecd8f7243e79bdMike Frysinger    if (base::PathExists(FilePath(kCollectChromeFile)))
5274fe30db1405498dd21162436eda081486f400fa8Michael Krebs      return true;
5284fe30db1405498dd21162436eda081486f400fa8Michael Krebs  }
5294fe30db1405498dd21162436eda081486f400fa8Michael Krebs  // We default to ignoring chrome crashes.
5304fe30db1405498dd21162436eda081486f400fa8Michael Krebs  return false;
5314fe30db1405498dd21162436eda081486f400fa8Michael Krebs}
5324fe30db1405498dd21162436eda081486f400fa8Michael Krebs
5334fe30db1405498dd21162436eda081486f400fa8Michael Krebsbool CrashCollector::IsUserSpecificDirectoryEnabled() {
5344fe30db1405498dd21162436eda081486f400fa8Michael Krebs  return !ShouldHandleChromeCrashes();
5354fe30db1405498dd21162436eda081486f400fa8Michael Krebs}
536