udev: allow global properties in assignments
authorDavid Tardon <dtardon@redhat.com>
Mon, 13 Nov 2023 15:23:37 +0000 (16:23 +0100)
committerDavid Tardon <dtardon@redhat.com>
Mon, 13 Nov 2023 18:19:54 +0000 (19:19 +0100)
Before, handling of global properties (set on systemd-udevd by `udevadm
control -p FOO=foo`) was inconsistent. They were honored in ENV matches,
but not in any assignment. This meant that any use of $env{FOO} (where
FOO was a global property) expanded to an empty string.

src/udev/udev-format.c
src/udev/udev-format.h
src/udev/udev-rules.c
src/udev/udevadm-test.c

index b17b754b5e17d7415d4d376d5a7c27d9603473e6..05ed9fdff79482f8b9814176b9d7a91f9cd6e451 100644 (file)
@@ -156,6 +156,7 @@ static ssize_t udev_event_subst_format(
                 const char *attr,
                 char *dest,
                 size_t l,
+                Hashmap *global_props,
                 bool *ret_truncated) {
 
         sd_device *parent, *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
@@ -348,7 +349,7 @@ static ssize_t udev_event_subst_format(
         case FORMAT_SUBST_ENV:
                 if (isempty(attr))
                         return -EINVAL;
-                r = sd_device_get_property_value(dev, attr, &val);
+                r = device_get_property_value_with_fallback(dev, attr, global_props, &val);
                 if (r == -ENOENT)
                         goto null_terminate;
                 if (r < 0)
@@ -378,6 +379,7 @@ size_t udev_event_apply_format(
                 char *dest,
                 size_t size,
                 bool replace_whitespace,
+                Hashmap *global_props,
                 bool *ret_truncated) {
 
         bool truncated = false;
@@ -410,7 +412,7 @@ size_t udev_event_apply_format(
                         continue;
                 }
 
-                subst_len = udev_event_subst_format(event, type, attr, dest, size, &t);
+                subst_len = udev_event_subst_format(event, type, attr, dest, size, global_props, &t);
                 if (subst_len < 0) {
                         log_device_warning_errno(event->dev, subst_len,
                                                  "Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m",
index 9914dc03b2d133a524ba5f80e4764fef8e54f084..92fef9baca764fdd2b7806421e50cef072b9414d 100644 (file)
@@ -14,6 +14,7 @@ size_t udev_event_apply_format(
                 char *dest,
                 size_t size,
                 bool replace_whitespace,
+                Hashmap *global_props,
                 bool *ret_truncated);
 int udev_check_format(const char *value, size_t *offset, const char **hint);
 
index d30c2f923e9e1c2c744eac681405f3f32de0ab40..5f120023948d07f04b6475007b2b08c30bb49c32 100644 (file)
@@ -1761,7 +1761,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
 
         switch (token->attr_subst_type) {
         case SUBST_TYPE_FORMAT:
-                (void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false, &truncated);
+                (void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false, NULL, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "sysfs attribute name", name,
                                             token->type == TK_M_ATTR ? "ATTR" : "ATTRS", /* is_match = */ true);
@@ -2038,7 +2038,7 @@ static int udev_rule_apply_token_to_event(
                 char buf[UDEV_PATH_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "sysctl entry name", token->data, "SYSCTL", /* is_match = */ true);
                         return false;
@@ -2056,7 +2056,7 @@ static int udev_rule_apply_token_to_event(
                 struct stat statbuf;
                 bool match, truncated;
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "file name", token->value, "TEST", /* is_match = */ true);
                         return false;
@@ -2099,7 +2099,7 @@ static int udev_rule_apply_token_to_event(
                 size_t count;
 
                 event->program_result = mfree(event->program_result);
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "command", token->value, "PROGRAM", /* is_match = */ true);
                         return false;
@@ -2131,7 +2131,7 @@ static int udev_rule_apply_token_to_event(
                 char buf[UDEV_PATH_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "file name to be imported", token->value, "IMPORT", /* is_match = */ true);
                         return false;
@@ -2182,7 +2182,7 @@ static int udev_rule_apply_token_to_event(
                 char buf[UDEV_LINE_SIZE], result[UDEV_LINE_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "command", token->value, "IMPORT", /* is_match = */ true);
                         return false;
@@ -2261,7 +2261,7 @@ static int udev_rule_apply_token_to_event(
                         event->builtin_run |= mask;
                 }
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "builtin command", token->value, "IMPORT", /* is_match = */ true);
                         return false;
@@ -2317,7 +2317,7 @@ static int udev_rule_apply_token_to_event(
                 char buf[UDEV_PATH_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "property name", token->value, "IMPORT", /* is_match = */ true);
                         return false;
@@ -2378,7 +2378,7 @@ static int udev_rule_apply_token_to_event(
                 if (token->op == OP_ASSIGN_FINAL)
                         event->owner_final = true;
 
-                (void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "user name", token->value, "OWNER", /* is_match = */ false);
                         break;
@@ -2401,7 +2401,7 @@ static int udev_rule_apply_token_to_event(
                 if (token->op == OP_ASSIGN_FINAL)
                         event->group_final = true;
 
-                (void) udev_event_apply_format(event, token->value, group, sizeof(group), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, group, sizeof(group), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "group name", token->value, "GROUP", /* is_match = */ false);
                         break;
@@ -2423,7 +2423,7 @@ static int udev_rule_apply_token_to_event(
                 if (token->op == OP_ASSIGN_FINAL)
                         event->mode_final = true;
 
-                (void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "mode", token->value, "MODE", /* is_match = */ false);
                         break;
@@ -2475,7 +2475,7 @@ static int udev_rule_apply_token_to_event(
                 if (!name)
                         return log_oom();
 
-                (void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "security label", token->value, "SECLABEL", /* is_match = */ false);
                         break;
@@ -2519,7 +2519,7 @@ static int udev_rule_apply_token_to_event(
                 }
 
                 if (token->op == OP_ADD &&
-                    sd_device_get_property_value(dev, name, &val) >= 0) {
+                    device_get_property_value_with_fallback(dev, name, properties_list, &val) >= 0) {
                         l = strpcpyl_full(&p, l, &truncated, val, " ", NULL);
                         if (truncated) {
                                 log_event_warning(dev, token,
@@ -2529,7 +2529,7 @@ static int udev_rule_apply_token_to_event(
                         }
                 }
 
-                (void) udev_event_apply_format(event, token->value, p, l, false, &truncated);
+                (void) udev_event_apply_format(event, token->value, p, l, false, properties_list, &truncated);
                 if (truncated) {
                         _cleanup_free_ char *key_with_name = strjoin("ENV{", name, "}");
                         log_event_truncated(dev, token, "property value", token->value,
@@ -2554,7 +2554,7 @@ static int udev_rule_apply_token_to_event(
                 char buf[UDEV_PATH_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "tag name", token->value, "TAG", /* is_match = */ false);
                         break;
@@ -2591,7 +2591,7 @@ static int udev_rule_apply_token_to_event(
                         break;
                 }
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "network interface name", token->value, "NAME", /* is_match = */ false);
                         break;
@@ -2629,7 +2629,7 @@ static int udev_rule_apply_token_to_event(
                         device_cleanup_devlinks(dev);
 
                 (void) udev_event_apply_format(event, token->value, buf, sizeof(buf),
-                                               /* replace_whitespace = */ event->esc != ESCAPE_NONE, &truncated);
+                                               /* replace_whitespace = */ event->esc != ESCAPE_NONE, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "symbolic link path", token->value, "SYMLINK", /* is_match = */ false);
                         break;
@@ -2701,7 +2701,7 @@ static int udev_rule_apply_token_to_event(
                         log_event_error_errno(dev, token, r, "Could not find file matches '%s', ignoring: %m", buf);
                         break;
                 }
-                (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "attribute value", token->value, "ATTR", /* is_match = */ false);
                         break;
@@ -2721,13 +2721,13 @@ static int udev_rule_apply_token_to_event(
                 char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "sysctl entry name", token->data, "SYSCTL", /* is_match = */ false);
                         break;
                 }
 
-                (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, properties_list, &truncated);
                 if (truncated) {
                         _cleanup_free_ char *key_with_name = strjoin("SYSCTL{", buf, "}");
                         log_event_truncated(dev, token, "sysctl value", token->value,
@@ -2756,7 +2756,7 @@ static int udev_rule_apply_token_to_event(
                 if (IN_SET(token->op, OP_ASSIGN, OP_ASSIGN_FINAL))
                         ordered_hashmap_clear_free_key(event->run_list);
 
-                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
+                (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, properties_list, &truncated);
                 if (truncated) {
                         log_event_truncated(dev, token, "command", token->value,
                                             token->type == TK_A_RUN_BUILTIN ? "RUN{builtin}" : "RUN{program}",
index 8590bf3bf55e40e59f46835025ac4fbab6e41795..809143ede0bc584ad15ff079307a8fa6444386fb 100644 (file)
@@ -138,7 +138,7 @@ int test_main(int argc, char *argv[], void *userdata) {
                 char program[UDEV_PATH_SIZE];
                 bool truncated;
 
-                (void) udev_event_apply_format(event, cmd, program, sizeof(program), false, &truncated);
+                (void) udev_event_apply_format(event, cmd, program, sizeof(program), false, NULL, &truncated);
                 if (truncated)
                         log_warning("The command '%s' is truncated while substituting into '%s'.", program, cmd);
                 printf("run: '%s'\n", program);