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' insysupdate.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-suggestedswitch ofsystemd-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-namedConditionArchitecture=,ConditionFirmware=,ConditionVirtualization=,ConditionHost=,ConditionFraction=,ConditionKernelCommandLine=,ConditionVersion=,ConditionCredential=,ConditionSecurity=,ConditionOSRelease=andConditionMachineTag=settings for unit files, which are documented over insystemd.unit(5). The feature gets suggested if all the specified conditions apply. And just like theCondition...=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 asx86,x86-64orarm64. Wanna see the whole roster? Peep the architectures defined forConditionArchitecture=insystemd.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 theIMAGE_VERSION=field of/etc/os-release. If it's not set, it resolves to an empty string (rip, nothing there ๐ญ). Seeos-release(5)for more information.%bโ Boot ID ๐ โ the boot ID of the running system, formatted as string. Seerandom(4)for more information.%Bโ Operating system build ID ๐ฆ โ the operating system build identifier of the running system, as read from theBUILD_ID=field of/etc/os-release. If not set, it resolves to an empty string. Seeos-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. somyhost.example.comgets its domain era cut off, periodt.%mโ Machine ID ๐ฅ โ the machine ID of the running system, formatted as string. Seemachine-id(5)for more information.%Mโ Operating system image identifier ๐ โ the operating system image identifier of the running system, as read from theIMAGE_ID=field of/etc/os-release. If not set, it resolves to an empty string. Seeos-release(5)for more information.%oโ Operating system ID ๐ โ the operating system identifier of the running system, as read from theID=field of/etc/os-release. Seeos-release(5)for more information.%vโ Kernel release โญ โ identical touname -routput. literally the same thing, no cap.%wโ Operating system version ID ๐ โ the operating system version identifier of the running system, as read from theVERSION_ID=field of/etc/os-release. If not set, it resolves to an empty string. Seeos-release(5)for more information.%Wโ Operating system variant ID ๐ง โ the operating system variant identifier of the running system, as read from theVARIANT_ID=field of/etc/os-release. If not set, it resolves to an empty string. Seeos-release(5)for more information.%Tโ Directory for temporary files ๐ โ this is either/tmpor 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/tmpor the path"$TMPDIR","$TEMP"or"$TMP"are set to. (Note that the directory may be specified without a trailing slash.) same energy as%Tbut 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/$TMPsituation on both%Tand%Vis 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
- 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