← 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 with ~dbungert/curtin:integration-old-sfdisk as a prerequisite.

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


Requested reviews:
  Server Team CI bot (server-team-bot): continuous-integration
  curtin developers (curtin-dev)

For more details, see:
https://code.launchpad.net/~dbungert/curtin/+git/curtin/+merge/443380
-- 
Your team curtin developers is requested to review the proposed merge of ~dbungert/curtin:old-series-extended into curtin:master.
diff --git a/curtin/block/__init__.py b/curtin/block/__init__.py
index 2f2b60c..0e13a0d 100644
--- a/curtin/block/__init__.py
+++ b/curtin/block/__init__.py
@@ -1041,9 +1041,21 @@ 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
+    try:
+        # Some older series have the extended partition block device but return
+        # ENXIO when attempting to read it.
+        file_size = util.file_size(devname)
+    except OSError as ose:
+        if ose.errno == errno.ENXIO:
+            return False
+        else:
+            raise
+    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):
diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py
index 7988f3a..71035f9 100644
--- a/curtin/commands/block_meta.py
+++ b/curtin/commands/block_meta.py
@@ -854,17 +854,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 a666bcc..e640dcd 100644
--- a/tests/integration/test_block_meta.py
+++ b/tests/integration/test_block_meta.py
@@ -443,8 +443,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)
@@ -735,6 +744,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)
@@ -884,6 +895,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