blob: e8a5b78f9ff39a96a18c7e791e894f78968a7b02 [file] [log] [blame]
// Copyright 2020 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 "vm_tools/common/naming.h"
#include "vm_tools/common/pstore.h"
#include "vm_tools/pstore_dump/persistent_ram_buffer.h"
#include <string>
#include <base/check.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <brillo/dbus/async_event_sequencer.h>
#include <brillo/flag_helper.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_proxy.h>
namespace {
// Return 2 as the exit status when the .pstore file doesn't exist. This value
// is used to distinguish the reason of failure from other critial errors.
constexpr int EXIT_NO_PSTORE_FILE = 2;
static_assert(EXIT_NO_PSTORE_FILE != EXIT_FAILURE);
bool RetrieveSanitizedPrimaryUsername(std::string* out_sanitized_username) {
DCHECK(out_sanitized_username);
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
CHECK(bus->Connect()) << "Failed to connect to system D-Bus";
dbus::ObjectProxy* session_manager_proxy = bus->GetObjectProxy(
login_manager::kSessionManagerServiceName,
dbus::ObjectPath(login_manager::kSessionManagerServicePath));
dbus::MethodCall method_call(
login_manager::kSessionManagerInterface,
login_manager::kSessionManagerRetrievePrimarySession);
std::unique_ptr<dbus::Response> response =
session_manager_proxy->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!response.get()) {
LOG(ERROR) << "Cannot retrieve username for primary session.";
bus->ShutdownAndBlock();
return false;
}
dbus::MessageReader response_reader(response.get());
std::string username;
if (!response_reader.PopString(&username)) {
LOG(ERROR) << "Primary session username bad format.";
bus->ShutdownAndBlock();
return false;
}
if (!response_reader.PopString(out_sanitized_username)) {
LOG(ERROR) << "Primary session sanitized username bad format.";
bus->ShutdownAndBlock();
return false;
}
bus->ShutdownAndBlock();
return true;
}
bool FindARCVMPstorePath(base::FilePath* out_path) {
DCHECK(out_path);
// Before users logged in to Chrome OS, mini-ARCVM uses
// /run/arcvm/arcvm.pstore for the path.
base::FilePath nonuser_pstore_path(vm_tools::kArcVmPstorePath);
if (base::PathExists(nonuser_pstore_path)) {
*out_path = nonuser_pstore_path;
return true;
}
// /run/arcvm/arcvm.pstore is moved to /home/root/<hash>/crosvm/*.pstore by
// arcvm-forward-pstore service after users logged in and mini-ARCVM is
// upgraded.
std::string sanitized_primary_username;
if (!RetrieveSanitizedPrimaryUsername(&sanitized_primary_username)) {
LOG(ERROR) << "Failed to get primary username";
return false;
}
base::FilePath cryptohome_pstore_path =
base::FilePath("/run/daemon-store/crosvm")
.Append(sanitized_primary_username)
.Append(vm_tools::GetEncodedName("arcvm") + ".pstore");
if (base::PathExists(cryptohome_pstore_path)) {
*out_path = cryptohome_pstore_path;
return true;
}
LOG(ERROR) << "The .pstore file doesn't exist at both "
<< vm_tools::kArcVmPstorePath << " and " << cryptohome_pstore_path;
return false;
}
} // namespace
int main(int argc, char** argv) {
DEFINE_string(file, "", "path to a .pstore file (default: ARCVM's .pstore)");
DEFINE_bool(dmesg, false,
"dumps the ring buffers for dmesg instead of the ring buffer for "
"console");
brillo::FlagHelper::Init(
argc, argv,
"A helper to read .pstore files generated by the ARCVM's guest kernel.");
base::FilePath path;
if (!FLAGS_file.empty()) {
path = base::FilePath(FLAGS_file);
} else if (!FindARCVMPstorePath(&path)) {
LOG(ERROR)
<< "Failed to detect the .pstore file. Please use --file option.";
exit(EXIT_NO_PSTORE_FILE);
}
if (FLAGS_dmesg) {
if (!vm_tools::pstore_dump::HandlePstoreDmesg(path)) {
exit(EXIT_FAILURE);
}
} else {
if (!vm_tools::pstore_dump::HandlePstore(path)) {
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}