blob: 802a8008bb50e6673756d1d840a590a9310359de [file] [log] [blame]
// Copyright (c) 2011 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 "cros-disks/cros_disks_server.h"
#include <utility>
#include <base/check.h>
#include <base/logging.h>
#include <chromeos/dbus/service_constants.h>
#include "cros-disks/device_event.h"
#include "cros-disks/disk.h"
#include "cros-disks/disk_manager.h"
#include "cros-disks/disk_monitor.h"
#include "cros-disks/error_logger.h"
#include "cros-disks/format_manager.h"
#include "cros-disks/partition_manager.h"
#include "cros-disks/platform.h"
#include "cros-disks/quote.h"
#include "cros-disks/rename_manager.h"
namespace cros_disks {
CrosDisksServer::CrosDisksServer(scoped_refptr<dbus::Bus> bus,
Platform* platform,
DiskMonitor* disk_monitor,
FormatManager* format_manager,
PartitionManager* partition_manager,
RenameManager* rename_manager)
: org::chromium::CrosDisksAdaptor(this),
dbus_object_(nullptr, bus, dbus::ObjectPath(kCrosDisksServicePath)),
platform_(platform),
disk_monitor_(disk_monitor),
format_manager_(format_manager),
partition_manager_(partition_manager),
rename_manager_(rename_manager) {
CHECK(platform_) << "Invalid platform object";
CHECK(disk_monitor_) << "Invalid disk monitor object";
CHECK(format_manager_) << "Invalid format manager object";
CHECK(partition_manager_) << "Invalid partition manager object";
CHECK(rename_manager_) << "Invalid rename manager object";
format_manager_->set_observer(this);
rename_manager_->set_observer(this);
}
void CrosDisksServer::RegisterAsync(
const brillo::dbus_utils::AsyncEventSequencer::CompletionAction& cb) {
RegisterWithDBusObject(&dbus_object_);
dbus_object_.RegisterAsync(cb);
}
void CrosDisksServer::RegisterMountManager(MountManager* mount_manager) {
CHECK(mount_manager) << "Invalid mount manager object";
mount_managers_.push_back(mount_manager);
}
void CrosDisksServer::Format(const std::string& path,
const std::string& filesystem_type,
const std::vector<std::string>& options) {
FormatErrorType error_type = FORMAT_ERROR_NONE;
Disk disk;
if (!disk_monitor_->GetDiskByDevicePath(base::FilePath(path), &disk)) {
error_type = FORMAT_ERROR_INVALID_DEVICE_PATH;
} else {
error_type = format_manager_->StartFormatting(path, disk.device_file,
filesystem_type, options);
}
if (error_type != FORMAT_ERROR_NONE) {
LOG(ERROR) << "Could not format device " << quote(path) << " as filesystem "
<< quote(filesystem_type) << ": " << error_type;
SendFormatCompletedSignal(error_type, path);
}
}
void CrosDisksServer::SinglePartitionFormat(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<uint32_t>> response,
const std::string& path) {
Disk disk;
if (!disk_monitor_->GetDiskByDevicePath(base::FilePath(path), &disk)) {
LOG(ERROR) << "Invalid device path: " << quote(path)
<< " error code: " << PARTITION_ERROR_INVALID_DEVICE_PATH;
response->Return(PARTITION_ERROR_INVALID_DEVICE_PATH);
} else if (disk.is_on_boot_device || !disk.is_drive || disk.is_read_only) {
LOG(ERROR) << "Device not allowed: " << quote(path)
<< " error code: " << PARTITION_ERROR_DEVICE_NOT_ALLOWED;
response->Return(PARTITION_ERROR_DEVICE_NOT_ALLOWED);
} else {
partition_manager_->StartSinglePartitionFormat(
base::FilePath(disk.device_file),
base::BindOnce(&CrosDisksServer::OnPartitionCompleted,
base::Unretained(this), std::move(response)));
}
}
void CrosDisksServer::Rename(const std::string& path,
const std::string& volume_name) {
RenameErrorType error_type = RENAME_ERROR_NONE;
Disk disk;
if (!disk_monitor_->GetDiskByDevicePath(base::FilePath(path), &disk)) {
error_type = RENAME_ERROR_INVALID_DEVICE_PATH;
} else {
error_type = rename_manager_->StartRenaming(
path, disk.device_file, volume_name, disk.filesystem_type);
}
if (error_type != RENAME_ERROR_NONE) {
LOG(ERROR) << "Could not rename device " << quote(path) << " as "
<< quote(volume_name) << ": " << error_type;
SendRenameCompletedSignal(error_type, path);
}
}
MountManager* CrosDisksServer::FindMounter(
const std::string& source_path) const {
for (const auto& manager : mount_managers_) {
if (manager->CanMount(source_path)) {
return manager;
}
}
return nullptr;
}
void CrosDisksServer::Mount(const std::string& source,
const std::string& filesystem_type,
const std::vector<std::string>& options) {
MountErrorType error_type = MOUNT_ERROR_INVALID_PATH;
MountSourceType source_type = MOUNT_SOURCE_INVALID;
std::string mount_path;
MountManager* mounter = FindMounter(source);
if (mounter) {
source_type = mounter->GetMountSourceType();
error_type = mounter->Mount(source, filesystem_type, options, &mount_path);
}
if (error_type != MOUNT_ERROR_NONE) {
LOG(ERROR) << "Cannot mount " << redact(source) << " of type "
<< quote(filesystem_type) << ": " << error_type;
}
SendMountCompletedSignal(error_type, source, source_type, mount_path);
}
uint32_t CrosDisksServer::Unmount(const std::string& path,
const std::vector<std::string>& options) {
if (path.empty()) {
LOG(ERROR) << "Cannot unmount an empty path";
return MOUNT_ERROR_INVALID_ARGUMENT;
}
LOG_IF(WARNING, !options.empty())
<< "Ignoring non-empty unmount options " << quote(options);
MountErrorType error_type = MOUNT_ERROR_INVALID_PATH;
for (const auto& manager : mount_managers_) {
error_type = manager->Unmount(path);
if (error_type != MOUNT_ERROR_PATH_NOT_MOUNTED)
break;
}
LOG_IF(ERROR, error_type != MOUNT_ERROR_NONE)
<< "Cannot unmount " << quote(path) << ": " << error_type;
return error_type;
}
void CrosDisksServer::UnmountAll() {
for (const auto& manager : mount_managers_) {
manager->UnmountAll();
}
}
std::vector<std::string> CrosDisksServer::EnumerateDevices() {
std::vector<Disk> disks = disk_monitor_->EnumerateDisks();
std::vector<std::string> devices;
devices.reserve(disks.size());
for (const auto& disk : disks) {
devices.push_back(disk.native_path);
}
return devices;
}
std::vector<CrosDisksServer::DBusMountEntry>
CrosDisksServer::EnumerateMountEntries() {
std::vector<DBusMountEntry> dbus_mount_entries;
for (const auto& manager : mount_managers_) {
for (const auto& mount_entry : manager->GetMountEntries()) {
dbus_mount_entries.push_back(
std::make_tuple(static_cast<uint32_t>(mount_entry.error_type),
mount_entry.source_path,
static_cast<uint32_t>(mount_entry.source_type),
mount_entry.mount_path));
}
}
return dbus_mount_entries;
}
bool CrosDisksServer::GetDeviceProperties(
brillo::ErrorPtr* error,
const std::string& device_path,
brillo::VariantDictionary* properties) {
Disk disk;
if (!disk_monitor_->GetDiskByDevicePath(base::FilePath(device_path), &disk)) {
std::string message =
"Could not get the properties of device " + device_path;
LOG(ERROR) << message;
brillo::Error::AddTo(error, FROM_HERE, brillo::errors::dbus::kDomain,
kCrosDisksServiceError, message);
return false;
}
brillo::VariantDictionary temp_properties;
temp_properties[kIsAutoMountable] = disk.is_auto_mountable;
temp_properties[kDeviceIsDrive] = disk.is_drive;
temp_properties[kDevicePresentationHide] = disk.is_hidden;
temp_properties[kDeviceIsMounted] = disk.IsMounted();
temp_properties[kDeviceIsMediaAvailable] = disk.is_media_available;
temp_properties[kDeviceIsOnBootDevice] = disk.is_on_boot_device;
temp_properties[kDeviceIsOnRemovableDevice] = disk.is_on_removable_device;
temp_properties[kDeviceIsVirtual] = disk.is_virtual;
temp_properties[kStorageDevicePath] = disk.storage_device_path;
temp_properties[kDeviceFile] = disk.device_file;
temp_properties[kIdUuid] = disk.uuid;
temp_properties[kIdLabel] = disk.label;
temp_properties[kVendorId] = disk.vendor_id;
temp_properties[kVendorName] = disk.vendor_name;
temp_properties[kProductId] = disk.product_id;
temp_properties[kProductName] = disk.product_name;
temp_properties[kDriveModel] = disk.drive_model;
temp_properties[kDeviceMediaType] = static_cast<uint32_t>(disk.media_type);
temp_properties[kBusNumber] = disk.bus_number;
temp_properties[kDeviceNumber] = disk.device_number;
temp_properties[kDeviceSize] = disk.device_capacity;
temp_properties[kDeviceIsReadOnly] = disk.is_read_only;
temp_properties[kFileSystemType] = disk.filesystem_type;
temp_properties[kDeviceMountPaths] = disk.mount_paths;
*properties = std::move(temp_properties);
return true;
}
void CrosDisksServer::AddDeviceToAllowlist(const std::string& device_path) {
disk_monitor_->AddDeviceToAllowlist(base::FilePath(device_path));
}
void CrosDisksServer::RemoveDeviceFromAllowlist(
const std::string& device_path) {
disk_monitor_->RemoveDeviceFromAllowlist(base::FilePath(device_path));
}
void CrosDisksServer::OnFormatCompleted(const std::string& device_path,
FormatErrorType error_type) {
SendFormatCompletedSignal(error_type, device_path);
}
void CrosDisksServer::OnPartitionCompleted(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<uint32_t>> response,
const base::FilePath& device_path,
PartitionErrorType error_type) {
LOG(ERROR) << "Partitioning for device " << quote(device_path)
<< " completed, result code: " << std::to_string(error_type);
response->Return(error_type);
}
void CrosDisksServer::OnRenameCompleted(const std::string& device_path,
RenameErrorType error_type) {
SendRenameCompletedSignal(error_type, device_path);
}
void CrosDisksServer::OnScreenIsLocked() {
// no-op
}
void CrosDisksServer::OnScreenIsUnlocked() {
// no-op
}
void CrosDisksServer::OnSessionStarted() {
for (const auto& manager : mount_managers_) {
manager->StartSession();
}
}
void CrosDisksServer::OnSessionStopped() {
for (const auto& manager : mount_managers_) {
manager->StopSession();
}
}
void CrosDisksServer::DispatchDeviceEvent(const DeviceEvent& event) {
switch (event.event_type) {
case DeviceEvent::kDeviceAdded:
SendDeviceAddedSignal(event.device_path);
break;
case DeviceEvent::kDeviceScanned:
SendDeviceScannedSignal(event.device_path);
break;
case DeviceEvent::kDeviceRemoved:
SendDeviceRemovedSignal(event.device_path);
break;
case DeviceEvent::kDiskAdded:
SendDiskAddedSignal(event.device_path);
break;
case DeviceEvent::kDiskChanged:
SendDiskChangedSignal(event.device_path);
break;
case DeviceEvent::kDiskRemoved:
SendDiskRemovedSignal(event.device_path);
break;
default:
break;
}
}
} // namespace cros_disks