swupdate.bbclass 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. # Copyright (C) 2015 Stefano Babic <sbabic@denx.de>
  2. #
  3. # Some parts from the patch class
  4. #
  5. # swupdate allows to generate a compound image for the
  6. # in the "swupdate" format, used for updating the targets
  7. # in field.
  8. # See also http://sbabic.github.io/swupdate/
  9. #
  10. #
  11. # To use, add swupdate to the inherit clause and set
  12. # set the images (all of them must be found in deploy directory)
  13. # that are part of the compound image.
  14. S = "${WORKDIR}/${PN}"
  15. DEPENDS += "${@ 'openssl-native' if d.getVar('SWUPDATE_SIGNING', True) else ''}"
  16. IMAGE_DEPENDS ?= ""
  17. def swupdate_is_hash_needed(s, filename):
  18. with open(os.path.join(s, "sw-description"), 'r') as f:
  19. for line in f:
  20. if line.find("@%s" % (filename)) != -1:
  21. return True
  22. return False
  23. def swupdate_get_sha256(s, filename):
  24. import hashlib
  25. m = hashlib.sha256()
  26. with open(os.path.join(s, filename), 'rb') as f:
  27. while True:
  28. data = f.read(1024)
  29. if not data:
  30. break
  31. m.update(data)
  32. return m.hexdigest()
  33. def swupdate_write_sha256(s, filename, hash):
  34. write_lines = []
  35. with open(os.path.join(s, "sw-description"), 'r') as f:
  36. for line in f:
  37. write_lines.append(line.replace("@%s" % (filename), hash))
  38. with open(os.path.join(s, "sw-description"), 'w+') as f:
  39. for line in write_lines:
  40. f.write(line)
  41. def swupdate_getdepends(d):
  42. def adddep(depstr, deps):
  43. for i in (depstr or "").split():
  44. if i not in deps:
  45. deps.append(i)
  46. deps = []
  47. images = (d.getVar('IMAGE_DEPENDS', True) or "").split()
  48. for image in images:
  49. adddep(image , deps)
  50. depstr = ""
  51. for dep in deps:
  52. depstr += " " + dep + ":do_build"
  53. return depstr
  54. IMGDEPLOYDIR = "${WORKDIR}/deploy-${PN}-swuimage"
  55. do_swuimage[dirs] = "${TOPDIR}"
  56. do_swuimage[cleandirs] += "${S} ${IMGDEPLOYDIR}"
  57. do_swuimage[umask] = "022"
  58. SSTATETASKS += "do_swuimage"
  59. SSTATE_SKIP_CREATION_task-swuimage = '1'
  60. do_swuimage[sstate-inputdirs] = "${IMGDEPLOYDIR}"
  61. do_swuimage[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
  62. do_swuimage[stamp-extra-info] = "${MACHINE}"
  63. do_configure[noexec] = "1"
  64. do_compile[noexec] = "1"
  65. do_install[noexec] = "1"
  66. deltask do_populate_sysroot
  67. do_package[noexec] = "1"
  68. deltask do_package_qa
  69. do_packagedata[noexec] = "1"
  70. do_package_write_ipk[noexec] = "1"
  71. do_package_write_deb[noexec] = "1"
  72. do_package_write_rpm[noexec] = "1"
  73. python () {
  74. deps = " " + swupdate_getdepends(d)
  75. d.appendVarFlag('do_swuimage', 'depends', deps)
  76. }
  77. python do_swuimage () {
  78. import shutil
  79. workdir = d.getVar('WORKDIR', True)
  80. images = (d.getVar('SWUPDATE_IMAGES', True) or "").split()
  81. s = d.getVar('S', True)
  82. shutil.copyfile(os.path.join(workdir, "sw-description"), os.path.join(s, "sw-description"))
  83. fetch = bb.fetch2.Fetch([], d)
  84. list_for_cpio = ["sw-description"]
  85. if d.getVar('SWUPDATE_SIGNING', True):
  86. list_for_cpio.append('sw-description.sig')
  87. for url in fetch.urls:
  88. local = fetch.localpath(url)
  89. filename = os.path.basename(local)
  90. if (filename != 'sw-description'):
  91. shutil.copyfile(local, os.path.join(s, "%s" % filename ))
  92. list_for_cpio.append(filename)
  93. # SWUPDATE_IMAGES refers to images in the DEPLOY directory
  94. # If they are not there, additional file can be added
  95. # by fetching from URLs
  96. deploydir = d.getVar('DEPLOY_DIR_IMAGE', True)
  97. imgdeploydir = d.getVar('IMGDEPLOYDIR', True)
  98. for image in images:
  99. fstypes = (d.getVarFlag("SWUPDATE_IMAGES_FSTYPES", image, True) or "").split()
  100. if not fstypes:
  101. fstypes = [""]
  102. for fstype in fstypes:
  103. appendmachine = d.getVarFlag("SWUPDATE_IMAGES_NOAPPEND_MACHINE", image, True)
  104. if appendmachine == None:
  105. imagebase = image + '-' + d.getVar('MACHINE', True)
  106. else:
  107. imagebase = image
  108. imagename = imagebase + fstype
  109. src = os.path.join(deploydir, "%s" % imagename)
  110. dst = os.path.join(s, "%s" % imagename)
  111. shutil.copyfile(src, dst)
  112. list_for_cpio.append(imagename)
  113. for file in list_for_cpio:
  114. if file != 'sw-description' and swupdate_is_hash_needed(s, file):
  115. hash = swupdate_get_sha256(s, file)
  116. swupdate_write_sha256(s, file, hash)
  117. signing = d.getVar('SWUPDATE_SIGNING', True)
  118. if signing == "1":
  119. bb.warn('SWUPDATE_SIGNING = "1" is deprecated, falling back to "RSA". It is advised to set it to "RSA" if using RSA signing.')
  120. signing = "RSA"
  121. if signing:
  122. if signing == "CUSTOM":
  123. sign_tool = d.getVar('SWUPDATE_SIGN_TOOL', True)
  124. if sign_tool:
  125. ret = os.system(sign_tool)
  126. if ret != 0:
  127. bb.fatal("Failed to sign with %s" % (sign_tool))
  128. else:
  129. bb.fatal("Custom SWUPDATE_SIGN_TOOL is not given")
  130. elif signing == "RSA":
  131. privkey = d.getVar('SWUPDATE_PRIVATE_KEY', True)
  132. if not privkey:
  133. bb.fatal("SWUPDATE_PRIVATE_KEY isn't set")
  134. if not os.path.exists(privkey):
  135. bb.fatal("SWUPDATE_PRIVATE_KEY %s doesn't exist" % (privkey))
  136. passout = d.getVar('SWUPDATE_PASSWORD_FILE', True)
  137. if passout:
  138. passout = "-passin file:'%s' " % (passout)
  139. else:
  140. passout = ""
  141. signcmd = "openssl dgst -sha256 -sign '%s' %s -out '%s' '%s'" % (
  142. privkey,
  143. passout,
  144. os.path.join(s, 'sw-description.sig'),
  145. os.path.join(s, 'sw-description'))
  146. if os.system(signcmd) != 0:
  147. bb.fatal("Failed to sign sw-description with %s" % (privkey))
  148. elif signing == "CMS":
  149. cms_cert = d.getVar('SWUPDATE_CMS_CERT', True)
  150. if not cms_cert:
  151. bb.fatal("SWUPDATE_CMS_CERT is not set")
  152. if not os.path.exists(cms_cert):
  153. bb.fatal("SWUPDATE_CMS_CERT %s doesn't exist" % (cms_cert))
  154. cms_key = d.getVar('SWUPDATE_CMS_KEY', True)
  155. if not cms_key:
  156. bb.fatal("SWUPDATE_CMS_KEY isn't set")
  157. if not os.path.exists(cms_key):
  158. bb.fatal("SWUPDATE_CMS_KEY %s doesn't exist" % (cms_key))
  159. signcmd = "openssl cms -sign -in '%s' -out '%s' -signer '%s' -inkey '%s' -outform DER -nosmimecap -binary" % (
  160. os.path.join(s, 'sw-description'),
  161. os.path.join(s, 'sw-description.sig'),
  162. cms_cert,
  163. cms_key)
  164. if os.system(signcmd) != 0:
  165. bb.fatal("Failed to sign sw-description with %s" % (privkey))
  166. else:
  167. bb.fatal("Unrecognized SWUPDATE_SIGNING mechanism.");
  168. line = 'for i in ' + ' '.join(list_for_cpio) + '; do echo $i;done | cpio -ov -H crc >' + os.path.join(imgdeploydir,d.getVar('IMAGE_NAME', True) + '.swu')
  169. os.system("cd " + s + ";" + line)
  170. line = 'ln -sf ' + d.getVar('IMAGE_NAME', True) + '.swu ' + d.getVar('IMAGE_LINK_NAME', True) + '.swu'
  171. os.system("cd " + imgdeploydir + "; " + line)
  172. }
  173. COMPRESSIONTYPES = ""
  174. PACKAGE_ARCH = "${MACHINE_ARCH}"
  175. INHIBIT_DEFAULT_DEPS = "1"
  176. EXCLUDE_FROM_WORLD = "1"
  177. addtask do_swuimage after do_unpack after do_prepare_recipe_sysroot before do_build