Skip to content

Commit

Permalink
install: Use sfdisk, not lsblk
Browse files Browse the repository at this point in the history
This works around an issue where `lsblk` ends up parsing
data cached from udev in `/run/udev`, but we don't have that
mounted by default.

Adding a new mount point hard requirement is logistically
complicated right now - we will eventually switch
to dynamic mounts with `open_tree` (cc
containers#380 )
but this is a relatively straightforward workaround.

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Jul 16, 2024
1 parent c866bba commit 79b2f2a
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 5 deletions.
96 changes: 96 additions & 0 deletions lib/src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,57 @@ pub(crate) fn list() -> Result<Vec<Device>> {
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: String,
pub(crate) name: String,
}

#[derive(Debug, Deserialize)]
#[allow(dead_code)]
pub(crate) struct PartitionTable {
pub(crate) label: String,
pub(crate) id: String,
pub(crate) device: String,
pub(crate) unit: String,
pub(crate) firstlba: u64,
pub(crate) lastlba: u64,
pub(crate) sectorsize: u64,
pub(crate) partitions: Vec<Partition>,
}

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<PartitionTable> {
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<Utf8PathBuf>,
}
Expand Down Expand Up @@ -324,3 +375,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(())
}
}
4 changes: 2 additions & 2 deletions lib/src/bootloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ 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)
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<()> {
Expand Down
4 changes: 2 additions & 2 deletions lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ fn require_skopeo_with_containers_storage() -> Result<()> {

pub(crate) struct RootSetup {
luks_device: Option<String>,
device_info: crate::blockdev::Device,
device_info: crate::blockdev::PartitionTable,
rootfs: Utf8PathBuf,
rootfs_fd: Dir,
rootfs_uuid: Option<String>,
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 79b2f2a

Please sign in to comment.