| Index: src/platform/crash/crash_dumper.cc
|
| diff --git a/src/platform/crash/crash_dumper.cc b/src/platform/crash/crash_dumper.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..94a82636d4f527bd67bac85e804c5b1f3be5c490
|
| --- /dev/null
|
| +++ b/src/platform/crash/crash_dumper.cc
|
| @@ -0,0 +1,127 @@
|
| +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <errno.h>
|
| +#include <pwd.h>
|
| +#include <sys/stat.h>
|
| +#include <sys/types.h>
|
| +#include <unistd.h>
|
| +
|
| +#include "base/file_path.h"
|
| +#include "base/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "client/linux/handler/exception_handler.h"
|
| +#include "common/linux/linux_libc_support.h"
|
| +#include "common/linux/linux_syscall_support.h"
|
| +#include "crash/crash_dumper.h"
|
| +
|
| +// Define sys_mkdir (sys_open passes mode_t as int, so we do too).
|
| +LSS_INLINE _syscall2(int, mkdir, const char *, pathname, int, mode);
|
| +
|
| +static const char kDefaultUser[] = "chronos";
|
| +static const char kSystemCrashParentPath[] = "/var/spool";
|
| +static const char kSystemCrashPath[] = "/var/spool/crash";
|
| +static const char kUserCrashParentPath[] = "/home/chronos/user";
|
| +static const char kUserCrashPath[] = "/home/chronos/user/crash";
|
| +
|
| +// Pointers to paths, set when crash dumping is enabled.
|
| +static const char *s_crash_path;
|
| +static const char *s_crash_parent_path;
|
| +static mode_t s_dump_directory_mode;
|
| +
|
| +static bool s_any_crashes_occurred = false;
|
| +static scoped_ptr<google_breakpad::ExceptionHandler> s_breakpad_handler;
|
| +
|
| +static bool s_enabled = false;
|
| +
|
| +
|
| +// Prepare the crash path. Must avoid allocating memory.
|
| +static bool PrepareCrashPath() {
|
| + struct kernel_stat buf;
|
| + if (sys_stat(s_crash_path, &buf) < 0) {
|
| + // Dump directory does not exist, so create it and its parent now,
|
| + // at the time of the crash.
|
| + sys_mkdir(s_crash_parent_path, 755);
|
| + sys_mkdir(s_crash_path, s_dump_directory_mode);
|
| + }
|
| + return sys_stat(s_crash_path, &buf) == 0;
|
| +}
|
| +
|
| +// Use FilterCallback to avoid recursive crashing.
|
| +// TODO(kmixter): Also use it to avoid enqueuing too many crash dumps
|
| +// system wide - if we get in a crash/restart loop we don't want the entire
|
| +// stateful partition to be filled up.
|
| +static bool FilterCallback(void *) {
|
| + // This function runs in a compromised context - a crash has already
|
| + // occurred so memory allocation and libc should be avoided.
|
| + bool old_any_crashes_occured = s_any_crashes_occurred;
|
| + s_any_crashes_occurred = true;
|
| + // The crash path may have been removed or mounted-over, so make sure
|
| + // there is a container directory. If it fails, not much we can do.
|
| + PrepareCrashPath();
|
| + return !old_any_crashes_occured;
|
| +}
|
| +
|
| +static bool GetEffectiveUser(std::string *result) {
|
| + char storage[256];
|
| + struct passwd passwd_storage;
|
| + struct passwd *passwd_result = NULL;
|
| +
|
| + if (getpwuid_r(geteuid(), &passwd_storage, storage, sizeof(storage),
|
| + &passwd_result) != 0 || passwd_result == NULL) {
|
| + return false;
|
| + }
|
| +
|
| + *result = passwd_result->pw_name;
|
| + return true;
|
| +}
|
| +
|
| +void CrashDumper::Enable() {
|
| + CHECK(!s_enabled) << "Crash handling already enabled";
|
| +
|
| + std::string name;
|
| + CHECK(GetEffectiveUser(&name))
|
| + << "getpwuid_r failed - " << errno
|
| + << " - crash reporting cannot be enabled";
|
| +
|
| + if (name == kDefaultUser) {
|
| + // Crashes as "chronos" when the user is not yet logged in will
|
| + // still be recorded to /home/chronos/user/crash in the
|
| + // stateful partition (outside cryptohome). These will eventually
|
| + // be uploaded when no user is logged in.
|
| + s_crash_path = kUserCrashPath;
|
| + s_crash_parent_path = kUserCrashParentPath;
|
| + s_dump_directory_mode = 0755;
|
| + } else {
|
| + s_crash_path = kSystemCrashPath;
|
| + s_crash_parent_path = kSystemCrashParentPath;
|
| + // Make the dump directory sticky so any UID can write to
|
| + // it but not remove another UID's crashes.
|
| + s_dump_directory_mode = 01777;
|
| + }
|
| +
|
| + CHECK(PrepareCrashPath()) << "Unable to create path " << s_crash_path;
|
| +
|
| + // Begin collecting crashes
|
| + s_breakpad_handler.reset(new google_breakpad::ExceptionHandler(
|
| + s_crash_path,
|
| + FilterCallback,
|
| + NULL, // No minidump callback - sending happens asynchronously to writing
|
| + NULL, // No callback context necessary
|
| + true)); // Install handler now.
|
| +
|
| + s_enabled = true;
|
| +}
|
| +
|
| +bool CrashDumper::IsEnabled() {
|
| + return s_enabled;
|
| +}
|
| +
|
| +void CrashDumper::Disable() {
|
| + CHECK(s_enabled) << "Crash handling was not enabled";
|
| + s_breakpad_handler.reset(NULL);
|
| + s_crash_path = NULL;
|
| + s_crash_parent_path = NULL;
|
| + s_enabled = false;
|
| +}
|
|
|