use std::path::Path; use color_eyre::eyre::eyre; use gpt::disk::LogicalBlockSize; use gpt::GptConfig; use crate::disk::util::DiskInfo; use crate::disk::OsPartitionInfo; use crate::os_install::partition_for; use crate::Error; pub async fn partition(disk: &DiskInfo, overwrite: bool) -> Result { let efi = { let disk = disk.clone(); tokio::task::spawn_blocking(move || { let use_efi = Path::new("/sys/firmware/efi").exists(); let mut device = Box::new( std::fs::File::options() .read(true) .write(true) .open(&disk.logicalname)?, ); let (mut gpt, guid_part) = if overwrite { let mbr = gpt::mbr::ProtectiveMBR::with_lb_size( u32::try_from((disk.capacity / 512) - 1).unwrap_or(0xFF_FF_FF_FF), ); mbr.overwrite_lba0(&mut device)?; ( GptConfig::new() .writable(true) .initialized(false) .logical_block_size(LogicalBlockSize::Lb512) .create_from_device(device, None)?, None, ) } else { let gpt = GptConfig::new() .writable(true) .initialized(true) .logical_block_size(LogicalBlockSize::Lb512) .open_from_device(device)?; let mut guid_part = None; for (idx, part_info) in disk .partitions .iter() .enumerate() .map(|(idx, x)| (idx + 1, x)) { if let Some(entry) = gpt.partitions().get(&(idx as u32)) { if part_info.guid.is_some() { if entry.first_lba < if use_efi { 33759266 } else { 33570850 } { return Err(Error::new( eyre!("Not enough space before embassy data"), crate::ErrorKind::InvalidRequest, )); } guid_part = Some(entry.clone()); break; } } } (gpt, guid_part) }; gpt.update_partitions(Default::default())?; let efi = if use_efi { gpt.add_partition("efi", 100 * 1024 * 1024, gpt::partition_types::EFI, 0, None)?; true } else { gpt.add_partition( "bios-grub", 8 * 1024 * 1024, gpt::partition_types::BIOS, 0, None, )?; false }; gpt.add_partition( "boot", 1024 * 1024 * 1024, gpt::partition_types::LINUX_FS, 0, None, )?; gpt.add_partition( "root", 15 * 1024 * 1024 * 1024, match *crate::ARCH { "x86_64" => gpt::partition_types::LINUX_ROOT_X64, "aarch64" => gpt::partition_types::LINUX_ROOT_ARM_64, _ => gpt::partition_types::LINUX_FS, }, 0, None, )?; if overwrite { gpt.add_partition( "data", gpt.find_free_sectors() .iter() .map(|(_, size)| *size * u64::from(*gpt.logical_block_size())) .max() .ok_or_else(|| { Error::new( eyre!("No free space left on device"), crate::ErrorKind::BlockDevice, ) })?, gpt::partition_types::LINUX_LVM, 0, None, )?; } else if let Some(guid_part) = guid_part { let mut parts = gpt.partitions().clone(); parts.insert(gpt.find_next_partition_id(), guid_part); gpt.update_partitions(parts)?; } gpt.write()?; Ok(efi) }) .await .unwrap()? }; Ok(OsPartitionInfo { efi: efi.then(|| partition_for(&disk.logicalname, 1)), bios: (!efi).then(|| partition_for(&disk.logicalname, 1)), boot: partition_for(&disk.logicalname, 2), root: partition_for(&disk.logicalname, 3), }) }