[recovery] Move block device resolution to recovery-util
The functionality to list devices in dev/class/block and resolve their
topological paths is useful in both installer and recovery OTA. This
code can live in a common location for reusability.
Cq-Include-Trybots: luci.fuchsia.try:core.x64-asan-slow
Bug: b/235401382
Change-Id: I0ff6ffe2dfc5ce641b8648940082df6f808bfa6f
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/690390
Commit-Queue: Eric Stone <ecstone@google.com>
Reviewed-by: Simon Shields <simonshields@google.com>
Reviewed-by: Mike "mc" Comfoltey <comfoltey@google.com>
diff --git a/src/recovery/lib/recovery-util/BUILD.gn b/src/recovery/lib/recovery-util/BUILD.gn
index b74f969..2a34723 100644
--- a/src/recovery/lib/recovery-util/BUILD.gn
+++ b/src/recovery/lib/recovery-util/BUILD.gn
@@ -9,14 +9,20 @@
edition = "2021"
with_unit_tests = true
deps = [
+ "//sdk/fidl/fuchsia.device:fuchsia.device-rustc",
+ "//sdk/fidl/fuchsia.hardware.block:fuchsia.hardware.block-rustc",
+ "//sdk/fidl/fuchsia.hardware.block.partition:fuchsia.hardware.block.partition-rustc",
+ "//sdk/fidl/fuchsia.hardware.block.volume:fuchsia.hardware.block.volume-rustc",
"//sdk/fidl/fuchsia.wlan.common:fuchsia.wlan.common-rustc",
"//sdk/fidl/fuchsia.wlan.policy:fuchsia.wlan.policy-rustc",
+ "//src/lib/fdio/rust:fdio",
"//src/lib/fidl/rust/fidl",
"//src/lib/fuchsia",
"//src/lib/fuchsia-async",
"//src/lib/fuchsia-component",
"//src/lib/ui/carnelian",
"//src/lib/zircon/rust:fuchsia-zircon",
+ "//src/lib/zircon/rust:fuchsia-zircon-status",
"//third_party/rust_crates:anyhow",
"//third_party/rust_crates:async-trait",
"//third_party/rust_crates:euclid",
@@ -28,6 +34,7 @@
"//third_party/rust_crates:pin-utils",
]
sources = [
+ "src/block.rs",
"src/lib.rs",
"src/testing/mod.rs",
"src/ui/mod.rs",
diff --git a/src/recovery/lib/recovery-util/src/block.rs b/src/recovery/lib/recovery-util/src/block.rs
new file mode 100644
index 0000000..17eb774
--- /dev/null
+++ b/src/recovery/lib/recovery-util/src/block.rs
@@ -0,0 +1,95 @@
+// Copyright 2022 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.
+
+use {
+ anyhow::{anyhow, Context, Error},
+ fdio,
+ fidl::endpoints::Proxy,
+ fidl_fuchsia_device::ControllerProxy,
+ fidl_fuchsia_hardware_block::BlockProxy,
+ fuchsia_zircon as zx, fuchsia_zircon_status as zx_status,
+ std::{fs, path::Path},
+};
+
+async fn connect_to_service(path: &str) -> Result<fidl::AsyncChannel, Error> {
+ let (local, remote) = zx::Channel::create().context("Creating channel")?;
+ fdio::service_connect(path, remote).context("Connecting to service")?;
+ let local = fidl::AsyncChannel::from_channel(local).context("Creating AsyncChannel")?;
+ Ok(local)
+}
+
+async fn block_device_get_info(
+ block_channel: fidl::AsyncChannel,
+) -> Result<Option<(String, u64)>, Error> {
+ // Figure out topological path of the block device, so we can guess if it's a disk or a
+ // partition.
+ let (maybe_path, block_channel) = get_topological_path(block_channel).await?;
+ let topo_path = maybe_path.ok_or(anyhow!("Failed to get topo path for device"))?;
+
+ if topo_path.contains("/ramdisk-") {
+ // This is probably ram, skip it
+ return Ok(None);
+ }
+
+ let block = BlockProxy::from_channel(block_channel);
+ let (status, maybe_info) = block.get_info().await?;
+ if let Some(info) = maybe_info {
+ let blocks = info.block_count;
+ let block_size = info.block_size as u64;
+ return Ok(Some((topo_path, blocks * block_size)));
+ }
+
+ return Err(Error::new(zx_status::Status::from_raw(status)));
+}
+
+// There's no nice way to use a service without losing the channel,
+// so this function returns the controller.
+async fn get_topological_path(
+ channel: fidl::AsyncChannel,
+) -> Result<(Option<String>, fidl::AsyncChannel), Error> {
+ let controller = ControllerProxy::from_channel(channel);
+ let topo_resp = controller.get_topological_path().await.context("Getting topological path")?;
+ Ok((topo_resp.ok(), controller.into_channel().unwrap()))
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct BlockDevice {
+ /// Topological path of the block device.
+ pub topo_path: String,
+ /// Path to the block device under /dev/class/block.
+ pub class_path: String,
+ /// Size of the block device, in bytes.
+ pub size: u64,
+}
+
+impl BlockDevice {
+ /// Returns true if this block device is a disk.
+ pub fn is_disk(&self) -> bool {
+ // partitions have paths like this:
+ // /dev/sys/platform/pci/00:14.0/xhci/usb-bus/001/001/ifc-000/ums/lun-000/block/part-000/block
+ // while disks are like this:
+ // /dev/sys/platform/pci/00:17.0/ahci/sata2/block
+ !self.topo_path.contains("/block/part-")
+ }
+}
+
+pub async fn get_block_device(class_path: String) -> Result<Option<BlockDevice>, Error> {
+ let block_channel = connect_to_service(&class_path).await?;
+ let result = block_device_get_info(block_channel).await.context("Getting block device info")?;
+ Ok(result.map(|(topo_path, size)| BlockDevice { topo_path, class_path, size }))
+}
+
+pub async fn get_block_devices() -> Result<Vec<BlockDevice>, Error> {
+ let block_dir = Path::new("/dev/class/block");
+ let mut devices = Vec::new();
+ for entry in fs::read_dir(block_dir)? {
+ let name = entry?.path().to_str().unwrap().to_owned();
+ if let Some(bd) = get_block_device(name.clone()).await? {
+ devices.push(bd);
+ } else {
+ println!("Bad disk: {:?}", name);
+ }
+ }
+ Ok(devices)
+}
diff --git a/src/recovery/lib/recovery-util/src/lib.rs b/src/recovery/lib/recovery-util/src/lib.rs
index 4b03276..cd547b5 100644
--- a/src/recovery/lib/recovery-util/src/lib.rs
+++ b/src/recovery/lib/recovery-util/src/lib.rs
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+pub mod block;
pub mod ui;
pub mod wlan;
diff --git a/src/recovery/system/BUILD.gn b/src/recovery/system/BUILD.gn
index 986e527..b49c40c 100644
--- a/src/recovery/system/BUILD.gn
+++ b/src/recovery/system/BUILD.gn
@@ -257,6 +257,7 @@
"//src/lib/ui/fuchsia-framebuffer",
"//src/lib/zircon/rust:fuchsia-zircon",
"//src/lib/zircon/rust:fuchsia-zircon-status",
+ "//src/recovery/lib/recovery-util",
"//src/sys/lib/payload_streamer",
"//src/sys/pkg/lib/isolated-ota",
"//third_party/rust_crates:anyhow",
diff --git a/src/recovery/system/installer/installer.rs b/src/recovery/system/installer/installer.rs
index c83b4d7..320f75e 100644
--- a/src/recovery/system/installer/installer.rs
+++ b/src/recovery/system/installer/installer.rs
@@ -7,15 +7,13 @@
anyhow::{anyhow, Context, Error},
fdio,
fidl::endpoints::{ClientEnd, Proxy, ServerEnd},
- fidl_fuchsia_device::ControllerProxy,
- fidl_fuchsia_hardware_block::BlockProxy,
fidl_fuchsia_paver::{
BootManagerMarker, Configuration, DynamicDataSinkProxy, PaverMarker, PaverProxy,
},
fidl_fuchsia_sysinfo as fsysinfo,
fuchsia_component::client,
- fuchsia_zircon as zx, fuchsia_zircon_status as zx_status,
- std::{fs, path::Path},
+ fuchsia_zircon as zx,
+ recovery_util::block::BlockDevice,
};
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -24,88 +22,6 @@
Coreboot,
}
-async fn connect_to_service(path: &str) -> Result<fidl::AsyncChannel, Error> {
- let (local, remote) = zx::Channel::create().context("Creating channel")?;
- fdio::service_connect(path, remote).context("Connecting to service")?;
- let local = fidl::AsyncChannel::from_channel(local).context("Creating AsyncChannel")?;
- Ok(local)
-}
-
-async fn block_device_get_info(
- block_channel: fidl::AsyncChannel,
-) -> Result<Option<(String, u64)>, Error> {
- // Figure out topological path of the block device, so we can guess if it's a disk or a
- // partition.
- let (maybe_path, block_channel) = get_topological_path(block_channel).await?;
- let topo_path = maybe_path.ok_or(anyhow!("Failed to get topo path for device"))?;
-
- if topo_path.contains("/ramdisk-") {
- // This is probably ram, skip it
- return Ok(None);
- }
-
- let block = BlockProxy::from_channel(block_channel);
- let (status, maybe_info) = block.get_info().await?;
- if let Some(info) = maybe_info {
- let blocks = info.block_count;
- let block_size = info.block_size as u64;
- return Ok(Some((topo_path, blocks * block_size)));
- }
-
- return Err(Error::new(zx_status::Status::from_raw(status)));
-}
-
-// There's no nice way to use a service without losing the channel,
-// so this function returns the controller.
-async fn get_topological_path(
- channel: fidl::AsyncChannel,
-) -> Result<(Option<String>, fidl::AsyncChannel), Error> {
- let controller = ControllerProxy::from_channel(channel);
- let topo_resp = controller.get_topological_path().await.context("Getting topological path")?;
- Ok((topo_resp.ok(), controller.into_channel().unwrap()))
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct BlockDevice {
- /// Topological path of the block device.
- pub topo_path: String,
- /// Path to the block device under /dev/class/block.
- pub class_path: String,
- /// Size of the block device, in bytes.
- pub size: u64,
-}
-
-impl BlockDevice {
- /// Returns true if this block device is a disk.
- pub fn is_disk(&self) -> bool {
- // partitions have paths like this:
- // /dev/sys/platform/pci/00:14.0/xhci/usb-bus/001/001/ifc-000/ums/lun-000/block/part-000/block
- // while disks are like this:
- // /dev/sys/platform/pci/00:17.0/ahci/sata2/block
- !self.topo_path.contains("/block/part-")
- }
-}
-
-pub async fn get_block_device(class_path: String) -> Result<Option<BlockDevice>, Error> {
- let block_channel = connect_to_service(&class_path).await?;
- let result = block_device_get_info(block_channel).await.context("Getting block device info")?;
- Ok(result.map(|(topo_path, size)| BlockDevice { topo_path, class_path, size }))
-}
-
-pub async fn get_block_devices() -> Result<Vec<BlockDevice>, Error> {
- let block_dir = Path::new("/dev/class/block");
- let mut devices = Vec::new();
- for entry in fs::read_dir(block_dir)? {
- let name = entry?.path().to_str().unwrap().to_owned();
- if let Some(bd) = get_block_device(name.clone()).await? {
- devices.push(bd);
- } else {
- println!("Bad disk: {:?}", name);
- }
- }
- Ok(devices)
-}
-
pub async fn find_install_source(
block_devices: &Vec<BlockDevice>,
bootloader: BootloaderType,
diff --git a/src/recovery/system/installer/main.rs b/src/recovery/system/installer/main.rs
index 8aee51d..ed24746 100644
--- a/src/recovery/system/installer/main.rs
+++ b/src/recovery/system/installer/main.rs
@@ -35,9 +35,10 @@
pub mod installer;
use installer::{
- find_install_source, get_block_device, get_block_devices, get_bootloader_type, paver_connect,
- set_active_configuration, BlockDevice, BootloaderType,
+ find_install_source, get_bootloader_type, paver_connect, set_active_configuration,
+ BootloaderType,
};
+use recovery_util::block::{get_block_device, get_block_devices, BlockDevice};
pub mod partition;
use partition::Partition;
@@ -662,7 +663,13 @@
let bootloader_type = installation_paths.bootloader_type.unwrap();
// TODO(fxbug.dev/100712): Remove this once flake is resolved.
- println!("Installing to {} ({}), source {} ({})", install_target.topo_path, install_target.class_path, install_source.topo_path, install_source.class_path);
+ println!(
+ "Installing to {} ({}), source {} ({})",
+ install_target.topo_path,
+ install_target.class_path,
+ install_source.topo_path,
+ install_source.class_path
+ );
let (paver, data_sink) =
paver_connect(&install_target.class_path).context("Could not contact paver")?;
diff --git a/src/recovery/system/installer/menu.rs b/src/recovery/system/installer/menu.rs
index 102c60a6..fb655ae 100644
--- a/src/recovery/system/installer/menu.rs
+++ b/src/recovery/system/installer/menu.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use crate::installer::BlockDevice;
+use recovery_util::block::BlockDevice;
const CONST_SELECT_INSTALL_HEADLINE: &'static str = "Select Installation Method";
const CONST_SELECT_DISK_HEADLINE: &'static str = "Select Disk you would like to install Fuchsia to";
diff --git a/src/recovery/system/installer/partition.rs b/src/recovery/system/installer/partition.rs
index 1c522ea3..76f01da 100644
--- a/src/recovery/system/installer/partition.rs
+++ b/src/recovery/system/installer/partition.rs
@@ -3,7 +3,7 @@
// found in the LICENSE file.
use {
- crate::installer::{BlockDevice, BootloaderType},
+ crate::installer::BootloaderType,
anyhow::{Context, Error},
fidl::endpoints::Proxy,
fidl_fuchsia_fshost::{BlockWatcherMarker, BlockWatcherProxy},
@@ -13,6 +13,7 @@
fuchsia_async as fasync, fuchsia_zircon as zx, fuchsia_zircon_status as zx_status,
futures::prelude::*,
payload_streamer::PayloadStreamer,
+ recovery_util::block::BlockDevice,
regex,
std::{fmt, fs, io::Read, path::Path, sync::Mutex},
};