From 854b3c0485a0e5d6c75537a300724cf16f6a21f2 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Mon, 13 Nov 2023 16:23:37 +0100 Subject: [PATCH] udev: allow global properties in assignments 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 | 6 ++++-- src/udev/udev-format.h | 1 + src/udev/udev-rules.c | 42 ++++++++++++++++++++--------------------- src/udev/udevadm-test.c | 2 +- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/udev/udev-format.c b/src/udev/udev-format.c index b17b754b5e1..05ed9fdff79 100644 --- a/src/udev/udev-format.c +++ b/src/udev/udev-format.c @@ -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", diff --git a/src/udev/udev-format.h b/src/udev/udev-format.h index 9914dc03b2d..92fef9baca7 100644 --- a/src/udev/udev-format.h +++ b/src/udev/udev-format.h @@ -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); diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index d30c2f923e9..5f120023948 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -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}", diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index 8590bf3bf55..809143ede0b 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -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); -- 2.47.3