@@ -17,7 +17,8 @@ use gptman::{GPTPartitionEntry, GPT};
1717use nix:: sys:: stat:: { major, minor} ;
1818use nix:: { errno:: Errno , mount, sched} ;
1919use regex:: Regex ;
20- use std:: collections:: HashMap ;
20+ use serde:: Deserialize ;
21+ use std:: collections:: { HashMap , HashSet } ;
2122use std:: convert:: TryInto ;
2223use std:: env;
2324use 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+ }
0 commit comments