dcavalca / rpms / systemd

Forked from rpms/systemd 4 months ago
Clone
ff2b41
From be88b819ecec075187ac313b8ab15d8ed8004b54 Mon Sep 17 00:00:00 2001
ff2b41
From: Jan Synacek <jsynacek@redhat.com>
ff2b41
Date: Wed, 11 Sep 2019 12:35:18 +0200
ff2b41
Subject: [PATCH] udev: introduce CONST key name
ff2b41
ff2b41
Currently, there is no way to match against system-wide constants, such
ff2b41
as architecture or virtualization type, without forking helper binaries.
ff2b41
That potentially results in a huge number of spawned processes which
ff2b41
output always the same answer.
ff2b41
ff2b41
This patch introduces a special CONST keyword which takes a hard-coded
ff2b41
string as its key and returns a value assigned to that key. Currently
ff2b41
implemented are CONST{arch} and CONST{virt}, which can be used to match
ff2b41
against the system's architecture and virtualization type.
ff2b41
ff2b41
(based on commit 4801d8afe2ff1c1c075c9f0bc5631612172e0bb7)
ff2b41
ff2b41
Resolves: #1748051
ff2b41
---
ff2b41
 man/udev.xml              | 26 ++++++++++++++++++++++++++
ff2b41
 rules/40-redhat.rules     |  4 ++--
ff2b41
 src/udev/udev-rules.c     | 39 +++++++++++++++++++++++++++++++++++++++
ff2b41
 test/rule-syntax-check.py |  2 +-
ff2b41
 4 files changed, 68 insertions(+), 3 deletions(-)
ff2b41
ff2b41
diff --git a/man/udev.xml b/man/udev.xml
ff2b41
index a948ea79a9..fc02edd214 100644
ff2b41
--- a/man/udev.xml
ff2b41
+++ b/man/udev.xml
ff2b41
@@ -240,6 +240,32 @@
ff2b41
           </listitem>
ff2b41
         </varlistentry>
ff2b41
 
ff2b41
+        <varlistentry>
ff2b41
+          <term><varname>CONST{<replaceable>key</replaceable>}</varname></term>
ff2b41
+          <listitem>
ff2b41
+            <para>Match against a system-wide constant. Supported keys are:</para>
ff2b41
+            <variablelist>
ff2b41
+              <varlistentry>
ff2b41
+                <term><literal>arch</literal></term>
ff2b41
+                <listitem>
ff2b41
+                  <para>System's architecture. See <option>ConditionArchitecture=</option> in
ff2b41
+                  <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
ff2b41
+                  for possible values.</para>
ff2b41
+                </listitem>
ff2b41
+              </varlistentry>
ff2b41
+              <varlistentry>
ff2b41
+                <term><literal>virt</literal></term>
ff2b41
+                <listitem>
ff2b41
+                  <para>System's virtualization environment. See
ff2b41
+                  <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
ff2b41
+                  for possible values.</para>
ff2b41
+                </listitem>
ff2b41
+              </varlistentry>
ff2b41
+            </variablelist>
ff2b41
+            <para>Unknown keys will never match.</para>
ff2b41
+          </listitem>
ff2b41
+        </varlistentry>
ff2b41
+
ff2b41
         <varlistentry>
ff2b41
           <term><varname>TAG</varname></term>
ff2b41
           <listitem>
ff2b41
diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
ff2b41
index 2c690e522e..83d823e172 100644
ff2b41
--- a/rules/40-redhat.rules
ff2b41
+++ b/rules/40-redhat.rules
ff2b41
@@ -6,10 +6,10 @@ SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}
ff2b41
 # Memory hotadd request
ff2b41
 SUBSYSTEM!="memory", GOTO="memory_hotplug_end"
ff2b41
 ACTION!="add", GOTO="memory_hotplug_end"
ff2b41
-PROGRAM="/bin/uname -p", RESULT=="s390*", GOTO="memory_hotplug_end"
ff2b41
+CONST{arch}=="s390*", GOTO="memory_hotplug_end"
ff2b41
 
ff2b41
 ENV{.state}="online"
ff2b41
-PROGRAM="/bin/systemd-detect-virt", RESULT=="none", ENV{.state}="online_movable"
ff2b41
+CONST{virt}=="none", ENV{.state}="online_movable"
ff2b41
 ATTR{state}=="offline", ATTR{state}="$env{.state}"
ff2b41
 
ff2b41
 LABEL="memory_hotplug_end"
ff2b41
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
ff2b41
index c9a0197534..9211f563b1 100644
ff2b41
--- a/src/udev/udev-rules.c
ff2b41
+++ b/src/udev/udev-rules.c
ff2b41
@@ -29,12 +29,14 @@
ff2b41
 #include <fnmatch.h>
ff2b41
 #include <time.h>
ff2b41
 
ff2b41
+#include "architecture.h"
ff2b41
 #include "udev.h"
ff2b41
 #include "path-util.h"
ff2b41
 #include "conf-files.h"
ff2b41
 #include "strbuf.h"
ff2b41
 #include "strv.h"
ff2b41
 #include "util.h"
ff2b41
+#include "virt.h"
ff2b41
 
ff2b41
 #define PREALLOC_TOKEN          2048
ff2b41
 
ff2b41
@@ -123,6 +125,7 @@ enum token_type {
ff2b41
         TK_M_DEVLINK,                   /* val */
ff2b41
         TK_M_NAME,                      /* val */
ff2b41
         TK_M_ENV,                       /* val, attr */
ff2b41
+        TK_M_CONST,                     /* val, attr */
ff2b41
         TK_M_TAG,                       /* val */
ff2b41
         TK_M_SUBSYSTEM,                 /* val */
ff2b41
         TK_M_DRIVER,                    /* val */
ff2b41
@@ -257,6 +260,7 @@ static const char *token_str(enum token_type type) {
ff2b41
                 [TK_M_DEVLINK] =                "M DEVLINK",
ff2b41
                 [TK_M_NAME] =                   "M NAME",
ff2b41
                 [TK_M_ENV] =                    "M ENV",
ff2b41
+                [TK_M_CONST] =                  "M CONST",
ff2b41
                 [TK_M_TAG] =                    "M TAG",
ff2b41
                 [TK_M_SUBSYSTEM] =              "M SUBSYSTEM",
ff2b41
                 [TK_M_DRIVER] =                 "M DRIVER",
ff2b41
@@ -365,6 +369,7 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
ff2b41
         case TK_M_ATTR:
ff2b41
         case TK_M_ATTRS:
ff2b41
         case TK_M_ENV:
ff2b41
+        case TK_M_CONST:
ff2b41
         case TK_A_ATTR:
ff2b41
         case TK_A_ENV:
ff2b41
                 log_debug("%s %s '%s' '%s'(%s)",
ff2b41
@@ -905,6 +910,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
ff2b41
                 token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
ff2b41
                 break;
ff2b41
         case TK_M_ENV:
ff2b41
+        case TK_M_CONST:
ff2b41
         case TK_M_ATTR:
ff2b41
         case TK_M_ATTRS:
ff2b41
         case TK_A_ATTR:
ff2b41
@@ -1264,6 +1270,22 @@ static int add_rule(struct udev_rules *rules, char *line,
ff2b41
                         continue;
ff2b41
                 }
ff2b41
 
ff2b41
+                if (startswith(key, "CONST{")) {
ff2b41
+                        attr = get_key_attribute(rules->udev, key + STRLEN("CONST"));
ff2b41
+                        if (attr == NULL || !STR_IN_SET(attr, "arch", "virt")) {
ff2b41
+                                log_error("error parsing CONST attribute");
ff2b41
+                                goto invalid;
ff2b41
+                        }
ff2b41
+                        if (op == OP_REMOVE) {
ff2b41
+                                log_error("invalid CONST operation");
ff2b41
+                                goto invalid;
ff2b41
+                        }
ff2b41
+                        if (op < OP_MATCH_MAX) {
ff2b41
+                                if (rule_add_key(&rule_tmp, TK_M_CONST, op, value, attr) != 0)
ff2b41
+                                        goto invalid;
ff2b41
+                        }
ff2b41
+                        continue;
ff2b41
+                }
ff2b41
                 if (streq(key, "TAG")) {
ff2b41
                         if (op < OP_MATCH_MAX)
ff2b41
                                 rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
ff2b41
@@ -1959,6 +1981,23 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
ff2b41
                                 goto nomatch;
ff2b41
                         break;
ff2b41
                 }
ff2b41
+                case TK_M_CONST: {
ff2b41
+                        const char *key_name = rules_str(rules, cur->key.attr_off);
ff2b41
+                        const char *value = NULL;
ff2b41
+                        int q;
ff2b41
+
ff2b41
+                        if (streq(key_name, "arch")) {
ff2b41
+                                q = uname_architecture();
ff2b41
+                                value = architecture_to_string(q);
ff2b41
+                        } else if (streq(key_name, "virt")) {
ff2b41
+                                q = detect_virtualization(&value);
ff2b41
+                        } else
ff2b41
+                                assert_not_reached("Invalid CONST key");
ff2b41
+
ff2b41
+                        if (match_key(rules, cur, value))
ff2b41
+                                goto nomatch;
ff2b41
+                        break;
ff2b41
+                }
ff2b41
                 case TK_M_TAG: {
ff2b41
                         struct udev_list_entry *list_entry;
ff2b41
                         bool match = false;
ff2b41
diff --git a/test/rule-syntax-check.py b/test/rule-syntax-check.py
ff2b41
index 80bbe65bea..c6d003b167 100644
ff2b41
--- a/test/rule-syntax-check.py
ff2b41
+++ b/test/rule-syntax-check.py
ff2b41
@@ -34,7 +34,7 @@ else:
ff2b41
     rules_files = glob(os.path.join(rules_dir, '*.rules'))
ff2b41
 
ff2b41
 no_args_tests = re.compile('(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|RESULT|TEST)\s*(?:=|!)=\s*"([^"]*)"$')
ff2b41
-args_tests = re.compile('(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*"([^"]*)"$')
ff2b41
+args_tests = re.compile('(ATTRS?|ENV|CONST|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*"([^"]*)"$')
ff2b41
 no_args_assign = re.compile('(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|PROGRAM|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*"([^"]*)"$')
ff2b41
 args_assign = re.compile('(ATTR|ENV|IMPORT|RUN){([a-zA-Z0-9/_.*%-]+)}\s*(=|\+=)\s*"([^"]*)"$')
ff2b41