[PATCH 2/7] binman: Allow listing an image created by a newer version

Simon Glass sjg at chromium.org
Wed Nov 24 05:09:49 CET 2021


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 <sjg at chromium.org>
---

 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 210d0c5c51b..26f462ae16f 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 2205bc8d923..e7a8365fd51 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 at 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 at 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 c3d5f3eef48..1b59c9056ec 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 2e01dccc6db..6ce07dd37d7 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 cdc58b39a40..891e8b488e9 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.34.0.rc2.393.gf8c9666880-goog



More information about the U-Boot mailing list