blob: 63ec522a1c05892b5a40ebc2d03e5bdc1229fabb [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 "diagnostics/cros_healthd/fetchers/storage/device_manager.h"
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <base/check.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <base/synchronization/lock.h>
#include <brillo/udev/udev.h>
#include <brillo/udev/udev_device.h>
#include "diagnostics/common/status_macros.h"
#include "diagnostics/common/statusor.h"
#include "diagnostics/cros_healthd/fetchers/storage/device_info.h"
#include "mojo/cros_healthd_probe.mojom.h"
namespace diagnostics {
namespace {
namespace mojo_ipc = ::chromeos::cros_healthd::mojom;
constexpr char kSysBlockPath[] = "sys/block/";
} // namespace
StorageDeviceManager::StorageDeviceManager(
std::unique_ptr<StorageDeviceLister> device_lister,
std::unique_ptr<StorageDeviceResolver> device_resolver,
std::unique_ptr<brillo::Udev> udev,
std::unique_ptr<Platform> platform)
: device_lister_(std::move(device_lister)),
device_resolver_(std::move(device_resolver)),
udev_(std::move(udev)),
platform_(std::move(platform)) {
DCHECK(device_lister_);
DCHECK(device_resolver_);
DCHECK(udev_);
DCHECK(platform_);
}
std::vector<base::FilePath> StorageDeviceManager::ListDevicesPaths(
const base::FilePath& root) const {
std::vector<base::FilePath> res;
std::vector<std::string> device_names = device_lister_->ListDevices(root);
for (auto d : device_names)
res.push_back(root.Append(kSysBlockPath).Append(d));
return res;
}
Status StorageDeviceManager::RefreshDevices(const base::FilePath& root) {
std::vector<base::FilePath> new_devices_vector = ListDevicesPaths(root);
std::set<base::FilePath> new_devices(new_devices_vector.begin(),
new_devices_vector.end());
// Cleanup devices that disappeared between probes. This shall never happen,
// but we handle it here just in case.
auto it = devices_.begin();
while (it != devices_.end()) {
const auto& devpath = it->first;
const auto& detected = new_devices.find(devpath);
if (detected == new_devices.end()) {
LOG(WARNING) << "Device disapeared: " << devpath.value();
it = devices_.erase(it);
continue;
} else {
new_devices.erase(detected);
++it;
}
}
// Add new devices. We expect it to happen only once for each device.
for (const auto& sys_path : new_devices) {
VLOG(1) << "Preparing the node " << sys_path.value();
std::unique_ptr<brillo::UdevDevice> dev =
udev_->CreateDeviceFromSysPath(sys_path.value().c_str());
if (!dev) {
return Status(StatusCode::kInternal,
"Unable to retrieve udev for " + sys_path.value());
}
// Fill the output with a colon-separated list of subsystems. For example,
// "block:mmc:mmc_host:pci". Similar output is returned by `lsblk -o
// SUBSYSTEMS`.
std::string subsystem = dev->GetSubsystem();
for (auto it = dev->GetParent(); it; it = it->GetParent()) {
auto s = it->GetSubsystem();
if (s != nullptr)
subsystem += std::string(":") + s;
}
auto dev_info = StorageDeviceInfo::Create(
sys_path, base::FilePath(dev->GetDeviceNode()), subsystem,
device_resolver_->GetDevicePurpose(sys_path.BaseName().value()),
platform_.get());
if (!dev_info) {
return Status(
StatusCode::kInternal,
base::StringPrintf("Unable to create dev info object for %s : '%s'",
sys_path.value().c_str(), subsystem.c_str()));
}
devices_[sys_path] = std::move(dev_info);
}
return Status::OkStatus();
}
StatusOr<std::vector<mojo_ipc::NonRemovableBlockDeviceInfoPtr>>
StorageDeviceManager::FetchDevicesInfo(const base::FilePath& root) {
std::vector<mojo_ipc::NonRemovableBlockDeviceInfoPtr> devices{};
base::AutoLock lock(fetch_lock_);
RETURN_IF_ERROR(RefreshDevices(root));
for (auto& dev_info_pair : devices_) {
mojo_ipc::NonRemovableBlockDeviceInfo info;
auto& dev_info = dev_info_pair.second;
RETURN_IF_ERROR(dev_info->PopulateDeviceInfo(&info));
dev_info->PopulateLegacyFields(&info);
devices.push_back(info.Clone());
}
return devices;
}
} // namespace diagnostics