From 858436dfda11158ea4bb9e17195dba7f62b30b74 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 23 Nov 2021 21:09:49 -0700 Subject: [PATCH] binman: Allow listing an image created by a newer version If an older version of binman is used to list images created by a newer one, it is possible that it will contain entry types that are not supported. At present this produces an error. Adjust binman to use a plain 'blob' entry type to cope with this, so the image can at least be listed. Signed-off-by: Simon Glass --- tools/binman/binman.rst | 5 +++ tools/binman/entry.py | 65 +++++++++++++++++++++++++++-------- tools/binman/entry_test.py | 9 +++++ tools/binman/etype/section.py | 3 +- tools/binman/image.py | 10 ++++-- 5 files changed, 74 insertions(+), 18 deletions(-) diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 210d0c5c51..26f462ae16 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -913,6 +913,11 @@ or with wildcards:: u-boot-dtb 180 108 u-boot-dtb 80 3b5 image-header bf8 8 image-header bf8 +If an older version of binman is used to list images created by a newer one, it +is possible that it will contain entry types that are not supported. These still +show with the correct type, but binman just sees them as blobs (plain binary +data). Any special features of that etype are not supported by the old binman. + Extracting files from images ---------------------------- diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 2205bc8d92..e7a8365fd5 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -102,7 +102,7 @@ class Entry(object): self.allow_missing = False @staticmethod - def Lookup(node_path, etype, expanded): + def FindEntryClass(etype, expanded): """Look up the entry class for a node. Args: @@ -113,10 +113,9 @@ class Entry(object): Returns: The entry class object if found, else None if not found and expanded - is True - - Raise: - ValueError if expanded is False and the class is not found + is True, else a tuple: + module name that could not be found + exception received """ # Convert something like 'u-boot@0' to 'u_boot' since we are only # interested in the type. @@ -137,30 +136,66 @@ class Entry(object): except ImportError as e: if expanded: return None - raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" % - (etype, node_path, module_name, e)) + return module_name, e modules[module_name] = module # Look up the expected class name return getattr(module, 'Entry_%s' % module_name) @staticmethod - def Create(section, node, etype=None, expanded=False): + def Lookup(node_path, etype, expanded, missing_etype=False): + """Look up the entry class for a node. + + Args: + node_node (str): Path name of Node object containing information + about the entry to create (used for errors) + etype (str): Entry type to use + expanded (bool): Use the expanded version of etype + missing_etype (bool): True to default to a blob etype if the + requested etype is not found + + Returns: + The entry class object if found, else None if not found and expanded + is True + + Raise: + ValueError if expanded is False and the class is not found + """ + # Convert something like 'u-boot@0' to 'u_boot' since we are only + # interested in the type. + cls = Entry.FindEntryClass(etype, expanded) + if cls is None: + return None + elif isinstance(cls, tuple): + if missing_etype: + cls = Entry.FindEntryClass('blob', False) + if isinstance(cls, tuple): # This should not fail + module_name, e = cls + raise ValueError( + "Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" % + (etype, node_path, module_name, e)) + return cls + + @staticmethod + def Create(section, node, etype=None, expanded=False, missing_etype=False): """Create a new entry for a node. Args: - section: Section object containing this node - node: Node object containing information about the entry to - create - etype: Entry type to use, or None to work it out (used for tests) - expanded: True to use expanded versions of entries, where available + section (entry_Section): Section object containing this node + node (Node): Node object containing information about the entry to + create + etype (str): Entry type to use, or None to work it out (used for + tests) + expanded (bool): Use the expanded version of etype + missing_etype (bool): True to default to a blob etype if the + requested etype is not found Returns: A new Entry object of the correct type (a subclass of Entry) """ if not etype: etype = fdt_util.GetString(node, 'type', node.name) - obj = Entry.Lookup(node.path, etype, expanded) + obj = Entry.Lookup(node.path, etype, expanded, missing_etype) if obj and expanded: # Check whether to use the expanded entry new_etype = etype + '-expanded' @@ -170,7 +205,7 @@ class Entry(object): else: obj = None if not obj: - obj = Entry.Lookup(node.path, etype, False) + obj = Entry.Lookup(node.path, etype, False, missing_etype) # Call its constructor to get the object we want. return obj(section, etype, node) diff --git a/tools/binman/entry_test.py b/tools/binman/entry_test.py index c3d5f3eef4..1b59c9056e 100644 --- a/tools/binman/entry_test.py +++ b/tools/binman/entry_test.py @@ -10,6 +10,7 @@ import sys import unittest from binman import entry +from binman.etype.blob import Entry_blob from dtoc import fdt from dtoc import fdt_util from patman import tools @@ -100,5 +101,13 @@ class TestEntry(unittest.TestCase): self.assertIn("Unknown entry type 'missing' in node '/binman/u-boot'", str(e.exception)) + def testMissingEtype(self): + """Test use of a blob etype when the requested one is not available""" + ent = entry.Entry.Create(None, self.GetNode(), 'missing', + missing_etype=True) + self.assertTrue(isinstance(ent, Entry_blob)) + self.assertEquals('missing', ent.etype) + + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 2e01dccc6d..6ce07dd37d 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -185,7 +185,8 @@ class Entry_section(Entry): if node.name.startswith('hash') or node.name.startswith('signature'): continue entry = Entry.Create(self, node, - expanded=self.GetImage().use_expanded) + expanded=self.GetImage().use_expanded, + missing_etype=self.GetImage().missing_etype) entry.ReadNode() entry.SetPrefix(self._name_prefix) self._entries[node.name] = entry diff --git a/tools/binman/image.py b/tools/binman/image.py index cdc58b39a4..891e8b488e 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -63,9 +63,13 @@ class Image(section.Entry_section): to ignore 'u-boot-bin' in this case, and build it ourselves in binman with 'u-boot-dtb.bin' and 'u-boot.dtb'. See Entry_u_boot_expanded and Entry_blob_phase for details. + missing_etype: Use a default entry type ('blob') if the requested one + does not exist in binman. This is useful if an image was created by + binman a newer version of binman but we want to list it in an older + version which does not support all the entry types. """ def __init__(self, name, node, copy_to_orig=True, test=False, - ignore_missing=False, use_expanded=False): + ignore_missing=False, use_expanded=False, missing_etype=False): super().__init__(None, 'section', node, test=test) self.copy_to_orig = copy_to_orig self.name = 'main-section' @@ -75,6 +79,7 @@ class Image(section.Entry_section): self.fdtmap_data = None self.allow_repack = False self._ignore_missing = ignore_missing + self.missing_etype = missing_etype self.use_expanded = use_expanded self.test_section_timeout = False if not test: @@ -124,7 +129,8 @@ class Image(section.Entry_section): # Return an Image with the associated nodes root = dtb.GetRoot() - image = Image('image', root, copy_to_orig=False, ignore_missing=True) + image = Image('image', root, copy_to_orig=False, ignore_missing=True, + missing_etype=True) image.image_node = fdt_util.GetString(root, 'image-node', 'image') image.fdtmap_dtb = dtb -- 2.39.5