diff --git a/lib/src/blockdev.rs b/lib/src/blockdev.rs index 0381128a..98eb30dd 100644 --- a/lib/src/blockdev.rs +++ b/lib/src/blockdev.rs @@ -124,6 +124,58 @@ pub(crate) fn list() -> Result> { list_impl(None) } +#[derive(Debug, Deserialize)] +struct SfDiskOutput { + partitiontable: PartitionTable, +} + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub(crate) struct Partition { + pub(crate) node: String, + pub(crate) start: u64, + pub(crate) size: u64, + #[serde(rename = "type")] + pub(crate) parttype: String, + pub(crate) uuid: Option, + pub(crate) name: Option, +} + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +pub(crate) struct PartitionTable { + pub(crate) label: String, + pub(crate) id: String, + pub(crate) device: String, + // We're not using these fields + // pub(crate) unit: String, + // pub(crate) firstlba: u64, + // pub(crate) lastlba: u64, + // pub(crate) sectorsize: u64, + pub(crate) partitions: Vec, +} + +impl PartitionTable { + /// Find the partition with the given device name + #[allow(dead_code)] + pub(crate) fn find<'a>(&'a self, devname: &str) -> Option<&'a Partition> { + self.partitions.iter().find(|p| p.node.as_str() == devname) + } + + pub(crate) fn path(&self) -> &Utf8Path { + self.device.as_str().into() + } +} + +#[context("Listing partitions of {dev}")] +pub(crate) fn partitions_of(dev: &Utf8Path) -> Result { + let o = Task::new_quiet("sfdisk") + .args(["-J", dev.as_str()]) + .read()?; + let o: SfDiskOutput = serde_json::from_str(&o).context("Parsing sfdisk output")?; + Ok(o.partitiontable) +} + pub(crate) struct LoopbackDevice { pub(crate) dev: Option, } @@ -324,3 +376,48 @@ fn test_parse_size_mib() { assert_eq!(parse_size_mib(&s).unwrap(), v as u64, "Parsing {s}"); } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_parse_sfdisk() -> Result<()> { + let fixture = indoc::indoc! { r#" + { + "partitiontable": { + "label": "gpt", + "id": "A67AA901-2C72-4818-B098-7F1CAC127279", + "device": "/dev/loop0", + "unit": "sectors", + "firstlba": 34, + "lastlba": 20971486, + "sectorsize": 512, + "partitions": [ + { + "node": "/dev/loop0p1", + "start": 2048, + "size": 8192, + "type": "9E1A2D38-C612-4316-AA26-8B49521E5A8B", + "uuid": "58A4C5F0-BD12-424C-B563-195AC65A25DD", + "name": "PowerPC-PReP-boot" + },{ + "node": "/dev/loop0p2", + "start": 10240, + "size": 20961247, + "type": "0FC63DAF-8483-4772-8E79-3D69D8477DE4", + "uuid": "F51ABB0D-DA16-4A21-83CB-37F4C805AAA0", + "name": "root" + } + ] + } + } + "# }; + let table: SfDiskOutput = serde_json::from_str(&fixture).unwrap(); + assert_eq!( + table.partitiontable.find("/dev/loop0p2").unwrap().size, + 20961247 + ); + Ok(()) + } +} diff --git a/lib/src/bootloader.rs b/lib/src/bootloader.rs index 810a2eb0..2ca9a881 100644 --- a/lib/src/bootloader.rs +++ b/lib/src/bootloader.rs @@ -2,7 +2,7 @@ use anyhow::Result; use camino::Utf8Path; use fn_error_context::context; -use crate::blockdev::Device; +use crate::blockdev::PartitionTable; use crate::task::Task; /// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel) @@ -10,7 +10,7 @@ pub(crate) const EFI_DIR: &str = "efi"; #[context("Installing bootloader")] pub(crate) fn install_via_bootupd( - device: &Device, + device: &PartitionTable, rootfs: &Utf8Path, configopts: &crate::install::InstallConfigOpts, ) -> Result<()> { diff --git a/lib/src/install.rs b/lib/src/install.rs index 9c7acee2..0a553c42 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -823,7 +823,7 @@ fn require_skopeo_with_containers_storage() -> Result<()> { pub(crate) struct RootSetup { luks_device: Option, - device_info: crate::blockdev::Device, + device_info: crate::blockdev::PartitionTable, rootfs: Utf8PathBuf, rootfs_fd: Dir, rootfs_uuid: Option, @@ -1598,7 +1598,7 @@ pub(crate) async fn install_to_filesystem( dev }; tracing::debug!("Backing device: {backing_device}"); - let device_info = crate::blockdev::list_dev(Utf8Path::new(&backing_device))?; + let device_info = crate::blockdev::partitions_of(Utf8Path::new(&backing_device))?; let rootarg = format!("root={}", root_info.mount_spec); let mut boot = if let Some(spec) = fsopts.boot_mount_spec { diff --git a/lib/src/install/baseline.rs b/lib/src/install/baseline.rs index 31abbe6a..01613add 100644 --- a/lib/src/install/baseline.rs +++ b/lib/src/install/baseline.rs @@ -439,7 +439,7 @@ pub(crate) fn install_create_rootfs( BlockSetup::Direct => None, BlockSetup::Tpm2Luks => Some(luks_name.to_string()), }; - let device_info = crate::blockdev::list_dev(&devpath)?; + let device_info = crate::blockdev::partitions_of(&devpath)?; Ok(RootSetup { luks_device, device_info,