SYSUPDATE.FEATURES(5)

๐ŸŒธ SYSUPDATE.FEATURES(5) โ€” Definition Files for Optional Features ๐ŸŒธ

okay bestie, welcome to sysupdate.features, the manual page that tells you all about Optional Features in systemd-sysupdate(8). grab a boba, this one's a whole saga (we're doing it in parts, don't worry).


โœจ SYNOPSIS โœจ

/etc/sysupdate.d/*.feature
/run/sysupdate.d/*.feature
/usr/local/lib/sysupdate.d/*.feature
/usr/lib/sysupdate.d/*.feature

๐Ÿ’… DESCRIPTION ๐Ÿ’…

so. "Optional Features" are this whole thing that systemd-sysupdate(8) provides, and the idea is: a distribution gets to define little bundles of sysupdate.d(5) transfer definitions, and those bundles are meant to be turned on or off by whoever runs the system (that's you, or your admin, or a very fancy tool).

When a feature is enabled, its transfers get considered whenever sysupdate checks for updates, downloads updates, does vacuuming, and honestly in all the other situations too. Basically: transfers that belong to a feature get updated in lock-step with the rest of their target, always, no exceptions. That lock-step thing is literally the main character difference between an Optional Feature and a plain old systemd-sysupdate(8) component.

When a feature is disabled, its transfers do not get considered when checking for or downloading updates โ€” but systemd-sysupdate still thinks about them while vacuuming, and in other spots where it needs to figure out who owns previously downloaded system resources. and here's the dramatic part: systemd-sysupdate will clean up all instances of that feature's transfers whenever it's disabled, which effectively uninstalls the whole feature. gone. periodt.

Optional Features are described by sysupdate.d/*.feature files, and those are what we're defining below. Transfers can declare that they belong to a feature through the Features= setting. Feature definitions support drop-in files, which are most commonly used to override the Enabled= setting. They can also be masked, which hides the availability of the feature entirely. ๐Ÿซฅ

Each *.feature file contains exactly one section: [Feature].


๐ŸŽ€ [FEATURE] SECTION OPTIONS ๐ŸŽ€

This section is where all the general properties of the feature live. let's go one by one.

  • Description= โ€” a short, human-readable description of this feature. it might get used as a label for the feature, so likeโ€ฆ make the string actually meaningfully identify which feature it is among all the other features chillin' in sysupdate.d/. no cryptic nonsense bestie ๐Ÿ’–

Added in version 257.

  • Documentation= โ€” one or more user-presentable URLs pointing at documentation about this feature. you can specify this setting more than once. If you assign the empty string to it, the list gets reset and all prior assignments stop having any effect. It supports specifier expansion; scroll down for the deets on which specifiers are supported. โœจ

Support for specifying this setting more than once was added in version 262.

Added in version 257.

  • AppStream= โ€” a URL to an AppStream catalog[1] XML file. software centers (think GNOME Software or KDE Discover) can use this to show off rich metadata about the feature โ€” display names, changelogs, icons, all of it. this setting supports specifier expansion; again, details below. ๐Ÿฆ‹

Added in version 257.

  • Enabled= โ€” whether or not this feature is enabled. If you don't specify it, the feature is disabled by default. ๐Ÿ™ˆ

Added in version 257.

  • Suggest= โ€” takes a boolean argument. If true, the feature is suggested for enablement; if false, it isn't. Important: this does not enable the feature by itself, it's just a hint that the update tools surface (for example via the --feature-suggested switch of systemd-sysupdate(8)), so that the system administrator or higher-level tooling can act on it if they feel like it.

If this setting is not specified, the SuggestOn...= conditions described below get evaluated instead to figure out whether the feature is suggested. And if neither this setting nor any SuggestOn...= condition is specified, the feature is simply not suggested. no hint, no vibe.

Added in version 262.

  • SuggestOnArchitecture=, SuggestOnFirmware=, SuggestOnVirtualization=, SuggestOnHost=, SuggestOnFraction=, SuggestOnKernelCommandLine=, SuggestOnVersion=, SuggestOnCredential=, SuggestOnSecurity=, SuggestOnOSRelease=, SuggestOnMachineTag= โ€” these suggest the feature for enablement depending on system properties. They take the same arguments and implement the same semantics โ€” including the leading "!" for negation โ€” as the identically-named ConditionArchitecture=, ConditionFirmware=, ConditionVirtualization=, ConditionHost=, ConditionFraction=, ConditionKernelCommandLine=, ConditionVersion=, ConditionCredential=, ConditionSecurity=, ConditionOSRelease= and ConditionMachineTag= settings for unit files, which are documented over in systemd.unit(5). The feature gets suggested if all the specified conditions apply. And just like the Condition...= settings, assigning an empty string to one of these resets the list. ๐Ÿงš

These conditions are only evaluated if Suggest= is not specified.

Added in version 262.


part 1 done bestie, stay tuned โ€” there's more coming and we're not done yet ๐Ÿ’œ

โœจ SPECIFIERS โœจ

okay so real talk โ€” you can drop these little specifier thingies into the Documentation= and AppStream= settings ๐Ÿ’ซ. Think of them as magic placeholder tokens that get swapped out for actual system info when systemd does its thing. Here's every single expansion it understands (this is Table 1, Specifiers available, and bestie I transcribed it ALL) ๐Ÿซถ:

  • %a โ€” Architecture ๐ŸŒˆ โ€” a short string identifying the architecture of the local system. Like a string such as x86, x86-64 or arm64. Wanna see the whole roster? Peep the architectures defined for ConditionArchitecture= in systemd.unit(5), that's where the full list lives.
  • %A โ€” Operating system image version ๐Ÿ’– โ€” the operating system image version identifier of the running system, as read from the IMAGE_VERSION= field of /etc/os-release. If it's not set, it resolves to an empty string (rip, nothing there ๐Ÿ˜ญ). See os-release(5) for more information.
  • %b โ€” Boot ID ๐ŸŽ€ โ€” the boot ID of the running system, formatted as string. See random(4) for more information.
  • %B โ€” Operating system build ID ๐Ÿฆ‹ โ€” the operating system build identifier of the running system, as read from the BUILD_ID= field of /etc/os-release. If not set, it resolves to an empty string. See os-release(5) for more information.
  • %H โ€” Host name ๐Ÿ‘‘ โ€” the hostname of the running system. that's it, that's the whole vibe.
  • %l โ€” Short host name ๐ŸŒธ โ€” the hostname of the running system, truncated at the first dot to remove any domain component. so myhost.example.com gets its domain era cut off, periodt.
  • %m โ€” Machine ID ๐Ÿ”ฅ โ€” the machine ID of the running system, formatted as string. See machine-id(5) for more information.
  • %M โ€” Operating system image identifier ๐Ÿ’… โ€” the operating system image identifier of the running system, as read from the IMAGE_ID= field of /etc/os-release. If not set, it resolves to an empty string. See os-release(5) for more information.
  • %o โ€” Operating system ID ๐ŸŒˆ โ€” the operating system identifier of the running system, as read from the ID= field of /etc/os-release. See os-release(5) for more information.
  • %v โ€” Kernel release โญ โ€” identical to uname -r output. literally the same thing, no cap.
  • %w โ€” Operating system version ID ๐Ÿ“ โ€” the operating system version identifier of the running system, as read from the VERSION_ID= field of /etc/os-release. If not set, it resolves to an empty string. See os-release(5) for more information.
  • %W โ€” Operating system variant ID ๐Ÿงš โ€” the operating system variant identifier of the running system, as read from the VARIANT_ID= field of /etc/os-release. If not set, it resolves to an empty string. See os-release(5) for more information.
  • %T โ€” Directory for temporary files ๐Ÿ’œ โ€” this is either /tmp or the path "$TMPDIR", "$TEMP" or "$TMP" are set to. (Note that the directory may be specified without a trailing slash.) ๐Ÿ™ˆ
  • %V โ€” Directory for larger and persistent temporary files ๐Ÿ’€ โ€” this is either /var/tmp or the path "$TMPDIR", "$TEMP" or "$TMP" are set to. (Note that the directory may be specified without a trailing slash.) same energy as %T but for the big-girl persistent temp files, iykyk.
  • %% โ€” Single percent sign โœจ โ€” use "%%" in place of "%" to specify a single percent sign. yes queen, you gotta escape it or it'll try to expand something and embarrass you in front of everyone ๐Ÿ˜ญ.

ngl the $TMPDIR / $TEMP / $TMP situation on both %T and %V is exactly as written above โ€” don't come for me, I just report the facts ๐Ÿ’–

โœจ EXAMPLES โœจ

okay bestie, this is the fun part โ€” actual real-life scenarios where features do their thing ๐Ÿ’–

๐Ÿ› ๏ธ Example 1. Development Tools for Image-Based OS

so we're rolling with the hypothetical "foobarOS" from sysupdate.d(5) as our example base OS, right? and like, the vast majority of foobarOS's users genuinely have zero need for a compiler, a build system, a debugger, and all that other development-tools goodness hanging out inside their OS. but the developers of foobarOS themselves? they absolutely need this build tooling to be available. so foobarOS needs to ship a system extension image (peep systemd-sysext(8)) containing these development tools, and that image has to be updated in lock-step with the underlying base OS. this is, like, a perfect use case for an optional OS feature, so let's define one:

# /usr/lib/sysupdate.d/devel.feature
[Feature]
Description=Development Tools
Documentation=https://developer.example.com/foobarOS/getting-started
Enabled=false

the above defines the devel feature, and disables it by default (as it should ๐Ÿ’…). now let's define a transfer that's associated with this feature:

# /usr/lib/sysupdate.d/50-devel.transfer
[Transfer]
Features=devel
ProtectVersion=%A

[Source]
Type=url-file
Path=https://download.example.com/
MatchPattern=foobarOS_@v_devel.raw.xz

[Target]
Type=regular-file
Path=/var/lib/extensions
MatchPattern=foobarOS_@v_devel.raw
Mode=0444
InstancesMax=2

with these two files, we have created a feature called devel that, when enabled, will download and decompress the appropriate version of https://download.example.com/foobarOS_@v_devel.raw.xz into /var/lib/extensions/foobarOS_@v_devel.raw during each OS update. slay. ๐Ÿ”ฅ

the developers of foobarOS can enable the devel feature on their workstations by creating the following drop-in:

# /etc/sysupdate.d/devel.feature.d/enable.conf
[Feature]
Enabled=true

๐ŸŽฎ Example 2. Proprietary Drivers

suppose that many of foobarOS's users have a GPU manufactured by the MVISUAL corporation ๐Ÿ‘‘ due to lack of documentation and difficulty in reverse-engineering the hardware, the open-source drivers for MVISUAL GPUs are unable to make proper use of available graphics and compute performance. MVISUAL provides a redistributable proprietary driver for their cards, and foobarOS's developers distribute them to address their users' needs.

MVISUAL's driver has a couple different parts that must be installed for it to function, and we're listing all of them, no skips:

  • a UKI addon to configure the kernel command-line
  • an initrd system extension image to add the MVISUAL kernel module into the initrd
  • a regular system extension image to add the proprietary OpenGL and Vulkan userspace drivers

all of these should be version-locked to the core OS, periodt.

let's start by defining an optional feature named mvisual-driver:

# /usr/lib/sysupdate.d/mvisual-driver.feature
[Feature]
Description=MVISUAL Proprietary GPU Driver
Documentation=https://support.example.com/foobarOS/mvisual
AppStream=https://metadata.example.com/mvisual-driver-%A.xml.gz

note that we define AppStream metadata for this feature, because we want software centers to present it to end-users โœจ next, let's define the corresponding transfers:

# /usr/lib/sysupdate.d/50-mvisual-userspace.transfer
[Transfer]
Features=mvisual-driver
ProtectVersion=%A

[Source]
Type=url-file
Path=https://download.example.com/
MatchPattern=foobarOS_@v_mvisual_userspace.raw.xz

[Target]
Type=regular-file
Path=/var/lib/extensions
MatchPattern=foobarOS_@v_mvisual.raw
Mode=0444
InstancesMax=2

# /usr/lib/sysupdate.d/70-mvisual-initrd.transfer
[Transfer]
Features=mvisual-driver
ProtectVersion=%A

[Source]
Type=url-file
Path=https://download.example.com/
MatchPattern=foobarOS_@v_mvisual_initrd.raw.xz

[Target]
Type=regular-file
Path=/EFI/Linux
PathRelativeTo=boot
MatchPattern=foobarOS_@v.efi.extra.d/foobarOS_mvisual.raw
Mode=0444
InstancesMax=2

# /usr/lib/sysupdate.d/90-mvisual-addon.transfer
[Transfer]
Features=mvisual-driver
ProtectVersion=%A

[Source]
Type=url-file
Path=https://download.example.com/
MatchPattern=foobarOS_@v_mvisual_addon.efi.xz

[Target]
Type=regular-file
Path=/EFI/Linux
PathRelativeTo=boot
MatchPattern=foobarOS_@v.efi.extra.d/foobarOS_mvisual.addon.efi
Mode=0444
InstancesMax=2

๐ŸŒˆ Example 3. Intersecting Features

suppose that MVISUAL releases special tooling to help a distribution developer troubleshoot crashes in their proprietary driver ๐Ÿฆ‹ let's define a transfer:

# /usr/lib/sysupdate.d/50-mvisual-debugger.transfer
[Transfer]
RequisiteFeatures=devel mvisual-driver
ProtectVersion=%A

[Source]
Type=url-file
Path=https://download.example.com/
MatchPattern=foobarOS_@v_devel.raw.xz

[Target]
Type=regular-file
Path=/var/lib/extensions
MatchPattern=foobarOS_@v_devel.raw
Mode=0444
InstancesMax=2

this transfer will be used only if both the devel and mvisual-driver features are enabled ๐Ÿ‘ฏโ€โ™€๏ธ


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€


๐Ÿ“ NOTES

  1. AppStream catalog โ€” https://www.freedesktop.org/software/appstream/docs/chap-CatalogData.html

and that's a wrap bestie ๐ŸŽ€ this was SYSUPDATE.FEATURES(5) from systemd 262.1 โ€” go forth, define your features, lock those versions, and stay iconic ๐Ÿ’–โœจ๐Ÿฆ‹ no cap, you ate. ๐Ÿ’…

๐Ÿ“ฆ where this page comes from
  • arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms