blob: d993576eb6848dd214a45c7fc9a77b204e43d53e [file] [log] [blame]
Steve Fung6c34c252015-08-20 00:27:30 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Ken Mixter03403162010-08-18 15:23:16 -070016
Steve Fung129bea52015-07-23 13:11:15 -070017#include "crash_collector.h"
Ken Mixter03403162010-08-18 15:23:16 -070018
Ken Mixter04ec10f2010-08-26 16:02:02 -070019#include <dirent.h>
Ken Mixter9b346472010-11-07 13:45:45 -080020#include <fcntl.h> // For file creation modes.
Alex Vakulenko7589aff2014-07-30 10:07:35 -070021#include <inttypes.h>
Ben Chanf3811f52014-08-26 06:46:38 -070022#include <linux/limits.h> // PATH_MAX
Ken Mixter03403162010-08-18 15:23:16 -070023#include <pwd.h> // For struct passwd.
24#include <sys/types.h> // for mode_t.
Ken Mixter9b346472010-11-07 13:45:45 -080025#include <sys/wait.h> // For waitpid.
26#include <unistd.h> // For execv and fork.
Ken Mixter03403162010-08-18 15:23:16 -070027
Ken Mixteree849c52010-09-30 15:30:10 -070028#include <set>
Ben Chan7e776902014-06-18 13:19:51 -070029#include <utility>
Simon Quef70060c2012-04-09 19:07:07 -070030#include <vector>
Ken Mixteree849c52010-09-30 15:30:10 -070031
Ben Chanab6cc902014-09-05 08:21:06 -070032#include <base/files/file_util.h>
Ben Chan7e776902014-06-18 13:19:51 -070033#include <base/logging.h>
34#include <base/posix/eintr_wrapper.h>
35#include <base/strings/string_split.h>
36#include <base/strings/string_util.h>
37#include <base/strings/stringprintf.h>
Alex Vakulenko74dc6242015-10-13 09:23:34 -070038#include <brillo/key_value_store.h>
Steve Fungb3a48e12016-02-25 03:37:33 -080039#include <brillo/osrelease_reader.h>
Alex Vakulenko74dc6242015-10-13 09:23:34 -070040#include <brillo/process.h>
Ken Mixter03403162010-08-18 15:23:16 -070041
Daniel Erat731da332015-01-28 09:48:10 -070042namespace {
43
44const char kCollectChromeFile[] =
Michael Krebs4fe30db2011-08-05 13:54:52 -070045 "/mnt/stateful_partition/etc/collect_chrome_crashes";
Steve Fung0e8746d2015-08-20 17:07:50 -070046const char kCrashTestInProgressPath[] =
47 "/data/misc/crash_reporter/tmp/crash-test-in-progress";
Daniel Erat731da332015-01-28 09:48:10 -070048const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
49const char kDefaultUserName[] = "chronos";
Steve Fung0e8746d2015-08-20 17:07:50 -070050const char kLeaveCoreFile[] = "/data/misc/crash_reporter/.leave_core";
Steve Fung0e8746d2015-08-20 17:07:50 -070051const char kShellPath[] = "/system/bin/sh";
Steve Fungab2ac7d2015-08-14 17:58:05 -070052const char kSystemCrashPath[] = "/data/misc/crash_reporter/crash";
Daniel Erat731da332015-01-28 09:48:10 -070053const char kUploadVarPrefix[] = "upload_var_";
54const char kUploadFilePrefix[] = "upload_file_";
55
Steve Fungb3a48e12016-02-25 03:37:33 -080056// Product information keys in the /etc/os-release.d folder.
57static const char kBdkVersionKey[] = "bdk_version";
58static const char kProductIDKey[] = "product_id";
59static const char kProductVersionKey[] = "product_version";
60
Mike Frysingerf19b5182013-05-17 19:36:47 -040061// Normally this path is not used. Unfortunately, there are a few edge cases
62// where we need this. Any process that runs as kDefaultUserName that crashes
63// is consider a "user crash". That includes the initial Chrome browser that
64// runs the login screen. If that blows up, there is no logged in user yet,
65// so there is no per-user dir for us to stash things in. Instead we fallback
66// to this path as it is at least encrypted on a per-system basis.
67//
68// This also comes up when running autotests. The GUI is sitting at the login
69// screen while tests are sshing in, changing users, and triggering crashes as
70// the user (purposefully).
Daniel Erat731da332015-01-28 09:48:10 -070071const char kFallbackUserCrashPath[] = "/home/chronos/crash";
Ken Mixter03403162010-08-18 15:23:16 -070072
73// Directory mode of the user crash spool directory.
Daniel Erat731da332015-01-28 09:48:10 -070074const mode_t kUserCrashPathMode = 0755;
Ken Mixter03403162010-08-18 15:23:16 -070075
76// Directory mode of the system crash spool directory.
Daniel Erat731da332015-01-28 09:48:10 -070077const mode_t kSystemCrashPathMode = 01755;
Ken Mixter03403162010-08-18 15:23:16 -070078
Daniel Erat731da332015-01-28 09:48:10 -070079const uid_t kRootOwner = 0;
80const uid_t kRootGroup = 0;
81
82} // namespace
Ken Mixter03403162010-08-18 15:23:16 -070083
Ken Mixterda5db7a2010-09-17 13:50:42 -070084// Maximum crash reports per crash spool directory. Note that this is
85// a separate maximum from the maximum rate at which we upload these
86// diagnostics. The higher this rate is, the more space we allow for
87// core files, minidumps, and kcrash logs, and equivalently the more
88// processor and I/O bandwidth we dedicate to handling these crashes when
89// many occur at once. Also note that if core files are configured to
90// be left on the file system, we stop adding crashes when either the
91// number of core files or minidumps reaches this number.
92const int CrashCollector::kMaxCrashDirectorySize = 32;
Ken Mixter04ec10f2010-08-26 16:02:02 -070093
Simon Que9f90aca2013-02-19 17:19:52 -080094using base::FilePath;
Mike Frysingera557c112014-02-05 22:55:39 -050095using base::StringPrintf;
Simon Que9f90aca2013-02-19 17:19:52 -080096
Ken Mixterafcf8082010-10-26 14:45:01 -070097CrashCollector::CrashCollector()
Steve Fung8ed101b2015-12-02 16:18:07 -080098 : log_config_path_(kDefaultLogConfig) {
Ken Mixter03403162010-08-18 15:23:16 -070099}
100
101CrashCollector::~CrashCollector() {
102}
103
104void CrashCollector::Initialize(
105 CrashCollector::CountCrashFunction count_crash_function,
Ken Mixtera3249322011-03-03 08:47:38 -0800106 CrashCollector::IsFeedbackAllowedFunction is_feedback_allowed_function) {
Ben Chan262d7982014-09-18 08:05:20 -0700107 CHECK(count_crash_function);
108 CHECK(is_feedback_allowed_function);
Ken Mixter03403162010-08-18 15:23:16 -0700109
110 count_crash_function_ = count_crash_function;
111 is_feedback_allowed_function_ = is_feedback_allowed_function;
Ken Mixter03403162010-08-18 15:23:16 -0700112}
113
Ken Mixter9b346472010-11-07 13:45:45 -0800114int CrashCollector::WriteNewFile(const FilePath &filename,
115 const char *data,
116 int size) {
117 int fd = HANDLE_EINTR(open(filename.value().c_str(),
118 O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666));
119 if (fd < 0) {
120 return -1;
121 }
122
Alex Vakulenko859ee452014-12-10 12:52:31 -0800123 int rv = base::WriteFileDescriptor(fd, data, size) ? size : -1;
Mike Frysingerf1a50142014-05-14 16:05:09 -0400124 IGNORE_EINTR(close(fd));
Ken Mixter9b346472010-11-07 13:45:45 -0800125 return rv;
126}
127
Ken Mixteree849c52010-09-30 15:30:10 -0700128std::string CrashCollector::Sanitize(const std::string &name) {
Thiemo Nagel98950962014-05-13 19:48:32 +0200129 // Make sure the sanitized name does not include any periods.
130 // The logic in crash_sender relies on this.
Ken Mixteree849c52010-09-30 15:30:10 -0700131 std::string result = name;
132 for (size_t i = 0; i < name.size(); ++i) {
133 if (!isalnum(result[i]) && result[i] != '_')
134 result[i] = '_';
135 }
136 return result;
137}
138
Ken Mixter03403162010-08-18 15:23:16 -0700139std::string CrashCollector::FormatDumpBasename(const std::string &exec_name,
140 time_t timestamp,
141 pid_t pid) {
142 struct tm tm;
143 localtime_r(&timestamp, &tm);
Ken Mixteree849c52010-09-30 15:30:10 -0700144 std::string sanitized_exec_name = Sanitize(exec_name);
Ken Mixter03403162010-08-18 15:23:16 -0700145 return StringPrintf("%s.%04d%02d%02d.%02d%02d%02d.%d",
Ken Mixteree849c52010-09-30 15:30:10 -0700146 sanitized_exec_name.c_str(),
Ken Mixter03403162010-08-18 15:23:16 -0700147 tm.tm_year + 1900,
148 tm.tm_mon + 1,
149 tm.tm_mday,
150 tm.tm_hour,
151 tm.tm_min,
152 tm.tm_sec,
153 pid);
154}
155
Ken Mixter207694d2010-10-28 15:42:37 -0700156FilePath CrashCollector::GetCrashPath(const FilePath &crash_directory,
157 const std::string &basename,
158 const std::string &extension) {
159 return crash_directory.Append(StringPrintf("%s.%s",
160 basename.c_str(),
161 extension.c_str()));
162}
163
Ken Mixter03403162010-08-18 15:23:16 -0700164FilePath CrashCollector::GetCrashDirectoryInfo(
Ken Mixter03403162010-08-18 15:23:16 -0700165 mode_t *mode,
166 uid_t *directory_owner,
167 gid_t *directory_group) {
Steve Fungab2ac7d2015-08-14 17:58:05 -0700168 *mode = kSystemCrashPathMode;
169 *directory_owner = kRootOwner;
170 *directory_group = kRootGroup;
171 return FilePath(kSystemCrashPath);
Ken Mixter03403162010-08-18 15:23:16 -0700172}
173
174bool CrashCollector::GetUserInfoFromName(const std::string &name,
175 uid_t *uid,
176 gid_t *gid) {
177 char storage[256];
178 struct passwd passwd_storage;
Ben Chan262d7982014-09-18 08:05:20 -0700179 struct passwd *passwd_result = nullptr;
Ken Mixter03403162010-08-18 15:23:16 -0700180
181 if (getpwnam_r(name.c_str(), &passwd_storage, storage, sizeof(storage),
Ben Chan262d7982014-09-18 08:05:20 -0700182 &passwd_result) != 0 || passwd_result == nullptr) {
Ken Mixtera3249322011-03-03 08:47:38 -0800183 LOG(ERROR) << "Cannot find user named " << name;
Ken Mixter03403162010-08-18 15:23:16 -0700184 return false;
185 }
186
187 *uid = passwd_result->pw_uid;
188 *gid = passwd_result->pw_gid;
189 return true;
190}
191
James Hawkinsb2de40a2016-02-26 15:44:46 -0800192bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid __unused,
Ken Mixter207694d2010-10-28 15:42:37 -0700193 FilePath *crash_directory,
194 bool *out_of_capacity) {
Ben Chan262d7982014-09-18 08:05:20 -0700195 if (out_of_capacity) *out_of_capacity = false;
Ken Mixter207694d2010-10-28 15:42:37 -0700196
Ken Mixter03403162010-08-18 15:23:16 -0700197 // For testing.
Lei Zhang9b1f3002014-04-24 02:10:57 -0700198 if (!forced_crash_directory_.empty()) {
199 *crash_directory = forced_crash_directory_;
Ken Mixter03403162010-08-18 15:23:16 -0700200 return true;
201 }
202
Ken Mixter03403162010-08-18 15:23:16 -0700203 mode_t directory_mode;
204 uid_t directory_owner;
205 gid_t directory_group;
206 *crash_directory =
Steve Fungab2ac7d2015-08-14 17:58:05 -0700207 GetCrashDirectoryInfo(&directory_mode,
Ken Mixter03403162010-08-18 15:23:16 -0700208 &directory_owner,
209 &directory_group);
210
Mike Frysingera557c112014-02-05 22:55:39 -0500211 if (!base::PathExists(*crash_directory)) {
Ken Mixter03403162010-08-18 15:23:16 -0700212 // Create the spool directory with the appropriate mode (regardless of
213 // umask) and ownership.
214 mode_t old_mask = umask(0);
215 if (mkdir(crash_directory->value().c_str(), directory_mode) < 0 ||
216 chown(crash_directory->value().c_str(),
217 directory_owner,
218 directory_group) < 0) {
Ken Mixtera3249322011-03-03 08:47:38 -0800219 LOG(ERROR) << "Unable to create appropriate crash directory";
Ken Mixter03403162010-08-18 15:23:16 -0700220 return false;
221 }
222 umask(old_mask);
223 }
224
Mike Frysingera557c112014-02-05 22:55:39 -0500225 if (!base::PathExists(*crash_directory)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800226 LOG(ERROR) << "Unable to create crash directory "
227 << crash_directory->value().c_str();
Ken Mixter03403162010-08-18 15:23:16 -0700228 return false;
229 }
230
Ken Mixter04ec10f2010-08-26 16:02:02 -0700231 if (!CheckHasCapacity(*crash_directory)) {
Ben Chan262d7982014-09-18 08:05:20 -0700232 if (out_of_capacity) *out_of_capacity = true;
Steve Fungab2ac7d2015-08-14 17:58:05 -0700233 LOG(ERROR) << "Directory " << crash_directory->value()
234 << " is out of capacity.";
Ken Mixter04ec10f2010-08-26 16:02:02 -0700235 return false;
236 }
237
Ken Mixter03403162010-08-18 15:23:16 -0700238 return true;
239}
Ken Mixter04ec10f2010-08-26 16:02:02 -0700240
Albert Chaulk426fcc02013-05-02 15:38:31 -0700241FilePath CrashCollector::GetProcessPath(pid_t pid) {
242 return FilePath(StringPrintf("/proc/%d", pid));
243}
244
245bool CrashCollector::GetSymlinkTarget(const FilePath &symlink,
Ben Chan8563d202014-01-27 19:30:13 -0800246 FilePath *target) {
Ben Chanf3811f52014-08-26 06:46:38 -0700247 ssize_t max_size = 64;
248 std::vector<char> buffer;
249
Albert Chaulk426fcc02013-05-02 15:38:31 -0700250 while (true) {
Ben Chanf3811f52014-08-26 06:46:38 -0700251 buffer.resize(max_size + 1);
252 ssize_t size = readlink(symlink.value().c_str(), buffer.data(), max_size);
Albert Chaulk426fcc02013-05-02 15:38:31 -0700253 if (size < 0) {
254 int saved_errno = errno;
255 LOG(ERROR) << "Readlink failed on " << symlink.value() << " with "
256 << saved_errno;
257 return false;
258 }
Ben Chanf3811f52014-08-26 06:46:38 -0700259
Albert Chaulk426fcc02013-05-02 15:38:31 -0700260 buffer[size] = 0;
261 if (size == max_size) {
Ben Chanf3811f52014-08-26 06:46:38 -0700262 max_size *= 2;
263 if (max_size > PATH_MAX) {
Albert Chaulk426fcc02013-05-02 15:38:31 -0700264 return false;
265 }
Ben Chanf3811f52014-08-26 06:46:38 -0700266 continue;
Albert Chaulk426fcc02013-05-02 15:38:31 -0700267 }
268 break;
269 }
270
Ben Chanf3811f52014-08-26 06:46:38 -0700271 *target = FilePath(buffer.data());
Albert Chaulk426fcc02013-05-02 15:38:31 -0700272 return true;
273}
274
275bool CrashCollector::GetExecutableBaseNameFromPid(pid_t pid,
276 std::string *base_name) {
277 FilePath target;
278 FilePath process_path = GetProcessPath(pid);
279 FilePath exe_path = process_path.Append("exe");
280 if (!GetSymlinkTarget(exe_path, &target)) {
281 LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value()
282 << " DirectoryExists: "
Mike Frysingera557c112014-02-05 22:55:39 -0500283 << base::DirectoryExists(process_path);
Albert Chaulk426fcc02013-05-02 15:38:31 -0700284 // Try to further diagnose exe readlink failure cause.
285 struct stat buf;
286 int stat_result = stat(exe_path.value().c_str(), &buf);
287 int saved_errno = errno;
288 if (stat_result < 0) {
289 LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result
290 << " " << saved_errno;
291 } else {
292 LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode="
293 << buf.st_mode;
294 }
295 return false;
296 }
297 *base_name = target.BaseName().value();
298 return true;
299}
300
Ken Mixter04ec10f2010-08-26 16:02:02 -0700301// Return true if the given crash directory has not already reached
302// maximum capacity.
303bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
304 DIR* dir = opendir(crash_directory.value().c_str());
305 if (!dir) {
Steve Fungab2ac7d2015-08-14 17:58:05 -0700306 LOG(WARNING) << "Unable to open crash directory "
307 << crash_directory.value();
Ken Mixter04ec10f2010-08-26 16:02:02 -0700308 return false;
309 }
310 struct dirent ent_buf;
311 struct dirent* ent;
Ken Mixter04ec10f2010-08-26 16:02:02 -0700312 bool full = false;
Ken Mixteree849c52010-09-30 15:30:10 -0700313 std::set<std::string> basenames;
Ben Chan262d7982014-09-18 08:05:20 -0700314 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
Ken Mixter04ec10f2010-08-26 16:02:02 -0700315 if ((strcmp(ent->d_name, ".") == 0) ||
316 (strcmp(ent->d_name, "..") == 0))
317 continue;
318
Ken Mixteree849c52010-09-30 15:30:10 -0700319 std::string filename(ent->d_name);
320 size_t last_dot = filename.rfind(".");
321 std::string basename;
322 // If there is a valid looking extension, use the base part of the
323 // name. If the only dot is the first byte (aka a dot file), treat
324 // it as unique to avoid allowing a directory full of dot files
325 // from accumulating.
326 if (last_dot != std::string::npos && last_dot != 0)
327 basename = filename.substr(0, last_dot);
328 else
329 basename = filename;
330 basenames.insert(basename);
Ken Mixter04ec10f2010-08-26 16:02:02 -0700331
Ken Mixteree849c52010-09-30 15:30:10 -0700332 if (basenames.size() >= static_cast<size_t>(kMaxCrashDirectorySize)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800333 LOG(WARNING) << "Crash directory " << crash_directory.value()
334 << " already full with " << kMaxCrashDirectorySize
335 << " pending reports";
Ken Mixter04ec10f2010-08-26 16:02:02 -0700336 full = true;
337 break;
338 }
339 }
340 closedir(dir);
341 return !full;
342}
Ken Mixteree849c52010-09-30 15:30:10 -0700343
Ken Mixterc49dbd42010-12-14 17:44:11 -0800344bool CrashCollector::GetLogContents(const FilePath &config_path,
345 const std::string &exec_name,
346 const FilePath &output_file) {
Alex Vakulenko74dc6242015-10-13 09:23:34 -0700347 brillo::KeyValueStore store;
Daniel Erat731da332015-01-28 09:48:10 -0700348 if (!store.Load(config_path)) {
Ken Mixtera3249322011-03-03 08:47:38 -0800349 LOG(INFO) << "Unable to read log configuration file "
350 << config_path.value();
Ken Mixterc49dbd42010-12-14 17:44:11 -0800351 return false;
352 }
353
Daniel Erat731da332015-01-28 09:48:10 -0700354 std::string command;
355 if (!store.GetString(exec_name, &command))
Ken Mixterc49dbd42010-12-14 17:44:11 -0800356 return false;
357
Alex Vakulenko74dc6242015-10-13 09:23:34 -0700358 brillo::ProcessImpl diag_process;
Ken Mixtera3249322011-03-03 08:47:38 -0800359 diag_process.AddArg(kShellPath);
Daniel Erat731da332015-01-28 09:48:10 -0700360 diag_process.AddStringOption("-c", command);
Ken Mixtera3249322011-03-03 08:47:38 -0800361 diag_process.RedirectOutput(output_file.value());
Ken Mixterc49dbd42010-12-14 17:44:11 -0800362
Daniel Erat731da332015-01-28 09:48:10 -0700363 const int result = diag_process.Run();
Ken Mixtera3249322011-03-03 08:47:38 -0800364 if (result != 0) {
Daniel Erat731da332015-01-28 09:48:10 -0700365 LOG(INFO) << "Log command \"" << command << "\" exited with " << result;
Ken Mixterc49dbd42010-12-14 17:44:11 -0800366 return false;
367 }
368 return true;
369}
370
Ken Mixterafcf8082010-10-26 14:45:01 -0700371void CrashCollector::AddCrashMetaData(const std::string &key,
372 const std::string &value) {
373 extra_metadata_.append(StringPrintf("%s=%s\n", key.c_str(), value.c_str()));
374}
375
Albert Chaulk33dfd472013-06-19 15:34:13 -0700376void CrashCollector::AddCrashMetaUploadFile(const std::string &key,
377 const std::string &path) {
378 if (!path.empty())
379 AddCrashMetaData(kUploadFilePrefix + key, path);
380}
381
382void CrashCollector::AddCrashMetaUploadData(const std::string &key,
383 const std::string &value) {
384 if (!value.empty())
385 AddCrashMetaData(kUploadVarPrefix + key, value);
386}
387
Ken Mixteree849c52010-09-30 15:30:10 -0700388void CrashCollector::WriteCrashMetaData(const FilePath &meta_path,
Ken Mixterc909b692010-10-18 12:26:05 -0700389 const std::string &exec_name,
390 const std::string &payload_path) {
Ben Chanf84ea212014-08-06 17:27:48 -0700391 int64_t payload_size = -1;
Mike Frysingera557c112014-02-05 22:55:39 -0500392 base::GetFileSize(FilePath(payload_path), &payload_size);
Steve Fungb3a48e12016-02-25 03:37:33 -0800393
394 brillo::OsReleaseReader reader;
395 if (!forced_osreleased_directory_.empty()) {
396 reader.LoadTestingOnly(forced_osreleased_directory_);
397 } else {
398 reader.Load();
399 }
400 std::string bdk_version = "undefined";
401 std::string product_id = "undefined";
402 std::string product_version = "undefined";
403
404 if (!reader.GetString(kBdkVersionKey, &bdk_version)) {
405 LOG(ERROR) << "Could not read " << kBdkVersionKey
406 << " from /etc/os-release.d/";
407 }
408
409 if (!reader.GetString(kProductIDKey, &product_id)) {
410 LOG(ERROR) << "Could not read " << kProductIDKey
411 << " from /etc/os-release.d/";
412 }
413
414 if (!reader.GetString(kProductVersionKey, &product_version)) {
415 LOG(ERROR) << "Could not read " << kProductVersionKey
416 << " from /etc/os-release.d/";
417 }
418
Ken Mixterafcf8082010-10-26 14:45:01 -0700419 std::string meta_data = StringPrintf("%sexec_name=%s\n"
Ken Mixter207694d2010-10-28 15:42:37 -0700420 "payload=%s\n"
Alex Vakulenkoeaf060c2014-08-08 09:36:48 -0700421 "payload_size=%" PRId64 "\n"
Steve Fungb3a48e12016-02-25 03:37:33 -0800422 "%s=%s\n"
423 "%s=%s\n"
424 "%s=%s\n"
Ken Mixteree849c52010-09-30 15:30:10 -0700425 "done=1\n",
Ken Mixterafcf8082010-10-26 14:45:01 -0700426 extra_metadata_.c_str(),
Ken Mixteree849c52010-09-30 15:30:10 -0700427 exec_name.c_str(),
Ken Mixter207694d2010-10-28 15:42:37 -0700428 payload_path.c_str(),
Steve Fungb3a48e12016-02-25 03:37:33 -0800429 payload_size,
430 kBdkVersionKey,
431 bdk_version.c_str(),
432 kProductIDKey,
433 product_id.c_str(),
434 kProductVersionKey,
435 product_version.c_str());
Ben Chanf30c6412014-05-22 23:09:01 -0700436 // We must use WriteNewFile instead of base::WriteFile as we
Ken Mixter9b346472010-11-07 13:45:45 -0800437 // do not want to write with root access to a symlink that an attacker
438 // might have created.
439 if (WriteNewFile(meta_path, meta_data.c_str(), meta_data.size()) < 0) {
Ken Mixtera3249322011-03-03 08:47:38 -0800440 LOG(ERROR) << "Unable to write " << meta_path.value();
Ken Mixteree849c52010-09-30 15:30:10 -0700441 }
442}
Thieu Le1652fb22011-03-03 12:14:43 -0800443
444bool CrashCollector::IsCrashTestInProgress() {
Mike Frysingera557c112014-02-05 22:55:39 -0500445 return base::PathExists(FilePath(kCrashTestInProgressPath));
Thieu Le1652fb22011-03-03 12:14:43 -0800446}
Michael Krebs4fe30db2011-08-05 13:54:52 -0700447
448bool CrashCollector::IsDeveloperImage() {
449 // If we're testing crash reporter itself, we don't want to special-case
450 // for developer images.
451 if (IsCrashTestInProgress())
452 return false;
Mike Frysingera557c112014-02-05 22:55:39 -0500453 return base::PathExists(FilePath(kLeaveCoreFile));
Michael Krebs4fe30db2011-08-05 13:54:52 -0700454}