Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ anyhow = "1.0.82"
camino = "1.1.6"
canon-json = "0.2.1"
cap-std-ext = "4.0.3"
cfg-if = "1.0"
chrono = { version = "0.4.38", default-features = false }
clap = "4.5.4"
clap_mangen = { version = "0.2.20" }
Expand Down
97 changes: 97 additions & 0 deletions crates/blockdev/src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,29 @@ impl PartitionTable {
.ok_or_else(|| anyhow::anyhow!("Missing partition for index {partno}"))?;
Ok(r)
}

/// Find the partition with the given type UUID (case-insensitive).
///
/// Partition type UUIDs are compared case-insensitively per the GPT specification,
/// as different tools may report them in different cases.
pub fn find_partition_of_type(&self, uuid: &str) -> Option<&Partition> {
self.partitions.iter().find(|p| p.parttype_matches(uuid))
}
}

impl Partition {
#[allow(dead_code)]
pub fn path(&self) -> &Utf8Path {
self.node.as_str().into()
}

/// Check if this partition's type matches the given UUID (case-insensitive).
///
/// Partition type UUIDs are compared case-insensitively per the GPT specification,
/// as different tools may report them in different cases.
pub fn parttype_matches(&self, uuid: &str) -> bool {
self.parttype.eq_ignore_ascii_case(uuid)
}
}

#[context("Listing partitions of {dev}")]
Expand Down Expand Up @@ -505,4 +521,85 @@ mod test {
);
Ok(())
}

#[test]
fn test_parttype_matches() {
let partition = Partition {
node: "/dev/loop0p1".to_string(),
start: 2048,
size: 8192,
parttype: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b".to_string(), // lowercase ESP UUID
uuid: Some("58A4C5F0-BD12-424C-B563-195AC65A25DD".to_string()),
name: Some("EFI System".to_string()),
};

// Test exact match (lowercase)
assert!(partition.parttype_matches("c12a7328-f81f-11d2-ba4b-00a0c93ec93b"));

// Test case-insensitive match (uppercase)
assert!(partition.parttype_matches("C12A7328-F81F-11D2-BA4B-00A0C93EC93B"));

// Test case-insensitive match (mixed case)
assert!(partition.parttype_matches("C12a7328-F81f-11d2-Ba4b-00a0C93ec93b"));

// Test non-match
assert!(!partition.parttype_matches("0FC63DAF-8483-4772-8E79-3D69D8477DE4"));
}

#[test]
fn test_find_partition_of_type() -> 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": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B",
"uuid": "58A4C5F0-BD12-424C-B563-195AC65A25DD",
"name": "EFI System"
},{
"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();

// Find ESP partition using lowercase UUID (should match uppercase in fixture)
let esp = table
.partitiontable
.find_partition_of_type("c12a7328-f81f-11d2-ba4b-00a0c93ec93b");
assert!(esp.is_some());
assert_eq!(esp.unwrap().node, "/dev/loop0p1");

// Find root partition using uppercase UUID (should match case-insensitively)
let root = table
.partitiontable
.find_partition_of_type("0fc63daf-8483-4772-8e79-3d69d8477de4");
assert!(root.is_some());
assert_eq!(root.unwrap().node, "/dev/loop0p2");

// Try to find non-existent partition type
let nonexistent = table
.partitiontable
.find_partition_of_type("00000000-0000-0000-0000-000000000000");
assert!(nonexistent.is_none());

Ok(())
}
}
1 change: 1 addition & 0 deletions crates/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ anyhow = { workspace = true }
camino = { workspace = true, features = ["serde1"] }
canon-json = { workspace = true }
cap-std-ext = { workspace = true, features = ["fs_utf8"] }
cfg-if = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
clap = { workspace = true, features = ["derive","cargo"] }
clap_mangen = { workspace = true, optional = true }
Expand Down
5 changes: 3 additions & 2 deletions crates/lib/src/bootc_composefs/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ use crate::{
BOOT_LOADER_ENTRIES, COMPOSEFS_CMDLINE, ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST,
STAGED_BOOT_LOADER_ENTRIES, STATE_DIR_ABS, USER_CFG, USER_CFG_STAGED,
},
install::{dps_uuid::DPS_UUID, RW_KARG},
discoverable_partition_specification::this_arch_root,
install::RW_KARG,
spec::{Bootloader, Host},
};

Expand Down Expand Up @@ -400,7 +401,7 @@ pub(crate) fn setup_composefs_bls_boot(
Utf8PathBuf::from("/sysroot"),
get_esp_partition(&sysroot_parent)?.0,
[
format!("root=UUID={DPS_UUID}"),
format!("root=UUID={}", this_arch_root()),
RW_KARG.to_string(),
format!("{COMPOSEFS_CMDLINE}={id_hex}"),
]
Expand Down
12 changes: 3 additions & 9 deletions crates/lib/src/bootloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,19 @@ use bootc_mount as mount;

#[cfg(any(feature = "composefs-backend", feature = "install-to-disk"))]
use crate::bootc_composefs::boot::mount_esp;
use crate::utils;
use crate::{discoverable_partition_specification, utils};

/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
pub(crate) const EFI_DIR: &str = "efi";
/// The EFI system partition GUID
#[allow(dead_code)]
pub(crate) const ESP_GUID: &str = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B";
/// Path to the bootupd update payload
#[allow(dead_code)]
const BOOTUPD_UPDATES: &str = "usr/lib/bootupd/updates";

#[allow(dead_code)]
pub(crate) fn esp_in(device: &PartitionTable) -> Result<&Partition> {
device
.partitions
.iter()
.find(|p| p.parttype.as_str() == ESP_GUID)
.find_partition_of_type(discoverable_partition_specification::ESP)
.ok_or(anyhow::anyhow!("ESP not found in partition table"))
}

Expand Down Expand Up @@ -84,9 +80,7 @@ pub(crate) fn install_systemd_boot(
_deployment_path: Option<&str>,
) -> Result<()> {
let esp_part = device
.partitions
.iter()
.find(|p| p.parttype.as_str() == ESP_GUID)
.find_partition_of_type(discoverable_partition_specification::ESP)
.ok_or_else(|| anyhow::anyhow!("ESP partition not found"))?;

let esp_mount = mount_esp(&esp_part.node).context("Mounting ESP")?;
Expand Down
Loading