Makes the whole routine a lot more robust by parsing the JSON output of `lsblk` instead of the human-readable output from `btrfs filesystem show`.
The labels of Btrfs filesystems are pretty much arbitrary labels, e.g. the following is a valid filesystem and thus output from `btrfs filesystem show`: Label: 'uuid: 70361d98-7492-45d4-a0e4-bf8fee9203a3' uuid: ab158685-c0b7-4540-a739-72c43a773282 Total devices 1 FS bytes used 144.00KiB devid 1 size 8.00GiB used 536.00MiB path /dev/sda .. which would break the current parsing code. Also drops the usage of a regex, thus being able to eliminate the whole regex machinery from the final binary. This reduces (stripped) binary size significantly, from 2.4 MiB to ~727 KiB, a ~70%(!) decrease. text data bss dec hex filename 2213016 261208 408 2474632 25c288 proxmox-chroot-old 702481 27776 360 730617 b25f9 proxmox-chroot-new No functional changes. Signed-off-by: Christoph Heiss <c.he...@proxmox.com> --- proxmox-chroot/Cargo.toml | 2 +- proxmox-chroot/src/main.rs | 48 +++++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/proxmox-chroot/Cargo.toml b/proxmox-chroot/Cargo.toml index c043938..a6a705d 100644 --- a/proxmox-chroot/Cargo.toml +++ b/proxmox-chroot/Cargo.toml @@ -9,6 +9,6 @@ homepage = "https://www.proxmox.com" [dependencies] anyhow.workspace = true -regex.workspace = true proxmox-installer-common = { workspace = true, features = [ "cli" ] } +serde = { workspace = true, features = [ "derive" ] } serde_json.workspace = true diff --git a/proxmox-chroot/src/main.rs b/proxmox-chroot/src/main.rs index 037f079..2cff630 100644 --- a/proxmox-chroot/src/main.rs +++ b/proxmox-chroot/src/main.rs @@ -18,7 +18,7 @@ use proxmox_installer_common::{ options::FsType, setup::{InstallConfig, SetupInfo}, }; -use regex::Regex; +use serde::Deserialize; const ANSWER_MP: &str = "answer"; static BINDMOUNTS: [&str; 4] = ["dev", "proc", "run", "sys"]; @@ -355,29 +355,49 @@ fn mount_btrfs(btrfs_uuid: Option<String>) -> Result<()> { Ok(()) } +/// Searches for all Btrfs filesystems present on the system. +/// +/// # Returns +/// +/// The UUID of that filesystem, if a single Btrfs filesystem is found. +/// If multiple are found, returns a (human-readable) error with all possible +/// filesystem UUIDs. fn get_btrfs_uuid() -> Result<String> { - let output = Command::new("btrfs") - .arg("filesystem") - .arg("show") + let output = Command::new("lsblk") + .args(["--json", "--fs", "--list", "--output", "fstype,uuid"]) .output()?; + if !output.status.success() { bail!( "Error checking for BTRFS file systems: {}", String::from_utf8(output.stderr)? ); } - let out = String::from_utf8(output.stdout)?; - let mut uuids = Vec::new(); - let re_uuid = - Regex::new(r"uuid: ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$")?; - for line in out.lines() { - if let Some(cap) = re_uuid.captures(line) { - if let Some(uuid) = cap.get(1) { - uuids.push(uuid.as_str()); - } - } + #[derive(Deserialize)] + struct Entry { + fstype: Option<String>, + uuid: Option<String>, } + + #[derive(Deserialize)] + struct LsblkOutput { + blockdevices: Vec<Entry>, + } + + let out: LsblkOutput = serde_json::from_slice(&output.stdout)?; + let uuids = out + .blockdevices + .iter() + .filter_map(|entry| match entry { + Entry { + fstype: Some(fstype), + uuid: Some(uuid), + } if fstype == "btrfs" => Some(uuid), + _ => None, + }) + .collect::<Vec<&String>>(); + match uuids.len() { 0 => bail!("Could not find any BTRFS UUID"), i if i > 1 => { -- 2.49.0 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel