Skip to content

Commit cbcdcaa

Browse files
Uwe Kleine-Königpoettering
authored andcommitted
Add support for conditions on the machines firmware
This allows to limit units to machines that run on a certain firmware type. For device tree defined machines checking against the machine's compatible is also possible.
1 parent 192a9d9 commit cbcdcaa

File tree

12 files changed

+120
-0
lines changed

12 files changed

+120
-0
lines changed

docs/TRANSIENT-SETTINGS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Most generic unit settings are available for transient units.
6868
✓ ConditionKernelCommandLine=
6969
✓ ConditionKernelVersion=
7070
✓ ConditionArchitecture=
71+
✓ ConditionFirmware=
7172
✓ ConditionVirtualization=
7273
✓ ConditionSecurity=
7374
✓ ConditionCapability=

man/systemd.link.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@
222222
</para>
223223
</listitem>
224224
</varlistentry>
225+
226+
<varlistentry id='firmware'>
227+
<term><varname>Firmware=</varname></term>
228+
<listitem>
229+
<para>Checks whether the system is running on a machine with the specified firmware. See
230+
<varname>ConditionFirmware=</varname> in
231+
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
232+
for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
233+
If an empty string is assigned, then previously assigned value is cleared.
234+
</para>
235+
</listitem>
236+
</varlistentry>
225237
</variablelist>
226238

227239
</refsect1>

man/systemd.netdev.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,17 @@
258258
</para>
259259
</listitem>
260260
</varlistentry>
261+
<varlistentry>
262+
<term><varname>Firmware=</varname></term>
263+
<listitem>
264+
<para>Checks whether the system is running on a machine with the specified firmware. See
265+
<literal>ConditionFirmware=</literal> in
266+
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
267+
for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
268+
If an empty string is assigned, then previously assigned value is cleared.
269+
</para>
270+
</listitem>
271+
</varlistentry>
261272
</variablelist>
262273
</refsect1>
263274

man/systemd.unit.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,16 @@
11721172
</listitem>
11731173
</varlistentry>
11741174

1175+
<varlistentry>
1176+
<term><varname>ConditionFirmware=</varname></term>
1177+
1178+
<listitem><para>Check whether the system's firmware is of a certain type. Possible values are:
1179+
<literal>uefi</literal> (for systems with EFI),
1180+
<literal>device-tree</literal> (for systems with a device tree) and
1181+
<literal>device-tree-compatible(xyz)</literal> (for systems with a device tree that is compatible to <literal>xyz</literal>).</para>
1182+
</listitem>
1183+
</varlistentry>
1184+
11751185
<varlistentry>
11761186
<term><varname>ConditionVirtualization=</varname></term>
11771187

src/core/load-fragment-gperf.gperf.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ Unit.ConditionFileIsExecutable, config_parse_unit_condition_path,
297297
Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions)
298298
Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions)
299299
Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions)
300+
Unit.ConditionFirmware, config_parse_unit_condition_string, CONDITION_FIRMWARE, offsetof(Unit, conditions)
300301
Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions)
301302
Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions)
302303
Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions)

src/network/netdev/netdev-gperf.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Match.Virtualization, config_parse_net_condition,
4444
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, conditions)
4545
Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(NetDev, conditions)
4646
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, conditions)
47+
Match.Firmware, config_parse_net_condition, CONDITION_FIRMWARE, offsetof(NetDev, conditions)
4748
NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
4849
NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
4950
NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)

src/network/networkd-network-gperf.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Match.Virtualization, config_parse_net_condition,
5656
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, conditions)
5757
Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(Network, conditions)
5858
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, conditions)
59+
Match.Firmware, config_parse_net_condition, CONDITION_FIRMWARE, offsetof(Network, conditions)
5960
Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
6061
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(Network, mtu)
6162
Link.Group, config_parse_uint32, 0, offsetof(Network, group)

src/shared/condition.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <fnmatch.h>
66
#include <limits.h>
77
#include <stdlib.h>
8+
#include <sys/stat.h>
89
#include <sys/types.h>
910
#include <sys/utsname.h>
1011
#include <time.h>
@@ -450,6 +451,81 @@ static int condition_test_architecture(Condition *c, char **env) {
450451
return a == b;
451452
}
452453

454+
#define DTCOMPAT_FILE "/sys/firmware/devicetree/base/compatible"
455+
static int condition_test_firmware_devicetree_compatible(const char *dtcarg) {
456+
int r;
457+
_cleanup_free_ char *dtcompat = NULL;
458+
_cleanup_strv_free_ char **dtcompatlist = NULL;
459+
size_t size;
460+
461+
r = read_full_virtual_file(DTCOMPAT_FILE, &dtcompat, &size);
462+
if (r < 0) {
463+
/* if the path doesn't exist it is incompatible */
464+
if (r != -ENOENT)
465+
log_debug_errno(r, "Failed to open() '%s', assuming machine is incompatible: %m", DTCOMPAT_FILE);
466+
return false;
467+
}
468+
469+
/* Not sure this can happen, but play safe. */
470+
if (size == 0) {
471+
log_debug("%s has zero length, assuming machine is incompatible", DTCOMPAT_FILE);
472+
return false;
473+
}
474+
475+
/*
476+
* /sys/firmware/devicetree/base/compatible consists of one or more
477+
* strings, each ending in '\0'. So the last character in dtcompat must
478+
* be a '\0'.
479+
*/
480+
if (dtcompat[size - 1] != '\0') {
481+
log_debug("%s is in an unknown format, assuming machine is incompatible", DTCOMPAT_FILE);
482+
return false;
483+
}
484+
485+
dtcompatlist = strv_parse_nulstr(dtcompat, size);
486+
if (!dtcompatlist)
487+
return -ENOMEM;
488+
489+
return strv_contains(dtcompatlist, dtcarg);
490+
}
491+
492+
static int condition_test_firmware(Condition *c, char **env) {
493+
sd_char *dtc;
494+
495+
assert(c);
496+
assert(c->parameter);
497+
assert(c->type == CONDITION_FIRMWARE);
498+
499+
if (streq(c->parameter, "device-tree")) {
500+
if (access("/sys/firmware/device-tree/", F_OK) < 0) {
501+
if (errno != ENOENT)
502+
log_debug_errno(errno, "Unexpected error when checking for /sys/firmware/device-tree/: %m");
503+
return false;
504+
} else
505+
return true;
506+
} else if ((dtc = startswith(c->parameter, "device-tree-compatible("))) {
507+
_cleanup_free_ char *dtcarg = NULL;
508+
char *end;
509+
510+
end = strchr(dtc, ')');
511+
if (!end || *(end + 1) != '\0') {
512+
log_debug("Malformed Firmware condition \"%s\"", c->parameter);
513+
return false;
514+
}
515+
516+
dtcarg = strndup(dtc, end - dtc);
517+
if (!dtcarg)
518+
return -ENOMEM;
519+
520+
return condition_test_firmware_devicetree_compatible(dtcarg);
521+
} else if (streq(c->parameter, "uefi"))
522+
return is_efi_boot();
523+
else {
524+
log_debug("Unsupported Firmware condition \"%s\"", c->parameter);
525+
return false;
526+
}
527+
}
528+
453529
static int condition_test_host(Condition *c, char **env) {
454530
_cleanup_free_ char *h = NULL;
455531
sd_id128_t x, y;
@@ -843,6 +919,7 @@ int condition_test(Condition *c, char **env) {
843919
[CONDITION_HOST] = condition_test_host,
844920
[CONDITION_AC_POWER] = condition_test_ac_power,
845921
[CONDITION_ARCHITECTURE] = condition_test_architecture,
922+
[CONDITION_FIRMWARE] = condition_test_firmware,
846923
[CONDITION_NEEDS_UPDATE] = condition_test_needs_update,
847924
[CONDITION_FIRST_BOOT] = condition_test_first_boot,
848925
[CONDITION_USER] = condition_test_user,
@@ -949,6 +1026,7 @@ void condition_dump_list(Condition *first, FILE *f, const char *prefix, conditio
9491026

9501027
static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
9511028
[CONDITION_ARCHITECTURE] = "ConditionArchitecture",
1029+
[CONDITION_FIRMWARE] = "ConditionFirmware",
9521030
[CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
9531031
[CONDITION_HOST] = "ConditionHost",
9541032
[CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
@@ -981,6 +1059,7 @@ DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
9811059

9821060
static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
9831061
[CONDITION_ARCHITECTURE] = "AssertArchitecture",
1062+
[CONDITION_FIRMWARE] = "AssertFirmware",
9841063
[CONDITION_VIRTUALIZATION] = "AssertVirtualization",
9851064
[CONDITION_HOST] = "AssertHost",
9861065
[CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",

src/shared/condition.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
typedef enum ConditionType {
1111
CONDITION_ARCHITECTURE,
12+
CONDITION_FIRMWARE,
1213
CONDITION_VIRTUALIZATION,
1314
CONDITION_HOST,
1415
CONDITION_KERNEL_COMMAND_LINE,

test/fuzz/fuzz-netdev-parser/directives.netdev

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Mode=
2222
SourceMACAddress=
2323
[Match]
2424
Architecture=
25+
Firmware=
2526
Host=
2627
KernelVersion=
2728
Virtualization=

0 commit comments

Comments
 (0)