Skip to content

Software Version Control

Welma includes a version control system that embeds version information and compatibility rules into software packages. This ensures that only compatible module combinations are installed, preventing system misconfiguration or malfunction due to incompatible versions.

Overview

The Welma version control system works by:

  • Embedding version tags in software images during build time with module metadata (name, version, and compatibility rules)
  • Checking compatibility before installing updates using version probing
  • Enforcing dependencies between modules to ensure system consistency

Runtime architecture

Version Tags

Each software image (partition, firmware) can contain a version tag that includes all the information required to check its compatibility with the system.

Version tags are stored in a binary format that can be embedded at the end of software images. The tag contains all module metadata and compatibility rules in a compact, fixed-size structure of 2048 bytes.

Tag Structure

Offset  Size  Field              Description
------  ----  -----              -----------
0       32    Module Name        UTF-8 encoded module name (e.g."bootloader")
32      30    Module Version     UTF-8 encoded version (e.g., "1.2.0")
62      1     Rules Count        Number of active rules (0-30)
63      1920  Rules              Array of 30 compatibility rules (64 bytes each)
1983    50    Padding            Reserved area (filled with 0xFF)
2033    4     CRC32              CRC32 checksum of tag data
2037    11    MAGIC              Magic identifier: "WELMAVMNGR1"

Maximum Rules per Tag

Each tag supports a maximum of 30 dependency rules. If a module requires more than 30 compatibility constraints, it exceeds the tag capacity and will result in a build-time error. The Rules Count field indicates how many of the 30 available rule slots are actually used (0-30). Unused rule slots are padded with 0xFF bytes.

Rule Entry Structure (64 bytes each)

Each rule entry contains a single dependency constraint:

Offset  Size  Field              Description
------  ----  -----              -----------
0       32    Rule Module Name   UTF-8 module name this rule applies to
32      30    Rule Version       UTF-8 version string for comparison
62      2     Rule Type          Comparison operator code (little-endian)

Rule Type Encoding

The rule type field encodes the comparison operator:

Operator Encoding Description
== 0x0001 Equal: version must exactly match
> 0x0002 Greater: version must be strictly greater
>= 0x0003 Greater or Equal: version must be greater or equal
< 0x0004 Less: version must be strictly less
<= 0x0005 Less or Equal: version must be le or equal
!= 0x0006 Not Equal: version must not match

Tag Placement in Images

The version tag placement strategy depends on the module type and whether its filesystem type is known. The Welma build system automatically determines the correct placement method during image creation.

Tags are created and installed using welma-tagtool according to the following logic:

Verity-Protected Modules

The Welma verity header is located at the beginning of the partition and contains metadata including the total size of verity data plus filesystem (see this page for more details). The version tag is placed immediately after this total size value, allowing runtime programs to easily locate it by reading the verity header.

A/B Filesystem Modules

When an A/B module with an explicit filesystem type is used (without verity protection), the build system calculates the total filesystem size and installs the tag immediately after it. This preserves the filesystem integrity and structure, while allowing version information to be probed without parsing the entire partition.

Warning

Version control requires filesystem tag support. Version tags are embedded in the partition images and depend on the filesystem type. Currently supported filesystems are:

  • ext2, ext3, ext4
  • vfat

Single Modules (raw data):

When a single-mode module is a raw binary (e.g bootloaders,...), the build system pads the image to a 2048-byte boundary. This ensures that the tag is always placed at a predictable, aligned offset.

Module File Layout:
┌─────────────────────────────────────┐
│        Original binary data         │
├─────────────────────────────────────┤
│        Padding (0xFF bytes)         │
│  (to align tag offset to 2048-byte) │
├─────────────────────────────────────┤
│       2048-byte version tag         │
└─────────────────────────────────────┘

Tagging Update Artifacts (SWU and Mender)

When creating update artifacts, a tag is embedded not only in the image installed by the artifact, but also in the SWU or Mender package itself.

This allows faster verification of the versions of the modules contained in the artifact, especially when the tagged image inside the package is compressed and would otherwise need to be fully decompressed to read the tag.

To achieve this, an update artifact contains as many tags as there are images.

Compatibility Checking During Updates

When installing software packages, the updated daemon automatically checks version compatibility in the following order:

  1. Parse module tags

    From each artifact being installed, updated daemon reads the embedded tags to build a final list of modules to be updated.

  2. Validate inter-artifact compatibility first

    If multiple artifacts are being installed together (in the same session) and an artifact (A1) provides a module M1 that requires a specific version of a module M2, and M2 is provided by a second artifact (A2) being installed, this M2 module should satisfy the requirement of M1. Otherwise, the dependency check fails and the update is aborted.

  3. Check dependency rules against currently running modules

    If an artifact (A1) provides a module M1 that requires a specific versions of a module not updated in the current session, this dependency is checked against the currently running module from the active/single partitions.

  4. Check running modules dependencies

    After verifying that all artifact module dependencies are satisfied, the updated daemon checks the running modules that are not updated in the current session to determine whether they have any specific dependency on the artifact modules. If any dependency check fails, the update is aborted.

  5. Install Artifacts and check version mismatch

    When a compatible artifact instsallation is submited, updated daemon checks that the retreived version information from the artifact tag matches the installed tag.

Note

Untagged modules are accepted for installation only if no module in the current session, nor any running module, depends on them.

Note

When a module M is provided by multiple artifacts during installation with InstallLocalFiles, the last artifact providing M will override the previous versions. As a result, only the last M module dependencies are used for the compatibility check (Step 1)

Yocto configuration

Default Behavior

Version tagging is enabled by default for all partitions with update=ab or update=single modes. This means:

  • All A/B update partitions are automatically tagged with version information
  • All single-mode update partitions are automatically tagged
  • Version tags can be explicitly disabled using tag=no in the .part file if needed
  • Partitions with update=no are not tagged

Disable tags

By default, the system supports tag management for modules. To disable this feature, set tag=no on all modules.

Specifying Module Dependencies

Module dependencies are specified in the .part file using the deps keyword. Multiple dependencies are separated by colons (:) with no spaces.

Dependency Format

Each dependency follows the format: modulename<operator>version, where operators are : ==, !=, >, >=, <, <=.

Rule Limit

A single module tag can contain up to 30 dependency rules maximum. Each rule specifies one compatibility constraint. If you need more than 30 rules for a single module, the build will fail with an error indicating too many rules have been specified.

Examples

  • Tag without dependencies (no rules):

    part appro update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6,version=1.2.0
    

  • Single dependency in .part:

    part appro update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6,version=1.2.0,deps=sysro>=1.0.0
    

  • Multiple dependencies (colon-separated) in .part:

    part appro update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6,version=1.2.0,deps=sysro>=1.0.0:boot>=2.0.0
    

  • More complex example in .part:

    part appro update=ab,dev=/dev/mmcblk0p5:/dev/mmcblk0p6,version=1.2.0,deps=sysro>=1.0.0:boot==2.1.0:kernel!=1.0.0
    

welma-tagtool Tool

The welma-tagtool command-line tool is used to create and embed version tags into module images. It can be invoked directly for custom tagging scenarios or is called automatically by the Welma build system during image creation.

Basic Syntax

welma-tagtool --module-file INPUT_IMAGE \
              --output-file OUTPUT_IMAGE \
              --module-name MODULE_NAME \
              --version VERSION_STRING \
              [--rules RULES] \
              [--fstype FILESYSTEM_TYPE | --align-tag]
              [--tag-only]

Command-Line Options

Option Short Argument Description
--module-file -m FILE Path to input module image file (optional with --tag-only)
--output-file -o FILE Path to output tagged module file (required)
--module-name -n NAME Module name (max 32 bytes UTF-8) (required)
--version -v VERSION Module version string (max 30 bytes UTF-8) (required)
--rules -r RULES Dependency rules as <module><op><version>:... (optional)
--fstype -f TYPE Filesystem type: ext2, ext3, ext4, or vfat
--align-tag -a - Align tag to 2048-byte boundary
--tag-only - - Generate tag without modifying input file
--list-fstypes -l - List supported filesystem types

Constraints

  • Cannot use both --align-tag and --fstype at the same time
  • Either --module-file or --tag-only is required
  • --tag-only cannot be used with --align-tag or --fstype
  • Maximum of 30 dependency rules per tag: Specifying more than 30 rules will result in an error

Examples

  • Example 1: Tag an ext4 filesystem image
welma-tagtool \
    --module-file appro.ext4 \
    --output-file appro.ext4.tagged \
    --module-name appro \
    --version 1.2.0 \
    --fstype ext4 \
    --rules "sysro>=1.0.0:boot>=2.0.0"

This embeds the version tag immediately after the ext4 filesystem data.

  • Example 2: Generate tag only (no module file)
welma-tagtool \
    --output-file tag.bin \
    --module-name appro \
    --version 1.2.0 \
    --tag-only \
    --rules "sysro>=1.0.0"

This creates a standalone 2048-byte tag file that can be manually appended to module images or used for inspection.

  • Example 3: Complex dependencies with multiple operators
welma-tagtool \
    --module-file appro.ext4 \
    --output-file appro.ext4.tagged \
    --module-name appro \
    --version 1.3.0 \
    --fstype ext4 \
    --rules "sysro>=1.0.0:boot==2.1.0:kernel!=1.0.0:hal<=3.5.0"

Multiple rules are separated by colons (:) and can use different operators.

Output Information

When successfully completing, welma-tagtool prints:

Tag successfully written to <output_file>
Tag size: 2048 bytes
Tag start offset: 0x<offset_in_hex>

The tag start offset indicates where in the output file the 2048-byte tag begins.

Tag Validation

The tag includes a CRC32 checksum covering the entire tag structure (excluding the CRC32 and MAGIC fields). The runtime version probing tools validate this checksum to ensure tag integrity when reading version information.

When Dependency Checking Occurs

Version dependencies are only validated during software updates, not during build time or at boot time. This means:

  • Build time: No validation - incompatible modules CAN be built together
  • Boot time: No validation - incompatible modules CAN be flashed on the same system
  • Update time: Validation occurs - incompatible updates are REJECTED before installation

This design allows maximum flexibility during development and initial deployment, while ensuring system consistency is maintained during runtime updates. The tag information is embedded for documentation and runtime use, not for build-time enforcement.

During normal Yocto builds, welma-tagtool is invoked automatically by the build system to tag all configured modules:

  1. The .part file specifies which partitions should be tagged
  2. For each partition with tag=yes or update mode of ab/single:
    • Module image is located in the build deploy directory
    • welma-tagtool is called with the appropriate parameters
    • Tagged image is installed in the deploy directory

Welma versionctl Tool

versionctl tool is used to query version information from the running system or from update artifacts.

Commands

List all modules:

versionctl list

Shows all system (active/single) modules on the system with their versions and dependencies.

Get a specific module version:

versionctl get MODULE [-i|--inactive]

Shows version information for a specific module. Use the -i|--inactive flag to query the inactive module in A/B systems.

Inspect an artifact:

versionctl artifact ARTIFACT_FILE

Shows all modules and their version information contained in a software package (SWU or Mender artifact).

Probe a specific device:

The versionctl tool can also be used to query version information directly from a specific device or a file using -d|--device argument:

versionctl get appro --device /dev/sda1

versionctl get appro --device appro.ext4

In this case the probing area can be limited by specifying an offset and probing size in bytes with -o|--offset and -s|--size:

# Query bootloader information
versionctl get bootloader --device /dev/mmcblk0 --size 3145728 --offset 32768

Example Usage

# List all active modules with versions
$ versionctl list
sysro (A/B):
 - Version: 1.0.0
 - Dependencies:
   - boot >= 2.0.0

appro (A/B):
 - Version: 1.2.0
 - Dependencies:
   - sysro >= 1.0.0

boot (A/B):
 - Version: 2.1.0

# Check what's in an update artifact
$ versionctl artifact appro-v1.3.0.swu
appro (A/B):
 - Version: 1.3.0
 - Dependencies:
   - sysro >= 1.0.0
   - boot >= 2.0.0

# Query the active module after installation
$ versionctl get appro
appro (A/B):
 - Version: 1.3.0
 - Dependencies:
   - sysro >= 1.0.0
   - boot >= 2.0.0

Runtime Version Checking Example

Typical update sequence with version checking:

# 1. Check current system state
$ versionctl list
sysro (A/B):
 - Version: 1.0.0

appro (A/B):
 - Version: 1.0.0
 - Dependencies:
   - sysro >= 1.0.0

boot (A/B):
 - Version: 2.0.0

# 2. Check what an update contains
$ versionctl artifact appro-v1.1.0.swu
appro (A/B):
 - Version: 1.1.0
 - Dependencies:
   - sysro >= 1.0.0
   - boot >= 2.0.0

# 3. Install update (version checking happens automatically)
$ updatectl install appro-v1.1.0.swu

# 4. Check inactive module before reboot
$ versionctl get appro -i
appro (A/B):
 - Version: 1.1.0
 - Dependencies:
   - sysro >= 1.0.0
   - boot >= 2.0.0

# 5. Check active module after reboot
$ versionctl get appro
appro (A/B):
 - Version: 1.1.0
 - Dependencies:
   - sysro >= 1.0.0
   - boot >= 2.0.0

# 5. Confirm the update
$ updatectl confirm

Error Example

If a module has incompatible dependencies, the installation will fail:

$ versionctl artifact appro-v1.2.0.swu
appro (A/B):
 - Version: 1.2.0
 - Dependencies:
   - sysro >= 2.0.0   # Requires sysro 2.0.0 or later

$ updatectl install appro-v1.2.0.swu
ERROR: Artifact Module appro: compatibility rule 'sysro >= 2.0.0' is not satisfied.

Multiple Module Update

When updating multiple modules together, compatibility is checked across all artifacts in the same transaction first, then with the system:

$ versionctl artifact sysro-v2.0.0.swu
sysro (A/B):
 - Version: 2.0.0

# appro requires sysro >= 2.0.0, and sysro v2.0.0 satisfies this
$ updatectl install appro-v1.2.0.swu sysro-v2.0.0.swu
# Installation OK

See Also