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 <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-11-23 21:09:49 -07:00
parent 7945077f79
commit 858436dfda
5 changed files with 74 additions and 18 deletions

View file

@ -913,6 +913,11 @@ or with wildcards::
u-boot-dtb 180 108 u-boot-dtb 80 3b5 u-boot-dtb 180 108 u-boot-dtb 80 3b5
image-header bf8 8 image-header bf8 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 Extracting files from images
---------------------------- ----------------------------

View file

@ -102,7 +102,7 @@ class Entry(object):
self.allow_missing = False self.allow_missing = False
@staticmethod @staticmethod
def Lookup(node_path, etype, expanded): def FindEntryClass(etype, expanded):
"""Look up the entry class for a node. """Look up the entry class for a node.
Args: Args:
@ -113,10 +113,9 @@ class Entry(object):
Returns: Returns:
The entry class object if found, else None if not found and expanded The entry class object if found, else None if not found and expanded
is True is True, else a tuple:
module name that could not be found
Raise: exception received
ValueError if expanded is False and the class is not found
""" """
# Convert something like 'u-boot@0' to 'u_boot' since we are only # Convert something like 'u-boot@0' to 'u_boot' since we are only
# interested in the type. # interested in the type.
@ -137,30 +136,66 @@ class Entry(object):
except ImportError as e: except ImportError as e:
if expanded: if expanded:
return None return None
raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" % return module_name, e
(etype, node_path, module_name, e))
modules[module_name] = module modules[module_name] = module
# Look up the expected class name # Look up the expected class name
return getattr(module, 'Entry_%s' % module_name) return getattr(module, 'Entry_%s' % module_name)
@staticmethod @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. """Create a new entry for a node.
Args: Args:
section: Section object containing this node section (entry_Section): Section object containing this node
node: Node object containing information about the entry to node (Node): Node object containing information about the entry to
create create
etype: Entry type to use, or None to work it out (used for tests) etype (str): Entry type to use, or None to work it out (used for
expanded: True to use expanded versions of entries, where available 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: Returns:
A new Entry object of the correct type (a subclass of Entry) A new Entry object of the correct type (a subclass of Entry)
""" """
if not etype: if not etype:
etype = fdt_util.GetString(node, 'type', node.name) 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: if obj and expanded:
# Check whether to use the expanded entry # Check whether to use the expanded entry
new_etype = etype + '-expanded' new_etype = etype + '-expanded'
@ -170,7 +205,7 @@ class Entry(object):
else: else:
obj = None obj = None
if not obj: 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. # Call its constructor to get the object we want.
return obj(section, etype, node) return obj(section, etype, node)

View file

@ -10,6 +10,7 @@ import sys
import unittest import unittest
from binman import entry from binman import entry
from binman.etype.blob import Entry_blob
from dtoc import fdt from dtoc import fdt
from dtoc import fdt_util from dtoc import fdt_util
from patman import tools from patman import tools
@ -100,5 +101,13 @@ class TestEntry(unittest.TestCase):
self.assertIn("Unknown entry type 'missing' in node '/binman/u-boot'", self.assertIn("Unknown entry type 'missing' in node '/binman/u-boot'",
str(e.exception)) 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__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -185,7 +185,8 @@ class Entry_section(Entry):
if node.name.startswith('hash') or node.name.startswith('signature'): if node.name.startswith('hash') or node.name.startswith('signature'):
continue continue
entry = Entry.Create(self, node, entry = Entry.Create(self, node,
expanded=self.GetImage().use_expanded) expanded=self.GetImage().use_expanded,
missing_etype=self.GetImage().missing_etype)
entry.ReadNode() entry.ReadNode()
entry.SetPrefix(self._name_prefix) entry.SetPrefix(self._name_prefix)
self._entries[node.name] = entry self._entries[node.name] = entry

View file

@ -63,9 +63,13 @@ class Image(section.Entry_section):
to ignore 'u-boot-bin' in this case, and build it ourselves in to ignore 'u-boot-bin' in this case, and build it ourselves in
binman with 'u-boot-dtb.bin' and 'u-boot.dtb'. See binman with 'u-boot-dtb.bin' and 'u-boot.dtb'. See
Entry_u_boot_expanded and Entry_blob_phase for details. 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, 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) super().__init__(None, 'section', node, test=test)
self.copy_to_orig = copy_to_orig self.copy_to_orig = copy_to_orig
self.name = 'main-section' self.name = 'main-section'
@ -75,6 +79,7 @@ class Image(section.Entry_section):
self.fdtmap_data = None self.fdtmap_data = None
self.allow_repack = False self.allow_repack = False
self._ignore_missing = ignore_missing self._ignore_missing = ignore_missing
self.missing_etype = missing_etype
self.use_expanded = use_expanded self.use_expanded = use_expanded
self.test_section_timeout = False self.test_section_timeout = False
if not test: if not test:
@ -124,7 +129,8 @@ class Image(section.Entry_section):
# Return an Image with the associated nodes # Return an Image with the associated nodes
root = dtb.GetRoot() 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.image_node = fdt_util.GetString(root, 'image-node', 'image')
image.fdtmap_dtb = dtb image.fdtmap_dtb = dtb