From 5022f08a23c0b64973b74cd71be9f5122ec655a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Dec 2017 20:34:13 +0100 Subject: [PATCH] core,udev,networkd: add ConditionKernelVersion= This adds a simple condition/assert/match to the service manager, to udev's .link handling and to networkd, for matching the kernel version string. In this version we only do fnmatch() based globbing, but we might want to extend that to version comparisons later on, if we like, by slightly extending the syntax with ">=", "<=", ">", "<" and "==" expressions. --- man/systemd.link.xml | 11 ++++++ man/systemd.netdev.xml | 10 ++++++ man/systemd.network.xml | 11 ++++++ man/systemd.unit.xml | 6 ++++ src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/libsystemd-network/network-internal.c | 8 +++-- src/libsystemd-network/network-internal.h | 3 +- src/network/netdev/netdev-gperf.gperf | 3 +- src/network/netdev/netdev.c | 6 ++-- src/network/netdev/netdev.h | 3 +- src/network/networkd-network-gperf.gperf | 3 +- src/network/networkd-network.c | 7 ++-- src/network/networkd-network.h | 3 +- src/shared/condition.c | 16 +++++++++ src/shared/condition.h | 1 + src/test/test-condition.c | 42 +++++++++++++++++++++-- src/udev/net/link-config-gperf.gperf | 3 +- src/udev/net/link-config.c | 6 ++-- src/udev/net/link-config.h | 3 +- 19 files changed, 129 insertions(+), 18 deletions(-) diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 162674f769..fb091b883c 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -172,6 +172,17 @@ for details. + + KernelVersion= + + Checks whether the kernel version (as reported by uname -r) matches a certain + expression (or if prefixed with the exclamation mark does not match it). See + ConditionKernelVersion= in + systemd.unit5 for + details. + + + Architecture= diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 4e5d47f585..b9647a2f7a 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -232,6 +232,16 @@ + + KernelVersion= + + Checks whether the kernel version (as reported by uname -r) matches a certain + expression (or if prefixed with the exclamation mark does not match it). See + ConditionKernelVersion= in + systemd.unit5 for details. + + + Architecture= diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 3466f3a3cf..f78beaa7dc 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -193,6 +193,17 @@ + + KernelVersion= + + Checks whether the kernel version (as reported by uname -r) matches a certain + expression (or if prefixed with the exclamation mark does not match it). See + ConditionKernelVersion= in + systemd.unit5 for + details. + + + Architecture= diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 005fdea73c..0d35d619e0 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -923,6 +923,7 @@ ConditionVirtualization= ConditionHost= ConditionKernelCommandLine= + ConditionKernelVersion= ConditionSecurity= ConditionCapability= ConditionACPower= @@ -1050,6 +1051,10 @@ the exact assignment is looked for with right and left hand side matching. + ConditionKernelVersion= may be used to check whether the kernel version (as reported + by uname -r) matches a certain expression (or if prefixed with the exclamation mark does not + match it). The argument must be a single string, optionally containing shell-style globs. + ConditionSecurity= may be used to check whether the given security module is enabled on the system. Currently, the recognized values are @@ -1201,6 +1206,7 @@ AssertVirtualization= AssertHost= AssertKernelCommandLine= + AssertKernelVersion= AssertSecurity= AssertCapability= AssertACPower= diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5604312bc5..549c7eb4d6 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -241,6 +241,7 @@ Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_F Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions) Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions) Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions) +Unit.ConditionKernelVersion, config_parse_unit_condition_string, CONDITION_KERNEL_VERSION, offsetof(Unit, conditions) Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions) Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions) Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions) @@ -263,6 +264,7 @@ Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_F Unit.AssertNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, asserts) Unit.AssertFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, asserts) Unit.AssertKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts) +Unit.AssertKernelVersion, config_parse_unit_condition_string, CONDITION_KERNEL_VERSION, offsetof(Unit, asserts) Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts) Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts) Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts) diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index e48b7d22dd..c20e9fca35 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -116,7 +116,8 @@ bool net_match_config(const struct ether_addr *match_mac, char * const *match_names, Condition *match_host, Condition *match_virt, - Condition *match_kernel, + Condition *match_kernel_cmdline, + Condition *match_kernel_version, Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, @@ -131,7 +132,10 @@ bool net_match_config(const struct ether_addr *match_mac, if (match_virt && condition_test(match_virt) <= 0) return false; - if (match_kernel && condition_test(match_kernel) <= 0) + if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0) + return false; + + if (match_kernel_version && condition_test(match_kernel_version) <= 0) return false; if (match_arch && condition_test(match_arch) <= 0) diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index a54adac602..4e69f1a598 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -37,7 +37,8 @@ bool net_match_config(const struct ether_addr *match_mac, char * const *match_name, Condition *match_host, Condition *match_virt, - Condition *match_kernel, + Condition *match_kernel_cmdline, + Condition *match_kernel_version, Condition *match_arch, const struct ether_addr *dev_mac, const char *dev_path, diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 3aeba06ee0..03b8661957 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -33,7 +33,8 @@ struct ConfigPerfItem; %% Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt) -Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel) +Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel_cmdline) +Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(NetDev, match_kernel_version) Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch) NetDev.Description, config_parse_string, 0, offsetof(NetDev, description) NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 7afe30f7fb..7cf110672f 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -149,7 +149,8 @@ static void netdev_free(NetDev *netdev) { condition_free_list(netdev->match_host); condition_free_list(netdev->match_virt); - condition_free_list(netdev->match_kernel); + condition_free_list(netdev->match_kernel_cmdline); + condition_free_list(netdev->match_kernel_version); condition_free_list(netdev->match_arch); if (NETDEV_VTABLE(netdev) && @@ -642,7 +643,8 @@ static int netdev_load_one(Manager *manager, const char *filename) { /* skip out early if configuration does not match the environment */ if (net_match_config(NULL, NULL, NULL, NULL, NULL, netdev_raw->match_host, netdev_raw->match_virt, - netdev_raw->match_kernel, netdev_raw->match_arch, + netdev_raw->match_kernel_cmdline, netdev_raw->match_kernel_version, + netdev_raw->match_arch, NULL, NULL, NULL, NULL, NULL, NULL) <= 0) return 0; diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 24915b2b04..507b86a078 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -93,7 +93,8 @@ typedef struct NetDev { Condition *match_host; Condition *match_virt; - Condition *match_kernel; + Condition *match_kernel_cmdline; + Condition *match_kernel_version; Condition *match_arch; NetDevState state; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 57a96aff94..cb0c01fbe7 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -27,7 +27,8 @@ Match.Type, config_parse_strv, Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt) -Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel) +Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel_cmdline) +Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(Network, match_kernel_version) Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 8e37a0a229..b037fc67e3 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -431,7 +431,8 @@ void network_free(Network *network) { condition_free_list(network->match_host); condition_free_list(network->match_virt); - condition_free_list(network->match_kernel); + condition_free_list(network->match_kernel_cmdline); + condition_free_list(network->match_kernel_version); condition_free_list(network->match_arch); free(network->dhcp_server_timezone); @@ -485,8 +486,8 @@ int network_get(Manager *manager, struct udev_device *device, if (net_match_config(network->match_mac, network->match_path, network->match_driver, network->match_type, network->match_name, network->match_host, - network->match_virt, network->match_kernel, - network->match_arch, + network->match_virt, network->match_kernel_cmdline, + network->match_kernel_version, network->match_arch, address, path, parent_driver, driver, devtype, ifname)) { if (network->match_name && device) { diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 49c62654b6..702aa7692a 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -112,7 +112,8 @@ struct Network { Condition *match_host; Condition *match_virt; - Condition *match_kernel; + Condition *match_kernel_cmdline; + Condition *match_kernel_version; Condition *match_arch; char *description; diff --git a/src/shared/condition.c b/src/shared/condition.c index d4bbaf3c65..887c9a7588 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -143,6 +144,18 @@ static int condition_test_kernel_command_line(Condition *c) { return false; } +static int condition_test_kernel_version(Condition *c) { + struct utsname u; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_KERNEL_VERSION); + + assert_se(uname(&u) >= 0); + + return fnmatch(c->parameter, u.release, 0) == 0; +} + static int condition_test_user(Condition *c) { uid_t id; int r; @@ -552,6 +565,7 @@ int condition_test(Condition *c) { [CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty, [CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable, [CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line, + [CONDITION_KERNEL_VERSION] = condition_test_kernel_version, [CONDITION_VIRTUALIZATION] = condition_test_virtualization, [CONDITION_SECURITY] = condition_test_security, [CONDITION_CAPABILITY] = condition_test_capability, @@ -612,6 +626,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", [CONDITION_HOST] = "ConditionHost", [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", + [CONDITION_KERNEL_VERSION] = "ConditionKernelVersion", [CONDITION_SECURITY] = "ConditionSecurity", [CONDITION_CAPABILITY] = "ConditionCapability", [CONDITION_AC_POWER] = "ConditionACPower", @@ -639,6 +654,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_VIRTUALIZATION] = "AssertVirtualization", [CONDITION_HOST] = "AssertHost", [CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine", + [CONDITION_KERNEL_VERSION] = "AssertKernelVersion", [CONDITION_SECURITY] = "AssertSecurity", [CONDITION_CAPABILITY] = "AssertCapability", [CONDITION_AC_POWER] = "AssertACPower", diff --git a/src/shared/condition.h b/src/shared/condition.h index 715866be70..98af2daaee 100644 --- a/src/shared/condition.h +++ b/src/shared/condition.h @@ -31,6 +31,7 @@ typedef enum ConditionType { CONDITION_VIRTUALIZATION, CONDITION_HOST, CONDITION_KERNEL_COMMAND_LINE, + CONDITION_KERNEL_VERSION, CONDITION_SECURITY, CONDITION_CAPABILITY, CONDITION_AC_POWER, diff --git a/src/test/test-condition.c b/src/test/test-condition.c index bf455aac89..8fb2ad5d18 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "sd-id128.h" @@ -38,10 +39,11 @@ #include "selinux-util.h" #include "set.h" #include "smack-util.h" +#include "string-util.h" #include "strv.h" -#include "virt.h" -#include "util.h" #include "user-util.h" +#include "util.h" +#include "virt.h" static void test_condition_test_path(void) { Condition *condition; @@ -298,6 +300,41 @@ static void test_condition_test_kernel_command_line(void) { condition_free(condition); } +static void test_condition_test_kernel_version(void) { + Condition *condition; + struct utsname u; + + condition = condition_new(CONDITION_KERNEL_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false); + assert_se(condition); + assert_se(!condition_test(condition)); + condition_free(condition); + + condition = condition_new(CONDITION_KERNEL_VERSION, "*", false, false); + assert_se(condition); + assert_se(condition_test(condition)); + condition_free(condition); + + condition = condition_new(CONDITION_KERNEL_VERSION, "", false, false); + assert_se(condition); + assert_se(!condition_test(condition)); + condition_free(condition); + + assert_se(uname(&u) >= 0); + + condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false); + assert_se(condition); + assert_se(condition_test(condition)); + condition_free(condition); + + strshorten(u.release, 4); + strcpy(strchr(u.release, 0), "*"); + + condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false); + assert_se(condition); + assert_se(condition_test(condition)); + condition_free(condition); +} + static void test_condition_test_null(void) { Condition *condition; @@ -556,6 +593,7 @@ int main(int argc, char *argv[]) { test_condition_test_host(); test_condition_test_architecture(); test_condition_test_kernel_command_line(); + test_condition_test_kernel_version(); test_condition_test_null(); test_condition_test_security(); test_condition_test_virtualization(); diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 85f0a0625b..5cb126d870 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -26,7 +26,8 @@ Match.Driver, config_parse_strv, 0, Match.Type, config_parse_strv, 0, offsetof(link_config, match_type) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, match_host) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, match_virt) -Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, match_kernel) +Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, match_kernel_cmdline) +Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(link_config, match_kernel_version) Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, match_arch) Link.Description, config_parse_string, 0, offsetof(link_config, description) Link.MACAddressPolicy, config_parse_mac_policy, 0, offsetof(link_config, mac_policy) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 92d41a6e95..a4368f088d 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -77,7 +77,8 @@ static void link_config_free(link_config *link) { free(link->match_name); free(link->match_host); free(link->match_virt); - free(link->match_kernel); + free(link->match_kernel_cmdline); + free(link->match_kernel_version); free(link->match_arch); free(link->description); @@ -248,7 +249,8 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device, if (net_match_config(link->match_mac, link->match_path, link->match_driver, link->match_type, link->match_name, link->match_host, - link->match_virt, link->match_kernel, link->match_arch, + link->match_virt, link->match_kernel_cmdline, + link->match_kernel_version, link->match_arch, attr_value ? ether_aton(attr_value) : NULL, udev_device_get_property_value(device, "ID_PATH"), udev_device_get_driver(udev_device_get_parent(device)), diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index a413251bd0..dabc3eff8f 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -58,7 +58,8 @@ struct link_config { char **match_name; Condition *match_host; Condition *match_virt; - Condition *match_kernel; + Condition *match_kernel_cmdline; + Condition *match_kernel_version; Condition *match_arch; char *description; -- 2.25.1