| // Copyright 2017 The Fuchsia 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 "block-device.h" |
| |
| #include <fcntl.h> |
| #include <fuchsia/device/c/fidl.h> |
| #include <fuchsia/device/llcpp/fidl.h> |
| #include <fuchsia/hardware/block/c/fidl.h> |
| #include <fuchsia/hardware/block/partition/c/fidl.h> |
| #include <fuchsia/hardware/block/partition/llcpp/fidl.h> |
| #include <fuchsia/hardware/block/volume/c/fidl.h> |
| #include <inttypes.h> |
| #include <lib/fdio/cpp/caller.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fdio/unsafe.h> |
| #include <lib/fdio/watcher.h> |
| #include <lib/fzl/time.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/status.h> |
| #include <lib/zx/time.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <zircon/device/block.h> |
| #include <zircon/processargs.h> |
| #include <zircon/status.h> |
| #include <zircon/syscalls.h> |
| |
| #include <utility> |
| |
| #include <fbl/algorithm.h> |
| #include <fbl/auto_call.h> |
| #include <fbl/string_buffer.h> |
| #include <fbl/unique_fd.h> |
| #include <fs-management/format.h> |
| #include <fs-management/mount.h> |
| #include <gpt/gpt.h> |
| |
| #include "block-watcher.h" |
| #include "encrypted-volume.h" |
| #include "extract-metadata.h" |
| #include "pkgfs-launcher.h" |
| #include "src/devices/block/drivers/block-verity/verified-volume-client.h" |
| #include "src/storage/minfs/fsck.h" |
| #include "src/storage/minfs/minfs.h" |
| |
| namespace devmgr { |
| namespace { |
| |
| const char kAllowAuthoringFactoryConfigFile[] = "/boot/config/allow-authoring-factory"; |
| |
| // Attempt to mount the device pointed to be the file descriptor at a known |
| // location. |
| // |
| // Returns ZX_ERR_ALREADY_BOUND if the device could be mounted, but something |
| // is already mounted at that location. Returns ZX_ERR_INVALID_ARGS if the |
| // GUID of the device does not match a known valid one. Returns |
| // ZX_ERR_NOT_SUPPORTED if the GUID is a system GUID. Returns ZX_OK if an |
| // attempt to mount is made, without checking mount success. |
| zx_status_t MountMinfs(FilesystemMounter* mounter, zx::channel block_device, |
| mount_options_t* options) { |
| fuchsia_hardware_block_partition_GUID type_guid; |
| zx_status_t io_status, status; |
| io_status = fuchsia_hardware_block_partition_PartitionGetTypeGuid(block_device.get(), &status, |
| &type_guid); |
| if (io_status != ZX_OK) { |
| return io_status; |
| } |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| if (gpt_is_sys_guid(type_guid.value, GPT_GUID_LEN)) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } else if (gpt_is_data_guid(type_guid.value, GPT_GUID_LEN)) { |
| return mounter->MountData(std::move(block_device), *options); |
| } else if (gpt_is_install_guid(type_guid.value, GPT_GUID_LEN)) { |
| options->readonly = true; |
| return mounter->MountInstall(std::move(block_device), *options); |
| } else if (gpt_is_durable_guid(type_guid.value, GPT_GUID_LEN)) { |
| return mounter->MountDurable(std::move(block_device), *options); |
| } |
| FX_LOGS(ERROR) << "Unrecognized partition GUID for minfs; not mounting"; |
| return ZX_ERR_WRONG_TYPE; |
| } |
| |
| // return value is ignored |
| int UnsealZxcryptThread(void* arg) { |
| std::unique_ptr<int> fd_ptr(static_cast<int*>(arg)); |
| fbl::unique_fd fd(*fd_ptr); |
| fbl::unique_fd devfs_root(open("/dev", O_RDONLY)); |
| EncryptedVolume volume(std::move(fd), std::move(devfs_root)); |
| volume.EnsureUnsealedAndFormatIfNeeded(); |
| return 0; |
| } |
| |
| // Holds thread state for OpenVerityDeviceThread |
| struct VerityDeviceThreadState { |
| fbl::unique_fd fd; |
| digest::Digest seal; |
| }; |
| |
| // return value is ignored |
| int OpenVerityDeviceThread(void* arg) { |
| std::unique_ptr<VerityDeviceThreadState> state(static_cast<VerityDeviceThreadState*>(arg)); |
| fbl::unique_fd devfs_root(open("/dev", O_RDONLY)); |
| |
| std::unique_ptr<block_verity::VerifiedVolumeClient> vvc; |
| zx_status_t status = block_verity::VerifiedVolumeClient::CreateFromBlockDevice( |
| state->fd.get(), std::move(devfs_root), |
| block_verity::VerifiedVolumeClient::Disposition::kDriverAlreadyBound, zx::sec(5), &vvc); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Couldn't create VerifiedVolumeClient: " << zx_status_get_string(status); |
| return 1; |
| } |
| |
| fbl::unique_fd inner_block_fd; |
| status = vvc->OpenForVerifiedRead(std::move(state->seal), zx::sec(5), inner_block_fd); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "OpenForVerifiedRead failed: " << zx_status_get_string(status); |
| return 1; |
| } |
| return 0; |
| } |
| |
| std::string GetTopologicalPath(int fd) { |
| fdio_cpp::UnownedFdioCaller disk_connection(fd); |
| auto resp = llcpp::fuchsia::device::Controller::Call::GetTopologicalPath( |
| zx::unowned_channel(disk_connection.borrow_channel())); |
| if (resp.status() != ZX_OK) { |
| FX_LOGS(WARNING) << "Unable to get topological path (fidl error): " |
| << zx_status_get_string(resp.status()); |
| return {}; |
| } |
| if (resp->result.is_err()) { |
| FX_LOGS(WARNING) << "Unable to get topological path: " |
| << zx_status_get_string(resp->result.err()); |
| return {}; |
| } |
| const auto& path = resp->result.response().path; |
| return {path.data(), path.size()}; |
| } |
| |
| } // namespace |
| |
| BlockDevice::BlockDevice(FilesystemMounter* mounter, fbl::unique_fd fd, const Config* device_config) |
| : mounter_(mounter), |
| fd_(std::move(fd)), |
| device_config_(device_config), |
| topological_path_(GetTopologicalPath(fd_.get())) {} |
| |
| disk_format_t BlockDevice::content_format() const { |
| if (content_format_) { |
| return *content_format_; |
| } |
| content_format_ = detect_disk_format(fd_.get()); |
| return *content_format_; |
| } |
| |
| disk_format_t BlockDevice::GetFormat() { return format_; } |
| |
| void BlockDevice::SetFormat(disk_format_t format) { format_ = format; } |
| |
| const std::string& BlockDevice::partition_name() const { |
| if (!partition_name_.empty()) { |
| return partition_name_; |
| } |
| // The block device might not support the partition protocol in which case the connection will be |
| // closed, so clone the channel in case that happens. |
| fdio_cpp::UnownedFdioCaller connection(fd_.get()); |
| fidl::ClientEnd<llcpp::fuchsia::hardware::block::partition::Partition> channel( |
| zx::channel(fdio_service_clone(connection.borrow_channel()))); |
| auto resp = fidl::BindSyncClient(std::move(channel)).GetName(); |
| if (resp.status() != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to get partiton name (fidl error): " |
| << zx_status_get_string(resp.status()); |
| return partition_name_; |
| } |
| if (resp->status != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to get partiton name: " << zx_status_get_string(resp->status); |
| return partition_name_; |
| } |
| partition_name_ = std::string(resp->name.data(), resp->name.size()); |
| return partition_name_; |
| } |
| |
| zx_status_t BlockDevice::GetInfo(fuchsia_hardware_block_BlockInfo* out_info) const { |
| if (info_.has_value()) { |
| memcpy(out_info, &*info_, sizeof(*out_info)); |
| return ZX_OK; |
| } |
| fdio_cpp::UnownedFdioCaller connection(fd_.get()); |
| zx_status_t io_status, call_status; |
| io_status = |
| fuchsia_hardware_block_BlockGetInfo(connection.borrow_channel(), &call_status, out_info); |
| if (io_status != ZX_OK) { |
| return io_status; |
| } |
| info_ = *out_info; |
| return call_status; |
| } |
| |
| const fuchsia_hardware_block_partition_GUID& BlockDevice::GetInstanceGuid() const { |
| if (instance_guid_) { |
| return *instance_guid_; |
| } |
| instance_guid_.emplace(); |
| fdio_cpp::UnownedFdioCaller connection(fd_.get()); |
| // The block device might not support the partition protocol in which case the connection will be |
| // closed, so clone the channel in case that happens. |
| zx::channel channel(fdio_service_clone(connection.borrow_channel())); |
| zx_status_t io_status, call_status; |
| io_status = fuchsia_hardware_block_partition_PartitionGetInstanceGuid(channel.get(), &call_status, |
| &instance_guid_.value()); |
| if (io_status != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to get partition instance GUID (fidl error: " |
| << zx_status_get_string(io_status) << ")"; |
| } else if (call_status != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to get partition instance GUID: " |
| << zx_status_get_string(call_status); |
| } |
| return *instance_guid_; |
| } |
| |
| const fuchsia_hardware_block_partition_GUID& BlockDevice::GetTypeGuid() const { |
| if (type_guid_) { |
| return *type_guid_; |
| } |
| type_guid_.emplace(); |
| fdio_cpp::UnownedFdioCaller connection(fd_.get()); |
| // The block device might not support the partition protocol in which case the connection will be |
| // closed, so clone the channel in case that happens. |
| zx::channel channel(fdio_service_clone(connection.borrow_channel())); |
| zx_status_t io_status, call_status; |
| io_status = fuchsia_hardware_block_partition_PartitionGetTypeGuid(channel.get(), &call_status, |
| &type_guid_.value()); |
| if (io_status != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to get partition type GUID (fidl error: " |
| << zx_status_get_string(io_status) << ")"; |
| } else if (call_status != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to get partition type GUID: " << zx_status_get_string(call_status); |
| } |
| return *type_guid_; |
| } |
| |
| zx_status_t BlockDevice::AttachDriver(const std::string_view& driver) { |
| FX_LOGS(INFO) << "Binding: " << driver; |
| fdio_cpp::UnownedFdioCaller connection(fd_.get()); |
| zx_status_t call_status = ZX_OK; |
| auto resp = ::llcpp::fuchsia::device::Controller::Call::Bind( |
| zx::unowned_channel(connection.borrow_channel()), |
| ::fidl::unowned_str(driver.data(), driver.length())); |
| zx_status_t io_status = resp.status(); |
| if (io_status != ZX_OK) { |
| return io_status; |
| } |
| if (resp->result.is_err()) { |
| call_status = resp->result.err(); |
| } |
| return call_status; |
| } |
| |
| zx_status_t BlockDevice::UnsealZxcrypt() { |
| FX_LOGS(INFO) << "unsealing zxcrypt"; |
| // Bind and unseal the driver from a separate thread, since we |
| // have to wait for a number of devices to do I/O and settle, |
| // and we don't want to block block-watcher for any nontrivial |
| // length of time. |
| |
| // We transfer fd to the spawned thread. Since it's UB to cast |
| // ints to pointers and back, we allocate the fd on the heap. |
| int loose_fd = fd_.release(); |
| int* raw_fd_ptr = new int(loose_fd); |
| thrd_t th; |
| int err = thrd_create_with_name(&th, &UnsealZxcryptThread, raw_fd_ptr, "zxcrypt-unseal"); |
| if (err != thrd_success) { |
| FX_LOGS(ERROR) << "failed to spawn zxcrypt worker thread"; |
| close(loose_fd); |
| delete raw_fd_ptr; |
| return ZX_ERR_INTERNAL; |
| } else { |
| thrd_detach(th); |
| } |
| return ZX_OK; |
| } |
| |
| zx_status_t BlockDevice::OpenBlockVerityForVerifiedRead(std::string seal_hex) { |
| FX_LOGS(INFO) << "preparing block-verity"; |
| |
| std::unique_ptr<VerityDeviceThreadState> state = std::make_unique<VerityDeviceThreadState>(); |
| zx_status_t rc = state->seal.Parse(seal_hex.c_str()); |
| if (rc != ZX_OK) { |
| FX_LOGS(ERROR) << "block-verity seal " << seal_hex |
| << " did not parse as SHA256 hex digest: " << zx_status_get_string(rc); |
| return rc; |
| } |
| |
| // Transfer FD to thread state. |
| state->fd = std::move(fd_); |
| |
| thrd_t th; |
| int err = thrd_create_with_name(&th, OpenVerityDeviceThread, state.get(), "block-verity-open"); |
| if (err != thrd_success) { |
| FX_LOGS(ERROR) << "failed to spawn block-verity worker thread"; |
| return ZX_ERR_INTERNAL; |
| } else { |
| // Release our reference to the state now owned by the other thread. |
| state.release(); |
| thrd_detach(th); |
| } |
| |
| return ZX_OK; |
| } |
| |
| zx_status_t BlockDevice::FormatZxcrypt() { |
| fbl::unique_fd devfs_root_fd(open("/dev", O_RDONLY)); |
| if (!devfs_root_fd) { |
| return ZX_ERR_NOT_FOUND; |
| } |
| EncryptedVolume volume(fd_.duplicate(), std::move(devfs_root_fd)); |
| return volume.Format(); |
| } |
| |
| zx::status<std::string> BlockDevice::VeritySeal() { |
| return mounter_->boot_args()->block_verity_seal(); |
| } |
| |
| bool BlockDevice::ShouldAllowAuthoringFactory() { |
| // Checks for presence of /boot/config/allow-authoring-factory |
| fbl::unique_fd allow_authoring_factory_fd(open(kAllowAuthoringFactoryConfigFile, O_RDONLY)); |
| return allow_authoring_factory_fd.is_valid(); |
| } |
| |
| zx_status_t BlockDevice::SetPartitionMaxSize(const std::string& fvm_path, uint64_t max_size) { |
| // Get the partition GUID for talking to FVM. |
| const fuchsia_hardware_block_partition_GUID& instance_guid = GetInstanceGuid(); |
| if (std::all_of(std::begin(instance_guid.value), std::end(instance_guid.value), |
| [](auto val) { return val == 0; })) |
| return ZX_ERR_NOT_SUPPORTED; // Not a partition, nothing to do. |
| |
| fbl::unique_fd fvm_fd(open(fvm_path.c_str(), O_RDONLY)); |
| if (!fvm_fd) |
| return ZX_ERR_NOT_SUPPORTED; // Not in FVM, nothing to do. |
| |
| // Actually set the limit. |
| fdio_cpp::UnownedFdioCaller caller(fvm_fd.get()); |
| zx_status_t set_status; |
| if (zx_status_t fidl_status = fuchsia_hardware_block_volume_VolumeManagerSetPartitionLimit( |
| caller.channel()->get(), &instance_guid, max_size, &set_status); |
| fidl_status != ZX_OK || set_status != ZX_OK) { |
| FX_LOGS(ERROR) << "Unable to set partition limit for " << topological_path() << " to " |
| << max_size << " bytes."; |
| FX_LOGS(ERROR) << " FIDL error: " << zx_status_get_string(fidl_status) |
| << " FVM error: " << zx_status_get_string(set_status); |
| return fidl_status != ZX_OK ? fidl_status : set_status; |
| } |
| |
| return ZX_OK; |
| } |
| |
| bool BlockDevice::ShouldCheckFilesystems() { return mounter_->ShouldCheckFilesystems(); } |
| |
| zx_status_t BlockDevice::CheckFilesystem() { |
| if (!ShouldCheckFilesystems()) { |
| return ZX_OK; |
| } |
| |
| zx_status_t status; |
| fuchsia_hardware_block_BlockInfo info; |
| if ((status = GetInfo(&info)) != ZX_OK) { |
| return status; |
| } |
| |
| switch (format_) { |
| case DISK_FORMAT_BLOBFS: { |
| FX_LOGS(INFO) << "Skipping blobfs consistency checker."; |
| return ZX_OK; |
| } |
| |
| case DISK_FORMAT_FACTORYFS: { |
| FX_LOGS(INFO) << "Skipping factory consistency checker."; |
| return ZX_OK; |
| } |
| |
| case DISK_FORMAT_MINFS: { |
| zx::ticks before = zx::ticks::now(); |
| auto timer = fbl::MakeAutoCall([before]() { |
| auto after = zx::ticks::now(); |
| auto duration = fzl::TicksToNs(after - before); |
| FX_LOGS(INFO) << "fsck took " << duration.to_secs() << "." << duration.to_msecs() % 1000 |
| << " seconds"; |
| }); |
| FX_LOGS(INFO) << "fsck of " << disk_format_string_[format_] << " started"; |
| uint64_t device_size = info.block_size * info.block_count / minfs::kMinfsBlockSize; |
| std::unique_ptr<block_client::BlockDevice> device; |
| zx_status_t status = minfs::FdToBlockDevice(fd_, &device); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Cannot convert fd to block device: " << status; |
| return status; |
| } |
| std::unique_ptr<minfs::Bcache> bc; |
| status = minfs::Bcache::Create(std::move(device), static_cast<uint32_t>(device_size), &bc); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Could not initialize minfs bcache."; |
| return status; |
| } |
| status = minfs::Fsck(std::move(bc), minfs::FsckOptions{.repair = true}); |
| |
| if (status != ZX_OK) { |
| mounter_->mutable_metrics()->LogMinfsCorruption(); |
| mounter_->FlushMetrics(); |
| FX_LOGS(ERROR) << "\n--------------------------------------------------------------\n" |
| "|\n" |
| "| WARNING: fshost fsck failure!\n" |
| "| Corrupt " |
| << disk_format_string_[format_] |
| << " filesystem\n" |
| "|\n" |
| "| If your system was shutdown cleanly (via 'dm poweroff'\n" |
| "| or an OTA), report this device to the local-storage\n" |
| "| team. Please file bugs with logs before and after reboot.\n" |
| "|\n" |
| "--------------------------------------------------------------"; |
| MaybeDumpMetadata(fd_.duplicate(), {.disk_format = DISK_FORMAT_MINFS}); |
| } else { |
| FX_LOGS(INFO) << "fsck of " << disk_format_string_[format_] << " completed OK"; |
| } |
| return status; |
| } |
| default: |
| FX_LOGS(ERROR) << "Not checking unknown filesystem"; |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| } |
| |
| zx_status_t BlockDevice::FormatFilesystem() { |
| zx_status_t status; |
| fuchsia_hardware_block_BlockInfo info; |
| if ((status = GetInfo(&info)) != ZX_OK) { |
| return status; |
| } |
| |
| switch (format_) { |
| case DISK_FORMAT_BLOBFS: { |
| FX_LOGS(ERROR) << "Not formatting blobfs."; |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| case DISK_FORMAT_FACTORYFS: { |
| FX_LOGS(ERROR) << "Not formatting factoryfs."; |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| case DISK_FORMAT_MINFS: { |
| FX_LOGS(INFO) << "Formatting minfs."; |
| uint64_t blocks = info.block_size * info.block_count / minfs::kMinfsBlockSize; |
| std::unique_ptr<block_client::BlockDevice> device; |
| zx_status_t status = minfs::FdToBlockDevice(fd_, &device); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Cannot convert fd to block device: " << status; |
| return status; |
| } |
| std::unique_ptr<minfs::Bcache> bc; |
| status = minfs::Bcache::Create(std::move(device), static_cast<uint32_t>(blocks), &bc); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Could not initialize minfs bcache."; |
| return status; |
| } |
| minfs::MountOptions options = {}; |
| if ((status = minfs::Mkfs(options, bc.get())) != ZX_OK) { |
| FX_LOGS(ERROR) << "Could not format minfs filesystem."; |
| return status; |
| } |
| FX_LOGS(INFO) << "Minfs filesystem re-formatted. Expect data loss."; |
| return ZX_OK; |
| } |
| default: |
| FX_LOGS(ERROR) << "Not formatting unknown filesystem."; |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| } |
| |
| zx_status_t BlockDevice::MountFilesystem() { |
| if (!fd_) { |
| return ZX_ERR_BAD_HANDLE; |
| } |
| zx::channel block_device; |
| { |
| fdio_cpp::UnownedFdioCaller disk_connection(fd_.get()); |
| zx::unowned_channel channel(disk_connection.borrow_channel()); |
| block_device.reset(fdio_service_clone(channel->get())); |
| } |
| switch (format_) { |
| case DISK_FORMAT_FACTORYFS: { |
| FX_LOGS(INFO) << "BlockDevice::MountFilesystem(factoryfs)"; |
| mount_options_t options = default_mount_options; |
| options.collect_metrics = false; |
| options.readonly = true; |
| |
| zx_status_t status = mounter_->MountFactoryFs(std::move(block_device), options); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Failed to mount factoryfs partition: " << zx_status_get_string(status) |
| << "."; |
| } |
| return status; |
| } |
| case DISK_FORMAT_BLOBFS: { |
| FX_LOGS(INFO) << "BlockDevice::MountFilesystem(blobfs)"; |
| mount_options_t options = default_mount_options; |
| options.collect_metrics = true; |
| std::optional<std::string> algorithm = std::nullopt; |
| std::optional<std::string> eviction_policy = std::nullopt; |
| if (mounter_->boot_args()) { |
| algorithm = mounter_->boot_args()->blobfs_write_compression_algorithm(); |
| if (algorithm == "ZSTD" || algorithm == "ZSTD_SEEKABLE") { |
| // These two algorithms are deprecated. |
| FX_LOGS(INFO) << "Ignoring " << *algorithm << " algorithm"; |
| algorithm = std::nullopt; |
| } |
| eviction_policy = mounter_->boot_args()->blobfs_eviction_policy(); |
| } |
| options.write_compression_algorithm = algorithm ? algorithm->c_str() : nullptr; |
| options.cache_eviction_policy = eviction_policy ? eviction_policy->c_str() : nullptr; |
| if (device_config_->is_set(Config::kSandboxDecompression)) { |
| options.sandbox_decompression = true; |
| } |
| zx_status_t status = mounter_->MountBlob(std::move(block_device), options); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Failed to mount blobfs partition: " << zx_status_get_string(status) |
| << "."; |
| return status; |
| } |
| mounter_->TryMountPkgfs(); |
| return ZX_OK; |
| } |
| case DISK_FORMAT_MINFS: { |
| mount_options_t options = default_mount_options; |
| FX_LOGS(INFO) << "BlockDevice::MountFilesystem(minfs)"; |
| zx_status_t status = MountMinfs(mounter_, std::move(block_device), &options); |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Failed to mount minfs partition: " << zx_status_get_string(status) |
| << "."; |
| MaybeDumpMetadata(fd_.duplicate(), {.disk_format = DISK_FORMAT_MINFS}); |
| return status; |
| } |
| mounter_->TryMountPkgfs(); |
| return ZX_OK; |
| } |
| default: |
| FX_LOGS(ERROR) << "BlockDevice::MountFilesystem(unknown)"; |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| } |
| |
| zx_status_t BlockDeviceInterface::Add(bool format_on_corruption) { |
| switch (GetFormat()) { |
| case DISK_FORMAT_BOOTPART: { |
| return AttachDriver(kBootpartDriverPath); |
| } |
| case DISK_FORMAT_GPT: { |
| return AttachDriver(kGPTDriverPath); |
| } |
| case DISK_FORMAT_FVM: { |
| return AttachDriver(kFVMDriverPath); |
| } |
| case DISK_FORMAT_MBR: { |
| return AttachDriver(kMBRDriverPath); |
| } |
| case DISK_FORMAT_BLOCK_VERITY: { |
| if (zx_status_t status = AttachDriver(kBlockVerityDriverPath); status != ZX_OK) { |
| return status; |
| } |
| |
| if (!ShouldAllowAuthoringFactory()) { |
| zx::status<std::string> seal_text = VeritySeal(); |
| if (seal_text.is_error()) { |
| FX_LOGS(ERROR) << "Couldn't get block-verity seal: " << seal_text.status_string(); |
| return seal_text.error_value(); |
| } |
| |
| return OpenBlockVerityForVerifiedRead(seal_text.value()); |
| } |
| |
| return ZX_OK; |
| } |
| case DISK_FORMAT_FACTORYFS: { |
| if (zx_status_t status = CheckFilesystem(); status != ZX_OK) { |
| return status; |
| } |
| |
| return MountFilesystem(); |
| } |
| case DISK_FORMAT_ZXCRYPT: { |
| return UnsealZxcrypt(); |
| } |
| case DISK_FORMAT_BLOBFS: { |
| if (zx_status_t status = CheckFilesystem(); status != ZX_OK) { |
| return status; |
| } |
| return MountFilesystem(); |
| } |
| case DISK_FORMAT_MINFS: { |
| FX_LOGS(INFO) << "mounting minfs: format on corruption is " |
| << (format_on_corruption ? "enabled" : "disabled"); |
| if (zx_status_t status = CheckFilesystem(); status != ZX_OK) { |
| if (!format_on_corruption) { |
| FX_LOGS(INFO) << "formatting minfs on this target is disabled"; |
| return status; |
| } |
| if (zx_status_t status = FormatFilesystem(); status != ZX_OK) { |
| return status; |
| } |
| } |
| if (zx_status_t status = MountFilesystem(); status != ZX_OK) { |
| FX_LOGS(ERROR) << "failed to mount filesystem: " << zx_status_get_string(status); |
| if (!format_on_corruption) { |
| FX_LOGS(ERROR) << "formatting minfs on this target is disabled"; |
| return status; |
| } |
| if ((status = FormatFilesystem()) != ZX_OK) { |
| return status; |
| } |
| return MountFilesystem(); |
| } |
| return ZX_OK; |
| } |
| case DISK_FORMAT_FAT: |
| case DISK_FORMAT_VBMETA: |
| case DISK_FORMAT_UNKNOWN: |
| case DISK_FORMAT_COUNT_: |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| |
| } // namespace devmgr |