Change from V1 at [1]:
* Resolves issues mentioned in code review there
The fix discussed in [2] resolves build issues on styhead but
introduces an issue which causes hash mismatches when building
without `rm_work`.
All builds succeed in generate a working .swu, however any build
which modifies the rootfs will fail to deploy.
On attempt to deploy, a hash mismatch will be noted like this:
```
[TRACE] : SWUPDATE running : [install_archive_image] : Installing file demo-image-base-jetson-orin-nano-devkit-nvme.rootfs.tar.gz on /tmp/datadst/Pfw8nm//, preserving attributes
[WARN ] : SWUPDATE running : [extract] : archive_read_next_header(): Pathname can't be converted from UTF-8 to current locale. for './etc/ssl/certs/NetLock_Arany_=Class_Gold=_Főtanúsítvány.pem': Invalid or incomplete multibyte or wide character
[WARN ] : SWUPDATE running : [extract] : archive_read_next_header(): Pathname can't be converted from UTF-8 to current locale. for './usr/share/ca-certificates/mozilla/NetLock_Arany_=Class_Gold=_Főtanúsítvány.crt': Invalid or incomplete multibyte or wide character
[ERROR] : SWUPDATE failed [0] ERROR cpio_utils.c : hash_compare : 465 : HASH mismatch : 0f7591f6ffa4aa8e1d919d774974f06d42f184ef5a552f9887201cf3649414da <--> 2497e5b3eaec665ec2ec7db4bb1025d2c92e38c9d8fc22d22aa5e71314f15e6f
[ERROR] : SWUPDATE failed [0] ERROR archive_handler.c : install_archive_image : 344 : Error copying extracted file
[TRACE] : SWUPDATE running : [install_single_image] : Installer for archive not successful !
[ERROR] : SWUPDATE failed [0] ERROR stream_interface.c : extract_files : 319 : Error streaming demo-image-base-jetson-orin-nano-devkit-nvme.rootfs.tar.gz
swupdate_image_write failed: Connection reset by peer
[ERROR] : SWUPDATE failed [1] Image invalid or corrupted. Not installing ...
[ERROR] : SWUPDATE failed [0] ERROR install_from_file.c : endupdate : 55 : SWUpdate *failed* !
```
This happens because the sha256 modifications made to files in the
S directory only happen once before variables are expanded
unless `rm_work` is used to remove the source dir on each build.
So anyone using `rm_work` for their builds would not see this issue.
The previous logic means there's a single expansion of
`$swupdate_get_sha256(` or similar variables, and future
builds use the hash previously placed in the file in the S directory
which is no longer correct when the rootfs file hash changes.
This change:
1. Moves the modified sw-description file to WORKDIR in
the function swupdate_expand_bitbake_variables, keeping
a copy in S which is unmodified and without exapanded vars.
2. Modifies swupdate_add_artifacts and swupdate_add_src_uri
to target WORKDIR instead of S as the copy destination.
3. Modifies swupdate_create_cpio to use WORKDIR for generation
of cpio instead of S, since all up to date content and
artifacts are stored there.
4. Modifies swupdate_exec_functions to target workdir instead
of s, since all exec functions in swupdate-lib.common operate
on artifacts which are now in workdir and none require the
unmodified sw-description file which is the only content
remaining in S.
5. Updates all references to s and workdir in swupdate-common.bbclass
to reference the correct directories. The references to s in
swupdate-lib.bbclass were not modified, however in all
cases the s variable will actually be set to workdir due to
the modification to swupdate_exec_functions above.
1:
https://groups.google.com/g/swupdate/c/ZrDn9hVCet8/m/4lZhxoFfAgAJ
2:
https://groups.google.com/g/swupdate/c/8K-9H7C9o5E/m/a9fqhIOjAAAJ
To reproduce this problem before this fix:
1. Turn off rm-work on your builds.
2. Build the swu target at least once.
3. Make some modification to the rootfs.
4. Build the swu target again.
5. Run the swupdate on target.
Testing (tested with my_swupdate_image_recipe="swupdate-image-tegra" and machine="jetson-orin-nano-devkit-nvme")
1. Ensure `rm_work` is disabled.
2. Started with `bitbake -c cleanall $my_swupdate_image_recipe`
3. Bitbaked with `bitbake $my_swupdate_image_recipe`
4. Examine the recipe work/$machine*/$my_swupdate_image_recipe/ directory
4a. Verify sources dir contains only sw-description, without any parameter fields (sha256, etc) filed in
4b. Verify base dir (workdir) contains sw-description with all parameter fields filed in
4c. Verify sha256sum on the rootfs file in workdir matches value in sw-description in the workdir.
5. Make a minor change to the image by including another package, for instance in local.conf add `IMAGE_INSTALL:append = " curl"`
6. Bitbaked with `bitbake $my_swupdate_image_recipe`
7. Examine the recipe work/$machine*/$my_swupdate_image_recipe/ directory
7a. Verify timestamp on sources/sw-description file has not changed, still contains variable references.
7b. Verify timestamp on sw-description on base workdir has changed
7c. Verify sha256sum on the rootfs in workdir matches value in sw-description in the workdir.
8. Run swupdate with resulting .swu file on target
8a. Swupdate run succeeds.
classes-recipe/swupdate-common.bbclass | 45 +++++++++++++-------------
1 file changed, 23 insertions(+), 22 deletions(-)
diff --git a/classes-recipe/swupdate-common.bbclass b/classes-recipe/swupdate-common.bbclass
index ef016ca..80a5d5b 100644
--- a/classes-recipe/swupdate-common.bbclass
+++ b/classes-recipe/swupdate-common.bbclass
@@ -65,22 +65,22 @@ def swupdate_getdepends(d):
return depstr
-def swupdate_write_sha256(s):
+def swupdate_write_sha256(workdir):
import re
write_lines = []
- with open(os.path.join(s, "sw-description"), 'r') as f:
+ with open(os.path.join(workdir, "sw-description"), 'r') as f:
for line in f:
shastr = r"sha256.+=.+@(.+\")"
m = re.match(r"^(?P<before_placeholder>.+)(sha256|version).+[=:].*(?P<quote>[\'\"])@(?P<filename>.*)(?P=quote)", line)
if m:
filename = m.group('filename')
bb.warn("Syntax for sha256 changed, please use $swupdate_get_sha256(%s)" % filename)
- hash = swupdate_get_sha256(None, s, filename)
+ hash = swupdate_get_sha256(None, workdir, filename)
write_lines.append(line.replace("@%s" % (filename), hash))
else:
write_lines.append(line)
- with open(os.path.join(s, "sw-description"), 'w+') as f:
+ with open(os.path.join(workdir, "sw-description"), 'w+') as f:
for line in write_lines:
f.write(line)
@@ -96,7 +96,7 @@ def swupdate_exec_functions(d, s, write_lines):
write_lines[index] = line
-def swupdate_expand_bitbake_variables(d, s):
+def swupdate_expand_bitbake_variables(d, s, workdir):
write_lines = []
with open(os.path.join(s, "sw-description"), 'r') as f:
@@ -128,9 +128,9 @@ def swupdate_expand_bitbake_variables(d, s):
write_lines.append(line)
- swupdate_exec_functions(d, s, write_lines)
+ swupdate_exec_functions(d, workdir, write_lines)
- with open(os.path.join(s, "sw-description"), 'w+') as f:
+ with open(os.path.join(workdir, "sw-description"), 'w+') as f:
for line in write_lines:
f.write(line)
@@ -172,17 +172,18 @@ def prepare_sw_description(d):
import subprocess
s = d.getVar('S')
- swupdate_expand_bitbake_variables(d, s)
+ workdir = d.getVar('WORKDIR')
+ swupdate_expand_bitbake_variables(d, s, workdir)
- swupdate_write_sha256(s)
+ swupdate_write_sha256(workdir)
encrypt = d.getVar('SWUPDATE_ENCRYPT_SWDESC')
if encrypt:
bb.note("Encryption of sw-description")
- shutil.copyfile(os.path.join(s, 'sw-description'), os.path.join(s, 'sw-description.plain'))
+ shutil.copyfile(os.path.join(workdir, 'sw-description'), os.path.join(workdir, 'sw-description.plain'))
key,iv = swupdate_extract_keys(d.getVar('SWUPDATE_AES_FILE'))
- iv = swupdate_get_IV(d, s, 'sw-description')
- swupdate_encrypt_file(os.path.join(s, 'sw-description.plain'), os.path.join(s, 'sw-description'), key, iv)
+ iv = swupdate_get_IV(d, workdir, 'sw-description')
+ swupdate_encrypt_file(os.path.join(workdir, 'sw-description.plain'), os.path.join(workdir, 'sw-description'), key, iv)
signing = d.getVar('SWUPDATE_SIGNING')
if signing == "1":
@@ -190,8 +191,8 @@ def prepare_sw_description(d):
signing = "RSA"
if signing:
- sw_desc_sig = os.path.join(s, 'sw-description.sig')
- sw_desc = os.path.join(s, 'sw-description.plain' if encrypt else 'sw-description')
+ sw_desc_sig = os.path.join(workdir, 'sw-description.sig')
+ sw_desc = os.path.join(workdir, 'sw-description.plain' if encrypt else 'sw-description')
if signing == "CUSTOM":
signcmd = []
@@ -239,7 +240,7 @@ def prepare_sw_description(d):
def swupdate_add_src_uri(d, list_for_cpio):
import shutil
- s = d.getVar('S')
+ workdir = d.getVar('WORKDIR')
exclude = (d.getVar("SWUPDATE_SRC_URI_EXCLUDE") or "").split()
fetch = bb.fetch2.Fetch([], d)
@@ -255,12 +256,12 @@ def swupdate_add_src_uri(d, list_for_cpio):
key,iv = swupdate_extract_keys(d.getVar('SWUPDATE_AES_FILE'))
if (filename != 'sw-description') and (os.path.isfile(local)):
encrypted = (d.getVarFlag("SWUPDATE_IMAGES_ENCRYPTED", filename) or "")
- dst = os.path.join(s, "%s" % filename )
+ dst = os.path.join(workdir, "%s" % filename )
if encrypted == '1':
bb.note("Encryption requested for %s" %(filename))
if not key or not iv:
bb.fatal("Encryption required, but no key found")
- iv = swupdate_get_IV(d, s, filename)
+ iv = swupdate_get_IV(d, workdir, filename)
swupdate_encrypt_file(local, dst, key, iv)
else:
shutil.copyfile(local, dst)
@@ -290,7 +291,7 @@ def swupdate_add_artifacts(d, list_for_cpio):
images = (d.getVar('SWUPDATE_IMAGES') or "").split()
deploydir = d.getVar('DEPLOY_DIR_IMAGE')
imgdeploydir = d.getVar('SWUDEPLOYDIR')
- s = d.getVar('S')
+ workdir = d.getVar('WORKDIR')
for image in images:
fstypes = (d.getVarFlag("SWUPDATE_IMAGES_FSTYPES", image) or "").split()
encrypted = (d.getVarFlag("SWUPDATE_IMAGES_ENCRYPTED", image) or "")
@@ -305,19 +306,19 @@ def swupdate_add_artifacts(d, list_for_cpio):
for fstype in fstypes:
image_found = False
for imagebase in imagebases:
- image_found = add_image_to_swu(d, deploydir, imagebase + fstype, s, encrypted, list_for_cpio)
+ image_found = add_image_to_swu(d, deploydir, imagebase + fstype, workdir, encrypted, list_for_cpio)
if image_found:
break
if not image_found:
bb.fatal("swupdate cannot find image file: %s" % os.path.join(deploydir, imagebase + fstype))
else: # Allow also complete entries like "image.ext4.gz" in SWUPDATE_IMAGES
- if not add_image_to_swu(d, deploydir, image, s, encrypted, list_for_cpio):
+ if not add_image_to_swu(d, deploydir, image, workdir, encrypted, list_for_cpio):
bb.fatal("swupdate cannot find %s image file" % image)
def swupdate_create_cpio(d, swudeploydir, list_for_cpio):
- s = d.getVar('S')
- os.chdir(s)
+ workdir = d.getVar('WORKDIR')
+ os.chdir(workdir)
updateimage = d.getVar('IMAGE_NAME') + '.swu'
line = 'for i in ' + ' '.join(list_for_cpio) + '; do echo $i;done | cpio -ov -H crc --reproducible > ' + os.path.join(swudeploydir, updateimage)
os.system(line)
--
2.34.1