Provided by: swupdate_2025.05+dfsg-3ubuntu1_amd64 bug

NAME

       swupdate - SWUpdate Documentation [image]

       SWUpdate  provides  a  reliable  way to update the software on an embedded system.  Sources are hosted at
       <https://github.com/sbabic/swupdate>. Do not forget to star SWUpdate.

SOFTWARE MANAGEMENT ON EMBEDDED SYSTEMS

       As Embedded Systems become more and more complex, their software reflects the augmented  complexity.   It
       is  vital  that  the  software on an embedded system can be updated in an absolutely reliable way, as new
       features and fixes are added.

       On a Linux-based system, we can find in most cases the following elements:

       • the boot loader.

       • the kernel and the DT (Device Tree) file.

       • the root file system

       • other file systems, mounted at a later point

       • customer data, in raw format or on a file system

       • application specific software. For example, firmware to be downloaded on  connected  micro-controllers,
         and so on.

       Generally  speaking,  in most cases it is required to update kernel and root file system, preserving user
       data - but cases vary.

       In only a few cases it is required to update the boot loader, too. In fact, updating the boot  loader  is
       quite  always  risky,  because  a  failure  in  the update breaks the board.  Restoring a broken board is
       possible in some cases, but this is not left in most cases to the end user and the system  must  be  sent
       back to the manufacturer.

       There  are  a  lot  of different concepts about updating the software. I like to expose some of them, and
       then explain why I have implemented this project.

   Updating through the boot loader
       Boot loaders do much more as simply start the kernel.  They have their own shell and can be managed using
       a processor's peripheral, in most cases a serial line.  They are often script-able, letting  possible  to
       implement some kind of software update mechanism.

       However,  I  found  some drawbacks in this approach, that let me search for another solution, based on an
       application running on Linux:

   Boot loaders have limited access to peripherals
       Not all peripherals supported by the kernel are available with the boot loader. When it  makes  sense  to
       add  support to the kernel, because the peripheral is then available by the main application, it does not
       always make sense to duplicate the effort to port the driver to the boot loader.

   Boot loader's drivers are not updated
       Boot loader's drivers are mostly ported from the Linux kernel, but due to adaptations they are not  later
       fixed  or  synchronized  with  the  kernel,  while  bug  fixes  flow regularly in the Linux kernel.  Some
       peripherals can then work in a not reliable ways, and fixing the issues can be not easy. Drivers in  boot
       loaders are more or less a fork of the respective drivers in kernel.

       As  example,  the UBI / UBIFS for NAND devices contains a lot of fixes in the kernel, that are not ported
       back to the boot loaders.  The same can be found for the USB stack. The effort to support new peripherals
       or protocols is better to be used for the kernel as for the boot loaders.

   Reduced file systems
       The number of supported file systems is limited and porting a file system to  the  boot  loader  requires
       high effort.

   Network support is limited
       Network stack is limited, generally an update is possible via UDP but not via TCP.

   Interaction with the operator
       It is difficult to expose an interface to the operator, such as a GUI with a browser or on a display.

       A  complex  logic  can be easier implemented inside an application else in the boot loader. Extending the
       boot loader becomes complicated because the whole range of services and libraries are not available.

   Boot loader's update advantages
       However, this approach has some advantages, too:

       • software for update is generally simpler.  - smaller footprint:  a  stand-alone  application  only  for
         software  management  requires  an own kernel and a root file system. Even if their size can be trimmed
         dropping what is not required for updating the software, their size is not negligible.

   Updating through a package manager
       All Linux distributions are updating with a package manager.  Why is it not suitable for embedded ?

       I cannot say it cannot be used, but there is an important drawback using this approach. Embedded  systems
       are  well tested with a specific software. Using a package manager can put weirdness because the software
       itself is not anymore atomic, but split into a long list of packages. How  can  we  be  assured  that  an
       application with library version x.y works, and also with different versions of the same library? How can
       it be successfully tested?

       For a manufacturer, it is generally better to say that a new release of software (well tested by its test
       engineers)  is  released,  and  the  new  software  (or firmware) is available for updating. Splitting in
       packages can generate nightmare and high effort for the testers.

       The ease of replacing single files can speed up the development, but it is a software-versions  nightmare
       at  the customer site.  If a customer report a bug, how can it is possible that software is "version 2.5"
       when a patch for some files were sent previously to the customer ?

       An atomic update is generally a must feature for an embedded system.

   Strategies for an application doing software upgrade
       Instead of using the boot loader, an application  can  take  into  charge  to  upgrade  the  system.  The
       application  can  use  all  services provided by the OS. The proposed solution is a stand-alone software,
       that follow customer rules and performs checks to determine  if  a  software  is  installable,  and  then
       install the software on the desired storage.

       The  application can detect if the provided new software is suitable for the hardware, and it is can also
       check if the software is released by a verified authority. The range of  features  can  grow  from  small
       system to a complex one, including the possibility to have pre- and post- install scripts, and so on.

       Different strategies can be used, depending on the system's resources. I am listing some of them.

   Double copy with fall-back
       If  there  is  enough  space  on  the storage to save two copies of the whole software, it is possible to
       guarantee that there is always a working copy even if the software update is interrupted or a  power  off
       occurs.

       Each  copy must contain the kernel, the root file system, and each further component that can be updated.
       It is required a mechanism to identify which version is running.

       SWUpdate should be inserted in the application software, and the application  software  will  trigger  it
       when  an  update  is  required.  The duty of SWUpdate is to update the stand-by copy, leaving the running
       copy of the software untouched.

       A synergy with the boot loader is often necessary, because the boot loader must decide which copy  should
       be started. Again, it must be possible to switch between the two copies.  After a reboot, the boot loader
       decides which copy should run.  [image]

       Check  the  chapter  about  boot  loader to see which mechanisms can be implemented to guarantee that the
       target is not broken after an update.

       The most evident drawback is the amount of required space. The available space for each copy is less than
       half the size of the storage. However, an update is always safe even in case of power off.

       This project supports this strategy. The application as part of this project should be installed  in  the
       root file system and started or triggered as required. There is no need of an own kernel, because the two
       copies guarantees that it is always possible to upgrade the not running copy.

       SWUpdate will set bootloader's variable to signal the that a new image is successfully installed.

   Single copy - running as standalone image
       The  software  upgrade application consists of kernel (maybe reduced dropping not required drivers) and a
       small root file system, with the application and its libraries. The whole size is much less than a single
       copy of the system software. Depending on set up, I get sizes from 2.5 until 8  MB  for  the  stand-alone
       root file system. If the size is very important on small systems, it becomes negligible on systems with a
       lot of storage or big NANDs.

       The  system can be put in "upgrade" mode, simply signaling to the boot loader that the upgrading software
       must be started. The way can differ, for example setting a boot loader environment or using and  external
       GPIO.

       The  boot loader starts "SWUpdate", booting the SWUpdate kernel and the initrd image as root file system.
       Because it runs in RAM, it is possible to upgrade the whole storage. Differently as  in  the  double-copy
       strategy, the systems must reboot to put itself in update mode.

       This  concept  consumes less space in storage as having two copies, but it does not guarantee a fall-back
       without updating again the software.  However, it can be guaranteed that the system goes automatically in
       upgrade mode when the productivity software is not found or  corrupted,  as  well  as  when  the  upgrade
       process is interrupted for some reason.  [image]

       In fact, it is possible to consider the upgrade procedure as a transaction, and only after the successful
       upgrade  the new software is set as "boot-able". With these considerations, an upgrade with this strategy
       is safe: it is always guaranteed that the system boots and it is ready to get a new software, if the  old
       one  is  corrupted  or  cannot  run.   With  U-Boot  as  boot loader, SWUpdate is able to manage U-Boot's
       environment setting variables to indicate the start and the end of a transaction  and  that  the  storage
       contains  a valid software.  A similar feature for GRUB environment block modification as well as for EFI
       Boot Guard has been introduced.

       SWUpdate is mainly used in this configuration. The recipes for Yocto generate an initrd image  containing
       the SWUpdate application, that is automatically started after mounting the root file system.  [image]

   Something went wrong ?
       Many  things  can go wrong, and it must be guaranteed that the system is able to run again and maybe able
       to reload a new software to fix a damaged image. SWUpdate works together with the boot loader to identify
       the possible causes of failures. Currently U-Boot, GRUB, and EFI Boot Guard are supported.

       We can at least group some of the common causes:

       • damage / corrupted image during installing.  SWUpdate is able to recognize it and the update process is
         interrupted. The old software is preserved and nothing is really copied into the target's storage.

       • corrupted image in the storage (flash)

       • remote update interrupted due to communication problem.

       • power-failure

       SWUpdate works as transaction process. The boot loader environment variable "recovery_status" is  set  to
       signal  the  update's status to the boot loader. Of course, further variables can be added to fine tuning
       and report error causes.  recovery_status can have the values "progress", "failed", or it can be unset.

       When SWUpdate starts, it sets recovery_status to "progress". After an update is  finished  with  success,
       the variable is erased. If the update ends with an error, recovery_status has the value "failed".

       When  an  update  is interrupted, independently from the cause, the boot loader recognizes it because the
       recovery_status variable is in "progress" or "failed".  The boot loader can then start again SWUpdate  to
       load again the software (single-copy case) or run the old copy of the application (double-copy case).

   Power Failure
       If  a  power  off  occurs,  it  must be guaranteed that the system is able to work again - starting again
       SWUpdate or restoring an old copy of the software.

       Generally, the behavior can be split according to the chosen scenario:

       • single copy: SWUpdate is interrupted and the update transaction did not end with a  success.  The  boot
         loader is able to start SWUpdate again, having the possibility to update the software again.

       • double  copy: SWUpdate did not switch between stand-by and current copy.  The same version of software,
         that was not touched by the update, is started again.

       To be completely safe, SWUpdate and the bootloader need to exchange some information. The bootloader must
       detect if an update was interrupted due  to  a  power-off,  and  restart  SWUpdate  until  an  update  is
       successful.   SWUpdate  supports  the  U-Boot, GRUB, and EFI Boot Guard bootloaders.  U-Boot and EFI Boot
       Guard have a power-safe environment which SWUpdate is able to read and change  in  order  to  communicate
       with  them.  In  case  of GRUB, a fixed 1024-byte environment block file is used instead. SWUpdate sets a
       variable as flag when it starts to update the system and resets the same variable after  completion.  The
       bootloader can read this flag to check if an update was running before a power-off.  [image]

   What about upgrading SWUpdate itself ?
       SWUpdate  is  thought to be used in the whole development process, replacing customized process to update
       the software during the development. Before going into production, SWUpdate is well tested for a project.

       If SWUpdate itself should be updated, the update cannot be safe if there is only one copy of SWUpdate  in
       the storage. Safe update can be guaranteed only if SWUpdate is duplicated.

       There are some ways to circumvent this issue if SWUpdate is part of the upgraded image:

       • have two copies of SWUpdate

       • take the risk, but have a rescue procedure using the boot loader.

   What about upgrading the Boot loader ?
       Updating  the  boot  loader  is in most cases a one-way process. On most SOCs, there is no possibility to
       have multiple copies of the boot loader, and when boot loader is broken, the board does not simply boot.

       Some SOCs allow one to have multiple copies of the boot loader. But again, there is no  general  solution
       for this because it is very hardware specific.

       In  my  experience, most targets do not allow one to update the boot loader. It is very uncommon that the
       boot loader must be updated when the product is ready for production.

       It is different if the U-Boot environment must be updated, that is a common practice. U-Boot  provides  a
       double copy of the whole environment, and updating the environment from SWUpdate is power-off safe. Other
       boot loaders can or cannot have this feature.

LICENSE

       SWUpdate  is Free Software.  It is copyrighted by Stefano Babic and many others who contributed code (see
       the actual source code and the git commit messages for details).  You can  redistribute  SWUpdate  and/or
       modify  it  under  the  terms  of  version  2  of the GNU General Public License as published by the Free
       Software Foundation.  Some files can also be distributed, at your option, under any later version of  the
       GNU General Public License -- see individual files for exceptions.

       To make this easier, license headers in the source files will be replaced with a single line reference to
       Unique  License  Identifiers  as  defined  by the Linux Foundation's SPDX project [1].  For example, in a
       source file the full "GPL v2.0 only" header text will be replaced by a single line:

          SPDX-License-Identifier:        GPL-2.0-only

       Ideally, the license terms of all files in the source tree should be defined by such License Identifiers;
       in no case a file can contain more than one such License Identifier list.

       If a "SPDX-License-Identifier:" line references more than one Unique License Identifier, then this  means
       that the respective file can be used under the terms of either of these licenses, i. e. with

          SPDX-License-Identifier:        GPL-2.0-only OR BSD-3-Clause

       you can choose between GPL-2.0-only and BSD-3-Clause licensing.

       We  use  the  SPDX  <http://spdx.org/>  Unique  License  Identifiers  (SPDX-Identifiers <http://spdx.org/
       licenses/>)

Licenses

                         ┌──────────────────────────────┬───────────────────┬──────────────┐
                         │ Full name                    │ SPDX Identifier   │ OSI Approved │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ GNU General  Public  License │ GPL-2.0-only      │ Y            │
                         │ v2.0    <http://www.gnu.org/ │                   │              │
                         │ licenses/gpl-2.0.txt> only   │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ GNU  Lesser  General  Public │ LGPL-2.1-or-later │ Y            │
                         │ License v2.1 <http://www.gnu │                   │              │
                         │ .org/licenses/old-licenses/  │                   │              │
                         │ lgpl-2.1.txt> or later       │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ BSD   1-Clause  <http://spdx │ BSD-1-Clause      │ Y            │
                         │ .org/licenses/BSD-1-Clause>  │                   │              │
                         │ License                      │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ BSD  2-Clause   <http://spdx │ BSD-2-Clause      │ Y            │
                         │ .org/licenses/BSD-2-Clause>  │                   │              │
                         │ License                      │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ BSD   3-Clause  <http://spdx │ BSD-3-Clause      │ Y            │
                         │ .org/licenses/BSD-3-Clause>  │                   │              │
                         │ "New" or "Revised" License   │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ MIT       <https://spdx.org/ │ MIT               │ Y            │
                         │ licenses/MIT.html> License   │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ Creative  Commons  Zero  1.0 │ CC0-1.0           │ N            │
                         │ Universal (CC0 <https://spdx │                   │              │
                         │ .org/licenses/CC0-1.0.html>) │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ Creative Commons Attribution │ CC-BY-SA-4.0      │ Y            │
                         │ Share  Alike  4.0  <https:// │                   │              │
                         │ spdx.org/licenses/CC-BY-SA-4 │                   │              │
                         │ .0.html>                     │                   │              │
                         ├──────────────────────────────┼───────────────────┼──────────────┤
                         │ ISC  License  (ISC <https:// │ ISC               │ Y            │
                         │ spdx.org/licenses/ISC.html>) │                   │              │
                         └──────────────────────────────┴───────────────────┴──────────────┘

SWUPDATE: SOFTWARE UPDATE FOR EMBEDDED SYSTEM

   Overview
       This project is thought to help to update an embedded system  from  a  storage  media  or  from  network.
       However,  it  should  be  mainly  considered  as  a  framework, where further protocols or installers (in
       SWUpdate they are called handlers) can be easily added to the application.

       One use case is to update from an external local media, as USB-Pen or SD-Card. In this case,  the  update
       is  done  without any intervention by an operator: it is thought as "one-key-update", and the software is
       started at reset simply pressing a key (or in any way that can be recognized by the target),  making  all
       checks  automatically.  At  the  end,  the  updating  process  reports  only  the  status to the operator
       (successful or failed).

       The output can be displayed on a LCD using the frame-buffer device or directed to a  serial  line  (Linux
       console).

       It  is generally used in the single copy approach, running in an initrd (recipes are provided to generate
       with Yocto).  However, it is possible to use it in a double-copy approach by use of Software  collections
       <#collections>.

       If  started  for  a  remote  update,  SWUpdate  starts an embedded Web-server and waits for requests. The
       operator must upload a suitable image, that SWUpdate checks and then install.  All output is notified  to
       the operator's browser via AJAX notifications.

   Features
   General Overview
       • Install on embedded Media (eMMC, SD, Raw NAND, NOR and SPI-NOR flashes)

       • check  if  an image is available. The image is built in a specified format (cpio) and it must contain a
         file describing the software that must be updated.

       • SWUpdate is thought to update UBI volumes (mainly for NAND,  but  not  only)  and  images  on  devices.
         Passing a whole image can still be updated as a partition on the SD card, or a MTD partition.

       • new  partition schema. This is bound with UBI volume.  SWUpdate can recreate UBI volumes, resizing them
         and copying the new software.

       • support for compressed images, using the zlib and zstd library.  tarball (tgz file) are supported.

       • support for partitioned USB-pen or unpartitioned (mainly used by Windows).

       • support for updating a single file inside a filesystem.  The filesystem where to put the file  must  be
         described.

       • checksum for the single components of an image

       • use  a  structured  language  to  describe  the  image.  This  is  done using the libconfig <http://www
         .hyperrealm.com/libconfig/> library as default parser, that uses a JSON-like description.

       • use custom's choice for the description of the image. It is possible to write an own parser  using  the
         Lua language.  An example using a XML description in Lua is provided in the examples directory.

       • Support for setting / erasing U-Boot variables

       • Support    for    setting    /    erasing   GRUB   <https://www.gnu.org/software/grub/manual/html_node/
         Environment-block.html> environment block variables

       • Support for setting / erasing EFI Boot Guard <https://github.com/siemens/efibootguard> variables

       • Support for pre and post update commands run before the update starts processing  data  and  after  the
         update has finished successfully.

       • Support for lua hooks, executed before any handler runs.

       • Support  for  preinstall  scripts. They run after streamed handlers have handled their data, and before
         regular handlers.

       • Support for postinstall scripts. They run after updating the images.

       • Network installer using an embedded Web-server (Mongoose Server was chosen, in the  version  under  Lua
         license). A different Web-server can be used.

       •

         Multiple interfaces for getting software

                • local Storage: USB, SD, UART,..

       •

         OTA / Remote

                • integrated Web-Server

                • pulling from remote Server (HTTP, HTTPS, ..)

                • using  a  Backend.  SWUpdate  is  open  to talk with back end servers for rolling out software
                  updates.  Current version supports the hawkBit server, but other backend can be added.

       • Can be configured to check for compatibility between software  and  hardware  revisions.  The  software
         image  must  contain  an entry declaring on which HW revision the software is allowed to run.  SWUpdate
         refuses to install if the compatibility is not verified.

       • support for image extraction. A manufacturer can require to have  a  single  image  that  contains  the
         software  for  more  as  one  device.   This simplifies the manufacturer's management and reduces their
         administrative costs having a single software  product.   SWUpdate  receives  the  software  as  stream
         without temporary storing, and extracts only the required components for the device to be installed.

       • allow custom handlers for installing FPGA firmware, micro-controller firmware via custom protocols.

       • Features are enabled / disabled using "make menuconfig".  (Kbuild is inherited from busybox project)

       • Images are authenticated and verified before installing

       • Power-Off safe

   Single image delivery
       The  main  concept  is  that  the  manufacturer delivers a single big image. All single images are packed
       together (cpio was chosen for its simplicity and because can be streamed)  together  with  an  additional
       file (sw-description), that contains meta information about each single image.

       The  format  of  sw-description  can be customized: SWUpdate can be configured to use its internal parser
       (based on libconfig), or calling an external parser in Lua.  [image]

       Changing the rules to accept images with an external parser, let to extend to new  image  types  and  how
       they  are  installed.   In  fact,  the  scope  of  the  parser is to retrieve which single images must be
       installed and how.  SWUpdate implements "handlers" to install a  single  image:  there  are  handlers  to
       install  images  into UBI volumes, or to a SD card, a CFI Flash, and so on. It is then easy to add an own
       handler if a very special installer is required.

       For example we can think at a project with a main processor and one or several  micro-controllers.  Let's
       say  for  simplicity  that  the  main processor communicates with the micro-controllers via UARTS using a
       proprietary protocol. The software  on  the  micro-controllers  can  be  updated  using  the  proprietary
       protocol.

       It is possible to extend SWUpdate writing a handler, that implements the part of the proprietary protocol
       to  perform  the upgrade on the micro-controller. The parser must recognize which image must be installed
       with the new handler, and SWUpdate will call the handler during the installation process.

   Streaming feature
       SWUpdate is thought to be able to stream the  received  image  directly  into  the  target,  without  any
       temporary  copy.  In fact, the single installer (handler) receive as input the file descriptor set at the
       beginning of the image that must be installed.

       The feature can be set on image basis, that means that a user can decide which partial images  should  be
       streamed. If not streamed (see installed-directly flag), files are temporary extracted into the directory
       pointed to by the environment variable TMPDIR with /tmp as fall-back if TMPDIR is not set.  Of course, by
       streaming  it  is  not  possible  to  make checks on the whole delivered software before installing.  The
       temporary copy is done only when updated from network. When the image is stored on an  external  storage,
       there is no need of that copy.

   Images fully streamed
       In  case  of  remote  update,  SWUpdate extracts relevant images from the stream and copies them into the
       directory pointed to by the environment variable TMPDIR (if unset, to /tmp) before calling the  handlers.
       This  guarantee  that  an update is initiated only if all parts are present and correct. However, on some
       systems with less resources, the amount of RAM to copy the images could be not enough, for example if the
       filesystem on an attached SD Card must be updated. In this case, it will help if the images are installed
       directly as stream by the corresponding handler, without temporary copies. Not all  handlers  support  to
       stream   directly   into   the  target.   Streaming  with  zero-copy  is  enabled  by  setting  the  flag
       "installed-directly" in the description of the single image.

   Configuration and Build
   Requirements
       There are only a few libraries strictly required to compile SWUpdate:

       • zlib (<https://www.zlib.net>)

       • libubootenv for U-Boot environment support (<https://github.com/sbabic/libubootenv>)

       • json-c for parsing JSON (<https://github.com/json-c/json-c>)

       Further library dependencies may be required when activating more SWUpdate features, see the next section
       on Configuring SWUpdate.

   Configuring SWUpdate
       SWUpdate is configurable via make menuconfig. A small footprint is realized, e.g., by using the  internal
       parser  and disabling the web server. Every option has a small help describing its usage.  In the default
       configuration, many options are already activated.

       To configure the options:

          make menuconfig

   Building
       To cross-compile, set the CC and CXX variables before running make.  It  is  also  possible  to  set  the
       cross-compiler prefix as option with make menuconfig. Then, generate the code by running

          make

       The result is the binary swupdate. Notably, the tools/swupdate-progress binary is built as well. It is an
       example  of  how  to  build  your own interface to SWUpdate to, e.g., show a progress bar on an HMI. This
       example simply prints on the console the current status of the update and, more importantly, reboots  the
       machine after successful installation.

   Building with Yocto
       See the corresponding chapter meta-swupdate: building with Yocto <> on how to build SWUpdate in Yocto.

   Distribution Packages
       SWUpdate  is  thought  for  Embedded  Systems and building in an embedded distribution is the primary use
       case. But apart from the most used build systems for embedded systems like Yocto or  Buildroot,  in  some
       cases, a standard Linux distro is used. SWUpdate is currently packaged for

       • Debian <https://packages.debian.org/search?searchon=names&keywords=swupdate>

       • Ubuntu <https://packages.ubuntu.com/search?keywords=swupdate>

       Refer to the distribution source package and build system on how to build a package from source.

   Running SWUpdate
   What is expected from a SWUpdate run
       The  whole  update  process  can  be  seen  as  a set of pipelines. The incoming stream (the SWU file) is
       processed by each pipe and passed to the next  step.   First,  the  SWU  is  streamed  from  one  of  the
       interfaces : local (USB, filesystem), Webserver, suricatta (one of the backend), etc. The incoming SWU is
       forwarded  to  the  installer  to  be  examined  and installed.  A run of SWUpdate consists mainly of the
       following steps:

       • extracts sw-description from the stream and  verifies  it  It  parses  sw-description  creating  a  raw
         description in RAM about the activities that must be performed.

       • if Signed Images is activated, extracts sw-description.sig and validate sw-description.

       • check for hardware-software compatibility, if any, reading hardware revision from hardware and matching
         with the table in sw-description.

       • Parse  sw-description  to  determine  which  artefacts  in  the incoming SWU are required. Not required
         artifacts are simply skipped.  If an "embedded-script" is defined, it is executed at this point  before
         parsing  files.  If "hooks" are defined, they are executed as each file is parsed, even if they will be
         skipped.  At the end of the parsing, SWUpdate builds an internal mapping for each artifact to recognize
         which handler should be called for each of them.

       • runs the pre update command, if set

       • runs partition handlers, if required.

       •

         reads through the cpio archive one file at a time and either:

                • execute handlers for each file marked as "installed-directly".  checksum is checked while  the
                  data  is  streamed  to  handler,  and copy will be marked as having failed if checksum was not
                  correct failing the rest of the install.

                • copy other files to a temporary location while checking checksums, stopping  if  there  was  a
                  mismatch.

       • iterates  through all scripts and call the corresponding handler for pre-install scripts.  Please note:
         if artifacts are streamed, they will be extracted before this runs. If earlier execution  is  required,
         please  use  the  "embedded-script"  or  hooks features to ensure code is run before installation takes
         place.

       • iterates through all images and call the corresponding handler for installing on target.

       • iterates through all files and call the corresponding handler for installing on target.

       • iterates through all scripts and call the corresponding handler for post-install scripts

       • iterates through all bootenv and updates the bootloader environment.

       • reports the status to the operator through the notification interface (logging, traces) and through the
         progress interface.

       • runs the post update command, if set.

       The first step that fails, stops the entire procedure and an error is reported.

       To start SWUpdate expecting the image from a file:

          swupdate -i <filename>

       To start with the embedded web server:

          swupdate -w "<web server options>"

       The main important parameters for the web server are "document-root" and "port".

          swupdate -w "--document-root ./www --port 8080"

       The embedded web server is taken from the Mongoose project.

       The list of available options (depending on activated features) is shown with:

          swupdate -h

       This uses as website the pages delivered with the code. Of course, they can be customized  and  replaced.
       The  website  uses  AJAX  to  communicate  with  SWUpdate,  and to show the progress of the update to the
       operator.

       The default port of the Web-server is 8080. You can then connect to the target with:

          http://<target_ip>:8080

       If it works, the start page should be displayed as in next figure.  [image]

       If a correct image is downloaded, SWUpdate starts to process the received image.  All  notifications  are
       sent  back  to  the  browser.  SWUpdate  provides  a  mechanism to send to a receiver the progress of the
       installation. In fact, SWUpdate takes a list of objects that registers itself with  the  application  and
       they  will  be  informed  any  time  the  application  calls the notify() function.  This allows also for
       self-written handlers to inform the upper layers about error conditions or simply return the  status.  It
       is  then  simply to add own receivers to implement customized way to display the results: displaying on a
       LCD (if the target has one), or  sending  back  to  another  device  via  network.   An  example  of  the
       notifications sent back to the browser is in the next figure: [image]

       Software  collections  can  be specified by passing --select command line option. Assuming sw-description
       file contains a collection named stable, with alt installation location,  SWUpdate  can  be  called  like
       this:

          swupdate --select stable,alt

   Command line parameters
                   ┌───────────────────────────┬───────────┬─────────────────────────────────────┐
                   │ Parameter                 │ Type      │ Description                         │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -f <file>                 │ string    │ SWUpdate  configuration file        │
                   │                           │           │ to         use.          See        │
                   │                           │           │ examples/configuration/swupdate.cfg │
                   │                           │           │ in   the   source  code  for        │
                   │                           │           │ details.                            │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -b <string>               │ string    │ Available  if  CONFIG_UBIATTACH  is │
                   │                           │           │ set.   It  allows  one to blacklist │
                   │                           │           │ MTDs when SWUpdate searches for UBI │
                   │                           │           │ volumes.    Example:   U-Boot   and │
                   │                           │           │ environment  in MTD0-1: swupdate -b │
                   │                           │           │ "0 1".                              │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -B <loader>               │ string    │ Override  the  default   bootloader │
                   │                           │           │ interface to use loader instead.    │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -e <sel>                  │ string    │ sel     is     in     the    format │
                   │                           │           │ <software>,<mode>.  It  allows  one │
                   │                           │           │ to  find  a  subset of rules in the │
                   │                           │           │ sw-description   file.   With   it, │
                   │                           │           │ multiple  rules  are  allowed.  One │
                   │                           │           │ common usage is in case of the dual │
                   │                           │           │ copy approach. Example: -e "stable, │
                   │                           │           │ copy1"  ==>  install  on  copy1  -e │
                   │                           │           │ "stable,  copy2"   ==>  install  on │
                   │                           │           │ copy2                               │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │                           │ string    │ sel    is     in     the     format │
                   │        --excluded         │           │ <software>,<mode>.    It   sets   a │
                   │               <sel>       │           │ blacklist of selections that cannot │
                   │                           │           │ be used for an update.   Selections │
                   │                           │           │ can  be activated not only with -e, │
                   │                           │           │ but   also   via   IPC.    Multiple │
                   │                           │           │ --excluded are allowed              │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -h                        │           │ Run usage with help.                │
                   │                           │        •  │                                     │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -k <file>                 │ string    │ Available  if CONFIG_SIGNED is set. │
                   │                           │           │ Filename with the public key.       │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -K <file>                 │ string    │ Available                        on │
                   │                           │           │ CONFIG_ENCRYPTED_IMAGES        set. │
                   │                           │           │ Filename with the symmetric key  to │
                   │                           │           │ be used for decryption.             │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ --cert-purpose <purpose>  │ string    │ Available  if  CONFIG_SIGNED_IMAGES │
                   │                           │           │ is set.  Set  expected  certificate │
                   │                           │           │ purpose.                            │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ --forced-signer-name <cn> │ string    │ Available  if  CONFIG_SIGNED_IMAGES │
                   │                           │           │ is set.  Set expected  common  name │
                   │                           │           │ of signer certificate.              │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ --ca-path <file>          │ string    │ Available  if  CONFIG_SIGNED_IMAGES │
                   │                           │           │ is set.  Path  to  the  Certificate │
                   │                           │           │ Authority (PEM).                    │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ --get-root                │           │ Detect  and  print  the root device │
                   │                           │           │ and exit                            │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ --get-emmc- boot <device> │           │ If devic eis an eMMC, reads the CSD │
                   │                           │           │ register and detect from which boot │
                   │                           │           │ device has booted (mmcblkXboot0  or │
                   │                           │           │ mmxblkXboot1)                       │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -l <level>                │ int       │ Set loglevel.                       │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -L                        │           │ Send LOG output to syslog (local).  │
                   │                           │        •  │                                     │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -i <file>                 │ string    │ Run  SWUpdate  with  a  local  .swu │
                   │                           │           │ file.                               │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -n                        │           │ Run SWUpdate in dry-run mode.       │
                   │                           │        •  │                                     │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -N <version>              │ string    │ The  minimum  required  version  of │
                   │                           │           │ software.   This  will  be  checked │
                   │                           │           │ with the version  of  new  software │
                   │                           │           │ and  forbids  downgrading.  Version │
                   │                           │           │ consists  of   either   4   numbers │
                   │                           │           │ (major.minor.rev.build   with  each │
                   │                           │           │ field in the range 0..65535) or  it │
                   │                           │           │ is a semantic version.              │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │                           │ string    │ The  maximum  required  version  of │
                   │        -max-version       │           │ software.   This  will  be  checked │
                   │               <version>   │           │ with  the  version of new software. │
                   │                           │           │ Version  consists   of   either   4 │
                   │                           │           │ numbers (major.minor.rev.build with │
                   │                           │           │ each  field  in the range 0..65535) │
                   │                           │           │ or it is a semantic version.        │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -R <version>              │ string    │ The current  installed  version  of │
                   │                           │           │ software.   This  will  be  checked │
                   │                           │           │ with the version  of  new  software │
                   │                           │           │ and forbids reinstalling.           │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -o <file>                 │ string    │ Save the stream (SWU) to a file.    │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -s <file>                 │ string    │ Save  installed  version  info to a │
                   │                           │           │ file.                               │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -v                        │           │ Activate verbose output.            │
                   │                           │        •  │                                     │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -M                        │           │ Disable  setting   the   bootloader │
                   │                           │        •  │ transaction marker.                 │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -m                        │           │ Disable setting the update state in │
                   │                           │        •  │ the bootloader.                     │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -w <parms>                │ string    │ Available  if  CONFIG_WEBSERVER  is │
                   │                           │           │ set.  Start internal webserver  and │
                   │                           │           │ pass to it a command line string.   │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -d <parms>                │ string    │ Available   if  CONFIG_DOWNLOAD  is │
                   │                           │           │ set.   Start  internal   downloader │
                   │                           │           │ client  and  pass  to  it a command │
                   │                           │           │ line   string.    See   below   the │
                   │                           │           │ internal command line arguments for │
                   │                           │           │ the downloader.                     │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -u <parms>                │ string    │ Available  if  CONFIG_SURICATTA  is │
                   │                           │           │ set.   Start   internal   suricatta │
                   │                           │           │ client  daemon  and  pass  to  it a │
                   │                           │           │ command line string.  See below the │
                   │                           │           │ internal command line arguments for │
                   │                           │           │ suricatta.                          │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -H <board:rev>            │ string    │ Available                        on │
                   │                           │           │ CONFIG_HW_COMPATIBILITY  set.   Set │
                   │                           │           │ board name and hardware revision.   │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -c                        │           │ Check *.swu file. It  ensures  that │
                   │                           │        •  │ files  referenced in sw-description │
                   │                           │           │ are present.  Usage: swupdate -c -i │
                   │                           │           │ <file>                              │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -P <cmd>                  │ string    │ Execute pre-update command.         │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -p <cmd>                  │ string    │ Execute post-update command.        │
                   ├───────────────────────────┼───────────┼─────────────────────────────────────┤
                   │ -q <sel>                  │ string    │                                     │
                   │                           │           │        List for software images set │
                   │                           │           │        and source                   │
                   │                           │           │               that are accepted via │
                   │                           │           │               IPC Ex.:  stable,main │
                   │                           │           │               it    can    be   set │
                   │                           │           │               multiple times        │
                   └───────────────────────────┴───────────┴─────────────────────────────────────┘

   Downloader command line parameters
       Example: swupdate -d "-u example.com"

       Mandatory arguments are marked with '*':
                             ┌────────────────┬─────────┬──────────────────────────────┐
                             │ Parameter      │ Type    │ Description                  │
                             ├────────────────┼─────────┼──────────────────────────────┤
                             │ -u <url>       │ string  │ * This is the URL where  new │
                             │                │         │ software is pulled. URL is a │
                             │                │         │ link to a valid .swu image   │
                             ├────────────────┼─────────┼──────────────────────────────┤
                             │ -r <retries>   │ integer │ Number  of  retries before a │
                             │                │         │ download    is    considered │
                             │                │         │ broken.    With    "-r   0", │
                             │                │         │ SWUpdate will not stop until │
                             │                │         │ a valid software is loaded.  │
                             ├────────────────┼─────────┼──────────────────────────────┤
                             │ -w <retrywait> │ integer │ Time to wait prior to  retry │
                             │                │         │ and    resume   a   download │
                             │                │         │ (default: 5s).               │
                             ├────────────────┼─────────┼──────────────────────────────┤
                             │ -t <timeout>   │ integer │ Timeout for connection  lost │
                             │                │         │ downloader or Webserver      │
                             ├────────────────┼─────────┼──────────────────────────────┤
                             │ -a <usr:pwd>   │ string  │ Send  user  and password for │
                             │                │         │ Basic Auth                   │
                             ├────────────────┼─────────┼──────────────────────────────┤
                             │ -n <value>     │ string  │ Maximum download speed to be │
                             │                │         │ used.  Value be specified in │
                             │                │         │ kB/s,  B/s,  MB/s  or  GB/s. │
                             │                │         │ Examples:   -n  100k  :  Set │
                             │                │         │ limit to 100 kB/s.   -n  500 │
                             │                │         │ :  Set limit to 500 B/s.  -n │
                             │                │         │ 2M   : Set limit to  1  M/s. │
                             │                │         │ -n  1G    :  Set  limit to 1 │
                             │                │         │ G/s.                         │
                             └────────────────┴─────────┴──────────────────────────────┘

   Suricatta command line parameters
       Example: swupdate -u "-t default -u localhost:8080 -i 1B7"

       Note that different suricatta modules may have different parameters.  The below listed  options  are  for
       SWUpdate's hawkBit support.

       Mandatory arguments are marked with '*':
                        ┌─────────────────────────┬───────────┬──────────────────────────────┐
                        │ Parameter               │ Type      │ Description                  │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -t <tenant>             │ string    │ *  Set hawkBit tenant ID for │
                        │                         │           │ this device.                 │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -u <url>                │ string    │ *  Host  and  port  of   the │
                        │                         │           │ hawkBit    instance,   e.g., │
                        │                         │           │ localhost:8080               │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -i <id>                 │ integer   │ *   The   device    ID    to │
                        │                         │           │ communicate to hawkBit.      │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -c <confirm>            │ integer   │ Confirm   update  status  to │
                        │                         │           │ server: 1=AGAIN,  2=SUCCESS, │
                        │                         │           │ 3=FAILED                     │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -x                      │           │ Do   not   abort  on  flawed │
                        │                         │        •  │ server certificates.         │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -p <polldelay>          │ integer   │ Delay in seconds between two │
                        │                         │           │ hawkBit   poll    operations │
                        │                         │           │ (default: 45s).              │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -r <retry>              │ integer   │ Resume and retry interrupted │
                        │                         │           │ downloads     (default:    5 │
                        │                         │           │ tries).                      │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -w <retrywait>          │ integer   │ Time to wait prior to  retry │
                        │                         │           │ and    resume   a   download │
                        │                         │           │ (default: 5s).               │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -y <proxy>              │ string    │ Use proxy. Either give proxy │
                        │                         │           │ URL,  else  {http,all}_proxy │
                        │                         │           │ env is tried.                │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -k <targettoken>        │ string    │ Set target token.            │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -g <gatewaytoken>       │ string    │ Set gateway token.           │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -f <interface>          │ string    │ Set the network interface to │
                        │                         │           │ connect to hawkBit.          │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -e                      │           │ Daemon  enabled  at  startup │
                        │                         │        •  │ (default).                   │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -d                      │           │ Daemon disabled at startup.  │
                        │                         │        •  │                              │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ --disable-token-for-dwl │           │ Do not  send  authentication │
                        │                         │        •  │ header when downloading SWU. │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ --cache-file            │ string    │ This allows one to resume an │
                        │                         │           │ update after a power cut. If │
                        │                         │           │ the  SWU is saved in a file, │
                        │                         │           │ SWUpdate can reuse the  file │
                        │                         │           │ and    download   just   the │
                        │                         │           │ remaining part of the SWU.   │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -m <seconds>            │ integer   │ Delay  in  seconds   between │
                        │                         │           │ re-trying  to  send  initial │
                        │                         │           │ feedback specified with "-c" │
                        │                         │           │ option. Default value is  10 │
                        │                         │           │ seconds.   If  Suricatta  is │
                        │                         │           │ started with  initial  state │
                        │                         │           │ of STATE_WAIT ("-c 6"), this │
                        │                         │           │ value is ignored.            │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -s <seconds>            │ integer   │ Connection timeout to use in │
                        │                         │           │ seconds.   If  user  doesn't │
                        │                         │           │ set  this  option,   default │
                        │                         │           │ libcurl  connection  timeout │
                        │                         │           │ value  of  300  seconds   is │
                        │                         │           │ used.    NOTE:   it  is  not │
                        │                         │           │ possible  for  Suricatta  to │
                        │                         │           │ respond  to external program │
                        │                         │           │ API  requests  during   this │
                        │                         │           │ period - adapt this value to │
                        │                         │           │ your use case!               │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -a <name> <value>       │ strings   │ Custom   HTTP   header  with │
                        │                         │           │ given name and value  to  be │
                        │                         │           │ sent with every HTTP request │
                        │                         │           │ made.                        │
                        ├─────────────────────────┼───────────┼──────────────────────────────┤
                        │ -n <value>              │ string    │ Maximum download speed to be │
                        │                         │           │ used.  Value be specified in │
                        │                         │           │ kB/s,  B/s,  MB/s  or  GB/s. │
                        │                         │           │ Examples:  -n  100k  :   Set │
                        │                         │           │ limit  to  100 kB/s.  -n 500 │
                        │                         │           │ : Set limit to 500 B/s.   -n │
                        │                         │           │ 2M    :  Set limit to 1 M/s. │
                        │                         │           │ -n 1G   :  Set  limit  to  1 │
                        │                         │           │ G/s.                         │
                        └─────────────────────────┴───────────┴──────────────────────────────┘

   Webserver command line parameters
       Example: swupdate -w "-r /www -p 8080"

       Mandatory arguments are marked with '*':
                        ┌───────────────────────────┬─────────┬──────────────────────────────┐
                        │ Parameter                 │ Type    │ Description                  │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ -r <document root>        │ string  │ *  Path where the web app is │
                        │                           │         │ stored.                      │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ -p <port>                 │ integer │ * TCP port to be listened if │
                        │                           │         │ not set, 8080 is used        │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ -s <ssl>                  │         │ * Enable SSL support.  Note: │
                        │                           │         │ it  must  be configured with │
                        │                           │         │ CONFIG_MONGOOSESSL           │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ --ssl-cert <cert>         │ string  │ Path to the  certificate  to │
                        │                           │         │ present to clients           │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ -K <key>                  │ string  │ Path to key corresponding to │
                        │                           │         │ ssl certificate              │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ -t <timeout>              │ integer │ Timeout    to   consider   a │
                        │                           │         │ connection lost  if  clients │
                        │                           │         │ stops  to send data. If hit, │
                        │                           │         │ an   update   is    aborted. │
                        │                           │         │ Default=0 (unlimited)        │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │ --auth-domain <string>    │ string  │ Set   authentication  domain │
                        │                           │         │ Default: none                │
                        ├───────────────────────────┼─────────┼──────────────────────────────┤
                        │                           │ string  │ Set authentication  file  if │
                        │        --global-auth-file │         │ any Default: none            │
                        │               <string>    │         │                              │
                        └───────────────────────────┴─────────┴──────────────────────────────┘

   systemd Integration
       SWUpdate  has  optional  systemd  <https://www.freedesktop.org/wiki/Software/systemd/>  support  via  the
       compile-time configuration switch CONFIG_SYSTEMD. If enabled, SWUpdate  signals  systemd  about  start-up
       completion and can make optional use of systemd's socket-based activation feature.

       A  sample  systemd  service  unit  file  /etc/systemd/system/swupdate.service may look like the following
       starting SWUpdate in suricatta daemon mode:

          [Unit]
          Description=SWUpdate daemon
          Documentation=https://github.com/sbabic/swupdate
          Documentation=https://sbabic.github.io/swupdate

          [Service]
          Type=notify
          RuntimeDirectory=swupdate
          RuntimeDirectoryPreserve=yes
          ExecStart=/usr/bin/swupdate -u '-t default -u http://localhost -i 25'

          [Install]
          WantedBy=multi-user.target

       Started via systemctl start swupdate.service, SWUpdate (re)creates its  sockets  on  startup.  For  using
       socket-based  activation, an accompanying systemd socket unit file /etc/systemd/system/swupdate.socket is
       required:

          [Unit]
          Description=SWUpdate socket listener
          Documentation=https://github.com/sbabic/swupdate
          Documentation=https://sbabic.github.io/swupdate

          [Socket]
          ListenStream=/run/swupdate/sockinstctrl
          ListenStream=/run/swupdate/swupdateprog

          [Install]
          WantedBy=sockets.target

       On swupdate.socket being started, systemd creates the socket files and hands them over to  SWUpdate  when
       it  starts.  So, for example, when talking to /run/swupdate/swupdateprog, systemd starts swupdate.service
       and hands-over the socket files. The socket files are also handed over on a "regular" start  of  SWUpdate
       via systemctl start swupdate.service.

       Note,  that  all  dependent  services  need to access the swupdate sockets via the paths specified in the
       swupdate.socket systemd unit.

   Changes in boot-loader code
       The SWUpdate consists of kernel and a root filesystem (image) that must be started  by  the  boot-loader.
       In case using U-Boot, the following mechanism can be implemented:

       • U-Boot checks if a sw update is required (check gpio, serial console, etc.).

       • the script "altbootcmd" sets the rules to start SWUpdate

       • in case SWUpdate is required, U-boot run the script "altbootcmd"

       Is  it  safe  to change U-Boot environment ? Well, it is, but U-Boot must be configured correctly. U-Boot
       supports two copies of the environment to be power-off safe during an  environment  update.  The  board's
       configuration  file must have defined CONFIG_ENV_OFFSET_REDUND or CONFIG_ENV_ADDR_REDUND. Check in U-Boot
       documentation for these constants and how to use them.

       There are a further enhancement that can be optionally integrated into U-boot to make the  system  safer.
       The  most  important  I  will  suggest  is to add support for boot counter in U-boot (documentation is in
       U-Boot docs). This allows U-Boot to track for attempts to successfully run the application,  and  if  the
       boot counter is greater as a limit, can start automatically SWUpdate to replace a corrupt software.

       GRUB by default does not support double copies of environment as in case of U-Boot. This means that there
       is possibility that environment block get's corrupted when power-off occurs during environment update. To
       minimize  the risk, we are not modifying original environment block. Variables are written into temporary
       file and after successful operation rename instruction is called.

   Image File Format
       SWUpdate uses cpio as image file format because it is a simple, well-established, and streamable  format.
       More specifically, the New ASCII format (header magic number 070701) and the New CRC format (header magic
       number  070702)  are  supported.   Both  formats  are  essentially  equivalent  with  the  New CRC format
       additionally having set the cpio header field check to the least-significant 32 bits of the  sum  of  all
       (unsigned)  data  bytes.  This  checksum  is  verified by SWUpdate.  If this verification fails, SWUpdate
       yields an error like the following:

          Checksum WRONG ! Computed 0xfa11ed00, it should be 0xffffffff

       Note that there's artifact sha256 verification available (see CONFIG_HASH_VERIFY)  which  is  recommended
       over relying on cpio's checksum facility.

       For  both  cpio formats, the New ASCII as well as the New CRC format, the cpio file size is limited to 32
       Bit, i.e., 4 GB.

   Building a single image
       cpio is used as container format because of its simplicity and its  ability  to  be  streamed.  The  meta
       information  file  sw-description  (default,  see  CONFIG_SETSWDESCRIPTION)  describing the images in the
       container must be the first file in the cpio archive. The images follow it, in any order.

       To produce an image, a script like the following can be used:

          CONTAINER_VER="1.0"
          PRODUCT_NAME="my-software"
          FILES="sw-description image1.ubifs  \
                 image2.gz.u-boot uImage.bin myfile sdcard.img"
          for i in $FILES;do
                  echo $i;done | cpio -ov -H crc >  ${PRODUCT_NAME}_${CONTAINER_VER}.swu

       Alternatively, swugenerator <https://github.com/sbabic/swugenerator/> may be used to generate the image.

       The generated image can be checked by running the following command:

          swupdate -c -i my-software_1.0.swu

   Support of compound image
       A single image can  be  built  automatically  inside  Yocto.   meta-swupdate  <https://github.com/sbabic/
       meta-swupdate>  extends  the  classes  with the swupdate class. A recipe should inherit it and add an own
       sw-description file to generate the image.

       Alternatively, swugenerator <https://github.com/sbabic/swugenerator/> may be used  to  generate  compound
       images outside Yocto.

UPDATE STRATEGY EXAMPLES

       SWUpdate  is a building block and it allows one to design and implementing its own update strategy.  Even
       if many projects have common ways for updating, it is possible to high  customize  the  update  for  each
       project.   The most common strategies (single-copy and dual-copy) were already described at the beginning
       of this documentation and of course are well supported in SWUpdate.

   Single copy - running as standalone image
       See Single copy - running as standalone image <#single-copy>.

   Double copy with fall-back
       See Double copy with fall-back <#double-copy>.

   Combine double-copy with rescue system
       This provides a recovery procedure to cover update failure in severe cases when software is damaged.   In
       case  none  of  the  copy can be started, the bootloader will start the rescue system (possibly stored on
       another storage as the main system) to try to rescue the board.  [image]

       The rescue system can be updated as well during a standard update.

   Split system update with application update
       Updating a whole image is quite straightforward, but this means to transfer bigger amount of data if just
       a few files are updated. It is possible to split the update  in  several  smaller  parts  to  reduce  the
       transfer size. This requires a special care to take care of compatibility between system and application,
       that  can be solved with customized Lua scripts in the sw-description file.  SWUpdate supports versioning
       for each artefact, and anyone can add own rules to verify compatibility between components.  [image]

   Configuration update
       Thought to update the software, SWUpdate can be used to install configuration data as well.  Build system
       can create configuration SWU with files / data  for  the  configuration  of  the  system.   There  is  no
       requirements  what  these  SWU should contains - it is duty of the integrator to build them and make them
       suitable for his own project. Again, configuration data can be updated as separate process using  one  of
       the above scenarios.

SWUPDATE: SYNTAX AND TAGS WITH THE DEFAULT PARSER

   Introduction
       SWUpdate  uses  the  library  "libconfig"  as  default  parser for the image description.  However, it is
       possible to extend SWUpdate and add an own parser, based on a different syntax and language  as  the  one
       supported by libconfig. In the examples directory there is the code for a parser written in Lua, with the
       description in XML.

       Using  the  default  parser,  sw-description  follows the syntax rules described in the libconfig manual.
       Please take a look at <http://www.hyperrealm.com/libconfig/libconfig_manual.html> for an  explanation  of
       basic  types.   The  whole  description must be contained in the sw-description file itself: using of the
       #include directive is not allowed by SWUpdate.

       The following example explains the implemented tags:

          software =
          {
                  version = "0.1.0";
                  description = "Firmware update for XXXXX Project";

                  hardware-compatibility: [ "1.0", "1.2", "1.3"];

                  /* partitions tag is used to resize UBI partitions */
                  partitions: ( /* UBI Volumes */
                          {
                                  name = "rootfs";
                                  device = "mtd4";
                                  size = 104896512; /* in bytes */
                          },
                          {
                                  name = "data";
                                  device = "mtd5";
                                  size = 50448384; /* in bytes */
                          }
                  );

                  images: (
                          {
                                  filename = "rootfs.ubifs";
                                  volume = "rootfs";
                          },
                          {
                                  filename = "swupdate.ext3.gz.u-boot";
                                  volume = "fs_recovery";
                          },
                          {
                                  filename = "sdcard.ext3.gz";
                                  device = "/dev/mmcblk0p1";
                                  compressed = "zlib";
                          },
                          {
                                  filename = "bootlogo.bmp";
                                  volume = "splash";
                          },
                          {
                                  filename = "uImage.bin";
                                  volume = "kernel";
                          },
                          {
                                  filename = "fpga.txt";
                                  type = "fpga";
                          },
                          {
                                  filename = "bootloader-env";
                                  type = "bootloader";
                          }
                  );

                  files: (
                          {
                                  filename = "README";
                                  path = "/README";
                                  device = "/dev/mmcblk0p1";
                                  filesystem = "vfat";
                          }
                  );

                  scripts: (
                          {
                                  filename = "erase_at_end";
                                  type = "lua";
                          },
                          {
                                  filename = "display_info";
                                  type = "lua";
                          }
                  );

                  bootenv: (
                          {
                                  name = "vram";
                                  value = "4M";
                          },
                          {
                                  name = "addfb";
                                  value = "setenv bootargs ${bootargs} omapfb.vram=1:2M,2:2M,3:2M omapdss.def_disp=lcd";
                          }
                  );
          }

       The first tag is "software". The whole description is contained in this tag.  It  is  possible  to  group
       settings per device by using Board specific settings.

   Handling configuration differences
       The  concept  can be extended to deliver a single image containing the release for multiple devices. Each
       device has its own kernel, dtb, and root filesystem, or they can share some parts.

       Currently this is managed (and already used in a real project) by writing  an  own  parser,  that  checks
       which images must be installed after recognizing which is the device where software is running.

       Because  the  external  parser can be written in Lua and it is completely customizable, everybody can set
       his own rules.  For this specific example, the  sw-description  is  written  in  XML  format,  with  tags
       identifying the images for each device. To run it, the liblxp library is needed.

          <?xml version="1.0" encoding="UTF-8"?>
          <software version="1.0">
            <name>Update Image</name>
            <version>1.0.0</version>
            <description>Firmware for XXXXX Project</description>

            <images>
              <image device="firstdevice" version="0.9">
                <stream name="dev1-uImage" type="ubivol" volume="kernel" />
                <stream name="dev1.dtb" type="ubivol" volume="dtb" />
                <stream name="dev1-rootfs.ubifs" type="ubivol" volume="rootfs"/>
                <stream name="dev1-uboot-env" type="uboot" />
                <stream name="raw_vfat" type="raw" dest="/dev/mmcblk0p4" />
                <stream name="sdcard.lua" type="lua" />
              </image>

              <image device="seconddevice" version="0.9">
                <stream name="dev2-uImage" type="ubivol" volume="kernel" />
                <stream name="dev2.dtb" rev="0.9" type="ubivol" volume="dtb" />
                <stream name="dev2-rootfs.ubifs" type="ubivol" volume="rootfs"/>
              </image>
            </images>
          </software>

       The  parser  for  this  is  in  the /examples directory.  By identifying which is the running device, the
       parser return a table containing the images that must be installed and  their  associated  handlers.   By
       reading  the  delivered  image, SWUpdate will ignore all images that are not in the list processed by the
       parser. In this way, it is possible to have a single delivered image for the update of multiple devices.

       Multiple devices are supported by the default parser, too.

          software =
          {
              version = "0.1.0";

              target-1 = {
                      images: (
                              {
                                      ...
                              }
                      );
              };

              target-2 = {
                      images: (
                              {
                                      ...
                              }
                      );
              };
          }

       In this way, it is possible to have a single image providing software for each device you have.

       By default, the hardware information is extracted from /etc/hwrevision file. The file  should  contain  a
       single line in the following format:
          <boardname> <revision>

       Where:

       • <revision> will be used for matching with hardware compatibility list

       • <boardname> can be used for grouping board specific settings

   Software collections
       Software collections and operation modes can be used to implement a dual copy strategy. The simplest case
       is  to  define  two  installation  locations  for  the  firmware  image  and  call SWUpdate selecting the
       appropriate image.

          software =
          {
                  version = "0.1.0";

                  stable = {
                          copy-1: {
                                  images: (
                                  {
                                          device = "/dev/mtd4"
                                          ...
                                  }
                                  );
                          }
                          copy-2: {
                                  images: (
                                  {
                                          device = "/dev/mtd5"
                                          ...
                                  }
                                  );
                          }
                  };
          }

       In this way it is possible to specify that copy-1 gets installed to /dev/mtd4, while copy-2 to /dev/mtd5.
       By properly selecting the installation locations, SWUpdate will update the firmware in the other slot.

       The method of image selection is out of the scope  of  SWUpdate  and  user  is  responsible  for  calling
       SWUpdate passing proper settings.

   Priority finding the elements in the file
       SWUpdate search for entries in the sw-description file according to the following priority:

       1. Try <boardname>.<selection>.<mode>.<entry>

       2. Try <selection>.<mode>.<entry>

       3. Try <boardname>.<entry>

       4. Try <entry>

       Take an example. The following sw-description describes the release for a set of boards.

          software =
          {
                  version = "0.1.0";

                  myboard = {
                      stable = {
                          copy-1: {
                                  images: (
                                  {
                                          device = "/dev/mtd4"
                                          ...
                                  }
                                  );
                          }
                          copy-2: {
                                  images: (
                                  {
                                          device = "/dev/mtd5"
                                          ...
                                  }
                                  );
                          }
                      }
                  }

                  stable = {
                      copy-1: {
                            images: (
                                {
                                     device = "/dev/mtd6"
                                          ...
                                }
                             );
                      }
                      copy-2: {
                             images: (
                             {
                                     device = "/dev/mtd7"
                                          ...
                             }
                             );
                      }
                  }
          }

       On  myboard,  SWUpdate  searches  and  finds  myboard.stable.copy1(2).  When running on different boards,
       SWUpdate does not find an entry corresponding to the boardname and it falls back to the  version  without
       boardname.  This  allows  to  realize the same release for different boards having a completely different
       hardware. myboard could have an eMMC and an ext4 filesystem, while another device can have raw flash  and
       install  an  UBI  filesystem. Nevertheless, they are both just a different format of the same release and
       they could be described together in sw-description.  It is important to  understand  the  priorities  how
       SWUpdate scans for entries during the parsing.

   Using links
       sw-description  can  become very complex. Let's think to have just one board, but in multiple hw revision
       and they differ in Hardware. Some of them can be grouped together,  some  of  them  require  a  dedicated
       section.  A way (but not the only one !) could be to add mode and selects the section with -e stable,<rev
       number>.

          software =
          {
                  version = "0.1.0";

                  myboard = {
                      stable = {

                          hardware-compatibility: ["1.0", "1.2", "2.0", "1.3", "3.0", "3.1"];
                          rev-1.0: {
                                  images: (
                                          ...
                                  );
                                  scripts: (
                                          ...
                                  );
                          }
                          rev-1.2: {
                                  hardware-compatibility: ["1.2"];
                                  images: (
                                          ...
                                  );
                                  scripts: (
                                          ...
                                  );
                          }
                          rev-2.0: {
                                  hardware-compatibility: ["2.0"];
                                  images: (
                                          ...
                                  );
                                  scripts: (
                                     ...
                                  );
                          }
                          rev-1.3: {
                                  hardware-compatibility: ["1.3"];
                                  images: (
                                      ...
                                  );
                                  scripts: (
                                      ...
                                  );
                          }

                          rev-3.0:
                          {
                                  hardware-compatibility: ["3.0"];
                                  images: (
                                          ...
                                  );
                                  scripts: (
                                          ...
                                  );
                          }
                          rev-3.1:
                          {
                                  hardware-compatibility: ["3.1"];
                                  images: (
                                          ...
                                  );
                                  scripts: (
                                          ...
                                  );
                          }
                       }
                  }
          }

       If each of them requires an own section, it is the way to do. Anyway, it is more probable than  revisions
       can  be  grouped  together,  for  example  board  with the same major revision number could have the same
       installation instructions. This leads in the example to 3 groups for rev1.X, rev2.X,  and  rev3.X.  Links
       allow  one  to  group section together. When a "ref" is found when SWUpdate searches for a group (images,
       files, script, bootenv), it replaces the current path in the tree with the value of the string.  In  this
       way, the example above can be written in this way:

           software =
           {
                   version = "0.1.0";

                   myboard = {
                       stable = {

                           hardware-compatibility: ["1.0", "1.2", "2.0", "1.3", "3.0", "3.1"];
                           rev-1x: {
                                   images: (
                                      ...
                                   );
                                   scripts: (
                                       ...
                                   );
                           }
                           rev1.0 = {
                                   ref = "#./rev-1x";
                           }
                           rev1.2 = {
                                   ref = "#./rev-1x";
                           }
                           rev1.3 = {
                                   ref = "#./rev-1x";
                           }
                           rev-2x: {
                                   images: (
                                        ...
                                   );
                                   scripts: (
                                        ...
                                   );
                           }
                           rev2.0 = {
                                   ref = "#./rev-2x";
                           }

                           rev-3x: {
                                   images: (
                                        ...
                                   );
                                   scripts: (
                                         ...
                                   );
                           }
                           rev3.0 = {
                                   ref = "#./rev-3x";
                           }
                           rev3.1 = {
                                   ref = "#./rev-3x";
                           }
                        }
                   }
          }

       The  link  can  be  absolute or relative. The keyword "ref" is used to indicate a link. If this is found,
       SWUpdate will traverse the tree and replaces the current path with the values find in the string  pointed
       by "ref". There are simple rules for a link:

          • it must start with the character '#'

          • "." points to the current level in the tree, that means the parent of "ref"

          • ".." points to the parent level in the tree

          • "/" is used as filed separator in the link

       A  relative path has a number of leading "../" to move the current cursor to the parent leaf of the tree.
       In the following example, rev40 sets a link to a "common" section, where images is found.  This  is  sets
       via  a  link,  too,  to a section in the parent node.  The path software.myboard.stable.common.images  is
       then replaced by software.myboard.stable.trythis

          software =
          {
            version = {
                    ref = "#./commonversion";
            }

            hardware-compatibility = ["rev10", "rev11", "rev20"];

            commonversion = "0.7-linked";

          pc:{
            stable:{

              common:{
                  images =
                  {
                    ref = "#./../trythis";
                  }
                };

              trythis:(
                  {
                  filename = "rootfs1.ext4";
                  device = "/dev/mmcblk0p8";
                  type = "raw";
                  } ,
                  {
                  filename = "rootfs5.ext4";
                  device = "/dev/mmcblk0p7";
                  type = "raw";
                  }
                );
              pdm3rev10:
                {
                images:(
                    {
                    filename = "rootfs.ext3"; device = "/dev/mmcblk0p2";}
                  );
                uboot:(
                    { name = "bootpart";
                    value = "0:2";}
                  );
                };
                pdm3rev11 =
                {
                  ref = "#./pdm3rev10";
                }
                pdm3rev20 =
                {
                  ref = "#./pdm3rev10";
                }
                pdm3rev40 =
                {
                  ref = "#./common";
                }
              };
            };
          }

       Each entry in sw-description can be redirect by a  link  as  in  the  above  example  for  the  "version"
       attribute.

   hardware-compatibility
       hardware-compatibility: [ "major.minor", "major.minor", ... ]

       This entry lists the hardware revisions that are compatible with this software image.

       Example:

          hardware-compatibility: [ "1.0", "1.2", "1.3"];

       This defines that the software is compatible with HW-Revisions 1.0, 1.2, and 1.3, but not with 1.1 or any
       other  version  not  explicitly  listed  here. In the above example, compatibility is checked by means of
       string comparison. If the software is compatible with a large number of hardware revisions,  it  may  get
       cumbersome  to  enumerate  all  compatible  versions.  To  allow  more  compact  specifications,  regular
       expressions (POSIX extended) can be used by adding a prefix  #RE:  to  the  entry.  Rewriting  the  above
       example would yield:

          hardware-compatibility: [ "#RE:^1\.[023]$" ];

       It is in the responsibility of the respective project to find the revision of the board on which SWUpdate
       is  running.  No  assumptions are made about how the revision can be obtained (GPIOs, EEPROM,..) and each
       project is free to select the most appropriate way. In the end the result must be  written  to  the  file
       /etc/hwrevision (or in another file if specified as configuration option) before SWUpdate is started.

   partitions : UBI layout
       This  tag allows one to change the layout of UBI volumes.  Please take care that MTDs are not touched and
       they are configured by the Device Tree or in another way directly in kernel.

          partitions: (
                  {
                          name = <volume name>;
                          size = <size in bytes>;
                          device = <MTD device>;
                  }
          );

       All fields are mandatory. SWUpdate searches for a volume of the given name and if necessary adjusts  size
       or type (see below). If no volume with the given name is found, a new volume is created on the UBI device
       attached  to  the  MTD device given by device. device can be specified by number (e.g. "mtd4") or by name
       (the name of the MTD device, e.g. "ubi_partition"). The UBI device is attached automatically.

       The default behavior of swupdate is to create a dynamic UBI volume. To create a static volume, add a line
       data = "static"; to the respective partition entry.

       If a size of 0 is given, the volume will be deleted if it exists. This  can  be  used  to  remove  orphan
       volumes possibly created by older software versions which are not required anymore.

   images
       The tag "images" collects the image that are installed to the system.  The syntax is:

          images: (
                  {
                          filename[mandatory] = <Name in CPIO Archive>;
                          volume[optional] = <destination volume>;
                          device[optional] = <destination volume>;
                          mtdname[optional] = <destination mtd name>;
                          type[optional] = <handler>;
                          /* optionally, the image can be copied at a specific offset */
                          offset[optional] = <offset>;
                          /* optionally, the image can be compressed if it is in raw mode */
                          compressed;
                  },
                  /* Next Image */
                  .....
          );

       volume  is  only  used to install the image in a UBI volume. volume and device cannot be used at the same
       time. If device is set, the raw handler is automatically selected.

       The following example is to update a UBI volume:

          {
                  filename = "core-image-base.ubifs";
                  volume = "rootfs";
          }

       To update an image in raw mode, the syntax is:

          {
                  filename = "core-image-base.ext3";
                  device = "/dev/mmcblk0p1";
          }

       To flash an image at a specific offset, the syntax is:

          {
                  filename = "u-boot.bin";
                  device = "/dev/mmcblk0p1";
                  offset = "16K";
          }

       The offset handles the following multiplicative suffixes: K=1024 and M=1024*1024.

       However, writing to flash in raw mode must be managed in a special way. Flashes  must  be  erased  before
       copying,  and  writing  into  NAND  must  take  care of bad blocks and ECC errors. For these reasons, the
       handler "flash" must be selected:

       For example, to copy the kernel into the MTD7 of a NAND flash:

          {
                  filename = "uImage";
                  device = "mtd7";
                  type = "flash";
          }

       The filename is mandatory. It is the Name of the file extracted by the stream.  volume is only  mandatory
       in case of UBI volumes. It should be not used in other cases.

       Alternatively, for the handler “flash”, the mtdname can be specified, instead of the device name:

          {
                  filename = "uImage";
                  mtdname = "kernel";
                  type = "flash";
          }

   Files
       It is possible to copy single files instead of images.  This is not the preferred way, but it can be used
       for debugging or special purposes.

          files: (
                  {
                          filename = <Name in CPIO Archive>;
                          path = <path in filesystem>;
                          device[optional] = <device node >;
                          filesystem[optional] = <filesystem for mount>;
                          properties[optional] = {create-destination = "true";}
                  }
          );

       Entries  in  "files"  section  are  managed  as  single  files.  The attributes "filename" and "path" are
       mandatory. Attributes "device" and "filesystem" are optional; they tell SWUpdate to mount device (of  the
       given  filesystem  type,  e.g.  "ext4")  before  copying  "filename"  to  "path".  Without  "device"  and
       "filesystem", the "filename" will be copied to "path" in the current rootfs.

       As a general rule, swupdate doesn't copy out a file if the destination path doesn't exists. This behavior
       could be changed using the special property "create-destination".

       As another general rule, the raw file handler installs the file directly to the specified  path.  If  the
       target  file already exists and the raw file handler is interrupted, the existing file may be replaced by
       an empty or partially written file. A use case can exist where having an empty or corrupted file is worse
       than the existing file. For this reason, the raw file  handler  supports  an  "atomic-install"  property.
       Setting  the  property  to  "true"  installs  the  file to the specified path with ".tmp" appended to the
       filename. Once the contents of the file have been written and the buffer is flushed, the ".tmp"  file  is
       renamed  to  the  target  file.  This  minimizes chances that an empty or corrupted file is created by an
       interrupted raw file handler.

   Scripts
       Scripts runs in the order they are put into the sw-description file.  The result of a script is  valuated
       by SWUpdate, that stops the update with an error if the result is <> 0.

       They are copied into a temporary directory before execution and their name must be unique inside the same
       cpio archive.

       If  no  type  is given, SWUpdate default to "lua". Please note that running a shell script opens a set of
       different security issues, check also chapter "Best practice".

   Lua
          scripts: (
                  {
                          filename = <Name in CPIO Archive>;
                          type = "lua";
                  }
          );

       Lua scripts are run using the internal interpreter.

       They must have at least one of the following functions:

          function preinst()

       SWUpdate scans for all scripts and check for a preinst function.  It  is  called  before  installing  the
       images.

          function postinst()

       SWUpdate  scans  for  all  scripts  and  check for a postinst function. It is called after installing the
       images.

          function postfailure()

       Only in case an update fails, SWUpdate scans for all scripts and check for a postfailure  function.  This
       could be useful in case it is necessary to restore a previous state, for example, in case the application
       was stop, it should run again.

   shellscript
       SWUpdate will run the binary shell "/bin/sh" to execute the script.

          scripts: (
                  {
                          filename = <Name in CPIO Archive>;
                          type = "shellscript";
                  }
          );

       Shell scripts are called by forking the process and running the shell as /bin/sh.  SWUpdate scans for all
       scripts  and  calls them before and after installing the images. SWUpdate passes 'preinst', 'postinst' or
       'postfailure' as first argument to the script.  If the data attribute is defined, its value is passed  as
       the last argument(s) to the script.

   preinstall
          scripts: (
                  {
                          filename = <Name in CPIO Archive>;
                          type = "preinstall";
                  }
          );

       preinstall  are  shell  scripts  and called via system command.  SWUpdate scans for all scripts and calls
       them before installing the images.  If the data attribute is defined, its value is  passed  as  the  last
       argument(s) to the script.

       Note  that  cannot  be  ensured  that preinstall scripts run before an artifact is installed in streaming
       mode. In fact, if streaming is activated, the artifact must be installed as soon as it is  received  from
       network  because there is no temporary copy. Because there is no fix order in the SWU, an artifact can be
       packed before any script in the SWU. The right way  is  to  write  an  "embedded-script"  in  Lua  inside
       sw-description:  because  it  becomes  part  of sw-description, it runs when sw-description is parsed and
       before any handler runs, even before a partition handler.

   postinstall
          scripts: (
                  {
                          filename = <Name in CPIO Archive>;
                          type = "postinstall";
                  }
          );

       postinstall are shell scripts and called via system command.  SWUpdate scans for all  scripts  and  calls
       them  after  installing  the  images.   If the data attribute is defined, its value is passed as the last
       argument(s) to the script.

   Update Transaction and Status Marker
       By default, SWUpdate sets the bootloader environment variable "recovery_status" to "in_progress" prior to
       an update operation and either unsets it or sets it to "failed" after the update operation.  This  is  an
       interface  for  SWUpdate-external  tooling: If there is no "recovery_status" variable in the bootloader's
       environment, the update operation has been successful. Else, if there  is  a  "recovery_status"  variable
       with the value "failed", the update operation has not been successful.

       While  this is in general essential behavior for firmware updates, it needn't be for less critical update
       operations. Hence, whether or not the update transaction marker is set by SWUpdate can be  controlled  by
       the  boolean switch "bootloader_transaction_marker" which is global per sw-description file.  It defaults
       to true. The following example snippet disables the update transaction marker:

          software =
          {
                  version = "0.1.0";
                  bootloader_transaction_marker = false;
                  ...

       It is also possible to disable setting of the transaction  marker  entirely  (and  independently  of  the
       setting in sw-description) by starting SWUpdate with the -M option.

       The  same  applies  to  setting  the update state in the bootloader via its environment variable "ustate"
       (default) to STATE_INSTALLED=1 or STATE_FAILED=3 after an installation. This behavior can be  turned  off
       globally   via   the   -m   option   to   SWUpdate   or   per   sw-description  via  the  boolean  switch
       "bootloader_state_marker".

   reboot flag
       It is possible to signal that a reboot for a specific  update  is  not  required.   This  information  is
       evaluated  by  SWUpdate  just  to  inform a backend about the transaction result. If a postinstall script
       (command line parameter -p) is passed at the startup to perform a reboot,  it  will  be  executed  anyway
       because SWUpdate cannot know the nature of this script.

       SWUpdate  sends  this  information to the progress interface and it is duty of the listeners to interpret
       the information. The attribute is a boolean:

          reboot = false;

       Attribute belongs to the general section, where also version belongs. It is not required to activate  the
       flag with reboot = true because it is the default behavior, so just disabling makes sense.

       The  tool swupdate-progress interprets the flag: if it was started with reboot support (-r parameter), it
       checks if a "no-reboot" message is received and disables to reboot the device for this  specific  update.
       When  the  transaction completes, the reboot feature is activated again in case a new update will require
       to reboot the device. This allows to have on the fly updates, where not the whole software is updated and
       a reboot is not required.

   bootloader
       There are two ways to update the bootloader (currently U-Boot, GRUB, and  EFI  Boot  Guard)  environment.
       First  way  is to add a file with the list of variables to be changed and setting "bootloader" as type of
       the image. This informs SWUpdate to call the bootloader handler to manage  the  file  (requires  enabling
       bootloader  handler in configuration). There is one bootloader handler for all supported bootloaders. The
       appropriate bootloader must be chosen from the bootloader selection menu in menuconfig.

          images: (
                  {
                          filename = "bootloader-env";
                          type = "bootloader";
                  }
          )

       The format of the file is described in U-boot documentation. Each line is in the format

          <name of variable>=<value>

       if value is missing, the variable is unset.

       The format is compatible with U-Boot "env import" command. It is possible to produce the file from target
       as result of "env export".

       Comments are allowed in the file to improve readability, see this example:

          # Default variables
          bootslot=0
          board_name=myboard
          baudrate=115200

          ## Board Revision dependent
          board_revision=1.0

       The second way is to define in a group setting the variables that must be changed:

          bootenv: (
                  {
                          name = <Variable name>;
                          value = <Variable value>;
                  }
          )

       SWUpdate will internally generate a script that will be passed to the bootloader  handler  for  adjusting
       the environment.

       For  backward  compatibility with previously built .swu images, the "uboot" group name is still supported
       as an alias. However, its usage is deprecated.

   SWUpdate persistent variables
       Not all updates require to inform the bootloader about the update, and in many  cases  a  reboot  is  not
       required. There are also cases where changing bootloader's environment is unwanted due to restriction for
       security.  SWUpdate needs then some information after new software is running to understand if everything
       is  fine  or some actions like a fallback are needed. SWUpdate can store such as information in variables
       (like shell variables), that can be stored persistently.  The  library  libubootenv  provide  a  way  for
       saving  such  kind as database in a power-cut safe mode.  It uses the algorythm originally implemented in
       the U-Boot bootloader. It is then guaranteed that the system will always have a  valid  instance  of  the
       environment.  The  library  supports  multiple  environment  databases  at the same time, identifies with
       namespaces.  SWUpdate should be configured to set the namespace used for own variables. This is  done  by
       setting  the  attribute  namespace-vars  in  the  runtime  configuration  file  (swupdate.cfg).  See also
       example/configuration/swupdate.cfg for details.

       The format is the same used with bootloader for single variable:

          vars: (
                  {
                          name = <Variable name>;
                          value = <Variable value>;
                  }
          )

       SWUpdate will set these variables all at once like the bootloader variables. These environment is  stored
       just before writing the bootloader environment, that is always the last step in an update.

   Board specific settings
       Each  setting  can  be  placed  under a custom tag matching the board name. This mechanism can be used to
       override particular setting in board specific fashion.

       Assuming that the hardware information file /etc/hwrevision contains the following entry:

          my-board 0.1.0

       and the following description:

          software =
          {
                  version = "0.1.0";

                  my-board = {
                          bootenv: (
                          {
                                  name = "bootpart";
                                  value = "0:2";
                          }
                          );
                  };

                  bootenv: (
                  {
                          name = "bootpart";
                          value = "0:1";
                  }
                  );
          }

       SWUpdate will set bootpart to 0:2 in bootloader's environment for  this  board.  For  all  other  boards,
       bootpart will be set to 0:1. Board specific settings take precedence over default scoped settings.

   Software collections and operation modes
       Software  collections  and  operations  modes  extend  the  description file syntax to provide an overlay
       grouping all previous configuration tags. The mechanism is similar to Board specific settings and can  be
       used  for implementing a dual copy strategy or delivering both stable and unstable images within a single
       update file.

       The mechanism uses a custom user-defined tags placed within software scope. The tag names must not be any
       of: version, hardware-compatibility, uboot, bootenv, files, scripts, partitions, images

       An example description file:

          software =
          {
                  version = "0.1";

                  hardware-compatibility = [ "revA" ];

                  /* differentiate running image modes/sets */
                  stable:
                  {
                          main:
                          {
                                  images: (
                                  {
                                          filename = "rootfs.ext3";
                                          device = "/dev/mmcblk0p2";
                                  }
                                  );

                                  bootenv: (
                                  {
                                          name = "bootpart";
                                          value = "0:2";
                                  }
                                  );
                          };
                          alt:
                          {
                                  images: (
                                  {
                                          filename = "rootfs.ext3";
                                          device = "/dev/mmcblk0p1";
                                  }
                                  );

                                  bootenv: (
                                  {
                                          name = "bootpart";
                                          value = "0:1";
                                  }
                                  );
                          };

                  };
          }

       The configuration describes a single software collection named stable. Two distinct image  locations  are
       specified for this collection: /dev/mmcblk0p1 and /dev/mmcblk0p2 for main mode and alt mode respectively.

       This  feature  can  be  used  to  implement  a  dual  copy strategy by specifying the collection and mode
       explicitly.

   Versioning schemas in SWUpdate
       SWUpdate can perform version comparisons for the whole Software by checking the version attribute in  the
       common  part  of  sw-description  and  / or for single artifacts. SWUpdate supports two different version
       schemas, and they must be followed if version comparison is requested.

   Numbering schema (default)
       SWUpdate supports a version based on the schema:

          <major>.<minor>.<revision>.<build>

       where each field is a plain number (no alphanumeric) in the range 0..65535.  User can add further  fields
       using  the  dot  separator,  but they are not considered for version comparison. SWUpdate will check if a
       version number is set according to this rule and fall back to semantic version upon failure. The  version
       is  converted  to  a 64 bit number (each field is 16 bit) and compared against the running version of the
       same artifact.

       Please consider that, because additional fields are descriptive only, for the  comparison  they  are  not
       considered.  This  example  contains  version  numbers that are interpreted as the same version number by
       SWUpdate:

          1.2.3.4
          1.2.3.4.5
          1.2.3.4.5.6

       But the following is different:

          1.2.3.4-alpha

       And it is treated as semantic version.

   Semantic version
       SWUpdate supports semantic <https://semver.org/> version. See official documentation for more details.

   Checking version of installed software
       SWUpdate can optionally verify if a sub-image is already installed and, if the version to be installed is
       exactly the same, it can skip to install it. This is very useful in case some high risky image should  be
       installed or to speed up the upgrade process.  One case is if the bootloader needs to be updated. In most
       time,  there is no need to upgrade the bootloader, but practice showed that there are some cases where an
       upgrade is strictly required - the project manager should take the risk. However, it  is  nicer  to  have
       always  the bootloader image as part of the .swu file, allowing to get the whole distro for the device in
       a single file, but the device should install it just when needed.

       SWUpdate searches for a file (/etc/sw-versions is the default location) containing all  versions  of  the
       installed  images.  This must be generated before running SWUpdate.  The file must contain pairs with the
       name of image and version, as:

          <name of component>     <version>

       In sw-description, the optional attributes "name",  "version",  and  "install-if-different"  provide  the
       connection.  Name  and version are then compared with the data in the versions file. install-if-different
       is a boolean that enables the check for this image. It is then possible to check the version just  for  a
       subset of the images to be installed.

       If used with "install-if-different", then version can be any string.  For example:

          bootloader              2015.01-rc3-00456-gd4978d
          kernel                  3.17.0-00215-g2e876af

       There  is  also an attribute "install-if-higher" that checks if the version of the new software is higher
       than the version of the installed software.  If it's false, the new software isn't installed. The goal is
       to avoid installing an older version of software.

       In this case, version can be any of 2 formats. Either the version consists of up  to  4  numbers  in  the
       range  0..65535  separated  by  a  dot,  e.g.  <major>.<minor>.<rev>.<build>, or it is a semantic version
       <https://semver.org>.

          bootloader              2018.03.01
          kernel                  3.17.0-pre1+g2e876af
          rfs                     0.17-foo3.bar5+2020.07.01
          app                     1.7

       It is advised not to mix version formats! Semantic versions only support 3 numbers (major, minor,  patch)
       and the fourth number will be silently dropped if present.

   Embedded Script
       It  is possible to embed a script inside sw-description. This is useful in a lot of conditions where some
       parameters are known just by the target at runtime. The script is global to  all  sections,  but  it  can
       contain several functions that can be specific for each entry in the sw-description file.

       These attributes are used for an embedded-script:

          embedded-script = "<Lua code>"

       It  must  be  taken into account that the parser has already run and usage of double quotes can interfere
       with the parser. For this reason, each double quote in the script must be escaped.

       That means a simple Lua code as:

          print ("Test")

       must be changed to:

          print (\"Test\")

       If not, the parser thinks to have the closure of the  script  and  this  generates  an  error.   See  the
       examples  directory for examples how to use it.  Any entry in files or images can trigger one function in
       the script. The "hook" attribute tells the parser to load the script  and  to  search  for  the  function
       pointed to by the hook attribute. For example:

          files: (
                  {
                          filename = "examples.tar";
                          type = "archive";
                          path = "/tmp/test";
                          hook = "set_version";
                          preserve-attributes = true;
                  }
          );

       After  the entry is parsed, the parser runs the Lua function pointed to by hook. If Lua is not activated,
       the parser raises an error because a sw-description with an embedded  script  must  be  parsed,  but  the
       interpreter is not available.

       Each Lua function receives as parameter a table with the setup for the current entry. A hook in Lua is in
       the format:

          function lua_hook(image)

       image  is a table where the keys are the list of available attributes. If an attribute contains a "-", it
       is replaced with "_", because "-" cannot be used in Lua. This means, for example, that:

          install-if-different ==> install_if_different
          installed-directly   ==> installed_directly

       Attributes can be changed in the Lua script and values are taken over on return.  The Lua  function  must
       return 2 values:

          • a boolean, to indicate whether the parsing was correct

          • the image table or nil to indicate that the image should be skipped

       Example:

          function set_version(image)
                  print (\"RECOVERY_STATUS.RUN: \".. swupdate.RECOVERY_STATUS.RUN)
                  for k,l in pairs(image) do
                          swupdate.trace(\"image[\" .. tostring(k) .. \"] = \" .. tostring(l))
                  end
                  image.version = \"1.0\"
                  image.install_if_different = true
                  return true, image
          end

       The  example  sets a version for the installed image. Generally, this is detected at runtime reading from
       the target.

   Attribute reference
       There are 4 main sections inside sw-description:

       • images: entries are images and SWUpdate has no knowledge about them.

       • files: entries are files, and SWUpdate needs a filesystem for them.  This is generally used  to  expand
         from a tar-ball or to update single files.

       • scripts:  all entries are treated as executables, and they will be run twice (as pre- and post- install
         scripts).

       • bootenv: entries are pair with bootloader environment variable name and its value.

   Attributes in sw-description
            ┌──────────────────────┬────────────────────┬──────────────────────┬────────────────────────┐
            │ Name                 │ Type               │ Applies to           │ Description            │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ filename             │ string             │ images files scripts │ filename as  found  in │
            │                      │                    │                      │ the cpio archive       │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ volume               │ string             │ images               │ Just    if    type   = │
            │                      │                    │                      │ "ubivol".  UBI  volume │
            │                      │                    │                      │ where  image  must  be │
            │                      │                    │                      │ installed.             │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ ubipartition         │ string             │ images               │ Just   if    type    = │
            │                      │                    │                      │ "ubivol". Volume to be │
            │                      │                    │                      │ created   or  adjusted │
            │                      │                    │                      │ with a new size        │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ device               │ string             │ images files         │ devicenode as found in │
            │                      │                    │                      │ /dev or a  symlink  to │
            │                      │                    │                      │ it.  Can  be specified │
            │                      │                    │                      │ as absolute path or  a │
            │                      │                    │                      │ name  in  /dev  folder │
            │                      │                    │                      │ For     example     if │
            │                      │                    │                      │ /dev/mtd-dtb is a link │
            │                      │                    │                      │ to  /dev/mtd3  "mtd3", │
            │                      │                    │                      │ "mtd-dtb", "/dev/mtd3" │
            │                      │                    │                      │ and "/dev/mtd-dtb" are │
            │                      │                    │                      │ valid  names.    Usage │
            │                      │                    │                      │ depends   on  handler. │
            │                      │                    │                      │ For     files,      it │
            │                      │                    │                      │ indicates   on   which │
            │                      │                    │                      │ device             the │
            │                      │                    │                      │ "filesystem"  must  be │
            │                      │                    │                      │ mounted.    If     not │
            │                      │                    │                      │ specified, the current │
            │                      │                    │                      │ rootfs will be used.   │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ filesystem           │ string             │ files                │ indicates          the │
            │                      │                    │                      │ filesystem type  where │
            │                      │                    │                      │ the   file   must   be │
            │                      │                    │                      │ installed.  Only  used │
            │                      │                    │                      │ if  "device" attribute │
            │                      │                    │                      │ is set.                │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ path                 │ string             │ files                │ For  files:  indicates │
            │                      │                    │                      │ the   path  (absolute) │
            │                      │                    │                      │ where the file must be │
            │                      │                    │                      │ installed. If "device" │
            │                      │                    │                      │ and  "filesystem"  are │
            │                      │                    │                      │ set,   SWUpdate   will │
            │                      │                    │                      │ install the file after │
            │                      │                    │                      │ mounting "device" with │
            │                      │                    │                      │ "filesystem"     type. │
            │                      │                    │                      │ (path     is    always │
            │                      │                    │                      │ relative to the  mount │
            │                      │                    │                      │ point.)                │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ preserve-attributes  │ bool               │ files                │ flag     to    control │
            │                      │                    │                      │ whether the  following │
            │                      │                    │                      │ attributes   will   be │
            │                      │                    │                      │ preserved  when  files │
            │                      │                    │                      │ are  unpacked  from an │
            │                      │                    │                      │ archive      (assuming │
            │                      │                    │                      │ destination filesystem │
            │                      │                    │                      │ supports    them,   of │
            │                      │                    │                      │ course):    timestamp, │
            │                      │                    │                      │ uid/gid     (numeric), │
            │                      │                    │                      │ perms,            file │
            │                      │                    │                      │ attributes,   extended │
            │                      │                    │                      │ attributes             │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ type                 │ string             │ images files scripts │ string identifier  for │
            │                      │                    │                      │ the  handler, as it is │
            │                      │                    │                      │ set  by  the   handler │
            │                      │                    │                      │ when    it   registers │
            │                      │                    │                      │ itself.       Example: │
            │                      │                    │                      │ "ubivol",       "raw", │
            │                      │                    │                      │ "rawfile",             │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ compressed           │ string             │ images files         │ string to indicate the │
            │                      │                    │                      │ "filename"          is │
            │                      │                    │                      │ compressed and must be │
            │                      │                    │                      │ decompressed    before │
            │                      │                    │                      │ being  installed.  the │
            │                      │                    │                      │ value    denotes   the │
            │                      │                    │                      │ compression      type. │
            │                      │                    │                      │ currently    supported │
            │                      │                    │                      │ values are "zlib"  and │
            │                      │                    │                      │ "zstd".                │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ compressed           │ bool (dep recated) │ images files         │ Deprecated.   Use  the │
            │                      │                    │                      │ string form.  true  is │
            │                      │                    │                      │ equal to 'compressed = │
            │                      │                    │                      │ "zlib"'.               │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ installed-directly   │ bool               │ images               │ flag  to indicate that │
            │                      │                    │                      │ image is streamed into │
            │                      │                    │                      │ the target without any │
            │                      │                    │                      │ temporary  copy.   Not │
            │                      │                    │                      │ all  handlers  support │
            │                      │                    │                      │ streaming.             │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ name                 │ string             │ bootenv              │ name of the bootloader │
            │                      │                    │                      │ variable to be set.    │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ value                │ string             │ bootenv              │ value to  be  assigned │
            │                      │                    │                      │ to    the   bootloader │
            │                      │                    │                      │ variable               │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ name                 │ string             │ images files         │ name  that  identifies │
            │                      │                    │                      │ the   sw-component  it │
            │                      │                    │                      │ can be any string  and │
            │                      │                    │                      │ it  is  compared  with │
            │                      │                    │                      │ the     entries     in │
            │                      │                    │                      │ sw-versions            │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ version              │ string             │ images files         │ version     for    the │
            │                      │                    │                      │ sw-component it can be │
            │                      │                    │                      │ any string and  it  is │
            │                      │                    │                      │ compared    with   the │
            │                      │                    │                      │ entries in sw-versions │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ description          │ string             │                      │ user-friendly          │
            │                      │                    │                      │ description   of   the │
            │                      │                    │                      │ swupdate  archive (any │
            │                      │                    │                      │ string)                │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ reboot               │ bool               │                      │ allows   to    disable │
            │                      │                    │                      │ reboot for the current │
            │                      │                    │                      │ running update         │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ install-if-different │ bool               │ images files         │ flag  if set, name and │
            │                      │                    │                      │ version  are  compared │
            │                      │                    │                      │ with  the  entries  in │
            │                      │                    │                      │ sw-versions            │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ install-if-higher    │ bool               │ images files         │ flag if set, name  and │
            │                      │                    │                      │ version  are  compared │
            │                      │                    │                      │ with  the  entries  in │
            │                      │                    │                      │ sw-versions            │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ encrypted            │ bool               │ images files scripts │ flag  if  set, file is │
            │                      │                    │                      │ encrypted and must  be │
            │                      │                    │                      │ decrypted       before │
            │                      │                    │                      │ installing.            │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ ivt                  │ string             │ images files scripts │ IVT   in    case    of │
            │                      │                    │                      │ encrypted  artefact It │
            │                      │                    │                      │ has   no   value    if │
            │                      │                    │                      │ "encrypted"   is   not │
            │                      │                    │                      │ set. Each artefact can │
            │                      │                    │                      │ have  an  own  IVT  to │
            │                      │                    │                      │ avoid   attacker   can │
            │                      │                    │                      │ guess the the key.  It │
            │                      │                    │                      │ is an ASCII string  of │
            │                      │                    │                      │ 32 chars               │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ data                 │ string             │ images files scripts │ This  is  used to pass │
            │                      │                    │                      │ arbitrary  data  to  a │
            │                      │                    │                      │ handler.               │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ sha256               │ string             │ images files scripts │ sha256  hash of image, │
            │                      │                    │                      │ file or script.   Used │
            │                      │                    │                      │ for   verification  of │
            │                      │                    │                      │ signed images.         │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ embedded-script      │ string             │                      │ Lua   code   that   is │
            │                      │                    │                      │ embedded     in    the │
            │                      │                    │                      │ sw-description file.   │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ offset               │ string             │ images               │ Optional   destination │
            │                      │                    │                      │ offset                 │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ hook                 │ string             │ images files         │ The    name   of   the │
            │                      │                    │                      │ function (Lua)  to  be │
            │                      │                    │                      │ called  when the entry │
            │                      │                    │                      │ is parsed.             │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ mtdname              │ string             │ images               │ name  of  the  MTD  to │
            │                      │                    │                      │ update.  Used  only by │
            │                      │                    │                      │ the flash  handler  to │
            │                      │                    │                      │ identify  the  the mtd │
            │                      │                    │                      │ to update, instead  of │
            │                      │                    │                      │ specifying         the │
            │                      │                    │                      │ devicenode             │
            ├──────────────────────┼────────────────────┼──────────────────────┼────────────────────────┤
            │ size                 │ int64              │ images files scripts │ size of the file as it │
            │                      │                    │                      │ is  expected  in   the │
            │                      │                    │                      │ SWU.  If  set  and the │
            │                      │                    │                      │ cpio  size  does   not │
            │                      │                    │                      │ match  for some reason │
            │                      │                    │                      │ the update  will  fail │
            │                      │                    │                      │ with an error.         │
            └──────────────────────┴────────────────────┴──────────────────────┴────────────────────────┘

UPDATE IMAGES FROM VERIFIED SOURCE

       It  is becoming very important that a device must not only be safely updated, but also that it can verify
       if the delivered image is coming from a known source and it was not corrupted introducing some malware.

       To achieve this goal, SWUpdate must verify the incoming images. There are several ways to do this. Should
       the compound image be signed ? Or some parts of it ?

       Advantages and disadvantages are described in the following chapter.

   Signing the compound image
       It looks quite straightforward if the whole compound image is  signed.   However,  this  has  some  heavy
       drawbacks.  It  is  not  possible  to know if the image is verified until the whole image is loaded. This
       means that verification can be done after installing  the  single  images  instead  of  doing  it  before
       touching  the  device.   This  leads  to have some uninstall procedure if part of a not verified image is
       already installed, procedures that cannot be safe in case of power off letting  some  unwanted  piece  of
       software on the device.

   Signing the sub-images
       If  each  sub-image  is  signed, the verification is done before calling the corresponding hardware. Only
       signed images can be installed.  Anyway, this remains unbound with the  description  of  the  release  in
       sw-description. Even if sw-description is signed, an attacker can mix signed images together generating a
       new compound image that can be installed as well, because all sub-images are verified.

   Combining signing sw-description with hash verification
       To avoid the described drawbacks, SWUpdate combines signed sw-description with the verification of hashes
       for each single image. This means that only sw-description generated by a verified source can be accepted
       by  the  installer.  sw-description  contains  hashes  for  each  sub-image to verify that each delivered
       sub-image really belongs to the release.

   Choice of algorithm
       The algorithm chosen to sign  and  verify  the  sw-description  file  can  be  selected  via  menuconfig.
       Currently, the following mechanisms are implemented:

       • RSA  Public  /  private  key. The private key belongs to the build system, while the public key must be
         installed on the target.

       • CMS using certificates

       • GPG key signing

       For RSA and CMS algorithms, key or certificate is passed to SWUpdate with the -k parameter.

   Tool to generate keys / certificates
       For RSA and CMS signing, the openssl tool is used to generate the keys.  This  is  part  of  the  OpenSSL
       project.  A  complete  documentation  can  be found at the openSSL Website <https://www.openssl.org/docs/
       manmaster/man1/openssl.html>.

       For GPG, gpg can be used to generate the keys and to sign the images. A  complete  documentation  can  be
       found at the GnuPG Website <https://www.gnupg.org>.

   Usage with RSA PKCS#1.5 or RSA PSS
   Generating private and public key
       First, the private key must be created:

          openssl genrsa -aes256 -out priv.pem

       This  asks for a passphrase. It is possible to retrieve the passphrase from a file - of course, this must
       be protected against intrusion.

          openssl genrsa -aes256 -passout file:passout -out priv.pem

       The private key is used to export the public key with:

          openssl rsa -in priv.pem -out public.pem -outform PEM -pubout

       "public.pem" contains the key in a format suitable for swupdate. The file can be passed  to  swupdate  at
       the command line with the -k parameter.

   How to sign with RSA
       Signing the image with rsa-pkcs#1.5 is very simple:

          openssl dgst -sha256 -sign priv.pem sw-description > sw-description.sig

       Signing the image with rsa-pss is also very simple:

          openssl dgst -sha256 -sign priv.pem -sigopt rsa_padding_mode:pss \
              -sigopt rsa_pss_saltlen:-2 sw-description > sw-description.sig

   Usage with certificates and CMS
   Generating self-signed certificates
          openssl req -x509 -newkey rsa:4096 -noenc -keyout mycert.key.pem \
              -out mycert.cert.pem -subj "/O=SWUpdate/CN=target" \
              -addext extendedKeyUsage=1.3.6.1.5.5.7.3.4 -addext keyUsage=digitalSignature

       Check  the documentation for more information about parameters. The "mycert.key.pem" contains the private
       key and it is used for signing. It is not delivered on the target.

       The target must have "mycert.cert.pem" installed - this is used by SWUpdate for verification.

       Note:
          The extendedKeyUsage value of "1.3.6.1.5.5.7.3.4" refers to "emailProtection". For  "codeSigning"  use
          "1.3.6.1.5.5.7.3.3".

   Using PKI issued certificates
       It  is  also possible to use PKI issued code signing certificates. However, SWUpdate uses OpenSSL library
       for handling CMS signatures and by default the library requires the following attributes to be set on the
       signing certificate:

          keyUsage=digitalSignature
          extendedKeyUsage=emailProtection

       It is possible to change the default extendedKeyUsage value by  setting  the  cert-purpose  parameter  in
       swupdate.cfg.

       It  is  also  possible  to  completely disable signing certificate key usage checking if this requirement
       cannot be satisfied. This is controlled by CONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE configuration option.

   How to sign with CMS
       Signing the image is simple as in the previous case:

          openssl cms -sign -in  sw-description -out sw-description.sig -signer mycert.cert.pem \
                  -inkey mycert.key.pem -outform DER -nosmimecap -binary

   Usage with GNU PG
   Generating a new keypair
       First, a primary keypair needs to be generated

          gpg --gen-key

       The generated keys can be listed as follows

          gpg -k

       Check the documentation for more information about parameters.

   How to sign with gpg
       Signing the image is very simple:

          gpg --batch --output sw-description.sig
                  --detach-sig sw-description

       For an alternative GnuPG home directory, and if there are multiple keypairs, the following can be used to
       specify. In this example, the GnuPG home directory is in GPG_HOMEDIR, while the signing key is  found  in
       GPG_KEY.

          gpg --batch --homedir "${GPG_HOMEDIR}" --default-key "${GPG_KEY}" --output sw-description.sig
                  --detach-sig sw-description

   Building a signed SWU image
       There are two files, sw-description and its signature sw-description.sig.  The signature file must always
       directly follow the description file.

       Each  image  inside sw-description must have the attribute "sha256", with the SHA256 sum of the image. If
       an image does not have the sha256 attribute, the  whole  compound  image  results  as  not  verified  and
       SWUpdate stops with an error before starting to install.

       A simple script to create a signed image can be:

          #!/bin/bash

          MODE="RSA-PKCS-1.5"
          PRODUCT_NAME="myproduct"
          CONTAINER_VER="1.0"
          IMAGES="rootfs kernel"
          FILES="sw-description sw-description.sig $IMAGES"

          #if you use RSA
          if [ x"$MODE" == "xRSA-PKCS-1.5" ]; then
              openssl dgst -sha256 -sign priv.pem sw-description > sw-description.sig
          elif if [ x"$MODE" == "xRSA-PSS" ]; then
              openssl dgst -sha256 -sign priv.pem -sigopt rsa_padding_mode:pss \
                  -sigopt rsa_pss_saltlen:-2 sw-description > sw-description.sig
          elif if [ x"$MODE" == "xGPG" ]; then
              gpg --batch --homedir "${GPG_HOME_DIR}" --default-key "${GPG_KEY}" \
                  --output sw-description.sig --detach-sig sw-description
          else
              openssl cms -sign -in  sw-description -out sw-description.sig -signer mycert.cert.pem \
                  -inkey mycert.key.pem -outform DER -nosmimecap -binary
          fi
          for i in $FILES;do
                  echo $i;done | cpio -ov -H crc >  ${PRODUCT_NAME}_${CONTAINER_VER}.swu

   Example for sw-description with signed image
       The example applies to a Beaglebone, installing Yocto images:

          software =
          {
                  version = "0.1.0";

                  hardware-compatibility: [ "revC"];

                  images: (
                          {
                              filename = "core-image-full-cmdline-beaglebone.ext3";
                              device = "/dev/mmcblk0p2";
                              type = "raw";
                              sha256 = "43cdedde429d1ee379a7d91e3e7c4b0b9ff952543a91a55bb2221e5c72cb342b";
                          }
                  );
                  scripts: (
                          {
                              filename = "test.lua";
                              type = "lua";
                              sha256 = "f53e0b271af4c2896f56a6adffa79a1ffa3e373c9ac96e00c4cfc577b9bea5f1";
                           }
                  );
          }

   Running SWUpdate with signed images
       Verification  is  activated  by  setting CONFIG_SIGNED_IMAGES in SWUpdate's configuration.  If activated,
       SWUpdate will always check the compound image. For security reasons, it is not possible  to  disable  the
       check at runtime.

       For  RSA  and  CMS  signing, the -k parameter (public key file) is mandatory and the program stops if the
       public key is not passed. For CMS signing, CONFIG_SIGALG_CMS needs to be enabled.

       For GPG signing, CONFIG_SIGALG_GPG needs to be enabled. The GPG key will  need  to  be  imported  to  the
       device's GnuPG home directory. To do this, the key will need to be exported:

          gpg --export <keyid> --output <public key>

       You can then copy it onto the device and import it into your public keyring:

          gpg --import <public key>

       To verify that the key has been imported successfully:

          gpg --list-keys

       SWUpdate will need need to be configured with the following parameters:

          GnuPG Home directory: gpg-home-dir in swupdate.cfg
          GPGME Protocol: gpgme-protocol in swupdate.cfg: openpgp or cms

SYMMETRICALLY ENCRYPTED UPDATE IMAGES

       SWUpdate  allows  one  to symmetrically encrypt update images using the AES block cipher in CBC mode. The
       following shows encryption with 256 bit key length but you may use other key lengths as well.

   Building an Encrypted SWU Image
       First, create a key; for aes-256-cbc we need 32 bytes of key and 16 bytes for  an  initialisation  vector
       (IV).   A  complete  documentation  can  be  found  at the OpenSSL Website <https://www.openssl.org/docs/
       manmaster/man1/openssl.html>.

          openssl rand -hex 32
          # key, for example 390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040
          openssl rand -hex 16
          # IV, for example d5d601bacfe13100b149177318ebc7a4

       Then, encrypt an image using this information via

          openssl enc -aes-256-cbc -in <INFILE> -out <OUTFILE> -K <KEY> -iv <IV>

       where <INFILE> is the unencrypted source image file and <OUTFILE> is the encrypted output image  file  to
       be  referenced  in  sw-description.   <KEY>  is the hex value part of the 2nd line of output from the key
       generation command above and <IV> is the hex value part of the 3rd line.

       Then, create a key file  to  be  supplied  to  SWUpdate  via  the  -K  switch  by  putting  the  key  and
       initialization vector hex values on one line separated by whitespace, e.g., for above example values

          390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040 d5d601bacfe13100b149177318ebc7a4

       Previous  versions of SWUpdate allowed for a salt as third word in key file, that was never actually used
       for aes and has been removed.

       You should change the IV with every encryption,  see  CWE-329  <http://cwe.mitre.org/data/definitions/329
       .html>. The ivt sw-description attribute overrides the key file's IV for one specific image.

   Encryption of UBI volumes
       Due to a limit in the Linux kernel API for UBI volumes, the size reserved to be written on disk should be
       declared before actually writing anything.

       See the property "decrypted-size" in UBI Volume Handler's documentation.

   Example sw-description with Encrypted Image
       The  following  example is a (minimal) sw-description for installing a Yocto image onto a Beaglebone. Pay
       attention to the encrypted = true; setting.

          software =
          {
                  version = "0.0.1";
                  images: ( {
                                  filename = "core-image-full-cmdline-beaglebone.ext3.enc";
                                  device = "/dev/mmcblk0p3";
                                  encrypted = true;
                                  ivt = "65D793B87B6724BB27954C7664F15FF3";
                          }
                  );
          }

   Running SWUpdate with Encrypted Images
       Symmetric  encryption  support  is  activated  by  setting  the  ENCRYPTED_IMAGES  option  in  SWUpdate's
       configuration. Use the -K parameter to provide the symmetric key file generated above to SWUpdate.

   Decrypting with a PKCS#11 token
       PKCS#11  support  is activated by setting the PKCS11 option in SWUpdate's configuration. The key file has
       to have a PKCS#11 URL instead of the key then, containing at least the elements of this example:

          pkcs11:slot-id=42;id=%CA%FE%BA%BE?pin-value=1234&module-path=/usr/lib/libsofthsm2.so 65D793B87B6724BB27954C7664F15FF3

       The encryption key can be imported to the PKCS#11 token by using pkcs11-tool as follow:

          echo -n "390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040" |  xxd -p -r > swupdate-aes-key.bin
          pkcs11-tool --module /usr/lib/libsofthsm2.so --slot 0x42 --login --write-object swupdate-aes-key.bin  --id CAFEBABE --label swupdate-aes-key  --type secrkey --key-type AES:32

HANDLERS

   Overview
       It is quite difficult to foresee all possible installation cases.  Instead of  trying  to  find  all  use
       cases,  SWUpdate  let  the developer free to add his own installer (that is, a new handler), that must be
       responsible to install an image of a certain type.  An image is marked to be of  a  defined  type  to  be
       installed with a specific handler.

       The  parser make the connection between 'image type' and 'handler'.  It fills a table containing the list
       of images to be installed with the required handler to execute the installation. Each image  can  have  a
       different installer.

   Supplied handlers
       In mainline there are the handlers for the most common cases. They include:

              • flash devices in raw mode (both NOR and NAND)

              • UBI volumes

              • UBI volumes partitioner

              • raw flashes handler (NAND, NOR, SPI-NOR, CFI interface)

              • disk partitioner

              • raw devices, such as a SD Card partition

              • bootloader (U-Boot, GRUB, EFI Boot Guard) environment

              • Lua scripts handler

              • shell scripts handler

              • rdiff handler

              • readback handler

              • archive (zo, tarballs) handler

              • remote handler

              • microcontroller update handler

       For example, if an image is marked to be updated into a UBI volume, the parser must fill a supplied table
       setting  "ubi"  as  required  handler,  and  filling  the other fields required for this handler: name of
       volume, size, and so on.

   Creating own handlers
       SWUpdate can be extended with new handlers. The user needs to register his own handler with the core  and
       he  must  provide  the  callback  that  SWUpdate uses when an image required to be installed with the new
       handler.

       The prototype for the callback is:

          int my_handler(struct img_type *img,
                  void __attribute__ ((__unused__)) *data)

       The most important parameter is the pointer to a struct img_type. It describes a single image and  inform
       the  handler  where  the  image  must be installed. The file descriptor of the incoming stream set to the
       start of the image to be installed is also part of the structure.

       The structure img_type contains the file descriptor of the stream pointing to the first byte of the image
       to be installed. The handler must read the whole image, and when it returns back SWUpdate can go on  with
       the next image in the stream.

       The  data  parameter is usually a pointer that was registered with the handler. For script handlers it is
       instead a pointer to a struct script_handler_data which contains a script_fn enum value,  indicating  the
       current installation phase, and the registered data pointer.

       SWUpdate provides a general function to extract data from the stream and copy to somewhere else:

          int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
                  int skip_file, int compressed, uint32_t *checksum, unsigned char *hash);

       fdin  is  the  input  stream, that is img->fdin from the callback. The hash, in case of signed images, is
       simply passed to copyfile() to perform the check, exactly as  the  checksum  parameter.  copyfile()  will
       return an error if checksum or hash do not match. The handler does not need to bother with them.  How the
       handler  manages  the  copied  data,  is specific to the handler itself. See supplied handlers code for a
       better understanding.

       The handler's developer registers his own handler with a call to:

          __attribute__((constructor))
          void my_handler_init(void)
          {
                  register_handler("mytype", my_handler, my_mask, data);
          }

       SWUpdate uses  the  gcc  constructors,  and  all  supplied  handlers  are  registered  when  SWUpdate  is
       initialized.

       register_handler has the syntax:

          register_handler(my_image_type, my_handler, my_mask, data);

       Where:

       • my_image_type : string identifying the own new image type.

       • my_handler : pointer to the installer to be registered.

       • my_mask : HANDLER_MASK enum value(s) specifying what input type(s) my_handler can process.

       • data  :  an optional pointer to an own structure, that SWUpdate saves in the handlers' list and pass to
         the handler when it will be executed.

   UBI Volume Handler
       The UBI volume handler will update UBI volumes without changing the layout  on  the  storage.  Therefore,
       volumes  must be created/adjusted beforehand. This can be done using the partitions tag (see partitions :
       UBI layout <#partitions-ubi-layout>).

       The UBI volume handler will search for volumes in all MTD devices (unless blacklisted, see  UBIBLACKLIST)
       to  find the volume into which the image shall be installed. For this reason, volume names must be unique
       within the system. Two volumes with the same name are  not  supported  and  will  lead  to  unpredictable
       results  (SWUpdate  will  install the image to the first volume with that name it finds, which may not be
       right one!).

       When updating volumes, it is guaranteed that erase counters are preserved and not lost. The  behavior  of
       updating  is identical to that of the ubiupdatevol(1) tool from mtd-utils. In fact, the same library from
       mtd-utils (libubi) is reused by SWUpdate.

   atomic volume renaming
       The UBI volume handler has basic support for carrying out atomic volume renames by defining the  replaces
       property, which must contain a valid UBI volume name. After successfully updating the image to volume, an
       atomic swap of the names of volume and replaces is done. Consider the following example

          {
                  filename ="u-boot.img";
                  volume ="u-boot_r";
                  properties: {
                          replaces = "u-boot";
                  }
          }

       After  u-boot.img  is successfully installed into the volume "u-boot_r", the volume "u-boot_r" is renamed
       to "u-boot" and "u-boot" is renamed to "u-boot_r".

       This mechanism allows one to implement a simple double copy update approach without the  need  of  shared
       state  with  the bootloader. For example, the U-Boot SPL can be configured to always load U-Boot from the
       volume u-boot without the need to access the environment. The volume replace  functionality  will  ensure
       that this volume name always points to the currently valid volume.

       However, please note the following limitations:

       • Currently  the  rename  takes  place  after each image was installed successfully. Hence, it only makes
         sense to use this feature for images that are independent of the  other  installed  images.  A  typical
         example  is  the  bootloader.  This behavior may be modified in the future to only carry out one atomic
         rename after all images were installed successfully.

       • Atomic renames are only possible and permitted for volumes residing on the same UBI device.

       There is a handler ubiswap that allow one to do an atomic swap for  several  ubi  volume  after  all  the
       images  were flashed. This handler is a script for the point of view of swudate, so the node that provide
       it the data should be added in the section scripts.

          scripts: (
                  {
                          type = "ubiswap";
                          properties: {
                                  swap-0 = [ "boot" , " boot_r" ];
                                  swap-1 = [ "kernel" , "kernel_r" ];
                                  swap-2 = [ "rootfs" , "rootfs_r" ];
                          },
                  },
          );

       WARNING: if you use the property replaces on an ubi volume that is also used with  the  handler  ubiswap,
       this ubi volume will be swapped twice.  It's probably not what you want ...

   volume auto resize
       The UBI volume handler has support to auto resize before flashing an image with the property auto-resize.
       When this property is set on an image, the ubi volume is resized to fit exactly the image.

          {
                  filename = "u-boot.img";
                  device = "mtd0";
                  volume = "u-boot_r";
                  properties: {
                          auto-resize = "true";
                  }
          }

       WARNING: when this property is used, the device must be defined.

   volume always remove
       The  UBI  volume  handler  has  support  to  always  remove  ubi volume before flashing with the property
       always-remove. When this property is set on an image, the ubi volume is  always  removed.  This  property
       should be used with property auto-resize.

          {
                  filename = "u-boot.img";
                  device = "mtd0";
                  volume = "u-boot_r";
                  properties: {
                          always-remove = "true";
                          auto-resize = "true";
                  }
          }

   size properties
       Due to a limit in the Linux kernel API for UBI volumes, the size reserved to be written on disk should be
       declared  before  actually writing anything.  Unfortunately, the size of an encrypted or compressed image
       is not known until the decryption or decompression finished. This prevents  correct  declaration  of  the
       file size to be written on disk.

       For  this  reason  UBI  images can declare the special properties "decrypted-size" or "decompressed-size"
       like this:

          images: ( {
                          filename = "rootfs.ubifs.enc";
                          volume = "rootfs";
                          encrypted = true;
                          properties: {
                                  decrypted-size = "104857600";
                          }
                  },
                  {
                          filename = "homefs.ubifs.gz";
                          volume = "homefs";
                          compressed = "zlib";
                          properties: {
                                  decompressed-size = "420000000";
                          }
                  }
          );

       The real size of the image should be calculated and written to the sw-description before  assembling  the
       cpio  archive.   In this example, 104857600 is the size of the rootfs after the decryption: the encrypted
       size is by the way larger. The decompressed size is of the homefs is 420000000.

       The sizes are bytes in decimal notation.

   Lua Handlers
       In addition to the handlers written in C, it is possible to extend SWUpdate with handlers written in  Lua
       that  get  loaded  at  SWUpdate startup. The Lua handler source code file may either be embedded into the
       SWUpdate binary via the CONFIG_EMBEDDED_LUA_HANDLER config option or has to be installed  on  the  target
       system  in  Lua's  search  path  as  swupdate_handlers.lua  so  that it can be loaded by the embedded Lua
       interpreter at run-time.

       In analogy to C handlers, the prototype for a Lua handler is

          --- Lua Handler.
          --
          --- @param  image  img_type  Lua equivalent of `struct img_type`
          --- @return number           # 0 on success, 1 on error
          function lua_handler(image)
              ...
          end

       where image is a Lua  table  (with  attributes  according  to  sw-description's  attribute  reference  <#
       sw-description-attribute-reference>)  that  describes  a  single  artifact to be processed by the handler
       (also see the Lua Handler Interface Specification in handlers/swupdate.lua, reproduced for convenience in
       Section Lua Handler Interface Specification).

       Note that dashes in the attributes' names are replaced with underscores for the Lua domain to  make  them
       idiomatic, e.g., installed-directly becomes installed_directly in the Lua domain.

       For a script handler written in Lua, the prototype is

          --- Lua Handler.
          --
          --- @param  image     img_type  Lua equivalent of `struct img_type`
          --- @param  scriptfn  string    Type, one of `preinst` or `postinst`
          --- @return number              # 0 on success, 1 on error
          function lua_handler(image, scriptfn)
              ...
          end

       where scriptfn is either "preinst" or "postinst".

       To register a Lua handler, the swupdate module provides the swupdate.register_handler() method that takes
       the handler's name, the Lua handler function to be registered under that name, and, optionally, the types
       of  artifacts  for  which  the  handler  may  be  called.  If the latter is not given, the Lua handler is
       registered for all types of artifacts. The following call registers the  above  function  lua_handler  as
       my_handler which may be called for images:

          swupdate.register_handler("my_handler", lua_handler, swupdate.HANDLER_MASK.IMAGE_HANDLER)

       A  Lua  handler may call C handlers ("chaining") via the swupdate.call_handler() method. The callable and
       registered C handlers are available (as keys) in the table swupdate.handler. The following Lua code is an
       example of a simple handler chain-calling the rawfile C handler:

          --- Lua Handler.
          --
          --- @param  image  img_type  Lua equivalent of `struct img_type`
          --- @return number           # 0 on success, 1 on error
          function lua_handler(image)
              if not swupdate.handler["rawfile"] then
                  swupdate.error("rawfile handler not available")
                  return 1
              end
              image.path = "/tmp/destination.path"
              local err, msg = swupdate.call_handler("rawfile", image)
              if err ~= 0 then
                  swupdate.error(string.format("Error chaining handlers: %s", msg))
                  return 1
              end
              return 0
          end

       Note that when chaining handlers and calling a C handler for a different type of artifact  than  the  Lua
       handler  is  registered  for,  the image table's values must satisfy the called C handler's expectations:
       Consider the above Lua handler being registered for  "images"  (swupdate.HANDLER_MASK.IMAGE_HANDLER)  via
       the  swupdate.register_handler()  call  shown  above.  As per the sw-description's attribute reference <#
       sw-description-attribute-reference>, the "images" artifact type doesn't have the path attribute  but  the
       "file"  artifact  type  does.  So,  for  calling  the  rawfile handler, image.path has to be set prior to
       chain-calling the rawfile handler, as done in the example above. Usually, however, no such adaptation  is
       necessary if the Lua handler is registered for handling the type of artifact that image represents.

       In  addition  to  calling  C  handlers,  the  image  table  passed  as  parameter  to a Lua handler has a
       image:copy2file() method that implements the common use case of writing the  input  stream's  data  to  a
       file,  which  is  passed as this method's argument. On success, image:copy2file() returns 0 or -1 plus an
       error  message  on  failure.  The  following  Lua  code  is  an  example  of  a  simple  handler  calling
       image:copy2file():

          --- Lua Handler.
          --
          --- @param  image  img_type  Lua equivalent of `struct img_type`
          --- @return number           # 0 on success, 1 on error
          function lua_handler(image)
              local err, msg = image:copy2file("/tmp/destination.path")
              if err ~= 0 then
                  swupdate.error(string.format("Error calling copy2file: %s", msg))
                  return 1
              end
              return 0
          end

       Beyond  using image:copy2file() or chain-calling C handlers, the image table passed as parameter to a Lua
       handler has a image:read(<callback()>) method that reads from the input stream and calls the Lua callback
       function <callback()> for every chunk read, passing this chunk as parameter. On success, 0 is returned by
       image:read(). On error, -1 plus an error message is returned. The following Lua code is an example  of  a
       simple handler printing the artifact's content:

          --- Lua Handler.
          --
          --- @param  image  img_type  Lua equivalent of `struct img_type`
          --- @return number           # 0 on success, 1 on error
          function lua_handler(image)
              err, msg = image:read(function(data) print(data) end)
              if err ~= 0 then
                  swupdate.error(string.format("Error reading image: %s", msg))
                  return 1
              end
              return 0
          end

       Using the image:read() method, an artifact's contents may be (post-)processed in and leveraging the power
       of Lua without relying on preexisting C handlers for the purpose intended.

       Just  as  C  handlers,  a  Lua handler must consume the artifact described in its image parameter so that
       SWUpdate can continue with the next artifact in the  stream  after  the  Lua  handler  returns.  Chaining
       handlers, calling image:copy2file(), or using image:read() satisfies this requirement.

       The  swupdate Lua module interface specification that details what functionality is made available to Lua
       handlers  by  SWUpdate's  corelib/lua_interface.c  is  found  in  handlers/swupdate.lua.   It  serves  as
       reference, for mocking purposes, and type checking thanks to the EmmyLua-inspired annotations.

       Note that although the dynamic nature of Lua handlers would technically allow one to embed them into a to
       be  processed  .swu  image,  this  is  not implemented as it carries some security implications since the
       behavior of SWUpdate is changed dynamically.

   Lua Handler Interface Specification
          --[[

              SWUpdate Lua Handler Interface.

              Interface specification for the Lua module
              provided by SWUpdate to Lua Handlers.
              See: corelib/lua_interface.c

              Copyright (C) 2022, Siemens AG
              Author: Christian Storm <christian.storm@siemens.com>

              SPDX-License-Identifier: GPL-2.0-or-later

          --]]

          ---@diagnostic disable: missing-return
          ---@diagnostic disable: unused-local
          -- luacheck: no unused args

          --- SWUpdate Lua Handler Module.
          --- @class swupdate
          local swupdate = {}

          --- @enum swupdate.RECOVERY_STATUS
          --- Lua equivalent of `RECOVERY_STATUS` as in `include/swupdate_status.h`.
          swupdate.RECOVERY_STATUS = {
              IDLE       = 0,
              START      = 1,
              RUN        = 2,
              SUCCESS    = 3,
              FAILURE    = 4,
              DOWNLOAD   = 5,
              DONE       = 6,
              SUBPROCESS = 7,
              PROGRESS   = 8
          }

          --- Lua equivalent of `ERROR(format, ...)`.
          --- @param format  string  Format string
          --- @param ...     any     Varargs as referenced in format string
          swupdate.error = function(format, ...) end

          --- Lua equivalent of `TRACE(format, ...)`.
          --- @param format  string  Format string
          --- @param ...     any     Varargs as referenced in format string
          swupdate.trace = function(format, ...) end

          --- Lua equivalent of `INFO(format, ...)`.
          --- @param format  string  Format string
          --- @param ...     any     Varargs as referenced in format string
          swupdate.info  = function(format, ...) end

          --- Lua equivalent of `WARN(format, ...)`.
          --- @param format  string  Format string
          --- @param ...     any     Varargs as referenced in format string
          swupdate.warn  = function(format, ...) end

          --- Lua equivalent of `DEBUG(format, ...)`.
          --- @param format  string  Format string
          --- @param ...     any     Varargs as referenced in format string
          swupdate.debug = function(format, ...) end

          --- Lua equivalent of `notify(PROGRESS, ..., msg)`.
          --- @param msg    string        Message to send to progress interface
          --- @param cause  number | nil  `progress_cause_t` value as defined in `include/progress_ipc.h`
          swupdate.progress = function(msg, cause) end

          --- Lua equivalent of `notify(status, error, INFOLEVEL, msg)`.
          --- @param status  swupdate.RECOVERY_STATUS  Current status, one of `swupdate.RECOVERY_STATUS`'s values
          --- @param error   number                    Error code
          --- @param msg     string                    Message
          swupdate.notify = function(status, error, msg) end

          --- Report whether dry-run installation is performed.
          --
          --- @return boolean  # `true` if dry-run installation is performed, `false` otherwise
          swupdate.is_dryrun = function() end

          --- Update progress.
          --
          --- @param percent  number  Progress percent to set
          swupdate.progress_update = function(percent) end

          --- Mount a filesystem to a temporary mountpoint.
          --
          --- @param  device      string  Device to mount
          --- @param  filesystem  string  Device's filesystem
          --- @return string | nil        # Mountpoint for use with `swupdate.umount(target)`, `nil` on error
          swupdate.mount = function(device, filesystem) end

          --- Unmount a mountpoint returned by `swupdate.mount()`.
          --
          --- @param  target  string  Mountpoint to unmount
          --- @return boolean | nil   # `true` if successful, `nil` on error
          swupdate.umount = function(target) end

          --- @enum swupdate.ROOT_DEVICE
          --- Lua equivalent of `root_dev_type` as in `include/lua_util.h`.
          swupdate.ROOT_DEVICE = {
              PATH      = 0,
              UUID      = 1,
              PARTUUID  = 2,
              PARTLABEL = 3
          }

          --- Current root device information.
          --- @class swupdate.rootdev
          --- @field type   swupdate.ROOT_DEVICE  Root device type, one of `swupdate.ROOT_DEVICE`'s values
          --- @field value  string                Root device path
          --- @field path   string                Full root device path, if identified, else nil

          --- Get current root device.
          --
          --- @return swupdate.rootdev  # Table containing type, and (full) path to root device
          swupdate.getroot = function() end

          --- Get the HW boot device of an eMMC.
          --
          --- @param devicepath  string  Fully qualified device path
          --- @return integer            # eMMC boot device number or `-1` on error
          swupdate.emmcbootpart = function(devicepath) end

          --- Table with major/minor numbers of the device on which the swupdate.stat()'d file resides.
          --- @class swupdate.stat_dev
          --- @field major  number  Major device number
          --- @field minor  number  Minor device number

          --- `struct stat`-alike Table.
          --- @class swupdate.stat_info
          --- @field mode          "directory"|"named pipe"|"link"|"regular file"|"socket"|"block device"|"char device"|"unknown"  File type and mode
          --- @field dev           swupdate.stat_dev  ID of device containing file
          --- @field ino           number             Inode number
          --- @field nlink         number             Number of hard links
          --- @field uid           number             User ID of owner
          --- @field gid           number             Group ID of owner
          --- @field rdev          swupdate.stat_dev  Device ID (if special file)
          --- @field access        string             Time of last access, e.g., "Wed Jun 30 21:49:08 1993"
          --- @field modification  string             Time of last modification, e.g., "Wed Jun 30 21:49:08 1993"
          --- @field change        string             Time of last status change, e.g., "Wed Jun 30 21:49:08 1993"
          --- @field size          number             Total size, in bytes
          --- @field permissions   string             Unix file permissions string, e.g., "rwxr-xr-x"
          --- @field blocks        number             Number of 512B blocks allocated
          --- @field blksize       number             Block size for filesystem I/O

          --- STAT(2) Wrapper.
          --
          --- @param  pathname  string          Retrieve information about the file `pathname`
          --- @return swupdate.stat_info | nil  # `struct stat`-alike Table if successful, nil on error
          swupdate.stat = function(pathname) end

          --- Get SWUpdate's TMPDIRSCRIPT directory.
          --
          --- @return string  # TMPDIRSCRIPT directory
          swupdate.tmpdirscripts = function() end

          --- Get SWUpdate's TMPDIR directory.
          --
          --- @return string  # TMPDIR directory
          swupdate.tmpdir = function() end

          --- SWUpdate hardware information.
          --- @class swupdate.hardware
          --- @field boardname   string  SWUpdate's boardname
          --- @field revision    string  SWUpdate's revision

          --- Get SWUpdate hardware.
          --
          --- @return swupdate.hardware  # Table with 'boardname' and 'revision' fields
          swupdate.get_hw = function() end

          --- SWUpdate version information.
          --- @class swupdate.version
          --- @field [1]         number  SWUpdate's version
          --- @field [2]         number  SWUpdate's patch level
          --- @field version     number  SWUpdate's version
          --- @field patchlevel  number  SWUpdate's patch level

          --- Get SWUpdate version.
          --
          --- @return swupdate.version  # Table with 'version' and 'patchlevel' fields
          swupdate.getversion = function() end

          --- Get software Selection and Mode.
          --
          --- @return string  # Selection
          --- @return string  # Mode
          swupdate.get_selection = function() end

          --- Set Bootloader environment key=value.
          --
          --- @param key    string  Bootloader environment key to set
          --- @param value  string  Value to set `key` to in bootloader environment
          swupdate.set_bootenv = function(key, value) end

          --- Get Bootloader environment key's value.
          --
          --- @param  key  string  Bootloader environment's key to get value from
          --- @return string       # Bootloader environment key's value, empty if key absent
          swupdate.get_bootenv = function(key) end

          --- @enum swupdate.HANDLER_MASK
          --- Lua equivalent of `HANDLER_MASK` as in `include/handler.h`.
          swupdate.HANDLER_MASK = {
              IMAGE_HANDLER      = 1,
              FILE_HANDLER       = 2,
              SCRIPT_HANDLER     = 4,
              BOOTLOADER_HANDLER = 8,
              PARTITION_HANDLER  = 16,
              NO_DATA_HANDLER    = 32,
              ANY_HANDLER        = 1 + 2 + 4 + 8 + 16 + 32
          }

          --- Register a Lua function as Handler implementation.
          --
          -- The signature of the function to be registered as Handler implementation is:
          --
          -- --- @param  image     img_type  Lua equivalent of `struct img_type`
          -- --- @param  fn | nil  string    `preinst` or `postinst` for `SCRIPT_HANDLER`s, else nil
          -- --- @return number    # 0 on success, 1 on error
          -- function lua_handler(image, fn)
          --     ...
          -- end
          --
          --- @param name     string    Registered Handler's name
          --- @param funcptr  function  Function to register as Handler implementation
          --- @param mask     number    Type(s) for which to register the Handler, one or more ORed values of `swupdate.HANDLER_MASK`
          swupdate.register_handler = function(name, funcptr, mask) end

          --- Lua equivalent of `struct img_type {...}` as in `include/swupdate.h` plus `read()` and `copy2file()` functions.
          --- @class img_type
          --- @field name                  string    `sw-component` name to check with `sw-versions`
          --- @field version               string    `sw-component` version to check with `sw-versions`
          --- @field filename              string    File name in CPIO archive
          --- @field volume                string    If handler is "ubivol", the UBI volume name
          --- @field type                  string    The Handler name
          --- @field device                string    Device node to operate on for mounting, flashing, ...
          --- @field path                  string    For FILE_HANDLERs: the relative destination path
          --- @field mtdname               string    MTD device where image must be installed
          --- @field data                  string    Handler-specific arbitrary data
          --- @field filesystem            string    For FILE_HANDLERs: the filesystem to mount
          --- @field ivt                   string    IVT of an encrypted artifact
          --- @field installed_directly    boolean   Whether to stream image to `device` w/o temporary copy
          --- @field install_if_different  boolean   Whether to compare `name` and `version` accordingly
          --- @field install_if_higher     boolean   Whether to compare `name` and `version` accordingly
          --- @field encrypted             boolean   Whether the artifact is encrypted
          --- @field partition             boolean   Whether the artifact is a partitioner
          --- @field script                boolean   Whether the artifact is a script
          --- @field preserve_attributes   boolean   Whether to preserve attributes in archives
          --- @field offset                number    Offset to seek to in artifact
          --- @field size                  number    Artifact size
          --- @field checksum              number    Computed checksum
          --- @field skip                  number    `skip_t` enum number as in `include/swupdate.h`
          --- @field compressed            string    `zlib` or `zstd` (boolean value is deprecated)
          --- @field properties            table     Properties Table equivalent as specified in `sw-description`
          --- @field sha256                string    sha256 hash of the image, file, or script
          local img_type = {
              --- Store the current image artifact to disk.
              --
              --- @param  self  img_type  This `img_type` instance
              --- @param  path  string    Path to store the current image artifact to
              --- @return number          # 0 on success, -1 on error
              --- @return string | nil    # nil on success, error message on failure
              ['copy2file'] = function(self, path) end,

              --- Process the current image artifact in Lua.
              --
              -- The `callback = function(chunk) ... end` is repeatedly called with
              -- chunked artifact data of type `string` in its `chunk` parameter as
              -- long as there is data available.
              -- The callback function must completely consume the artifact data so
              -- that SWUpdate can continue with the stream's next artifact after
              -- the Lua Handler returns.
              --
              --- @param  self      img_type  This `img_type` instance
              --- @param  callback  function  Callback `function(chunk) ... end` that is fed the current image artifact in chunks.
              --- @return number              # 0 on success, -1 on error
              --- @return string | nil        # nil on success, error message on failure
              ['read'] = function(self, callback) end,
          }

          --- @class swupdate.handler
          --- Chain-callable SWUpdate Handlers (Non-exhaustive).
          --
          -- Note: This list of built-in Handlers is non-exhaustive and
          -- purely illustrative. At run-time, SWUpdate populates this
          -- Table with the actually available Handlers according to its
          -- compile-time configuration and Lua Handlers loaded.
          --
          --- @type table<string, number>
          swupdate.handler = {
              --- Archive Handler (See: `handlers/archive_handler.c`).
              ["archive"]        = 1,
              --- `tar` Archive Handler (See: `handlers/archive_handler.c`).
              ["tar"]            = 1,
              --- Bootloader Handler (See: `handlers/boot_handler.c`).
              ["bootloader"]     = 1,
              --- "dummy" Handler (See: `handlers/dummy_handler.c`).
              ["dummy"]          = 1,
              --- Delta Handler (See: `handlers/delta_handler.c`).
              ["delta"]          = 1,
              --- Disk Format Handler (See: `handlers/diskformat_handler.c`).
              ["diskformat"]     = 1,
              --- Disk Partition Handler (See: `handlers/diskpart_handler.c`).
              ["diskpart"]       = 1,
              --- Toggle Boot Flag Handler (See: `handlers/diskpart_handler.c`).
              ["toggleboot"]     = 1,
              --- Flash Hamming1 Handler (See: `handlers/flash_hamming1_handler.c`).
              ["flash-hamming1"] = 1,
              --- Flash Handler (See: `handlers/flash_handler.c`).
              ["flash"]          = 1,
              --- Raw Image Handler (See: `handlers/raw_handler.c`).
              ["raw"]            = 1,
              --- Raw File Handler (See: `handlers/raw_handler.c`).
              ["rawfile"]        = 1,
              --- Raw Copy Handler (See: `handlers/raw_handler.c`).
              ["rawcopy"]        = 1,
              --- rdiff Image Handler (See: `handlers/rdiff_handler.c`).
              ["rdiff_image"]    = 1,
              --- rdiff File Handler (See: `handlers/rdiff_handler.c`).
              ["rdiff_file"]     = 1,
              --- Readback Handler (See: `handlers/readback_handler.c`).
              ["readback"]       = 1,
              --- Remote Handler (See: `handlers/remote_handler.c`).
              ["remote"]         = 1,
              --- SSBL Handler (See: `handlers/ssbl_handler.c`).
              ["ssblswitch"]     = 1,
              --- SWU Forward Handler (See: `handlers/swuforward_handler.c`).
              ["swuforward"]     = 1,
              --- UBI Volume Handler (See: `handlers/ubivol_handler.c`).
              ["ubivol"]         = 1,
              --- UBI Partition Handler (See: `handlers/ubivol_handler.c`).
              ["ubipartition"]   = 1,
              --- UBI Swap Handler (See: `handlers/ubivol_handler.c`).
              ["ubiswap"]        = 1,
              --- ucfw Handler (See: `handlers/ucfw_handler.c`).
              ["ucfw"]           = 1,
              --- Unique UUID Handler (See: `handlers/uniqueuuid_handler.c`).
              ["uniqueuuid"]     = 1,
          }

          --- Chain-call another Handler.
          --
          --- @param  handler  string    Chain-called Handler's name
          --- @param  image    img_type  Lua equivalent of `struct img_type` as in `include/swupdate.h`
          --- @return number             # 0 on success, 1 on failure
          --- @return string | nil       # nil on success, error message on failure
          swupdate.call_handler = function(handler, image) end

          return swupdate

   Shell script handler
       This handler allows to run a shell script that is packed into the SWU. Please note that running  a  shell
       script  opens  a  set  of  different  security  issues.  Shell  scripts  are supported due to their large
       acceptance, but you should prefer Lua Scripts.

       SWUpdate will run the binary shell "/bin/sh" to execute the script.

   Lua script handler
       A Lua Script handler runs a script in Lua language. There are two possible ways to run the script:

          • local: the script runs in own (isolated) Lua state that is created for the script.  The  script  has
            access  only to function defined inside the script or functions provided by external libraries, like
            the internal swupdate library called via "require(swupdate)".

          • global: SWUpdate create a Lua state at the beginning of an Update and this is valid until the update
            is terminated. In this case, the script has access to any function and structure  that  was  defined
            during  the update. For example, a function can be defined inside sw-description, and the script can
            call it.

       As default, each script runs in isolated / local Lua state. If the property "global-state" is  set,  then
       the common LUa state used for each Update transaction is taken.

       Scripts  ran in isolated context in previous versions. SWUpdate allocates a new Lua state, and import the
       basic libraries before loading the script. A script is then isolated, but it cannot  access  to  function
       already loaded, or it is not possible to reuse functions from 2 or more scripts.

       With  the introduction of a per installation Lua state, Lua scripts can call functions already defined in
       previous scripts, or defined in sw-description. Because when a script is loaded, existing functions  with
       the  same  name  are  overwritten,  it was decided that functions in scripts must be unique, that is each
       function should be declared just once during an installation process.

       This means that for global state, sw-description should contain the name of the function  for  each  step
       (pre-  ,  postinstall  or postfailure) that should be called: the names preinst, postinst and postfailure
       are still valid in case the script runs with isolated state.

       This allows also to load a script without executing if no functions are defined,  and  functions  in  the
       script can be called by later scripts.

       Note  that  the  handler  will  load the script in case of global state just once during the "preinstall"
       call.  Later, it is assumed that functions will be already available.

       Example:

          scripts: (
              {
                  filename = "testscript.lua";
                  type = "lua";
                  properties: {
                      global-state = "true";
                      preinstall = "pretest1";
                  }
              },
              {
                  filename = "test2script.lua";
                  type = "lua";
                  properties: {
                      global-state = "true";
                      postinstall = "posttest2";
                      postfailure = "failure";
                  }
          }

       Two scripts are defined. Both are using the global Lua state.  Functions in test2script can find and  run
       functions  defined  in  testscript.lua,  because  both are belonging to the same context. When preinstall
       scripts are called, only the function "pretest1" from the first script is  called,  because  no  function
       name is defined for this step with the following scripts.

   Remote handler
       Remote handlers are thought for binding legacy installers without having the necessity to rewrite them in
       Lua.  The remote handler forward the image to be installed to another process, waiting for an acknowledge
       to be sure that the image is installed correctly.  The remote handler makes use of the zeromq  library  -
       this  is  to simplify the IPC with Unix Domain Socket. The remote handler is quite general, describing in
       sw-description with the "data" attribute how to  communicate  with  the  external  process.   The  remote
       handler  always  acts as client, and try a connect() using the socket identified by the "data" attribute.
       For example, a possible setup using a remote handler could be:

          images: (
                  {
                      filename = "myimage"";
                      type = "remote";
                      data = "test_remote";
                   }
          )

       The connection is instantiated using the socket test_remote (according to the "data"  field's  value)  in
       the  directory pointed to by the environment variable TMPDIR with /tmp as fall-back if TMPDIR is not set.
       If connect() fails, the  remote handler signals that the update is not successful.  Each  zeromq  message
       from SWUpdate is a multi-part message split into two frames:

          • first frame contains a string with a command.

          • second frame contains data and can be of 0 bytes.

       There are currently just two possible commands: INIT and DATA. After a successful connect, SWUpdate sends
       the initialization string in the format:

          INIT:<size of image to be installed>

       The  external  installer  is  informed  about  the  size  of the image to be installed, and it can assign
       resources if it needs. It will answer with the string ACK or NACK. The first NACK  received  by  SWUpdate
       will  interrupt  the  update.  After sending the INIT command, the remote handler will send a sequence of
       DATA commands, where the second frame in message will contain chunks of the image to be installed.  It is
       duty of the external process to take care of the amount of data transferred and to release resources when
       the last chunk is received. For each DATA message, the external  process  answers  with  a  ACK  or  NACK
       message.

   SWU forwarder
       The  SWU  forwarder handler can be used to update other systems where SWUpdate is running. It can be used
       in case of master / slaves systems, where the master is connected to the network  and  the  "slaves"  are
       hidden  to  the  external  world.   The master is then the only interface to the world. A general SWU can
       contain embedded SWU images as single artifacts, and the SWU handler  will  forward  it  to  the  devices
       listed  in the description of the artifact.  The handler can have a single "url" properties entry with an
       array of urls. Each url is the address of a secondary board where  SWUpdate  is  running  with  webserver
       activated.   The  SWU  handler  expects  to talk with SWUpdate's embedded webserver. This helps to update
       systems where an old version of SWUpdate is running, because the embedded webserver is a  common  feature
       present  in  all  versions.   The  handler  will  send the embedded SWU to all URLs at the same time, and
       setting installed-directly is supported by this handler.  [image]

       The following example shows how to set a SWU as artifact and enables the SWU forwarder:

          images: (
                  {
                          filename = "image.swu";
                          type = "swuforward";

                          properties: {
                                  url = ["http://192.168.178.41:8080", "http://192.168.178.42:8080"];
                          };
                  });

       The SWU forwarder can be used as generic uploader to an URL. This is requires to enable Lua support.  The
       back channel should still run via Websocket, if  the  connected  server  should  communicate  a  progress
       status.   The  handler allows to link an own Lua code that is able to parse the incoming data, and report
       an error. The properties field should contain the name of the Lua function that should be called to parse
       the answer from the remote system. Note that the data passed to Lua is converted to a  string  (and  null
       terminated).

          images: (
                  {
                          filename = "image.swu";
                          type = "swuforward";

                          properties: {
                                  url = ["http://192.168.178.41", "http://192.168.178.42];
                                  parser-function = "parse_answer";
                          };
                  });

       The  parser  function should be already loaded. The Lua function receives as input a string with the data
       received via the Websocket back channel. The function will read the data and return a single scalar value
       of swupdate_status, that is one of swupdate.RECOVERY_STATUS.*.  Example:

          function parse_answer(s)
                  if string.match (s, 'SUCCESS') then
                          return swupdate.RECOVERY_STATUS.SUCCESS
                  end
                  if string.match (s, 'FAILURE') then
                          return swupdate.RECOVERY_STATUS.FAILURE
                  end

                  return swupdate.RECOVERY_STATUS.RUN

          end";

       The handler evaluates the return value, and stops when one of SUCCESS or FAILURE is returned.

       If no parser-function is passed, the handler will run the internal parser used to connect remote SWUpdate
       systems, and expects to see a JSON message sent by the Mongoose Webserver.

   rdiff handler
       The rdiff handler adds support for applying binary delta patches generated by librsync's <http://librsync
       .sourcefrog.net/> rdiff tool.

       Naturally, the smaller the difference between the diff's source and target, the more effective  is  using
       this handler rather than shipping the full target, e.g., via the image handler. Hence, the most prominent
       use  case  for  the  rdiff handler is when having a read-only root filesystem and applying a small update
       like security fixes or feature additions. If the sweet spot is crossed, an rdiff patch  may  even  exceed
       the full target's size due to necessary patch metadata.  Also note that in order to be most effective, an
       image  to  be  processed  with rdiff should be built deterministic (see reproducible-builds.org <https://
       reproducible-builds.org>).

       The rdiff algorithm requires no resources whatsoever on the device as the patch is fully computed in  the
       backend. Consequently, the backend has to have knowledge of the current software running on the device in
       order  to  compute  a  sensible  patch. Alike, the patch has to be applied on the device to an unmodified
       source as used in the  backend  for  patch  computation.  This  property  is  in  particular  useful  for
       resource-constrained  devices  as  there's  no  need  for  the  device  to,  e.g.,  aid in the difference
       computation.

       First, create the signature of the original (base) file via rdiff signature  <basefile>  <signaturefile>.
       Then,  create the delta file (i.e., patch) from the original base file to the target file via rdiff delta
       <signaturefile> <targetfile> <deltafile>.  The <deltafile> is the artifact to be applied via this handler
       on the device.  Essentially, it mimics running rdiff patch <basefile>  <deltafile>  <targetfile>  on  the
       device.  Naturally  for  patches,  the  very  same  <basefile> has to be used for creating as well as for
       applying the patch to.

       This handler registers itself for handling files and images.  An exemplary  sw-description  fragment  for
       the files section is

          files: (
              {
                  type = "rdiff_file"
                  filename = "file.rdiff.delta";
                  path = "/usr/bin/file";
              }
          );

       Note  that  the  file  referenced  to  by path serves as <basefile> and gets replaced by a temporary file
       serving as <targetfile> while the rdiff patch processing.

       An exemplary sw-description fragment for the images section is

          images: (
              {
                  type = "rdiff_image";
                  filename = "image.rdiff.delta";
                  device = "/dev/mmcblk0p2";
                  properties: {
                      rdiffbase = ["/dev/mmcblk0p1"];
                  };
              }
          );

       Here, the property  rdiffbase  qualifies  the  <basefile>  while  the  device  attribute  designates  the
       <targetfile>.   Note that there's no support for the optional offset attribute in the rdiff_image handler
       as there's currently no apparent use case for it and skipping over unchanged content is handled  well  by
       the rdiff algorithm.

   ucfw handler
       This  handler allows one to update the firmware on a microcontroller connected to the main controller via
       UART.  Parameters for setup are passed via sw-description file.  Its behavior can be extended to be  more
       general.   The  protocol  is  ASCII  based.  There is a sequence to be done to put the microcontroller in
       programming mode, after that the handler sends the data and waits for an ACK from the microcontroller.

       The programming of the firmware shall be:

       1. Enter firmware update mode (bootloader)

             1. Set "reset line" to logical "low"

             2. Set "update line" to logical "low"

             3. Set "reset line" to logical "high"

       2. Send programming message

          $PROG;<<CS>><CR><LF>

       to the microcontroller.  (microcontroller will remain in programming state)

       3. microcontroller confirms with

          $READY;<<CS>><CR><LF>

       4. Data transmissions package based from mainboard to microcontroller package definition:

             • within a package the records are sent one after another without the end of line marker <CR><LF>

             • the package is completed with <CR><LF>

       5. The microcontroller requests the next package with $READY;<<CS>><CR><LF>

       6. Repeat step 4 and 5 until the complete firmware is transmitted.

       7. The keypad confirms the firmware completion with $COMPLETED;<<CS>><CR><LF>

       8.

          Leave firmware update mode

                 1. Set "Update line" to logical "high"

                 2. Perform a reset over the "reset line"

       <<CS>> : checksum. The checksum is calculated as the two's complement of  the  modulo-256  sum  over  all
       bytes  of  the  message  string  except  for  the  start  marker  "$".  The handler expects to get in the
       properties the setup for the reset and prog gpios. They should be in this format:

          properties = {
                  reset = "<gpiodevice>:<gpionumber>:<activelow>";
                  prog = "<gpiodevice>:<gpionumber>:<activelow>";
          }

       Example:

          images: (
              {
                  filename = "microcontroller-image";
                  type = "ucfw";
                  device = "/dev/ttymxc5";

                  properties: {
                      reset =  "/dev/gpiochip0:38:false";
                      prog =  "/dev/gpiochip0:39:false";
                  };
              }
          );

   SSBL Handler
       This implements a way to switch two software sets  using  a  duplicated  structure  saved  on  the  flash
       (currently,  only  NOR  flash  is supported). Each of the two structures contains address and size of the
       image to be loaded by a first loader. A field contain the "age", and it is incremented after each  switch
       to show which is the active set.

   Structure of SSBL Admin
                                   ┌────────────────────────────────┬─────────────┐
                                   │ SSBL Magic Number (29 bit)Name │ Age (3 bit) │
                                   ├────────────────────────────────┼─────────────┤
                                   │ Image Address Offset           │             │
                                   ├────────────────────────────────┼─────────────┤
                                   │ Image Size                     │             │
                                   └────────────────────────────────┴─────────────┘

       The  handler  implements  a  post install script. First, it checks for consistency the two structures and
       find the active reading the first 32 bit value with a magic number and the age.  It  increments  the  age
       and saves the new structure in the inactive copy. After a reboot, the loader will check it and switch the
       software set.

          scripts: (
                  {
                          type = "ssblswitch";
                          properties: {
                                  device = ["mtdX", "mtdY"];
                                  offset = ["0", "0"];
                                  imageoffs = ["0x780000",  "0xA40000"];
                                  imagesize = ["0x800000", "0x800000"];
                          }
          }

       Properties in sw-description are all mandatory. They define where the SSBL Administration data are stored
       for  both  sets.  Each  properties is an array of two entries, containing values for each of the two SSBL
       administration.

   Properties for SSBL handler
                               ┌─────────────┬────────┬──────────────────────────────┐
                               │ Name        │ Type   │ Description                  │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ device      │ string │ MTD device  where  the  SSBL │
                               │             │        │ Admin Header is stored       │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ offset      │ hex    │ Offset of SSBL header inside │
                               │             │        │ the MTD device               │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ imageoffset │ hex    │ Offset  of  the  image to be │
                               │             │        │ loaded by a bootloader  when │
                               │             │        │ this SSBL is set.            │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ imagesize   │ hex    │ Size  of  the  image  to  be │
                               │             │        │ loaded by a bootloader  when │
                               │             │        │ this SSBL is set.            │
                               └─────────────┴────────┴──────────────────────────────┘

   Readback Handler
       To  verify  that  an  image  was  written properly, this readback handler calculates the sha256 hash of a
       partition (or part of it) and compares it against a given hash value.

       The following example explains how to use this handler:

          scripts: (
          {
              device = "/dev/mmcblk2p1";
              type = "readback";
              properties: {
                  sha256 = "e7afc9bd98afd4eb7d8325196d21f1ecc0c8864d6342bfc6b6b6c84eac86eb42";
                  size = "184728576";
                  offset = "0";
              };
          }
          );

       Properties size and offset are optional, all the other properties are mandatory.

   Properties for readback handler
                                  ┌────────┬────────┬──────────────────────────────┐
                                  │ Name   │ Type   │ Description                  │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ device │ string │ The partition which shall be │
                                  │        │        │ verified.                    │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ type   │ string │ Identifier for the handler.  │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ sha256 │ string │ Expected sha256 hash of  the │
                                  │        │        │ partition.                   │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ size   │ string │ Data  size  (in bytes) to be │
                                  │        │        │ verified.  If 0 or not  set, │
                                  │        │        │ the  handler  will  get  the │
                                  │        │        │ partition  size   from   the │
                                  │        │        │ device.                      │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ offset │ string │ Offset  (in  bytes)  to  the │
                                  │        │        │ start of the partition.   If │
                                  │        │        │ not  set,  default  value  0 │
                                  │        │        │ will be used.                │
                                  └────────┴────────┴──────────────────────────────┘

   Copy handler
       The copy handler copies one source to a destination. It is a script handler, and no artifact in  the  SWU
       is associated with the handler.  It can be used to copy configuration data, or parts that should be taken
       by  the  current installation.  It requires the mandatory  property (copyfrom), while device contains the
       destination path.  The handler performs a byte copy, and it does not matter which is the source - it  can
       be  a file or a partition.  An optional type field can set if the handler is active as pre or postinstall
       script. If not set, the handler is called twice.

   Attributes for copy handler
                                  ┌────────┬────────┬──────────────────────────────┐
                                  │ Name   │ Type   │ Description                  │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ device │ string │ If   set,    it    is    the │
                                  │        │        │ destination.                 │
                                  ├────────┼────────┼──────────────────────────────┤
                                  │ type   │ string │ One   of   "preinstall"   or │
                                  │        │        │ "postinstall"                │
                                  └────────┴────────┴──────────────────────────────┘

   Properties for copy handler
                           ┌─────────────────────┬────────┬──────────────────────────────┐
                           │ Name                │ Type   │ Description                  │
                           ├─────────────────────┼────────┼──────────────────────────────┤
                           │ size                │ string │ Data size (in bytes)  to  be │
                           │                     │        │ copied.   If  0  or not set, │
                           │                     │        │ the handler will try to find │
                           │                     │        │ the size from the device.    │
                           ├─────────────────────┼────────┼──────────────────────────────┤
                           │ chain               │ string │ Handler  to  be  called   to │
                           │                     │        │ install  the  data read from │
                           │                     │        │ the "copyfrom" source.       │
                           ├─────────────────────┼────────┼──────────────────────────────┤
                           │ recursive           │ string │ Recursive copy  if  copyfrom │
                           │                     │        │ is  a  directory  ("true" or │
                           │                     │        │ "false")                     │
                           ├─────────────────────┼────────┼──────────────────────────────┤
                           │ create- destination │ string │ Create the destination  path │
                           │                     │        │ if it does not exist ("true" │
                           │                     │        │ or "false")                  │
                           └─────────────────────┴────────┴──────────────────────────────┘

          scripts : (
                  {
                  device = "/dev/mmcblk2p1";
                  type = "copy";
                  properties : {
                          copyfrom = "/dev/mmcblk2p2";
                          type = "postinstall";
                          chain = "raw";
                  }
          }

   Bootloader handler
       The  bootloader  handler  allows  to  set  bootloader's  environment with a file. The file shold have the
       format:

          # Comments are allowed using the hash char

          varname=value

       Empty lines are skipped. This simplifies the update of the whole  environment  instead  of  setting  each
       variable inside the "bootenv" section in sw-description. The property nooverride allows to skip variables
       that are already set in sw-description. If not set, variables set in bootenv are overwritten.

          images: (
                  {
                          filename = "uEnv.txt";
                          type = "bootloader";
                          properties: {
                                  nooverride = "true";
                          }
                  }
          );

          bootenv: (
          {
                  name = "bootenv01key";
                  value = "SOME VALUE";
          });

       In  the  example  above,  bootenv01key  is  not  overwritten  by  a  value  in  uEnv.txt because the flag
       "nooverride" is set.

   Archive handler
       The archive handler extracts an archive to a destination path.  It supports  whatever  format  libarchive
       has  been compiled to support, for example even if swupdate itself has no direct support for xz it can be
       possible to extract tar.xz files with it.

       The attribute preserve-attributes must be set to  preserve  timestamps.  uid/gid  (numeric),  permissions
       (except +x, always preserved) and extended attributes.

       The  property  create-destination  can  be set to the string true to have swupdate create the destination
       path before extraction.

          files: (
                  {
                          filename = "examples.tar.zst";
                          type = "archive";
                          path = "/extract/here";
                          preserve-attributes = true;
                          installed-directly = true;
                          properties: {
                                  create-destination = "true";
                          }
                  }
          );

   Disk partitioner
       This handler creates or modifies partitions using the library libfdisk. Handler  must  be  put  into  the
       partitions  section  of  sw-description.  Setup  for  each  partition is put into the properties field of
       sw-description.  After writing the partition table it may create a file system  on  selected  partitions.
       (Available only if CONFIG_DISKFORMAT is set.)

   Properties for diskpart handler
                               ┌─────────────┬────────┬──────────────────────────────┐
                               │ Name        │ Type   │ Description                  │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ labeltype   │ string │ "gpt" or "dos"               │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ nolock      │ string │ "true"       or      "false" │
                               │             │        │ (default=false) This is like │
                               │             │        │ a force. If  it  is  set,  a │
                               │             │        │ lock    failure    will   be │
                               │             │        │ ignored(lock will  still  be │
                               │             │        │ attempted).                  │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ noinuse     │ string │ "true"       or      "false" │
                               │             │        │ (default=false) If  set,  it │
                               │             │        │ does  not require the device │
                               │             │        │ to be not in  use  (mounted, │
                               │             │        │ etc.)                        │
                               ├─────────────┼────────┼──────────────────────────────┤
                               │ partition-X │ array  │ Array of values belonging to │
                               │             │        │ the partition number X       │
                               └─────────────┴────────┴──────────────────────────────┘

       For each partition, an array of couples key=value must be given. The following keys are supported:

   Setup for a disk partition
                                ┌──────────┬─────────┬──────────────────────────────┐
                                │ Name     │ Type    │ Description                  │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ size     │ string  │ Size  of partition. K, M and │
                                │          │         │ G can be used for Kilobytes, │
                                │          │         │ Megabytes and Gigabytes.     │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ start    │ integer │ First   sector    for    the │
                                │          │         │ partition                    │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ name     │ string  │ Name of the partition        │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ type     │ string  │ Type  of  partition,  it has │
                                │          │         │ two different meanings.   It │
                                │          │         │ is  the  hex  code  for  DOS │
                                │          │         │ (MBR) partition table or  it │
                                │          │         │ is  the string identifier in │
                                │          │         │ case of GPT.                 │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ dostype  │ string  │ Type of DOS (MBR)  partition │
                                │          │         │ entry  when  using  a  table │
                                │          │         │ with  a   "gpt"   labeltype. │
                                │          │         │ Using   this   option   will │
                                │          │         │ create a hybrid  MBR  table. │
                                │          │         │ It  is  the hex code for DOS │
                                │          │         │ (MBR) partition table.  This │
                                │          │         │ would typically be used when │
                                │          │         │ one  wants  to  use  a   GPT │
                                │          │         │ formatted  disk with a board │
                                │          │         │ that requires  a  dos  table │
                                │          │         │ entry       for      initial │
                                │          │         │ bootstrapping.    Note:    A │
                                │          │         │ maximum  of 3 partitions can │
                                │          │         │ have  a  dostype  specified, │
                                │          │         │ this  limit  only applies to │
                                │          │         │ dos table entries  and  does │
                                │          │         │ not     affect    partitions │
                                │          │         │ without a dostype specified. │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ fstype   │ string  │ Optional filesystem type  to │
                                │          │         │ be created on the partition. │
                                │          │         │ If  no  fstype key is given, │
                                │          │         │ no file will be  created  on │
                                │          │         │ the corresponding partition. │
                                │          │         │ vfat  /  ext2 / ext3 /ext4 / │
                                │          │         │ btrfs   file    system    is │
                                │          │         │ supported                    │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ partuuid │ string  │ The   partition   UUID  (GPT │
                                │          │         │ only). If  omitted,  a  UUID │
                                │          │         │ will       be      generated │
                                │          │         │ automatically.               │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ flag     │ string  │ The  following   flags   are │
                                │          │         │ supported:  Dos  Partition : │
                                │          │         │ "boot" set bootflag          │
                                ├──────────┼─────────┼──────────────────────────────┤
                                │ force    │ string  │ If set to  "true",  existing │
                                │          │         │ file-system     shall     be │
                                │          │         │ overwritten  uncoditionally. │
                                │          │         │ Default value is "false".    │
                                └──────────┴─────────┴──────────────────────────────┘

       GPT example:

          partitions: (
          {
             type = "diskpart";
             device = "/dev/sde";
             properties: {
                  labeltype = "gpt";
                  partition-1 = [ "size=64M", "start=2048",
                      "name=bigrootfs", "type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B"];
                  partition-2 = ["size=256M", "start=133120",
                      "name=ldata", "type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7",
                      "fstype=vfat"];
                  partition-3 = ["size=512M", "start=657408",
                      "name=log", "fstype =ext4", 63DAF-8483-4772-8E79-3D69D8477DE4"];
                  partition-4 = ["size=4G", "start=1705984",
                      "name=system",  "type=0FC63DAF-8483-4772-8E79-3D69D8477DE4"];
                  partition-5 = ["size=512M", "start=10094592",
                      "name=part5",  "type=0FC63DAF-8483-4772-8E79-3D69D8477DE4"];
             }
          }

       MBR Example:

          partitions: (
          {
             type = "diskpart";
             device = "/dev/sde";
             properties: {
                  labeltype = "dos";
                  partition-1 = [ "size=64M", "start=2048", "name=bigrootfs", "type=0x83"];
                  partition-2 = ["size=256M", "start=133120", "name=ldata", "type=0x83"];
                  partition-3 = ["size=256M", "start=657408", "name=log", "type=0x83"];
                  partition-4 = ["size=6G", "start=1181696", "name=system",  "type=0x5"];
                  partition-5 = ["size=512M", "start=1183744", "name=part5",  "type=0x83"];
                  partition-6 = ["size=512M", "start=2234368", "name=part6",  "type=0x83"];
                  partition-7 = ["size=16M", "start=3284992", "name=part7", "type=0x6",
                      "fstype=vfat"];
             }
          }

   Toggleboot Handler
       This  handler  is a script handler. It turns on the bootflag for one of a disk partition if the partition
       table is DOS. It reports an error if the table is GPT.

          script: (
          {
             type = "toggleboot";
             device = "/dev/sde";
             properties: {
                  partition = "1";
             }
          }

   GPT Partition Handler
   GPT Partition Installer
       There is a handler gptpart that allows writing an image into a gpt partition selected by the  name.  This
       handler do not modify the gpt partition (type, size, ...), it just writes the image in the GPT partition.

          images: (
                  {
                          filename = "u-boot.bin";
                          type = "gptpart";
                          device = "/dev/vdb";
                          volume = "u-boot-1";
                          offset = "1024";
                  },
                  {
                          filename = "kernel.bin";
                          type = "gptpart";
                          device = "/dev/vdb";
                          volume = "kernel-1";
                  },
          );

   GPT Partition Swap
       There  is  a  handler  gptswap that allow to swap gpt partitions after all the images were flashed.  This
       handler only swaps the name of the partition. It coud be useful for a dual bank strategy.   This  handler
       is  a  script  for  the  point  of  view of swupdate, so the node that provides it should be added in the
       section scripts.

       Simple example:

          scripts: (
                  {
                          type = "gptswap";
                          device = "/dev/vdb";
                          properties =
                          {
                                  swap-0 = [ "u-boot-0" , "u-boot-1" ];
                                  swap-1 = [ "kernel-0" , "kernel-1" ];
                          };
                  },
          );

   Diskformat Handler
       This handler checks if the device already has a file system of the specified  type.  (Available  only  if
       CONFIG_DISKFORMAT  is  set.)   If  the  file  system  does not yet exist, it will be created.  In case an
       existing file system shall be overwritten, this can be achieved by setting the property force to true.

          partitions: (
          {
                  type = "diskformat";
                  device = "/dev/loop0p1";

                  properties: {
                          fstype = "vfat";
                          force = "true";
                  }
          })

   Unique UUID Handler
       This handler checks if the device already has a filesystems with a provide UUID. This is helpful in  case
       the  bootloader chooses the device to boot from the UUID and not from the partition number.  One use case
       is with the GRUB bootloader when GRUB_DISABLE_LINUX_UUID is not set, as usual on Linux Distro  as  Debian
       or Ubuntu.

       The  handler  iterates  all UUIDs given in sw-description and raises error if one of them is found on the
       device. It is a partition handler and it runs before any image is installed.

          partitions: (
          {
                  type = "uniqueuuid";
                  properties: {
                          fs-uuid = ["21f16cae-612f-4bc6-8ef5-e68cc9dc4380",
                                     "18e12df1-d8e1-4283-8727-37727eb4261d"];
                  }
          });

   BTRFS Handler
   BTRFS Partition Handler
       This handler is activated if support for BTRFS is on. It allows to created and delete  subvolumes  during
       an update.

          partitions: (
          {
                  type = "btrfs";
                  device = "/dev/loop0p1";

                  properties: {
                          command = < one of create" or "delete" >
                          path = <path for the subvolume>;
                          mount = "true" or missing;
                          create-destination = "true" or missing;
                  }
          })

       If  mount  is  set,  SWUpdate  will mount the device and the path is appended to the mountpoint used with
       mount. If device is already mounted, path is the absolute path.

   BTRFS Snapshot Handler
       The handler allows to install a BTRFS snapshot created with the "btrfs send" command.  SWUpdate is  using
       the  external  "btrfs"  utility, that must be installed on the target, and "btrfs receive" is executed by
       sending the stream to the command.

       All generic features are  avaiulable,  that  means  that  an  srtifact  can  be  streamed  by  using  the
       "installed-directly" attribute.

          images: (
          {
                  filename = "btrfs-snapshot";
                  type = "btrfs-receive";
                  device = <optional, device with BTRFS fs, must be set if tomount is "true">;
                  properties: {
                          path = <mandatory, path where to install subvolume>;
                          btrfs-cmd = <optional, path to btrfs command>;
                          tomount = <boolean, optional, "true" / "false" >;
                  }
          })

       If tomount is set, SWUpdate will temporary mount "device" as BTRFS filesystem and will try to install the
       snapshot to path. btrfs-cmd is optional, fallback is /usr/bin/btrfs.

   Generic Executor Handler
       The  BTRFS  snapshot  handler  requires  to  stream  an  artifact  after  normal handling (decompression,
       decryption, etc.) to the external command "btrfs" without any temporary copy.  The same infrastucture can
       be used to stream any artifact to any arbitrary external command that accepts the stream as  stdin.  This
       is done with the "executor" handler.

          {
                  filename = "test";
                  type = "executor";
                  properties: {
                          cmd = <mandatory, command to be executed in a pipe>;
                  }
          }

       If  create-destination is set, SWUpdate will create the destination path of the subvolume before creating
       it.

   Delta Update Handler
       The handler processes a ZCHUNK header and finds which chunks should be downloaded  after  generating  the
       corresponding header of the running artifact to be updated.  The handler uses just a couple of attributes
       from  the  main setup, and gets more information from the properties. The attributes are then passed to a
       secondary handler that will install the artefact after the delta handler has assembled it.   The  handler
       requires ZST because this is the compression format for Zchunk.

       The  SWU  must  just  contain  the  ZCK's  header, while the ZCK file is put as it is on the server.  The
       utilities in Zchunk project are used to build the zck file.

          zck -u -h sha256 <artifact>

       This will generates a file <arifact>.zck. To extract the header, use the zck_read_header utility:

          HSIZE=`zck_read_header -v <artifact>.zck | grep "Header size" | cut -d':' -f2`
          dd if=<artifact>.zck of=<artifact>.header bs=1 count=$((HSIZE))

       The resulting header file must be packed inside the SWU.

   Properties for delta update handler
                               ┌──────────────┬────────┬──────────────────────────────┐
                               │ Name         │ Type   │ Description                  │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ url          │ string │ This is the URL  from  where │
                               │              │        │ the  handler  will  download │
                               │              │        │ the  missing  chunks.    The │
                               │              │        │ server   must  support  byte │
                               │              │        │ range header.                │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ source       │ string │ name of the device  or  file │
                               │              │        │ to    be    used   for   the │
                               │              │        │ comparison.                  │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ chain        │ string │ this is the name  (type)  of │
                               │              │        │ the  handler  that is called │
                               │              │        │ after    reassembling    the │
                               │              │        │ artifact.                    │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ max-ranges   │ string │ Max  number of ranges that a │
                               │              │        │ server can  accept.  Default │
                               │              │        │ value (150) should be ok for │
                               │              │        │ most servers.                │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ zckloglevel  │ string │ this  sets  the log level of │
                               │              │        │ the   zcklib.    Logs    are │
                               │              │        │ intercepted  by SWupdate and │
                               │              │        │ appear  in  SWUpdate's  log. │
                               │              │        │ Value  is  one of debug,info │
                               │              │        │ warn,error,none              │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ debug-chunks │ string │ "true", default is not  set. │
                               │              │        │ This  activates more verbose │
                               │              │        │ debugging  output  and   the │
                               │              │        │ list   of   all   chunks  is │
                               │              │        │ printed, and it reports if a │
                               │              │        │ chunk  is   downloaded    or │
                               │              │        │ copied from the source.      │
                               ├──────────────┼────────┼──────────────────────────────┤
                               │ source-size  │ string │ This limits the index of the │
                               │              │        │ source It is helpful in case │
                               │              │        │ of filesystem in much bigger │
                               │              │        │ partition.  It has the value │
                               │              │        │ for the size or  it  can  be │
                               │              │        │ set   to  "detect"  and  the │
                               │              │        │ handler will try to find the │
                               │              │        │ effective size of fs.        │
                               └──────────────┴────────┴──────────────────────────────┘

       Example:

          {
                  filename = "software.header";
                  type = "delta";

                  device = "/dev/mmcblk0p2";
                  properties: {
                          url = "http://examples.com/software.zck";
                          chain = "raw";
                          source = "/dev/mmcblk0p3";
                          zckloglevel = "error";
                          /* debug-chunks = "true"; */
                  };
          }

   Memory issue with zchunk
       SWUpdate will create the header from the current version, often  from  a  block  partition.  As  default,
       Zchunk  creates  a  temporary file with all chunks in /tmp, that is at the end concatenated to the header
       and written to the destination file. This means that an amount of memory equal to the partition (SWUpdate
       does not compress the chunks) is required. This was solved with later version of Zchunk  -  check  inside
       zchunk code if ZCK_NO_WRITE is supported.

   Docker Handlers
       To improve containers update, a docker set of handlers implements part of the API to communicate with the
       docker  daemon.  Podman  (another  container  solution) has a compatibility layer for docker REST API and
       could be used as well, but SWUpdate is currently not checking if a podman daemon must be started.

       Goal of these handlers is just to provice the few API to update images and start containers - it does not
       implement the full API.

   Docker Load Image
       This handler allow to load an image without copying temporarily and push it to  the  docker  daemon.   It
       implements the /images/load entry point., and it is implemented as "image" handler. The file should be in
       a format accepted by docker.

          images: (
          {
                  filename = "docker-image.tar"
                  type = "docker_imageload";
                  installed-directly = true;
          });

       The  handler checks return value (JSON message) from the daemon, and returns with success if the image is
       added.

       In case the file must be decompressed, SWUpdate requires the size of the decompressed image to be  passed
       to the daemon:

          images: (
          {
                  filename = "alpine.tar.gz";
                  type = "docker_imageload";
                  installed-directly = true;
                  compressed = "zlib";
                  properties: {
                       decompressed-size = "5069312";
                  };
          });

   Docker Remove Image
       It is implemented as script (post install).  Example:

          scripts: ( {
                  type = "docker_imagedelete";
                  properties: {
                          name = "alpine:3.4";
                  };
          });

   Docker Delete Unused Images
       It is implemented as script (post install).  Example:

          scripts: ( {
                  type = "docker_imageprune";
          });

   Docker: container create
       It  is  implemented  as  post-install  script. The script itself is the json file passed to the daemon to
       configure and set the container. The container is just created, not started.

       For example, having this hello-world.json file:

          {
                  "Image": "hello-world",
                  "HostConfig": {
                          "RestartPolicy": {
                                  "Name": "always"
                          },
                  "AutoRemove": false
                  }
          }

       Creating the container can be done in sw-description with:

          scripts: ( {
                  filename = "hello-world.json";
                  type = "docker_containercreate";
                  properties: {
                          name = "helloworld"; /* Name of container */
                  }
          });

   Docker Remove Container
       It is implemented as script (post install).  Example:

          scripts: ( {
                  type = "docker_containerdelete";
                  properties: {
                          name = "helloworld";
                  };
          });

   Docker : Start / Stop containers
       Examples:

          scripts: ( {
                  type = "docker_containerstart";
                  properties: {
                          name = "helloworld";
                  };
          });

          scripts: ( {
                  type = "docker_containerstop";
                  properties: {
                          name = "helloworld";
                  };
          });

MONGOOSE DAEMON MODE

   Introduction
       Mongoose is a daemon mode of SWUpdate that provides a web server, web interface and web application.

       The web application in web-app  uses  the  Node.js  <https://nodejs.org/en/>  package  manager  and  gulp
       <https://gulpjs.com/>  as build tool. It depends on Bootstrap 4 <https://getbootstrap.com/>, Font Awesome
       5 <https://fontawesome.com/> and Dropzone.js <http://www.dropzonejs.com/>.

   Startup
       After having configured and compiled SWUpdate with enabled mongoose web server:

          ./swupdate --help

       lists the mandatory and optional arguments to be provided to mongoose.  As an example,

          ./swupdate -l 5 -w '-r ./examples/www/v2 -p 8080' -p 'reboot'

       runs SWUpdate in mongoose daemon mode with log-level TRACE and a web server at <http://localhost:8080>.

   Example
       The ready to use example of the web application in  the examples/www/v2 directory uses  a  Public  Domain
       background.jpg  image  from pixabay <https://pixabay.com/de/leiterbahn-platine-technologie-3157431/> with
       is released under the Creative Commons CC0 license. The used favicon.png and  logo.png  images  are  made
       from the SWUpdate logo and therefore subject to the GNU General Public License version 2. You must comply
       to this license or replace the images with your own files.

   Customize
       You  could  customize  the  web  application  inside  the  web-app  directory.  Beside the replace of the
       favicon.png, logo.png and background.jpg images inside the  images  directory  you  could  customize  the
       Bootstrap  colors and settings inside the scss/bootstrap.scss style sheet. The style sheet changes need a
       rebuild of the web application source code.

   Develop
       The development requires Node.js version 18 or greater and  a  prebuilt  SWUpdate  project  with  enabled
       mongoose web server and web application interface version 2 support.

       1. Enter the web application directory:

             cd ./web-app

       2. Install the dependencies:

             npm install

       3. Build the web application:

             npm run build

       4. Start the web application:

             ../swupdate -w '-r ./dist -p 8080' -p 'echo reboot'

       5. Test the web application:
             <http://localhost:8080/>

       6. Pack the web application (optional):

             npm run package -- --output swupdate-www.tar.gz

   Contribute
       Please run the linter before any commit

          npm run lint

SURICATTA DAEMON MODE

   Introduction
       Suricatta  is  -- like mongoose -- a daemon mode of SWUpdate, hence the name suricatta (engl. meerkat) as
       it belongs to the mongoose family.

       Suricatta regularly polls a remote server for updates,  downloads,  and  installs  them.  Thereafter,  it
       reboots  the  system  and  reports  the  update  status  to the server, based on an update state variable
       currently stored in bootloader's environment ensuring persistent  storage  across  reboots.  Some  U-Boot
       script logics or U-Boot's bootcount feature may be utilized to alter this update state variable, e.g., by
       setting  it  to  reflect  failure  in  case  booting  the newly flashed root file system has failed and a
       switchback had to be performed.

       Suricatta is designed to be extensible in terms of the servers supported  as  described  in  Section  The
       Suricatta  Interface.  Currently,  support  for  the  hawkBit  <https://projects.eclipse.org/projects/iot
       .hawkbit>  server  is  implemented  via  the  hawkBit  Direct  Device  Integration  API   <http://sp.apps
       .bosch-iot-cloud.com/documentation/developerguide/apispecifications/directdeviceintegrationapi.html>
       alongside  a simple general purpose HTTP server.  The support for suricatta modules written in Lua is not
       a particular server support implementation but rather an option for writing such in Lua instead of C.

   Running suricatta
       After having configured and compiled SWUpdate with enabled suricatta support for hawkBit,

          ./swupdate --help

       lists the mandatory and optional arguments to be provided to suricatta when using hawkBit as  server.  As
       an example,

          ./swupdate -l 5 -u '-t default -u http://10.0.0.2:8080 -i 25'

       runs   SWUpdate   in  suricatta  daemon  mode  with  log-level  TRACE,  polling  a  hawkBit  instance  at
       http://10.0.0.2:8080 with tenant default and device ID 25.

       If multiple server support is  compiled  in,  the  -S  /  --server  option  or  a  server  entry  in  the
       configuration file's [suricatta] section selects the one to use at run-time. For convenience, when having
       support for just one server compiled-in, this is chosen automatically.

       Note  that on startup when having installed an update, suricatta tries to report the update status to its
       upstream server, e.g., hawkBit, prior to entering the  main  loop  awaiting  further  updates.   If  this
       initial  report fails, e.g., because of a not (yet) configured network or a currently unavailable hawkBit
       server, SWUpdate may exit with an according error code. This behavior allows one  to,  for  example,  try
       several  upstream  servers  sequentially.   If  suricatta should keep retrying until the update status is
       reported to its upstream server irrespective of the error conditions, this has to be realized  externally
       in terms of restarting SWUpdate on exit.

       After  an update has been performed, an agent listening on the progress interface may execute post-update
       actions, e.g., a reboot, on receiving  DONE.   Additionally,  a  post-update  command  specified  in  the
       configuration file or given by the -p command line option can be executed.

       Note  that  at  least  a  restart  of  SWUpdate has to be performed as post-update action since only then
       suricatta tries to report the update status to its upstream server. Otherwise,  succinct  update  actions
       announced  by  the  upstream server are skipped with an according message until a restart of SWUpdate has
       happened in order to not install the same update again.

   The Suricatta Interface
       Support for servers other than hawkBit or the general purpose HTTP server can be realized by implementing
       the "interfaces" described in include/channel.h and include/suricatta/server.h, the latter either in C or
       in Lua.  The channel interface abstracts a particular connection to the server, e.g., HTTP-based in  case
       of   hawkBit.   The   server   interface   defines   the   logics   to  poll  and  install  updates.  See
       corelib/channel_curl.c  /  include/channel_curl.h  and  suricatta/server_hawkbit.{c,h}  for  an   example
       implementation in C targeted towards hawkBit.

       include/channel.h describes the functionality a channel has to implement:

          typedef struct channel channel_t;
          struct channel {
              ...
          };

          channel_t *channel_new(void);

       which  sets  up and returns a channel_t struct with pointers to functions for opening, closing, fetching,
       and sending data over the channel.

       include/suricatta/server.h describes the functionality a server has to implement:

          typedef struct {
              server_op_res_t has_pending_action(int *action_id);
              server_op_res_t install_update(void);
              server_op_res_t send_target_data(void);
              unsigned int get_polling_interval(void);
              server_op_res_t start(const char *cfgfname, int argc, char *argv[]);
              server_op_res_t stop(void);
              server_op_res_t ipc(int fd);
              void (*help)(void);
          } server_t;

       These functions constituting a particular suricatta server implementation have to be registered for being
       selectable at run-time by calling register_server() (see include/suricatta/server.h) with a  name  and  a
       server_t   struct   pointer   implemented   in   a   __attribute__((constructor))  marked  function,  see
       suricatta/server_hawkbit.c as example.

       The type server_op_res_t is defined in include/suricatta/suricatta.h.  It represents the  valid  function
       return codes for a server's implementation.

       In  addition  to  implementing  the  particular  channel and server, the suricatta/Kconfig file has to be
       adapted to include a new  option  so  that  the  new  implementation  becomes  selectable  in  SWUpdate's
       configuration.  In  the  simplest case, adding an option like the following one for hawkBit into the menu
       "Server" section is sufficient.

          config SURICATTA_HAWKBIT
              bool "hawkBit support"
              default y
              select JSON
              help
                Support for hawkBit server.
                https://projects.eclipse.org/projects/iot.hawkbit

       Having included the new server implementation into the configuration, edit suricatta/Makefile to  specify
       the  implementation's linkage into the SWUpdate binary, e.g., for the hawkBit example implementation, the
       following lines add server_hawkbit.o to the resulting SWUpdate binary if SURICATTA_HAWKBIT  was  selected
       while configuring SWUpdate.

          ifneq ($(CONFIG_SURICATTA_HAWKBIT),)
          obj-$(CONFIG_SURICATTA) += server_hawkbit.o
          endif

   Support for wfx
       The   wfx   <https://github.com/siemens/wfx>   server   is   supported   by   the  Lua  Suricatta  module
       suricatta/server_wfx.lua (cf. Section Support for Suricatta Modules in Lua).  Specifically, it implements
       a binding to the Device  Artifact  Update  <https://github.com/siemens/wfx/tree/main/workflow/dau>  (DAU)
       workflow family.

       If enabled via CONFIG_SURICATTA_WFX, the wfx Lua Suricatta module is embedded into the SWUpdate binary so
       that  no  extra  deployment  steps  are required. Note that this is purely a convenience shortcut for the
       installation of a Lua Suricatta module as described in Support for Suricatta Modules in Lua.

   Job Definition
       As being a general purpose workflow executor, wfx doesn't impose a particular job definition nor  schema,
       except  that it's in JSON format. Instead, the job definition is a contract between the operator creating
       jobs, each possibly following a different workflow, and the client(s) executing those jobs  in  lock-step
       with the wfx.

       The   wfx   Lua   Suricatta  module  understands  job  definitions  as  in  the  following  example  (see
       job.definition.json_schema in suricatta/server_wfx.lua):

          {
              "version": "1.0",
              "type": ["firmware", "dummy"],
              "artifacts": [
                  {
                      "name": "Example Device Firmware Artifact",
                      "version": "1.1",
                      "uri": "http://localhost:8080/download/example_artifact.swu"
                  }
              ]
          }

       The type list field allows to label update jobs. Labels are sent :-concatenated to the progress interface
       on Update Activation. The only predefined label firmware instructs the wfx Lua Suricatta module to record
       an installed update to the bootloader environment (see Bootloader Interface <>).   Within  the  artifacts
       list,  only  the  uri  field is strictly required for each artifact while the fields name and version are
       used for informational purposes, if provided.  Further fields, including top-level fields, are ignored on
       purpose and may be freely used, e.g., to enrich the job definition with metadata for update management.

       Since wfx is not concerned with the job definition except for conveying it to the client (i.e. SWUpdate),
       it can be adapted to specific needs by feeding a different job definition into the wfx  on  job  creation
       and adapting the verification and job handling methods in the wfx Lua Suricatta module's job.definition =
       {...} Table.

   Workflows
       The  two  Device Artifact Update (DAU) workflows wfx.workflow.dau.direct <https://github.com/siemens/wfx/
       blob/main/workflow/dau/wfx.workflow.dau.direct.yml>  and   wfx.workflow.dau.phased   <https://github.com/
       siemens/wfx/blob/main/workflow/dau/wfx.workflow.dau.phased.yml>  are  supported  by the wfx Lua Suricatta
       module.  Hint: Use wfx's wfx-viewer command line tool to visualize the  YAML workflows in SVG or PlantUML
       format.

       For each transition in a workflow for which the eligible field contains CLIENT, e.g.,

          transitions:
            - from: <FROM_STATE>
              to: <TO_STATE>
              eligible: CLIENT

       there has to be a matching transition execution function defined in the  wfx  Lua  Suricatta  module.  It
       executes  the  client actions to go from state <FROM_STATE> to state <TO_STATE> and finally sends the new
       job status to the wfx, updating it:

          job.workflow.dispatch:set(
              "<FROM_STATE>",
              "<TO_STATE>",
              --- @param  self  job.workflow.transition
              --- @param  job   job
              --- @return transition.result
              function(self, job)
                  if not job.status
                      :set({
                          state = self.to.name, -- resolves to `<TO_STATE>`
                          message = ("[%s] <TO_STATE> reached"):format(self.to.name),
                          progress = 100,
                      })
                      :send() then
                      -- Do not try to execute further transitions, yield to wfx.
                      return transition.result.FAIL_YIELD
                  end
                  return transition.result.COMPLETED
              end
          )

       See suricatta/server_wfx.lua for examples of such transition execution functions.

       New or adapted workflows are supported  by  appropriately  defining/modifying  the  transition  execution
       functions in suricatta/server_wfx.lua -- or taking it as inspiration and creating a new wfx Lua Suricatta
       module as described in Support for Suricatta Modules in Lua.

   Update Activation
       The Device Artifact Update (DAU) workflows offer a dedicated activation step in the update steps sequence
       to  decouple  artifact  installation  and activation times so to not, e.g., upon a power-cut, prematurely
       test-boot into the new firmware after installation until the activation is actually due.

       When the activation step is executed, the wfx Lua Suricatta module sends a progress message (see  Getting
       information on running update <>) upon which a progress client executes or schedules activation measures.
       For  example,  the  following JSON is sent as the progress message's .info field on activation of the Job
       Definition example given above:

          {
              "state": "ACTIVATING",
              "progress": 100,
              "message": "firmware:dummy"
          }

       The progress message's .status is PROGRESS, see tools/swupdate-progress.c for details on how  a  progress
       client can be implemented.

       Note:  The  activation  message may be sent multiple times if the update activation is pending, namely on
       each wfx poll operation and if a new update job is enqueued while the current one is not activated.

       Because of the (predefined) firmware label present, the progress client should  initiate  or  schedule  a
       reboot of the device in order to test-boot the new firmware.  Also because of the firmware label present,
       the  wfx  Lua  Suricatta module records the installed update to the bootloader environment. If this label
       was missing, no such recording  would've  been  made  which  is  suitable  for,  e.g.,  configuration  or
       application updates.

       In  order  for  the  this  mechanism  to  work,  SWUpdate  must  not  record the update to the bootloader
       environment after it has installed it or, in case of configuration or application updates, must not touch
       the bootloader environment at all (see the Sections Update Transaction and Status Marker  and  bootloader
       in SWUpdate: syntax and tags with the default parser <>).

       Hence,  for firmware updates requiring a test-boot into the new firmware, the following properties should
       be set in the .swu file's sw-description:

          software =
          {
              bootloader_transaction_marker = true;
              bootloader_state_marker = false;
              ...

       For configuration or application updates, the following properties apply:

          software =
          {
              bootloader_transaction_marker = false;
              bootloader_state_marker = false;
              ...

   Support for general purpose HTTP server
       This is a very simple backend that uses standard HTTP response codes to signal if an update is available.
       There are closed source backends implementing this interface, but because the interface  is  very  simple
       interface,  this  server  type  is also suitable for implementing an own backend server. For inspiration,
       there's a simple (mock) server implementation available in examples/suricatta/server_general.py.

       The API consists of a GET with Query parameters to inform the server about the  installed  version.   The
       query string has the format:

          http(s)://<base URL>?param1=val1&param2=value2...

       As examples for parameters, the device can send its serial number, MAC address and the running version of
       the software.  It is duty of the backend to interpret this - SWUpdate just takes them from the "identify"
       section of the configuration file and encodes the URL.

       The server answers with the following return codes:
                              ┌───────────┬─────────────┬──────────────────────────────┐
                              │ HTTP Code │ Text        │ Description                  │
                              ├───────────┼─────────────┼──────────────────────────────┤
                              │ 302       │ Found       │ A  new software is available │
                              │           │             │ at  URL  in   the   Location │
                              │           │             │ header                       │
                              ├───────────┼─────────────┼──────────────────────────────┤
                              │ 400       │ Bad Request │ Some  query  parameters  are │
                              │           │             │ missing or in wrong format   │
                              ├───────────┼─────────────┼──────────────────────────────┤
                              │ 403       │ Forbidden   │ Client certificate not valid │
                              ├───────────┼─────────────┼──────────────────────────────┤
                              │ 404       │ Not found   │ No update is  available  for │
                              │           │             │ this device                  │
                              ├───────────┼─────────────┼──────────────────────────────┤
                              │ 503       │ Unavailable │ An  update  is available but │
                              │           │             │ server can't handle  another │
                              │           │             │ update process now.          │
                              └───────────┴─────────────┴──────────────────────────────┘

       Server's answer can contain the following headers:
                               ┌───────────────┬───────┬──────────────────────────────┐
                               │ Header's name │ Codes │ Description                  │
                               ├───────────────┼───────┼──────────────────────────────┤
                               │ Retry-after   │ 503   │ Contains   a   number  which │
                               │               │       │ tells the device how long to │
                               │               │       │ wait until ask the next time │
                               │               │       │ for updates. (Seconds)       │
                               ├───────────────┼───────┼──────────────────────────────┤
                               │ Content-MD5   │ 302   │ Contains the checksum of the │
                               │               │       │ update   file    which    is │
                               │               │       │ available  under  the url of │
                               │               │       │ location header              │
                               ├───────────────┼───────┼──────────────────────────────┤
                               │ Location      │ 302   │ URL where  the  update  file │
                               │               │       │ can be downloaded.           │
                               └───────────────┴───────┴──────────────────────────────┘

       The device can send logging data to the server. Any information is transmitted in a HTTP PUT request with
       the data as plain string in the message body. The Content-Type Header need to be set to text/plain.

       The URL for the logging can be set as separate URL in the configuration file or via --logurl command line
       parameter:

       The device sends data in a CSV format (Comma Separated Values). The format is:

          value1,value2,...

       The format can be specified in the configuration file. A format For each event can be set.  The supported
       events are:
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ Event   │ Description                           │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ check   │ dummy.  It  could  send an event each │
                                 │         │ time the server is polled.            │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ started │ A new software is found and  SWUpdate │
                                 │         │ starts to install it                  │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ success │ A   new   software  was  successfully │
                                 │         │ installed                             │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ fail    │ Failure   by   installing   the   new │
                                 │         │ software                              │
                                 └─────────┴───────────────────────────────────────┘

       The general server has an own section inside the configuration file. As example:

          gservice =
          {
                  url             = ....;
                  logurl          = ;
                  logevent : (
                          {event = "check"; format="#2,date,fw,hw,sp"},
                          {event = "started"; format="#12,date,fw,hw,sp"},
                          {event = "success"; format="#13,date,fw,hw,sp"},
                          {event = "fail"; format="#14,date,fw,hw,sp"}
                  );
          }

       date is a special field and it is interpreted as localtime in RFC 2822 format. Each Comma Separated field
       is  looked  up  inside  the  identify  section  in  the  configuration  file, and if a match is found the
       substitution occurs. In case of no match, the field is sent as  it  is.  For  example,  if  the  identify
       section has the following values:

          identify : (
                  { name = "sp"; value = "333"; },
                  { name = "hw"; value = "ipse"; },
                  { name = "fw"; value = "1.0"; }
          );

       with the events set as above, the formatted text in case of "success" will be:

          Formatted log: #13,Mon, 17 Sep 2018 10:55:18 CEST,1.0,ipse,333

   Support for Suricatta Modules in Lua
       The server_lua.c C-to-Lua bridge enables writing suricatta modules in Lua. It provides the infrastructure
       in  terms  of  the  interface  to SWUpdate "core" to the Lua realm, enabling the "business logic" such as
       handling update flows and communicating with backend server APIs to be modeled in Lua. To the Lua  realm,
       the  server_lua.c  C-to-Lua bridge provides the same functionality as the other suricatta modules written
       in C have, realizing a separation of means and control. Effectively, it lifts the interface  outlined  in
       Section The Suricatta Interface to the Lua realm.

       As  an example server implementation, see examples/suricatta/server_general.py for a simple (mock) server
       of a backend that's modeled after the "General Purpose HTTP Server"  (cf.  Section  Support  for  general
       purpose     HTTP     server).     The     matching     Lua     suricatta     module     is    found    in
       examples/suricatta/swupdate_suricatta.lua. Place it in Lua's path so that a require("swupdate_suricatta")
       can load it or embed it into the SWUpdate binary by enabling  CONFIG_EMBEDDED_SURICATTA_LUA  and  setting
       CONFIG_EMBEDDED_SURICATTA_LUA_SOURCE accordingly.

       The  interface  specification  in  terms of a Lua (suricatta) module is found in suricatta/suricatta.lua,
       reproduced for convenience in Section Lua Suricatta Interface Specification.

   suricatta
       The suricatta table is the module's main table housing the exposed  functions  and  definitions  via  the
       sub-tables described below.  In addition, the main functions suricatta.install() and suricatta.download()
       as    well    as    the    convenience    functions    suricatta.getversion(),   suricatta.sleep(),   and
       suricatta.get_tmpdir() are exposed:

       The function suricatta.install(install_channel) installs an update artifact from a  remote  server  or  a
       local  file.  The  install_channel  table  parameter  designates the channel to be used for accessing the
       artifact plus channel options diverging from the defaults set at channel creation time. For  example,  an
       install_channel table may look like this:

          { channel = chn, url = "https://artifacts.io/update.swu" }

       where  chn  is the return value of a call to channel.open(). The other table attributes, like url in this
       example,  are  channel  options  diverging  from  or   omitted   while   channel   creation   time,   see
       suricatta.channel. For installing a local file, an install_channel table may look like this:

          { channel = chn, url = "file:///path/to/file.swu" }

       The  function  suricatta.download(download_channel,  localpath)  just  downloads  an update artifact. The
       parameter download_channel is as for suricatta.install().  The parameter localpath designates the  output
       path  for  the artifact. The suricatta.get_tmpdir() function (see below) is in particular useful for this
       case to supply a temporary download location as localpath. A just downloaded artifact  may  be  installed
       later using suricata.install() with an appropriate file:// URL, realizing a deferred installation.

       Both,   suricatta.install()  and  suricatta.download()  return  true,  or,  in  case  of  error,  nil,  a
       suricatta.status value, and a table with messages in case of errors, else an empty table.

       The function suricatta.getversion() returns a table with SWUpdate's version and patchlevel  fields.  This
       information can be used to determine API (in-)compatibility of the Lua suricatta module with the SWUpdate
       version running it.

       The  function  suricatta.sleep(seconds)  is  a wrapper around SLEEP(3) for, e.g., implementing a REST API
       call retry mechanism after a number of given seconds have elapsed.

       The function suricatta.get_tmpdir() returns the path to SWUpdate's  temporary  working  directory  where,
       e.g., the suricatta.download() function may place the downloaded artifacts.

   suricatta.status
       The  suricatta.status  table exposes the server_op_res_t enum values defined in include/util.h to the Lua
       realm.

   suricatta.notify
       The suricatta.notify table provides the usual logging functions to  the  Lua  suricatta  module  matching
       their uppercase-named pendants available in the C realm.

       One  notable  exception  is suricatta.notify.progress(message, cause) which dispatches the message to the
       progress interface (see Getting information on running update <>). Custom progress client implementations
       listening and acting on custom progress messages can be realized using this function.

       All notify functions return nil.

   suricatta.pstate
       The suricatta.pstate table provides a binding to SWUpdate's (persistent) state handling functions defined
       in include/state.h, however,  limited  to  the  bootloader  environment  variable  STATE_KEY  defined  by
       CONFIG_UPDATE_STATE_BOOTLOADER and defaulting to ustate. In addition, it captures the update_state_t enum
       values.

       The  function  suricatta.pstate.save(state) requires one of suricatta.pstate's "enum" values as parameter
       and returns true, or, in case  of  error,  nil.   The  function  suricatta.pstate.get()  returns  one  of
       suricatta.pstate's "enum" values or, in case of error, STATE_ERROR.

   suricatta.server
       The  suricatta.server table provides the sole function suricatta.server.register(function_p, purpose). It
       registers a Lua function "pointed" to  by  function_p  for  the  purpose  purpose  which  is  defined  by
       suricatta.server's  "enum" values. Those enum values correspond to the functions defined in the interface
       outlined in the Section on The Suricatta Interface.

       In addition to these functions, the two callback functions  CALLBACK_PROGRESS  and  CALLBACK_CHECK_CANCEL
       can  be  registered optionally: The former can be used to upload progress information to the server while
       the latter serves as dwlwrdata function (see include/channel_curl.h) to decide on whether an installation
       should be aborted while the download phase.

       For  details  on  the  (callback)  functions  and  their  signatures,  see  the  interface  specification
       suricatta/suricatta.lua    and    the    documented    example    Lua    suricatta    module   found   in
       examples/suricatta/swupdate_suricatta.lua.

       The suricatta.server.register() function returns true, or, in case of error, nil.

   suricatta.channel
       The suricatta.channel table captures channel handling for suricatta Lua  modules.   The  single  function
       suricatta.channel.open(options)  creates and opens a channel to a server. Its single parameter options is
       a table specifying  the  channel's  default  options  such  as  proxy,  retries,  usessl,  strictssl,  or
       headers_to_send.  For  convenience,  options  that  may  change per request such as url, content-type, or
       headers_to_send may be set as defaults on channel creation time while being selectively  overruled  on  a
       per   request   basis.   The   channel   options  currently  supported  to  be  set  are  listed  in  the
       suricatta.channel.options table. In essence, the options parameter table is the Lua table  equivalent  of
       include/channel_curl.h's channel_data_t.

       The  suricatta.channel.open(options)  function  returns  a  channel  table  which is either passed to the
       suricatta.install() and suricatta.download() functions or used directly for communication with a  server.
       More specifically, it has the three functions

       • get(options) for retrieving information from the server,

       • put(options) for sending information to the server, and

       • close() for closing the channel.

       The  get()  and  put()  functions'  single  parameter  options  is  a per-request channel option table as
       described above.

       The functions get() and put() return true, or, in case of error, nil, a suricatta.status  value,  and  an
       operation result table.  The latter contains the fields:

       • http_response_code carrying the HTTP error code,

       • format as one of suricatta.channel.content's options,

       • raw_reply if options contained format = suricatta.channel.content.RAW,

       • json_reply if options contained format = suricatta.channel.content.JSON, and

       • the HTTP headers received in the received_headers table, if any.

       The suricatta.channel.content "enum" table defines the "format", i.e., the response body content type and
       whether to parse it or not:

       • NONE means the response body is discarded.

       • RAW means the raw server's reply is available as raw_reply.

       • JSON means the server's JSON reply is parsed into a Lua table and available as json_reply.

       The  suricatta.channel.method  "enum"  table defines the HTTP method to use for a request issued with the
       put(options) function, i.e., POST, PATCH, or PUT as specified in the  options  parameter  table  via  the
       method  attribute.   In  addition  to  the  HTTP  method,  the  request  body's  content  is set with the
       request_body attribute in the options parameter table.

       As a contrived example, consider the following call to a channel's put() function

          ...
          local res, _, data = channel.put({
                  url          = string.format("%s/%s", base_url, device_id),
                  content_type = "application/json",
                  method       = suricatta.channel.method.PATCH,
                  format       = suricatta.channel.content.NONE,
                  request_body = "{ ... }"
              })
          ...

       that issues a HTTP PATCH to some URL with a JSON content without having interest in the response body.

       More  examples  of  how  to  use  a  channel  can  be  found  in  the  example   suricatta   Lua   module
       examples/suricatta/swupdate_suricatta.lua.

   suricatta.bootloader
       The  suricatta.bootloader  table  exposes  SWUpdate's  bootloader  environment  modification functions to
       suricatta Lua modules.

       The enum-like table suricatta.bootloader.bootloaders holds the bootloaders SWUpdate supports, i.e.

              suricatta.bootloader.bootloaders = {
                  EBG   = "ebg",
                  NONE  = "none",
                  GRUB  = "grub",
                  UBOOT = "uboot",
              },

       The function  suricatta.bootloader.get()  returns  the  currently  selected  bootloader  in  terms  of  a
       suricatta.bootloader.bootloaders field value.

       The  function  suricatta.bootloader.is(name) takes one of suricatta.bootloader.bootloaders's field values
       as name and returns true if it is the currently selected bootloader, false otherwise.

       The functions in the suricatta.bootloader.env table interact with  the  currently  selected  bootloader's
       environment:

       The  function  suricatta.bootloader.env.get(variable) retrieves the value associated to variable from the
       bootloader's environment.

       The function suricatta.bootloader.env.set(variable, value) sets the bootloader environment's key variable
       to value.

       The function suricatta.bootloader.env.unset(variable) deletes the bootloader environment's key variable.

       The function suricatta.bootloader.env.apply(filename)  applies  all  key=value  lines  of  a  local  file
       filename to the currently selected bootloader's environment.

   Lua Suricatta Interface Specification
          --[[

              SWUpdate Suricatta Lua Module.

              Interface specification for the Lua module provided by the
              "Suricatta Lua module" suricatta "server" (suricatta/server_lua.c).

              Author: Christian Storm <christian.storm@siemens.com>
              Copyright (C) 2022, Siemens AG

              SPDX-License-Identifier: GPL-2.0-or-later

          --]]

          ---@diagnostic disable: missing-return
          ---@diagnostic disable: unused-local
          -- luacheck: no max line length
          -- luacheck: no unused args

          -- Note: Definitions prefixed with `---` are not part of the SWUpdate functionality
          -- exposed to the Lua realm but instead are `typedef`-alikes returned by a function
          -- of the SWUpdate Suricatta Lua Module. Nonetheless, they are in the suricatta
          -- "namespace" for avoiding name clashes and, not least, convenience.

          --- SWUpdate Suricatta Binding.
          --
          --- @class suricatta
          local suricatta = {}

          --- @enum suricatta.status
          --- Lua equivalent of `server_op_res_t` enum as in `include/util.h`.
          suricatta.status = {
              OK                  = 0,
              EERR                = 1,
              EBADMSG             = 2,
              EINIT               = 3,
              EACCES              = 4,
              EAGAIN              = 5,
              UPDATE_AVAILABLE    = 6,
              NO_UPDATE_AVAILABLE = 7,
              UPDATE_CANCELED     = 8,
              ID_REQUESTED        = 9,
          }

          --- SWUpdate notify function bindings.
          --
          -- Translates to `notify(string.format(message, ...))`,
          -- @see `corelib/lua_interface.c`
          -- except for `suricatta.notify.progress()`.
          --
          --- @class suricatta.notify
          suricatta.notify = {
              --- @type fun(message: string, ...: any)
              error    = function(message, ...) end,
              --- @type fun(message: string, ...: any)
              trace    = function(message, ...) end,
              --- @type fun(message: string, ...: any)
              debug    = function(message, ...) end,
              --- @type fun(message: string, ...: any)
              info     = function(message, ...) end,
              --- @type fun(message: string, ...: any)
              warn     = function(message, ...) end,
              --- @type fun(message: string, cause:suricatta.ipc.progress_cause?)
              progress = function(message, cause) end,
          }

          --- SWUpdate's bootloader interface as in `include/bootloader.h`.
          --
          --- @class suricatta.bootloader
          suricatta.bootloader = {
              --- @enum suricatta.bootloader.bootloaders
              --- Bootloaders supported by SWUpdate.
              bootloaders = {
                  EBG   = "ebg",
                  NONE  = "none",
                  GRUB  = "grub",
                  UBOOT = "uboot",
              },
          }

          --- Get currently set bootloader's name.
          --
          --- @return suricatta.bootloader.bootloaders | nil  # Name of currently set bootloader
          suricatta.bootloader.get = function() end

          --- Test whether bootloader `name` is currently set.
          --
          --- @param  name     suricatta.bootloader.bootloaders  Name of bootloader to test for being currently selected
          --- @return boolean                                    # True if `name` is currently set bootloader, false otherwise
          suricatta.bootloader.is = function(name) end

          --- Operations on the currently set bootloader's environment.
          --
          --- @class suricatta.bootloader.env
          suricatta.bootloader.env = {}

          --- Get value of a bootloader environment variable.
          --
          --- @param  variable  string  Name of the bootloader environment variable to get value for
          --- @return string | nil      # Value of the bootloader environment variable or nil if non-existent
          suricatta.bootloader.env.get = function(variable) end

          --- Set value of a bootloader environment variable.
          --
          --- @param  variable  string  Name of the bootloader environment variable to set
          --- @param  value     string  Value to set the bootloader environment variable `variable` to
          --- @return boolean | nil     # True on success, nil on error
          suricatta.bootloader.env.set = function(variable, value) end

          --- Drop a bootloader environment variable.
          --
          --- @param  variable  string  Name of the bootloader environment variable to drop
          --- @return boolean | nil     # True on success, nil on error
          suricatta.bootloader.env.unset = function(variable) end

          --- Set multiple bootloader environment variables from local file.
          --
          --- @param  filename  string  Path to local file in format `<variable>=<value>`
          --- @return boolean | nil     # True on success, nil on error
          suricatta.bootloader.env.apply = function(filename) end

          --- SWUpdate's persistent state IDs as in `include/state.h` and reverse-lookup.
          --
          --- @class suricatta.pstate
          suricatta.pstate = {
              OK            = string.byte('0'), [string.byte('0')] = "OK",
              INSTALLED     = string.byte('1'), [string.byte('1')] = "INSTALLED",
              TESTING       = string.byte('2'), [string.byte('2')] = "TESTING",
              FAILED        = string.byte('3'), [string.byte('3')] = "FAILED",
              NOT_AVAILABLE = string.byte('4'), [string.byte('4')] = "NOT_AVAILABLE",
              ERROR         = string.byte('5'), [string.byte('5')] = "ERROR",
              WAIT          = string.byte('6'), [string.byte('6')] = "WAIT",
              IN_PROGRESS   = string.byte('7'), [string.byte('7')] = "IN_PROGRESS",
          }

          --- Get the current stored persistent state.
          --
          --- @return number   # Persistent state ID number, suricatta.pstate.ERROR if unsuccessful
          suricatta.pstate.get = function() end

          --- Save persistent state information.
          --
          --- @param  state  number  Persistent state ID number
          --- @return boolean | nil  # True on success, nil on error
          suricatta.pstate.save = function(state) end

          --- Function registry IDs for Lua suricatta functions.
          --
          --- @class suricatta.server
          suricatta.server = {
              HAS_PENDING_ACTION    = 0,
              INSTALL_UPDATE        = 1,
              SEND_TARGET_DATA      = 2,
              GET_POLLING_INTERVAL  = 3,
              SERVER_START          = 4,
              SERVER_STOP           = 5,
              IPC                   = 6,
              PRINT_HELP            = 7,
              CALLBACK_PROGRESS     = 8,
              CALLBACK_CHECK_CANCEL = 9,
          }

          --- Register a Lua function as Suricatta interface implementation.
          --
          --- @param  function_p  function   Function to register for `purpose`
          --- @param  purpose     number     Suricatta interface function implemented (one of suricatta.server's enums)
          --- @return boolean                # Whether operation was successful or not
          suricatta.server.register = function(function_p, purpose) end

          --- Channel result table.
          --
          -- Result in return of a channel operation.
          --
          --- @class suricatta.channel_operation_result
          --- @field http_response_code  number
          --- @field format              suricatta.channel.content
          --- @field json_reply          table | nil   Table if `format` was `suricatta.channel.content.JSON`
          --- @field raw_reply           string | nil  Table if `format` was `suricatta.channel.content.RAW`
          --- @field received_headers    table<string, string> | nil

          --- Options and methods on the opened channel.
          --
          -- Table as returned by `suricatta.channel.open()`.
          --
          --- @class suricatta.open_channel
          --- @field options  suricatta.channel.options                                                                               Channel creation-time set options as in `include/channel_curl.h`.
          --- @field get      fun(options: suricatta.channel.options): boolean, suricatta.status, suricatta.channel_operation_result  Channel get operation
          --- @field put      fun(options: suricatta.channel.options): boolean, suricatta.status, suricatta.channel_operation_result  Channel put operation
          --- @field close    fun()                                                                                                   Channel close operation

          --- @class suricatta.channel
          suricatta.channel = {

              -- Lua-alike of proxy environment variable usage marker as in `include/channel_curl.h`.
              -- An empty `proxy` string means to use proxy environment variables.
              -- @type string
              USE_PROXY_ENV = "",

              --- @enum suricatta.channel.content
              --- Content type passed over the channel as in `include/channel_curl.h`.
              content = {
                  NONE = 0,
                  JSON = 1,
                  RAW  = 2,
              },

              --- @enum suricatta.channel.method
              --- Transfer method to use over channel as in `include/channel_curl.h`.
              method = {
                  GET   = 0,
                  POST  = 1,
                  PUT   = 2,
                  PATCH = 3,
              },

              --- Channel options as in `include/channel_curl.h`.
              --
              --- @class suricatta.channel.options
              --- @field url                 string | nil   `CURLOPT_URL` - URL for this transfer
              --- @field cached_file         string | nil   Resume download from cached file at path
              --- @field auth                string | nil   `CURLOPT_USERPWD` - user name and password to use in authentication
              --- @field request_body        string | nil   Data to send to server for `PUT` and `POST`
              --- @field iface               string | nil   `CURLOPT_INTERFACE` - source interface for outgoing traffic
              --- @field dry_run             boolean | nil  `swupdate_request`'s dry_run field as in `include/network_ipc.h`
              --- @field cafile              string | nil   `CURLOPT_CAINFO` - path to Certificate Authority (CA) bundle
              --- @field sslkey              string | nil   `CURLOPT_SSLKEY` - private key file for TLS and SSL client cert
              --- @field sslcert             string | nil   `CURLOPT_SSLCERT` - SSL client certificate
              --- @field ciphers             string | nil   `CURLOPT_SSL_CIPHER_LIST` - ciphers to use for TLS
              --- @field proxy               string | nil   `CURLOPT_PROXY` - proxy to use
              --- @field info                string | nil   `swupdate_request`'s info field as in `include/network_ipc.h`
              --- @field auth_token          string | nil   String appended to Header
              --- @field content_type        string | nil   `Content-Type:` and `Accept:` appended to Header
              --- @field retry_sleep         number | nil   Time to wait prior to retry and resume a download
              --- @field method              suricatta.channel.method | nil  Channel transfer method to use
              --- @field retries             number | nil   Maximal download attempt count
              --- @field low_speed_timeout   number | nil   `CURLOPT_LOW_SPEED_TIME` - low speed limit time period
              --- @field connection_timeout  number | nil   `CURLOPT_CONNECTTIMEOUT` - timeout for the connect phase
              --- @field format              suricatta.channel.content | nil  Content type passed over the channel
              --- @field debug               boolean | nil  Set channel debug logging
              --- @field usessl              boolean | nil  Enable SSL hash sum calculation
              --- @field strictssl           boolean | nil  `CURLOPT_SSL_VERIFYHOST` + `CURLOPT_SSL_VERIFYPEER`
              --- @field nocheckanswer       boolean | nil  Whether the reply is interpreted/logged and tried to be parsed
              --- @field nofollow            boolean | nil  `CURLOPT_FOLLOWLOCATION` - follow HTTP 3xx redirects
              --- @field max_download_speed  string | nil   `CURLOPT_MAX_RECV_SPEED_LARGE` - rate limit data download speed
              --- @field headers_to_send     table<string, string> | nil  Header to send
              options = {},

              --- Open a new channel.
              --
              --- @param  options  suricatta.channel.options  Channel default options overridable per operation
              --- @return boolean                             # Whether operation was successful or not
              --- @return suricatta.open_channel              # Options of and operations on the opened channel
              open = function(options) end,
          }

          --- Channel and Options Table to use for an operation.
          --
          -- Channel to use for the download / installation operation as returned by `suricatta.channel.open()`
          -- plus channel options overriding the defaults per operation (@see suricatta.channel.options)
          -- and specific options to the download / installation operation, e.g., `drain_messages`.
          --
          --- @class suricatta.operation_channel
          --- @field channel          suricatta.open_channel           Channel table as returned by `suricatta.channel.open()`
          --- @field drain_messages   boolean  | nil                   Whether to flush all progress messages or only those while in-flight operation (default)
          --- @field                  suricatta.channel.options | nil  Channel options to override for this operation

          --- Install an update artifact from remote server or local file.
          --
          -- If the protocol specified in Table `install_channel`'s `url` field is `file://`,
          -- a local update artifact file is installed. If it is, e.g., `https://`, the
          -- update artifact is downloaded *and* installed.
          -- Note that this file is to be deleted, if applicable, from the Lua realm.
          --
          --- @see suricatta.download
          --- @param  install_channel  suricatta.operation_channel  Channel to use for the download+installation operation
          --- @return boolean                                       # Whether operation was successful or not
          --- @return suricatta.status                              # Suricatta return code
          --- @return table<number, string>                         # Error messages, if any
          suricatta.install = function(install_channel) end

          --- Download an update artifact from remote server.
          --
          -- `suricatta.download()` just downloads an update artifact from the remote server
          -- without installing it. For later installation, call `suricatta.install()` with
          -- an appropriate `install_channel` Table's `url` field.
          --
          --- @see suricatta.install
          --- @param  download_channel  suricatta.operation_channel  Channel to use for the download operation
          --- @param  localpath         string                       Path where to store the downloaded artifact to
          --- @return boolean                                        # Whether operation was successful or not
          --- @return suricatta.status                               # Suricatta return code
          --- @return table<number, string>                          # Error messages, if any
          suricatta.download = function(download_channel, localpath) end

          --- Sleep for a number of seconds.
          --
          -- Call `SLEEP(3)` via C realm.
          --
          --- @param seconds number  # Number of seconds to sleep
          suricatta.sleep = function(seconds) end

          --- Get TMPDIR from SWUpdate.
          --
          -- @see `core/util.c` :: get_tmpdir()
          --
          --- @return string  # TMPDIR path
          suricatta.get_tmpdir = function() end

          --- SWUpdate version information.
          --- @class suricatta.version
          --- @field [1]         number  SWUpdate's version
          --- @field [2]         number  SWUpdate's patch level
          --- @field version     number  SWUpdate's version
          --- @field patchlevel  number  SWUpdate's patch level

          --- Get SWUpdate version.
          --
          --- @return suricatta.version  # Table with `version` and `patchlevel` fields
          suricatta.getversion = function() end

          --- SWUpdate IPC types and definitions.
          --
          --- @class suricatta.ipc
          suricatta.ipc = {}

          --- @enum suricatta.ipc.sourcetype
          --- Lua equivalent of `sourcetype` as in `include/swupdate_status.h`.
          suricatta.ipc.sourcetype = {
              SOURCE_UNKNOWN           = 0,
              SOURCE_WEBSERVER         = 1,
              SOURCE_SURICATTA         = 2,
              SOURCE_DOWNLOADER        = 3,
              SOURCE_LOCAL             = 4,
              SOURCE_CHUNKS_DOWNLOADER = 5
          }

          --- @enum suricatta.ipc.RECOVERY_STATUS
          --- Lua equivalent of `RECOVERY_STATUS` as in `include/swupdate_status.h`.
          suricatta.ipc.RECOVERY_STATUS = {
              IDLE       = 0,
              START      = 1,
              RUN        = 2,
              SUCCESS    = 3,
              FAILURE    = 4,
              DOWNLOAD   = 5,
              DONE       = 6,
              SUBPROCESS = 7,
              PROGRESS   = 8
          }

          --- @enum suricatta.ipc.progress_cause
          --- Lua equivalent of `progress_cause_t` as in `include/progress_ipc.h`.
          suricatta.ipc.progress_cause = {
              CAUSE_NONE        = 0,
              CAUSE_REBOOT_MODE = 1,
          }

          --- Lua-alike of `progress_msg` as in `include/progress_ipc.h`.
          --
          --- @class suricatta.ipc.progress_msg
          --- @field magic        number                         SWUpdate IPC magic number
          --- @field status       suricatta.ipc.RECOVERY_STATUS  Update status
          --- @field dwl_percent  number                         Percent of downloaded data
          --- @field nsteps       number                         Total steps count
          --- @field cur_step     number                         Current step
          --- @field cur_percent  number                         Percent in current step
          --- @field cur_image    string                         Name of the current image to be installed (max: 256 chars)
          --- @field hnd_name     string                         Name of the running handler (max: 64 chars)
          --- @field source       suricatta.ipc.sourcetype       The source that has triggered the update
          --- @field info         string                         Additional information about the installation (max: 2048 chars)
          --- @field jsoninfo     table                          If `info` is JSON, according Lua Table

          --- Lua enum of IPC commands as in `include/network_ipc.h`.
          --
          -- `CMD_ENABLE` is not passed through and hence not in `ipc_commands`
          -- as it's handled directly in `suricatta/suricatta.c`.
          --
          --- @type  {[string]: number}
          --- @class suricatta.ipc.ipc_commands
          --- @field ACTIVATION  number  0
          --- @field CONFIG      number  1
          --- @field GET_STATUS  number  3

          --- Lua-alike of `ipc_message` as in `include/network_ipc.h`.
          --
          -- Note: Some members are deliberately not passed through to the Lua
          -- realm such as `ipc_message.data.len` since that's transparently
          -- handled by the C-to-Lua bridge.
          -- Note: This is not a direct equivalent but rather a "sensible" selection
          -- as, e.g., the `json` field is not present in `struct ipc_message`.
          --
          --- @class suricatta.ipc.ipc_message
          --- @field magic     number                      SWUpdate IPC magic number
          --- @field commands  suricatta.ipc.ipc_commands  IPC commands
          --- @field cmd       number                      Command number, one of `ipc_commands`'s values
          --- @field msg       string                      String data sent via IPC
          --- @field json      table                       If `msg` is JSON, JSON as Lua Table

          return suricatta

CONFIG FOR HAWKBIT UNDER SSL/TLS USING PRIVATE CA / SUB CA

       A user-contributed recipe based on hawkBit (0.2.0-SNAPSHOT) + swupdate (v2018.03)

   Purpose
       Use HTTPS on a hawkBit server to avoid server spoofing. Anonymous client connections are authorized.

   Recipe
       1. On the PKI:

          • Create  a  pkcs#12  (.p12)  file, rolling server key, server, private CA, sub CA certs into a single
            file.

          • Use a password on the server key you won't be ashamed of.

          • Also create a single .pem file for the private CA + sub-CA

       2. On the hawkBit host:

          • hawkBit uses the Java KeyStore to access credentials, but a JKS is not designed apparently  to  hold
            CA  certs,  which  is a problem for private CAs. The workaround is to make it gulp an entire pkcs#12
            file.

          • It looks like a JKS like this cannot have a password different from the  one  protecting  the  .p12.
            Keytool  also  seems to have a little tendency to destruct the .jks if you change your mind and want
            to change the password... Basically do everything you need with openssl and  use  only  keytool  for
            generating the .jks file.

          The following command imports a .p12 into a "pkcs12 Java keystore", keeping the same password:

              keytool -importkeystore -srckeystore hb-pass.p12 -srcstoretype pkcs12 \
                      -destkeystore hb-pass.jks -deststoretype pkcs12 \
                      -alias 1 -deststorepass <password_of_p12>

          Then  you  need  to  adapt  application.properties  of the hawkBit server to make use of the keystore.
          There are extra requirements to make hawkBit send artifacts via HTTPS.

          This           is            the            relevant            part            of            <hawkBit
          dir>/hawkbit-runtime/hawkbit-update-server/src/main/resources/application.properties:

              # HTTPS mode working w/ swupdate
              # See also https://docs.spring.io/spring-boot/docs/1.4.7.RELEASE/reference/html/howto-embedded-servlet-containers.html#howto-configure-ssl
              #          https://github.com/eclipse/hawkbit/issues/618
              #
              # Need to run as root to use port 443
              server.hostname=hb.domain
              server.port=8443
              #
              # Overriding some of hawkbit-artifactdl-defaults.properties is required
              hawkbit.artifact.url.protocols.download-http.protocol=https
              hawkbit.artifact.url.protocols.download-http.port=8443
              #
              # Upgrades http:8443 to https:8443
              # Would redirect + upgrade http:80 to https:443
              security.require-ssl=true
              server.use-forward-headers=true
              #
              # Server cert+key w/ private CA + subCA
              # See also https://stackoverflow.com/questions/906402/how-to-import-an-existing-x509-certificate-and-private-key-in-java-keystore-to-u
              #          http://cunning.sharp.fm/2008/06/importing_private_keys_into_a.html (2008, still relevant!?)
              #
              # File .jks is a .p12 imported via keytool. Only one password supported, set from openssl.
              server.ssl.key-store=hb-pass.jks
              server.ssl.key-password=password
              server.ssl.key-store-password=password-yes_the_same_one
              ...

       3. On the swupdate client host(s):

          • The client needs the private CA certificate(s) to authenticate the server.

          • There  is  a  setting  in  swupdate to specify the path to a single CA cert, not a directory. Beyond
            that, libcurl looks into /etc/ssl/certs. So we're using a compound "CA chain" .pem file to hold both
            private CA and sub-CA in our preferred location.

          This is the relevant part of /etc/swupdate/swupdate.conf:

              ...
              suricatta :
              {
               tenant = "default";
               id = "machineID";
               url = "https://hb.domain:8443";
               nocheckcert = false;
               cafile = "/etc/swupdate/priv-cachain.pem"; /* CA + sub CA in one file */
               /* sslkey = anon client: do not set; */
               /* sslcert = anon client: do not set; */
              ...

SWUPDATE: API FOR EXTERNAL PROGRAMS

   Overview
       SWUpdate contains an integrated web-server to  allow  remote  updating.   However,  which  protocols  are
       involved  during an update is project specific and differs significantly. Some projects can decide to use
       FTP to load an image from an external server, or using  even  a  proprietary  protocol.   The  integrated
       web-server uses this interface.

       SWUpdate  has  a simple interface to let external programs to communicate with the installer. Clients can
       start an upgrade and stream an image to the installer, querying then for the status and the final result.
       The API is at the moment very simple, but it can easy be extended in the future if  new  use  cases  will
       arise.

   API Description
       The communication runs via Unix Domain Socket (UDS). The socket path is determined by

       • the CONFIG_SOCKET_CTRL_PATH compile-time configuration,

       • $RUNTIME_DIRECTORY/sockinstctrl if $RUNTIME_DIRECTORY is set,

       • $TMPDIR/sockinstctrl if $TMPDIR is set, or

       • /tmp/sockinstctrl,

       in  this  order, and taken over from systemd or created by SWUpdate.  This socket should, however, not be
       used directly but instead by the Client Library explained below.

       The exchanged packets are described in network_ipc.h

          typedef struct {
                  int magic;
                  int type;
                  msgdata data;
          } ipc_message;

       Where the fields have the meaning:

       • magic : a magic number as simple proof of the packet

       • type : one of REQ_INSTALL, ACK, NACK, GET_STATUS, POST_UPDATE, SWUPDATE_SUBPROCESS, SET_AES_KEY

       • msgdata : a buffer used by the client to send the image or by SWUpdate to report back notifications and
         status.

       The client sends a REQ_INSTALL packet and waits for an answer.  SWUpdate sends back ACK or NACK,  if  for
       example an update is already in progress.

       After  the  ACK,  the client sends the whole image as a stream. SWUpdate expects that all bytes after the
       ACK are part of the image to be installed.  SWUpdate recognizes the size  of  the  image  from  the  CPIO
       header.   Any  error lets SWUpdate to leave the update state, and further packets will be ignored until a
       new REQ_INSTALL will be received.  [image]

       It is recommended to use the client library to communicate with SWUpdate. On the lower level with  direct
       socket  communication,  it cannot be guaranteed that the structures will remain compatible in the future.
       The client library was affected by this issue, too, and it is changed to accept an opaque interface  that
       will survive API changes. Compatibility layers could be added on-demand in the future due to API changes.

   Client Library
   Functions to start an update
       A library simplifies the usage of the IPC making available a way to start asynchronously an update.

       The library consists of one function and several call-backs.

          int swupdate_async_start(writedata wr_func, getstatus status_func,
                  terminated end_func, void *req, ssize_t size)
          typedef int (*writedata)(char **buf, int *size);
          typedef int (*getstatus)(ipc_message *msg);
          typedef int (*terminated)(RECOVERY_STATUS status);

       swupdate_async_start creates a new thread and start the communication with SWUpdate, triggering for a new
       update.  The wr_func is called to get the image to be installed.  It is responsibility of the callback to
       provide the buffer and the size of the chunk of data.

       The getstatus call-back is called after the stream was downloaded to check how upgrade is  going  on.  It
       can be omitted if only the result is required.

       The terminated call-back is called when SWUpdate has finished with the result of the upgrade.

       Example about using this library is in the examples/client directory.

       The  req structure is casted to void to ensure API compatibility. Am user should instantiate it as struct
       swupdate_request. This contains fields that can control the update process:

          struct swupdate_request {
                  unsigned int apiversion;
                  sourcetype source;
                  int dry_run;
                  size_t len;
                  char info[512];
                  char software_set[256];
                  char running_mode[256];
          };

       A user should first call swupdate_prepare_req()

          void swupdate_prepare_req(struct swupdate_request *req);

       This fills the request structure with default values. After that, the user can fill the other fields as:

          • sourcetype  :  one  of  SOURCE_UNKNOWN,   SOURCE_WEBSERVER,   SOURCE_SURICATTA,   SOURCE_DOWNLOADER,
            SOURCE_LOCAL

          • dry_run : one of RUN_DEFAULT (set from command line), RUN_DRYRUN, RUN_INSTALL.

          • info, len : a variable length data that can be forwarded to the progress interface. The installer in
            SWUpdate does not evaluate it.

          • software_set  and  running_mode  : this allows one to set the selection for the update, it should be
            accepted by swupdate (-q, --accepted-select option when swupdate is launched).

   Functions to set AES keys
       The key for decryption can be set with command line parameter (see -K), but it is possible to set it  via
       IPC. In this way, each update could have a different key.

          int swupdate_set_aes(char *key, char *ivt)

       The  key is for AES-256. The length for key and ivt are then defined by the algorithm amd they are passed
       as ASCII string, so the length must be 64 bytes for key and 32 bytes for IVT.

   Functions to control SWUpdate
          int ipc_send_cmd(ipc_message *msg);

       ipc_send_cmd is used to send a command to a SWUpdate subprocess (as suricatta). The function is synchron,
       that means it clocks until the subprocess has answered with ACK or  NACK.  This  function  sets  type  to
       SWUPDATE_SUBPROCESS.   The caller must then set the other fields in message according to the destination.
       The msgdata field is a structure as:

          struct {
             sourcetype source; /* Who triggered the update */
             int     cmd;       /* Optional encoded command */
             int     timeout;     /* timeout in seconds if an aswer is expected */
             unsigned int len;    /* Len of data valid in buf */
             char    buf[2048];   /*
                                   * Buffer that each source can fill
                                   * with additional information
                                   */
             }

       The caller fills source with the subprocess that accepts the command. Values of cmd are in network_ipc.h.

   Messages for suricatta
       suricatta accepts messages in JSON format. The message must be formatted in the buf field of the  message
       data.

   Setting the polling time
          { "polling" : <value in seconds, range 0..X>}

       Setting  it  to 0 has the special meaning that the polling time is retrieved from the Backend (if this is
       supported by the server).

   Enable / disable Suricatta daemon
          { "enable" : true }
          { "enable" : false }

   Set custom device attributes for Suricatta (for Hawkbit implementation)
          { "identify" : [
              {
                  "name"  : "customizableAttributeOne",
                  "value" : "valueOne"
              },
              {
                  "name"  : "customizableAttributeTwo",
                  "value" : "valueTwo"
              }
          ]}

       New attributes can be added at runtime, and existing attributes can be modified in the same way.  Changes
       will be reflected on the server in the next poll iteration.

   Trigger a check on the server
       This  is  useful in case the device is mostly offline, and when it is online, it should check immediately
       if an update exists and run it. In fact, after enabling the suricatta  daemon,  the  update  follows  the
       usual  states,  and  the  daemon  waits  for a polling time before loading the new software. This command
       forces an update (if available) without changing the polling time.

          { "trigger" : true }

   Activate an already installed Software
       After a software was installed, the new software boots and if everything runs fine, an acknowledge should
       be sent to the hawkBit server. If this feature is used, for example to let the end user decide if the new
       software is accepted, the parameters used by the installation should be stored during the update process.

          { "id" : <action id>,
            "finished" : "success", "failure", "none",
            "execution" : ["closed", "proceeding", canceled", "rejected", "resumed"]
            "details" : [ ]
          }

   Get hawkBit Server Status
       To provide the hawkBit server status to other processes, it can be requested by sending an empty  message
       with message type CMD_GET_STATUS.

       The  response  is  a  JSON  object  containing  the hawkBit server status <status>.  <status> is a number
       representing the value of the channel_op_res_t enum from  channel_op_res.h.  As  the  hawkBit  server  is
       polled,  its status can only be updated when it has been polled. Therefore the response also contains the
       time <time>, when the hawkBit server has been polled the last time. It is provided as ISO 8601  date  and
       time string. (2021-10-14T13:42:37.000+00)

          { "server" : {
                          "status" : <status>
                          "time" : <time>
                       }
          }

       An example application can be found under tools/swupdate-gethawkbitstatus.c

   API to the integrated Webserver
       The integrated Webserver provides REST resources to push a SWU package and to get inform about the update
       process.  This API is based on HTTP standards. There are to kind of interface:

       • Install API to push a SWU and to restart the device after update.

       • A WebSocket interface to send the status of the update process.

   Install API
          POST /upload

       This  initiates an update: the initiator sends the request and start to stream the SWU in the same way as
       described in API Description.  The POST /upload request contains:

       • the SWU file in its body

       • the following header field
            Content-Type: multipart/form-data; boundary...

       For example to stream the SWU file and start the update procedure using curl:

          curl -F file=@update_file.swu http://host:8080/upload

   Restart API
          POST /restart

       If configured (see post update command), this request will restart the device.

   WebSocket API
       The integrated Webserver exposes a  WebSocket  API.  The  WebSocket  protocol  specification  defines  ws
       (WebSocket) and wss (WebSocket Secure) as two new uniform resource identifier (URI) schemes that are used
       for  unencrypted  and  encrypted connections, respectively and both of them are supported by SWUpdate.  A
       WebSocket provides full-duplex communication but it is used in SWUpdate to send  events  to  an  external
       host  after each change in the update process. The Webserver sends JSON formatted responses as results of
       internal events.

       The response contains the field type, that defines which event is sent.

   Event Type
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ type    │ Description of event                  │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ status  │ Event sent when  SWUpdate's  internal │
                                 │         │ state changes                         │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ source  │ Event  to inform from which interface │
                                 │         │ an update is received                 │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ info    │ Event  with  custom  message  to   be │
                                 │         │ passed to an external process         │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ message │ Event that contains the error message │
                                 │         │ in case of error                      │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ step    │ Event  to  inform  about  the running │
                                 │         │ update                                │
                                 └─────────┴───────────────────────────────────────┘

   Status Change Event
       This event is sent when the internal SWUpdate status change. Following status are supported:

          IDLE
          START
          RUN
          SUCCESS
          FAILURE
          DONE

       Example:

          {
                  "type": "status",
                  "status": "SUCCESS"
          }

   Source Event
       This event informs from which interface a SWU is loaded.

          {
                  "type": "source",
                  "source": "WEBSERVER"
          }

       The field source can have one of the following values:

          UNKNOWN
          WEBSERVER
          SURICATTA
          DOWNLOADER
          LOCAL

   Info Event
       This event forwards all internal logs sent with level=INFO.

          {
                  "type": "info",
                  "source": < text message >
          }

   Message Event
       This event contains the error message in case of failure.

   Fields for message event
                                    ┌────────┬───────────────────────────────────┐
                                    │ name   │ Description                       │
                                    ├────────┼───────────────────────────────────┤
                                    │ status │ "message"                         │
                                    ├────────┼───────────────────────────────────┤
                                    │ level  │ "3" in case of error, "6" as info │
                                    ├────────┼───────────────────────────────────┤
                                    │ text   │ Message associated to the event   │
                                    └────────┴───────────────────────────────────┘

       Example:

          {
                  "type": "message",
                  "level": "3",
                  "text" : "[ERROR] : SWUPDATE failed [0] ERROR core/cpio_utils.c : ",
          }

   Step event
       This event contains which is the current step running and which percentage  of  this  step  is  currently
       installed.

   Fields for step event
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ name    │ Description                           │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ number  │ total  number  of  steps  N  for this │
                                 │         │ update                                │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ step    │ running step in range [1..N]          │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ name    │ filename of artefact to be installed  │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ percent │ percentage of the running step        │
                                 └─────────┴───────────────────────────────────────┘

       Example:

          {
                  "type": "step",
                  "number": "7",
                  "step": "2",
                  "name": "rootfs.ext4.gz",
                  "percent": "18"
          }

GETTING INFORMATION ON RUNNING UPDATE

       It is often required to inform the operator about the status of the running update and not just to return
       if the update was successful or not.  For example, if the target has a display or a remote interface,  it
       can be forwarded which is reached percentage of the update to let estimate how much the update will still
       run.   SWUpdate  has an interface for this ("progress API"). An external process can register itself with
       SWUpdate, and it will receive notifications when something in the update was changed. This  is  different
       from  the IPC API, because the last one is mainly used to transfer the SWU image, and it is only possible
       to poll the interface to know if the update is still running.

   API Description
       An external process registers  itself  to  SWUpdate  with  a  connect()  request  to  the  domain  socket
       "/tmp/swupdateprog"  as  per  default  configuration  of  SWUpdate.  There is no information to send, and
       SWUpdate simply inserts the new connection into the list of processes to be informed. SWUpdate will  send
       a frame back after any change in the update process with the following data (see include/progress_ipc.h):

          struct progress_msg {
                  unsigned int    magic;          /* Magic Number */
                  unsigned int    status;         /* Update Status (Running, Failure) */
                  unsigned int    dwl_percent;    /* % downloaded data */
                  unsigned long long dwl_bytes;   /* total of bytes to be downloaded */
                  unsigned int    nsteps;         /* No. total of steps */
                  unsigned int    cur_step;       /* Current step index */
                  unsigned int    cur_percent;    /* % in current step */
                  char            cur_image[256]; /* Name of image to be installed */
                  char            hnd_name[64];   /* Name of running handler */
                  sourcetype      source;         /* Interface that triggered the update */
                  unsigned int    infolen;        /* Len of data valid in info */
                  char            info[2048];     /* additional information about install */
          };

       The single fields have the following meaning:

          • magic is not yet used, it could be added for simply verification of the frame.

          • status is one of the values in swupdate_status.h (START, RUN, SUCCESS, FAILURE, DOWNLOAD, DONE).

          • dwl_percent is the percentage of downloaded data when status = DOWNLOAD.

          • dwl_bytes is the total number of bytes that are to be downloaded.

          • nsteps is the total number of installers (handlers) to be run.

          • cur_step is the index of the running handler. cur_step is in the range 1..nsteps

          • cur_percent  is the percentage of work done inside the current handler. This is useful when updating
            a slow interface, such as a slow flash, and signals which is the percentage of image already  copied
            into the destination.

          • cur_image is the name of the image in sw-description that is currently being installed.

          • hnd_name reports the name of the running handler.

          • source is the interface that triggered the update.

          • infolen length of data in the following info field.

          • info additional information about installation.

       As  an  example  for  a  progress  client, tools/swupdate-progress.c prints the status on the console and
       drives "psplash" to draw a progress bar on a display.

LANGUAGE BINDINGS

   Overview
       In general, SWUpdate is agnostic to a particular language it  is  operated  from,  thanks  to  SWUpdate's
       socket-based control <> and progress APIs <> for external programs. As long as the language of choice has
       proper socket (library) support, SWUpdate can be operated with it.

       However,   for   convenience,   a   Lua  language  binding  in  terms  of  a  shared  library,  currently
       lua_swupdate.so.0.1, is provided.

   Lua Language Binding
       The Lua language binding is realized in terms of the lua_swupdate module  that  defines  three  bindings,
       namely  for  the  control  interface, the progress interface, and a convenience function yielding a table
       holding all local network interfaces including their IP addresses and submasks.

       The lua_swupdate Lua module interface specification that details what functionality is made available  by
       bindings/lua_swupdate.c  is found in bindings/lua_swupdate.lua, reproduced for convenience in Section Lua
       Language Binding Interface Specification.  It  serves  as  reference,  for  mocking  purposes,  and  type
       checking thanks to the EmmyLua-inspired annotations.

       Note  that, depending on the filesystem location of the Lua binding's shared library, Lua's package.cpath
       may have to be adapted by setting the environment variable LUA_CPATH, modifying package.cpath prior to  a
       require('lua_swupdate'), or , as last resort, using package.loadlib() instead of require('lua_swupdate').

   Control Interface
       The  lua_swupdate  module's  control interface binding conveniently makes SWUpdate's socket-based control
       API <> available to pure Lua.

       The binding is captured in the swupdate_control object that is returned by a call to  swupdate.control().
       This object offers the three methods connect(), write(<chunkdata>), and close():

       The  connect()  method  initializes  the  connection to SWUpdate's control socket, sends REQ_INSTALL, and
       waits for ACK or NACK, returning the socket connection file descriptor, mostly for information  purposes,
       or, in case of an error, nil plus an error message.

       The  artifact's  data can then be sent to SWUpdate via the write(<chunkdata>) method, returning true, or,
       in case of errors, nil plus an error message.

       Finally, the close() method closes the connection to SWUpdate's control socket after which it  waits  for
       SWUpdate to complete the update transaction and executes the post-install command, if given.

       The following example snippet illustrates how to use the control interface binding:

          local artifact = io.open("/some/path/to/artifact.swu", "rb" )
          swupdate = require('lua_swupdate')
          local ctrl = swupdate.control()
          if not ctrl:connect() then
                  -- Deliberately neglecting error message.
                  io.stderr:write("Error connecting to SWUpdate control socket.\n")
                  return
          end

          while true do
                  local chunk = artifact:read(1024)
                  if not chunk then break end
                  if not ctrl:write(chunk) then
                          -- Deliberately neglecting error message.
                          io.stderr:write("Error writing to SWUpdate control socket.\n")
                          break
                  end
          end

          local res, msg = ctrl:close()
          if not res then
                  io.stderr:write(string.format("Error finalizing update: %s\n", msg))
          end

   Progress Interface
       The  lua_swupdate module's progress interface binding conveniently makes SWUpdate's socket-based progress
       API <> available to pure Lua.

       The  binding  is  captured  in  the  swupdate_progress  object  that   is   returned   by   a   call   to
       swupdate.progress(). This object offers the three methods connect(), receive(), and close():

       The  connect()  method  connects  to  SWUpdate's  progress  socket, waiting until the connection has been
       established. Note that it is only really required to explicitly call connect() to  reestablish  a  broken
       connection as the swupdate_progress object's instantiation already initiates the connection.

       The  receive() method returns a table representation of the struct progress_msg described in the progress
       interface's API description <>.

       The close() method deliberately closes the connection to SWUpdate's progress socket.

   IPv4 Interface
       For convenience, the lua_swupdate module provides the ipv4() method returning a table holding  the  local
       network  interfaces  as  the  table's  keys  and  their space-separated IP addresses plus subnet masks as
       respective values.

   Lua Language Binding Interface Specification
          --[[

              SWUpdate IPC Lua Module Interface.

              Interface specification for the Lua IPC module.
              See: bindings/lua_swupdate.c

              Copyright (C) 2022, Siemens AG
              Author: Christian Storm <christian.storm@siemens.com>

              SPDX-License-Identifier: GPL-2.0-or-later

          --]]

          ---@diagnostic disable: missing-return
          ---@diagnostic disable: unused-local
          -- luacheck: no unused args

          --- SWUpdate IPC Lua Module.
          --- @class lua_swupdate
          local lua_swupdate = {}

          --- Get local IPv4 network interface(s) information.
          --
          -- The returned Table contains the network interface names
          -- as keys and a space-separated IP address and subnet mask
          -- as values, e.g., {['eth0']="192.168.1.1 255.255.255.0"}.
          --
          --- @return table<string, string>
          lua_swupdate.ipv4 = function() end

          --- @enum lua_swupdate.RECOVERY_STATUS
          --- Lua equivalent of `RECOVERY_STATUS` as in `include/swupdate_status.h`.
          lua_swupdate.RECOVERY_STATUS = {
              IDLE       = 0,
              START      = 1,
              RUN        = 2,
              SUCCESS    = 3,
              FAILURE    = 4,
              DOWNLOAD   = 5,
              DONE       = 6,
              SUBPROCESS = 7,
              PROGRESS   = 8
          }

          --- @enum lua_swupdate.sourcetype
          --- Lua equivalent of `sourcetype` as in `include/swupdate_status.h`.
          lua_swupdate.sourcetype = {
              SOURCE_UNKNOWN           = 0,
              SOURCE_WEBSERVER         = 1,
              SOURCE_SURICATTA         = 2,
              SOURCE_DOWNLOADER        = 3,
              SOURCE_LOCAL             = 4,
              SOURCE_CHUNKS_DOWNLOADER = 5
          }

          --- Lua equivalent of `struct progress_msg` as in `include/progress_ipc.h`.
          --- @class lua_swupdate.progress_msg
          --- @field status    lua_swupdate.RECOVERY_STATUS  Update status, one of `lua_swupdate.RECOVERY_STATUS`'s values
          --- @field download  number  Downloaded data percentage
          --- @field source    lua_swupdate.sourcetype  Interface that triggered the update, one of `lua_swupdate.sourcetype`'s values
          --- @field nsteps    number  Total number of steps
          --- @field step      number  Current step
          --- @field percent   number  Percentage done in current step
          --- @field artifact  string  Name of image to be installed
          --- @field handler   string  Name of running Handler
          --- @field info      string  Additional information about installation

          --- SWUpdate progress socket binding.
          --
          -- The returned Class Table contains methods to
          -- interact with SWUpdate's progress socket.
          --
          lua_swupdate.progress = function()
              return {
                  --- Connect to SWUpdate's progress socket.
                  --
                  --- @param  self  table   This `lua_swupdate.progress` instance
                  --- @return number | nil  # The connection handle or nil in case of error
                  --- @return nil | string  # nil or an error message in case of error
                  connect = function(self) end,

                  --- Receive data from SWUpdate's progress socket.
                  --
                  --- @param  self  table                        This `lua_swupdate.progress` instance
                  --- @return table | lua_swupdate.progress_msg  # This `lua_swupdate.progress` instance on error or the received progress message
                  --- @return nil                                # nil in case of error
                  receive = function(self) end,

                  --- Close connection to SWUpdate's progress socket.
                  --
                  --- @param  self  table  This `lua_swupdate.progress` instance
                  --- @return table        # This `lua_swupdate.progress` instance
                  close = function(self) end,
              }
          end

          --- SWUpdate control socket binding.
          --
          -- The returned Class Table contains methods to
          -- interact with SWUpdate's control socket.
          --
          lua_swupdate.control = function()
              return {
                  --- Connect to SWUpdate's control socket.
                  --
                  --- @param  self  table   This `lua_swupdate.control` instance
                  --- @return number | nil  # Connection handle or nil in case of error
                  --- @return nil | string  # nil or an error message in case of error
                  connect = function(self) end,

                  --- Write to connected SWUpdate control socket.
                  --
                  --- @param  self  table    This `lua_swupdate.control` instance
                  --- @param  data  string   Chunk data to write to SWUpdate's control socket
                  --- @return boolean | nil  # true or nil in case of error
                  --- @return nil | string   # nil or an error message in case of error
                  write = function(self, data) end,

                  --- Close connection to SWUpdate's control socket.
                  --
                  --- @param  self  table    This `lua_swupdate.control` instance
                  --- @return boolean | nil  # true or nil in case of error
                  --- @return nil | string   # nil or an error message in case of error
                  close = function(self) end,
              }
          end

          return lua_swupdate

BOOTLOADER INTERFACE

   Overview
       SWUpdate has bindings to various bootloaders in  order  to  store  persistent  state  information  across
       reboots. Currently, the following bootloaders are supported:

       • A fake bootloader called "Environment in RAM",

       • EFI Boot Guard <https://github.com/siemens/efibootguard>,

       • U-Boot <https://www.denx.de/wiki/U-Boot>, and

       • GRUB <https://www.gnu.org/software/grub/>.

       The  actual (sub)set of bootloaders supported is a compile-time choice. At run-time, the compile-time set
       default bootloader interface implementation is used unless overruled to use another bootloader  interface
       implementation  via the -B command line switch or a configuration file (via the bootloader setting in the
       globals section, see examples/configuration/swupdate.cfg).

       Note that the run-time support for some bootloaders, currently U-Boot  and  EFI  Boot  Guard,  relies  on
       loading  the  respective bootloader's environment modification shared library at run-time. Hence, even if
       support for a particular bootloader is compiled-in, the according shared  library  must  be  present  and
       loadable  on  the  target  system  at  run-time for using this bootloader interface implementation.  This
       allows, e.g., distributions to ship a generic SWUpdate package and downstream integrators to combine this
       generic package with the appropriate bootloader by just providing  its  environment  modification  shared
       library.

   Bootloader Interface Description
       The  bootloader  interface  implementations are located in bootloader/.  Each bootloader has to implement
       the interface functions as defined in include/bootloader.h, more precisely

          char *env_get(const char *name);
          int env_set(const char *name, const char *value);
          int env_unset(const char *name);
          int apply_list(const char *filename);

       which retrieve a key's value from the bootloader environment, set a key to  a  value  in  the  bootloader
       environment, delete a key-value pair from the bootloader environment, and apply the key=value pairs found
       in a file.

       Then,  each bootloader interface implementation has to register itself to SWUpdate at run-time by calling
       the register_bootloader(const char *name, bootloader *bl) function that takes the bootloader's name and a
       pointer to struct bootloader as in include/bootloader.h which is filled with pointers to  the  respective
       above  mentioned  interface functions.  If the bootloader setup fails and hence it cannot be successfully
       registered, e.g., because the required shared library for environment modification cannot be loaded, NULL
       is to be returned as pointer to struct bootloader.

       For example, assuming a  bootloader  named  "trunk"  and  (static)  interface  functions  implementations
       do_env_{get,set,unset}()  as  well as do_apply_list() in a bootloader/trunk.c file, the following snippet
       registers this bootloader to SWUpdate at run-time:

          static bootloader trunk = {
              .env_get = &do_env_get,
              .env_set = &do_env_set,
              .env_unset = &do_env_unset,
              .apply_list = &do_apply_list
          };

          __attribute__((constructor))
          static void trunk_probe(void)
          {
              (void)register_bootloader(BOOTLOADER_TRUNK, &trunk);
          }

       with

          #define BOOTLOADER_TRUNK "trunk"

       added to  include/bootloader.h  as  a  single  central  "trunk"  bootloader  name  definition  aiding  in
       maintaining  the uniqueness of bootloader names.  This new "trunk" bootloader should also be added to the
       Suricatta Lua Module interface specification's bootloader Table suricatta.bootloader.bootloaders = {  ...
       } in suricatta/suricatta.lua.

       Attention:
          Take care to uniquely name the bootloader.

       See,  e.g., bootloader/{uboot,ebg}.c for examples of a bootloader using a shared environment modification
       library and bootloader/{grub,none}.c for a simpler bootloader support example.

   Bootloader Build System Integration
       A bootloader support implementation needs to be registered to the kconfig build system.

       First, the bootloader support implementation, named "trunk" and  implemented  in  bootloader/trunk.c  for
       example, needs to be added to bootloader/Kconfig in the Bootloader Interfaces menu as follows:

          ...

          menu "Bootloader"

          menu "Bootloader Interfaces"

          ...

          config BOOTLOADER_TRUNK
              bool "TrUnK Bootloader"
              help
                Support for the TrUnK Bootloader
                https://github.com/knurt/trunk

       Then,  in  order to enable the compile-time selection of the "trunk" bootloader as default, add a section
       to the Default Bootloader Interface choice submenu of the Bootloader menu as follows:

          choice
              prompt "Default Bootloader Interface"
              help
                Default bootloader interface to use if not explicitly
                overridden via configuration or command-line option
                at run-time.

          ...

          config BOOTLOADER_DEFAULT_TRUNK
              bool "TrUnK"
              depends on BOOTLOADER_TRUNK
              help
                Use TrUnK as default bootloader interface.

       Finally, bootloader/Makefile needs to be adapted to build the  "trunk"  bootloader  support  code,  given
       BOOTLOADER_TRUNK was enabled:

          obj-$(CONFIG_BOOTLOADER_TRUNK) += trunk.o

       If  the "trunk" bootloader, for example, requires loading a shared environment modification library, then
       Makefile.flags needs to be adapted as well, e.g., as follows:

          ifeq ($(CONFIG_BOOTLOADER_TUNK),y)
          LDLIBS += dl
          endif

META-SWUPDATE: BUILDING WITH YOCTO

   Overview
       The Yocto-Project <http://www.yoctoproject.org> is a community project under the umbrella  of  the  Linux
       Foundation  that  provides  tools and template to create the own custom Linux-based software for embedded
       systems.

       Add-on features can be added using layers. meta-swupdate <https://github.com/sbabic/meta-swupdate.git> is
       the layer to cross-compile the SWUpdate application and to generate the compound  SWU  images  containing
       the release of the product.  It contains the required changes for mtd-utils and for generating Lua. Using
       meta-SWUpdate  is  a  straightforward  process.  As  described in Yocto's documentation about layers, you
       should include it in your bblayers.conf file to use it.

       Add meta-SWUpdate as usual to your bblayers.conf. You have also to add meta-oe to the list.

       In meta-SWUpdate there is a recipe to generate an initrd with a rescue system with SWUpdate. Use:

          MACHINE=<your machine> bitbake swupdate-image

       You will find the result in your tmp/deploy/<your machine> directory.  How to install and start an initrd
       is very target specific - please check in the documentation of your bootloader.

   What about libubootenv ?
       This is a common issue when SWUpdate is built. SWUpdate depends on this library, that is  generated  from
       the  U-Boot's  sources. This library allows one to safe modify the U-Boot environment. It is not required
       if U-Boot is not used as bootloader.  If SWUpdate cannot be linked, you  are  using  an  old  version  of
       U-Boot  (you  need  at  least  2016.05). If this is the case, you can add your own recipe for the package
       u-boot-fw-utils, adding the code for the library.

       It is important that the package u-boot-fw-utils is built with the same sources of the bootloader and for
       the same machine. In fact, the target can have a default environment linked together with U-Boot's  code,
       and it is not (yet) stored into a storage. SWUpdate should be aware of it, because it cannot read it: the
       default environment must be linked as well to SWUpdate's code. This is done inside the libubootenv.

       If  you  build  for a different machine, SWUpdate will destroy the environment when it tries to change it
       the first time. In fact, a wrong default environment is taken, and your board won't boot again.

       To avoid possible mismatch, a new library was developed to be hardware independent.  A strict match  with
       the bootloader is not required anymore. The meta-swupdate layer contains recipes to build the new library
       (libubootenv) and adjust SWUpdate to be linked against it. To use it as replacement for u-boot-fw-utils:

          • set PREFERRED_PROVIDER_u-boot-fw-utils = "libubootenv"

          • add to SWUpdate config:

          CONFIG_UBOOT=y

       With  this  library,  you  can  simply  pass the default environment as file (u-boot-initial-env).  It is
       recommended for new project to switch to the new library to become independent from the bootloader.

   The swupdate class
       meta-swupdate contains a class specific for SWUpdate. It helps to generate the SWU  image  starting  from
       images built inside the Yocto. It requires that all components, that means the artifacts that are part of
       the  SWU  image,  are present in the Yocto's deploy directory.  This class should be inherited by recipes
       generating the SWU. The class defines new variables, all of them have the prefix SWUPDATE_ in the name.

       • SWUPDATE_IMAGES : this is a list of the artifacts to be packaged together.  The list contains the  name
         of images without any extension for MACHINE or filetype, that are added automatically.  Example :

          SWUPDATE_IMAGES = "core-image-full-cmdline uImage"

       • SWUPDATE_IMAGES_FSTYPES  :  extension  of  the  artifact.  Each  artifact  can  have multiple extension
         according to the IMAGE_FSTYPES variable.  For example, an image can be  generated  as  tarball  and  as
         UBIFS  for  target.   Setting  the variable for each artifact tells the class which file must be packed
         into the SWU image.

          SWUPDATE_IMAGES_FSTYPES[core-image-full-cmdline] = ".ubifs"

       • SWUPDATE_IMAGES_NOAPPEND_MACHINE : flag to use drop the machine  name  from  the  artifact  file.  Most
         images in deploy have the name of the Yocto's machine in the filename. The class adds automatically the
         name of the MACHINE to the file, but some artifacts can be deployed without it.

          SWUPDATE_IMAGES_NOAPPEND_MACHINE[my-image] = "1"

       • SWUPDATE_SIGNING  : if set, the SWU is signed. There are 3 allowed values: RSA, CMS, CUSTOM. This value
         determines used signing mechanism.

       • SWUPDATE_SIGN_TOOL : instead of using openssl, use SWUPDATE_SIGN_TOOL to sign the image. A typical  use
         case is together with a hardware key. It is available if SWUPDATE_SIGNING is set to CUSTOM

       • SWUPDATE_PRIVATE_KEY  :  this  is  the  file  with  the  private  key  used to sign the image using RSA
         mechanism. Is available if SWUPDATE_SIGNING is set to RSA.

       • SWUPDATE_PASSWORD_FILE : an optional file containing the password for the private key. It is  available
         if SWUPDATE_SIGNING is set to RSA.

       • SWUPDATE_CMS_KEY  :  this is the file with the private key used in signing process using CMS mechanism.
         It is available if SWUPDATE_SIGNING is set to CMS.

       • SWUPDATE_CMS_CERT : this is the file with the certificate used in signing process using CMS method.  It
         is available if SWUPDATE_SIGNING is set to CMS.

       • SWUPDATE_AES_FILE  :  this  is  the  file  with  the  AES password to encrypt artifact. A new fstype is
         supported by the class (type: enc). SWUPDATE_AES_FILE is generated as output from openssl to  create  a
         new key with

            openssl enc -aes-256-cbc -k <PASSPHRASE> -P -md sha1 -nosalt > $SWUPDATE_AES_FILE

         To use it, it is enough to add IMAGE_FSTYPES += "enc" to the  artifact. SWUpdate supports decryption of
         compressed artifact, such as

            IMAGE_FSTYPES += ".ext4.gz.enc"

   Automatic sha256 in sw-description
       The  swupdate  class  takes care of computing and inserting sha256 hashes in the sw-description file. The
       attribute sha256 must be set in case the image is signed. Each artifact must have the attribute:

          sha256 = "$swupdate_get_sha256(artifact-file-name)"

       For example, to add sha256 to the standard Yocto core-image-full-cmdline:

          sha256 = "$swupdate_get_sha256(core-image-full-cmdline-machine.ubifs)";

       The name of the file must be the same as in deploy directory.

   BitBake variable expansion in sw-description
       To insert the value of a BitBake variable into the update file, pre- and postfix the variable  name  with
       "@@".  For example, to automatically set the version tag:

          version = "@@DISTRO_VERSION@@";

   Automatic versions in sw-description
       By setting the version tag in the update file to $swupdate_get_pkgvar(<package-name>) it is automatically
       replaced  with  PV  from  BitBake's  package-data-file  for the package matching the name of the provided
       <package-name> tag.  For example, to set the version tag to PV of package u-boot:

          version = "$swupdate_get_pkgvar(u-boot)";

       To automatically insert the value of a variable from BitBake's package-data-file different  to  PV  (e.g.
       PKGV)        you       can       append       the       variable       name       to       the       tag:
       $swupdate_get_pkgvar(<package-name>@<package-data-variable>) For example, to set the version tag to  PKGV
       of package u-boot:

          version = "$swupdate_get_pkgvar(u-boot@PKGV)";

   Using checksum for version
       It  is  possible  to  use  the hash of an artifact as the version in order to use "install-if-different".
       This allows versionless artifacts to be skipped if the artifact  in  the  update  matches  the  currently
       installed artifact.

       In  order  to  use the hash as the version, the sha256 hash file placeholder described above in Automatic
       sha256 in sw-description must be used for version.

       Each artifact must have the attribute:

          version = "@artifact-file-name"

       The name of the file must be the same as in deploy directory.

   Template for recipe using the class
          DESCRIPTION = "Example recipe generating SWU image"
          SECTION = ""

          LICENSE = ""

          # Add all local files to be added to the SWU
          # sw-description must always be in the list.
          # You can extend with scripts or whatever you need
          SRC_URI = " \
              file://sw-description \
              "

          # images to build before building swupdate image
          IMAGE_DEPENDS = "core-image-full-cmdline virtual/kernel"

          # images and files that will be included in the .swu image
          SWUPDATE_IMAGES = "core-image-full-cmdline uImage"

          # a deployable image can have multiple format, choose one
          SWUPDATE_IMAGES_FSTYPES[core-image-full-cmdline] = ".ubifs"
          SWUPDATE_IMAGES_FSTYPES[uImage] = ".bin"

          inherit swupdate

   Simplified version for just image
       In many cases there is a single image in the SWU. This is for example when just rootfs  is  updated.  The
       generic  case described above required an additional recipe that must be written and maintained. For this
       reason, a simplified version of the class is introduced that allowed to build  the  SWU  from  the  image
       recipe.

       Users  just  need to import the swupdate-image class. This already sets some variables.  A sw-description
       must still be added into a files directory, that is automatically searched  by  the  class.   User  still
       needs  to  set  SWUPDATE_IMAGE_FSTYPES[your  image] to the fstype that should be packed into the SWU - an
       error is raised if the flag is not set.

       In the simple way, your recipe looks like

          <your original recipe code>

          SWUPDATE_IMAGES_FSTYPES[<name of your image>] = <fstype to be put into SWU>
          inherit swupdate-image

   SWU image content's encryption
       The swupdate class is able to encrypt the contents of the SWU image. In order to do so first  check  that
       SWUpdate  is compiled with CONFIG_ENCRYPTED_IMAGES=y enabled. Then set SWUPDATE_AES_FILE to the full path
       of the key. Finally, for each content you want to encrypt, on your SWU image recipe add:

          SWUPDATE_IMAGES_ENCRYPTED[content] = "1"

       Where content matches the files described on sw-description.

       If   you   want   to   encrypt   sw-description   check   that   SWUpdate   is   being   compiled    with
       CONFIG_ENCRYPTED_SW_DESCRIPTION=y and then set the following on your SWU image recipe:

          SWUPDATE_ENCRYPT_SWDESC = "1"

       Do  not  forget  to  add  encrypted  =  true; on each of the contents that will require decryption on the
       sw-description file.

       Expanding on the previous example:

          DESCRIPTION = "Example recipe generating SWU image"
          SECTION = ""

          LICENSE = ""

          # Add all local files to be added to the SWU
          # sw-description must always be in the list.
          # You can extend with scripts or whatever you need
          SRC_URI = " \
              file://sw-description \
              "

          # images to build before building swupdate image
          IMAGE_DEPENDS = "core-image-full-cmdline virtual/kernel"

          # images and files that will be included in the .swu image
          SWUPDATE_IMAGES = "core-image-full-cmdline uImage"

          # a deployable image can have multiple format, choose one
          SWUPDATE_IMAGES_FSTYPES[core-image-full-cmdline] = ".ubifs"
          SWUPDATE_IMAGES_FSTYPES[uImage] = ".bin"

          SWUPDATE_IMAGES_ENCRYPTED[core-image-full-cmdline.ubifs] = "1"
          SWUPDATE_IMAGES_ENCRYPTED[uImage] = "1"
          SWUPDATE_ENCRYPT_SWDESC = "1"

          inherit swupdate

   What about grub ?
       In order to use swupdate with grub, swupdate needs to be configured to use grub. Some of  the  imporatant
       configurations  are  CONFIG_GRUBENV_PATH="/path/to/grubenv",  where "/path/to/grubenv" is thepath to grub
       environment.  Example: "/boot/EFI/BOOT/grubenv".

       The grubenv file should be created using grub-editenv tool, because it is a  1024-byte  file,  therefore,
       any modification using nano or vim will only corrupt the file, and grub will not be able to use it.

       You can create a grubenv file using these commands for instance:

          GRUBENV="/path/to/grubenv"
          grub-editenv $GRUBENV create
          grub-editenv $GRUBENV set rootfs=2
          grub-editenv $GRUBENV set kernel=2

       grub-editenv is a tool that is integrated to yocto.

       When  the  grubenv file is created, grub should be configured to use it.  This configuration should be in
       the configuration file grub.cfg.  Here is an example of grub.cfg that loads the environment  file  before
       booting:

          # Take a kernel and a rootfs by default in case grubenv is corrupted
          rootfs=1
          kernel=1
          serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
          default=boot
          # set timeout to zero to boot without timeout
          timeout=0
          # load grubenv the environment file that contains the value of rootfs and kernel variables
          load_env -f "/path/to/grubenv"
          # detect which memory contains 5 partitions
          for i in 1 2 3 4 5; do  if [ -d (hd${i},gpt5)/ ]; then drive=${i};fi ; done
          # detect which rootfs should we boot with
          if [ ${rootfs} = "1" ]; then rootfs_part=4 ; elif [ ${rootfs} = "2" ]; then rootfs_part=5 ; fi
          # detect which kernel should we boot with
          if [ ${kernel} = "1" ]; then kernel_part="(hd${drive},gpt2)" ; elif [ ${kernel} = "2" ]; then kernel_part="(hd${drive},gpt3)" ; fi

          # The menuentry that is used to boot (more can be added if it is wanted)
          menuentry 'boot'{
          linux ${kernel_part}/bzImage root=/dev/mmcblk1p${rootfs_part} rw rootwait quiet console=ttyS2,115200 console=tty0 panic=5
          }

       The  grub.cfg  above  is merely an example, and can be modified as the user wants to, as long as it loads
       the environment variables,and it boots correctly using these environment variables.

SWUPDATE BEST PRACTICE

       This is intended as general rule to integrate SWUpdate into a custom project.

       SWUpdate is an update agent and it is thought to be a framework. This means it is highly configurable and
       SWUpdate should be configured to fit  into  a  project,  not  vice  versa.  SWUpdate  makes  just  a  few
       requirements  on  the  system  and  it  has  no fixed update schema.  There is no restriction on how many
       partitions or which storage you are using.  In some more complex cases, the update depends on  a  lot  of
       conditions,  and  SWUpdate can run differently according to the mode a device is started in.  Think about
       SWUpdate not being a ready-to-use updater but a framework, and hence you should first write a meaningful:

   Update Concept
       Take your time and write first an update concept for your device.  It is not wasted time.   You  have  to
       imagine  conditions when an update is not working, and try to write down the use cases when an update can
       fail and how the device can be restored.  SWUpdate installs new software, but a successful  update  means
       that  the new software is started and runs flawlessly. The interface with the bootloader (or the one that
       starts the software) must be checked in details.  A successful update means:

       • SWUpdate runs successfully,

       • the device reboots,

       • the bootloader can start the new software, and

       • the new software runs, makes some consistency checks, and declares that the transaction (that  is  from
         old to new software) is terminated.

       This  means  that  some  coordination  between the bootloader and the update agent is necessary.  In most
       cases, this is done via persistent variables that are available to  both  SWUpdate  and  the  bootloader.
       SWUpdate has two built-in variables:

       • recovery_status:  this  is  set  when SWUpdate starts to write to the device, and it is unset after the
         installation completed with success or it is set to failed in case of error. A bootloader can use it to
         check if an update was interrupted.  This is a must in case a single copy of the  software  is  on  the
         device.

       • ustate: this triggers a state machine. SWUpdate sets it to 1 (INSTALL) after an update.  The bootloader
         can  use  it to check whether a new software must be tested.  The bootloader should implement a counter
         mechanism to check how many times it tried to start a new software. When a threshold  is  reached,  the
         bootloader  should  declare  the  new  software  as  buggy, and proceed with a fallback in case the old
         software is available.

       A fallback is always initiated by the bootloader, because it knows if the new  software  is  running.  It
       should  toggle  the  copies  and  start  the  old software set.  To communicate this to user space and to
       SWUpdate, the bootloader sets the ustate variable to 3 (FAILED). SWUpdate uses this information  in  case
       the  result  must  be  forwarded  to  an external server (like a backend).  There is a time window when a
       fallback can take place. In fact, after a reboot and some attempts, the update  transaction  is  declared
       successful  or failed, and later a new update can be executed.  When a new update runs, the status of the
       stand-by copy is unknown, because it could be the result of an interrupted update. Running an  incomplete
       software can lead to unpredictable results and must be strongly avoided.  A common pattern for a toggling
       in the bootloader is:

       • ustate  is  not  set or set to 0 (no update pending). The bootloader runs the configured copy and won't
         ever toggle. In case of failure, a rescue system can be started if available.

       • ustate is set to  1 (INSTALLED): the new software is under test. The bootloader initiates a fallback if
         the new software is not running and sets ustate to 3 (FAILED). If the new software runs, it is the duty
         of user space (often SWUpdate or the init script  for  SWUpdate)  to  reset  ustate  to  0.  Note  that
         resetting  the  variable  is  project  specific,  and  it  could  be  set  as  last action after having
         sufficiently checked that the new software is running. This includes performing in  the  application  a
         database migration, starting communicating with peers, whatever.

       A  possible  diagram is shown in next picture - it is not supposed to work with any project, but it gives
       an idea how fallback is working together with the bootloaders.  [image]

       Check in advance which security topics are relevant for your project. This includes:

       • signed images (SWU is verified before installing), and then which crypto mechanism is used  (RSA  keys,
         certificates, PKI)

       • encryption for artifacts

       • under  which user and group SWUpdate and other components are allowed to run.  Set user id and group id
         if not root in swupdate.cfg.

       • if any version can be installed or if you forbid a downgrade, and then be sure to  pass  the  range  of
         versions you allow via --M, -R and --max-version.

       • hardware-software compatibility check and how your device knows which hardware revision is running.

   Reduce dependencies to minimum
       An  update  should  be possible in any condition. Even if the system is degraded or in a bad shape, if an
       update can work, the device can be functional again without returning it back to the  factory.   SWUpdate
       is  thought  to  be  self contained: that means it does not make use of external tools. If your system is
       degraded and filesystems get corrupted, there are less chances to restore it if the update calls external
       tools. SWUpdate is started at boot time and there are good chances it succeeds even if  your  system  has
       some  (software)  flaws.  Be careful to make an update depending on your application or try to reduce the
       dependencies.  In fact, the application is updated often and an introduction of new  bugs  can  make  the
       device  no  longer  updatable. Take the dependencies under control, and if you have any, be sure that the
       update is still working. You can fix any bugs if the update works, but not anymore if the  device  cannot
       be updated.

   Make a risk analysis
       A  more  accurate analysis brings less surprises in the field. Think twice about what you want to update,
       which components should be updated, and the risks of updating a single point  of  failure.   Very  often,
       this  means  the  bootloader.  Compare  risks  and  benefits: it happens in many projects that having the
       possibility (with some risk) to update the bootloader is  better  that  returning  the  devices  back  to
       service. A cost / benefits analysis should be part of the integration of the update agent.

   SWUpdate builtin configuration
       SWUpdate  has a compile time configuration. The default configuration delivered with meta-swupdate is not
       suitable for most projects. The easy way to check configuration in Yocto is to run:

          bitbake -c menuconfig swupdate

       Outside Yocto, just run in SWUpdate's sources:

          make menuconfig

       Check security, bootloader, and which handlers should be installed. They depend strongly on your project.
       If you build with  OE,  add  a  swupdate_%.bbappend  to  one  of  your  layers,  and  put  the  resulting
       configuration file as defconfig that can be fetched.  Please review the following configuration:

       • Security settings

       • Interfaces required (where the software is coming from). Disable the interface you do not need.

       • Handlers  required  for your project. Disable what you do not need, but consider if you could need some
         of them in future. As example, you can safely disable ubivol if you do not use raw NAND,  but  you  can
         let archive enabled if you plan to install artifacts from tarballs in future.

       • It is highly recommended to enable Lua to extend runtime behavior.

   SWUpdate startup
       An  easy  way  to  start  SWUpdate  is provided only with meta-swupdate and Yocto. A generic SystemV init
       script or a systemd unit for SWUpdate are executing a script swupdate.sh, that is delivered together with
       the SWUpdate binaries.  The script goes through /etc/swupdate/conf.d/ and sources all  found  files.  The
       integrator can use a set of predefined variables to configure SWUpdate's command line parameters.

       • SWUPDATE_WEBSERVER_ARGS  :  This  string is passed if the webserver must be started. It consists of the
         webserver specific parameters. If this variable is  set,  the  script  will  add  -w  to  the  list  of
         parameters.   Note:  meta-swupdate  contains  a default configuration for SWUPDATE_WEBSERVER_ARGS, that
         uses /www as document root for the Website and default port 8080.

       • SWUPDATE_SURICATTA_ARGS : Suricatta (backend) specific parameters. There is no default.

       • SWUPDATE_ARGS : Parameters not belonging to Webserver or Suricatta.

       Note that swupdate.sh sources the files in sorted order, so it is possible to override the variables with
       a configuration file whose filename is loaded at the end. Preferred style is to use SystemV  like  names,
       for example 10-webserver, 11-suricatta, and so on.

   Write sw-description
       sw-description  is  the  central  file  that  describes  a new software release and how a release must be
       installed.  It should be a consequence of the update concept. There is not a single right  way.  SWUpdate
       heavily  uses  'selections'  and  links to extract just one part of the whole sw-description, that can be
       used for different situations and different ways to run the device. One use case  for  selections  is  to
       implement  the  dual-copy  (often  referred  to as A/B) mode: one selection contains instructions for one
       copy, the other for the second copy. Which copy is the stand-by must be detected before running  SWUpdate
       and  passed via the -e <selection,mode> switch.  Other methods set up a link to the standby storage (like
       /dev/standby) during boot. Or the standby device can be detected at runtime with an  embedded-script,  as
       part  of  sw-description,  with  Lua code.  Please note that for the last case, SWUpdate is extended with
       functions exported to the Lua context that simplify the detection. SWUpdate exports a getroot()  function
       that returns type and value for the device used as rootfs. See SWUpdate documentation for a complete list
       of functions exported by SWUpdate that can be used in Lua. An embedded Lua script must just start with

          require ('swupdate')

       to make use of them.

   Use OE variables as much as possible
       meta-swupdate  replaces  a  special  construct in sw-description with the values of build variables.  The
       recognized construct in sw-description is delimited by @@, that is @@VARIABLE-NAME@@.  The exception (for
       compatibility reasons) is the automatic generation of sha256. The syntax in that case is :

          sha256 = "$swupdate_get_sha256(<name of artifact>)"

       You can again use variable substitution for artifact names. Example:

          sha256 = "$swupdate_get_sha256(@@SYSTEM_IMAGE@@-@@MACHINE@@@@SWUPDATE_IMAGES_FSTYPES[@@SYSTEM_IMAGE@@]@@)";

       Please note that each variable is double delimited (at the beginning and at the end) by @@.

   Deliver your scripts instead of relying on them being installed
       You have the freedom to call any tools during an update. However, take care if you are using  some  tools
       from the running rootfs / current software. This implies that the current software is running flawlessly,
       as well as the tools you are calling. And this may not always be the case.

   Prefer Lua to shell scripts
       Shell  scripts  are very popular, and they are often used even when they are not strictly required.  They
       can raise security issues. In fact, take as example a simple shell script. Goal of rootkits is often  the
       shell,  because  taking  control  of  the  shell  means  to  control  the  whole  device. If the shell is
       compromised, the whole system is compromised.  Running a shell script means  that  SWUpdate  should  call
       "fork"  followed  by  an "exec". This means also that many resources are duplicated in the child process,
       and it could cause a further problem if system is getting rid of resources.  A better approach is to  use
       Lua  and  to  deliver  the scripts inside the SWU. In fact, the Lua interpreter is linked to SWUpdate and
       runs in context of the SWUpdate process without forking a child process. Shell is not involved at all. Of
       course, Lua scripts should be written to be self-contained, too, and executing external tools  should  be
       done only if unavoidable.

   Use installed-directly when possible
       SWUpdate  can  be  enabled for zero-copy (or streaming mode), that is the incoming SWU is analyzed on the
       fly and it is installed by the associated handler without  any  temporary  copy.  If  this  is  not  set,
       SWUpdate  creates  a  temporary  copy  in  $TMPDIR  before  passing it to the handlers. Note that $TMPDIR
       generally points to a RAMDISK and storing files there reduces the amount  of  memory  available  for  the
       application.   It  makes  sense to disable the flag in case the artifact is a single point of failure.  A
       typical example could be the bootloader (not duplicated on the devices), and if the SWU is  corrupted  or
       the  connection  gets  broken,  the board is left in a bricked state. It makes sense then to download the
       whole artifact before installing.

   Always enable sha256 verification
       The SWU image is a CPIO archive with CRC (new ASCII format), but the check in CPIO is very weak.  Do  not
       trust it, but enable sha256 for each artifact.

   Always set the "type" attribute
       SWUpdate  sets  some  default  handler if the type is not set. Do not use it, but set explicitly the type
       (that is, which handler should install the artifact) in sw-description.

   Do not rely on install order
       SWUpdate does not require that artifacts are put into the CPIO in a  specific  order.  The  exception  is
       sw-description,  that  must  be  the  first  file in a SWU. Avoid dependencies inside the SWU, that is an
       artifact that can be installed only after another one was installed before. If you really  need  it,  for
       example  if you want to install a file into a filesystem provided as image, disable installed-directy for
       the file and enable it for the filesystem image.

   Do not drop atomicity !
       SWUpdate guarantees atomicity as long as you don't do something that simply breaks it. As example,  think
       about  the  bootloader's  environment.  In  an  sw-description,  there  is  a  specific section where the
       environment can be set, adding /  modifying  /  deleting  variables.  SWUpdate  does  not  change  single
       variables,  but  generates the resulting new environment for the supported bootloader and this is written
       in one shot in a way (for U-Boot / EFIBootguard, not for GRUB) that is power-cut safe.  You can of course
       change the environment in a postinstall script, like in the following way (for U-Boot):

          fw_setenv var1 val1
          fw_setenv var2 val2
          fw_setenv var3 val3
          fw_setenv var4 val4
          fw_setenv var5 val5

       If a power cut happens during two calls of fw_setenv, the environment is in  an  intermediate  state  and
       this can brick the device.

   Plan to have a rescue system
       Even  if  you  have  a  double-copy  setup,  something  can  go  wrong.  Plan  to  have  a  rescue system
       (swupdate-image in meta-swupdate) and to install it on a separate storage than the main system, if it  is
       possible.  This  helps  when  the  main storage is corrupted, and the device can be restored in the field
       without returning it back to the factory.  Plan to update the rescue system as well: it is software, too,
       and its bugs should be fixed, too.

DELTA UPDATE WITH SWUPDATE

   Overview
       The size of update packages is steadily increasing. While once the whole software was  just  a  bunch  of
       megabytes,  it  is not unusual now that OS and application on devices running Linux as OS reach huge size
       of Gigabytes.

       Several mechanisms can be used to reduce the size  of  downloaded  data.  The  resulting  images  can  be
       compressed.  However,  this  is  not enough when bandwidth is important and not cheap.  It is very common
       that a device will be upgraded to a version that is similar to the running one but add new  features  and
       solves  some  bugs. Specially in case of just fixes, the new version is pretty much equal as the original
       one. This asks to find methods to download  just  the  differences  with  the  current  software  without
       downloading a full image.  In case an update is performed from a known base, we talk about delta updates.
       In the following chapter some well known algorithms are considered and verified if they can be integrated
       into SWUpdate. The following criteria are important to find a suitable algorithm:

          • license must be compatible with GPLv2

          • good performance for smaller downloads, but not necessarily the best one.

          • SWUpdate  remains  with  the  concept  to deliver one package (SWU), the same independently from the
            source where the SWU is stored (USB, OTA, etc.)

          • It must comply to SWUpdate's security requirements (signed images, privilege separation, etc.)

       Specific ad-hoc delta updates mechanisms can be realized when the nature of  the  updated  files  is  the
       same.  It  is always possible with SWUpdate to install single files, but coherency and compatibility with
       the running software must be guaranteed by the integrator / manufacturer. This is not covered  here:  the
       scope  is  to get an efficient and content unaware delta mechanism, that can upgrade in differential mode
       two arbitrary images, without any previous knowledge about what they content.

   FOSS projects for delta encoding
       There are several algorithms for delta encoding, that is to find the difference between files,  generally
       in  binary  format.  Only algorithms available under a compatible FOSS license (GPLv2) are considered for
       SWUpdate.  One of the goals in SWUpdate is that it should work independently which is the format  of  the
       artifacts.  Very  specialized  algorithm and libraries like Google's Courgette used in Chromium will give
       much better results, but it works on programs (ELF  files)  and  take  advantages  of  the  structure  of
       compiled  code.  In case of OTA update, not only software, but any kind of artifact can be delivered, and
       this includes configuration data, databases, videos, docs, etc.

   librsync <https://librsync.github.io/>
       librsync <https://librsync.github.io/> is an independent implementation for rsync and does  not  use  the
       rsync  protocol.  It  is well suited to generate offline differential update and it is already integrated
       into SWUpdate.  However, librsync takes the whole artifact and generates a  differential  image  that  is
       applied  on the whole image. It gives the best results in terms of reduced size when differences are very
       small, but the differential output tends to be very large as soon  as  the  differences  are  meaningful.
       Differential  images  created  for SWUpdate show that, as soon as the difference larger is, the resulting
       delta image can even become larger as the original one.

       SWUpdate supports librsync as delta encoder via the rdiff handler.

   xdelta <http://xdelta.org/>
       xdelta <http://xdelta.org/> uses the VCDIFF algorithm to compute  differences  between  binaries.  It  is
       often  used  to deliver smaller images for CD and DVD. The resulting images are created from an installed
       image that should be loaded entirely in main memory. For this reason, it does not  scale  well  when  the
       images are becoming larger and it is unsuitable for embedded systems and SWUpdate.

   casync <http://0pointer.net/blog/casync-a-tool-for-distributing-file-system-images.html>
       casync <http://0pointer.net/blog/casync-a-tool-for-distributing-file-system-images.html> is, according to
       his  author.  a tool for distributing images. It has several interesting aspects that can be helpful with
       OTA update.  Files itself are grouped together in chunks and casync creates a "Chunk storage" where  each
       chunk is stored on a separate file. The chunk storage is part of the delivery, and it must be stored on a
       server.  casync  checks  if  the  chunk is already present on the target, and if not download it. If this
       seems to be what is required, there are some drawbacks if casync should be integrated in SWUpdate:

          • because of the nature of casync, each chunk is a separate file. This cause  a  huge  number  of  new
            connections,  because  each  file  is  a  separate  GET  on  the  server.   The  overhead  caused to
            re-instantiate connection is high on small devices, where SSL connections are  also  increasing  CPU
            load.  There  are  downloads  of  hundreds or thousands of small files just to recreate the original
            metadata file.

          • casync has no authentication and verification and the index (.caidx or .caibx) are not signed.  This
            is known, but casync goals and scopes are outside the ones on embedded devices.

          • it  is difficult to deliver a whole chunk storage. The common usage for OTA is to deliver artifacts,
            and they should be just a few. Thousands of files to be delivered to let casync to compute  the  new
            image is not practical for companies: they have a new "firmware" or "software" and they need an easy
            way  to  deliver  this file (the output from their build system) to the devices. In some cases, they
            are even not responsible for that, and the firmware is given to another authority  that  groups  all
            packages from vendors and realizes a sort of OTA service.

          • casync  is  quite  a  huge project - even if it was stated that it will be converted into a library,
            this never happened. This makes difficult to interface to SWUpdate, and using it as external process
            is a no way in SWUpdate for security reason.  It breaks privilege separation, and adds a lot of code
            that is difficult to maintain.

       For all these reasons, even if the idea of a chunk storage is good for an OTA updater, casync  is  not  a
       candidate for SWUpdate. A out-of-the-box solution cannot be found, and it is required to implement an own
       solution that better suits for SWUpdate.

   Zchunk <https://github.com/zchunk/zchunk> - compression format
       zchunk <https://github.com/zchunk/zchunk> seems to combine the usage of a chunk storage without having to
       deliver  it  on a server.  zchunk is a FOSS project released under BSD by its author <https://www.jdieter
       .net/posts/2018/05/31/what-is-zchunk/>. The goal of this project is something else: zchunk creates a  new
       compression  format  that  adds  the  ability  to download the differences between new and old file. This
       matches very well with SWUpdate. A zchunk file contains a header that has metadata for  all  chunks,  and
       according to the header, it is known which chunks must be downloaded and which ones can be reused. zchunk
       has  utilities  to download itself the missing chunks, but it could be just used to find which part of an
       artifact must be downloading, and SWUpdate can go on with its own way to do this.

       One big advantage on this approach is that metadata and compressed chunks are still bound into  a  single
       file,  that  can  be built by the buildsystem and delivered as it is used to. The updater needs first the
       metadata, that is the header in zchunk file,  and  processes  it  to  detect  which  chunks  need  to  be
       downloaded.  Each  chunk  has  its  own hash, and the chunks already available on the device are verified
       against the hash to be sure they are not corrupted.

       Zchunk supports multiple sha algorithms - to be compatible with SWUpdate, zchunk should  be  informed  to
       generate sha256 hashes.

   Design Delta Update in SWUpdate
       For  all  reasons  stated  before,  zchunk  is  chosen as format to deliver delta update in SWUpdate.  An
       artifact can be generated in ZCK format and then the ZCK's header (as described in format <https://github
       .com/zchunk/zchunk/blob/main/zchunk_format.txt>) can be extracted and added to the SWU. In  this  way,  a
       ZCK  file is signed (and if requested compressed and/or encrypted) as part of the SWU, and loading chunks
       from an external URL can be verified as well because the corresponding hashes  are  already  verified  as
       part of the header.

   Changes in ZCHUNK project
       Zchunk  has  an  API  that  hides  most  of  its  internal,  and provides a set of tools for creating and
       downloading itself a file in ZCK format. Nevertheless, Zchunk relies on hashes for the  compressed  (ZST)
       chunks,  and  it  was  missing  for  support for uncompressed data. To combine SWUpdate and zchunk, it is
       required that a comparison can be done between uncompressed data, because it is unwanted that a device is
       obliged to compress big amount of data just to perform a comparisons.  A short list  of  changes  in  the
       Zchunk project is:

          • create  hashes for uncompressed data and extend format to support it. The header must be extended to
            include both size and hash of uncompressed data.

          • make the library embedded friendly, that means reports errors in case of failure instead of  exiting
            and find a suitable way to integrate the log output for the caller.

          • allow to use sha256 (already foreseen in zchunk) as this is the only hash type used in SWUpdate.

          • add  API  to  allow  an external caller to take itself the decision if a chunk must be downloaded or
            reused.

       These changes were merged into Zchunk project - be sure to get a recent version of Zchunk, at least  with
       commit 1b36f8b5e0ecb, that means newer as 1.1.16.

       Most  of  missing  features  in  Zchunk  listed  in TODO for the project have no relevance here: SWUpdate
       already verifies the downloaded data, and there is no need to add signatures to Zchunk itself.

   Integration in sw-description
       The most important part in a Zchunk file is the header: this contains all metadata and hashes to  perform
       comparisons.  The  zck  tool splits a file in chunks and creates the header. Size of the header are know,
       and the header itself can be extracted from the ZCK file.  The header will  be  part  of  sw-description:
       this  is the header for the file that must be installed. Because the header is very small compared to the
       size of the whole file (quite 1 %), this header can be delivered into the SWU.

   Integration in SWUpdate: the delta handler
       The delta handler is responsible to compute the differences and to download the missing parts. It is  not
       responsible to install the artifact, because this breaks the module design in SWUpdate and will constrain
       to  have just one artifact type, for example installing as raw or rawfile. But what about if the artifact
       should be installed by a different handler, for example UBI, or a custom handler ?  The best way is  that
       the delta handler does not install, but it creates the stream itself so that this stream can be passed to
       another  (chained)  handler,  that  is responsible for installing. All current SWUpdate's handlers can be
       reused: each handler does not know that the artifact is coming with separate chunks and it  sees  just  a
       stream as before.  The delta handler has in short the following duties:

          • parse and understand the ZCK header

          • create a ZCK header from the file / partition used as source for the comparison

          • detect which chunks are missing and which one must be copied.

          • build   a  mixer  that  copies  and  downloads  all  chunks and generates a stream for the following
            handler.

          • detect any error coming form the chained handler.

       Because the delta handler requires to download more data, it must start a connection to the storage where
       the original ZCK is stored. This can lead to security issues, because handlers run with  high  privileges
       because  they write into the hardware. In fact, this breaks privilege separation that is part of SWUpdate
       design.  To avoid this, the delta handler does not download itself. A separate  process,  that  can  runs
       with  different  userid and groupid, is responsible for this. The handler sends a request to this process
       with a list of ranges that should be downloaded (see HTTP Range request). The delta handler does not know
       how the chunks are downloaded, and even if using HTTP Range Request is the most frequent  choice,  it  is
       open  to further implementations.  The downloader process prepares the connection and asks the server for
       ranges. If the server is not able to provide ranges, the update aborts. It is in fact a  requirement  for
       delta  update  that the server storing the ZCK file is able to answer to HTTP Range Request, and there is
       no fallback to download the full file.  An easy IPC is implemented between  the  delta  handler  and  the
       downloader  process.  This  allows to exchange messages, and the downloader can inform the handler if any
       error occurs so that the update can be stopped.  The downloader will send a termination message when  all
       chunks will be downloaded.  Because the number of missing chunks can be very high, the delta handler must
       sends  and  organize  several  requests  to the downloader, and tracking each of them.  The downloader is
       thought as dummy servant: it starts the connection, retrieves HTTP headers and data, and sends them  back
       to  the  caller.  The  delta handler is then responsible to parse the answer, and to retrieve the missing
       chunks from the multipart HTTP body.

   Configuration
       The delta handler is configured in the runtime configuration file (swupdate.cfg).  The  configuration  is
       done in the delta section. See also example/configuration/swupdate.cfg for details.

       API  key  authentication  can be setup by providing api_key_header and api_key in the configuration file.
       api_key_header is the header name that is used to send the api_key.  api_key is the value that is sent in
       the header.

   Creation of ZCK Header and ZCK file for SWUpdate
       Zchunk supports more SHA algorithms and it sets as  default  SHA512/128.  This  is  not  compatible  with
       SWUpdate  that  just support SHA256. Be sure to generate header and chunks with SHA256 support.  You have
       to enable the generation of hashes for uncompressed chunk, too. A possible usage of the tool is:

          zck --output <output file> -u --chunk-hash-type sha256 <artifact, like rootfs>

       The output is the ZCK file with all chunks.  This file should be put on a  Webserver  accessible  to  the
       target, and that supports Range Request (RFC 7233). All modern Webserver support it.

       The SWU must just contain the header. This can be easy extracted from the ZCK file with:

          HSIZE=`zck_read_header -v <ZCK file> | grep "Header size" | cut -d':' -f2`
          dd if=<ZCK FILE> of=<ZCK HEADER file> bs=1 count=$((HSIZE))

   Using ZCK tools to foresee download size
       There are tools that can be used at build time to know how many chunks should be downloaded when a device
       is upgrading from a known version. You can use zck_cmp_uncomp from the test directory:

          ../build/test/zck_cmp_uncomp --verbose <uncompressed old version file> <ZCK file>

       This  prints  a  list  with all chunks, marking them with SRC if they are the same in the old version and
       they should not retrieved and with DST if they are new and must be downloaded.  The tool show at the  end
       a  summary  with  the  total number of bytes of the new release (uncompressed) and how many bytes must be
       downloaded for the upgrade.  Please remember that these  value  are  just  payload.  SWUpdate  reports  a
       summary,  too,  but  it takes into account also the HTTP overhead (headers, etc.), so that values are not
       the same and the ones from SWUpdate are slightly bigger.

SWUPDATE-CLIENT

       swupdate-client is a small tool that sends a SWU image to a running instance of SWUpdate. It can be  used
       if  the  update package (SWU) is downloaded by another application external to SWUpdate. It is an example
       how to use the IPC to forward an image to SWUpdate.

   SYNOPSIS
       swupdate-client [OPTIONS] <image.swu to be installed>...

   DESCRIPTION
       -h     print help and exit

       -d     ask the server to only perform a dry-run

       -e     <software>,<mode> select software image set and source (for example: stable,main)

       -q     go quiet, resets verbosity

       -v     go verbose, essentially print upgrade status messages from server

       -p     ask the server to run post-update commands if upgrade succeeds

SWUPDATE-PROGRESS

       swupdate-progress tries to connect to a running instance of SWUpdate to  get  the  status  of  a  running
       update.

   SYNOPSIS
       swupdate-progress [option]

   DESCRIPTION
       swupdate-progress  is  an  example  how  to  connect to SWUpdate via the progress interface.  It shows on
       stdout a simple bar with the percent indication of the current update  and  reports  the  result  of  the
       update. It can optionally drive "psplash" or execute a script after an update.

       -c     Use colors to show results on stdout

       -e     Command to be execute after an update

       -p     send percentage to psplash

       -r     optionally reboot the target after a successful update

       -s     path to progress IPC socket in case the default is not taken

       -w     waits for a SWUpdate connection instead of exit with error

       -q     don't print progress bar

       -h     print a help

SWUPDATE-IPC

       swupdate-ipc sends a specific command to SWUpdate. The following commands are enabled:

   aes
       send a new aes key to SWUpdate

   setversion
       sends a range of versions that can be accepted.

   gethawkbit
       return status of the connection to Hawkbit.

   sendtohawkbit
       send  data to the Hawkbit Server.  A typical use case is acknowledgement for activation by an application
       or operator after a new software has been installed.  The tool can forward the result for the  activation
       to the hawkBit server.

   sysrestart
       send a restart command after a network update

   SYNOPSIS
       swupdate-ipc <cmd> [option]

       Where cmd is one of the listed above.

   DESCRIPTION
       aes <key> <ivt>
              AES key to be used for decryption

       setversion <min> <max> <current>
              configure the accepted range of versions

       hawkbitcfg
              configuration for Hawkbit Module

       -h     help

       -p     allows one to set the polling time (in seconds)

       -e     enable suricatta mode

       -d     disable suricatta mode

       swupdate-sendtohawkbit <action id> <status> <finished> <execution> <detail 1> <detail 2> ..
              Send Acknowledge to Hawkbit server after an update if SWUpdate is set to wait for.

       sysrestart
              Used with SWU handler, allow one to perform a network restart

       -r     optionally reboot the target after a successful update

       -w     waits for a SWUpdate connection instead of exit with error

       -s <path>
              path to progress IPC socket

HELP AND SUPPORT

   Mailing List
       There is a mailing list for this project:
          <swupdate@googlegroups.com>

       Issue related to the project or to the documentation are discussed here.

   SWUpdate Flyer
       A  short description about the project and the features (in English and German) can be found in the flyer
       <http://www.denx.de/en/pub/Software/WebHome/we-update.pdf>

   Workshop and SWUpdate integration in project
       For quick integration of SWUpdate in your project, you could be  interested  in  the  Training  <https://
       swupdate.org/services>

   Commercial support and board integration
       Please  check  for  services <https://swupdate.org/services> if you need professional support or you need
       help to get SWUpdate on your device.

   Talks about SWUpdate
          • Software  Update   in   Embedded   Systems   by   Stefano   Babic   <https://elinux.org/images/1/19/
            Babic--software_update_in_embedded_systems.pdf>

          • Updating  Embedded Linux devices in field by Chris Simmonds <http://de.slideshare.net/chrissimmonds/
            linux-fieldupdate2015>

          • OpenEmbedded in the Real World by Scott Murray <https://elinux.org/images/7/74/Murray.pdf>

          • [RFC] Device-side support for software update in AGL by Matt  Porter  <https://lists.linuxfoundation
            .org/pipermail/automotive-discussions/2016-May/002061.html>

          • Open  Source  secure  software  updates for Linux-based IVI systems by Arthur Taylor <https://events
            .static.linuxfound.org/sites/events/files/slides/
            Open%20Source%20secure%20software%20updates%20for%20Linux-based%20IVI%20systems.pdf>

          • How do you update your embedded Linux devices? by Daniel Sangorrin /  Keijiro  Yano  <https://events
            .static.linuxfound.org/sites/events/files/slides/linuxcon-japan-2016-softwre-updates-sangorrin.pdf>

          • Comparison  of  Linux  Software  Update Technologies by Matt Porter <https://elinux.org/images/3/31/
            Comparison_of_Linux_Software_Update_Technologies.pdf>

          • Software update for IoT: the current state of play by Chris Simmonds, ELCE 2016,  Slides  <http://de
            .slideshare.net/chrissimmonds/software-update-for-iot-the-current-state-of-play>,   Video  <https://
            youtu.be/GZGnBK2NycI?list=PLbzoR-pLrL6pRFP6SOywVJWdEHlmQE51q>

          • OSS Remote Firmware Updates for IoT-like Projects by Silvano Cirujano Cuesta, ELCE 2016, Slides ELCE
            2016  <https://elinux.org/images/1/11/OSS_Remote_Firmware_Updates_for_IoT-like_Projects.pdf>,  Video
            ELCE 2016 <https://youtu.be/vVS-ZRNE0Lc?list=PLbzoR-pLrL6pRFP6SOywVJWdEHlmQE51q>

          • System  Upgrade  with  SWUpdate  by  Gabriel  Huau,  ELC  2017,  Slides  ELC  2017  <http://events17
            .linuxfoundation.org/sites/events/files/slides/ELC2017_SWUpdate.pdf>, Video  ELC  2017  <https://www
            .youtube.com/watch?v=ePRTTfGJUI4&t=16s>

          • BoF:  Secure  OTA Collaboration, by Ricardo Salveti and Alan Bennett, ELCE 2017 <https://elinux.org/
            images/0/0c/BoF_secure_ota_linux.pdf>

          • Orchestrated Android-Style System Upgrades for Embedded Linux by Diego Rondini,  ELCE  2017,  Slides
            Android-Style       <https://www.elinux.org/images/6/6d/UF_-_ELCE_2017_Presentation.pdf>,      Video
            Android-Style <https://www.youtube.com/watch?v=Za21QFJGvJ0>

          • Updating an Embedded System with SWUpdate Framework by Stefano Babic, ELCE 2017,  Slides  ELCE  2017
            <http://events17.linuxfoundation.org/sites/events/files/slides/SWUpdateELCE2017.pdf>,   Video   ELCE
            2017 <https://www.youtube.com/watch?v=6sKLH95g4Do>

          • Upgrading buildroot based devices  with  SWUpdate  by  Angelo  Compagnucci,  LinuxLab  2018,  Slides
            LinuxLab                        2018                      <https://www.slideshare.net/linuxlab_conf/
            angelo-compagnucci-upgrading-buildroot-based-devices-with-swupdate>, Video LinuxLab  2018  <https://
            www.youtube.com/watch?v=8vv5Xf6dBKE>,

          • Evolution  of (OTA) Update in the IoT world by Stefano Babic, ELC 2019, Slides ELC 2019 <https://www
            .slideshare.net/StefanoBabic/evolution-of-otaupdateintheiotworld>,  Video  ELC   2019   <https://www
            .youtube.com/watch?v=WZHO18EhD7Y>,

          • Introduction  of  CIP Software Updates Working Group by Akihiro Suzuki, CIP Mini Summit 2019, Slides
            CIP    2019     <https://wiki.linuxfoundation.org/_media/civilinfrastructureplatform/cipconferences/
            sw_updates_wg_mini-summit.pdf>,

          • There  is  No  Store  For Self-Driving Car Parts by Stephen Segal and Matt Fornero (Cruise LLC), ELC
            2020,    Slides     Cruise     ELC     2020     <https://static.sched.com/hosted_files/ossna2020/56/
            No_Store_for_AV_Parts_ELC_NA_2020.pdf>, Video Cruise <https://www.youtube.com/watch?v=PSq13Kv4Qk4>

          • Secure  Boot  and  Over-the-Air  Updates - That's simple, no ? by Jan Kiszka (Siemens AG), ELC 2020,
            Slides     Secure     OTA     ELC     2020      <https://static.sched.com/hosted_files/ossna2020/17/
            Secure-OTA-Updates_elc-na-2020.pdf>,  Video Secure OTA <https://www.youtube.com/watch?v=vfYSP4qIJP0&
            t=1647s>

          • Diving into SWUpdate: adding new platform support with Yocto/OE! by Pierre-Jean Texier, LiveEmbedded
            2020,     Slides     Diving     into      SWUpdate      <https://de.slideshare.net/PierrejeanTexier/
            diving-into-swupdate-adding-new-platform-support-in-30minutes-with-yoctooe>,   Video   Diving   into
            SWUpdate <https://www.youtube.com/watch?v=TK10pNb_mzw>

          • Implementing UEFI-based Secure Boot + OTA Update for Embedded ARM Devices by Jan Kiszka &  Christian
            Storm,  ELCE  2022  Slides  Implementing  UEFI Secure Boot + OTA Update <https://https://elinux.org/
            images/4/42/ELCE2022-UEFISecureBootOTAUpdatesOnARM.pdf>, Video Implementing UEFI-based Secure Boot +
            OTA Update for Embedded ARM Devices <https://www.youtube.com/watch?v=H_dBnwkTAbw>

          • Delta OTA Update with SWUpdate by Stefano Babic, ELCE 2022 Slides  Delta OTA  Update  with  SWUpdate
            <https://elinux.org/images/9/98/Delta_OTA_Update_with_SWUpdate_-_ELCE_2022.pdf>,   Video  Delta  OTA
            Update with SWUpdate <https://www.youtube.com/watch?v=noURP22fJhs>

          • Ligthning Talk: SWUpdate Over CAN Bus - Can it ? by Stefano Babic, EOSS 2023 Video SWUpdate Over CAN
            Bus <https://www.youtube.com/watch?v=OU7MuX2sPUU&t=59s>

          • Best Practices with SWUpdate by Stefano Babic, Embedded Recipes  2023  Slides  Best  Practices  with
            SWUpdate    <https://drive.google.com/file/d/1pbMtFH6IkztpsgvL6GJ54Fs7hPu7tPBf/view?usp=drive_link>,
            Video     Best     Practices     with     SWUpdate     <https://www.youtube.com/watch?v=SXzfDa8HEss&
            list=PLwnbCeeZfQ_Mi7gjUpLZxXGOcEBS_K8kH&index=7&pp=iAQB>

          • Delta  Updates:  Making  Updates  Leaner by Felix Moessbauer & Jan Kiszka, Siemens AG, Embedded Open
            Source  Summit  2024  Slides  Delta  Updates:  Making  Updates   Leaner   <https://static.sched.com/
            hosted_files/eoss24/26/2024_EOSS_CIP_delta_updates.pdf>,  Video Delta Updates: Making Updates Leaner
            <https://www.youtube.com/watch?v=1rzf7tE-cKY>

   Useful references
          • Boundary  Devices,   Using   SWUpdate   to   upgrade   your   system   <https://boundarydevices.com/
            using-swupdate-upgrade-system>

          • Présentation      de      Software     Update     (French)     <http://www.linuxembedded.fr/2016/09/
            presentation-de-software-update>

          • Easy OS upgrades with SWUpdate <http://warpx.io/blog/tutorial/easy-os-upgrades-swupdate>

          • SWUpdate       for       feature-rich       IoT       applications       <https://3mdeb.com/app-dev/
            swupdate-for-feature-rich-iot-applications/>

          • Implement swupdate - replacing opkg based updating, VictronEnergy <https://github.com/victronenergy/
            venus/issues/27>

          • Variscite, SWUpdate <http://www.variwiki.com/index.php?title=SWUpdate_Guide>

          • Updating       Embedded       Linux       Devices:       SWUpdate      <http://mkrak.org/2018/01/26/
            updating-embedded-linux-devices-part2/>

          • Approach  to  Software  Update   Management,   Pelux   <https://pelux.io/software-factory/PELUX-3.0/
            swf-blueprint/docs/articles/architecture/vert-config-SOTA.html>

          • SOTA  System,  Pelux  <https://pelux.io/software-factory/PELUX-3.0/chapters/architecture/subsystems/
            SOTA/SOTA-system.html>

          • Building a Linux system for the STM32MP1: remote  firmware  updates,  Bootlin  <https://bootlin.com/
            blog/tag/swupdate/>

CONTRIBUTING TO SWUPDATE

       Contributions are welcome ! Please follow the following guideline for contributions.

   Contribution Checklist
       These are mostly general recommendations and are common practice in a lot of FOSS projects.

       • use git to manage your changes [recommended]

       • follow as much as possible kernel codestyle [recommended] Nevertheless, some rules are not so strict as
         in kernel. The maximum line length can be extended over 80 chars if this increase code readability.

       • add the required copyright header to each new file introduced [required]

       •

         add signed-off to all patches [required]

                • to certify the "Developer's Certificate of Origin", see below

                • check with your employer when not working on your own!

       •

         add version number for your patches if follow-up versions are requested [recommended]

                • Add  a  "Change  from Vx" description under the commit message to take track of the history of
                  the patch.

                • It is suggested to use excellent "patman" tool to manage patches  series.   This  is  part  of
                  U-Boot's project (tools/patman), but it can be used in other projects, too.

       • check that your patches do not break build [required]

         • There is a set of configuration files in the configs/ directory.  Please run a build for all files in
           the directory to ensure that SWUpdate is still buildable from configurations different as yours.

       •

         post patches to mailing list [required]

                • use git format-patch to generate your patches.

                • use git send-email if possible. This avoid corruptions due to the mailers

                • add a prefix [meta-swupdate] if patches are intended to the Yocto's meta layer.

                • send patches inline, do not append them

                • no HTML emails!

       • do not use github Pull Request. github facilities are not used for this project.  The review is done in
         a single place : the Mailing List. PR from github are ignored.

       Patches  are  tracked  by  patchwork  (see  <http://jk.ozlabs.org/projects/patchwork/>).  You can see the
       status of your patches at <http://patchwork.ozlabs.org/project/swupdate/list>.

   Developer's Certificate of Origin 1.1
       When signing-off a patch for this project like this
          Signed-off-by: Random J Developer <<random@developer.example.org>>

       using your real name (no pseudonyms or anonymous contributions), you declare the following:
          By making a contribution to this project, I certify that:

              a. The contribution was created in whole or in part by me and I have the right to submit it  under
                 the open source license indicated in the file; or

              b. The  contribution  is  based  upon  previous work that, to the best of my knowledge, is covered
                 under an appropriate open source license and I have the right under that license to submit that
                 work with modifications, whether created in whole or in part by me, under the same open  source
                 license  (unless I am permitted to submit under a different license), as indicated in the file;
                 or

              c. The contribution was provided directly to me by some other person who certified (a), (b) or (c)
                 and I have not modified it.

              d. I understand and agree that this project and the contribution are public and that a  record  of
                 the  contribution  (including all personal information I submit with it, including my sign-off)
                 is maintained indefinitely and may be redistributed consistent with this project  or  the  open
                 source license(s) involved.

PROPOSALS TO IMPROVE SWUPDATE

       Please  take  into  account  that  most  of  the items here are proposals.  I get some ideas talking with
       customers, some ideas are my own thoughts.  There is no plan when these features will  be  implemented  -
       this  depends if there will be contribution to the project in terms of patches or financial contributions
       to develop a feature.

       Each item listed here contains a status and if the feature is already planned or I am looking for sponsor
       to implement it. This should avoid double work and make more  transparent  what  is  going  on  with  the
       project.

       If  you have further ideas about the project, just send your proposal to the Mailing List or post a patch
       for this document.

       Thanks again to all companies that have supported my work up now and to everybody who has contributed  to
       the project, let me bring SWUpdate to the current status !

   Legende
   Feature's status
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ Value   │ Description                           │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ Wait    │ No activity is planned, just proposal │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ Design  │ Design / Concept is done              │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ Planned │ Feature will be implemented soon      │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ WIP     │ Feature  is current to be implemented │
                                 │         │ and will be posted                    │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ Running │ Implemented                           │
                                 └─────────┴───────────────────────────────────────┘

   Request for Support
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ Value   │ Description                           │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ None    │ No sponsoring required                │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ Sponsor │ Looking for sponsors to  finance  the │
                                 │         │ feature                               │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ Planned │ Feature is already sponsored          │
                                 └─────────┴───────────────────────────────────────┘

   Priority
                                  ┌────────┬───────────────────────────────────────┐
                                  │ Value  │ Description                           │
                                  ├────────┼───────────────────────────────────────┤
                                  │ Low    │ Probably  just an idea, feedback from │
                                  │        │ community asked                       │
                                  ├────────┼───────────────────────────────────────┤
                                  │ Medium │ Not critical,  but  nice  feature  to │
                                  │        │ have                                  │
                                  ├────────┼───────────────────────────────────────┤
                                  │ High   │ Critical   feature,   it   should  be │
                                  │        │ implemented soon                      │
                                  └────────┴───────────────────────────────────────┘

   Main goal
       First goal is to reach a quite big audience, making SWUpdate suitable for a  large  number  of  products.
       This will help to build a community around the project itself.

       • Status : Running

       • Request for Support : None

   Core features
   Support for OpenWRT
       OpenWRT is used on many routers and has its own way for updating that is not power-cut safe.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Low

   Software-Software compatibility
       SWUpdate  has  from the early stage a hardware to software compatibility check. In case software is split
       in several components (like OS and application), it is desirable to have a sort of software compatibility
       check. For example, SWUpdate verifies if a component (like an application) is compatible with a runningOS
       and reject the update in case of mismatch.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Support files bigger than 4GB
       SWUpdate currently uses CPIO to pack updates in the 'newc' and 'crc' formats.  These formats limit single
       files to 4GB - 1byte in size, which could become a problem as update size grows.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : High

   Fetcher and interfaces
   Selective downloading
       SWUpdate starts to fetch the whole SWU and process it until an error is found. There are some requests to
       have a selective downloading, that means SWUpdate will load just the chunks are needed and not the  whole
       SWU.  An  example  for  this use case is in case a single SWU contains software for multiple devices, and
       each of them needs a subset of the whole SWU. Like the delta handler, SWUpdate knows from  sw-description
       which artifacts are to be installed, and reading the stream could decide to skip unnecessary components.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Tools and utilities
   Single tool to create SWU
       SWUGenerator  is  a separate project that helps to create SWUs. It is used on not OE projects. In OE, the
       SWU is created using code in meta-swupdate. This leads to a duplication of code  with  higher  effort  to
       maintain.

       Even if it was tried to have the same features, there are some important differences:

       • SWUGenerator  is  able to full understand a sw-description written in libconfig language and to rewrite
         it.  This means it is not yet possible to write sw-description using JSON if SWUGenerator  is  planned.
         However, it is possible to split sw-description in small files (for example for the embedded Lua code),
         and SWUGenerator is able to write the final sw-description combined all include files.

       • meta-swupdate is just able to replace variables known by bitbake, but it has no semantic knowledge.  It
         is not possible to use @include directive, but it is possible to use JSON as language.

       The  logical  step  will  be  to use a single tool (SWUGenerator), and let meta-swupdate to use it. To do
       this, SWUGenerator should be enhanced to understand and write sw-description in JSON, too.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Further enhancement to SWUGenerator
       SWUGenerator is thought to support multiple subcommands, but it currently supports just "create".  It  is
       thinkable, even if this can be done with other tools, to implement further commands like:

       • extract: take a SWU and extracts all artifacts in a directory

       • sign:  take  a  SWU  and  resign  with  a  new key. This is useful when it is required to install a new
         Software, but the certificate or the key on the device is older and rejects the installation.

       • verify: just verify if the SWU is correctly signed.

       SWUGenerator does not yet support all features present in meta-swupdate. As replacement for meta-swupdate
       and the wish to have just one tool, SWUGenerator should align itself with meta-swupdate. It will be  then
       possible  to  drop  most  of  code  from  meta-swupdate's  classes,  and  replace with the single call to
       SWUGenerator.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   swupdate-progress start up
       On SystemV (and compatible) systems, swupdate-progress is started from swupdate.sh via exec. This is  not
       the right solution and was discussed on the Mailing List.

       The  agreed  solution  is  to  create  an  own startup script for swupdate-progress, and let run it after
       SWUpdate is started. This is more generic and  let  also  to  identify  if  swupdate-progress  should  be
       installed or not.

       • Status: Wait

       • Request for Support : Not required

       • Priority : Low

   Lua
       • API between SWUpdate and Lua is poorly documented.

       • Store in SWUpdate's repo Lua libraries and common functions to be reused by projects.

       • Status : Running

       • Request for Support : None

       • Priority : Medium

   Handlers:
   New Handlers
       Users develop own custom handlers - I just enforce and encourage everyone to send them and discuss how to
       integrate custom handler in mainline.

       Some ideas for new handlers:

              • FPGA updater for FPGA with Flash

              • Package  handler  to  install  packages (ipk, deb) Packages can be inserted into the SWU and the
                atomicity is guaranteed by SWUpdate.

              • Lua handlers should be added if possible to the project to show how to solve custom install.

       • Status : Running

       • Request for Support : None

       • Priority : Low

   Internal Webserver
       SWUpdate make usage of the project "mongoose" as internal Webserver. It fits all requirements and  allows
       to  stream  a  SWU  without temporary copy.  However, upgrading the Webserver code requires to adjust the
       interface and code. It will be nice to have further implementation of the Webserver, and/or  to  open  to
       Webserver that allows streaming.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Security / Crypto engines
       • add support for asymmetric decryption

       • rework support for crypto engine - let possible to load multiple libraries at the same time. Currently,
         there is support for openSSL, WolfSSL and mbedTLS.  However, WolfSSL are missing together. There should
         be a way to select one or more libraries and independently the algorithms that SWUpdate should support.
         Some  hacks are currently built to avoid conflicts (pkcs#7 and CMS are the same thing, but supported by
         different libraries), and they should be solved.

       • add more algorithms for decryption, as AES-CTR can be very useful to decrypt chunks in delta updates.

       • Support for TPM2 to store secrets (requires rework above).

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : High

   Back-end support (suricatta mode)
   Back-end: responsiveness for IPC
       Suricatta is implemented as process that launches functions for the selected module.  This means that the
       IPC does not answer if Suricatta is doing something, specially if it is  downloading  and  upgrading  the
       system.  This can be enhanced adding a separate thread for IPC and of course all required synchronization
       with the main modules.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Back-end: check before installing
       In some cases (for example, where bandwidth is important), it is better to check if  an  update  must  be
       installed  instead  of  installing  and  performs  checks  later.  If SWUpdate provides a way to inform a
       checker if an update can be accepted before downloading, a download  is  only  done  when  it  is  really
       necessary.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Back-end: hawkBit Offline support
       There are several discussions on hawkBit's ML about how to synchronize an offline update (done locally or
       via  the  internal  Web-server)  with  the hawkBit's server. Currently, hawkBit thinks to be the only one
       deploying software. hawkBit DDI API should be extended, and afterwards changes  must  be  implemented  in
       SWUpdate.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Low

   Backend: hawkBit support for Delta Update
       Delta Update requires two or more files:

       • the SWU

       • one file ".zck" for each artifact that is upgraded via delta handler.

       The  .zck  must  be uploaded somewhere and the URL is defined inside sw-description, that is then signed.
       This causes a chicken-egg issue, because the buzild cannot be completed with  hawkBit  until  the  ".zck"
       files  are  not uploaded. In fact, hawkBit assigns to each Software Module an "id" that is unknown at the
       moment of the build.

       It is required to implement a mechanism that let suricatta to inform the core about URLs  passed  by  the
       hawkBit  server,  and  they  can  override  the URL set inside sw-description.  This lets the URL for ZCK
       unknown during the build and it will be detected at runtime.

       The authentication to the hawkBit Server does not work in case  of  delta.  In  fact,  authentication  is
       performed  by  the  backend  connector,  but  the  download  of .zck files is done by a different process
       ("downloader") that don't use the setup from suricatta.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Back-end: support for generic down-loader
       SWUpdate in down-loader mode works as one-shot: it simply try to download a SWU from a  URL.  For  simple
       applications, it could be moved into suricatta to detect if a new version is available before downloading
       and installing.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Back-end: further connectors
       Further  connectors  could  be implemented. The structure in SWUpdate is modular, and allows to write new
       connectors, even in Lua. New connectors could be added if there are requests in this direction.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Low

   Test and Continuous Integration
       The number of configurations and features in SWUpdate is steadily increasing and  it  becomes  urgent  to
       find  a  way  to  test  all  incoming  patch to fix regression issues.  One step in this direction is the
       support for Travis build - a set of configuration files is stored with the project  and  should  help  to
       find  fast  breakages  in  the  build.  More in this direction must be done to perform test on targets. A
       suitable test framework should be found. Scope is to have a "SWUpdate factory"  where  patches  are  fast
       integrated and tested on real hardware.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Binding to languages
       libswupdate  allows  to write an application that can control SWUpdate's behavior and be informed about a
       running update. There are bindings for C/C++, Lua and nodejs (just progress).

       Applications can be written in other languages, and binding to Python and Rust can be implemented, too.

       • Status: Wait

       • Request for Support : Sponsor

       • Priority : Medium

   Documentation
       Documentation is a central point in SWUpdate - maintaining it up to date is a must in this project.  Help
       from any user fixing wrong sentence, bad english, adding missing topics is high appreciated.

       • Status : Running

       • Request for Support : None

   Already completed and mainlined
       Following items were already implemented and are supported in mainlined - thanks for whom sponsored them.

   Support for BTRFS snapshot
       BTRFS supports subvolume and delta backup for volumes - supporting subvolumes is a way to move the  delta
       approach to filesystems, while SWUpdate should apply the deltas generated by BTRFS utilities.

       • Status: since 2024.12

   Parser
       SWUpdate supports two parsers : libconfig and JSON. It would be nice if tools can be used to convert from
       one  format  to  the  other  one. Currently, due to some specialties in libconfig, a manual conversion is
       still required.

       • Status: since 2024.12

   Handlers installable as plugin at runtime
       The project supports Lua as script language for pre- and postinstall script. It will be easy to add a way
       for installing a handler at run-time written in Lua, allowing to expand SWUpdate to the cases not covered
       in the design phase of a product.

       Of course, this issue is related to the security features: it must be ensured that only verified handlers
       can be added to the system to avoid that malware can get the control of the target.

       Current release supports verified images. That means that a handler written in Lua could be now  be  part
       of the compound image, because a unauthenticated handler cannot run.

       • Status : since 2024.05

DOCUMENTATION FOR PREVIOUS RELEASES

       • 2024.12 <./2024.12/index.html>

       • 2024.05 <./2024.05/index.html>

       • 2023.12 <./2023.12/index.html>

       • 2023.05 <./2023.05/index.html>

       • 2022.12 <./2022.12/index.html>

       • 2022.05 <./2022.05/index.html>

       • 2021.11 <./2021.11/index.html>

       • 2021.04 <./2021.04/index.html>

       • 2020.11 <./2020.11/index.html>

       • 2020.04 <./2020.04/index.html>

       • 2019.11 <./2019.11/index.html>

       • 2019.04 <./2019.04/index.html>

       • 2018.11 <./2018.11/index.html>

INDICES AND TABLES

       • Index <>

       • Module Index <>

       • Search Page <>

Author

       Stefano Babic

Copyright

       2013-2025, Stefano Babic

2025.05                                           Oct 21, 2025                                       SWUPDATE(1)