binman: Detect when valid images are not produced
authorSimon Glass <sjg@chromium.org>
Fri, 10 Jul 2020 00:39:40 +0000 (18:39 -0600)
committerSimon Glass <sjg@chromium.org>
Sat, 25 Jul 2020 20:46:57 +0000 (14:46 -0600)
When external blobs are missing, show a message indicating that the images
are not functional.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/control.py
tools/binman/entry.py
tools/binman/etype/blob_ext.py
tools/binman/etype/section.py
tools/binman/ftest.py
tools/binman/test/159_blob_ext_missing_sect.dts [new file with mode: 0644]
tools/patman/tout.py

index 8c6eae8..343b0a0 100644 (file)
@@ -403,6 +403,9 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
         allow_resize: True to allow entries to change size (this does a re-pack
             of the entries), False to raise an exception
         allow_missing: Allow blob_ext objects to be missing
+
+    Returns:
+        True if one or more external blobs are missing, False if all are present
     """
     if get_contents:
         image.SetAllowMissing(allow_missing)
@@ -450,6 +453,12 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
     image.BuildImage()
     if write_map:
         image.WriteMap()
+    missing_list = []
+    image.CheckMissing(missing_list)
+    if missing_list:
+        tout.Warning("Image '%s' is missing external blobs and is non-functional: %s" %
+                     (image.name, ' '.join([e.name for e in missing_list])))
+    return bool(missing_list)
 
 
 def Binman(args):
@@ -524,14 +533,17 @@ def Binman(args):
 
             images = PrepareImagesAndDtbs(dtb_fname, args.image,
                                           args.update_fdt)
+            missing = False
             for image in images.values():
-                ProcessImage(image, args.update_fdt, args.map,
-                             allow_missing=args.allow_missing)
+                missing |= ProcessImage(image, args.update_fdt, args.map,
+                                        allow_missing=args.allow_missing)
 
             # Write the updated FDTs to our output files
             for dtb_item in state.GetAllFdts():
                 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
 
+            if missing:
+                tout.Warning("Some images are invalid")
         finally:
             tools.FinaliseOutputDir()
     finally:
index 9388586..3434a3f 100644 (file)
@@ -84,6 +84,7 @@ class Entry(object):
         self.image_pos = None
         self._expand_size = False
         self.compress = 'none'
+        self.missing = False
 
     @staticmethod
     def Lookup(node_path, etype):
@@ -803,3 +804,14 @@ features to produce new behaviours.
         """
         # This is meaningless for anything other than sections
         pass
+
+    def CheckMissing(self, missing_list):
+        """Check if any entries in this section have missing external blobs
+
+        If there are missing blobs, the entries are added to the list
+
+        Args:
+            missing_list: List of Entry objects to be added to
+        """
+        if self.missing:
+            missing_list.append(self)
index 51779c8..8d64100 100644 (file)
@@ -34,5 +34,6 @@ class Entry_blob_ext(Entry_blob):
         # Allow the file to be missing
         if not self._pathname:
             self.SetContents(b'')
+            self.missing = True
             return True
         return super().ObtainContents()
index 9b718f1..dd7f1cc 100644 (file)
@@ -55,6 +55,7 @@ class Entry_section(Entry):
         self._skip_at_start = None
         self._end_4gb = False
         self._allow_missing = False
+        self.missing = False
 
     def ReadNode(self):
         """Read properties from the image node"""
@@ -559,3 +560,14 @@ class Entry_section(Entry):
             True if allowed, False if not allowed
         """
         return self._allow_missing
+
+    def CheckMissing(self, missing_list):
+        """Check if any entries in this section have missing external blobs
+
+        If there are missing blobs, the entries are added to the list
+
+        Args:
+            missing_list: List of Entry objects to be added to
+        """
+        for entry in self._entries.values():
+            entry.CheckMissing(missing_list)
index 928d360..cc551c9 100644 (file)
@@ -3380,7 +3380,19 @@ class TestFunctional(unittest.TestCase):
 
     def testExtblobMissingOk(self):
         """Test an image with an missing external blob that is allowed"""
-        self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
+        err = stderr.getvalue()
+        self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
+
+    def testExtblobMissingOkSect(self):
+        """Test an image with an missing external blob that is allowed"""
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoTestFile('159_blob_ext_missing_sect.dts',
+                             allow_missing=True)
+        err = stderr.getvalue()
+        self.assertRegex(err, "Image 'main-section'.*missing.*: "
+                         "blob-ext blob-ext2")
 
 
 if __name__ == "__main__":
diff --git a/tools/binman/test/159_blob_ext_missing_sect.dts b/tools/binman/test/159_blob_ext_missing_sect.dts
new file mode 100644 (file)
index 0000000..5f14c54
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               size = <0x80>;
+
+               section {
+                       blob-ext {
+                               filename = "missing-file";
+                       };
+               };
+
+               blob-ext2 {
+                       type = "blob-ext";
+                       filename = "missing-file2";
+               };
+       };
+};
index 91a53f4..3330526 100644 (file)
@@ -171,6 +171,7 @@ def Init(_verbose=WARNING, stdout=sys.stdout):
 
     # TODO(sjg): Move this into Chromite libraries when we have them
     stdout_is_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
+    stderr_is_tty = hasattr(sys.stderr, 'isatty') and sys.stderr.isatty()
 
 def Uninit():
     ClearProgress()