]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-device: Support matching all properties
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 9 Oct 2023 14:06:50 +0000 (16:06 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 11 Oct 2023 17:57:49 +0000 (19:57 +0200)
Let's support enumerating over devices that match all of the given
properties instead of any of the given properties by adding a new
function sd_device_enumerator_add_match_property_required() which
specifies properties that should all be matched instead of just one.

Fixes #28372

src/libsystemd/libsystemd.sym
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/test-sd-device.c
src/systemd/sd-device.h

index 56a8831f0fec07c6c8591a695bd327e66ec31df2..4113920ee045bd56e1bb7333eed6d0b79682bb07 100644 (file)
@@ -832,4 +832,5 @@ global:
 LIBSYSTEMD_255 {
 global:
         sd_id128_get_app_specific;
+        sd_device_enumerator_add_match_property_required;
 } LIBSYSTEMD_254;
index 766fadd22c536b9a069b27e58976ba5706ea79d8..15c5c42ade757f634bcf10cd6b1527c70e17c689 100644 (file)
@@ -40,6 +40,7 @@ struct sd_device_enumerator {
         Hashmap *match_sysattr;
         Hashmap *nomatch_sysattr;
         Hashmap *match_property;
+        Hashmap *match_property_required;
         Set *match_sysname;
         Set *nomatch_sysname;
         Set *match_tag;
@@ -95,6 +96,7 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer
         hashmap_free(enumerator->match_sysattr);
         hashmap_free(enumerator->nomatch_sysattr);
         hashmap_free(enumerator->match_property);
+        hashmap_free(enumerator->match_property_required);
         set_free(enumerator->match_sysname);
         set_free(enumerator->nomatch_sysname);
         set_free(enumerator->match_tag);
@@ -180,6 +182,21 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume
         return 1;
 }
 
+_public_ int sd_device_enumerator_add_match_property_required(sd_device_enumerator *enumerator, const char *property, const char *value) {
+        int r;
+
+        assert_return(enumerator, -EINVAL);
+        assert_return(property, -EINVAL);
+
+        r = update_match_strv(&enumerator->match_property_required, property, value, /* clear_on_null = */ false);
+        if (r <= 0)
+                return r;
+
+        enumerator->scan_uptodate = false;
+
+        return 1;
+}
+
 static int device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname, bool match) {
         int r;
 
@@ -459,28 +476,38 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
         return 1;
 }
 
-static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
+static bool match_property(Hashmap *properties, sd_device *device, bool match_all) {
         const char *property_pattern;
         char * const *value_patterns;
 
-        assert(enumerator);
         assert(device);
 
         /* Unlike device_match_sysattr(), this accepts device that has at least one matching property. */
 
-        if (hashmap_isempty(enumerator->match_property))
+        if (hashmap_isempty(properties))
                 return true;
 
-        HASHMAP_FOREACH_KEY(value_patterns, property_pattern, enumerator->match_property)
+        HASHMAP_FOREACH_KEY(value_patterns, property_pattern, properties) {
+                bool match = false;
+
                 FOREACH_DEVICE_PROPERTY(device, property, value) {
                         if (fnmatch(property_pattern, property, 0) != 0)
                                 continue;
 
-                        if (strv_fnmatch(value_patterns, value))
-                                return true;
+                        match = strv_fnmatch(value_patterns, value);
+                        if (match) {
+                                if (!match_all)
+                                        return true;
+
+                                break;
+                        }
                 }
 
-        return false;
+                if (!match && match_all)
+                        return false;
+        }
+
+        return match_all;
 }
 
 static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
@@ -599,7 +626,10 @@ static int test_matches(
         if (r <= 0)
                 return r;
 
-        if (!match_property(enumerator, device))
+        if (!match_property(enumerator->match_property, device, /* match_all = */ false))
+                return false;
+
+        if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
                 return false;
 
         if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
index 43376a203602445ffa6a8fbefd4fb0d3e1e54770..bce99b55186a2392d2511d0444577228ca76200f 100644 (file)
@@ -399,6 +399,32 @@ TEST(sd_device_enumerator_add_match_property) {
         assert_se(ifindex == 1);
 }
 
+TEST(sd_device_enumerator_add_match_property_required) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        int ifindex;
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+        assert_se(sd_device_enumerator_add_match_subsystem(e, "net", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_property_required(e, "IFINDE*", "1*") >= 0);
+
+        /* Only one required match which should be satisfied. */
+        dev = sd_device_enumerator_get_device_first(e);
+        assert_se(dev);
+        assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
+        assert_se(ifindex == 1);
+
+        /* Now let's add a bunch of garbage properties which should not be satisfied. */
+        assert_se(sd_device_enumerator_add_match_property_required(e, "IFINDE*", "hoge") >= 0);
+        assert_se(sd_device_enumerator_add_match_property_required(e, "IFINDE*", NULL) >= 0);
+        assert_se(sd_device_enumerator_add_match_property_required(e, "AAAAA", "BBBB") >= 0);
+        assert_se(sd_device_enumerator_add_match_property_required(e, "FOOOO", NULL) >= 0);
+
+        assert_se(!sd_device_enumerator_get_device_first(e));
+}
+
 static void check_parent_match(sd_device_enumerator *e, sd_device *dev) {
         const char *syspath;
         bool found = false;
index e3d647f75d1eb272632ca4d5530ed8714287f7d4..b67ec0f34dc5bca71d3910c49cc944aebf417f64 100644 (file)
@@ -129,6 +129,7 @@ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumera
 int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match);
 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_property_required(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);