← Back to team overview

curtin-dev team mailing list archive

[Merge] ~dbungert/curtin:old-series-extended into curtin:master

 

Dan Bungert has proposed merging ~dbungert/curtin:old-series-extended into curtin:master.

Commit message:
fixes and workarounds for extended partitions on old series


Requested reviews:
  Michael Hudson-Doyle (mwhudson)
  Server Team CI bot (server-team-bot): continuous-integration

For more details, see:
https://code.launchpad.net/~dbungert/curtin/+git/curtin/+merge/443512
-- 
Your team curtin developers is subscribed to branch curtin:master.
diff --git a/curtin/block/__init__.py b/curtin/block/__init__.py
index 2f69bd3..1caa5e3 100644
--- a/curtin/block/__init__.py
+++ b/curtin/block/__init__.py
@@ -1042,9 +1042,13 @@ def check_dos_signature(device):
     # this signature must be at 0x1fe
     # https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout
     devname = dev_path(path_to_kname(device))
-    return (is_block_device(devname) and util.file_size(devname) >= 0x200 and
-            (util.load_file(devname, decode=False, read_len=2, offset=0x1fe) ==
-             b'\x55\xAA'))
+    if not is_block_device(devname):
+        return False
+    file_size = util.file_size(devname)
+    if file_size < 0x200:
+        return False
+    signature = util.load_file(devname, decode=False, read_len=2, offset=0x1fe)
+    return signature == b'\x55\xAA'
 
 
 def check_efi_signature(device):
@@ -1085,9 +1089,20 @@ def is_extended_partition(device):
     # within the first 4 partitions and will have a valid dos signature,
     # because the format of the extended partition matches that of a real mbr
     (parent_dev, part_number) = get_blockdev_for_partition(device)
-    return (get_part_table_type(parent_dev) in ['dos', 'msdos'] and
-            part_number is not None and int(part_number) <= 4 and
-            check_dos_signature(device))
+    if (get_part_table_type(parent_dev) in ['dos', 'msdos'] and
+            part_number is not None and int(part_number) <= 4):
+        try:
+            return check_dos_signature(device)
+        except OSError as ose:
+            # Some older series have the extended partition block device but return
+            # ENXIO when attempting to read it.  Make a best guess from the
+            # parent_dev.
+            if ose.errno == errno.ENXIO:
+                return check_dos_signature(parent_dev)
+            else:
+                raise
+    else:
+        return False
 
 
 def is_zfs_member(device):
diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py
index 5e670ae..6ce8440 100644
--- a/curtin/commands/block_meta.py
+++ b/curtin/commands/block_meta.py
@@ -861,17 +861,28 @@ def calc_dm_partition_info(partition_kname):
 
 
 def calc_partition_info(partition_kname, logical_block_size_bytes):
+    p_size_sec = 0
+    p_start_sec = 0
     if partition_kname.startswith('dm-'):
         p_start, p_size = calc_dm_partition_info(partition_kname)
     else:
         pdir = block.sys_block_path(partition_kname)
         p_size = int(util.load_file(os.path.join(pdir, "size")))
         p_start = int(util.load_file(os.path.join(pdir, "start")))
+        if not all([p_size, p_start]):
+            # if sysfs reported a 0, let's try sfdisk
+            sfdisk_info = block.sfdisk_info(partition_kname)
+            part_path = block.kname_to_path(partition_kname)
+            part_info = block.get_partition_sfdisk_info(part_path, sfdisk_info)
+            p_size_sec = part_info['size']
+            p_start_sec = part_info['start']
 
     # NB: sys/block/X/{size,start} and dmsetup output are both always
     # in 512b sectors
-    p_size_sec = p_size * 512 // logical_block_size_bytes
-    p_start_sec = p_start * 512 // logical_block_size_bytes
+    if p_size_sec == 0:
+        p_size_sec = p_size * 512 // logical_block_size_bytes
+    if p_start_sec == 0:
+        p_start_sec = p_start * 512 // logical_block_size_bytes
 
     LOG.debug("calc_partition_info: %s size_sectors=%s start_sectors=%s",
               partition_kname, p_size_sec, p_start_sec)
diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py
index dc7f8a1..a2368e8 100644
--- a/tests/integration/test_block_meta.py
+++ b/tests/integration/test_block_meta.py
@@ -426,8 +426,17 @@ class TestBlockMeta(IntegrationTestCase):
                     PartData(number=6, offset=13 << 20, size=10 << 20),
                 ])
 
-            p1kname = block.partition_kname(block.path_to_kname(dev), 1)
-            self.assertTrue(block.is_extended_partition('/dev/' + p1kname))
+            if distro.lsb_release()['release'] >= '20.04':
+                p1kname = block.partition_kname(block.path_to_kname(dev), 1)
+                self.assertTrue(block.is_extended_partition('/dev/' + p1kname))
+            else:
+                # on Bionic and earlier, the block device for the extended
+                # partition is not functional, so attempting to verify it is
+                # expected to fail.  So just read the value directly from the
+                # expected signature location.
+                signature = util.load_file(dev, decode=False,
+                                           read_len=2, offset=0x1001fe)
+                self.assertEqual(b'\x55\xAA', signature)
 
     def test_logical_v1(self):
         self._test_logical(1)
@@ -718,6 +727,8 @@ class TestBlockMeta(IntegrationTestCase):
                     PartData(number=6, offset=13 << 20, size=20 << 20),
                 ])
 
+    @skipIf(distro.lsb_release()['release'] < '20.04',
+            'old lsblk will not list info about extended partitions')
     def test_resize_extended(self):
         img = self.tmp_path('image.img')
         config = StorageConfigBuilder(version=2)
@@ -867,6 +878,8 @@ class TestBlockMeta(IntegrationTestCase):
             self.assertEqual(139 << 20, _get_filesystem_size(dev, p2))
             self.assertEqual(50 << 20, _get_filesystem_size(dev, p3))
 
+    @skipIf(distro.lsb_release()['release'] < '20.04',
+            'old lsblk will not list info about extended partitions')
     def test_mix_of_operations_msdos(self):
         # a test that keeps, creates, resizes, and deletes a partition
         # including handling of extended/logical

Follow ups