'\" t
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SWUPDATE" "1" "Apr 03, 2025" "2024.12" "Embedded Software Update Documentation"
.SH NAME
swupdate \- SWUpdate Documentation
[image]
.sp
SWUpdate provides a reliable way to update
the software on an embedded system.
Sources are hosted at \X'tty: link https://github.com/sbabic/swupdate'\fI\%https://github.com/sbabic/swupdate\fP\X'tty: link'\&. Do not
forget to \fIstar\fP SWUpdate.
.SH SOFTWARE MANAGEMENT ON EMBEDDED SYSTEMS
.sp
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.
.sp
On a Linux\-based system, we can find in most cases
the following elements:
.INDENT 0.0
.IP \(bu 2
the boot loader.
.IP \(bu 2
the kernel and the DT (Device Tree) file.
.IP \(bu 2
the root file system
.IP \(bu 2
other file systems, mounted at a later point
.IP \(bu 2
customer data, in raw format or on a file system
.IP \(bu 2
application specific software. For example, firmware
to be downloaded on connected micro\-controllers, and so on.
.UNINDENT
.sp
Generally speaking, in most cases it is required to update
kernel and root file system, preserving user data \- but cases vary.
.sp
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.
.sp
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.
.SS Updating through the boot loader
.sp
Boot loaders do much more as simply start the kernel.
They have their own shell and can be managed using
a processor\(aqs peripheral, in most cases a serial line.
They are often script\-able, letting possible to implement
some kind of software update mechanism.
.sp
However, I found some drawbacks in this approach, that
let me search for another solution, based on an application
running on Linux:
.SS Boot loaders have limited access to peripherals
.sp
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.
.SS Boot loader\(aqs drivers are not updated
.sp
Boot loader\(aqs 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.
.sp
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.
.SS Reduced file systems
.sp
The number of supported file systems is limited and
porting a file system to the boot loader requires high effort.
.SS Network support is limited
.sp
Network stack is limited, generally an update is possible via
UDP but not via TCP.
.SS Interaction with the operator
.sp
It is difficult to expose an interface to the operator,
such as a GUI with a browser or on a display.
.sp
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.
.SS Boot loader\(aqs update advantages
.sp
However, this approach has some advantages, too:
.INDENT 0.0
.IP \(bu 2
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.
.UNINDENT
.SS Updating through a package manager
.sp
All Linux distributions are updating with a package manager.
Why is it not suitable for embedded ?
.sp
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 \fIatomic\fP, 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?
.sp
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.
.sp
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 \(dqversion 2.5\(dq when a patch for some files were sent previously
to the customer ?
.sp
An atomic update is generally a must feature for an embedded system.
.SS Strategies for an application doing software upgrade
.sp
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.
.sp
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.
.sp
Different strategies can be used, depending on the system\(aqs
resources. I am listing some of them.
.SS Double copy with fall\-back
.sp
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.
.sp
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.
.sp
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.
.sp
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]
.sp
Check the chapter about boot loader to see which mechanisms can be
implemented to guarantee that the target is not broken after an update.
.sp
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.
.sp
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.
.sp
SWUpdate will set bootloader\(aqs variable to signal the that a new image is
successfully installed.
.SS Single copy \- running as standalone image
.sp
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.
.sp
The system can be put in \(dqupgrade\(dq 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.
.sp
The boot loader starts \(dqSWUpdate\(dq, 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.
.sp
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]
.sp
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 \(dqboot\-able\(dq. 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\(aqs 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.
.sp
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]
.SS Something went wrong ?
.sp
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.
.sp
We can at least group some of the common causes:
.INDENT 0.0
.IP \(bu 2
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\(aqs storage.
.IP \(bu 2
corrupted image in the storage (flash)
.IP \(bu 2
remote update interrupted due to communication problem.
.IP \(bu 2
power\-failure
.UNINDENT
.sp
SWUpdate works as transaction process. The boot loader environment variable
\(dqrecovery_status\(dq is set to signal the update\(aqs 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 \(dqprogress\(dq, \(dqfailed\(dq, or it can be unset.
.sp
When SWUpdate starts, it sets recovery_status to \(dqprogress\(dq. After an update is
finished with success, the variable is erased. If the update ends with an
error, recovery_status has the value \(dqfailed\(dq.
.sp
When an update is interrupted, independently from the cause, the boot loader
recognizes it because the recovery_status variable is in \(dqprogress\(dq or \(dqfailed\(dq.
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).
.SS Power Failure
.sp
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.
.sp
Generally, the behavior can be split according to the chosen scenario:
.INDENT 0.0
.IP \(bu 2
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.
.IP \(bu 2
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.
.UNINDENT
.sp
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]
.SS What about upgrading SWUpdate itself ?
.sp
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.
.sp
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.
.sp
There are some ways to circumvent this issue if SWUpdate is part of the
upgraded image:
.INDENT 0.0
.IP \(bu 2
have two copies of SWUpdate
.IP \(bu 2
take the risk, but have a rescue procedure using the boot loader.
.UNINDENT
.SS What about upgrading the Boot loader ?
.sp
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.
.sp
Some SOCs allow one to have multiple copies of the
boot loader. But again, there is no general solution for this because it
is \fIvery\fP hardware specific.
.sp
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.
.sp
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.
.SH LICENSE
.sp
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.
.sp
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\(aqs SPDX project [1].  For example,
in a source file the full \(dqGPL v2.0 only\(dq header text will be
replaced by a single line:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
SPDX\-License\-Identifier:        GPL\-2.0\-only
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
If a \(dqSPDX\-License\-Identifier:\(dq 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
.INDENT 0.0
.INDENT 3.5
.sp
.EX
SPDX\-License\-Identifier:        GPL\-2.0\-only OR BSD\-3\-Clause
.EE
.UNINDENT
.UNINDENT
.sp
you can choose between GPL\-2.0\-only and BSD\-3\-Clause licensing.
.sp
We use the \X'tty: link http://spdx.org/'\fI\%SPDX\fP\X'tty: link' Unique License Identifiers (\X'tty: link http://spdx.org/licenses/'\fI\%SPDX\-Identifiers\fP\X'tty: link')
.SH LICENSES
.TS
box center;
l|l|l.
T{
Full name
T}	T{
SPDX Identifier
T}	T{
OSI Approved
T}
_
T{
GNU General Public License \X'tty: link http://www.gnu.org/licenses/gpl-2.0.txt'\fI\%v2.0\fP\X'tty: link' only
T}	T{
GPL\-2.0\-only
T}	T{
Y
T}
_
T{
GNU Lesser General Public License \X'tty: link http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt'\fI\%v2.1\fP\X'tty: link' or later
T}	T{
LGPL\-2.1\-or\-later
T}	T{
Y
T}
_
T{
BSD \X'tty: link http://spdx.org/licenses/BSD-1-Clause'\fI\%1\-Clause\fP\X'tty: link' License
T}	T{
BSD\-1\-Clause
T}	T{
Y
T}
_
T{
BSD \X'tty: link http://spdx.org/licenses/BSD-2-Clause'\fI\%2\-Clause\fP\X'tty: link' License
T}	T{
BSD\-2\-Clause
T}	T{
Y
T}
_
T{
BSD \X'tty: link http://spdx.org/licenses/BSD-3-Clause'\fI\%3\-Clause\fP\X'tty: link' \(dqNew\(dq or \(dqRevised\(dq License
T}	T{
BSD\-3\-Clause
T}	T{
Y
T}
_
T{
\X'tty: link https://spdx.org/licenses/MIT.html'\fI\%MIT\fP\X'tty: link' License
T}	T{
MIT
T}	T{
Y
T}
_
T{
Creative Commons Zero 1.0 Universal (\X'tty: link https://spdx.org/licenses/CC0-1.0.html'\fI\%CC0\fP\X'tty: link')
T}	T{
CC0\-1.0
T}	T{
N
T}
_
T{
Creative Commons Attribution Share Alike \X'tty: link https://spdx.org/licenses/CC-BY-SA-4.0.html'\fI\%4.0\fP\X'tty: link'
T}	T{
CC\-BY\-SA\-4.0
T}	T{
Y
T}
_
T{
ISC License (\X'tty: link https://spdx.org/licenses/ISC.html'\fI\%ISC\fP\X'tty: link')
T}	T{
ISC
T}	T{
Y
T}
.TE
.SH SWUPDATE: SOFTWARE UPDATE FOR EMBEDDED SYSTEM
.SS Overview
.sp
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.
.sp
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 \(dqone\-key\-update\(dq, 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).
.sp
The output can be displayed on a LCD using the frame\-buffer
device or directed to a serial line (Linux console).
.sp
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 \fI\%Software collections\fP\&.
.sp
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\(aqs browser via AJAX
notifications.
.SS Features
.SS General Overview
.INDENT 0.0
.IP \(bu 2
Install on embedded Media (eMMC, SD, Raw NAND,
NOR and SPI\-NOR flashes)
.IP \(bu 2
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.
.IP \(bu 2
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.
.IP \(bu 2
new partition schema. This is bound with UBI volume.
SWUpdate can recreate UBI volumes, resizing them and
copying the new software.
.IP \(bu 2
support for compressed images, using the zlib and zstd library.
tarball (tgz file) are supported.
.IP \(bu 2
support for partitioned USB\-pen or unpartitioned (mainly
used by Windows).
.IP \(bu 2
support for updating a single file inside a filesystem.
The filesystem where to put the file must be described.
.IP \(bu 2
checksum for the single components of an image
.IP \(bu 2
use a structured language to describe the image. This is done
using the \X'tty: link http://www.hyperrealm.com/libconfig/'\fI\%libconfig\fP\X'tty: link' library as default parser, that uses a
JSON\-like description.
.IP \(bu 2
use custom\(aqs 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.
.IP \(bu 2
Support for setting / erasing U\-Boot variables
.IP \(bu 2
Support for setting / erasing \X'tty: link https://www.gnu.org/software/grub/manual/html_node/Environment-block.html'\fI\%GRUB\fP\X'tty: link' environment block variables
.IP \(bu 2
Support for setting / erasing \X'tty: link https://github.com/siemens/efibootguard'\fI\%EFI Boot Guard\fP\X'tty: link' variables
.IP \(bu 2
Support for pre and post update commands run before the update starts
processing data and after the update has finished successfully.
.IP \(bu 2
Support for lua hooks, executed before any handler runs.
.IP \(bu 2
Support for preinstall scripts. They run after streamed handlers have
handled their data, and before regular handlers.
.IP \(bu 2
Support for postinstall scripts. They run after updating the images.
.IP \(bu 2
Network installer using an embedded Web\-server (Mongoose Server
was chosen, in the version under Lua license). A different
Web\-server can be used.
.IP \(bu 2
.INDENT 2.0
.TP
.B Multiple interfaces for getting software
.INDENT 7.0
.IP \(bu 2
local Storage: USB, SD, UART,..
.UNINDENT
.UNINDENT
.IP \(bu 2
.INDENT 2.0
.TP
.B OTA / Remote
.INDENT 7.0
.IP \(bu 2
integrated Web\-Server
.IP \(bu 2
pulling from remote Server (HTTP, HTTPS, ..)
.IP \(bu 2
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.
.UNINDENT
.UNINDENT
.IP \(bu 2
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.
.IP \(bu 2
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\(aqs 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.
.IP \(bu 2
allow custom handlers for installing FPGA firmware,
micro\-controller firmware via custom protocols.
.IP \(bu 2
Features are enabled / disabled using \(dqmake menuconfig\(dq.
(Kbuild is inherited from busybox project)
.IP \(bu 2
Images are authenticated and verified before installing
.IP \(bu 2
Power\-Off safe
.UNINDENT
.SS Single image delivery
.sp
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.
.sp
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]
.sp
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 \(dqhandlers\(dq 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.
.sp
For example we can think at a project with a main processor and
one or several micro\-controllers. Let\(aqs 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.
.sp
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.
.SS Streaming feature
.sp
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.
.sp
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 \fBTMPDIR\fP with \fB/tmp\fP as
fall\-back if \fBTMPDIR\fP 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.
.SS Images fully streamed
.sp
In case of remote update, SWUpdate extracts relevant images from the stream
and copies them into the directory pointed to by the environment variable
\fBTMPDIR\fP (if unset, to \fB/tmp\fP) 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 \(dqinstalled\-directly\(dq
in the description of the single image.
.SS Configuration and Build
.SS Requirements
.sp
There are only a few libraries strictly required to compile SWUpdate:
.INDENT 0.0
.IP \(bu 2
\fBzlib\fP (\X'tty: link https://www.zlib.net'\fI\%https://www.zlib.net\fP\X'tty: link')
.IP \(bu 2
\fBlibubootenv\fP for U\-Boot environment support
(\X'tty: link https://github.com/sbabic/libubootenv'\fI\%https://github.com/sbabic/libubootenv\fP\X'tty: link')
.IP \(bu 2
\fBjson\-c\fP for parsing JSON
(\X'tty: link https://github.com/json-c/json-c'\fI\%https://github.com/json\-c/json\-c\fP\X'tty: link')
.UNINDENT
.sp
Further library dependencies may be required when activating more
SWUpdate features, see the next section on \fI\%Configuring SWUpdate\fP\&.
.SS Configuring SWUpdate
.sp
SWUpdate is configurable via \fBmake menuconfig\fP\&. 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.
.sp
To configure the options:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
make menuconfig
.EE
.UNINDENT
.UNINDENT
.SS Building
.sp
To cross\-compile, set the \fBCC\fP and \fBCXX\fP variables before running make.
It is also possible to set the cross\-compiler prefix as option with
\fBmake menuconfig\fP\&. Then, generate the code by running
.INDENT 0.0
.INDENT 3.5
.sp
.EX
make
.EE
.UNINDENT
.UNINDENT
.sp
The result is the binary \fBswupdate\fP\&. Notably, the \fBtools/swupdate\-progress\fP
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.
.SS Building with Yocto
.sp
See the corresponding chapter
\fI\%meta\-swupdate: building with Yocto\fP
on how to build SWUpdate in Yocto.
.SS Distribution Packages
.sp
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
.INDENT 0.0
.IP \(bu 2
\X'tty: link https://packages.debian.org/search?searchon=names&keywords=swupdate'\fI\%Debian\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://packages.ubuntu.com/search?keywords=swupdate'\fI\%Ubuntu\fP\X'tty: link'
.UNINDENT
.sp
Refer to the distribution source package and build system on how to
build a package from source.
.SS Running SWUpdate
.SS What is expected from a SWUpdate run
.sp
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:
.INDENT 0.0
.IP \(bu 2
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.
.IP \(bu 2
if Signed Images is activated, extracts sw\-description.sig and
validate sw\-description.
.IP \(bu 2
check for hardware\-software compatibility, if any,
reading hardware revision from hardware and matching
with the table in sw\-description.
.IP \(bu 2
Parse sw\-description to determine which artefacts in the incoming SWU
are required. Not required artifacts are simply skipped.
If an \(dqembedded\-script\(dq is defined, it is executed at this point
before parsing files.
If \(dqhooks\(dq 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.
.IP \(bu 2
runs the pre update command, if set
.IP \(bu 2
runs partition handlers, if required.
.IP \(bu 2
.INDENT 2.0
.TP
.B reads through the cpio archive one file at a time and either:
.INDENT 7.0
.IP \(bu 2
execute handlers for each file marked as \(dqinstalled\-directly\(dq.
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.
.IP \(bu 2
copy other files to a temporary location while checking checksums,
stopping if there was a mismatch.
.UNINDENT
.UNINDENT
.IP \(bu 2
iterates through all \fIscripts\fP 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 \(dqembedded\-script\(dq or hooks features to ensure code is run
before installation takes place.
.IP \(bu 2
iterates through all \fIimages\fP and call the corresponding
handler for installing on target.
.IP \(bu 2
iterates through all \fIfiles\fP and call the corresponding
handler for installing on target.
.IP \(bu 2
iterates through all \fIscripts\fP and call the corresponding
handler for post\-install scripts
.IP \(bu 2
iterates through all \fIbootenv\fP and updates the bootloader environment.
.IP \(bu 2
reports the status to the operator through the notification interface
(logging, traces) and through the progress interface.
.IP \(bu 2
runs the post update command, if set.
.UNINDENT
.sp
The first step that fails, stops the entire procedure and
an error is reported.
.sp
To start SWUpdate expecting the image from a file:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate \-i <filename>
.EE
.UNINDENT
.UNINDENT
.sp
To start with the embedded web server:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate \-w \(dq<web server options>\(dq
.EE
.UNINDENT
.UNINDENT
.sp
The main important parameters for the web server are \(dqdocument\-root\(dq and \(dqport\(dq.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate \-w \(dq\-\-document\-root ./www \-\-port 8080\(dq
.EE
.UNINDENT
.UNINDENT
.sp
The embedded web server is taken from the Mongoose project.
.sp
The list of available options (depending on activated features) is shown with:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate \-h
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
The default port of the Web\-server is 8080. You can then connect to the target
with:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
http://<target_ip>:8080
.EE
.UNINDENT
.UNINDENT
.sp
If it works, the start page should be displayed as in next figure.
[image]
.sp
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]
.sp
Software collections can be specified by passing \fI\-\-select\fP command
line option. Assuming \fIsw\-description\fP file contains a collection
named \fIstable\fP, with \fIalt\fP installation location, \fISWUpdate\fP can be
called like this:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate \-\-select stable,alt
.EE
.UNINDENT
.UNINDENT
.SS Command line parameters
.TS
box center;
l|l|l.
T{
Parameter
T}	T{
Type
T}	T{
Description
T}
_
T{
\-f <file>
T}	T{
string
T}	T{
SWUpdate configuration file to use.
See \fBexamples/configuration/swupdate.cfg\fP
in the source code for details.
T}
_
T{
\-b <string>
T}	T{
string
T}	T{
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:
\fBswupdate \-b \(dq0 1\(dq\fP\&.
T}
_
T{
\-B <loader>
T}	T{
string
T}	T{
Override the default bootloader interface
to use \fBloader\fP instead.
T}
_
T{
\-e <sel>
T}	T{
string
T}	T{
\fBsel\fP 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 \(dqstable, copy1\(dq  ==> install on copy1
\-e \(dqstable, copy2\(dq  ==> install on copy2
T}
_
T{
.INDENT 0.0
.TP
.B  \-\-excluded
<sel>
.UNINDENT
T}	T{
string
T}	T{
\fBsel\fP is in the format <software>,<mode>.
It sets a 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
T}
_
T{
\-h
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Run usage with help.
T}
_
T{
\-k <file>
T}	T{
string
T}	T{
Available if CONFIG_SIGNED is set.
Filename with the public key.
T}
_
T{
\-K <file>
T}	T{
string
T}	T{
Available on CONFIG_ENCRYPTED_IMAGES set.
Filename with the symmetric key to be used
for decryption.
T}
_
T{
\-\-cert\-purpose
<purpose>
T}	T{
string
T}	T{
Available if CONFIG_SIGNED_IMAGES is set.
Set expected certificate purpose.
T}
_
T{
\-\-forced\-signer\-name <cn>
T}	T{
string
T}	T{
Available if CONFIG_SIGNED_IMAGES is set.
Set expected common name of signer
certificate.
T}
_
T{
\-\-ca\-path <file>
T}	T{
string
T}	T{
Available if CONFIG_SIGNED_IMAGES is set.
Path to the Certificate Authority (PEM).
T}
_
T{
\-\-get\-root
T}	T{
T}	T{
Detect and print the root device and exit
T}
_
T{
\-\-get\-emmc\-
boot
<device>
T}	T{
T}	T{
If devic eis an eMMC, reads the CSD
register and detect from which boot device
has booted (mmcblkXboot0 or mmxblkXboot1)
T}
_
T{
\-l <level>
T}	T{
int
T}	T{
Set loglevel.
T}
_
T{
\-L
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Send LOG output to syslog (local).
T}
_
T{
\-i <file>
T}	T{
string
T}	T{
Run SWUpdate with a local .swu file.
T}
_
T{
\-n
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Run SWUpdate in dry\-run mode.
T}
_
T{
\-N <version>
T}	T{
string
T}	T{
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.
T}
_
T{
.INDENT 0.0
.TP
.BI \-m\fB ax\-version
<version>
.UNINDENT
T}	T{
string
T}	T{
The maximum required version of software.
This will be checked 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.
T}
_
T{
\-R <version>
T}	T{
string
T}	T{
The current installed version of software.
This will be checked with the version of
new software and forbids reinstalling.
T}
_
T{
\-o <file>
T}	T{
string
T}	T{
Save the stream (SWU) to a file.
T}
_
T{
\-s <file>
T}	T{
string
T}	T{
Save installed version info to a file.
T}
_
T{
\-v
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Activate verbose output.
T}
_
T{
\-M
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Disable setting the bootloader transaction
marker.
T}
_
T{
\-m
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Disable setting the update state in the
bootloader.
T}
_
T{
\-w <parms>
T}	T{
string
T}	T{
Available if CONFIG_WEBSERVER is set.
Start internal webserver and pass to it
a command line string.
T}
_
T{
\-d <parms>
T}	T{
string
T}	T{
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.
T}
_
T{
\-u <parms>
T}	T{
string
T}	T{
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.
T}
_
T{
\-H
<board:rev>
T}	T{
string
T}	T{
Available on CONFIG_HW_COMPATIBILITY set.
Set board name and hardware revision.
T}
_
T{
\-c
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Check \fB*.swu\fP file. It ensures that files
referenced in sw\-description are present.
Usage: \fBswupdate \-c \-i <file>\fP
T}
_
T{
\-P <cmd>
T}	T{
string
T}	T{
Execute pre\-update command.
T}
_
T{
\-p <cmd>
T}	T{
string
T}	T{
Execute post\-update command.
T}
_
T{
\-q <sel>
T}	T{
string
T}	T{
.INDENT 0.0
.TP
.B List for software images set and source
that are accepted via IPC
Ex.: stable,main
it can be set multiple times
.UNINDENT
T}
.TE
.SS Downloader command line parameters
.sp
Example: \fBswupdate \-d \(dq\-u example.com\(dq\fP
.sp
Mandatory arguments are marked with \(aq*\(aq:
.TS
box center;
l|l|l.
T{
Parameter
T}	T{
Type
T}	T{
Description
T}
_
T{
\-u <url>
T}	T{
string
T}	T{
* This is the URL where new software is
pulled. URL is a link to a valid .swu image
T}
_
T{
\-r <retries>
T}	T{
integer
T}	T{
Number of retries before a download is
considered broken. With \(dq\-r 0\(dq, SWUpdate
will not stop until a valid software is
loaded.
T}
_
T{
\-w <retrywait>
T}	T{
integer
T}	T{
Time to wait prior to retry and resume a
download (default: 5s).
T}
_
T{
\-t <timeout>
T}	T{
integer
T}	T{
Timeout for connection lost
downloader or Webserver
T}
_
T{
\-a <usr:pwd>
T}	T{
string
T}	T{
Send user and password for Basic Auth
T}
_
T{
\-n <value>
T}	T{
string
T}	T{
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.
T}
.TE
.SS Suricatta command line parameters
.sp
Example: \fBswupdate \-u \(dq\-t default \-u localhost:8080 \-i 1B7\(dq\fP
.sp
Note that different suricatta modules may have different parameters.
The below listed options are for SWUpdate\(aqs hawkBit support.
.sp
Mandatory arguments are marked with \(aq*\(aq:
.TS
box center;
l|l|l.
T{
Parameter
T}	T{
Type
T}	T{
Description
T}
_
T{
\-t <tenant>
T}	T{
string
T}	T{
* Set hawkBit tenant ID for this device.
T}
_
T{
\-u <url>
T}	T{
string
T}	T{
* Host and port of the hawkBit instance,
e.g., localhost:8080
T}
_
T{
\-i <id>
T}	T{
integer
T}	T{
* The device ID to communicate to hawkBit.
T}
_
T{
\-c <confirm>
T}	T{
integer
T}	T{
Confirm update status to server: 1=AGAIN,
2=SUCCESS, 3=FAILED
T}
_
T{
\-x
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Do not abort on flawed server certificates.
T}
_
T{
\-p <polldelay>
T}	T{
integer
T}	T{
Delay in seconds between two hawkBit poll
operations (default: 45s).
T}
_
T{
\-r <retry>
T}	T{
integer
T}	T{
Resume and retry interrupted downloads
(default: 5 tries).
T}
_
T{
\-w <retrywait>
T}	T{
integer
T}	T{
Time to wait prior to retry and resume a
download (default: 5s).
T}
_
T{
\-y <proxy>
T}	T{
string
T}	T{
Use proxy. Either give proxy URL,
else {http,all}_proxy env is tried.
T}
_
T{
\-k <targettoken>
T}	T{
string
T}	T{
Set target token.
T}
_
T{
\-g <gatewaytoken>
T}	T{
string
T}	T{
Set gateway token.
T}
_
T{
\-f <interface>
T}	T{
string
T}	T{
Set the network interface to connect to
hawkBit.
T}
_
T{
\-e
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Daemon enabled at startup (default).
T}
_
T{
\-d
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Daemon disabled at startup.
T}
_
T{
\-\-disable\-token\-for\-dwl
T}	T{
.INDENT 0.0
.IP \(bu 2
.UNINDENT
T}	T{
Do not send authentication header when
downloading SWU.
T}
_
T{
\-\-cache\-file
T}	T{
string
T}	T{
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.
T}
_
T{
\-m <seconds>
T}	T{
integer
T}	T{
Delay in seconds between re\-trying to send
initial feedback specified with \(dq\-c\(dq
option. Default value is 10 seconds. If
Suricatta is started with initial state of
STATE_WAIT (\(dq\-c 6\(dq), this value is ignored.
T}
_
T{
\-s <seconds>
T}	T{
integer
T}	T{
Connection timeout to use in seconds.
If user doesn\(aqt 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!
T}
_
T{
\-a <name> <value>
T}	T{
strings
T}	T{
Custom HTTP header with given name and
value to be sent with every HTTP request
made.
T}
_
T{
\-n <value>
T}	T{
string
T}	T{
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.
T}
.TE
.SS Webserver command line parameters
.sp
Example: \fBswupdate \-w \(dq\-r /www \-p 8080\(dq\fP
.sp
Mandatory arguments are marked with \(aq*\(aq:
.TS
box center;
l|l|l.
T{
Parameter
T}	T{
Type
T}	T{
Description
T}
_
T{
\-r <document root>
T}	T{
string
T}	T{
* Path where the web app is stored.
T}
_
T{
\-p <port>
T}	T{
integer
T}	T{
* TCP port to be listened
if not set, 8080 is used
T}
_
T{
\-s <ssl>
T}	T{
T}	T{
* Enable SSL support. Note: it must be
configured with CONFIG_MONGOOSESSL
T}
_
T{
\-\-ssl\-cert <cert>
T}	T{
string
T}	T{
Path to the certificate to present to
clients
T}
_
T{
\-K <key>
T}	T{
string
T}	T{
Path to key corresponding to ssl
certificate
T}
_
T{
\-t <timeout>
T}	T{
integer
T}	T{
Timeout to consider a connection lost if
clients stops to send data. If hit, an
update is aborted. Default=0 (unlimited)
T}
_
T{
\-\-auth\-domain <string>
T}	T{
string
T}	T{
Set authentication domain
Default: none
T}
_
T{
.INDENT 0.0
.TP
.B  \-\-global\-auth\-file
<string>
.UNINDENT
T}	T{
string
T}	T{
Set authentication file if any
Default: none
T}
.TE
.SS systemd Integration
.sp
SWUpdate has optional \X'tty: link https://www.freedesktop.org/wiki/Software/systemd/'\fI\%systemd\fP\X'tty: link' support via the compile\-time
configuration switch \fBCONFIG_SYSTEMD\fP\&. If enabled, SWUpdate
signals systemd about start\-up completion and can make optional
use of systemd\(aqs socket\-based activation feature.
.sp
A sample systemd service unit file \fB/etc/systemd/system/swupdate.service\fP
may look like the following starting SWUpdate in suricatta daemon mode:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[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 \(aq\-t default \-u http://localhost \-i 25\(aq

[Install]
WantedBy=multi\-user.target
.EE
.UNINDENT
.UNINDENT
.sp
Started via \fBsystemctl start swupdate.service\fP, SWUpdate
(re)creates its sockets on startup. For using socket\-based
activation, an accompanying systemd socket unit file
\fB/etc/systemd/system/swupdate.socket\fP is required:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
[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
.EE
.UNINDENT
.UNINDENT
.sp
On \fBswupdate.socket\fP being started, systemd creates the socket
files and hands them over to SWUpdate when it starts. So, for
example, when talking to \fB/run/swupdate/swupdateprog\fP, systemd
starts \fBswupdate.service\fP and hands\-over the socket files. The
socket files are also handed over on a \(dqregular\(dq start of SWUpdate
via \fBsystemctl start swupdate.service\fP\&.
.sp
Note, that all dependent services need to access the swupdate
sockets via the paths specified in the \fBswupdate.socket\fP systemd
unit.
.SS Changes in boot\-loader code
.sp
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:
.INDENT 0.0
.IP \(bu 2
U\-Boot checks if a sw update is required (check gpio, serial console, etc.).
.IP \(bu 2
the script \(dqaltbootcmd\(dq sets the rules to start SWUpdate
.IP \(bu 2
in case SWUpdate is required, U\-boot run the script \(dqaltbootcmd\(dq
.UNINDENT
.sp
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\(aqs
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.
.sp
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.
.sp
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\(aqs
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.
.SS Image File Format
.sp
SWUpdate uses cpio as image file format because it is a simple,
well\-established, and streamable format. More specifically, the
\fINew ASCII\fP format (header magic number \fB070701\fP) and the
\fINew CRC\fP format (header magic number \fB070702\fP) are supported.
Both formats are essentially equivalent with the New CRC format additionally
having set the cpio header field \fBcheck\fP 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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
Checksum WRONG ! Computed 0xfa11ed00, it should be 0xffffffff
.EE
.UNINDENT
.UNINDENT
.sp
Note that there\(aqs artifact sha256 verification available
(see \fBCONFIG_HASH_VERIFY\fP) which is recommended over relying
on cpio\(aqs checksum facility.
.sp
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.
.SS Building a single image
.sp
cpio is used as container format because of its simplicity and its ability
to be streamed. The meta information file \fBsw\-description\fP (default, see
\fBCONFIG_SETSWDESCRIPTION\fP) describing the images in the container must be
the first file in the cpio archive. The images follow it, in any order.
.sp
To produce an image, a script like the following can be used:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
CONTAINER_VER=\(dq1.0\(dq
PRODUCT_NAME=\(dqmy\-software\(dq
FILES=\(dqsw\-description image1.ubifs  \e
       image2.gz.u\-boot uImage.bin myfile sdcard.img\(dq
for i in $FILES;do
        echo $i;done | cpio \-ov \-H crc >  ${PRODUCT_NAME}_${CONTAINER_VER}.swu
.EE
.UNINDENT
.UNINDENT
.sp
Alternatively, \X'tty: link https://github.com/sbabic/swugenerator/'\fI\%swugenerator\fP\X'tty: link' may be used to generate the image.
.sp
The generated image can be checked by running the following command:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate \-c \-i my\-software_1.0.swu
.EE
.UNINDENT
.UNINDENT
.SS Support of compound image
.sp
A single image can be built automatically inside Yocto.
\X'tty: link https://github.com/sbabic/meta-swupdate'\fI\%meta\-swupdate\fP\X'tty: link' extends the classes with the \fBswupdate\fP class. A recipe
should inherit it and add an own \fBsw\-description\fP file to generate the image.
.sp
Alternatively, \X'tty: link https://github.com/sbabic/swugenerator/'\fI\%swugenerator\fP\X'tty: link' may be used to generate compound images outside Yocto.
.SH UPDATE STRATEGY EXAMPLES
.sp
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.
.SS Single copy \- running as standalone image
.sp
See \fI\%Single copy \- running as standalone image\fP\&.
.SS Double copy with fall\-back
.sp
See \fI\%Double copy with fall\-back\fP\&.
.SS Combine double\-copy with rescue system
.sp
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]
.sp
The rescue system can be updated as well during a standard update.
.SS Split system update with application update
.sp
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]
.SS Configuration update
.sp
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.
.SH SWUPDATE: SYNTAX AND TAGS WITH THE DEFAULT PARSER
.SS Introduction
.sp
SWUpdate uses the library \(dqlibconfig\(dq
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.
.sp
Using the default parser, sw\-description follows the
syntax rules described in the libconfig manual.
Please take a look at \X'tty: link http://www.hyperrealm.com/libconfig/libconfig_manual.html'\fI\%http://www.hyperrealm.com/libconfig/libconfig_manual.html\fP\X'tty: link'
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.
.sp
The following example explains the implemented tags:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;
        description = \(dqFirmware update for XXXXX Project\(dq;

        hardware\-compatibility: [ \(dq1.0\(dq, \(dq1.2\(dq, \(dq1.3\(dq];

        /* partitions tag is used to resize UBI partitions */
        partitions: ( /* UBI Volumes */
                {
                        name = \(dqrootfs\(dq;
                        device = \(dqmtd4\(dq;
                        size = 104896512; /* in bytes */
                },
                {
                        name = \(dqdata\(dq;
                        device = \(dqmtd5\(dq;
                        size = 50448384; /* in bytes */
                }
        );


        images: (
                {
                        filename = \(dqrootfs.ubifs\(dq;
                        volume = \(dqrootfs\(dq;
                },
                {
                        filename = \(dqswupdate.ext3.gz.u\-boot\(dq;
                        volume = \(dqfs_recovery\(dq;
                },
                {
                        filename = \(dqsdcard.ext3.gz\(dq;
                        device = \(dq/dev/mmcblk0p1\(dq;
                        compressed = \(dqzlib\(dq;
                },
                {
                        filename = \(dqbootlogo.bmp\(dq;
                        volume = \(dqsplash\(dq;
                },
                {
                        filename = \(dquImage.bin\(dq;
                        volume = \(dqkernel\(dq;
                },
                {
                        filename = \(dqfpga.txt\(dq;
                        type = \(dqfpga\(dq;
                },
                {
                        filename = \(dqbootloader\-env\(dq;
                        type = \(dqbootloader\(dq;
                }
        );

        files: (
                {
                        filename = \(dqREADME\(dq;
                        path = \(dq/README\(dq;
                        device = \(dq/dev/mmcblk0p1\(dq;
                        filesystem = \(dqvfat\(dq
                }
        );

        scripts: (
                {
                        filename = \(dqerase_at_end\(dq;
                        type = \(dqlua\(dq;
                },
                {
                        filename = \(dqdisplay_info\(dq;
                        type = \(dqlua\(dq;
                }
        );

        bootenv: (
                {
                        name = \(dqvram\(dq;
                        value = \(dq4M\(dq;
                },
                {
                        name = \(dqaddfb\(dq;
                        value = \(dqsetenv bootargs ${bootargs} omapfb.vram=1:2M,2:2M,3:2M omapdss.def_disp=lcd\(dq
                }
        );
}
.EE
.UNINDENT
.UNINDENT
.sp
The first tag is \(dqsoftware\(dq. The whole description is contained in
this tag. It is possible to group settings per device by using \fI\%Board
specific settings\fP\&.
.SS Handling configuration differences
.sp
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.
.sp
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.
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
<?xml version=\(dq1.0\(dq encoding=\(dqUTF\-8\(dq?>
<software version=\(dq1.0\(dq>
  <name>Update Image</name>
  <version>1.0.0</version>
  <description>Firmware for XXXXX Project</description>

  <images>
    <image device=\(dqfirstdevice\(dq version=\(dq0.9\(dq>
      <stream name=\(dqdev1\-uImage\(dq type=\(dqubivol\(dq volume=\(dqkernel\(dq />
      <stream name=\(dqdev1.dtb\(dq type=\(dqubivol\(dq volume=\(dqdtb\(dq />
      <stream name=\(dqdev1\-rootfs.ubifs\(dq type=\(dqubivol\(dq volume=\(dqrootfs\(dq/>
      <stream name=\(dqdev1\-uboot\-env\(dq type=\(dquboot\(dq />
      <stream name=\(dqraw_vfat\(dq type=\(dqraw\(dq dest=\(dq/dev/mmcblk0p4\(dq />
      <stream name=\(dqsdcard.lua\(dq type=\(dqlua\(dq />
    </image>

    <image device=\(dqseconddevice\(dq version=\(dq0.9\(dq>
      <stream name=\(dqdev2\-uImage\(dq type=\(dqubivol\(dq volume=\(dqkernel\(dq />
      <stream name=\(dqdev2.dtb\(dq rev=\(dq0.9\(dq type=\(dqubivol\(dq volume=\(dqdtb\(dq />
      <stream name=\(dqdev2\-rootfs.ubifs\(dq type=\(dqubivol\(dq volume=\(dqrootfs\(dq/>
    </image>
  </images>
</software>
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
Multiple devices are supported by the default parser, too.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
    version = \(dq0.1.0\(dq;

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

    target\-2 = {
            images: (
                    {
                            ...
                    }
            );
    };
}
.EE
.UNINDENT
.UNINDENT
.sp
In this way, it is possible to have a single image providing software
for each device you have.
.sp
By default, the hardware information is extracted from
\fI/etc/hwrevision\fP file. The file should contain a single line in the
following format:
.INDENT 0.0
.INDENT 3.5
<boardname> <revision>
.UNINDENT
.UNINDENT
.sp
Where:
.INDENT 0.0
.IP \(bu 2
\fI<revision>\fP will be used for matching with hardware compatibility
list
.IP \(bu 2
\fI<boardname>\fP can be used for grouping board specific settings
.UNINDENT
.SS Software collections
.sp
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 \fISWUpdate\fP selecting the
appropriate image.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;

        stable = {
                copy\-1: {
                        images: (
                        {
                                device = \(dq/dev/mtd4\(dq
                                ...
                        }
                        );
                }
                copy\-2: {
                        images: (
                        {
                                device = \(dq/dev/mtd5\(dq
                                ...
                        }
                        );
                }
        };
}
.EE
.UNINDENT
.UNINDENT
.sp
In this way it is possible to specify that \fIcopy\-1\fP gets installed to
\fI/dev/mtd4\fP, while \fIcopy\-2\fP to \fI/dev/mtd5\fP\&. By properly selecting the
installation locations, \fISWUpdate\fP will update the firmware in the
other slot.
.sp
The method of image selection is out of the scope of SWUpdate and user
is responsible for calling \fISWUpdate\fP passing proper settings.
.SS Priority finding the elements in the file
.sp
SWUpdate search for entries in the sw\-description file according to the following priority:
.INDENT 0.0
.IP 1. 3
Try <boardname>.<selection>.<mode>.<entry>
.IP 2. 3
Try <selection>.<mode>.<entry>
.IP 3. 3
Try <boardname>.<entry>
.IP 4. 3
Try <entry>
.UNINDENT
.sp
Take an example. The following sw\-description describes the release for a set of boards.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;

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

        stable = {
            copy\-1: {
                  images: (
                      {
                           device = \(dq/dev/mtd6\(dq
                                ...
                      }
                   );
            }
            copy\-2: {
                   images: (
                   {
                           device = \(dq/dev/mtd7\(dq
                                ...
                   }
                   );
            }
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
On \fImyboard\fP, 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. \fImyboard\fP 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.
.SS Using links
.sp
sw\-description can become very complex. Let\(aqs 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 \fImode\fP and selects
the section with \fI\-e stable,<rev number>\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;

        myboard = {
            stable = {

                hardware\-compatibility: [\(dq1.0\(dq, \(dq1.2\(dq, \(dq2.0\(dq, \(dq1.3\(dq, \(dq3.0\(dq, \(dq3.1\(dq];
                rev\-1.0: {
                        images: (
                                ...
                        );
                        scripts: (
                                ...
                        );
                }
                rev\-1.2: {
                        hardware\-compatibility: [\(dq1.2\(dq];
                        images: (
                                ...
                        );
                        scripts: (
                                ...
                        );
                }
                rev\-2.0: {
                        hardware\-compatibility: [\(dq2.0\(dq];
                        images: (
                                ...
                        );
                        scripts: (
                           ...
                        );
                }
                rev\-1.3: {
                        hardware\-compatibility: [\(dq1.3\(dq];
                        images: (
                            ...
                        );
                        scripts: (
                            ...
                        );
                }

                rev\-3.0:
                {
                        hardware\-compatibility: [\(dq3.0\(dq];
                        images: (
                                ...
                        );
                        scripts: (
                                ...
                        );
                }
                rev\-3.1:
                {
                        hardware\-compatibility: [\(dq3.1\(dq];
                        images: (
                                ...
                        );
                        scripts: (
                                ...
                        );
                }
             }
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
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 \(dqref\(dq 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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
 software =
 {
         version = \(dq0.1.0\(dq;

         myboard = {
             stable = {

                 hardware\-compatibility: [\(dq1.0\(dq, \(dq1.2\(dq, \(dq2.0\(dq, \(dq1.3\(dq, \(dq3.0\(dq, \(dq3.1\(dq];
                 rev\-1x: {
                         images: (
                            ...
                         );
                         scripts: (
                             ...
                         );
                 }
                 rev1.0 = {
                         ref = \(dq#./rev\-1x\(dq;
                 }
                 rev1.2 = {
                         ref = \(dq#./rev\-1x\(dq;
                 }
                 rev1.3 = {
                         ref = \(dq#./rev\-1x\(dq;
                 }
                 rev\-2x: {
                         images: (
                              ...
                         );
                         scripts: (
                              ...
                         );
                 }
                 rev2.0 = {
                         ref = \(dq#./rev\-2x\(dq;
                 }

                 rev\-3x: {
                         images: (
                              ...
                         );
                         scripts: (
                               ...
                         );
                 }
                 rev3.0 = {
                         ref = \(dq#./rev\-3x\(dq;
                 }
                 rev3.1 = {
                         ref = \(dq#./rev\-3x\(dq;
                 }
              }
         }
}
.EE
.UNINDENT
.UNINDENT
.sp
The link can be absolute or relative. The keyword \fI\(dqref\(dq\fP 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 \(dqref\(dq. There are
simple rules for a link:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
it must start with the character \(aq#\(aq
.IP \(bu 2
\(dq.\(dq points to the current level in the tree, that means the parent of \(dqref\(dq
.IP \(bu 2
\(dq..\(dq points to the parent level in the tree
.IP \(bu 2
\(dq/\(dq is used as filed separator in the link
.UNINDENT
.UNINDENT
.UNINDENT
.sp
A relative path has a number of
leading \(dq../\(dq to move the current cursor to the parent leaf of the tree.
In the following example, rev40 sets a link to a \(dqcommon\(dq section, where \fIimages\fP
is found. This is sets via a link, too, to a section in the parent node.
The path \fIsoftware.myboard.stable.common.images\fP  is then replaced by
\fIsoftware.myboard.stable.trythis\fP
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
  version = {
          ref = \(dq#./commonversion\(dq;
  }

  hardware\-compatibility = [\(dqrev10\(dq, \(dqrev11\(dq, \(dqrev20\(dq];

  commonversion = \(dq0.7\-linked\(dq;

pc:{
  stable:{

    common:{
        images =
        {
          ref = \(dq#./../trythis\(dq;
        }
      };

    trythis:(
        {
        filename = \(dqrootfs1.ext4\(dq;
        device = \(dq/dev/mmcblk0p8\(dq;
        type = \(dqraw\(dq;
        } ,
        {
        filename = \(dqrootfs5.ext4\(dq;
        device = \(dq/dev/mmcblk0p7\(dq;
        type = \(dqraw\(dq;
        }
      );
    pdm3rev10:
      {
      images:(
          {
          filename = \(dqrootfs.ext3\(dq; device = \(dq/dev/mmcblk0p2\(dq;}
        );
      uboot:(
          { name = \(dqbootpart\(dq;
          value = \(dq0:2\(dq;}
        );
      };
      pdm3rev11 =
      {
        ref = \(dq#./pdm3rev10\(dq;
      }
      pdm3rev20 =
      {
        ref = \(dq#./pdm3rev10\(dq;
      }
      pdm3rev40 =
      {
        ref = \(dq#./common\(dq;
      }
    };
  };
}
.EE
.UNINDENT
.UNINDENT
.sp
Each entry in sw\-description can be redirect by a link as in the above example for the
\(dqversion\(dq attribute.
.SS hardware\-compatibility
.sp
\fBhardware\-compatibility: [ \(dqmajor.minor\(dq, \(dqmajor.minor\(dq, ... ]\fP
.sp
This entry lists the hardware revisions that are compatible with this
software image.
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
hardware\-compatibility: [ \(dq1.0\(dq, \(dq1.2\(dq, \(dq1.3\(dq];
.EE
.UNINDENT
.UNINDENT
.sp
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 \fB#RE:\fP
to the entry. Rewriting the above example would yield:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
hardware\-compatibility: [ \(dq#RE:^1\e.[023]$\(dq ];
.EE
.UNINDENT
.UNINDENT
.sp
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 \fB/etc/hwrevision\fP (or in
another file if specified as configuration option) before SWUpdate is
started.
.SS partitions : UBI layout
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
partitions: (
        {
                name = <volume name>;
                size = <size in bytes>;
                device = <MTD device>;
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
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 \fBdevice\fP\&. \fBdevice\fP can
be specified by number (e.g. \(dqmtd4\(dq) or by name (the name of the MTD
device, e.g. \(dqubi_partition\(dq). The UBI device is attached
automatically.
.sp
The default behavior of swupdate is to create a dynamic UBI volume. To
create a static volume, add a line \fBdata = \(dqstatic\(dq;\fP to the
respective partition entry.
.sp
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.
.SS images
.sp
The tag \(dqimages\(dq collects the image that are installed to the system.
The syntax is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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 */
        .....
);
.EE
.UNINDENT
.UNINDENT
.sp
\fIvolume\fP is only used to install the image in a UBI volume. \fIvolume\fP and
\fIdevice\fP cannot be used at the same time. If device is set,
the raw handler is automatically selected.
.sp
The following example is to update a UBI volume:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqcore\-image\-base.ubifs\(dq;
        volume = \(dqrootfs\(dq;
}
.EE
.UNINDENT
.UNINDENT
.sp
To update an image in raw mode, the syntax is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqcore\-image\-base.ext3\(dq;
        device = \(dq/dev/mmcblk0p1\(dq;
}
.EE
.UNINDENT
.UNINDENT
.sp
To flash an image at a specific offset, the syntax is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqu\-boot.bin\(dq;
        device = \(dq/dev/mmcblk0p1\(dq;
        offset = \(dq16K\(dq;
}
.EE
.UNINDENT
.UNINDENT
.sp
The offset handles the following multiplicative suffixes: K=1024 and M=1024*1024.
.sp
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 \(dqflash\(dq must be selected:
.sp
For example, to copy the kernel into the MTD7 of a NAND flash:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dquImage\(dq;
        device = \(dqmtd7\(dq;
        type = \(dqflash\(dq;
}
.EE
.UNINDENT
.UNINDENT
.sp
The \fIfilename\fP is mandatory. It is the Name of the file extracted by the stream.
\fIvolume\fP is only mandatory in case of UBI volumes. It should be not used
in other cases.
.sp
Alternatively, for the handler “flash”, the \fImtdname\fP can be specified, instead of the device name:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dquImage\(dq;
        mtdname = \(dqkernel\(dq;
        type = \(dqflash\(dq;
}
.EE
.UNINDENT
.UNINDENT
.SS Files
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
files: (
        {
                filename = <Name in CPIO Archive>;
                path = <path in filesystem>;
                device[optional] = <device node >;
                filesystem[optional] = <filesystem for mount>;
                properties[optional] = {create\-destination = \(dqtrue\(dq;}
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
Entries in \(dqfiles\(dq section are managed as single files. The attributes
\(dqfilename\(dq and \(dqpath\(dq are mandatory. Attributes \(dqdevice\(dq and \(dqfilesystem\(dq are
optional; they tell SWUpdate to mount device (of the given filesystem type,
e.g. \(dqext4\(dq) before copying \(dqfilename\(dq to \(dqpath\(dq. Without \(dqdevice\(dq and
\(dqfilesystem\(dq, the \(dqfilename\(dq will be copied to \(dqpath\(dq in the current rootfs.
.sp
As a general rule, swupdate doesn\(aqt copy out a file if the destination path
doesn\(aqt exists. This behavior could be changed using the special property
\(dqcreate\-destination\(dq.
.sp
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
\(dqatomic\-install\(dq property. Setting the property to \(dqtrue\(dq installs the file to
the specified path with \(dq.tmp\(dq appended to the filename. Once the contents of
the file have been written and the buffer is flushed, the \(dq.tmp\(dq file is renamed
to the target file. This minimizes chances that an empty or corrupted file is
created by an interrupted raw file handler.
.SS Scripts
.sp
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.
.sp
They are copied into a temporary directory before execution and their name must
be unique inside the same cpio archive.
.sp
If no type is given, SWUpdate default to \(dqlua\(dq. Please note that running a shell script
opens a set of different security issues, check also chapter \(dqBest practice\(dq.
.SS Lua
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                filename = <Name in CPIO Archive>;
                type = \(dqlua\(dq;
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
Lua scripts are run using the internal interpreter.
.sp
They must have at least one of the following functions:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
function preinst()
.EE
.UNINDENT
.UNINDENT
.sp
SWUpdate scans for all scripts and check for a preinst function. It is
called before installing the images.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
function postinst()
.EE
.UNINDENT
.UNINDENT
.sp
SWUpdate scans for all scripts and check for a postinst function. It is
called after installing the images.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
function postfailure()
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS shellscript
.sp
SWUpdate will run the binary shell \(dq/bin/sh\(dq to execute the script.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                filename = <Name in CPIO Archive>;
                type = \(dqshellscript\(dq;
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
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 \(aqpreinst\(aq, \(aqpostinst\(aq or \(aqpostfailure\(aq as first argument to
the script.
If the data attribute is defined, its value is passed as the last argument(s)
to the script.
.SS preinstall
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                filename = <Name in CPIO Archive>;
                type = \(dqpreinstall\(dq;
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
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 \(dqembedded\-script\(dq 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.
.SS postinstall
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                filename = <Name in CPIO Archive>;
                type = \(dqpostinstall\(dq;
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS Update Transaction and Status Marker
.sp
By default, SWUpdate sets the bootloader environment variable \(dqrecovery_status\(dq
to \(dqin_progress\(dq prior to an update operation and either unsets it or sets it to
\(dqfailed\(dq after the update operation. This is an interface for SWUpdate\-external
tooling: If there is no \(dqrecovery_status\(dq variable in the bootloader\(aqs
environment, the update operation has been successful. Else, if there is
a \(dqrecovery_status\(dq variable with the value \(dqfailed\(dq, the update operation has
not been successful.
.sp
While this is in general essential behavior for firmware updates, it needn\(aqt 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
\(dqbootloader_transaction_marker\(dq which is global per \fIsw\-description\fP file.
It defaults to \fBtrue\fP\&. The following example snippet disables the update
transaction marker:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;
        bootloader_transaction_marker = false;
        ...
.EE
.UNINDENT
.UNINDENT
.sp
It is also possible to disable setting of the transaction marker
entirely (and independently of the setting in \fIsw\-description\fP) by
starting SWUpdate with the \fI\-M\fP option.
.sp
The same applies to setting the update state in the bootloader via its
environment variable \(dqustate\(dq (default) to \fISTATE_INSTALLED=1\fP or
\fISTATE_FAILED=3\fP after an installation. This behavior can be turned off
globally via the \fI\-m\fP option to SWUpdate or per \fIsw\-description\fP via the
boolean switch \(dqbootloader_state_marker\(dq.
.SS reboot flag
.sp
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.
.sp
SWUpdate sends this information to the progress interface and it is duty of the
listeners to interpret the information. The attribute is a boolean:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
reboot = false;
.EE
.UNINDENT
.UNINDENT
.sp
Attribute belongs to the general section, where also version belongs. It is
not required to activate the flag with \fIreboot = true\fP because it is the
default behavior, so just disabling makes sense.
.sp
The tool \fIswupdate\-progress\fP interprets the flag: if it was started with
reboot support (\-r parameter), it checks if a \(dqno\-reboot\(dq 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.
.SS bootloader
.sp
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 \(dqbootloader\(dq 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 \fImenuconfig\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
        {
                filename = \(dqbootloader\-env\(dq;
                type = \(dqbootloader\(dq;
        }
)
.EE
.UNINDENT
.UNINDENT
.sp
The format of the file is described in U\-boot documentation. Each line
is in the format
.INDENT 0.0
.INDENT 3.5
.sp
.EX
<name of variable>=<value>
.EE
.UNINDENT
.UNINDENT
.sp
if value is missing, the variable is unset.
.sp
The format is compatible with U\-Boot \(dqenv import\(dq command. It is possible
to produce the file from target as result of \(dqenv export\(dq.
.sp
Comments are allowed in the file to improve readability, see this example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Default variables
bootslot=0
board_name=myboard
baudrate=115200

## Board Revision dependent
board_revision=1.0
.EE
.UNINDENT
.UNINDENT
.sp
The second way is to define in a group setting the variables
that must be changed:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
bootenv: (
        {
                name = <Variable name>;
                value = <Variable value>;
        }
)
.EE
.UNINDENT
.UNINDENT
.sp
SWUpdate will internally generate a script that will be passed to the
bootloader handler for adjusting the environment.
.sp
For backward compatibility with previously built \fI\&.swu\fP images, the
\(dquboot\(dq group name is still supported as an alias. However, its usage
is deprecated.
.SS SWUpdate persistent variables
.sp
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\(aqs 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 \fIlibubootenv\fP 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 \fInamespaces\fP\&.
SWUpdate should be configured to set the namespace used for own variables. This is done by setting
the attribute \fInamespace\-vars\fP in the runtime configuration file (swupdate.cfg). See also
example/configuration/swupdate.cfg for details.
.sp
The format is the same used with bootloader for single variable:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
vars: (
        {
                name = <Variable name>;
                value = <Variable value>;
        }
)
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS Board specific settings
.sp
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.
.sp
Assuming that the hardware information file \fI/etc/hwrevision\fP contains
the following entry:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
my\-board 0.1.0
.EE
.UNINDENT
.UNINDENT
.sp
and the following description:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;

        my\-board = {
                bootenv: (
                {
                        name = \(dqbootpart\(dq;
                        value = \(dq0:2\(dq;
                }
                );
        };

        bootenv: (
        {
                name = \(dqbootpart\(dq;
                value = \(dq0:1\(dq;
        }
        );
}
.EE
.UNINDENT
.UNINDENT
.sp
SWUpdate will set \fIbootpart\fP to \fI0:2\fP in bootloader\(aqs environment for this
board. For all other boards, \fIbootpart\fP will be set to \fI0:1\fP\&. Board
specific settings take precedence over default scoped settings.
.SS Software collections and operation modes
.sp
Software collections and operations modes extend the description file
syntax to provide an overlay grouping all previous configuration
tags. The mechanism is similar to \fI\%Board specific settings\fP and can
be used for implementing a dual copy strategy or delivering both
stable and unstable images within a single update file.
.sp
The mechanism uses a custom user\-defined tags placed within \fIsoftware\fP
scope. The tag names must not be any of: \fIversion\fP,
\fIhardware\-compatibility\fP, \fIuboot\fP, \fIbootenv\fP, \fIfiles\fP, \fIscripts\fP, \fIpartitions\fP,
\fIimages\fP
.sp
An example description file:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1\(dq;

        hardware\-compatibility = [ \(dqrevA\(dq ];

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

                        bootenv: (
                        {
                                name = \(dqbootpart\(dq;
                                value = \(dq0:2\(dq;
                        }
                        );
                };
                alt:
                {
                        images: (
                        {
                                filename = \(dqrootfs.ext3\(dq;
                                device = \(dq/dev/mmcblk0p1\(dq;
                        }
                        );

                        bootenv: (
                        {
                                name = \(dqbootpart\(dq;
                                value = \(dq0:1\(dq;
                        }
                        );
                };

        };
}
.EE
.UNINDENT
.UNINDENT
.sp
The configuration describes a single software collection named
\fIstable\fP\&. Two distinct image locations are specified for this
collection: \fI/dev/mmcblk0p1\fP and \fI/dev/mmcblk0p2\fP for \fImain\fP mode and
\fIalt\fP mode respectively.
.sp
This feature can be used to implement a dual copy strategy by
specifying the collection and mode explicitly.
.SS Versioning schemas in SWUpdate
.sp
SWUpdate can perform version comparisons for the whole Software by checking
the \fIversion\fP 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.
.SS Numbering schema (default)
.sp
SWUpdate supports a version based on the schema:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
<major>.<minor>.<revision>.<build>
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
1.2.3.4
1.2.3.4.5
1.2.3.4.5.6
.EE
.UNINDENT
.UNINDENT
.sp
But the following is different:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
1.2.3.4\-alpha
.EE
.UNINDENT
.UNINDENT
.sp
And it is treated as semantic version.
.SS Semantic version
.sp
SWUpdate supports \X'tty: link https://semver.org/'\fI\%semantic\fP\X'tty: link' version. See official documentation
for more details.
.SS Checking version of installed software
.sp
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.
.sp
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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
<name of component>     <version>
.EE
.UNINDENT
.UNINDENT
.sp
In sw\-description, the optional attributes \(dqname\(dq, \(dqversion\(dq, and
\(dqinstall\-if\-different\(dq 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.
.sp
If used with \(dqinstall\-if\-different\(dq, then version can be any string.
For example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
bootloader              2015.01\-rc3\-00456\-gd4978d
kernel                  3.17.0\-00215\-g2e876af
.EE
.UNINDENT
.UNINDENT
.sp
There is also an attribute \(dqinstall\-if\-higher\(dq that checks if the version
of the new software is higher than the version of the installed software.
If it\(aqs false, the new software isn\(aqt installed. The goal is to avoid
installing an older version of software.
.sp
In this case, version can be any of 2 formats. Either the version consists
of \fIup to\fP 4 numbers in the range 0..65535 separated by a dot,
e.g. \fI<major>.<minor>.<rev>.<build>\fP,
or it is a \X'tty: link https://semver.org'\fI\%semantic version\fP\X'tty: link'\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
bootloader              2018.03.01
kernel                  3.17.0\-pre1+g2e876af
rfs                     0.17\-foo3.bar5+2020.07.01
app                     1.7
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS Embedded Script
.sp
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.
.sp
These attributes are used for an embedded\-script:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
embedded\-script = \(dq<Lua code>\(dq
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
That means a simple Lua code as:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
print (\(dqTest\(dq)
.EE
.UNINDENT
.UNINDENT
.sp
must be changed to:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
print (\e\(dqTest\e\(dq)
.EE
.UNINDENT
.UNINDENT
.sp
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 \(dqhook\(dq attribute
tells the parser to load the script and to search for the function pointed to by the hook
attribute. For example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
files: (
        {
                filename = \(dqexamples.tar\(dq;
                type = \(dqarchive\(dq;
                path = \(dq/tmp/test\(dq;
                hook = \(dqset_version\(dq;
                preserve\-attributes = true;
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
Each Lua function receives as parameter a table with the setup for the current entry. A hook
in Lua is in the format:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
function lua_hook(image)
.EE
.UNINDENT
.UNINDENT
.sp
image is a table where the keys are the list of available attributes. If an attribute contains
a \(dq\-\(dq, it is replaced with \(dq_\(dq, because \(dq\-\(dq cannot be used in Lua. This means, for example, that:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
install\-if\-different ==> install_if_different
installed\-directly   ==> installed_directly
.EE
.UNINDENT
.UNINDENT
.sp
Attributes can be changed in the Lua script and values are taken over on return.
The Lua function must return 2 values:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
a boolean, to indicate whether the parsing was correct
.IP \(bu 2
the image table or nil to indicate that the image should be skipped
.UNINDENT
.UNINDENT
.UNINDENT
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
function set_version(image)
        print (\e\(dqRECOVERY_STATUS.RUN: \e\(dq.. swupdate.RECOVERY_STATUS.RUN)
        for k,l in pairs(image) do
                swupdate.trace(\e\(dqimage[\e\(dq .. tostring(k) .. \e\(dq] = \e\(dq .. tostring(l))
        end
        image.version = \e\(dq1.0\e\(dq
        image.install_if_different = true
        return true, image
end
.EE
.UNINDENT
.UNINDENT
.sp
The example sets a version for the installed image. Generally, this is detected at runtime
reading from the target.
.SS Attribute reference
.sp
There are 4 main sections inside sw\-description:
.INDENT 0.0
.IP \(bu 2
images: entries are images and SWUpdate has no knowledge
about them.
.IP \(bu 2
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.
.IP \(bu 2
scripts: all entries are treated as executables, and they will
be run twice (as pre\- and post\- install scripts).
.IP \(bu 2
bootenv: entries are pair with bootloader environment variable name and its
value.
.UNINDENT
.SS Attributes in sw\-description
.TS
box center;
l|l|l|l.
T{
Name
T}	T{
Type
T}	T{
Applies to
T}	T{
Description
T}
_
T{
filename
T}	T{
string
T}	T{
images
files
scripts
T}	T{
filename as found in the cpio archive
T}
_
T{
volume
T}	T{
string
T}	T{
images
T}	T{
Just if type = \(dqubivol\(dq. UBI volume
where image must be installed.
T}
_
T{
ubipartition
T}	T{
string
T}	T{
images
T}	T{
Just if type = \(dqubivol\(dq. Volume to be
created or adjusted with a new size
T}
_
T{
device
T}	T{
string
T}	T{
images
files
T}	T{
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 \(dqmtd3\(dq, \(dqmtd\-dtb\(dq,
\(dq/dev/mtd3\(dq and \(dq/dev/mtd\-dtb\(dq are
valid names.
Usage depends on handler.
For files, it indicates on which
device the \(dqfilesystem\(dq must be
mounted. If not specified, the current
rootfs will be used.
T}
_
T{
filesystem
T}	T{
string
T}	T{
files
T}	T{
indicates the filesystem type where
the file must be installed. Only
used if \(dqdevice\(dq attribute is set.
T}
_
T{
path
T}	T{
string
T}	T{
files
T}	T{
For files: indicates the path
(absolute) where the file must be
installed. If \(dqdevice\(dq and
\(dqfilesystem\(dq are set,
SWUpdate will install the
file after mounting \(dqdevice\(dq with
\(dqfilesystem\(dq type. (path is always
relative to the mount point.)
T}
_
T{
preserve\-attributes
T}	T{
bool
T}	T{
files
T}	T{
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
T}
_
T{
type
T}	T{
string
T}	T{
images
files
scripts
T}	T{
string identifier for the handler,
as it is set by the handler when it
registers itself.
Example: \(dqubivol\(dq, \(dqraw\(dq, \(dqrawfile\(dq,
T}
_
T{
compressed
T}	T{
string
T}	T{
images
files
T}	T{
string to indicate the \(dqfilename\(dq is
compressed and must be decompressed
before being installed. the value
denotes the compression type.
currently supported values are \(dqzlib\(dq
and \(dqzstd\(dq.
T}
_
T{
compressed
T}	T{
bool (dep
recated)
T}	T{
images
files
T}	T{
Deprecated. Use the string form. true
is equal to \(aqcompressed = \(dqzlib\(dq\(aq.
T}
_
T{
installed\-directly
T}	T{
bool
T}	T{
images
T}	T{
flag to indicate that image is
streamed into the target without any
temporary copy. Not all handlers
support streaming.
T}
_
T{
name
T}	T{
string
T}	T{
bootenv
T}	T{
name of the bootloader variable to be
set.
T}
_
T{
value
T}	T{
string
T}	T{
bootenv
T}	T{
value to be assigned to the
bootloader variable
T}
_
T{
name
T}	T{
string
T}	T{
images
files
T}	T{
name that identifies the sw\-component
it can be any string and it is
compared with the entries in
sw\-versions
T}
_
T{
version
T}	T{
string
T}	T{
images
files
T}	T{
version for the sw\-component
it can be any string and it is
compared with the entries in
sw\-versions
T}
_
T{
description
T}	T{
string
T}	T{
T}	T{
user\-friendly description of the
swupdate archive (any string)
T}
_
T{
reboot
T}	T{
bool
T}	T{
T}	T{
allows to disable reboot for the
current running update
T}
_
T{
install\-if\-different
T}	T{
bool
T}	T{
images
files
T}	T{
flag
if set, name and version are
compared with the entries in
sw\-versions
T}
_
T{
install\-if\-higher
T}	T{
bool
T}	T{
images
files
T}	T{
flag
if set, name and version are
compared with the entries in
sw\-versions
T}
_
T{
encrypted
T}	T{
bool
T}	T{
images
files
scripts
T}	T{
flag
if set, file is encrypted
and must be decrypted before
installing.
T}
_
T{
ivt
T}	T{
string
T}	T{
images
files
scripts
T}	T{
IVT in case of encrypted artefact
It has no value if \(dqencrypted\(dq 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
T}
_
T{
data
T}	T{
string
T}	T{
images
files
scripts
T}	T{
This is used to pass arbitrary data
to a handler.
T}
_
T{
sha256
T}	T{
string
T}	T{
images
files
scripts
T}	T{
sha256 hash of image, file or script.
Used for verification of signed
images.
T}
_
T{
embedded\-script
T}	T{
string
T}	T{
T}	T{
Lua code that is embedded in the
sw\-description file.
T}
_
T{
offset
T}	T{
string
T}	T{
images
T}	T{
Optional destination offset
T}
_
T{
hook
T}	T{
string
T}	T{
images
files
T}	T{
The name of the function (Lua) to be
called when the entry is parsed.
T}
_
T{
mtdname
T}	T{
string
T}	T{
images
T}	T{
name of the MTD to update. Used only
by the flash handler to identify the
the mtd to update, instead of
specifying the devicenode
T}
_
T{
size
T}	T{
int64
T}	T{
images
files
scripts
T}	T{
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.
T}
.TE
.SH UPDATE IMAGES FROM VERIFIED SOURCE
.sp
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.
.sp
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 ?
.sp
Advantages and disadvantages are described in the following chapter.
.SS Signing the compound image
.sp
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.
.SS Signing the sub\-images
.sp
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.
.SS Combining signing sw\-description with hash verification
.sp
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.
.SS Choice of algorithm
.sp
The algorithm chosen to sign and verify the sw\-description file can be
selected via menuconfig. Currently, the following mechanisms are implemented:
.INDENT 0.0
.IP \(bu 2
RSA Public / private key. The private key belongs to the build system,
while the public key must be installed on the target.
.IP \(bu 2
CMS using certificates
.IP \(bu 2
GPG key signing
.UNINDENT
.sp
For RSA and CMS algorithms, key or certificate is passed to SWUpdate
with the \fI\-k\fP parameter.
.SS Tool to generate keys / certificates
.sp
For RSA and CMS signing, the \fIopenssl\fP tool is used to generate the keys.
This is part of the OpenSSL project. A complete documentation can be found at
the \X'tty: link https://www.openssl.org/docs/manmaster/man1/openssl.html'\fI\%openSSL Website\fP\X'tty: link'\&.
.sp
For GPG, \fIgpg\fP can be used to generate the keys and to sign the images. A complete
documentation can be found at the \X'tty: link https://www.gnupg.org'\fI\%GnuPG Website\fP\X'tty: link'\&.
.SS Usage with RSA PKCS#1.5 or RSA PSS
.SS Generating private and public key
.sp
First, the private key must be created:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl genrsa \-aes256 \-out priv.pem
.EE
.UNINDENT
.UNINDENT
.sp
This asks for a passphrase. It is possible to retrieve
the passphrase from a file \- of course, this must be
protected against intrusion.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl genrsa \-aes256 \-passout file:passout \-out priv.pem
.EE
.UNINDENT
.UNINDENT
.sp
The private key is used to export the public key with:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl rsa \-in priv.pem \-out public.pem \-outform PEM \-pubout
.EE
.UNINDENT
.UNINDENT
.sp
\(dqpublic.pem\(dq contains the key in a format suitable for swupdate. The file
can be passed to swupdate at the command line with the \-k parameter.
.SS How to sign with RSA
.sp
Signing the image with rsa\-pkcs#1.5 is very simple:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl dgst \-sha256 \-sign priv.pem sw\-description > sw\-description.sig
.EE
.UNINDENT
.UNINDENT
.sp
Signing the image with rsa\-pss is also very simple:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl dgst \-sha256 \-sign priv.pem \-sigopt rsa_padding_mode:pss \e
    \-sigopt rsa_pss_saltlen:\-2 sw\-description > sw\-description.sig
.EE
.UNINDENT
.UNINDENT
.SS Usage with certificates and CMS
.SS Generating self\-signed certificates
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl req \-x509 \-newkey rsa:4096 \-nodes \-keyout mycert.key.pem \e
    \-out mycert.cert.pem \-subj \(dq/O=SWUpdate /CN=target\(dq
.EE
.UNINDENT
.UNINDENT
.sp
Check the documentation for more information about parameters. The \(dqmycert.key.pem\(dq contains
the private key and it is used for signing. It is \fInot\fP delivered on the target.
.sp
The target must have \(dqmycert.cert.pem\(dq installed \- this is used by SWUpdate for verification.
.SS Using PKI issued certificates
.sp
It is also possible to use PKI issued code signing certificates. However,
SWUpdate uses OpenSSL library for handling CMS signatures and the library
requires the following attributes to be set on the signing certificate:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
keyUsage=digitalSignature
extendedKeyUsage=emailProtection
.EE
.UNINDENT
.UNINDENT
.sp
It is also possible to completely disable signing certificate key usage
checking if this requirement cannot be satisfied. This is controlled by
\fICONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE\fP configuration option.
.SS How to sign with CMS
.sp
Signing the image is simple as in the previous case:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl cms \-sign \-in  sw\-description \-out sw\-description.sig \-signer mycert.cert.pem \e
        \-inkey mycert.key.pem \-outform DER \-nosmimecap \-binary
.EE
.UNINDENT
.UNINDENT
.SS Usage with GNU PG
.SS Generating a new keypair
.sp
First, a primary keypair needs to be generated
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-\-gen\-key
.EE
.UNINDENT
.UNINDENT
.sp
The generated keys can be listed as follows
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-k
.EE
.UNINDENT
.UNINDENT
.sp
Check the documentation for more information about parameters.
.SS How to sign with gpg
.sp
Signing the image is very simple:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-\-batch \-\-output sw\-description.sig
        \-\-detach\-sig sw\-description
.EE
.UNINDENT
.UNINDENT
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-\-batch \-\-homedir \(dq${GPG_HOMEDIR}\(dq \-\-default\-key \(dq${GPG_KEY}\(dq \-\-output sw\-description.sig
        \-\-detach\-sig sw\-description
.EE
.UNINDENT
.UNINDENT
.SS Building a signed SWU image
.sp
There are two files, sw\-description and its signature sw\-description.sig.
The signature file must always directly follow the description file.
.sp
Each image inside sw\-description must have the attribute \(dqsha256\(dq, 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.
.sp
A simple script to create a signed image can be:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
#!/bin/bash

MODE=\(dqRSA\-PKCS\-1.5\(dq
PRODUCT_NAME=\(dqmyproduct\(dq
CONTAINER_VER=\(dq1.0\(dq
IMAGES=\(dqrootfs kernel\(dq
FILES=\(dqsw\-description sw\-description.sig $IMAGES\(dq

#if you use RSA
if [ x\(dq$MODE\(dq == \(dqxRSA\-PKCS\-1.5\(dq ]; then
    openssl dgst \-sha256 \-sign priv.pem sw\-description > sw\-description.sig
elif if [ x\(dq$MODE\(dq == \(dqxRSA\-PSS\(dq ]; then
    openssl dgst \-sha256 \-sign priv.pem \-sigopt rsa_padding_mode:pss \e
        \-sigopt rsa_pss_saltlen:\-2 sw\-description > sw\-description.sig
elif if [ x\(dq$MODE\(dq == \(dqxGPG\(dq ]; then
    gpg \-\-batch \-\-homedir \(dq${GPG_HOME_DIR}\(dq \-\-default\-key \(dq${GPG_KEY}\(dq \e
        \-\-output sw\-description.sig \-\-detach\-sig sw\-description
else
    openssl cms \-sign \-in  sw\-description \-out sw\-description.sig \-signer mycert.cert.pem \e
        \-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
.EE
.UNINDENT
.UNINDENT
.SS Example for sw\-description with signed image
.sp
The example applies to a Beaglebone, installing Yocto images:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.1.0\(dq;

        hardware\-compatibility: [ \(dqrevC\(dq];

        images: (
                {
                    filename = \(dqcore\-image\-full\-cmdline\-beaglebone.ext3\(dq;
                    device = \(dq/dev/mmcblk0p2\(dq;
                    type = \(dqraw\(dq;
                    sha256 = \(dq43cdedde429d1ee379a7d91e3e7c4b0b9ff952543a91a55bb2221e5c72cb342b\(dq;
                }
        );
        scripts: (
                {
                    filename = \(dqtest.lua\(dq;
                    type = \(dqlua\(dq;
                    sha256 = \(dqf53e0b271af4c2896f56a6adffa79a1ffa3e373c9ac96e00c4cfc577b9bea5f1\(dq;
                 }
        );
}
.EE
.UNINDENT
.UNINDENT
.SS Running SWUpdate with signed images
.sp
Verification is activated by setting CONFIG_SIGNED_IMAGES in SWUpdate\(aqs configuration.
If activated, SWUpdate will always check the compound image. For security reasons,
it is not possible to disable the check at runtime.
.sp
For RSA and CMS signing, the \-k parameter (public key file) is mandatory and the program stops
if the public key is not passed.
.sp
For GPG signing, CONFIG_SIGALG_GPG needs to be enabled. The GPG key will
need to be imported to the device\(aqs GnuPG home directory. To do this, the
key will need to be exported:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-\-export <keyid> \-\-output <public key>
.EE
.UNINDENT
.UNINDENT
.sp
You can then copy it onto the device and import it into your public keyring:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-\-import <public key>
.EE
.UNINDENT
.UNINDENT
.sp
To verify that the key has been imported successfully:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gpg \-\-list\-keys
.EE
.UNINDENT
.UNINDENT
.sp
SWUpdate will need need to be configured with the following parameters:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
GnuPG Home directory: gpg\-home\-dir in swupdate.cfg
GPGME Protocol: gpgme\-protocol in swupdate.cfg: openpgp or cms
.EE
.UNINDENT
.UNINDENT
.SH SYMMETRICALLY ENCRYPTED UPDATE IMAGES
.sp
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.
.SS Building an Encrypted SWU Image
.sp
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
\X'tty: link https://www.openssl.org/docs/manmaster/man1/openssl.html'\fI\%OpenSSL Website\fP\X'tty: link'\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl rand \-hex 32
# key, for example 390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040
openssl rand \-hex 16
# IV, for example d5d601bacfe13100b149177318ebc7a4
.EE
.UNINDENT
.UNINDENT
.sp
Then, encrypt an image using this information via
.INDENT 0.0
.INDENT 3.5
.sp
.EX
openssl enc \-aes\-256\-cbc \-in <INFILE> \-out <OUTFILE> \-K <KEY> \-iv <IV>
.EE
.UNINDENT
.UNINDENT
.sp
where \fB<INFILE>\fP is the unencrypted source image file and \fB<OUTFILE>\fP is the
encrypted output image file to be referenced in \fBsw\-description\fP\&.
\fB<KEY>\fP is the hex value part of the 2nd line of output from the key generation
command above and \fB<IV>\fP is the hex value part of the 3rd line.
.sp
Then, create a key file to be supplied to SWUpdate via the \fI\-K\fP switch by
putting the key and initialization vector hex values on one line
separated by whitespace, e.g., for above example values
.INDENT 0.0
.INDENT 3.5
.sp
.EX
390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040 d5d601bacfe13100b149177318ebc7a4
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
You should change the IV with every encryption, see \X'tty: link http://cwe.mitre.org/data/definitions/329.html'\fI\%CWE\-329\fP\X'tty: link'\&. The \fBivt\fP
sw\-description attribute overrides the key file\(aqs IV for one specific image.
.SS Encryption of UBI volumes
.sp
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.
.sp
See the property \(dqdecrypted\-size\(dq in UBI Volume Handler\(aqs documentation.
.SS Example sw\-description with Encrypted Image
.sp
The following example is a (minimal) \fBsw\-description\fP for installing
a Yocto image onto a Beaglebone. Pay attention to the \fBencrypted = true;\fP
setting.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
        version = \(dq0.0.1\(dq;
        images: ( {
                        filename = \(dqcore\-image\-full\-cmdline\-beaglebone.ext3.enc\(dq;
                        device = \(dq/dev/mmcblk0p3\(dq;
                        encrypted = true;
                        ivt = \(dq65D793B87B6724BB27954C7664F15FF3\(dq;
                }
        );
}
.EE
.UNINDENT
.UNINDENT
.SS Running SWUpdate with Encrypted Images
.sp
Symmetric encryption support is activated by setting the \fBENCRYPTED_IMAGES\fP
option in SWUpdate\(aqs configuration. Use the \fI\-K\fP parameter to provide the
symmetric key file generated above to SWUpdate.
.SS Decrypting with a PKCS#11 token
.sp
PKCS#11 support is activated by setting the \fBPKCS11\fP option in SWUpdate\(aqs
configuration. The key file has to have a PKCS#11 URL instead of the key then,
containing at least the elements of this example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
pkcs11:slot\-id=42;id=%CA%FE%BA%BE?pin\-value=1234&module\-path=/usr/lib/libsofthsm2.so 65D793B87B6724BB27954C7664F15FF3
.EE
.UNINDENT
.UNINDENT
.sp
The encryption key can be imported to the PKCS#11 token by using \fBpkcs11\-tool\fP as follow:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
echo \-n \(dq390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040\(dq |  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
.EE
.UNINDENT
.UNINDENT
.SH HANDLERS
.SS Overview
.sp
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 \fBhandler\fP),
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.
.sp
The parser make the connection between \(aqimage type\(aq and \(aqhandler\(aq.
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.
.SS Supplied handlers
.INDENT 0.0
.TP
.B In mainline there are the handlers for the most common cases. They include:
.INDENT 7.0
.IP \(bu 2
flash devices in raw mode (both NOR and NAND)
.IP \(bu 2
UBI volumes
.IP \(bu 2
UBI volumes partitioner
.IP \(bu 2
raw flashes handler (NAND, NOR, SPI\-NOR, CFI interface)
.IP \(bu 2
disk partitioner
.IP \(bu 2
raw devices, such as a SD Card partition
.IP \(bu 2
bootloader (U\-Boot, GRUB, EFI Boot Guard) environment
.IP \(bu 2
Lua scripts handler
.IP \(bu 2
shell scripts handler
.IP \(bu 2
rdiff handler
.IP \(bu 2
readback handler
.IP \(bu 2
archive (zo, tarballs) handler
.IP \(bu 2
remote handler
.IP \(bu 2
microcontroller update handler
.UNINDENT
.UNINDENT
.sp
For example, if an image is marked to be updated into a UBI volume,
the parser must fill a supplied table setting \(dqubi\(dq as required handler,
and filling the other fields required for this handler: name of volume, size,
and so on.
.SS Creating own handlers
.sp
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.
.sp
The prototype for the callback is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
int my_handler(struct img_type *img,
        void __attribute__ ((__unused__)) *data)
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
The structure \fIimg_type\fP 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.
.sp
The data parameter is usually a pointer that was registered with the
handler. For script handlers it is instead a pointer to a \fBstruct
script_handler_data\fP which contains a \fBscript_fn\fP enum value,
indicating the current installation phase, and the registered data
pointer.
.sp
SWUpdate provides a general function to extract data from the stream and copy
to somewhere else:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
        int skip_file, int compressed, uint32_t *checksum, unsigned char *hash);
.EE
.UNINDENT
.UNINDENT
.sp
fdin is the input stream, that is img\->fdin from the callback. The \fIhash\fP, in case of
signed images, is simply passed to copyfile() to perform the check, exactly as the \fIchecksum\fP
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.
.sp
The handler\(aqs developer registers his own handler with a call to:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
__attribute__((constructor))
void my_handler_init(void)
{
        register_handler(\(dqmytype\(dq, my_handler, my_mask, data);
}
.EE
.UNINDENT
.UNINDENT
.sp
SWUpdate uses the gcc constructors, and all supplied handlers are registered
when SWUpdate is initialized.
.sp
register_handler has the syntax:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
register_handler(my_image_type, my_handler, my_mask, data);
.EE
.UNINDENT
.UNINDENT
.sp
Where:
.INDENT 0.0
.IP \(bu 2
my_image_type : string identifying the own new image type.
.IP \(bu 2
my_handler : pointer to the installer to be registered.
.IP \(bu 2
my_mask : \fBHANDLER_MASK\fP enum value(s) specifying what
input type(s) my_handler can process.
.IP \(bu 2
data : an optional pointer to an own structure, that SWUpdate
saves in the handlers\(aq list and pass to the handler when it will
be executed.
.UNINDENT
.SS UBI Volume Handler
.sp
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 \fBpartitions\fP tag (see
\fI\%partitions : UBI layout\fP).
.sp
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, \fBvolume names must be
unique\fP 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!).
.sp
When updating volumes, it is guaranteed that erase counters are
preserved and not lost. The behavior of updating is identical to that
of the \fBubiupdatevol(1)\fP tool from mtd\-utils. In fact, the same
library from mtd\-utils (libubi) is reused by SWUpdate.
.SS atomic volume renaming
.sp
The UBI volume handler has basic support for carrying out atomic
volume renames by defining the \fBreplaces\fP property, which must
contain a valid UBI volume name. After successfully updating the image
to \fBvolume\fP, an atomic swap of the names of \fBvolume\fP and
\fBreplaces\fP is done. Consider the following example
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename =\(dqu\-boot.img\(dq;
        volume =\(dqu\-boot_r\(dq;
        properties: {
                replaces = \(dqu\-boot\(dq;
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
After u\-boot.img is successfully installed into the volume \(dqu\-boot_r\(dq,
the volume \(dqu\-boot_r\(dq is renamed to \(dqu\-boot\(dq and \(dqu\-boot\(dq is renamed
to \(dqu\-boot_r\(dq.
.sp
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 \fBu\-boot\fP without the need to access the environment. The
volume replace functionality will ensure that this volume name always
points to the currently valid volume.
.sp
However, please note the following limitations:
.INDENT 0.0
.IP \(bu 2
Currently the rename takes place after \fIeach\fP 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.
.IP \(bu 2
Atomic renames are only possible and permitted for volumes residing
on the same UBI device.
.UNINDENT
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                type = \(dqubiswap\(dq;
                properties: {
                        swap\-0 = [ \(dqboot\(dq , \(dq boot_r\(dq ];
                        swap\-1 = [ \(dqkernel\(dq , \(dqkernel_r\(dq ];
                        swap\-2 = [ \(dqrootfs\(dq , \(dqrootfs_r\(dq ];
                },
        },
);
.EE
.UNINDENT
.UNINDENT
.sp
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\(aqs probably not what you want ...
.SS volume auto resize
.sp
The UBI volume handler has support to auto resize before flashing an
image with the property \fBauto\-resize\fP\&. When this property is set
on an image, the ubi volume is resized to fit exactly the image.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqu\-boot.img\(dq;
        device = \(dqmtd0\(dq;
        volume = \(dqu\-boot_r\(dq;
        properties: {
                auto\-resize = \(dqtrue\(dq;
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
WARNING: when this property is used, the device must be defined.
.SS volume always remove
.sp
The UBI volume handler has support to always remove ubi volume
before flashing with the property \fBalways\-remove\fP\&. When this property
is set on an image, the ubi volume is always removed. This property
should be used with property \fBauto\-resize\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqu\-boot.img\(dq;
        device = \(dqmtd0\(dq;
        volume = \(dqu\-boot_r\(dq;
        properties: {
                always\-remove = \(dqtrue\(dq;
                auto\-resize = \(dqtrue\(dq;
        }
}
.EE
.UNINDENT
.UNINDENT
.SS size properties
.sp
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.
.sp
For this reason UBI images can declare the special properties \(dqdecrypted\-size\(dq
or \(dqdecompressed\-size\(dq like this:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: ( {
                filename = \(dqrootfs.ubifs.enc\(dq;
                volume = \(dqrootfs\(dq;
                encrypted = true;
                properties: {
                        decrypted\-size = \(dq104857600\(dq;
                }
        },
        {
                filename = \(dqhomefs.ubifs.gz\(dq;
                volume = \(dqhomefs\(dq;
                compressed = \(dqzlib\(dq;
                properties: {
                        decompressed\-size = \(dq420000000\(dq;
                }
        }
);
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
The sizes are bytes in decimal notation.
.SS Lua Handlers
.sp
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 \fBCONFIG_EMBEDDED_LUA_HANDLER\fP
config option or has to be installed on the target system in Lua\(aqs
search path as \fBswupdate_handlers.lua\fP so that it can be loaded
by the embedded Lua interpreter at run\-time.
.sp
In analogy to C handlers, the prototype for a Lua handler is
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\-\-\- Lua Handler.
\-\-
\-\-\- @param  image  img_type  Lua equivalent of \(gastruct img_type\(ga
\-\-\- @return number           # 0 on success, 1 on error
function lua_handler(image)
    ...
end
.EE
.UNINDENT
.UNINDENT
.sp
where \fBimage\fP is a Lua table (with attributes according to
\fI\%sw\-description\(aqs attribute reference\fP)
that describes a single artifact to be processed by the handler
(also see the Lua Handler Interface Specification in \fBhandlers/swupdate.lua\fP).
.sp
Note that dashes in the attributes\(aq names are replaced with
underscores for the Lua domain to make them idiomatic, e.g.,
\fBinstalled\-directly\fP becomes \fBinstalled_directly\fP in the
Lua domain.
.sp
For a script handler written in Lua, the prototype is
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\-\-\- Lua Handler.
\-\-
\-\-\- @param  image     img_type  Lua equivalent of \(gastruct img_type\(ga
\-\-\- @param  scriptfn  string    Type, one of \(gapreinst\(ga or \(gapostinst\(ga
\-\-\- @return number              # 0 on success, 1 on error
function lua_handler(image, scriptfn)
    ...
end
.EE
.UNINDENT
.UNINDENT
.sp
where \fBscriptfn\fP is either \fB\(dqpreinst\(dq\fP or \fB\(dqpostinst\(dq\fP\&.
.sp
To register a Lua handler, the \fBswupdate\fP module provides the
\fBswupdate.register_handler()\fP method that takes the handler\(aqs
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 \fBlua_handler\fP as \fImy_handler\fP which may be
called for images:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
swupdate.register_handler(\(dqmy_handler\(dq, lua_handler, swupdate.HANDLER_MASK.IMAGE_HANDLER)
.EE
.UNINDENT
.UNINDENT
.sp
A Lua handler may call C handlers (\(dqchaining\(dq) via the
\fBswupdate.call_handler()\fP method. The callable and registered
C handlers are available (as keys) in the table
\fBswupdate.handler\fP\&. The following Lua code is an example of
a simple handler chain\-calling the \fBrawfile\fP C handler:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\-\-\- Lua Handler.
\-\-
\-\-\- @param  image  img_type  Lua equivalent of \(gastruct img_type\(ga
\-\-\- @return number           # 0 on success, 1 on error
function lua_handler(image)
    if not swupdate.handler[\(dqrawfile\(dq] then
        swupdate.error(\(dqrawfile handler not available\(dq)
        return 1
    end
    image.path = \(dq/tmp/destination.path\(dq
    local err, msg = swupdate.call_handler(\(dqrawfile\(dq, image)
    if err ~= 0 then
        swupdate.error(string.format(\(dqError chaining handlers: %s\(dq, msg))
        return 1
    end
    return 0
end
.EE
.UNINDENT
.UNINDENT
.sp
Note that when chaining handlers and calling a C handler for
a different type of artifact than the Lua handler is registered
for, the \fBimage\fP table\(aqs values must satisfy the called
C handler\(aqs expectations: Consider the above Lua handler being
registered for \(dqimages\(dq (\fBswupdate.HANDLER_MASK.IMAGE_HANDLER\fP)
via the \fBswupdate.register_handler()\fP call shown above. As per the
\fI\%sw\-description\(aqs attribute reference\fP,
the \(dqimages\(dq artifact type doesn\(aqt have the \fBpath\fP attribute
but the \(dqfile\(dq artifact type does. So, for calling the \fBrawfile\fP
handler, \fBimage.path\fP has to be set prior to chain\-calling the
\fBrawfile\fP 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 \fBimage\fP represents.
.sp
In addition to calling C handlers, the \fBimage\fP table passed as
parameter to a Lua handler has a \fBimage:copy2file()\fP method that
implements the common use case of writing the input stream\(aqs data
to a file, which is passed as this method\(aqs argument. On success,
\fBimage:copy2file()\fP returns \fB0\fP or \fB\-1\fP plus an error
message on failure. The following Lua code is an example of
a simple handler calling \fBimage:copy2file()\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\-\-\- Lua Handler.
\-\-
\-\-\- @param  image  img_type  Lua equivalent of \(gastruct img_type\(ga
\-\-\- @return number           # 0 on success, 1 on error
function lua_handler(image)
    local err, msg = image:copy2file(\(dq/tmp/destination.path\(dq)
    if err ~= 0 then
        swupdate.error(string.format(\(dqError calling copy2file: %s\(dq, msg))
        return 1
    end
    return 0
end
.EE
.UNINDENT
.UNINDENT
.sp
Beyond using \fBimage:copy2file()\fP or chain\-calling C handlers,
the \fBimage\fP table passed as parameter to a Lua handler has
a \fBimage:read(<callback()>)\fP method that reads from the input
stream and calls the Lua callback function \fB<callback()>\fP for
every chunk read, passing this chunk as parameter. On success,
\fB0\fP is returned by \fBimage:read()\fP\&. On error, \fB\-1\fP plus an
error message is returned. The following Lua code is an example
of a simple handler printing the artifact\(aqs content:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\-\-\- Lua Handler.
\-\-
\-\-\- @param  image  img_type  Lua equivalent of \(gastruct img_type\(ga
\-\-\- @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(\(dqError reading image: %s\(dq, msg))
        return 1
    end
    return 0
end
.EE
.UNINDENT
.UNINDENT
.sp
Using the \fBimage:read()\fP method, an artifact\(aqs contents may be
(post\-)processed in and leveraging the power of Lua without relying
on preexisting C handlers for the purpose intended.
.sp
Just as C handlers, a Lua handler must consume the artifact
described in its \fBimage\fP parameter so that SWUpdate can
continue with the next artifact in the stream after the Lua handler
returns. Chaining handlers, calling \fBimage:copy2file()\fP, or using
\fBimage:read()\fP satisfies this requirement.
.sp
The \fBswupdate\fP Lua module interface specification that details what
functionality is made available to Lua handlers by SWUpdate\(aqs
\fBcorelib/lua_interface.c\fP is found in \fBhandlers/swupdate.lua\fP\&.
It serves as reference, for mocking purposes, and type checking thanks
to the EmmyLua\-inspired annotations.
.sp
Note that although the dynamic nature of Lua handlers would
technically allow one to embed them into a to be processed \fB\&.swu\fP
image, this is not implemented as it carries some security
implications since the behavior of SWUpdate is changed
dynamically.
.SS Shell script handler
.sp
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.
.sp
SWUpdate will run the binary shell \(dq/bin/sh\(dq to execute the script.
.SS Lua script handler
.sp
A Lua Script handler runs a script in Lua language. There are two possible ways to run the
script:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
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
\(dqrequire(swupdate)\(dq.
.IP \(bu 2
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.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
As default, each script runs in isolated / local Lua state. If the property \(dqglobal\-state\(dq is set,
then the common LUa state used for each Update transaction is taken.
.sp
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.
.sp
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.
.sp
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.
.sp
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.
.sp
Note that the handler will load the script in case of global state just once during the \(dqpreinstall\(dq call.
Later, it is assumed that functions will be already available.
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
    {
        filename = \(dqtestscript.lua\(dq;
        type = \(dqlua\(dq;
        properties: {
            global\-state = \(dqtrue\(dq;
            preinstall = \(dqpretest1\(dq;
        }
    },
    {
        filename = \(dqtest2script.lua\(dq;
        type = \(dqlua\(dq;
        properties: {
            global\-state = \(dqtrue\(dq;
            postinstall = \(dqposttest2\(dq;
            postfailure = \(dqfailure\(dq;
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
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
\(dqpretest1\(dq from the first script is called, because no function name is defined for this step with
the following scripts.
.SS Remote handler
.sp
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
\(dqdata\(dq 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 \(dqdata\(dq attribute. For example,
a possible setup using a remote handler could be:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
        {
            filename = \(dqmyimage\(dq\(dq;
            type = \(dqremote\(dq;
            data = \(dqtest_remote\(dq;
         }
)
.EE
.UNINDENT
.UNINDENT
.sp
The connection is instantiated using the socket \fBtest_remote\fP (according
to the \(dqdata\(dq field\(aqs value) in the directory pointed to by the environment
variable \fBTMPDIR\fP with \fB/tmp\fP as fall\-back if \fBTMPDIR\fP is not set.
If \fBconnect()\fP 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:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
first frame contains a string with a command.
.IP \(bu 2
second frame contains data and can be of 0 bytes.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
There are currently just two possible commands: INIT and DATA. After
a successful connect, SWUpdate sends the initialization string in the
format:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
INIT:<size of image to be installed>
.EE
.UNINDENT
.UNINDENT
.sp
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 \fIACK\fP or \fINACK\fP\&. The first NACK received by SWUpdate
will interrupt the update. After sending the INIT command, the remote
handler will send a sequence of \fIDATA\fP 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
\fIACK\fP or \fINACK\fP message.
.SS SWU forwarder
.sp
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 \(dqslaves\(dq 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 \(dqurl\(dq 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\(aqs 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
\fBinstalled\-directly\fP is supported by this handler.
[image]
.sp
The following example shows how to set a SWU as artifact and enables
the SWU forwarder:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
        {
                filename = \(dqimage.swu\(dq;
                type = \(dqswuforward\(dq;

                properties: {
                        url = [\(dqhttp://192.168.178.41:8080\(dq, \(dqhttp://192.168.178.42:8080\(dq];
                };
        });
.EE
.UNINDENT
.UNINDENT
.sp
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 \fIproperties field\fP 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).
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
        {
                filename = \(dqimage.swu\(dq;
                type = \(dqswuforward\(dq;

                properties: {
                        url = [\(dqhttp://192.168.178.41\(dq, \(dqhttp://192.168.178.42];
                        parser\-function = \(dqparse_answer\(dq;
                };
        });
.EE
.UNINDENT
.UNINDENT
.sp
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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
function parse_answer(s)
        if string.match (s, \(aqSUCCESS\(aq) then
                return swupdate.RECOVERY_STATUS.SUCCESS
        end
        if string.match (s, \(aqFAILURE\(aq) then
                return swupdate.RECOVERY_STATUS.FAILURE
        end

        return swupdate.RECOVERY_STATUS.RUN

end\(dq;
.EE
.UNINDENT
.UNINDENT
.sp
The handler evaluates the return value, and stops when one of SUCCESS or FAILURE is returned.
.sp
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.
.SS rdiff handler
.sp
The rdiff handler adds support for applying binary delta patches generated by
\X'tty: link http://librsync.sourcefrog.net/'\fI\%librsync\(aqs\fP\X'tty: link' rdiff tool.
.sp
Naturally, the smaller the difference between the diff\(aqs 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\(aqs 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 \X'tty: link https://reproducible-builds.org'\fI\%reproducible\-builds.org\fP\X'tty: link').
.sp
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\(aqs no need for the
device to, e.g., aid in the difference computation.
.sp
First, create the signature of the original (base) file via
\fBrdiff signature <basefile> <signaturefile>\fP\&.
Then, create the delta file (i.e., patch) from the original base file to the target
file via \fBrdiff delta <signaturefile> <targetfile> <deltafile>\fP\&.
The \fB<deltafile>\fP is the artifact to be applied via this handler on the device.
Essentially, it mimics running \fBrdiff patch <basefile> <deltafile> <targetfile>\fP
on the device. Naturally for patches, the very same \fB<basefile>\fP has to be used
for creating as well as for applying the patch to.
.sp
This handler registers itself for handling files and images.
An exemplary sw\-description fragment for the files section is
.INDENT 0.0
.INDENT 3.5
.sp
.EX
files: (
    {
        type = \(dqrdiff_file\(dq
        filename = \(dqfile.rdiff.delta\(dq;
        path = \(dq/usr/bin/file\(dq;
    }
);
.EE
.UNINDENT
.UNINDENT
.sp
Note that the file referenced to by \fBpath\fP serves as \fB<basefile>\fP and
gets replaced by a temporary file serving as \fB<targetfile>\fP while the rdiff
patch processing.
.sp
An exemplary sw\-description fragment for the images section is
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
    {
        type = \(dqrdiff_image\(dq;
        filename = \(dqimage.rdiff.delta\(dq;
        device = \(dq/dev/mmcblk0p2\(dq;
        properties: {
            rdiffbase = [\(dq/dev/mmcblk0p1\(dq];
        };
    }
);
.EE
.UNINDENT
.UNINDENT
.sp
Here, the property \fBrdiffbase\fP qualifies the \fB<basefile>\fP while the \fBdevice\fP
attribute designates the \fB<targetfile>\fP\&.
Note that there\(aqs no support for the optional \fBoffset\fP attribute in the
\fBrdiff_image\fP handler as there\(aqs currently no apparent use case for it and
skipping over unchanged content is handled well by the rdiff algorithm.
.SS ucfw handler
.sp
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.
.sp
The programming of the firmware shall be:
.INDENT 0.0
.IP 1. 3
Enter firmware update mode (bootloader)
.INDENT 3.0
.INDENT 3.5
.INDENT 0.0
.IP 1. 3
Set \(dqreset line\(dq to logical \(dqlow\(dq
.IP 2. 3
Set \(dqupdate line\(dq to logical \(dqlow\(dq
.IP 3. 3
Set \(dqreset line\(dq to logical \(dqhigh\(dq
.UNINDENT
.UNINDENT
.UNINDENT
.IP 2. 3
Send programming message
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$PROG;<<CS>><CR><LF>
.EE
.UNINDENT
.UNINDENT
.sp
to the microcontroller.  (microcontroller will remain in programming state)
.INDENT 0.0
.IP 3. 3
microcontroller confirms with
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$READY;<<CS>><CR><LF>
.EE
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP 4. 3
Data transmissions package based from mainboard to microcontroller package definition:
.INDENT 3.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
within a package the records are sent one after another without the end of line marker <CR><LF>
.IP \(bu 2
the package is completed with <CR><LF>
.UNINDENT
.UNINDENT
.UNINDENT
.IP 5. 3
The microcontroller requests the next package with $READY;<<CS>><CR><LF>
.IP 6. 3
Repeat step 4 and 5 until the complete firmware is transmitted.
.IP 7. 3
The keypad confirms the firmware completion with $COMPLETED;<<CS>><CR><LF>
.IP 8. 3
.INDENT 3.0
.TP
.B Leave firmware update mode
.INDENT 7.0
.IP 1. 3
Set \(dqUpdate line\(dq to logical \(dqhigh\(dq
.IP 2. 3
Perform a reset over the \(dqreset line\(dq
.UNINDENT
.UNINDENT
.UNINDENT
.sp
<<CS>> : checksum. The checksum is calculated as the two\(aqs complement of
the modulo\-256 sum over all bytes of the message
string except for the start marker \(dq$\(dq.
The handler expects to get in the properties the setup for the reset
and prog gpios. They should be in this format:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
properties = {
        reset = \(dq<gpiodevice>:<gpionumber>:<activelow>\(dq;
        prog = \(dq<gpiodevice>:<gpionumber>:<activelow>\(dq;
}
.EE
.UNINDENT
.UNINDENT
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
    {
        filename = \(dqmicrocontroller\-image\(dq;
        type = \(dqucfw\(dq;
        device = \(dq/dev/ttymxc5\(dq;

        properties: {
            reset =  \(dq/dev/gpiochip0:38:false\(dq;
            prog =  \(dq/dev/gpiochip0:39:false\(dq;
        };
    }
);
.EE
.UNINDENT
.UNINDENT
.SS SSBL Handler
.sp
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 \(dqage\(dq, and it is
incremented after each switch to show which is the active set.
.SS Structure of SSBL Admin
.TS
box center;
l|l.
T{
SSBL Magic Number (29 bit)Name
T}	T{
Age (3 bit)
T}
_
T{
Image Address Offset
T}
_
T{
Image Size
T}
.TE
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                type = \(dqssblswitch\(dq;
                properties: {
                        device = [\(dqmtdX\(dq, \(dqmtdY\(dq];
                        offset = [\(dq0\(dq, \(dq0\(dq];
                        imageoffs = [\(dq0x780000\(dq,  \(dq0xA40000\(dq];
                        imagesize = [\(dq0x800000\(dq, \(dq0x800000\(dq];
                }
}
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS Properties for SSBL handler
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
device
T}	T{
string
T}	T{
MTD device where the SSBL Admin Header is stored
T}
_
T{
offset
T}	T{
hex
T}	T{
Offset of SSBL header inside the MTD device
T}
_
T{
imageoffset
T}	T{
hex
T}	T{
Offset of the image to be loaded by a bootloader
when this SSBL is set.
T}
_
T{
imagesize
T}	T{
hex
T}	T{
Size of the image to be loaded by a bootloader
when this SSBL is set.
T}
.TE
.SS Readback Handler
.sp
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.
.sp
The following example explains how to use this handler:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
{
    device = \(dq/dev/mmcblk2p1\(dq;
    type = \(dqreadback\(dq;
    properties: {
        sha256 = \(dqe7afc9bd98afd4eb7d8325196d21f1ecc0c8864d6342bfc6b6b6c84eac86eb42\(dq;
        size = \(dq184728576\(dq;
        offset = \(dq0\(dq;
    };
}
);
.EE
.UNINDENT
.UNINDENT
.sp
Properties \fBsize\fP and \fBoffset\fP are optional, all the other properties are mandatory.
.SS Properties for readback handler
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
device
T}	T{
string
T}	T{
The partition which shall be verified.
T}
_
T{
type
T}	T{
string
T}	T{
Identifier for the handler.
T}
_
T{
sha256
T}	T{
string
T}	T{
Expected sha256 hash of the partition.
T}
_
T{
size
T}	T{
string
T}	T{
Data size (in bytes) to be verified.
If 0 or not set, the handler will get the
partition size from the device.
T}
_
T{
offset
T}	T{
string
T}	T{
Offset (in bytes) to the start of the partition.
If not set, default value 0 will be used.
T}
.TE
.SS Copy handler
.sp
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 (\fIcopyfrom\fP), 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 \fItype\fP field can set if the handler is active as pre or postinstall script. If not set, the handler
is called twice.
.SS Attributes for copy handler
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
device
T}	T{
string
T}	T{
If set, it is the destination.
T}
_
T{
type
T}	T{
string
T}	T{
One of \(dqpreinstall\(dq or \(dqpostinstall\(dq
T}
.TE
.SS Properties for copy handler
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
size
T}	T{
string
T}	T{
Data size (in bytes) to be copied.
If 0 or not set, the handler will try to find the
size from the device.
T}
_
T{
chain
T}	T{
string
T}	T{
Handler to be called to install the data read
from the \(dqcopyfrom\(dq source.
T}
_
T{
recursive
T}	T{
string
T}	T{
Recursive copy if copyfrom is a directory
(\(dqtrue\(dq or \(dqfalse\(dq)
T}
_
T{
create\-
destination
T}	T{
string
T}	T{
Create the destination path if it does not exist
(\(dqtrue\(dq or \(dqfalse\(dq)
T}
.TE
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts : (
        {
        device = \(dq/dev/mmcblk2p1\(dq;
        type = \(dqcopy\(dq;
        properties : {
                copyfrom = \(dq/dev/mmcblk2p2\(dq;
                type = \(dqpostinstall\(dq;
                chain = \(dqraw\(dq;
        }
}
.EE
.UNINDENT
.UNINDENT
.SS Bootloader handler
.sp
The bootloader handler allows to set bootloader\(aqs environment with a file. The file shold have the format:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# Comments are allowed using the hash char

varname=value
.EE
.UNINDENT
.UNINDENT
.sp
Empty lines are skipped. This simplifies the update of the whole environment instead of setting each variable inside the
\(dqbootenv\(dq section in sw\-description. The property \fInooverride\fP allows to skip variables that are already set in sw\-description. If
not set, variables set in bootenv are overwritten.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
        {
                filename = \(dquEnv.txt\(dq;
                type = \(dqbootloader\(dq;
                properties: {
                        nooverride = \(dqtrue\(dq;
                }
        }
);

bootenv: (
{
        name = \(dqbootenv01key\(dq;
        value = \(dqSOME VALUE\(dq;
});
.EE
.UNINDENT
.UNINDENT
.sp
In the example above, bootenv01key is not overwritten by a value in uEnv.txt because the flag \(dqnooverride\(dq is set.
.SS Archive handler
.sp
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.
.sp
The attribute \fIpreserve\-attributes\fP must be set to preserve timestamps. uid/gid (numeric),
permissions (except +x, always preserved) and extended attributes.
.sp
The property \fIcreate\-destination\fP can be set to the string \fItrue\fP to have swupdate create
the destination path before extraction.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
files: (
        {
                filename = \(dqexamples.tar.zst\(dq;
                type = \(dqarchive\(dq;
                path = \(dq/extract/here\(dq;
                preserve\-attributes = true;
                installed\-directly = true;
                properties: {
                        create\-destination = \(dqtrue\(dq;
                }
        }
);
.EE
.UNINDENT
.UNINDENT
.SS Disk partitioner
.sp
This handler creates or modifies partitions using the library libfdisk. Handler must be put into
the \fIpartitions\fP section of sw\-description. Setup for each partition is put into the \fIproperties\fP 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.)
.SS Properties for diskpart handler
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
labeltype
T}	T{
string
T}	T{
\(dqgpt\(dq or \(dqdos\(dq
T}
_
T{
nolock
T}	T{
string
T}	T{
\(dqtrue\(dq or \(dqfalse\(dq (default=false)
This is like a force. If it is set, a lock failure
will be ignored(lock will still be attempted).
T}
_
T{
noinuse
T}	T{
string
T}	T{
\(dqtrue\(dq or \(dqfalse\(dq (default=false)
If set, it does not require the device to be not
in use (mounted, etc.)
T}
_
T{
partition\-X
T}	T{
array
T}	T{
Array of values belonging to the partition number X
T}
.TE
.sp
For each partition, an array of couples key=value must be given. The following keys are
supported:
.SS Setup for a disk partition
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
size
T}	T{
string
T}	T{
Size of partition. K, M and G can be used for
Kilobytes, Megabytes and Gigabytes.
T}
_
T{
start
T}	T{
integer
T}	T{
First sector for the partition
T}
_
T{
name
T}	T{
string
T}	T{
Name of the partition
T}
_
T{
type
T}	T{
string
T}	T{
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.
T}
_
T{
dostype
T}	T{
string
T}	T{
Type of DOS (MBR) partition entry when using a
table with a \(dqgpt\(dq 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.
T}
_
T{
fstype
T}	T{
string
T}	T{
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
T}
_
T{
partuuid
T}	T{
string
T}	T{
The partition UUID (GPT only). If omitted, a UUID
will be generated automatically.
T}
_
T{
flag
T}	T{
string
T}	T{
The following flags are supported:
Dos Partition : \(dqboot\(dq set bootflag
T}
_
T{
force
T}	T{
string
T}	T{
If set to \(dqtrue\(dq, existing file\-system shall be
overwritten uncoditionally.
Default value is \(dqfalse\(dq.
T}
.TE
.sp
GPT example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
partitions: (
{
   type = \(dqdiskpart\(dq;
   device = \(dq/dev/sde\(dq;
   properties: {
        labeltype = \(dqgpt\(dq;
        partition\-1 = [ \(dqsize=64M\(dq, \(dqstart=2048\(dq,
            \(dqname=bigrootfs\(dq, \(dqtype=C12A7328\-F81F\-11D2\-BA4B\-00A0C93EC93B\(dq];
        partition\-2 = [\(dqsize=256M\(dq, \(dqstart=133120\(dq,
            \(dqname=ldata\(dq, \(dqtype=EBD0A0A2\-B9E5\-4433\-87C0\-68B6B72699C7\(dq,
            \(dqfstype=vfat\(dq];
        partition\-3 = [\(dqsize=512M\(dq, \(dqstart=657408\(dq,
            \(dqname=log\(dq, \(dqfstype =ext4\(dq, 63DAF\-8483\-4772\-8E79\-3D69D8477DE4\(dq];
        partition\-4 = [\(dqsize=4G\(dq, \(dqstart=1705984\(dq,
            \(dqname=system\(dq,  \(dqtype=0FC63DAF\-8483\-4772\-8E79\-3D69D8477DE4\(dq];
        partition\-5 = [\(dqsize=512M\(dq, \(dqstart=10094592\(dq,
            \(dqname=part5\(dq,  \(dqtype=0FC63DAF\-8483\-4772\-8E79\-3D69D8477DE4\(dq];
   }
}
.EE
.UNINDENT
.UNINDENT
.sp
MBR Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
partitions: (
{
   type = \(dqdiskpart\(dq;
   device = \(dq/dev/sde\(dq;
   properties: {
        labeltype = \(dqdos\(dq;
        partition\-1 = [ \(dqsize=64M\(dq, \(dqstart=2048\(dq, \(dqname=bigrootfs\(dq, \(dqtype=0x83\(dq];
        partition\-2 = [\(dqsize=256M\(dq, \(dqstart=133120\(dq, \(dqname=ldata\(dq, \(dqtype=0x83\(dq];
        partition\-3 = [\(dqsize=256M\(dq, \(dqstart=657408\(dq, \(dqname=log\(dq, \(dqtype=0x83\(dq];
        partition\-4 = [\(dqsize=6G\(dq, \(dqstart=1181696\(dq, \(dqname=system\(dq,  \(dqtype=0x5\(dq];
        partition\-5 = [\(dqsize=512M\(dq, \(dqstart=1183744\(dq, \(dqname=part5\(dq,  \(dqtype=0x83\(dq];
        partition\-6 = [\(dqsize=512M\(dq, \(dqstart=2234368\(dq, \(dqname=part6\(dq,  \(dqtype=0x83\(dq];
        partition\-7 = [\(dqsize=16M\(dq, \(dqstart=3284992\(dq, \(dqname=part7\(dq, \(dqtype=0x6\(dq,
            \(dqfstype=vfat\(dq];
   }
}
.EE
.UNINDENT
.UNINDENT
.SS Toggleboot Handler
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
script: (
{
   type = \(dqtoggleboot\(dq;
   device = \(dq/dev/sde\(dq;
   properties: {
        partition = \(dq1\(dq;
   }
}
.EE
.UNINDENT
.UNINDENT
.SS gpt partition installer
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
        {
                filename = \(dqu\-boot.bin\(dq;
                type = \(dqgptpart\(dq;
                device = \(dq/dev/vdb\(dq;
                volume = \(dqu\-boot\-1\(dq;
                offset = \(dq1024\(dq;
        },
        {
                filename = \(dqkernel.bin\(dq;
                type = \(dqgptpart\(dq;
                device = \(dq/dev/vdb\(dq;
                volume = \(dqkernel\-1\(dq;
        },
);
.EE
.UNINDENT
.UNINDENT
.SS gpt partition swap
.sp
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.
.sp
Simple example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: (
        {
                type = \(dqgptswap\(dq;
                device = \(dq/dev/vdb\(dq;
                properties =
                {
                        swap\-0 = [ \(dqu\-boot\-0\(dq , \(dqu\-boot\-1\(dq ];
                        swap\-1 = [ \(dqkernel\-0\(dq , \(dqkernel\-1\(dq ];
                };
        },
);
.EE
.UNINDENT
.UNINDENT
.SS Diskformat Handler
.sp
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 \fBforce\fP to \fBtrue\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
partitions: (
{
        type = \(dqdiskformat\(dq;
        device = \(dq/dev/loop0p1\(dq;

        properties: {
                fstype = \(dqvfat\(dq;
                force = \(dqtrue\(dq;
        }
})
.EE
.UNINDENT
.UNINDENT
.SS Unique UUID Handler
.sp
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.
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
partitions: (
{
        type = \(dquniqueuuid\(dq;
        properties: {
                fs\-uuid = [\(dq21f16cae\-612f\-4bc6\-8ef5\-e68cc9dc4380\(dq,
                           \(dq18e12df1\-d8e1\-4283\-8727\-37727eb4261d\(dq];
        }
});
.EE
.UNINDENT
.UNINDENT
.SS BTRFS Partition Handler
.sp
This handler is activated if support for BTRFS is on. It allows to created and delete subvolumes
during an update.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
partitions: (
{
        type = \(dqbtrfs\(dq;
        device = \(dq/dev/loop0p1\(dq;

        properties: {
                command = < one of create\(dq or \(dqdelete\(dq >
                path = <path for the subvolume>;
                mount = \(dqtrue\(dq or missing;
                create\-destination = \(dqtrue\(dq or missing;
        }
})
.EE
.UNINDENT
.UNINDENT
.sp
If \fImount\fP 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.
.SS BTRFS Snapshot Handler
.sp
The handler allows to install a BTRFS snapshot created with the \(dqbtrfs send\(dq command.
SWUpdate is using the external \(dqbtrfs\(dq utility, that must be installed on the target,
and \(dqbtrfs receive\(dq is executed by sending the stream to the command.
.sp
All generic features are avaiulable, that means that an srtifact can be streamed by
using the \(dqinstalled\-directly\(dq attribute.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
{
        filename = \(dqbtrfs\-snapshot\(dq;
        type = \(dqbtrfs\-receive\(dq;
        device = <optional, device with BTRFS fs, must be set if tomount is \(dqtrue\(dq>;
        properties: {
                path = <mandatory, path where to install subvolume>;
                btrfs\-cmd = <optional, path to btrfs command>;
                tomount = <boolean, optional, \(dqtrue\(dq / \(dqfalse\(dq >;
        }
})
.EE
.UNINDENT
.UNINDENT
.sp
If \fItomount\fP is set, SWUpdate will temporary mount \(dqdevice\(dq as BTRFS filesystem and will try to install
the snapshot to \fIpath\fP\&. \fIbtrfs\-cmd\fP is optional, fallback is /usr/bin/btrfs.
.SS Generic Executor handler
.sp
The BTRFS snapshot handler requires to stream an artifact after normal handling
(decompression, decryption, etc.) to the external command \(dqbtrfs\(dq 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 \(dqexecutor\(dq handler.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqtest\(dq;
        type = \(dqexecutor\(dq;
        properties: {
                cmd = <mandatory, command to be executed in a pipe>;
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
If \fIcreate\-destination\fP is set, SWUpdate will create the destination path of the subvolume before
creating it.
.SS Delta Update Handler
.sp
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.
.sp
The SWU must just contain the ZCK\(aqs 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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
zck \-u \-h sha256 <artifact>
.EE
.UNINDENT
.UNINDENT
.sp
This will generates a file <arifact>.zck. To extract the header, use the \fIzck_read_header\fP
utility:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
HSIZE=\(gazck_read_header \-v <artifact>.zck | grep \(dqHeader size\(dq | cut \-d\(aq:\(aq \-f2\(ga
dd if=<artifact>.zck of=<artifact>.header bs=1 count=$((HSIZE))
.EE
.UNINDENT
.UNINDENT
.sp
The resulting header file must be packed inside the SWU.
.SS Properties for delta update handler
.TS
box center;
l|l|l.
T{
Name
T}	T{
Type
T}	T{
Description
T}
_
T{
url
T}	T{
string
T}	T{
This is the URL from where the handler will
download the missing chunks.
The server must support byte range header.
T}
_
T{
source
T}	T{
string
T}	T{
name of the device or file to be used for
the comparison.
T}
_
T{
chain
T}	T{
string
T}	T{
this is the name (type) of the handler
that is called after reassembling
the artifact.
T}
_
T{
max\-ranges
T}	T{
string
T}	T{
Max number of ranges that a server can
accept. Default value (150) should be ok
for most servers.
T}
_
T{
zckloglevel
T}	T{
string
T}	T{
this sets the log level of the zcklib.
Logs are intercepted by SWupdate and
appear in SWUpdate\(aqs log.
Value is one of debug,info
warn,error,none
T}
_
T{
debug\-chunks
T}	T{
string
T}	T{
\(dqtrue\(dq, 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.
T}
_
T{
source\-size
T}	T{
string
T}	T{
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 \(dqdetect\(dq and the handler
will try to find the effective size of fs.
T}
.TE
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        filename = \(dqsoftware.header\(dq;
        type = \(dqdelta\(dq;

        device = \(dq/dev/mmcblk0p2\(dq;
        properties: {
                url = \(dqhttp://examples.com/software.zck\(dq;
                chain = \(dqraw\(dq;
                source = \(dq/dev/mmcblk0p3\(dq;
                zckloglevel = \(dqerror\(dq;
                /* debug\-chunks = \(dqtrue\(dq; */
        };
}
.EE
.UNINDENT
.UNINDENT
.SS Memory issue with zchunk
.sp
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.
.SS Docker handlers
.sp
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.
.sp
Goal of these handlers is just to provice the few API to update images and start containers \- it
does not implement the full API.
.SS Docker Load Image
.sp
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 \(dqimage\(dq handler. The file
should be in a format accepted by docker.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
{
        filename = \(dqdocker\-image.tar\(dq
        type = \(dqdocker_imageload\(dq;
        installed\-directly = true;
});
.EE
.UNINDENT
.UNINDENT
.sp
The handler checks return value (JSON message) from the daemon, and returns with success if the image
is added.
.sp
In case the file must be decompressed, SWUpdate requires the size of the decompressed image to be
passed to the daemon:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
images: (
{
        filename = \(dqalpine.tar.gz\(dq;
        type = \(dqdocker_imageload\(dq;
        installed\-directly = true;
        compressed = \(dqzlib\(dq;
        properties: {
             decompressed\-size = \(dq5069312\(dq;
        };
});
.EE
.UNINDENT
.UNINDENT
.SS Docker Remove Image
.sp
It is implemented as script (post install).
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: ( {
        type = \(dqdocker_imagedelete\(dq;
        properties: {
                name = \(dqalpine:3.4\(dq;
        };
});
.EE
.UNINDENT
.UNINDENT
.SS Docker Delete Unused Images
.sp
It is implemented as script (post install).
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: ( {
        type = \(dqdocker_imageprune\(dq;
});
.EE
.UNINDENT
.UNINDENT
.SS Docker: container create
.sp
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.
.sp
For example, having this hello\-world.json file:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        \(dqImage\(dq: \(dqhello\-world\(dq,
        \(dqHostConfig\(dq: {
                \(dqRestartPolicy\(dq: {
                        \(dqName\(dq: \(dqalways\(dq
                },
        \(dqAutoRemove\(dq: false
        }
}
.EE
.UNINDENT
.UNINDENT
.sp
Creating the container can be done in sw\-description with:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: ( {
        filename = \(dqhello\-world.json\(dq;
        type = \(dqdocker_containercreate\(dq;
        properties: {
                name = \(dqhelloworld\(dq; /* Name of container */
        }
});
.EE
.UNINDENT
.UNINDENT
.SS Docker Remove Container
.sp
It is implemented as script (post install).
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: ( {
        type = \(dqdocker_containerdelete\(dq;
        properties: {
                name = \(dqhelloworld\(dq;
        };
});
.EE
.UNINDENT
.UNINDENT
.SS Docker : Start / Stop containers
.sp
Examples:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: ( {
        type = \(dqdocker_containerstart\(dq;
        properties: {
                name = \(dqhelloworld\(dq;
        };
});
.EE
.UNINDENT
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
scripts: ( {
        type = \(dqdocker_containerstop\(dq;
        properties: {
                name = \(dqhelloworld\(dq;
        };
});
.EE
.UNINDENT
.UNINDENT
.SH MONGOOSE DAEMON MODE
.SS Introduction
.sp
Mongoose is a daemon mode of SWUpdate that provides a web server, web
interface and web application.
.sp
The web application in \fBweb\-app\fP uses the \X'tty: link https://nodejs.org/en/'\fI\%Node.js\fP\X'tty: link' package manager
and \X'tty: link https://gulpjs.com/'\fI\%gulp\fP\X'tty: link' as build tool. It depends on \X'tty: link https://getbootstrap.com/'\fI\%Bootstrap 4\fP\X'tty: link',
\X'tty: link https://fontawesome.com/'\fI\%Font Awesome 5\fP\X'tty: link' and \X'tty: link http://www.dropzonejs.com/'\fI\%Dropzone.js\fP\X'tty: link'\&.
.SS Startup
.sp
After having configured and compiled SWUpdate with enabled mongoose web
server:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&./swupdate \-\-help
.EE
.UNINDENT
.UNINDENT
.sp
lists the mandatory and optional arguments to be provided to mongoose.
As an example,
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&./swupdate \-l 5 \-w \(aq\-r ./examples/www/v2 \-p 8080\(aq \-p \(aqreboot\(aq
.EE
.UNINDENT
.UNINDENT
.sp
runs SWUpdate in mongoose daemon mode with log\-level \fBTRACE\fP and a web
server at \X'tty: link http://localhost:8080'\fI\%http://localhost:8080\fP\X'tty: link'\&.
.SS Example
.sp
The ready to use example of the web application in  the
\fBexamples/www/v2\fP directory uses a Public Domain \fIbackground.jpg\fP
image from \X'tty: link https://pixabay.com/de/leiterbahn-platine-technologie-3157431/'\fI\%pixabay\fP\X'tty: link' with is released under the Creative Commons CC0
license. The used \fIfavicon.png\fP and \fIlogo.png\fP 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.
.SS Customize
.sp
You could customize the web application inside the \fBweb\-app\fP directory.
Beside the replace of the \fIfavicon.png\fP, \fIlogo.png\fP and \fIbackground.jpg\fP
images inside the \fBimages\fP directory you could customize the Bootstrap
colors and settings inside the \fBscss/bootstrap.scss\fP style sheet. The
style sheet changes need a rebuild of the web application source code.
.SS Develop
.sp
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.
.INDENT 0.0
.IP 1. 3
Enter the web application directory:
.INDENT 3.0
.INDENT 3.5
.sp
.EX
cd ./web\-app
.EE
.UNINDENT
.UNINDENT
.IP 2. 3
Install the dependencies:
.INDENT 3.0
.INDENT 3.5
.sp
.EX
npm install
.EE
.UNINDENT
.UNINDENT
.IP 3. 3
Build the web application:
.INDENT 3.0
.INDENT 3.5
.sp
.EX
npm run build
.EE
.UNINDENT
.UNINDENT
.IP 4. 3
Start the web application:
.INDENT 3.0
.INDENT 3.5
.sp
.EX
\&../swupdate \-w \(aq\-r ./dist \-p 8080\(aq \-p \(aqecho reboot\(aq
.EE
.UNINDENT
.UNINDENT
.IP 5. 3
Test the web application:
.INDENT 3.0
.INDENT 3.5
\X'tty: link http://localhost:8080/'\fI\%http://localhost:8080/\fP\X'tty: link'
.UNINDENT
.UNINDENT
.IP 6. 3
Pack the web application (optional):
.INDENT 3.0
.INDENT 3.5
.sp
.EX
npm run package \-\- \-\-output swupdate\-www.tar.gz
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.SS Contribute
.sp
Please run the linter before any commit
.INDENT 0.0
.INDENT 3.5
.sp
.EX
npm run lint
.EE
.UNINDENT
.UNINDENT
.SH SURICATTA DAEMON MODE
.SS Introduction
.sp
Suricatta is \-\- like mongoose \-\- a daemon mode of SWUpdate, hence the
name suricatta (engl. meerkat) as it belongs to the mongoose family.
.sp
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\(aqs environment ensuring persistent storage across reboots. Some
U\-Boot script logics or U\-Boot\(aqs \fBbootcount\fP 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.
.sp
Suricatta is designed to be extensible in terms of the servers supported
as described in Section \fI\%The Suricatta Interface\fP\&. Currently,
support for the \X'tty: link https://projects.eclipse.org/projects/iot.hawkbit'\fI\%hawkBit\fP\X'tty: link' server is implemented via the \X'tty: link http://sp.apps.bosch-iot-cloud.com/documentation/developerguide/apispecifications/directdeviceintegrationapi.html'\fI\%hawkBit Direct
Device Integration API\fP\X'tty: link' 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.
.SS Running suricatta
.sp
After having configured and compiled SWUpdate with enabled suricatta
support for hawkBit,
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&./swupdate \-\-help
.EE
.UNINDENT
.UNINDENT
.sp
lists the mandatory and optional arguments to be provided to suricatta
when using hawkBit as server. As an example,
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&./swupdate \-l 5 \-u \(aq\-t default \-u http://10.0.0.2:8080 \-i 25\(aq
.EE
.UNINDENT
.UNINDENT
.sp
runs SWUpdate in suricatta daemon mode with log\-level \fBTRACE\fP, polling
a hawkBit instance at \fBhttp://10.0.0.2:8080\fP with tenant \fBdefault\fP
and device ID \fB25\fP\&.
.sp
If multiple server support is compiled in, the \fB\-S\fP / \fB\-\-server\fP
option or a \fBserver\fP entry in the configuration file\(aqs \fB[suricatta]\fP
section selects the one to use at run\-time. For convenience, when having
support for just one server compiled\-in, this is chosen automatically.
.sp
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.
.sp
After an update has been performed, an agent listening on the progress
interface may execute post\-update actions, e.g., a reboot, on receiving
\fBDONE\fP\&.
Additionally, a post\-update command specified in the configuration file or
given by the \fB\-p\fP command line option can be executed.
.sp
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.
.SS The Suricatta Interface
.sp
Support for servers other than hawkBit or the general purpose HTTP server can be
realized by implementing the \(dqinterfaces\(dq described in \fBinclude/channel.h\fP and
\fBinclude/suricatta/server.h\fP, 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 \fBcorelib/channel_curl.c\fP / \fBinclude/channel_curl.h\fP
and \fBsuricatta/server_hawkbit.{c,h}\fP for an example implementation in C targeted
towards hawkBit.
.sp
\fBinclude/channel.h\fP describes the functionality a channel
has to implement:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
typedef struct channel channel_t;
struct channel {
    ...
};

channel_t *channel_new(void);
.EE
.UNINDENT
.UNINDENT
.sp
which sets up and returns a \fBchannel_t\fP struct with pointers to
functions for opening, closing, fetching, and sending data over
the channel.
.sp
\fBinclude/suricatta/server.h\fP describes the functionality a server has
to implement:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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;
.EE
.UNINDENT
.UNINDENT
.sp
These functions constituting a particular suricatta server implementation
have to be registered for being selectable at run\-time by calling
\fBregister_server()\fP (see \fBinclude/suricatta/server.h\fP) with
a name and a \fBserver_t\fP struct pointer implemented in a
\fB__attribute__((constructor))\fP marked function, see
\fBsuricatta/server_hawkbit.c\fP as example.
.sp
The type \fBserver_op_res_t\fP is defined in \fBinclude/suricatta/suricatta.h\fP\&.
It represents the valid function return codes for a server\(aqs implementation.
.sp
In addition to implementing the particular channel and server, the
\fBsuricatta/Kconfig\fP file has to be adapted to include a new option
so that the new implementation becomes selectable in SWUpdate\(aqs
configuration. In the simplest case, adding an option like the following
one for hawkBit into the \fBmenu \(dqServer\(dq\fP section is sufficient.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
config SURICATTA_HAWKBIT
    bool \(dqhawkBit support\(dq
    default y
    select JSON
    help
      Support for hawkBit server.
      https://projects.eclipse.org/projects/iot.hawkbit
.EE
.UNINDENT
.UNINDENT
.sp
Having included the new server implementation into the configuration,
edit \fBsuricatta/Makefile\fP to specify the implementation\(aqs linkage into
the SWUpdate binary, e.g., for the hawkBit example implementation, the
following lines add \fBserver_hawkbit.o\fP to the resulting SWUpdate binary
if \fBSURICATTA_HAWKBIT\fP was selected while configuring SWUpdate.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
ifneq ($(CONFIG_SURICATTA_HAWKBIT),)
obj\-$(CONFIG_SURICATTA) += server_hawkbit.o
endif
.EE
.UNINDENT
.UNINDENT
.SS Support for wfx
.sp
The \X'tty: link https://github.com/siemens/wfx'\fI\%wfx\fP\X'tty: link' server is supported by the Lua Suricatta module
\fBsuricatta/server_wfx.lua\fP (cf. Section \fI\%Support for Suricatta Modules in Lua\fP).
Specifically, it implements a binding to the \X'tty: link https://github.com/siemens/wfx/tree/main/workflow/dau'\fI\%Device Artifact Update\fP\X'tty: link' (DAU) workflow
family.
.sp
If enabled via \fBCONFIG_SURICATTA_WFX\fP, 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 \fI\%Support for Suricatta Modules in Lua\fP\&.
.SS Job Definition
.sp
As being a general purpose workflow executor, wfx doesn\(aqt impose a particular job
definition nor schema, except that it\(aqs 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.
.sp
The wfx Lua Suricatta module understands job definitions as in the following
example (see \fBjob.definition.json_schema\fP in \fBsuricatta/server_wfx.lua\fP):
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
    \(dqversion\(dq: \(dq1.0\(dq,
    \(dqtype\(dq: [\(dqfirmware\(dq, \(dqdummy\(dq],
    \(dqartifacts\(dq: [
        {
            \(dqname\(dq: \(dqExample Device Firmware Artifact\(dq,
            \(dqversion\(dq: \(dq1.1\(dq,
            \(dquri\(dq: \(dqhttp://localhost:8080/download/example_artifact.swu\(dq
        }
    ]
}
.EE
.UNINDENT
.UNINDENT
.sp
The \fBtype\fP list field allows to label update jobs. Labels are sent \fB:\fP\-concatenated
to the progress interface on \fI\%Update Activation\fP\&. The only predefined label \fBfirmware\fP
instructs the wfx Lua Suricatta module to record an installed update to the bootloader
environment (see \fI\%Bootloader Interface\fP).
Within the artifacts list, only the \fBuri\fP field is strictly required for each artifact
while the fields \fBname\fP and \fBversion\fP 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.
.sp
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\(aqs \fBjob.definition = {...}\fP Table.
.SS Workflows
.sp
The two Device Artifact Update (DAU) workflows \X'tty: link https://github.com/siemens/wfx/blob/main/workflow/dau/wfx.workflow.dau.direct.yml'\fI\%wfx.workflow.dau.direct\fP\X'tty: link' and
\X'tty: link https://github.com/siemens/wfx/blob/main/workflow/dau/wfx.workflow.dau.phased.yml'\fI\%wfx.workflow.dau.phased\fP\X'tty: link' are supported by the wfx Lua Suricatta module.
Hint: Use wfx\(aqs \fBwfx\-viewer\fP command line tool to visualize the  YAML
workflows in SVG or PlantUML format.
.sp
For each transition in a workflow for which the \fBeligible\fP field contains
\fBCLIENT\fP, e.g.,
.INDENT 0.0
.INDENT 3.5
.sp
.EX
transitions:
  \- from: <FROM_STATE>
    to: <TO_STATE>
    eligible: CLIENT
.EE
.UNINDENT
.UNINDENT
.sp
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 \fB<FROM_STATE>\fP
to state \fB<TO_STATE>\fP and finally sends the new job status to the wfx, updating it:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
job.workflow.dispatch:set(
    \(dq<FROM_STATE>\(dq,
    \(dq<TO_STATE>\(dq,
    \-\-\- @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 \(ga<TO_STATE>\(ga
                message = (\(dq[%s] <TO_STATE> reached\(dq):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
)
.EE
.UNINDENT
.UNINDENT
.sp
See \fBsuricatta/server_wfx.lua\fP for examples of such transition execution functions.
.sp
New or adapted workflows are supported by appropriately defining/modifying the
transition execution functions in \fBsuricatta/server_wfx.lua\fP \-\- or taking it as
inspiration and creating a new wfx Lua Suricatta module as described in \fI\%Support
for Suricatta Modules in Lua\fP\&.
.SS Update Activation
.sp
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.
.sp
When the activation step is executed, the wfx Lua Suricatta module sends a progress
message (see \fI\%Getting information on running update\fP) upon which a progress client executes or schedules
activation measures. For example, the following JSON is sent as the progress
message\(aqs \fB\&.info\fP field on activation of the \fI\%Job Definition\fP example given above:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
    \(dqstate\(dq: \(dqACTIVATING\(dq,
    \(dqprogress\(dq: 100,
    \(dqmessage\(dq: \(dqfirmware:dummy\(dq
}
.EE
.UNINDENT
.UNINDENT
.sp
The progress message\(aqs \fB\&.status\fP is \fBPROGRESS\fP, see \fBtools/swupdate\-progress.c\fP
for details on how a progress client can be implemented.
.sp
\fBNote:\fP 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.
.sp
Because of the (predefined) \fBfirmware\fP 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 \fBfirmware\fP label present, the wfx Lua Suricatta module records
the installed update to the bootloader environment. If this label was missing, no such
recording would\(aqve been made which is suitable for, e.g., configuration or
application updates.
.sp
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 \fIUpdate Transaction and Status Marker\fP and \fIbootloader\fP in
\fI\%SWUpdate: syntax and tags with the default parser\fP).
.sp
Hence, for firmware updates requiring a test\-boot into the new firmware, the
following properties should be set in the \fB\&.swu\fP file\(aqs \fBsw\-description\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
    bootloader_transaction_marker = true;
    bootloader_state_marker = false;
    ...
.EE
.UNINDENT
.UNINDENT
.sp
For configuration or application updates, the following properties apply:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
software =
{
    bootloader_transaction_marker = false;
    bootloader_state_marker = false;
    ...
.EE
.UNINDENT
.UNINDENT
.SS Support for general purpose HTTP server
.sp
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\(aqs a simple (mock)
server implementation available in \fBexamples/suricatta/server_general.py\fP\&.
.sp
The API consists of a GET with Query parameters to inform the server about the installed version.
The query string has the format:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
http(s)://<base URL>?param1=val1&param2=value2...
.EE
.UNINDENT
.UNINDENT
.sp
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 \(dqidentify\(dq section of
the configuration file and encodes the URL.
.sp
The server answers with the following return codes:
.TS
box center;
l|l|l.
T{
HTTP Code
T}	T{
Text
T}	T{
Description
T}
_
T{
302
T}	T{
Found
T}	T{
A new software is available at URL in the Location header
T}
_
T{
400
T}	T{
Bad Request
T}	T{
Some query parameters are missing or in wrong format
T}
_
T{
403
T}	T{
Forbidden
T}	T{
Client certificate not valid
T}
_
T{
404
T}	T{
Not found
T}	T{
No update is available for this device
T}
_
T{
503
T}	T{
Unavailable
T}	T{
An update is available but server can\(aqt handle another
update process now.
T}
.TE
.sp
Server\(aqs answer can contain the following headers:
.TS
box center;
l|l|l.
T{
Header\(aqs name
T}	T{
Codes
T}	T{
Description
T}
_
T{
Retry\-after
T}	T{
503
T}	T{
Contains a number which tells the device how long to wait
until ask the next time for updates. (Seconds)
T}
_
T{
Content\-MD5
T}	T{
302
T}	T{
Contains the checksum of the update file which is available
under the url of location header
T}
_
T{
Location
T}	T{
302
T}	T{
URL where the update file can be downloaded.
T}
.TE
.sp
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.
.sp
The URL for the logging can be set as separate URL in the configuration file or via
\-\-logurl command line parameter:
.sp
The device sends data in a CSV format (Comma Separated Values). The format is:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
value1,value2,...
.EE
.UNINDENT
.UNINDENT
.sp
The format can be specified in the configuration file. A \fIformat\fP For each \fIevent\fP can be set.
The supported events are:
.TS
box center;
l|l.
T{
Event
T}	T{
Description
T}
_
T{
check
T}	T{
dummy. It could send an event each time the server is
polled.
T}
_
T{
started
T}	T{
A new software is found and SWUpdate starts to install it
T}
_
T{
success
T}	T{
A new software was successfully installed
T}
_
T{
fail
T}	T{
Failure by installing the new software
T}
.TE
.sp
The \fIgeneral server\fP has an own section inside the configuration file. As example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
gservice =
{
        url             = ....;
        logurl          = ;
        logevent : (
                {event = \(dqcheck\(dq; format=\(dq#2,date,fw,hw,sp\(dq},
                {event = \(dqstarted\(dq; format=\(dq#12,date,fw,hw,sp\(dq},
                {event = \(dqsuccess\(dq; format=\(dq#13,date,fw,hw,sp\(dq},
                {event = \(dqfail\(dq; format=\(dq#14,date,fw,hw,sp\(dq}
        );
}
.EE
.UNINDENT
.UNINDENT
.sp
\fIdate\fP is a special field and it is interpreted as localtime in RFC 2822 format. Each
Comma Separated field is looked up inside the \fIidentify\fP 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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
identify : (
        { name = \(dqsp\(dq; value = \(dq333\(dq; },
        { name = \(dqhw\(dq; value = \(dqipse\(dq; },
        { name = \(dqfw\(dq; value = \(dq1.0\(dq; }
);
.EE
.UNINDENT
.UNINDENT
.sp
with the events set as above, the formatted text in case of \(dqsuccess\(dq will be:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
Formatted log: #13,Mon, 17 Sep 2018 10:55:18 CEST,1.0,ipse,333
.EE
.UNINDENT
.UNINDENT
.SS Support for Suricatta Modules in Lua
.sp
The \fBserver_lua.c\fP C\-to\-Lua bridge enables writing suricatta modules in Lua. It
provides the infrastructure in terms of the interface to SWUpdate \(dqcore\(dq to the Lua
realm, enabling the \(dqbusiness logic\(dq such as handling update flows and communicating
with backend server APIs to be modeled in Lua. To the Lua realm, the \fBserver_lua.c\fP
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 \fI\%The Suricatta Interface\fP to the Lua realm.
.sp
As an example server implementation, see \fBexamples/suricatta/server_general.py\fP for
a simple (mock) server of a backend that\(aqs modeled after the \(dqGeneral Purpose HTTP
Server\(dq (cf. Section \fI\%Support for general purpose HTTP server\fP). The matching Lua
suricatta module is found in \fBexamples/suricatta/swupdate_suricatta.lua\fP\&. Place it in
Lua\(aqs path so that a \fBrequire(\(dqswupdate_suricatta\(dq)\fP can load it or embed it into the
SWUpdate binary by enabling \fBCONFIG_EMBEDDED_SURICATTA_LUA\fP and setting
\fBCONFIG_EMBEDDED_SURICATTA_LUA_SOURCE\fP accordingly.
.sp
The interface specification in terms of a Lua (suricatta) module is found in
\fBsuricatta/suricatta.lua\fP\&.
.SS \fIsuricatta\fP
.sp
The \fBsuricatta\fP table is the module\(aqs main table housing the exposed functions and
definitions via the sub\-tables described below.
In addition, the main functions \fBsuricatta.install()\fP and \fBsuricatta.download()\fP
as well as the convenience functions \fBsuricatta.getversion()\fP, \fBsuricatta.sleep()\fP,
and \fBsuricatta.get_tmpdir()\fP are exposed:
.sp
The function \fBsuricatta.install(install_channel)\fP installs an update artifact from
a remote server or a local file. The \fBinstall_channel\fP 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 \fBinstall_channel\fP
table may look like this:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ channel = chn, url = \(dqhttps://artifacts.io/update.swu\(dq }
.EE
.UNINDENT
.UNINDENT
.sp
where \fBchn\fP is the return value of a call to \fBchannel.open()\fP\&. The other table
attributes, like \fBurl\fP in this example, are channel options diverging from or
omitted while channel creation time, see \fI\%suricatta.channel\fP\&. For installing
a local file, an \fBinstall_channel\fP table may look like this:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ channel = chn, url = \(dqfile:///path/to/file.swu\(dq }
.EE
.UNINDENT
.UNINDENT
.sp
The function \fBsuricatta.download(download_channel, localpath)\fP just downloads an
update artifact. The parameter \fBdownload_channel\fP is as for \fBsuricatta.install()\fP\&.
The parameter \fBlocalpath\fP designates the output path for the artifact. The
\fBsuricatta.get_tmpdir()\fP function (see below) is in particular useful for this case
to supply a temporary download location as \fBlocalpath\fP\&. A just downloaded artifact
may be installed later using \fBsuricata.install()\fP with an appropriate \fBfile://\fP
URL, realizing a deferred installation.
.sp
Both, \fBsuricatta.install()\fP and \fBsuricatta.download()\fP return \fBtrue\fP, or, in
case of error, \fBnil\fP, a \fBsuricatta.status\fP value, and a table with messages in
case of errors, else an empty table.
.nf

.fi
.sp
.sp
The function \fBsuricatta.getversion()\fP returns a table with SWUpdate\(aqs \fBversion\fP
and \fBpatchlevel\fP fields. This information can be used to determine API
(in\-)compatibility of the Lua suricatta module with the SWUpdate version running it.
.sp
The function \fBsuricatta.sleep(seconds)\fP is a wrapper around \fISLEEP(3)\fP for, e.g.,
implementing a REST API call retry mechanism after a number of given seconds have
elapsed.
.sp
The function \fBsuricatta.get_tmpdir()\fP returns the path to SWUpdate\(aqs temporary
working directory where, e.g., the \fBsuricatta.download()\fP function may place the
downloaded artifacts.
.SS \fIsuricatta.status\fP
.sp
The \fBsuricatta.status\fP table exposes the \fBserver_op_res_t\fP enum values defined in
\fBinclude/util.h\fP to the Lua realm.
.SS \fIsuricatta.notify\fP
.sp
The \fBsuricatta.notify\fP table provides the usual logging functions to the Lua
suricatta module matching their uppercase\-named pendants available in the C realm.
.sp
One notable exception is \fBsuricatta.notify.progress(message)\fP which dispatches the
message to the progress interface (see \fI\%Getting information on running update\fP). Custom progress client
implementations listening and acting on custom progress messages can be realized
using this function.
.sp
All notify functions return \fBnil\fP\&.
.SS \fIsuricatta.pstate\fP
.sp
The \fBsuricatta.pstate\fP table provides a binding to SWUpdate\(aqs (persistent) state
handling functions defined in \fBinclude/state.h\fP, however, limited to the bootloader
environment variable \fBSTATE_KEY\fP defined by \fBCONFIG_UPDATE_STATE_BOOTLOADER\fP and
defaulting to \fBustate\fP\&. In addition, it captures the \fBupdate_state_t\fP enum values.
.sp
The function \fBsuricatta.pstate.save(state)\fP requires one of \fBsuricatta.pstate\fP\(aqs
\(dqenum\(dq values as parameter and returns \fBtrue\fP, or, in case of error, \fBnil\fP\&.
The function \fBsuricatta.pstate.get()\fP returns one of \fBsuricatta.pstate\fP\(aqs
\(dqenum\(dq values or, in case of error, \fBSTATE_ERROR\fP\&.
.SS \fIsuricatta.server\fP
.sp
The \fBsuricatta.server\fP table provides the sole function
\fBsuricatta.server.register(function_p, purpose)\fP\&. It registers a Lua function
\(dqpointed\(dq to by \fBfunction_p\fP for the purpose \fBpurpose\fP which is defined by
\fBsuricatta.server\fP\(aqs \(dqenum\(dq values. Those enum values correspond to the functions
defined in the interface outlined in the Section on \fI\%The Suricatta Interface\fP\&.
.sp
In addition to these functions, the two callback functions \fBCALLBACK_PROGRESS\fP and
\fBCALLBACK_CHECK_CANCEL\fP can be registered optionally: The former can be used to upload
progress information to the server while the latter serves as \fBdwlwrdata\fP function
(see \fBinclude/channel_curl.h\fP) to decide on whether an installation should be aborted
while the download phase.
.sp
For details on the (callback) functions and their signatures, see the interface
specification \fBsuricatta/suricatta.lua\fP and the documented example Lua suricatta
module found in \fBexamples/suricatta/swupdate_suricatta.lua\fP\&.
.sp
The \fBsuricatta.server.register()\fP function returns \fBtrue\fP, or, in case of error,
\fBnil\fP\&.
.SS \fIsuricatta.channel\fP
.sp
The \fBsuricatta.channel\fP table captures channel handling for suricatta Lua modules.
The single function \fBsuricatta.channel.open(options)\fP creates and opens a channel
to a server. Its single parameter \fBoptions\fP is a table specifying the channel\(aqs
default options such as \fIproxy\fP, \fIretries\fP, \fIusessl\fP, \fIstrictssl\fP, or
\fIheaders_to_send\fP\&. For convenience, options that may change per request such as
\fIurl\fP, \fIcontent\-type\fP, or \fIheaders_to_send\fP 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 \fBsuricatta.channel.options\fP
table. In essence, the \fBoptions\fP parameter table is the Lua table equivalent of
\fBinclude/channel_curl.h\fP\(aqs \fBchannel_data_t\fP\&.
.sp
The \fBsuricatta.channel.open(options)\fP function returns a channel table which is
either passed to the \fBsuricatta.install()\fP and \fBsuricatta.download()\fP functions
or used directly for communication with a server. More specifically, it has the three
functions
.INDENT 0.0
.IP \(bu 2
\fBget(options)\fP for retrieving information from the server,
.IP \(bu 2
\fBput(options)\fP for sending information to the server, and
.IP \(bu 2
\fBclose()\fP for closing the channel.
.UNINDENT
.sp
The \fBget()\fP and \fBput()\fP functions\(aq single parameter \fBoptions\fP is a per\-request
channel option table as described above.
.sp
The functions \fBget()\fP and \fBput()\fP return \fBtrue\fP, or, in case of error, \fBnil\fP,
a \fBsuricatta.status\fP value, and an operation result table.
The latter contains the fields:
.INDENT 0.0
.IP \(bu 2
\fBhttp_response_code\fP carrying the HTTP error code,
.IP \(bu 2
\fBformat\fP as one of \fBsuricatta.channel.content\fP\(aqs options,
.IP \(bu 2
\fBraw_reply\fP if \fBoptions\fP contained \fBformat = suricatta.channel.content.RAW\fP,
.IP \(bu 2
\fBjson_reply\fP if \fBoptions\fP contained \fBformat = suricatta.channel.content.JSON\fP, and
.IP \(bu 2
the HTTP headers received in the \fBreceived_headers\fP table, if any.
.UNINDENT
.sp
The \fBsuricatta.channel.content\fP \(dqenum\(dq table defines the \(dqformat\(dq, i.e., the response
body content type and whether to parse it or not:
.INDENT 0.0
.IP \(bu 2
\fBNONE\fP means the response body is discarded.
.IP \(bu 2
\fBRAW\fP means the raw server\(aqs reply is available as \fBraw_reply\fP\&.
.IP \(bu 2
\fBJSON\fP means the server\(aqs JSON reply is parsed into a Lua table and available
as \fBjson_reply\fP\&.
.UNINDENT
.sp
The \fBsuricatta.channel.method\fP \(dqenum\(dq table defines the HTTP method to use for
a request issued with the \fBput(options)\fP function, i.e., \fIPOST\fP, \fIPATCH\fP, or \fIPUT\fP as
specified in the \fBoptions\fP parameter table via the \fBmethod\fP attribute.
In addition to the HTTP method, the request body\(aqs content is set with the
\fBrequest_body\fP attribute in the \fBoptions\fP parameter table.
.sp
As a contrived example, consider the following call to a channel\(aqs \fBput()\fP function
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&...
local res, _, data = channel.put({
        url          = string.format(\(dq%s/%s\(dq, base_url, device_id),
        content_type = \(dqapplication/json\(dq,
        method       = suricatta.channel.method.PATCH,
        format       = suricatta.channel.content.NONE,
        request_body = \(dq{ ... }\(dq
    })
\&...
.EE
.UNINDENT
.UNINDENT
.sp
that issues a HTTP \fIPATCH\fP to some URL with a JSON content without having interest in
the response body.
.sp
More examples of how to use a channel can be found in the example suricatta Lua
module \fBexamples/suricatta/swupdate_suricatta.lua\fP\&.
.SS \fIsuricatta.bootloader\fP
.sp
The \fBsuricatta.bootloader\fP table exposes SWUpdate\(aqs bootloader environment
modification functions to suricatta Lua modules.
.sp
The enum\-like table \fBsuricatta.bootloader.bootloaders\fP holds the bootloaders
SWUpdate supports, i.e.
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.INDENT 3.5
.sp
.EX
suricatta.bootloader.bootloaders = {
    EBG   = \(dqebg\(dq,
    NONE  = \(dqnone\(dq,
    GRUB  = \(dqgrub\(dq,
    UBOOT = \(dquboot\(dq,
},
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.UNINDENT
.sp
The function \fBsuricatta.bootloader.get()\fP returns the currently selected
bootloader in terms of a \fBsuricatta.bootloader.bootloaders\fP field value.
.sp
The function \fBsuricatta.bootloader.is(name)\fP takes one of
\fBsuricatta.bootloader.bootloaders\fP\(aqs field values as \fBname\fP and returns
\fBtrue\fP if it is the currently selected bootloader, \fBfalse\fP otherwise.
.sp
The functions in the \fBsuricatta.bootloader.env\fP table interact with the
currently selected bootloader\(aqs environment:
.sp
The function \fBsuricatta.bootloader.env.get(variable)\fP retrieves the value
associated to \fBvariable\fP from the bootloader\(aqs environment.
.sp
The function \fBsuricatta.bootloader.env.set(variable, value)\fP sets the
bootloader environment\(aqs key \fBvariable\fP to \fBvalue\fP\&.
.sp
The function \fBsuricatta.bootloader.env.unset(variable)\fP deletes the bootloader
environment\(aqs key \fBvariable\fP\&.
.sp
The function \fBsuricatta.bootloader.env.apply(filename)\fP applies
all key=value lines of a local file \fBfilename\fP to the currently selected
bootloader\(aqs environment.
.SH CONFIG FOR HAWKBIT UNDER SSL/TLS USING PRIVATE CA / SUB CA
.sp
A user\-contributed recipe based on hawkBit (0.2.0\-SNAPSHOT) + swupdate (v2018.03)
.SS Purpose
.sp
Use HTTPS on a hawkBit server to avoid server spoofing. Anonymous client connections are authorized.
.SS Recipe
.INDENT 0.0
.IP 1. 3
On the PKI:
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
Create a pkcs#12 (\fB\&.p12\fP) file, rolling server key, server, private CA, sub CA certs into a single file.
.IP \(bu 2
Use a password on the server key you won\(aqt be ashamed of.
.IP \(bu 2
Also create a single \fB\&.pem\fP file for the private CA + sub\-CA
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP 2. 3
On the hawkBit host:
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
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.
.IP \(bu 2
It looks like a JKS like this cannot have a password different from the one protecting the \fB\&.p12\fP\&. Keytool also seems to have a little tendency to destruct the \fB\&.jks\fP 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 \fB\&.jks\fP file.
.UNINDENT
.sp
The following command imports a \fB\&.p12\fP into a \(dqpkcs12 Java keystore\(dq, keeping the same password:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
keytool \-importkeystore \-srckeystore hb\-pass.p12 \-srcstoretype pkcs12 \e
        \-destkeystore hb\-pass.jks \-deststoretype pkcs12 \e
        \-alias 1 \-deststorepass <password_of_p12>
.EE
.UNINDENT
.UNINDENT
.sp
Then you need to adapt \fBapplication.properties\fP of the hawkBit server to make use of the keystore.
There are extra requirements to make hawkBit send artifacts via HTTPS.
.sp
This is the relevant part of \fB<hawkBit dir>/hawkbit\-runtime/hawkbit\-update\-server/src/main/resources/application.properties\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# 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
\&...
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP 3. 3
On the swupdate client host(s):
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
The client needs the private CA certificate(s) to authenticate the server.
.IP \(bu 2
There is a setting in swupdate to specify the path to a single CA cert, not a directory. Beyond that, libcurl looks into \fB/etc/ssl/certs\fP\&. So we\(aqre using a compound \(dqCA chain\(dq \fB\&.pem\fP file to hold both private CA and sub\-CA in our preferred location.
.UNINDENT
.sp
This is the relevant part of \fB/etc/swupdate/swupdate.conf\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&...
suricatta :
{
 tenant = \(dqdefault\(dq;
 id = \(dqmachineID\(dq;
 url = \(dqhttps://hb.domain:8443\(dq;
 nocheckcert = false;
 cafile = \(dq/etc/swupdate/priv\-cachain.pem\(dq; /* CA + sub CA in one file */
 /* sslkey = anon client: do not set; */
 /* sslcert = anon client: do not set; */
\&...
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.UNINDENT
.SH SWUPDATE: API FOR EXTERNAL PROGRAMS
.SS Overview
.sp
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.
.sp
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.
.SS API Description
.sp
The communication runs via Unix Domain Socket (UDS). The socket path
is determined by
.INDENT 0.0
.IP \(bu 2
the \fBCONFIG_SOCKET_CTRL_PATH\fP compile\-time configuration,
.IP \(bu 2
\fB$RUNTIME_DIRECTORY/sockinstctrl\fP if \fB$RUNTIME_DIRECTORY\fP is set,
.IP \(bu 2
\fB$TMPDIR/sockinstctrl\fP if \fB$TMPDIR\fP is set, or
.IP \(bu 2
\fB/tmp/sockinstctrl\fP,
.UNINDENT
.sp
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.
.sp
The exchanged packets are described in network_ipc.h
.INDENT 0.0
.INDENT 3.5
.sp
.EX
typedef struct {
        int magic;
        int type;
        msgdata data;
} ipc_message;
.EE
.UNINDENT
.UNINDENT
.sp
Where the fields have the meaning:
.INDENT 0.0
.IP \(bu 2
magic : a magic number as simple proof of the packet
.IP \(bu 2
type : one of REQ_INSTALL, ACK, NACK,
GET_STATUS, POST_UPDATE, SWUPDATE_SUBPROCESS, SET_AES_KEY
.IP \(bu 2
msgdata : a buffer used by the client to send the image
or by SWUpdate to report back notifications and status.
.UNINDENT
.sp
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.
.sp
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]
.sp
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.
.SS Client Library
.SS Functions to start an update
.sp
A library simplifies the usage of the IPC making available a way to
start asynchronously an update.
.sp
The library consists of one function and several call\-backs.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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);
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
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.
.sp
The terminated call\-back is called when SWUpdate has finished with the result
of the upgrade.
.sp
Example about using this library is in the examples/client directory.
.sp
The \fIreq\fP structure is casted to void to ensure API compatibility. Am user
should instantiate it as \fIstruct swupdate_request\fP\&. This contains fields that can control
the update process:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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];
};
.EE
.UNINDENT
.UNINDENT
.sp
A user should first call \fIswupdate_prepare_req()\fP
.INDENT 0.0
.INDENT 3.5
.sp
.EX
void swupdate_prepare_req(struct swupdate_request *req);
.EE
.UNINDENT
.UNINDENT
.sp
This fills the request structure with default values. After that, the user can fill the
other fields as:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
\fIsourcetype\fP : one of SOURCE_UNKNOWN, SOURCE_WEBSERVER,
SOURCE_SURICATTA, SOURCE_DOWNLOADER, SOURCE_LOCAL
.IP \(bu 2
\fIdry_run\fP : one of RUN_DEFAULT (set from command line), RUN_DRYRUN, RUN_INSTALL.
.IP \(bu 2
\fIinfo, len\fP : a variable length data that can be forwarded to the progress
interface. The installer in SWUpdate does not evaluate it.
.IP \(bu 2
\fIsoftware_set\fP and \fIrunning_mode\fP : this allows one to set the \fIselection\fP for the update,
it should be accepted by swupdate (\-q, \-\-accepted\-select option when swupdate is launched).
.UNINDENT
.UNINDENT
.UNINDENT
.SS Functions to set AES keys
.sp
The key for decryption can be set with command line parameter (see \fI\-K\fP), but it is possible
to set it via IPC. In this way, each update could have a different key.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
int swupdate_set_aes(char *key, char *ivt)
.EE
.UNINDENT
.UNINDENT
.sp
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 \fImust\fP be 64 bytes for key and 32 bytes for IVT.
.SS Functions to control SWUpdate
.INDENT 0.0
.INDENT 3.5
.sp
.EX
int ipc_send_cmd(ipc_message *msg);
.EE
.UNINDENT
.UNINDENT
.sp
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 \fItype\fP to SWUPDATE_SUBPROCESS.
The caller must then set the other fields in message according to the destination.
The msgdata field is a structure as:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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
                         */
   }
.EE
.UNINDENT
.UNINDENT
.sp
The caller fills \fIsource\fP with the subprocess that accepts the command. Values of cmd
are in \fInetwork_ipc.h\fP\&.
.SS Messages for suricatta
.sp
suricatta accepts messages in JSON format. The message must be formatted in the \fIbuf\fP field of
the message data.
.SS Setting the polling time
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ \(dqpolling\(dq : <value in seconds, range 0..X>}
.EE
.UNINDENT
.UNINDENT
.sp
Setting it to 0 has the special meaning that the polling time is retrieved from the Backend
(if this is supported by the server).
.SS Enable / disable Suricatta daemon
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ \(dqenable\(dq : true }
{ \(dqenable\(dq : false }
.EE
.UNINDENT
.UNINDENT
.SS Set custom device attributes for Suricatta (for Hawkbit implementation)
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ \(dqidentify\(dq : [
    {
        \(dqname\(dq  : \(dqcustomizableAttributeOne\(dq,
        \(dqvalue\(dq : \(dqvalueOne\(dq
    },
    {
        \(dqname\(dq  : \(dqcustomizableAttributeTwo\(dq,
        \(dqvalue\(dq : \(dqvalueTwo\(dq
    }
]}
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS Trigger a check on the server
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ \(dqtrigger\(dq : true }
.EE
.UNINDENT
.UNINDENT
.SS Activate an already installed Software
.sp
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.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ \(dqid\(dq : <action id>,
  \(dqfinished\(dq : \(dqsuccess\(dq, \(dqfailure\(dq, \(dqnone\(dq,
  \(dqexecution\(dq : [\(dqclosed\(dq, \(dqproceeding\(dq, canceled\(dq, \(dqrejected\(dq, \(dqresumed\(dq]
  \(dqdetails\(dq : [ ]
}
.EE
.UNINDENT
.UNINDENT
.SS Get hawkBit Server Status
.sp
To provide the hawkBit server status to other processes, it can be requested by
sending an empty message with message type CMD_GET_STATUS.
.sp
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)
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{ \(dqserver\(dq : {
                \(dqstatus\(dq : <status>
                \(dqtime\(dq : <time>
             }
}
.EE
.UNINDENT
.UNINDENT
.sp
An example application can be found under tools/swupdate\-gethawkbitstatus.c
.SS API to the integrated Webserver
.sp
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:
.INDENT 0.0
.IP \(bu 2
Install API to push a SWU and to restart the device after update.
.IP \(bu 2
A WebSocket interface to send the status of the update process.
.UNINDENT
.SS Install API
.INDENT 0.0
.INDENT 3.5
.sp
.EX
POST /upload
.EE
.UNINDENT
.UNINDENT
.sp
This initiates an update: the initiator sends the request and start to stream the SWU in the same
way as described in \fI\%API Description\fP\&.
The \fBPOST /upload\fP request contains:
.INDENT 0.0
.IP \(bu 2
the SWU file in its body
.IP \(bu 2
the following header field
.INDENT 2.0
.INDENT 3.5
\fBContent\-Type: multipart/form\-data; boundary...\fP
.UNINDENT
.UNINDENT
.UNINDENT
.sp
For example to stream the SWU file and start the update procedure using \fBcurl\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
curl \-F file=@update_file.swu http://host:8080/upload
.EE
.UNINDENT
.UNINDENT
.SS Restart API
.INDENT 0.0
.INDENT 3.5
.sp
.EX
POST /restart
.EE
.UNINDENT
.UNINDENT
.sp
If configured (see post update command), this request will restart the device.
.SS WebSocket API
.sp
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.
.sp
The response contains the field type, that defines which event is sent.
.SS Event Type
.TS
box center;
l|l.
T{
type
T}	T{
Description of event
T}
_
T{
status
T}	T{
Event sent when SWUpdate\(aqs internal state changes
T}
_
T{
source
T}	T{
Event to inform from which interface an update is received
T}
_
T{
info
T}	T{
Event with custom message to be passed to an external process
T}
_
T{
message
T}	T{
Event that contains the error message in case of error
T}
_
T{
step
T}	T{
Event to inform about the running update
T}
.TE
.SS Status Change Event
.sp
This event is sent when the internal SWUpdate status change. Following status are supported:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
IDLE
START
RUN
SUCCESS
FAILURE
DONE
.EE
.UNINDENT
.UNINDENT
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        \(dqtype\(dq: \(dqstatus\(dq,
        \(dqstatus\(dq: \(dqSUCCESS\(dq
}
.EE
.UNINDENT
.UNINDENT
.SS Source Event
.sp
This event informs from which interface a SWU is loaded.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        \(dqtype\(dq: \(dqsource\(dq,
        \(dqsource\(dq: \(dqWEBSERVER\(dq
}
.EE
.UNINDENT
.UNINDENT
.sp
The field \fIsource\fP can have one of the following values:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
UNKNOWN
WEBSERVER
SURICATTA
DOWNLOADER
LOCAL
.EE
.UNINDENT
.UNINDENT
.SS Info Event
.sp
This event forwards all internal logs sent with level=INFO.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        \(dqtype\(dq: \(dqinfo\(dq,
        \(dqsource\(dq: < text message >
}
.EE
.UNINDENT
.UNINDENT
.SS Message Event
.sp
This event contains the error message in case of failure.
.SS Fields for message event
.TS
box center;
l|l.
T{
name
T}	T{
Description
T}
_
T{
status
T}	T{
\(dqmessage\(dq
T}
_
T{
level
T}	T{
\(dq3\(dq in case of error, \(dq6\(dq as info
T}
_
T{
text
T}	T{
Message associated to the event
T}
.TE
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        \(dqtype\(dq: \(dqmessage\(dq,
        \(dqlevel\(dq: \(dq3\(dq,
        \(dqtext\(dq : \(dq[ERROR] : SWUPDATE failed [0] ERROR core/cpio_utils.c : \(dq,
}
.EE
.UNINDENT
.UNINDENT
.SS Step event
.sp
This event contains which is the current step running and which percentage of this step is currently installed.
.SS Fields for step event
.TS
box center;
l|l.
T{
name
T}	T{
Description
T}
_
T{
number
T}	T{
total number of steps N for this update
T}
_
T{
step
T}	T{
running step in range [1..N]
T}
_
T{
name
T}	T{
filename of artefact to be installed
T}
_
T{
percent
T}	T{
percentage of the running step
T}
.TE
.sp
Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{
        \(dqtype\(dq: \(dqstep\(dq,
        \(dqnumber\(dq: \(dq7\(dq,
        \(dqstep\(dq: \(dq2\(dq,
        \(dqname\(dq: \(dqrootfs.ext4.gz\(dq,
        \(dqpercent\(dq: \(dq18\(dq
}
.EE
.UNINDENT
.UNINDENT
.SH GETTING INFORMATION ON RUNNING UPDATE
.sp
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 (\(dqprogress API\(dq). 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.
.SS API Description
.sp
An external process registers itself to SWUpdate with a connect()
request to the domain socket \(dq/tmp/swupdateprog\(dq 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):
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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 */
};
.EE
.UNINDENT
.UNINDENT
.sp
The single fields have the following meaning:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
\fImagic\fP is not yet used, it could be added for simply verification of the frame.
.IP \(bu 2
\fIstatus\fP is one of the values in swupdate_status.h (START, RUN, SUCCESS, FAILURE, DOWNLOAD, DONE).
.IP \(bu 2
\fIdwl_percent\fP is the percentage of downloaded data when status = DOWNLOAD.
.IP \(bu 2
\fIdwl_bytes\fP is the total number of bytes that are to be downloaded.
.IP \(bu 2
\fInsteps\fP is the total number of installers (handlers) to be run.
.IP \(bu 2
\fIcur_step\fP is the index of the running handler. cur_step is in the range 1..nsteps
.IP \(bu 2
\fIcur_percent\fP 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.
.IP \(bu 2
\fIcur_image\fP is the name of the image in sw\-description that is currently being installed.
.IP \(bu 2
\fIhnd_name\fP reports the name of the running handler.
.IP \(bu 2
\fIsource\fP is the interface that triggered the update.
.IP \(bu 2
\fIinfolen\fP length of data in the following info field.
.IP \(bu 2
\fIinfo\fP additional information about installation.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
As an example for a progress client, \fBtools/swupdate\-progress.c\fP prints the status
on the console and drives \(dqpsplash\(dq to draw a progress bar on a display.
.SH LANGUAGE BINDINGS
.SS Overview
.sp
In general, SWUpdate is agnostic to a particular language it is operated from,
thanks to \fI\%SWUpdate\(aqs socket\-based control\fP and
\fI\%progress APIs\fP for external programs. As long as the language
of choice has proper socket (library) support, SWUpdate can be operated with it.
.sp
However, for convenience, a Lua language binding in terms of a shared library,
currently \fBlua_swupdate.so.0.1\fP, is provided.
.SS Lua Language Binding
.sp
The Lua language binding is realized in terms of the \fBlua_swupdate\fP 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.
.sp
The \fBlua_swupdate\fP Lua module interface specification that details what
functionality is made available by \fBbindings/lua_swupdate.c\fP is found
in \fBbindings/lua_swupdate.lua\fP\&. It serves as reference, for mocking
purposes, and type checking thanks to the EmmyLua\-inspired annotations.
.sp
Note that, depending on the filesystem location of the Lua binding\(aqs shared
library, Lua\(aqs \fBpackage.cpath\fP may have to be adapted by setting the
environment variable \fBLUA_CPATH\fP, modifying \fBpackage.cpath\fP prior to
a \fBrequire(\(aqlua_swupdate\(aq)\fP, or , as last resort, using \fBpackage.loadlib()\fP
instead of \fBrequire(\(aqlua_swupdate\(aq)\fP\&.
.SS Control Interface
.sp
The \fBlua_swupdate\fP module\(aqs control interface binding conveniently makes
\fI\%SWUpdate\(aqs socket\-based control API\fP available to pure Lua.
.sp
The binding is captured in the \fBswupdate_control\fP object that is returned
by a call to \fBswupdate.control()\fP\&. This object offers the three methods
\fBconnect()\fP, \fBwrite(<chunkdata>)\fP, and \fBclose()\fP:
.sp
The \fBconnect()\fP method initializes the connection to SWUpdate\(aqs control
socket, sends \fBREQ_INSTALL\fP, and waits for \fBACK\fP or \fBNACK\fP, returning the
socket connection file descriptor, mostly for information purposes, or, in case
of an error, \fBnil\fP plus an error message.
.sp
The artifact\(aqs data can then be sent to SWUpdate via the \fBwrite(<chunkdata>)\fP
method, returning \fBtrue\fP, or, in case of errors, \fBnil\fP plus an error message.
.sp
Finally, the \fBclose()\fP method closes the connection to SWUpdate\(aqs control
socket after which it waits for SWUpdate to complete the update transaction and
executes the post\-install command, if given.
.sp
The following example snippet illustrates how to use the control interface binding:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
local artifact = io.open(\(dq/some/path/to/artifact.swu\(dq, \(dqrb\(dq )
swupdate = require(\(aqlua_swupdate\(aq)
local ctrl = swupdate.control()
if not ctrl:connect() then
        \-\- Deliberately neglecting error message.
        io.stderr:write(\(dqError connecting to SWUpdate control socket.\en\(dq)
        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(\(dqError writing to SWUpdate control socket.\en\(dq)
                break
        end
end

local res, msg = ctrl:close()
if not res then
        io.stderr:write(string.format(\(dqError finalizing update: %s\en\(dq, msg))
end
.EE
.UNINDENT
.UNINDENT
.SS Progress Interface
.sp
The \fBlua_swupdate\fP module\(aqs progress interface binding conveniently makes
\fI\%SWUpdate\(aqs socket\-based progress API\fP available to pure Lua.
.sp
The binding is captured in the \fBswupdate_progress\fP object that is returned
by a call to \fBswupdate.progress()\fP\&. This object offers the three methods
\fBconnect()\fP, \fBreceive()\fP, and \fBclose()\fP:
.sp
The \fBconnect()\fP method connects to SWUpdate\(aqs progress socket, waiting until
the connection has been established. Note that it is only really required to
explicitly call \fBconnect()\fP to reestablish a broken connection as the
\fBswupdate_progress\fP object\(aqs instantiation already initiates the connection.
.sp
The \fBreceive()\fP method returns a table representation of the \fBstruct
progress_msg\fP described in the \fI\%progress interface\(aqs API description\fP\&.
.sp
The \fBclose()\fP method deliberately closes the connection to SWUpdate\(aqs progress
socket.
.SS IPv4 Interface
.sp
For convenience, the \fBlua_swupdate\fP module provides the \fBipv4()\fP method
returning a table holding the local network interfaces as the table\(aqs keys and
their space\-separated IP addresses plus subnet masks as respective values.
.SH BOOTLOADER INTERFACE
.SS Overview
.sp
SWUpdate has bindings to various bootloaders in order to store persistent
state information across reboots. Currently, the following bootloaders are
supported:
.INDENT 0.0
.IP \(bu 2
A fake bootloader called \(dqEnvironment in RAM\(dq,
.IP \(bu 2
\X'tty: link https://github.com/siemens/efibootguard'\fI\%EFI Boot Guard\fP\X'tty: link',
.IP \(bu 2
\X'tty: link https://www.denx.de/wiki/U-Boot'\fI\%U\-Boot\fP\X'tty: link', and
.IP \(bu 2
\X'tty: link https://www.gnu.org/software/grub/'\fI\%GRUB\fP\X'tty: link'\&.
.UNINDENT
.sp
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 \fB\-B\fP command line switch or a configuration file (via the
\fBbootloader\fP setting in the \fBglobals\fP section, see
\fBexamples/configuration/swupdate.cfg\fP).
.sp
Note that the run\-time support for some bootloaders, currently U\-Boot and
EFI Boot Guard, relies on loading the respective bootloader\(aqs 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.
.SS Bootloader Interface Description
.sp
The bootloader interface implementations are located in \fBbootloader/\fP\&.
Each bootloader has to implement the interface functions as defined in
\fBinclude/bootloader.h\fP, more precisely
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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);
.EE
.UNINDENT
.UNINDENT
.sp
which
retrieve a key\(aqs 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 \fBkey=value\fP pairs found in a file.
.sp
Then, each bootloader interface implementation has to register itself to
SWUpdate at run\-time by calling the \fBregister_bootloader(const char *name,
bootloader *bl)\fP function that takes the bootloader\(aqs name and a pointer
to \fBstruct bootloader\fP as in \fBinclude/bootloader.h\fP 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, \fBNULL\fP is to be returned as pointer to \fBstruct bootloader\fP\&.
.sp
For example, assuming a bootloader named \(dqtrunk\(dq and (static) interface
functions implementations \fBdo_env_{get,set,unset}()\fP as well as
\fBdo_apply_list()\fP in a \fBbootloader/trunk.c\fP file, the following snippet
registers this bootloader to SWUpdate at run\-time:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
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);
}
.EE
.UNINDENT
.UNINDENT
.sp
with
.INDENT 0.0
.INDENT 3.5
.sp
.EX
#define BOOTLOADER_TRUNK \(dqtrunk\(dq
.EE
.UNINDENT
.UNINDENT
.sp
added to \fBinclude/bootloader.h\fP as a single central \(dqtrunk\(dq bootloader
name definition aiding in maintaining the uniqueness of bootloader names.
This new \(dqtrunk\(dq bootloader should also be added to the Suricatta Lua
Module interface specification\(aqs bootloader Table
\fBsuricatta.bootloader.bootloaders = { ... }\fP in
\fBsuricatta/suricatta.lua\fP\&.
.sp
\fBATTENTION:\fP
.INDENT 0.0
.INDENT 3.5
Take care to uniquely name the bootloader.
.UNINDENT
.UNINDENT
.sp
See, e.g., \fBbootloader/{uboot,ebg}.c\fP for examples of a bootloader using
a shared environment modification library and \fBbootloader/{grub,none}.c\fP
for a simpler bootloader support example.
.SS Bootloader Build System Integration
.sp
A bootloader support implementation needs to be registered to the kconfig
build system.
.sp
First, the bootloader support implementation, named \(dqtrunk\(dq and implemented
in \fBbootloader/trunk.c\fP for example, needs to be added to
\fBbootloader/Kconfig\fP in the \fBBootloader Interfaces\fP menu as
follows:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&...

menu \(dqBootloader\(dq

menu \(dqBootloader Interfaces\(dq

\&...

config BOOTLOADER_TRUNK
    bool \(dqTrUnK Bootloader\(dq
    help
      Support for the TrUnK Bootloader
      https://github.com/knurt/trunk
.EE
.UNINDENT
.UNINDENT
.sp
Then, in order to enable the compile\-time selection of the \(dqtrunk\(dq bootloader
as default, add a section to the \fBDefault Bootloader Interface\fP choice
submenu of the \fBBootloader\fP menu as follows:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
choice
    prompt \(dqDefault Bootloader Interface\(dq
    help
      Default bootloader interface to use if not explicitly
      overridden via configuration or command\-line option
      at run\-time.

\&...

config BOOTLOADER_DEFAULT_TRUNK
    bool \(dqTrUnK\(dq
    depends on BOOTLOADER_TRUNK
    help
      Use TrUnK as default bootloader interface.
.EE
.UNINDENT
.UNINDENT
.sp
Finally, \fBbootloader/Makefile\fP needs to be adapted to build the \(dqtrunk\(dq
bootloader support code, given \fBBOOTLOADER_TRUNK\fP was enabled:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
obj\-$(CONFIG_BOOTLOADER_TRUNK) += trunk.o
.EE
.UNINDENT
.UNINDENT
.sp
If the \(dqtrunk\(dq bootloader, for example, requires loading a shared
environment modification library, then \fBMakefile.flags\fP needs to be
adapted as well, e.g., as follows:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
ifeq ($(CONFIG_BOOTLOADER_TUNK),y)
LDLIBS += dl
endif
.EE
.UNINDENT
.UNINDENT
.SH META-SWUPDATE: BUILDING WITH YOCTO
.SS Overview
.sp
The \X'tty: link http://www.yoctoproject.org'\fI\%Yocto\-Project\fP\X'tty: link' 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.
.sp
Add\-on features can be added using \fIlayers\fP\&. \X'tty: link https://github.com/sbabic/meta-swupdate.git'\fI\%meta\-swupdate\fP\X'tty: link' 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\(aqs documentation
about layers, you should include it in your \fIbblayers.conf\fP file to use it.
.sp
Add meta\-SWUpdate as usual to your bblayers.conf. You have also
to add meta\-oe to the list.
.sp
In meta\-SWUpdate there is a recipe to generate an initrd with a
rescue system with SWUpdate. Use:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
MACHINE=<your machine> bitbake swupdate\-image
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS What about libubootenv ?
.sp
This is a common issue when SWUpdate is built. SWUpdate depends on this library,
that is generated from the U\-Boot\(aqs 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.
.sp
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\(aqs 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\(aqs code. This is done inside the libubootenv.
.sp
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\(aqt boot again.
.sp
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 (\fIlibubootenv\fP) and adjust SWUpdate to be linked
against it. To use it as replacement for u\-boot\-fw\-utils:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
set PREFERRED_PROVIDER_u\-boot\-fw\-utils = \(dqlibubootenv\(dq
.IP \(bu 2
add to SWUpdate config:
.UNINDENT
.UNINDENT
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
CONFIG_UBOOT=y
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SS The swupdate class
.sp
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\(aqs deploy directory.  This class should be inherited by recipes
generating the SWU. The class defines new variables, all of them have the prefix
\fISWUPDATE_\fP in the name.
.INDENT 0.0
.IP \(bu 2
\fBSWUPDATE_IMAGES\fP : 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 :
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
SWUPDATE_IMAGES = \(dqcore\-image\-full\-cmdline uImage\(dq
.EE
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
\fBSWUPDATE_IMAGES_FSTYPES\fP : 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.
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
SWUPDATE_IMAGES_FSTYPES[core\-image\-full\-cmdline] = \(dq.ubifs\(dq
.EE
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
\fBSWUPDATE_IMAGES_NOAPPEND_MACHINE\fP : flag to use drop the machine name from the
artifact file. Most images in \fIdeploy\fP have the name of the Yocto\(aqs machine in the
filename. The class adds automatically the name of the MACHINE to the file, but some
artifacts can be deployed without it.
.UNINDENT
.INDENT 0.0
.INDENT 3.5
.sp
.EX
SWUPDATE_IMAGES_NOAPPEND_MACHINE[my\-image] = \(dq1\(dq
.EE
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
\fBSWUPDATE_SIGNING\fP : if set, the SWU is signed. There are 3 allowed values:
RSA, CMS, CUSTOM. This value determines used signing mechanism.
.IP \(bu 2
\fBSWUPDATE_SIGN_TOOL\fP : 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
.IP \(bu 2
\fBSWUPDATE_PRIVATE_KEY\fP : 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.
.IP \(bu 2
\fBSWUPDATE_PASSWORD_FILE\fP : an optional file containing the password for the private
key. It is available if SWUPDATE_SIGNING is set to RSA.
.IP \(bu 2
\fBSWUPDATE_CMS_KEY\fP : 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.
.IP \(bu 2
\fBSWUPDATE_CMS_CERT\fP : this is the file with the certificate used in signing
process using CMS method. It is available if SWUPDATE_SIGNING is
set to CMS.
.IP \(bu 2
\fBSWUPDATE_AES_FILE\fP : this is the file with the AES password to encrypt artifact. A new \fIfstype\fP is
supported by the class (type: \fIenc\fP). SWUPDATE_AES_FILE is generated as output from openssl to create
a new key with
.INDENT 2.0
.INDENT 3.5
.sp
.EX
openssl enc \-aes\-256\-cbc \-k <PASSPHRASE> \-P \-md sha1 \-nosalt > $SWUPDATE_AES_FILE
.EE
.UNINDENT
.UNINDENT
.sp
To use it, it is enough to add IMAGE_FSTYPES += \(dqenc\(dq to the  artifact. SWUpdate supports decryption of
compressed artifact, such as
.INDENT 2.0
.INDENT 3.5
.sp
.EX
IMAGE_FSTYPES += \(dq.ext4.gz.enc\(dq
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.SS Automatic sha256 in sw\-description
.sp
The swupdate class takes care of computing and inserting sha256 hashes in the
sw\-description file. The attribute \fIsha256\fP \fBmust\fP be set in case the image
is signed. Each artifact must have the attribute:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
sha256 = \(dq$swupdate_get_sha256(artifact\-file\-name)\(dq
.EE
.UNINDENT
.UNINDENT
.sp
For example, to add sha256 to the standard Yocto core\-image\-full\-cmdline:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
sha256 = \(dq$swupdate_get_sha256(core\-image\-full\-cmdline\-machine.ubifs)\(dq;
.EE
.UNINDENT
.UNINDENT
.sp
The name of the file must be the same as in deploy directory.
.SS BitBake variable expansion in sw\-description
.sp
To insert the value of a BitBake variable into the update file, pre\- and
postfix the variable name with \(dq@@\(dq.
For example, to automatically set the version tag:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
version = \(dq@@DISTRO_VERSION@@\(dq;
.EE
.UNINDENT
.UNINDENT
.SS Automatic versions in sw\-description
.sp
By setting the version tag in the update file to \fI$swupdate_get_pkgvar(<package\-name>)\fP it is
automatically replaced with \fIPV\fP from BitBake\(aqs package\-data\-file for the package
matching the name of the provided <package\-name> tag.
For example, to set the version tag to \fIPV\fP of package \fIu\-boot\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
version = \(dq$swupdate_get_pkgvar(u\-boot)\(dq;
.EE
.UNINDENT
.UNINDENT
.sp
To automatically insert the value of a variable from BitBake\(aqs package\-data\-file
different to \fIPV\fP (e.g. \fIPKGV\fP) you can append the variable name to the tag:
\fI$swupdate_get_pkgvar(<package\-name>@<package\-data\-variable>)\fP
For example, to set the version tag to \fIPKGV\fP of package \fIu\-boot\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
version = \(dq$swupdate_get_pkgvar(u\-boot@PKGV)\(dq;
.EE
.UNINDENT
.UNINDENT
.SS Using checksum for version
.sp
It is possible to use the hash of an artifact as the version in order to use
\(dqinstall\-if\-different\(dq.  This allows versionless artifacts to be skipped if the
artifact in the update matches the currently installed artifact.
.sp
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.
.sp
Each artifact must have the attribute:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
version = \(dq@artifact\-file\-name\(dq
.EE
.UNINDENT
.UNINDENT
.sp
The name of the file must be the same as in deploy directory.
.SS Template for recipe using the class
.INDENT 0.0
.INDENT 3.5
.sp
.EX
DESCRIPTION = \(dqExample recipe generating SWU image\(dq
SECTION = \(dq\(dq

LICENSE = \(dq\(dq

# 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 = \(dq \e
    file://sw\-description \e
    \(dq

# images to build before building swupdate image
IMAGE_DEPENDS = \(dqcore\-image\-full\-cmdline virtual/kernel\(dq

# images and files that will be included in the .swu image
SWUPDATE_IMAGES = \(dqcore\-image\-full\-cmdline uImage\(dq

# a deployable image can have multiple format, choose one
SWUPDATE_IMAGES_FSTYPES[core\-image\-full\-cmdline] = \(dq.ubifs\(dq
SWUPDATE_IMAGES_FSTYPES[uImage] = \(dq.bin\(dq

inherit swupdate
.EE
.UNINDENT
.UNINDENT
.SS Simplified version for just image
.sp
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.
.sp
Users just need to import the \fIswupdate\-image\fP class. This already sets some variables.
A sw\-description must still be added into a \fIfiles\fP directory, that is automatically searched by the class.
User still needs to set SWUPDATE_IMAGE_FSTYPES[\fIyour image\fP] to the fstype that should be packed
into the SWU \- an error is raised if the flag is not set.
.sp
In the simple way, your recipe looks like
.INDENT 0.0
.INDENT 3.5
.sp
.EX
<your original recipe code>

SWUPDATE_IMAGES_FSTYPES[<name of your image>] = <fstype to be put into SWU>
inherit swupdate\-image
.EE
.UNINDENT
.UNINDENT
.SS What about grub ?
.sp
In order to use swupdate with grub, swupdate needs to be configured to use grub. Some of
the imporatant configurations are \fBCONFIG_GRUBENV_PATH=\(dq/path/to/grubenv\(dq\fP,
where \fB\(dq/path/to/grubenv\(dq\fP is thepath to grub environment.
Example: \(dq/boot/EFI/BOOT/grubenv\(dq.
.sp
The grubenv file should be created using grub\-editenv tool, because it is a \fB1024\-byte file\fP, therefore,
any modification using nano or vim will only corrupt the file, and grub will not be able to use it.
.sp
You can create a grubenv file using these commands for instance:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
GRUBENV=\(dq/path/to/grubenv\(dq
grub\-editenv $GRUBENV create
grub\-editenv $GRUBENV set rootfs=2
grub\-editenv $GRUBENV set kernel=2
.EE
.UNINDENT
.UNINDENT
.sp
grub\-editenv is a tool that is integrated to yocto.
.sp
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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
# 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 \(dq/path/to/grubenv\(dq
# 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} = \(dq1\(dq ]; then rootfs_part=4 ; elif [ ${rootfs} = \(dq2\(dq ]; then rootfs_part=5 ; fi
# detect which kernel should we boot with
if [ ${kernel} = \(dq1\(dq ]; then kernel_part=\(dq(hd${drive},gpt2)\(dq ; elif [ ${kernel} = \(dq2\(dq ]; then kernel_part=\(dq(hd${drive},gpt3)\(dq ; fi

# The menuentry that is used to boot (more can be added if it is wanted)
menuentry \(aqboot\(aq{
linux ${kernel_part}/bzImage root=/dev/mmcblk1p${rootfs_part} rw rootwait quiet console=ttyS2,115200 console=tty0 panic=5
}
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SH SWUPDATE BEST PRACTICE
.sp
This is intended as general rule to integrate SWUpdate into a custom project.
.sp
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 \fImode\fP 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:
.SS Update Concept
.sp
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:
.INDENT 0.0
.IP \(bu 2
SWUpdate runs successfully,
.IP \(bu 2
the device reboots,
.IP \(bu 2
the bootloader can start the new software, and
.IP \(bu 2
the new software runs, makes some consistency checks, and declares that the transaction (that is from old to new software) is terminated.
.UNINDENT
.sp
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:
.INDENT 0.0
.IP \(bu 2
\fIrecovery_status\fP: 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 \fIfailed\fP 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.
.IP \(bu 2
\fIustate\fP: this triggers a state machine. SWUpdate sets it to \fI1\fP (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.
.UNINDENT
.sp
A \fIfallback\fP 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 \fIustate\fP variable to
\fI3\fP (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:
.INDENT 0.0
.IP \(bu 2
\fIustate\fP is not set or set to \fI0\fP (no update pending). The bootloader runs the configured
copy and won\(aqt ever toggle. In case of failure, a rescue system can be started if available.
.IP \(bu 2
\fIustate\fP is set to  \fI1\fP (INSTALLED): the new software is under test. The bootloader initiates
a fallback if the new software is not running and sets \fIustate\fP to \fI3\fP (FAILED). If the new software runs,
it is the duty of user space (often SWUpdate or the init script for SWUpdate) to reset \fIustate\fP
to \fI0\fP\&. 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.
.UNINDENT
.sp
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]
.sp
Check in advance which security topics are relevant for your project. This includes:
.INDENT 0.0
.IP \(bu 2
signed images (SWU is verified before installing), and then which crypto mechanism is used
(RSA keys, certificates, PKI)
.IP \(bu 2
encryption for artifacts
.IP \(bu 2
under which user and group SWUpdate and other components are allowed to run.
Set user id and group id if not \fIroot\fP in \fIswupdate.cfg\fP\&.
.IP \(bu 2
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 \fI\-\-M\fP, \fI\-R\fP and \fI\-\-max\-version\fP\&.
.IP \(bu 2
hardware\-software compatibility check and how your device knows which hardware
revision is running.
.UNINDENT
.SS Reduce dependencies to minimum
.sp
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.
.SS Make a risk analysis
.sp
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.
.SS SWUpdate builtin configuration
.sp
SWUpdate has a compile time configuration. The default configuration delivered with \fImeta\-swupdate\fP
is not suitable for most projects. The easy way to check configuration in Yocto is to run:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
bitbake \-c menuconfig swupdate
.EE
.UNINDENT
.UNINDENT
.sp
Outside Yocto, just run in SWUpdate\(aqs sources:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
make menuconfig
.EE
.UNINDENT
.UNINDENT
.sp
Check security, bootloader, and which handlers should be installed. They depend strongly on
your project.
If you build with OE, add a \fIswupdate_%.bbappend\fP to one of your layers, and put the resulting
configuration file as \fIdefconfig\fP that can be fetched.
Please review the following configuration:
.INDENT 0.0
.IP \(bu 2
Security settings
.IP \(bu 2
Interfaces required (where the software is coming from). Disable the interface you do not need.
.IP \(bu 2
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 \fIubivol\fP if
you do not use raw NAND, but you can let \fIarchive\fP enabled if you plan to install artifacts
from tarballs in future.
.IP \(bu 2
It is highly recommended to enable Lua to extend runtime behavior.
.UNINDENT
.SS SWUpdate startup
.sp
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 \fIswupdate.sh\fP, that is delivered together with the SWUpdate
binaries.
The script goes through \fI/etc/swupdate/conf.d/\fP and sources all found files. The integrator can use
a set of predefined variables to configure SWUpdate\(aqs command line parameters.
.INDENT 0.0
.IP \(bu 2
\fISWUPDATE_WEBSERVER_ARGS\fP : 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 \fI\-w\fP 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.
.IP \(bu 2
\fISWUPDATE_SURICATTA_ARGS\fP : Suricatta (backend) specific parameters. There is no default.
.IP \(bu 2
\fISWUPDATE_ARGS\fP : Parameters not belonging to Webserver or Suricatta.
.UNINDENT
.sp
Note that \fIswupdate.sh\fP 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 \fI10\-webserver\fP, \fI11\-suricatta\fP, and so on.
.SS Write sw\-description
.sp
\fIsw\-description\fP 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 \(aqselections\(aq and links to extract just one part of the whole \fIsw\-description\fP, 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 \fI\-e <selection,mode>\fP switch.
Other methods set up a link to the standby storage (like \fI/dev/standby\fP) during boot. Or the standby
device can be detected at runtime with an \fIembedded\-script\fP, as part of \fIsw\-description\fP, 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 \fIgetroot()\fP 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
.INDENT 0.0
.INDENT 3.5
.sp
.EX
require (\(aqswupdate\(aq)
.EE
.UNINDENT
.UNINDENT
.sp
to make use of them.
.SS Use OE variables as much as possible
.sp
meta\-swupdate replaces a special construct in \fIsw\-description\fP with the values of build variables.
The recognized construct in \fIsw\-description\fP is delimited by \fI@@\fP, that is \fI@@VARIABLE\-NAME@@\fP\&.
The exception (for compatibility reasons) is the automatic generation of \fIsha256\fP\&. The syntax in that case
is :
.INDENT 0.0
.INDENT 3.5
.sp
.EX
sha256 = \(dq$swupdate_get_sha256(<name of artifact>)\(dq
.EE
.UNINDENT
.UNINDENT
.sp
You can again use variable substitution for artifact names. Example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
sha256 = \(dq$swupdate_get_sha256(@@SYSTEM_IMAGE@@\-@@MACHINE@@@@SWUPDATE_IMAGES_FSTYPES[@@SYSTEM_IMAGE@@]@@)\(dq;
.EE
.UNINDENT
.UNINDENT
.sp
Please note that each variable is double delimited (at the beginning and at the end) by \fI@@\fP\&.
.SS Deliver your scripts instead of relying on them being installed
.sp
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.
.SS Prefer Lua to shell scripts
.sp
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 \(dqfork\(dq followed by an \(dqexec\(dq. 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.
.SS Use installed\-directly when possible
.sp
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 \fI$TMPDIR\fP before passing it to the handlers. Note that \fI$TMPDIR\fP 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.
.SS Always enable sha256 verification
.sp
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.
.SS Always set the \(dqtype\(dq attribute
.sp
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 \fIsw\-description\fP\&.
.SS Do not rely on install order
.sp
SWUpdate does not require that artifacts are put into the CPIO in a specific order. The exception is
\fIsw\-description\fP, 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 \fIinstalled\-directy\fP for the file
and enable it for the filesystem image.
.SS Do not drop atomicity !
.sp
SWUpdate guarantees atomicity as long as you don\(aqt do something that simply breaks it. As example,
think about the bootloader\(aqs environment. In an \fIsw\-description\fP, 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):
.INDENT 0.0
.INDENT 3.5
.sp
.EX
fw_setenv var1 val1
fw_setenv var2 val2
fw_setenv var3 val3
fw_setenv var4 val4
fw_setenv var5 val5
.EE
.UNINDENT
.UNINDENT
.sp
If a power cut happens during two calls of fw_setenv, the environment is in an intermediate state and this
can brick the device.
.SS Plan to have a rescue system
.sp
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.
.SH DELTA UPDATE WITH SWUPDATE
.SS Overview
.sp
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.
.sp
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 \fIdelta updates\fP\&. 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:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
license must be compatible with GPLv2
.IP \(bu 2
good performance for smaller downloads, but not necessarily the best one.
.IP \(bu 2
SWUpdate remains with the concept to deliver one package (SWU), the same
independently from the source where the SWU is stored (USB, OTA, etc.)
.IP \(bu 2
It must comply to SWUpdate\(aqs security requirements (signed images, privilege separation, etc.)
.UNINDENT
.UNINDENT
.UNINDENT
.sp
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 \fIdelta\fP mechanism, that can upgrade in differential
mode two arbitrary images, without any previous knowledge about what they content.
.SS FOSS projects for delta encoding
.sp
There are several algorithms for \fIdelta encoding\fP, 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\(aqs 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.
.SS \X'tty: link https://librsync.github.io/'\fI\%librsync\fP\X'tty: link'
.sp
\X'tty: link https://librsync.github.io/'\fI\%librsync\fP\X'tty: link' 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.
.sp
SWUpdate supports \fIlibrsync\fP as delta encoder via the rdiff handler.
.SS \X'tty: link http://xdelta.org/'\fI\%xdelta\fP\X'tty: link'
.sp
\X'tty: link http://xdelta.org/'\fI\%xdelta\fP\X'tty: link' 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.
.SS \X'tty: link http://0pointer.net/blog/casync-a-tool-for-distributing-file-system-images.html'\fI\%casync\fP\X'tty: link'
.sp
\X'tty: link http://0pointer.net/blog/casync-a-tool-for-distributing-file-system-images.html'\fI\%casync\fP\X'tty: link' 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 \(dqChunk storage\(dq 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:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
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.
.IP \(bu 2
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.
.IP \(bu 2
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 \(dqfirmware\(dq
or \(dqsoftware\(dq 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.
.IP \(bu 2
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.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
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.
.SS \X'tty: link https://github.com/zchunk/zchunk'\fI\%Zchunk\fP\X'tty: link' \- compression format
.sp
\X'tty: link https://github.com/zchunk/zchunk'\fI\%zchunk\fP\X'tty: link' 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 \X'tty: link https://www.jdieter.net/posts/2018/05/31/what-is-zchunk/'\fI\%author\fP\X'tty: link'\&. 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.
.sp
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.
.sp
Zchunk supports multiple sha algorithms \- to be compatible with SWUpdate, zchunk should be informed
to generate sha256 hashes.
.SS Design Delta Update in SWUpdate
.sp
For all reasons stated before, \fIzchunk\fP is chosen as format to deliver delta update in SWUpdate.  An artifact
can be generated in ZCK format and then the ZCK\(aqs header (as described in \X'tty: link https://github.com/zchunk/zchunk/blob/main/zchunk_format.txt'\fI\%format\fP\X'tty: link') 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.
.SS Changes in ZCHUNK project
.sp
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:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
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.
.IP \(bu 2
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.
.IP \(bu 2
allow to use sha256 (already foreseen in zchunk) as this is the only hash type
used in SWUpdate.
.IP \(bu 2
add API to allow an external caller to take itself the decision if a chunk must be
downloaded or reused.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
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.
.sp
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.
.SS Integration in sw\-description
.sp
The most important part in a Zchunk file is the header: this contains all metadata and hashes to perform
comparisons. The \fIzck\fP 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.
.SS Integration in SWUpdate: the delta handler
.sp
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 \fIraw\fP or \fIrawfile\fP\&. 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\(aqs 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:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
parse and understand the ZCK header
.IP \(bu 2
create a ZCK header from the file / partition used as source for the comparison
.IP \(bu 2
detect which chunks are missing and which one must be copied.
.IP \(bu 2
build  a mixer that copies and downloads all chunks and generates a stream
for the following handler.
.IP \(bu 2
detect any error coming form the chained handler.
.UNINDENT
.UNINDENT
.UNINDENT
.sp
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 \fIprivilege separation\fP 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.
.SS Creation of ZCK Header and ZCK file for SWUpdate
.sp
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:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
zck \-\-output <output file> \-u \-\-chunk\-hash\-type sha256 <artifact, like rootfs>
.EE
.UNINDENT
.UNINDENT
.sp
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.
.sp
The SWU must just contain the header. This can be easy extracted from the ZCK file with:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
HSIZE=\(gazck_read_header \-v <ZCK file> | grep \(dqHeader size\(dq | cut \-d\(aq:\(aq \-f2\(ga
dd if=<ZCK FILE> of=<ZCK HEADER file> bs=1 count=$((HSIZE))
.EE
.UNINDENT
.UNINDENT
.SS Using ZCK tools to foresee download size
.sp
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 \fIzck_cmp_uncomp\fP from the test
directory:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
\&../build/test/zck_cmp_uncomp \-\-verbose <uncompressed old version file> <ZCK file>
.EE
.UNINDENT
.UNINDENT
.sp
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.
.SH SWUPDATE-CLIENT
.sp
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.
.SS SYNOPSIS
.sp
swupdate\-client [OPTIONS] <image.swu to be installed>...
.SS DESCRIPTION
.INDENT 0.0
.TP
.B  \-h
print help and exit
.TP
.B  \-d
ask the server to only perform a dry\-run
.TP
.B  \-e
<software>,<mode>
select software image set and source (for example: stable,main)
.TP
.B  \-q
go quiet, resets verbosity
.TP
.B  \-v
go verbose, essentially print upgrade status messages from server
.TP
.B  \-p
ask the server to run post\-update commands if upgrade succeeds
.UNINDENT
.SH SWUPDATE-PROGRESS
.sp
swupdate\-progress tries to connect to a running instance
of SWUpdate to get the status of a running update.
.SS SYNOPSIS
.sp
swupdate\-progress [option]
.SS DESCRIPTION
.sp
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 \(dqpsplash\(dq or execute a script
after an update.
.INDENT 0.0
.TP
.B  \-c
Use colors to show results on stdout
.TP
.B  \-e
Command to be execute after an update
.TP
.B  \-p
send percentage to psplash
.TP
.B  \-r
optionally reboot the target after a successful update
.TP
.B  \-s
path to progress IPC socket in case the default is not taken
.TP
.B  \-w
waits for a SWUpdate connection instead of exit with error
.TP
.B  \-q
don\(aqt print progress bar
.TP
.B  \-h
print a help
.UNINDENT
.SH SWUPDATE-IPC
.sp
swupdate\-ipc sends a specific command to SWUpdate. The following commands are
enabled:
.SS aes
.sp
send a new aes key to SWUpdate
.SS setversion
.sp
sends a range of versions that can be accepted.
.SS gethawkbit
.sp
return status of the connection to Hawkbit.
.SS sendtohawkbit
.sp
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.
.SS sysrestart
.sp
send a restart command after a network update
.SS SYNOPSIS
.sp
swupdate\-ipc <cmd> [option]
.sp
Where cmd is one of the listed above.
.SS DESCRIPTION
.INDENT 0.0
.TP
.B aes <key> <ivt>
AES key to be used for decryption
.TP
.B setversion <min> <max> <current>
configure the accepted range of versions
.TP
.B hawkbitcfg
configuration for Hawkbit Module
.UNINDENT
.INDENT 0.0
.TP
.B  \-h
help
.TP
.B  \-p
allows one to set the polling time (in seconds)
.TP
.B  \-e
enable suricatta mode
.TP
.B  \-d
disable suricatta mode
.UNINDENT
.INDENT 0.0
.TP
.B 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.
.TP
.B sysrestart
Used with SWU handler, allow one to perform a network restart
.UNINDENT
.INDENT 0.0
.TP
.B  \-r
optionally reboot the target after a successful update
.TP
.B  \-w
waits for a SWUpdate connection instead of exit with error
.TP
.BI \-s \ <path>
path to progress IPC socket
.UNINDENT
.SH HELP AND SUPPORT
.SS Mailing List
.sp
There is a mailing list for this project:
.INDENT 0.0
.INDENT 3.5
\X'tty: link mailto:swupdate@googlegroups.com'\fI\%swupdate@googlegroups.com\fP\X'tty: link'
.UNINDENT
.UNINDENT
.sp
Issue related to the project or to the documentation are discussed
here.
.SS SWUpdate Flyer
.sp
A short description about the project and the features (in English and German)
can be found in the \X'tty: link http://www.denx.de/en/pub/Software/WebHome/we-update.pdf'\fI\%flyer\fP\X'tty: link'
.SS Workshop and SWUpdate integration in project
.sp
For quick integration of SWUpdate in your project, you could be interested in the \X'tty: link https://swupdate.org/services'\fI\%Training\fP\X'tty: link'
.SS Commercial support and board integration
.sp
Please check for \fIservices <https://swupdate.org/services>\fP if you need professional support or you need help to get SWUpdate on your device.
.SS Talks about SWUpdate
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
\X'tty: link https://elinux.org/images/1/19/Babic--software_update_in_embedded_systems.pdf'\fI\%Software Update in Embedded Systems by Stefano Babic\fP\X'tty: link'
.IP \(bu 2
\X'tty: link http://de.slideshare.net/chrissimmonds/linux-fieldupdate2015'\fI\%Updating Embedded Linux devices in field by Chris Simmonds\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://elinux.org/images/7/74/Murray.pdf'\fI\%OpenEmbedded in the Real World by Scott Murray\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://lists.linuxfoundation.org/pipermail/automotive-discussions/2016-May/002061.html'\fI\%[RFC] Device\-side support for software update in AGL by Matt Porter\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://events.static.linuxfound.org/sites/events/files/slides/Open%20Source%20secure%20software%20updates%20for%20Linux-based%20IVI%20systems.pdf'\fI\%Open Source secure software updates for Linux\-based IVI systems by Arthur Taylor\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://events.static.linuxfound.org/sites/events/files/slides/linuxcon-japan-2016-softwre-updates-sangorrin.pdf'\fI\%How do you update your embedded Linux devices? by Daniel Sangorrin / Keijiro Yano\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://elinux.org/images/3/31/Comparison_of_Linux_Software_Update_Technologies.pdf'\fI\%Comparison of Linux Software Update Technologies by Matt Porter\fP\X'tty: link'
.IP \(bu 2
Software update for IoT: the current state of play by Chris Simmonds, ELCE 2016, \X'tty: link http://de.slideshare.net/chrissimmonds/software-update-for-iot-the-current-state-of-play'\fI\%Slides\fP\X'tty: link',
\X'tty: link https://youtu.be/GZGnBK2NycI?list=PLbzoR-pLrL6pRFP6SOywVJWdEHlmQE51q'\fI\%Video\fP\X'tty: link'
.IP \(bu 2
OSS Remote Firmware Updates for IoT\-like Projects by Silvano Cirujano Cuesta, ELCE 2016,
\X'tty: link https://elinux.org/images/1/11/OSS_Remote_Firmware_Updates_for_IoT-like_Projects.pdf'\fI\%Slides ELCE 2016\fP\X'tty: link',
\X'tty: link https://youtu.be/vVS-ZRNE0Lc?list=PLbzoR-pLrL6pRFP6SOywVJWdEHlmQE51q'\fI\%Video ELCE 2016\fP\X'tty: link'
.IP \(bu 2
System Upgrade with SWUpdate by Gabriel Huau, ELC 2017,
\X'tty: link http://events17.linuxfoundation.org/sites/events/files/slides/ELC2017_SWUpdate.pdf'\fI\%Slides ELC 2017\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=ePRTTfGJUI4&t=16s'\fI\%Video ELC 2017\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://elinux.org/images/0/0c/BoF_secure_ota_linux.pdf'\fI\%BoF: Secure OTA Collaboration, by Ricardo Salveti and Alan Bennett, ELCE 2017\fP\X'tty: link'
.IP \(bu 2
Orchestrated Android\-Style System Upgrades for Embedded Linux by Diego Rondini, ELCE 2017,
\X'tty: link https://www.elinux.org/images/6/6d/UF_-_ELCE_2017_Presentation.pdf'\fI\%Slides Android\-Style\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=Za21QFJGvJ0'\fI\%Video Android\-Style\fP\X'tty: link'
.IP \(bu 2
Updating an Embedded System with SWUpdate Framework by Stefano Babic, ELCE 2017,
\X'tty: link http://events17.linuxfoundation.org/sites/events/files/slides/SWUpdateELCE2017.pdf'\fI\%Slides ELCE 2017\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=6sKLH95g4Do'\fI\%Video ELCE 2017\fP\X'tty: link'
.IP \(bu 2
Upgrading buildroot based devices with SWUpdate by Angelo Compagnucci, LinuxLab 2018,
\X'tty: link https://www.slideshare.net/linuxlab_conf/angelo-compagnucci-upgrading-buildroot-based-devices-with-swupdate'\fI\%Slides LinuxLab  2018\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=8vv5Xf6dBKE'\fI\%Video LinuxLab 2018\fP\X'tty: link',
.IP \(bu 2
Evolution of (OTA) Update in the IoT world by Stefano Babic, ELC 2019,
\X'tty: link https://www.slideshare.net/StefanoBabic/evolution-of-otaupdateintheiotworld'\fI\%Slides ELC 2019\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=WZHO18EhD7Y'\fI\%Video ELC 2019\fP\X'tty: link',
.IP \(bu 2
Introduction of CIP Software Updates Working Group by Akihiro Suzuki, CIP Mini Summit 2019,
\X'tty: link https://wiki.linuxfoundation.org/_media/civilinfrastructureplatform/cipconferences/sw_updates_wg_mini-summit.pdf'\fI\%Slides CIP 2019\fP\X'tty: link',
.IP \(bu 2
There is No Store For Self\-Driving Car Parts by Stephen Segal and Matt Fornero (Cruise LLC), ELC 2020,
\X'tty: link https://static.sched.com/hosted_files/ossna2020/56/No_Store_for_AV_Parts_ELC_NA_2020.pdf'\fI\%Slides Cruise ELC 2020\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=PSq13Kv4Qk4'\fI\%Video Cruise\fP\X'tty: link'
.IP \(bu 2
Secure Boot and Over\-the\-Air Updates \- That\(aqs simple, no ? by Jan Kiszka (Siemens AG), ELC 2020,
\X'tty: link https://static.sched.com/hosted_files/ossna2020/17/Secure-OTA-Updates_elc-na-2020.pdf'\fI\%Slides Secure OTA ELC 2020\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=vfYSP4qIJP0&t=1647s'\fI\%Video Secure OTA\fP\X'tty: link'
.IP \(bu 2
Diving into SWUpdate: adding new platform support with Yocto/OE! by Pierre\-Jean Texier, LiveEmbedded 2020,
\X'tty: link https://de.slideshare.net/PierrejeanTexier/diving-into-swupdate-adding-new-platform-support-in-30minutes-with-yoctooe'\fI\%Slides Diving into SWUpdate\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=TK10pNb_mzw'\fI\%Video Diving into SWUpdate\fP\X'tty: link'
.IP \(bu 2
Implementing UEFI\-based Secure Boot + OTA Update for Embedded ARM Devices by Jan Kiszka & Christian Storm, ELCE 2022
\X'tty: link https://https://elinux.org/images/4/42/ELCE2022-UEFISecureBootOTAUpdatesOnARM.pdf'\fI\%Slides Implementing UEFI Secure Boot + OTA Update\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=H_dBnwkTAbw'\fI\%Video Implementing UEFI\-based Secure Boot + OTA Update for Embedded ARM Devices\fP\X'tty: link'
.IP \(bu 2
Delta OTA Update with SWUpdate by Stefano Babic, ELCE 2022
\X'tty: link https://elinux.org/images/9/98/Delta_OTA_Update_with_SWUpdate_-_ELCE_2022.pdf'\fI\%Slides  Delta OTA Update with SWUpdate\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=noURP22fJhs'\fI\%Video Delta OTA Update with SWUpdate\fP\X'tty: link'
.IP \(bu 2
Ligthning Talk: SWUpdate Over CAN Bus \- Can it ? by Stefano Babic, EOSS 2023
\X'tty: link https://www.youtube.com/watch?v=OU7MuX2sPUU&t=59s'\fI\%Video SWUpdate Over CAN Bus\fP\X'tty: link'
.IP \(bu 2
Best Practices with SWUpdate by Stefano Babic, Embedded Recipes 2023
\X'tty: link https://drive.google.com/file/d/1pbMtFH6IkztpsgvL6GJ54Fs7hPu7tPBf/view?usp=drive_link'\fI\%Slides Best Practices with SWUpdate\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=SXzfDa8HEss&list=PLwnbCeeZfQ_Mi7gjUpLZxXGOcEBS_K8kH&index=7&pp=iAQB'\fI\%Video Best Practices with SWUpdate\fP\X'tty: link'
.IP \(bu 2
Delta Updates: Making Updates Leaner by Felix Moessbauer & Jan Kiszka, Siemens AG, Embedded Open Source Summit 2024
\X'tty: link https://static.sched.com/hosted_files/eoss24/26/2024_EOSS_CIP_delta_updates.pdf'\fI\%Slides Delta Updates: Making Updates Leaner\fP\X'tty: link',
\X'tty: link https://www.youtube.com/watch?v=1rzf7tE-cKY'\fI\%Video Delta Updates: Making Updates Leaner\fP\X'tty: link'
.UNINDENT
.UNINDENT
.UNINDENT
.SS Useful references
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP \(bu 2
\X'tty: link https://boundarydevices.com/using-swupdate-upgrade-system'\fI\%Boundary Devices, Using SWUpdate to upgrade your system\fP\X'tty: link'
.IP \(bu 2
\X'tty: link http://www.linuxembedded.fr/2016/09/presentation-de-software-update'\fI\%Présentation de Software Update (French)\fP\X'tty: link'
.IP \(bu 2
\X'tty: link http://warpx.io/blog/tutorial/easy-os-upgrades-swupdate'\fI\%Easy OS upgrades with SWUpdate\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://3mdeb.com/app-dev/swupdate-for-feature-rich-iot-applications/'\fI\%SWUpdate for feature\-rich IoT applications\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://github.com/victronenergy/venus/issues/27'\fI\%Implement swupdate \- replacing opkg based updating, VictronEnergy\fP\X'tty: link'
.IP \(bu 2
\X'tty: link http://www.variwiki.com/index.php?title=SWUpdate_Guide'\fI\%Variscite, SWUpdate\fP\X'tty: link'
.IP \(bu 2
\X'tty: link http://mkrak.org/2018/01/26/updating-embedded-linux-devices-part2/'\fI\%Updating Embedded Linux Devices: SWUpdate\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://pelux.io/software-factory/PELUX-3.0/swf-blueprint/docs/articles/architecture/vert-config-SOTA.html'\fI\%Approach to Software Update Management, Pelux\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://pelux.io/software-factory/PELUX-3.0/chapters/architecture/subsystems/SOTA/SOTA-system.html'\fI\%SOTA System, Pelux\fP\X'tty: link'
.IP \(bu 2
\X'tty: link https://bootlin.com/blog/tag/swupdate/'\fI\%Building a Linux system for the STM32MP1: remote firmware updates, Bootlin\fP\X'tty: link'
.UNINDENT
.UNINDENT
.UNINDENT
.SH CONTRIBUTING TO SWUPDATE
.sp
Contributions are welcome ! Please follow the following guideline for contributions.
.SS Contribution Checklist
.sp
These are mostly general recommendations and are common practice in a lot of
FOSS projects.
.INDENT 0.0
.IP \(bu 2
use git to manage your changes [\fIrecommended\fP]
.IP \(bu 2
follow as much as possible kernel codestyle [\fIrecommended\fP]
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.
.IP \(bu 2
add the required copyright header to each new file introduced [\fBrequired\fP]
.IP \(bu 2
.INDENT 2.0
.TP
add signed\-off to all patches [\fBrequired\fP]
.INDENT 7.0
.IP \(bu 2
to certify the \(dqDeveloper\(aqs Certificate of Origin\(dq, see below
.IP \(bu 2
check with your employer when not working on your own!
.UNINDENT
.UNINDENT
.IP \(bu 2
.INDENT 2.0
.TP
.B add version number for your patches if follow\-up versions are requested [\fIrecommended\fP]
.INDENT 7.0
.IP \(bu 2
Add a \(dqChange from Vx\(dq description under the commit message to take track
of the history of the patch.
.IP \(bu 2
It is suggested to use excellent \(dqpatman\(dq tool to manage patches series.
This is part of U\-Boot\(aqs project (tools/patman), but it can be used in other projects, too.
.UNINDENT
.UNINDENT
.IP \(bu 2
check that your patches do not break build [\fBrequired\fP]
.INDENT 2.0
.IP \(bu 2
There is a set of configuration files in the \fIconfigs/\fP directory.
Please run a build for all files in the directory to ensure that SWUpdate is
still buildable from configurations different as yours.
.UNINDENT
.IP \(bu 2
.INDENT 2.0
.TP
post patches to mailing list [\fBrequired\fP]
.INDENT 7.0
.IP \(bu 2
use \fIgit format\-patch\fP to generate your patches.
.IP \(bu 2
use \fIgit send\-email\fP if possible. This avoid corruptions due
to the mailers
.IP \(bu 2
add a prefix [meta\-swupdate] if patches are intended to the Yocto\(aqs meta layer.
.IP \(bu 2
send patches inline, do not append them
.IP \(bu 2
no HTML emails!
.UNINDENT
.UNINDENT
.IP \(bu 2
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.
.UNINDENT
.sp
Patches are tracked by patchwork (see \X'tty: link http://jk.ozlabs.org/projects/patchwork/'\fI\%http://jk.ozlabs.org/projects/patchwork/\fP\X'tty: link').
You can see the status of your patches at \X'tty: link http://patchwork.ozlabs.org/project/swupdate/list'\fI\%http://patchwork.ozlabs.org/project/swupdate/list\fP\X'tty: link'\&.
.SS Developer\(aqs Certificate of Origin 1.1
.sp
When signing\-off a patch for this project like this
.INDENT 0.0
.INDENT 3.5
Signed\-off\-by: Random J Developer <\X'tty: link mailto:random@developer.example.org'\fI\%random@developer.example.org\fP\X'tty: link'>
.UNINDENT
.UNINDENT
.sp
using your real name (no pseudonyms or anonymous contributions), you declare the
following:
.INDENT 0.0
.INDENT 3.5
By making a contribution to this project, I certify that:
.INDENT 0.0
.INDENT 3.5
.INDENT 0.0
.IP a. 3
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
.IP b. 3
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
.IP c. 3
The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
.IP d. 3
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.
.UNINDENT
.UNINDENT
.UNINDENT
.UNINDENT
.UNINDENT
.SH PROPOSALS TO IMPROVE SWUPDATE
.sp
Please take into account that most of the items here are \fIproposals\fP\&.
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.
.sp
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.
.sp
If you have further ideas about the project, just send your proposal to the
Mailing List or post a patch for this document.
.sp
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 !
.SS Legende
.SS Feature\(aqs status
.TS
box center;
l|l.
T{
Value
T}	T{
Description
T}
_
T{
Wait
T}	T{
No activity is planned, just proposal
T}
_
T{
Design
T}	T{
Design / Concept is done
T}
_
T{
Planned
T}	T{
Feature will be implemented soon
T}
_
T{
WIP
T}	T{
Feature is current to be implemented and will be posted
T}
_
T{
Running
T}	T{
Implemented
T}
.TE
.SS Request for Support
.TS
box center;
l|l.
T{
Value
T}	T{
Description
T}
_
T{
None
T}	T{
No sponsoring required
T}
_
T{
Sponsor
T}	T{
Looking for sponsors to finance the feature
T}
_
T{
Planned
T}	T{
Feature is already sponsored
T}
.TE
.SS Priority
.TS
box center;
l|l.
T{
Value
T}	T{
Description
T}
_
T{
Low
T}	T{
Probably just an idea, feedback from community asked
T}
_
T{
Medium
T}	T{
Not critical, but nice feature to have
T}
_
T{
High
T}	T{
Critical feature, it should be implemented soon
T}
.TE
.SS Main goal
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status : Running
.IP \(bu 2
Request for Support : None
.UNINDENT
.SS Core features
.SS Support for OpenWRT
.sp
OpenWRT is used on many routers and has its own way for updating that is not power\-cut safe.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Low
.UNINDENT
.SS Software\-Software compatibility
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Support files bigger than 4GB
.sp
SWUpdate currently uses CPIO to pack updates in the \(aqnewc\(aq and \(aqcrc\(aq formats.
These formats limit single files to 4GB \- 1byte in size, which could become a
problem as update size grows.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : High
.UNINDENT
.SS Parser
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : None
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Fetcher and interfaces
.SS Selective downloading
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Tools and utilities
.SS Single tool to create SWU
.sp
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.
.sp
Even if it was tried to have the same features, there are some important differences:
.INDENT 0.0
.IP \(bu 2
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.
.IP \(bu 2
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.
.UNINDENT
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Further enhancement to SWUGenerator
.sp
SWUGenerator is thought to support multiple subcommands, but it currently supports just \(dqcreate\(dq.
It is thinkable, even if this can be done with other tools, to implement further commands like:
.INDENT 0.0
.IP \(bu 2
extract: take a SWU and extracts all artifacts in a directory
.IP \(bu 2
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.
.IP \(bu 2
verify: just verify if the SWU is correctly signed.
.UNINDENT
.sp
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\(aqs classes, and replace with the single call
to SWUGenerator.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS swupdate\-progress start up
.sp
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.
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Not required
.IP \(bu 2
Priority : Low
.UNINDENT
.SS Lua
.INDENT 0.0
.IP \(bu 2
API between SWUpdate and Lua is poorly documented.
.IP \(bu 2
Store in SWUpdate\(aqs repo Lua libraries and common functions to be reused by projects.
.UNINDENT
.INDENT 0.0
.IP \(bu 2
Status : Running
.IP \(bu 2
Request for Support : None
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Handlers:
.SS New Handlers
.sp
Users develop own custom handlers \- I just enforce and encourage everyone
to send them and discuss how to integrate custom handler in mainline.
.INDENT 0.0
.TP
.B Some ideas for new handlers:
.INDENT 7.0
.IP \(bu 2
FPGA updater for FPGA with Flash
.IP \(bu 2
Package handler to install packages (ipk, deb)
Packages can be inserted into the SWU and the atomicity is
guaranteed by SWUpdate.
.IP \(bu 2
Lua handlers should be added if possible to the project
to show how to solve custom install.
.UNINDENT
.UNINDENT
.INDENT 0.0
.IP \(bu 2
Status : Running
.IP \(bu 2
Request for Support : None
.IP \(bu 2
Priority : Low
.UNINDENT
.SS Handlers installable as plugin at runtime
.sp
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.
.sp
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.
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status : Running
.IP \(bu 2
Request for Support : None
.UNINDENT
.SS Support for BTRFS snapshot
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Design
.IP \(bu 2
Request for Support : Planned
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Internal Webserver
.sp
SWUpdate make usage of the project \(dqmongoose\(dq 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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Security / Crypto engines
.INDENT 0.0
.IP \(bu 2
add support for asymmetric decryption
.IP \(bu 2
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.
.IP \(bu 2
add more algorithms for decryption, as AES\-CTR can be very useful to decrypt
chunks in delta updates.
.IP \(bu 2
Support for TPM2 to store secrets (requires rework above).
.UNINDENT
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : High
.UNINDENT
.SS Back\-end support (suricatta mode)
.SS Back\-end: responsiveness for IPC
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Back\-end: check before installing
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Back\-end: hawkBit Offline support
.sp
There are several discussions on hawkBit\(aqs ML about how to synchronize
an offline update (done locally or via the internal Web\-server) with
the hawkBit\(aqs 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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Low
.UNINDENT
.SS Backend: hawkBit support for Delta Update
.sp
Delta Update requires two or more files:
.INDENT 0.0
.IP \(bu 2
the SWU
.IP \(bu 2
one file \(dq.zck\(dq for each artifact that is upgraded via delta handler.
.UNINDENT
.sp
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 \(dq.zck\(dq files are not uploaded. In fact, hawkBit assigns to each
Software Module an \(dqid\(dq that is unknown at the moment of the build.
.sp
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.
.sp
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 (\(dqdownloader\(dq) that don\(aqt use the setup from suricatta.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Back\-end: support for generic down\-loader
.sp
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 \fIsuricatta\fP to detect
if a new version is available before downloading and installing.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Back\-end: further connectors
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Low
.UNINDENT
.SS Test and Continuous Integration
.sp
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 \(dqSWUpdate factory\(dq where patches are fast integrated
and tested on real hardware.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Binding to languages
.sp
libswupdate allows to write an application that can control SWUpdate\(aqs behavior and be informed
about a running update. There are bindings for C/C++, Lua and nodejs (just progress).
.sp
Applications can be written in other languages, and binding to Python and Rust can be
implemented, too.
.INDENT 0.0
.IP \(bu 2
Status: Wait
.IP \(bu 2
Request for Support : Sponsor
.IP \(bu 2
Priority : Medium
.UNINDENT
.SS Documentation
.sp
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.
.INDENT 0.0
.IP \(bu 2
Status : Running
.IP \(bu 2
Request for Support : None
.UNINDENT
.SH DOCUMENTATION FOR PREVIOUS RELEASES
.INDENT 0.0
.IP \(bu 2
\fI\%2024.05\fP
.IP \(bu 2
\fI\%2023.12\fP
.IP \(bu 2
\fI\%2023.05\fP
.IP \(bu 2
\fI\%2022.12\fP
.IP \(bu 2
\fI\%2022.05\fP
.IP \(bu 2
\fI\%2021.11\fP
.IP \(bu 2
\fI\%2021.04\fP
.IP \(bu 2
\fI\%2020.11\fP
.IP \(bu 2
\fI\%2020.04\fP
.IP \(bu 2
\fI\%2019.11\fP
.IP \(bu 2
\fI\%2019.04\fP
.IP \(bu 2
\fI\%2018.11\fP
.UNINDENT
.SH INDICES AND TABLES
.INDENT 0.0
.IP \(bu 2
\fI\%Index\fP
.IP \(bu 2
\fI\%Module Index\fP
.IP \(bu 2
\fI\%Search Page\fP
.UNINDENT
.SH AUTHOR
Stefano Babic
.SH COPYRIGHT
2013-2024, Stefano Babic
.\" Generated by docutils manpage writer.
.