core,udev,networkd: add ConditionKernelVersion=
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Dec 2017 19:34:13 +0000 (20:34 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 26 Dec 2017 16:39:44 +0000 (17:39 +0100)
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.

19 files changed:
man/systemd.link.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.unit.xml
src/core/load-fragment-gperf.gperf.m4
src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/shared/condition.c
src/shared/condition.h
src/test/test-condition.c
src/udev/net/link-config-gperf.gperf
src/udev/net/link-config.c
src/udev/net/link-config.h

index 162674f..fb091b8 100644 (file)
           for details.</para>
         </listitem>
       </varlistentry>
+        <varlistentry>
+          <term><varname>KernelVersion=</varname></term>
+          <listitem>
+            <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
+            expression (or if prefixed with the exclamation mark does not match it). See
+            <literal>ConditionKernelVersion=</literal> in
+            <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+            details.
+            </para>
+          </listitem>
+        </varlistentry>
       <varlistentry>
         <term><varname>Architecture=</varname></term>
         <listitem>
index 4e5d47f..b9647a2 100644 (file)
         </listitem>
       </varlistentry>
       <varlistentry>
+        <term><varname>KernelVersion=</varname></term>
+        <listitem>
+          <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
+          expression (or if prefixed with the exclamation mark does not match it). See
+          <literal>ConditionKernelVersion=</literal> in
+          <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
         <term><varname>Architecture=</varname></term>
         <listitem>
           <para>Checks whether the system is running on a specific
index 3466f3a..f78beaa 100644 (file)
           </listitem>
         </varlistentry>
         <varlistentry>
+          <term><varname>KernelVersion=</varname></term>
+          <listitem>
+            <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
+            expression (or if prefixed with the exclamation mark does not match it). See
+            <literal>ConditionKernelVersion=</literal> in
+            <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+            details.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
           <term><varname>Architecture=</varname></term>
           <listitem>
             <para>Checks whether the system is running on a specific
index 005fdea..0d35d61 100644 (file)
         <term><varname>ConditionVirtualization=</varname></term>
         <term><varname>ConditionHost=</varname></term>
         <term><varname>ConditionKernelCommandLine=</varname></term>
+        <term><varname>ConditionKernelVersion=</varname></term>
         <term><varname>ConditionSecurity=</varname></term>
         <term><varname>ConditionCapability=</varname></term>
         <term><varname>ConditionACPower=</varname></term>
         the exact assignment is looked for with right and left hand
         side matching.</para>
 
+        <para><varname>ConditionKernelVersion=</varname> may be used to check whether the kernel version (as reported
+        by <command>uname -r</command>) 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.</para>
+
         <para><varname>ConditionSecurity=</varname> may be used to
         check whether the given security module is enabled on the
         system. Currently, the recognized values are
         <term><varname>AssertVirtualization=</varname></term>
         <term><varname>AssertHost=</varname></term>
         <term><varname>AssertKernelCommandLine=</varname></term>
+        <term><varname>AssertKernelVersion=</varname></term>
         <term><varname>AssertSecurity=</varname></term>
         <term><varname>AssertCapability=</varname></term>
         <term><varname>AssertACPower=</varname></term>
index 5604312..549c7eb 100644 (file)
@@ -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)
index e48b7d2..c20e9fc 100644 (file)
@@ -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)
index a54adac..4e69f1a 100644 (file)
@@ -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,
index 3aeba06..03b8661 100644 (file)
@@ -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)
index 7afe30f..7cf1106 100644 (file)
@@ -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;
 
index 24915b2..507b86a 100644 (file)
@@ -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;
index 57a96af..cb0c01f 100644 (file)
@@ -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)
index 8e37a0a..b037fc6 100644 (file)
@@ -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) {
index 49c6265..702aa76 100644 (file)
@@ -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;
index d4bbaf3..887c9a7 100644 (file)
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -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",
index 715866b..98af2da 100644 (file)
@@ -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,
index bf455aa..8fb2ad5 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <stdio.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #include "sd-id128.h"
 #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();
index 85f0a06..5cb126d 100644 (file)
@@ -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)
index 92d41a6..a4368f0 100644 (file)
@@ -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)),
index a413251..dabc3ef 100644 (file)
@@ -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;