Merge pull request #30016 from dtardon/udevadm-control-p-test
Add test for udevadm control -p
This commit is contained in:
@@ -410,3 +410,30 @@ int device_get_model_string(sd_device *device, const char **ret) {
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int device_get_property_value_with_fallback(
|
||||
sd_device *device,
|
||||
const char *prop,
|
||||
Hashmap *extra_props,
|
||||
const char **ret) {
|
||||
const char *value;
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
assert(prop);
|
||||
assert(ret);
|
||||
|
||||
r = sd_device_get_property_value(device, prop, &value);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
|
||||
value = hashmap_get(extra_props, prop);
|
||||
if (!value)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*ret = value;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "sd-device.h"
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "time-util.h"
|
||||
|
||||
int udev_set_max_log_level(char *str);
|
||||
@@ -25,3 +26,9 @@ bool udev_available(void);
|
||||
|
||||
int device_get_vendor_string(sd_device *device, const char **ret);
|
||||
int device_get_model_string(sd_device *device, const char **ret);
|
||||
|
||||
int device_get_property_value_with_fallback(
|
||||
sd_device *device,
|
||||
const char *prop,
|
||||
Hashmap *extra_props,
|
||||
const char **ret);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+23
-24
@@ -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);
|
||||
@@ -1981,10 +1981,9 @@ static int udev_rule_apply_token_to_event(
|
||||
case TK_M_NAME:
|
||||
return token_match_string(token, event->name);
|
||||
case TK_M_ENV: {
|
||||
const char *val;
|
||||
const char *val = NULL;
|
||||
|
||||
if (sd_device_get_property_value(dev, token->data, &val) < 0)
|
||||
val = hashmap_get(properties_list, token->data);
|
||||
(void) device_get_property_value_with_fallback(dev, token->data, properties_list, &val);
|
||||
|
||||
return token_match_string(token, val);
|
||||
}
|
||||
@@ -2039,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;
|
||||
@@ -2057,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;
|
||||
@@ -2100,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;
|
||||
@@ -2132,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;
|
||||
@@ -2183,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;
|
||||
@@ -2262,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;
|
||||
@@ -2318,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;
|
||||
@@ -2379,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;
|
||||
@@ -2402,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;
|
||||
@@ -2424,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;
|
||||
@@ -2476,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;
|
||||
@@ -2520,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,
|
||||
@@ -2530,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,
|
||||
@@ -2555,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;
|
||||
@@ -2592,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;
|
||||
@@ -2630,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;
|
||||
@@ -2702,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;
|
||||
@@ -2722,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,
|
||||
@@ -2757,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}",
|
||||
|
||||
@@ -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);
|
||||
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/util.sh
|
||||
. "$(dirname "$0")"/util.sh
|
||||
|
||||
# Test for `udevadm control -p`
|
||||
|
||||
test_not_property() {
|
||||
assert_eq "$(udevadm info --query property --property "$2" --value "$1")" ""
|
||||
}
|
||||
|
||||
test_property() {
|
||||
assert_eq "$(udevadm info --query property --property "$2" --value "$1")" "$3"
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2317
|
||||
cleanup() {
|
||||
set +e
|
||||
|
||||
udevadm control -p FOO= -p BAR=
|
||||
|
||||
rm -f "$rules"
|
||||
}
|
||||
|
||||
# Set up a test device
|
||||
trap cleanup EXIT
|
||||
|
||||
rules="/run/udev/rules.d/99-test-17.13.rules"
|
||||
|
||||
mkdir -p "${rules%/*}"
|
||||
cat > "$rules" <<'EOF'
|
||||
ENV{FOO}=="?*", ENV{PROP_FOO}="$env{FOO}"
|
||||
ENV{BAR}=="?*", ENV{PROP_BAR}="$env{BAR}"
|
||||
EOF
|
||||
|
||||
udevadm control --reload
|
||||
|
||||
test_not_property /dev/null PROP_FOO
|
||||
test_not_property /dev/null PROP_BAR
|
||||
|
||||
: Setting of a property works
|
||||
|
||||
udevadm control --property FOO=foo
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_property /dev/null PROP_FOO foo
|
||||
test_not_property /dev/null PROP_BAR
|
||||
|
||||
: Change of a property works
|
||||
|
||||
udevadm control --property FOO=goo
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_property /dev/null PROP_FOO goo
|
||||
|
||||
: Removal of a property works
|
||||
|
||||
udevadm control --property FOO=
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_not_property /dev/null PROP_FOO
|
||||
|
||||
: Repeated removal of a property does nothing
|
||||
|
||||
udevadm control --property FOO=
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_not_property /dev/null PROP_FOO
|
||||
|
||||
: Multiple properties can be set at once
|
||||
|
||||
udevadm control --property FOO=foo --property BAR=bar
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_property /dev/null PROP_FOO foo
|
||||
test_property /dev/null PROP_BAR bar
|
||||
|
||||
: Multiple setting of the same property is handled correctly
|
||||
|
||||
udevadm control --property FOO=foo --property FOO=42
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_property /dev/null PROP_FOO 42
|
||||
|
||||
: Mix of settings and removals of the same property is handled correctly
|
||||
|
||||
udevadm control -p FOO= -p FOO=foo -p BAR=car -p BAR=
|
||||
udevadm trigger --action change --settle /dev/null
|
||||
test_property /dev/null PROP_FOO foo
|
||||
test_not_property /dev/null PROP_BAR
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user