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
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
----------------------------

View file

@ -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)

View file

@ -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()

View file

@ -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

View file

@ -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