diff options
author | Dmitry V. Levin <ldv@strace.io> | 2023-03-20 08:00:00 +0000 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-03-21 09:34:50 +0900 |
commit | f0a16c9ae8cc9fd7719e58cc3b858ced64bd67da (patch) | |
tree | 661d37eb1ca60f461a58776e02b99d86b6e1c863 | |
parent | 92035969e0d75295eece85b4371f460ec7d60e4f (diff) | |
download | systemd-f0a16c9ae8cc9fd7719e58cc3b858ced64bd67da.tar.gz |
udev-rules: add another check for conflicting expressions
Log an error when a rule line contains the following kind of conflicting
match expressions:
KEY=="foo", KEY=="bar"
-rw-r--r-- | src/udev/udev-rules.c | 42 | ||||
-rwxr-xr-x | test/units/testsuite-17.11.sh | 3 |
2 files changed, 40 insertions, 5 deletions
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index f708f79c9a..4859a142da 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -1409,6 +1409,28 @@ static bool tokens_eq(const UdevRuleToken *a, const UdevRuleToken *b) { token_type_and_data_eq(a, b); } +static bool nulstr_tokens_conflict(const UdevRuleToken *a, const UdevRuleToken *b) { + assert(a); + assert(b); + + if (!(a->type == b->type && + type_has_nulstr_value(a->type) && + a->op == b->op && + a->op == OP_MATCH && + a->match_type == b->match_type && + a->match_type == MATCH_TYPE_PLAIN && + a->attr_subst_type == b->attr_subst_type && + a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace && + token_type_and_data_eq(a, b))) + return false; + + NULSTR_FOREACH(i, a->value) + if (nulstr_contains(b->value, i)) + return false; + + return true; +} + static void udev_check_unused_labels(UdevRuleLine *line) { assert(line); @@ -1424,14 +1446,24 @@ static void udev_check_conflicts_duplicates(UdevRuleLine *line) { LIST_FOREACH(tokens, token, line->tokens) LIST_FOREACH(tokens, i, token->tokens_next) { - if (!tokens_eq(token, i)) + bool new_conflicts = false, new_duplicates = false; + + if (tokens_eq(token, i)) { + if (!duplicates && token->op == i->op) + new_duplicates = true; + if (!conflicts && conflicting_op(token->op, i->op)) + new_conflicts = true; + } else if (!conflicts && nulstr_tokens_conflict(token, i)) + new_conflicts = true; + else continue; - if (!duplicates && token->op == i->op) { - duplicates = true; + + if (new_duplicates) { + duplicates = new_duplicates; log_line_warning(line, "duplicate expressions"); } - if (!conflicts && conflicting_op(token->op, i->op)) { - conflicts = true; + if (new_conflicts) { + conflicts = new_conflicts; log_line_error(line, "conflicting match expressions, the line takes no effect"); } if (conflicts && duplicates) diff --git a/test/units/testsuite-17.11.sh b/test/units/testsuite-17.11.sh index 5f067f02b2..88172acde6 100755 --- a/test/units/testsuite-17.11.sh +++ b/test/units/testsuite-17.11.sh @@ -278,6 +278,7 @@ test_syntax_error 'a="b"' "Invalid key 'a'" test_syntax_error 'KERNEL=="", KERNEL=="?*", NAME="a"' 'conflicting match expressions, the line takes no effect' test_syntax_error 'KERNEL=="abc", KERNEL!="abc", NAME="b"' 'conflicting match expressions, the line takes no effect' test_syntax_error 'KERNEL=="|a|b", KERNEL!="b|a|", NAME="c"' 'conflicting match expressions, the line takes no effect' +test_syntax_error 'KERNEL=="a|b", KERNEL=="c|d|e", NAME="f"' 'conflicting match expressions, the line takes no effect' # shellcheck disable=SC2016 test_syntax_error 'ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", ENV{DISKSEQ}!="?*" ENV{ID_IGNORE_DISKSEQ}!="1", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}"' \ 'conflicting match expressions, the line takes no effect' @@ -290,6 +291,8 @@ test_syntax_error 'ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", ENV{DISKSEQ}== cat >"${rules}" <<'EOF' KERNEL=="a|b", KERNEL=="a|c", NAME="d" KERNEL=="a|b", KERNEL!="a|c", NAME="d" +KERNEL!="a", KERNEL!="b", NAME="c" +KERNEL=="|a", KERNEL=="|b", NAME="c" EOF assert_0 "${rules}" |