Skip to content

Commit

Permalink
install: print warning when system may have more than one boot/root p…
Browse files Browse the repository at this point in the history
…artition

Inspired by: coreos/fedora-coreos-tracker#976

Signed-off-by: Nikita Dubrovskii <[email protected]>
  • Loading branch information
nikita-dubrovskii committed Oct 4, 2021
1 parent 31c5adf commit 500eb08
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 1 deletion.
269 changes: 268 additions & 1 deletion src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use gptman::{GPTPartitionEntry, GPT};
use nix::sys::stat::{major, minor};
use nix::{errno::Errno, mount, sched};
use regex::Regex;
use std::collections::HashMap;
use serde::Deserialize;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::env;
use std::fs::{
Expand Down Expand Up @@ -1515,3 +1516,269 @@ mod tests {
);
}
}

#[derive(Debug, Deserialize)]
struct BlockDevices {
pub blockdevices: Vec<Device>,
}

#[derive(Debug, Clone, Deserialize)]
struct Device {
pub name: String,
pub label: Option<String>,
pub uuid: Option<String>,
pub children: Option<Vec<Device>>,
}

fn count_partition_by_label(label: &str, devices: &[Device]) -> usize {
fn disks_flatten<'a>(root: &'a [Device], all: &mut HashMap<&'a str, HashSet<&'a str>>) {
for device in root {
if let Some(label) = device.label.as_ref() {
let uuid = match device.uuid.as_ref() {
Some(v) => v.as_str(),
_ => device.name.as_str(),
};
all.entry(label).or_default().insert(uuid);
}
if let Some(children) = device.children.as_ref() {
disks_flatten(children, all);
}
}
}

let mut all = HashMap::new();
disks_flatten(devices, &mut all);
eprintln!("{:?}", all);
match all.get(label) {
Some(v) => v.len(),
_ => 0,
}
}

pub fn check_single_partition(label: &str) -> Result<bool> {
let mut cmd = Command::new("lsblk");
cmd.arg("-o")
.arg("NAME,LABEL,UUID")
.arg("--noheadings")
.arg("--json")
.arg("--paths");
let output = cmd_output(&mut cmd)?;
let devices: BlockDevices = serde_json::from_str(&output)?;
Ok(count_partition_by_label(label, &devices.blockdevices) == 1)
}

#[cfg(test)]
mod partitions_by_label_tests {
use super::*;
#[test]
fn count_two_disks() {
let json = r#"
{
"blockdevices": [
{"name":"/dev/sda", "label":null, "uuid":null,
"children": [
{"name":"/dev/sda3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/sda4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
},
{"name":"/dev/dasda", "label":null, "uuid":null,
"children": [
{"name":"/dev/dasda1", "label":"boot", "uuid":"0ca76601-1ddd-4e1f-9d5a-f8a50fdcd091"},
{"name":"/dev/dasda2", "label":"root", "uuid":"82496045-9743-4484-89d5-869265d4a15c"}
]
}
]
}"#;

//when
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
//then
assert_eq!(2, count_partition_by_label("boot", &disks.blockdevices));
}

#[test]
fn count_two_paths_to_disk() {
let json = r#"
{
"blockdevices": [
{"name":"/dev/sda", "label":null, "uuid":null,
"children": [
{"name":"/dev/sda3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/sda4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
},
{"name":"/dev/sdb", "label":null, "uuid":null,
"children": [
{"name":"/dev/sdb3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/sdb4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
}
]
}"#;

//when
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
//then
assert_eq!(1, count_partition_by_label("boot", &disks.blockdevices));
}

#[test]
fn count_multipath() {
// given
let json = r#"
{
"blockdevices": [
{"name":"/dev/sda", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
}
]
},
{"name":"/dev/sdb", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
}
]
}
]
}"#;

//when
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
//then
assert_eq!(1, count_partition_by_label("boot", &disks.blockdevices));
}

#[test]
fn count_multipath_with_blockdevice() {
// given
let json = r#"
{
"blockdevices": [
{"name":"/dev/sda", "label":null, "uuid":null,
"children": [
{"name":"/dev/sda3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/sda4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
]
}
]
},
{"name":"/dev/sdb", "label":null, "uuid":null,
"children": [
{"name":"/dev/sdb3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/sdb4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
]
}
]
}
]
}"#;

//when
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
//then
assert_eq!(1, count_partition_by_label("boot", &disks.blockdevices));
}

#[test]
fn count_disk_and_multipath() {
// given
let json = r#"
{
"blockdevices": [
{"name":"/dev/sda", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
}
]
},
{"name":"/dev/sdb", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
]
}
]
},
{"name":"/dev/dasda", "label":null, "uuid":null,
"children": [
{"name":"/dev/dasda1", "label":"boot", "uuid":"0ca76601-1ddd-4e1f-9d5a-f8a50fdcd091"},
{"name":"/dev/dasda2", "label":"root", "uuid":"82496045-9743-4484-89d5-869265d4a15c"}
]
}
]
}"#;

//when
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
//then
assert_eq!(2, count_partition_by_label("boot", &disks.blockdevices));
}

#[test]
fn count_disk_and_multipath_with_blockdevice() {
// given
let json = r#"
{
"blockdevices": [
{"name":"/dev/sda", "label":null, "uuid":null,
"children": [
{"name":"/dev/sda3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/sda4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
]
}
]
},
{"name":"/dev/sdb", "label":null, "uuid":null,
"children": [
{"name":"/dev/sdb3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/sdb4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
"children": [
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
]
}
]
},
{"name":"/dev/dasda", "label":null, "uuid":null,
"children": [
{"name":"/dev/dasda1", "label":"boot", "uuid":"0ca76601-1ddd-4e1f-9d5a-f8a50fdcd091"},
{"name":"/dev/dasda2", "label":"root", "uuid":"82496045-9743-4484-89d5-869265d4a15c"}
]
}
]
}"#;

//when
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
//then
assert_eq!(2, count_partition_by_label("boot", &disks.blockdevices));
}
}
8 changes: 8 additions & 0 deletions src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ pub fn install(config: &InstallConfig) -> Result<()> {
bail!("install failed");
}

// warn if we have more than 1 partition with boot label
if !check_single_partition("boot")? {
eprintln!(
"System has several partitions with boot label. Please 'wipefs' other disks except {}",
config.device
);
}

eprintln!("Install complete.");
Ok(())
}
Expand Down

0 comments on commit 500eb08

Please sign in to comment.