Skip to content

Commit 500eb08

Browse files
install: print warning when system may have more than one boot/root partition
Inspired by: coreos/fedora-coreos-tracker#976 Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
1 parent 31c5adf commit 500eb08

2 files changed

Lines changed: 276 additions & 1 deletion

File tree

src/blockdev.rs

Lines changed: 268 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use gptman::{GPTPartitionEntry, GPT};
1717
use nix::sys::stat::{major, minor};
1818
use nix::{errno::Errno, mount, sched};
1919
use regex::Regex;
20-
use std::collections::HashMap;
20+
use serde::Deserialize;
21+
use std::collections::{HashMap, HashSet};
2122
use std::convert::TryInto;
2223
use std::env;
2324
use std::fs::{
@@ -1515,3 +1516,269 @@ mod tests {
15151516
);
15161517
}
15171518
}
1519+
1520+
#[derive(Debug, Deserialize)]
1521+
struct BlockDevices {
1522+
pub blockdevices: Vec<Device>,
1523+
}
1524+
1525+
#[derive(Debug, Clone, Deserialize)]
1526+
struct Device {
1527+
pub name: String,
1528+
pub label: Option<String>,
1529+
pub uuid: Option<String>,
1530+
pub children: Option<Vec<Device>>,
1531+
}
1532+
1533+
fn count_partition_by_label(label: &str, devices: &[Device]) -> usize {
1534+
fn disks_flatten<'a>(root: &'a [Device], all: &mut HashMap<&'a str, HashSet<&'a str>>) {
1535+
for device in root {
1536+
if let Some(label) = device.label.as_ref() {
1537+
let uuid = match device.uuid.as_ref() {
1538+
Some(v) => v.as_str(),
1539+
_ => device.name.as_str(),
1540+
};
1541+
all.entry(label).or_default().insert(uuid);
1542+
}
1543+
if let Some(children) = device.children.as_ref() {
1544+
disks_flatten(children, all);
1545+
}
1546+
}
1547+
}
1548+
1549+
let mut all = HashMap::new();
1550+
disks_flatten(devices, &mut all);
1551+
eprintln!("{:?}", all);
1552+
match all.get(label) {
1553+
Some(v) => v.len(),
1554+
_ => 0,
1555+
}
1556+
}
1557+
1558+
pub fn check_single_partition(label: &str) -> Result<bool> {
1559+
let mut cmd = Command::new("lsblk");
1560+
cmd.arg("-o")
1561+
.arg("NAME,LABEL,UUID")
1562+
.arg("--noheadings")
1563+
.arg("--json")
1564+
.arg("--paths");
1565+
let output = cmd_output(&mut cmd)?;
1566+
let devices: BlockDevices = serde_json::from_str(&output)?;
1567+
Ok(count_partition_by_label(label, &devices.blockdevices) == 1)
1568+
}
1569+
1570+
#[cfg(test)]
1571+
mod partitions_by_label_tests {
1572+
use super::*;
1573+
#[test]
1574+
fn count_two_disks() {
1575+
let json = r#"
1576+
{
1577+
"blockdevices": [
1578+
{"name":"/dev/sda", "label":null, "uuid":null,
1579+
"children": [
1580+
{"name":"/dev/sda3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1581+
{"name":"/dev/sda4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1582+
]
1583+
},
1584+
{"name":"/dev/dasda", "label":null, "uuid":null,
1585+
"children": [
1586+
{"name":"/dev/dasda1", "label":"boot", "uuid":"0ca76601-1ddd-4e1f-9d5a-f8a50fdcd091"},
1587+
{"name":"/dev/dasda2", "label":"root", "uuid":"82496045-9743-4484-89d5-869265d4a15c"}
1588+
]
1589+
}
1590+
]
1591+
}"#;
1592+
1593+
//when
1594+
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
1595+
//then
1596+
assert_eq!(2, count_partition_by_label("boot", &disks.blockdevices));
1597+
}
1598+
1599+
#[test]
1600+
fn count_two_paths_to_disk() {
1601+
let json = r#"
1602+
{
1603+
"blockdevices": [
1604+
{"name":"/dev/sda", "label":null, "uuid":null,
1605+
"children": [
1606+
{"name":"/dev/sda3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1607+
{"name":"/dev/sda4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1608+
]
1609+
},
1610+
{"name":"/dev/sdb", "label":null, "uuid":null,
1611+
"children": [
1612+
{"name":"/dev/sdb3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1613+
{"name":"/dev/sdb4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1614+
]
1615+
}
1616+
]
1617+
}"#;
1618+
1619+
//when
1620+
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
1621+
//then
1622+
assert_eq!(1, count_partition_by_label("boot", &disks.blockdevices));
1623+
}
1624+
1625+
#[test]
1626+
fn count_multipath() {
1627+
// given
1628+
let json = r#"
1629+
{
1630+
"blockdevices": [
1631+
{"name":"/dev/sda", "label":null, "uuid":null,
1632+
"children": [
1633+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1634+
"children": [
1635+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1636+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1637+
]
1638+
}
1639+
]
1640+
},
1641+
{"name":"/dev/sdb", "label":null, "uuid":null,
1642+
"children": [
1643+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1644+
"children": [
1645+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1646+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1647+
]
1648+
}
1649+
]
1650+
}
1651+
]
1652+
}"#;
1653+
1654+
//when
1655+
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
1656+
//then
1657+
assert_eq!(1, count_partition_by_label("boot", &disks.blockdevices));
1658+
}
1659+
1660+
#[test]
1661+
fn count_multipath_with_blockdevice() {
1662+
// given
1663+
let json = r#"
1664+
{
1665+
"blockdevices": [
1666+
{"name":"/dev/sda", "label":null, "uuid":null,
1667+
"children": [
1668+
{"name":"/dev/sda3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1669+
{"name":"/dev/sda4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
1670+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1671+
"children": [
1672+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1673+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
1674+
]
1675+
}
1676+
]
1677+
},
1678+
{"name":"/dev/sdb", "label":null, "uuid":null,
1679+
"children": [
1680+
{"name":"/dev/sdb3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1681+
{"name":"/dev/sdb4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
1682+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1683+
"children": [
1684+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1685+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
1686+
]
1687+
}
1688+
]
1689+
}
1690+
]
1691+
}"#;
1692+
1693+
//when
1694+
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
1695+
//then
1696+
assert_eq!(1, count_partition_by_label("boot", &disks.blockdevices));
1697+
}
1698+
1699+
#[test]
1700+
fn count_disk_and_multipath() {
1701+
// given
1702+
let json = r#"
1703+
{
1704+
"blockdevices": [
1705+
{"name":"/dev/sda", "label":null, "uuid":null,
1706+
"children": [
1707+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1708+
"children": [
1709+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1710+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1711+
]
1712+
}
1713+
]
1714+
},
1715+
{"name":"/dev/sdb", "label":null, "uuid":null,
1716+
"children": [
1717+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1718+
"children": [
1719+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b168dfd5-7ea6-49fb-a006-a241c35b46da"},
1720+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"50a003eb-6708-4f52-8ece-3e9a4a6c838f"}
1721+
]
1722+
}
1723+
]
1724+
},
1725+
{"name":"/dev/dasda", "label":null, "uuid":null,
1726+
"children": [
1727+
{"name":"/dev/dasda1", "label":"boot", "uuid":"0ca76601-1ddd-4e1f-9d5a-f8a50fdcd091"},
1728+
{"name":"/dev/dasda2", "label":"root", "uuid":"82496045-9743-4484-89d5-869265d4a15c"}
1729+
]
1730+
}
1731+
]
1732+
}"#;
1733+
1734+
//when
1735+
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
1736+
//then
1737+
assert_eq!(2, count_partition_by_label("boot", &disks.blockdevices));
1738+
}
1739+
1740+
#[test]
1741+
fn count_disk_and_multipath_with_blockdevice() {
1742+
// given
1743+
let json = r#"
1744+
{
1745+
"blockdevices": [
1746+
{"name":"/dev/sda", "label":null, "uuid":null,
1747+
"children": [
1748+
{"name":"/dev/sda3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1749+
{"name":"/dev/sda4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
1750+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1751+
"children": [
1752+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1753+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
1754+
]
1755+
}
1756+
]
1757+
},
1758+
{"name":"/dev/sdb", "label":null, "uuid":null,
1759+
"children": [
1760+
{"name":"/dev/sdb3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1761+
{"name":"/dev/sdb4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"},
1762+
{"name":"/dev/mapper/mpatha", "label":null, "uuid":null,
1763+
"children": [
1764+
{"name":"/dev/mapper/mpatha3", "label":"boot", "uuid":"b5aea785-3d60-4455-ae8d-a3ba06132157"},
1765+
{"name":"/dev/mapper/mpatha4", "label":"root", "uuid":"1948b11c-40ec-47d0-af67-0869928e50b8"}
1766+
]
1767+
}
1768+
]
1769+
},
1770+
{"name":"/dev/dasda", "label":null, "uuid":null,
1771+
"children": [
1772+
{"name":"/dev/dasda1", "label":"boot", "uuid":"0ca76601-1ddd-4e1f-9d5a-f8a50fdcd091"},
1773+
{"name":"/dev/dasda2", "label":"root", "uuid":"82496045-9743-4484-89d5-869265d4a15c"}
1774+
]
1775+
}
1776+
]
1777+
}"#;
1778+
1779+
//when
1780+
let disks: BlockDevices = serde_json::from_str(&json).unwrap();
1781+
//then
1782+
assert_eq!(2, count_partition_by_label("boot", &disks.blockdevices));
1783+
}
1784+
}

src/install.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,14 @@ pub fn install(config: &InstallConfig) -> Result<()> {
241241
bail!("install failed");
242242
}
243243

244+
// warn if we have more than 1 partition with boot label
245+
if !check_single_partition("boot")? {
246+
eprintln!(
247+
"System has several partitions with boot label. Please 'wipefs' other disks except {}",
248+
config.device
249+
);
250+
}
251+
244252
eprintln!("Install complete.");
245253
Ok(())
246254
}

0 commit comments

Comments
 (0)