diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 1855367072..e33d6c3073 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include #include @@ -2070,3 +2071,27 @@ bool set_equal(Set *a, Set *b) { return true; } + +static bool set_fnmatch_one(Set *patterns, const char *needle) { + const char *p; + + assert(needle); + + SET_FOREACH(p, patterns) + if (fnmatch(p, needle, 0) == 0) + return true; + + return false; +} + +bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) { + assert(needle); + + if (set_fnmatch_one(exclude_patterns, needle)) + return false; + + if (set_isempty(include_patterns)) + return true; + + return set_fnmatch_one(include_patterns, needle); +} diff --git a/src/basic/set.h b/src/basic/set.h index 5cae13160b..243a747e98 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -153,3 +153,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret); bool set_equal(Set *a, Set *b); + +bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle); diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index bdf76b467b..ccc321ec33 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -776,4 +776,5 @@ global: sd_device_new_from_devname; sd_device_new_from_path; sd_device_open; + sd_device_enumerator_add_nomatch_sysname; } LIBSYSTEMD_250; diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h index 5aaa384095..cf62fabdad 100644 --- a/src/libsystemd/sd-device/device-enumerator-private.h +++ b/src/libsystemd/sd-device/device-enumerator-private.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #include "sd-device.h" typedef enum MatchInitializedType { diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 757f748927..3af9e36a5a 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -42,6 +42,7 @@ struct sd_device_enumerator { Hashmap *nomatch_sysattr; Hashmap *match_property; Set *match_sysname; + Set *nomatch_sysname; Set *match_tag; Set *match_parent; MatchInitializedType match_initialized; @@ -96,6 +97,7 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer hashmap_free(enumerator->nomatch_sysattr); hashmap_free(enumerator->match_property); set_free(enumerator->match_sysname); + set_free(enumerator->nomatch_sysname); set_free(enumerator->match_tag); set_free(enumerator->match_parent); @@ -183,13 +185,13 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume return 1; } -_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) { +static int device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname, bool match) { int r; assert_return(enumerator, -EINVAL); assert_return(sysname, -EINVAL); - r = set_put_strdup(&enumerator->match_sysname, sysname); + r = set_put_strdup(match ? &enumerator->match_sysname : &enumerator->nomatch_sysname, sysname); if (r <= 0) return r; @@ -198,6 +200,14 @@ _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumer return 1; } +_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) { + return device_enumerator_add_match_sysname(enumerator, sysname, true); +} + +_public_ int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, const char *sysname) { + return device_enumerator_add_match_sysname(enumerator, sysname, false); +} + _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) { int r; @@ -500,19 +510,10 @@ static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) { } static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) { - const char *sysname_match; - assert(enumerator); assert(sysname); - if (set_isempty(enumerator->match_sysname)) - return true; - - SET_FOREACH(sysname_match, enumerator->match_sysname) - if (fnmatch(sysname_match, sysname, 0) == 0) - return true; - - return false; + return set_fnmatch(enumerator->match_sysname, enumerator->nomatch_sysname, sysname); } static int match_initialized(sd_device_enumerator *enumerator, sd_device *device) { @@ -580,25 +581,12 @@ static int test_matches( } static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) { - const char *subsystem_match; - assert(enumerator); if (!subsystem) return false; - SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem) - if (fnmatch(subsystem_match, subsystem, 0) == 0) - return false; - - if (set_isempty(enumerator->match_subsystem)) - return true; - - SET_FOREACH(subsystem_match, enumerator->match_subsystem) - if (fnmatch(subsystem_match, subsystem, 0) == 0) - return true; - - return false; + return set_fnmatch(enumerator->match_subsystem, enumerator->nomatch_subsystem, subsystem); } static int enumerator_add_parent_devices( diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index 7bc6135406..3bd3761f3b 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -182,6 +182,10 @@ TEST(sd_device_enumerator_devices) { assert_se(sd_device_enumerator_new(&e) >= 0); assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0); + /* On some CI environments, it seems some loop block devices and corresponding bdi devices sometimes + * disappear during running this test. Let's exclude them here for stability. */ + assert_se(sd_device_enumerator_add_match_subsystem(e, "bdi", false) >= 0); + assert_se(sd_device_enumerator_add_nomatch_sysname(e, "loop*") >= 0); FOREACH_DEVICE(e, d) test_sd_device_one(d); } @@ -208,6 +212,8 @@ static void test_sd_device_enumerator_filter_subsystem_one( assert_se(sd_device_enumerator_new(&e) >= 0); assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, true) >= 0); + if (streq(subsystem, "block")) + assert_se(sd_device_enumerator_add_nomatch_sysname(e, "loop*") >= 0); FOREACH_DEVICE(e, d) { const char *syspath; @@ -250,6 +256,9 @@ TEST(sd_device_enumerator_filter_subsystem) { assert_se(subsystems = hashmap_new(&string_hash_ops)); assert_se(sd_device_enumerator_new(&e) >= 0); + /* See comments in TEST(sd_device_enumerator_devices). */ + assert_se(sd_device_enumerator_add_match_subsystem(e, "bdi", false) >= 0); + assert_se(sd_device_enumerator_add_nomatch_sysname(e, "loop*") >= 0); FOREACH_DEVICE(e, d) { const char *syspath, *subsystem; diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index f0c3c115e4..2d12288864 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -126,6 +126,7 @@ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, c int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match); int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value); int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname); +int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, const char *sysname); int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag); int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent); int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator); diff --git a/src/test/test-set.c b/src/test/test-set.c index 4dd98ef4f8..5c5c35f3a2 100644 --- a/src/test/test-set.c +++ b/src/test/test-set.c @@ -330,4 +330,50 @@ TEST(set_equal) { assert_se(set_equal(b, a)); } +TEST(set_fnmatch) { + _cleanup_set_free_ Set *match = NULL, *nomatch = NULL; + + assert_se(set_put_strdup(&match, "aaa") >= 0); + assert_se(set_put_strdup(&match, "bbb*") >= 0); + assert_se(set_put_strdup(&match, "*ccc") >= 0); + + assert_se(set_put_strdup(&nomatch, "a*") >= 0); + assert_se(set_put_strdup(&nomatch, "bbb") >= 0); + assert_se(set_put_strdup(&nomatch, "ccc*") >= 0); + + assert_se(set_fnmatch(NULL, NULL, "")); + assert_se(set_fnmatch(NULL, NULL, "hoge")); + + assert_se(set_fnmatch(match, NULL, "aaa")); + assert_se(set_fnmatch(match, NULL, "bbb")); + assert_se(set_fnmatch(match, NULL, "bbbXXX")); + assert_se(set_fnmatch(match, NULL, "ccc")); + assert_se(set_fnmatch(match, NULL, "XXXccc")); + assert_se(!set_fnmatch(match, NULL, "")); + assert_se(!set_fnmatch(match, NULL, "aaaa")); + assert_se(!set_fnmatch(match, NULL, "XXbbb")); + assert_se(!set_fnmatch(match, NULL, "cccXX")); + + assert_se(set_fnmatch(NULL, nomatch, "")); + assert_se(set_fnmatch(NULL, nomatch, "Xa")); + assert_se(set_fnmatch(NULL, nomatch, "bbbb")); + assert_se(set_fnmatch(NULL, nomatch, "XXXccc")); + assert_se(!set_fnmatch(NULL, nomatch, "a")); + assert_se(!set_fnmatch(NULL, nomatch, "aXXXX")); + assert_se(!set_fnmatch(NULL, nomatch, "bbb")); + assert_se(!set_fnmatch(NULL, nomatch, "ccc")); + assert_se(!set_fnmatch(NULL, nomatch, "cccXXX")); + + assert_se(set_fnmatch(match, nomatch, "bbbbb")); + assert_se(set_fnmatch(match, nomatch, "XXccc")); + assert_se(!set_fnmatch(match, nomatch, "")); + assert_se(!set_fnmatch(match, nomatch, "a")); + assert_se(!set_fnmatch(match, nomatch, "aaa")); + assert_se(!set_fnmatch(match, nomatch, "b")); + assert_se(!set_fnmatch(match, nomatch, "bbb")); + assert_se(!set_fnmatch(match, nomatch, "ccc")); + assert_se(!set_fnmatch(match, nomatch, "ccccc")); + assert_se(!set_fnmatch(match, nomatch, "cccXX")); +} + DEFINE_TEST_MAIN(LOG_INFO);