From: Yu Watanabe Date: Mon, 8 Aug 2022 13:03:35 +0000 (+0900) Subject: sd-device-enumerator,monitor: fix sysattr match X-Git-Tag: v252-rc1~491^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=585f2035b37a073dcea5c61e26ccb869b1c43578;p=thirdparty%2Fsystemd.git sd-device-enumerator,monitor: fix sysattr match Previously, if sd_device_enumerator_add_match_sysattr() is called for the same sysattr with different values, then no device passed the filter. Now, the accepted values (or patterns) are stored in strv, and if the sysattr value of a device matches with the strv, then the device passes the filter. --- diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 39f769c35cf..1f18b843f21 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -157,9 +157,7 @@ _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumer else hashmap = &enumerator->nomatch_sysattr; - /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called - * multiple times with the same sysattr but different value. */ - r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value); + r = update_match_strv(hashmap, sysattr, value); if (r <= 0) return r; diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index e8913c3d1f8..98163058be5 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -787,7 +787,7 @@ _public_ int sd_device_monitor_filter_add_match_sysattr(sd_device_monitor *m, co hashmap = &m->nomatch_sysattr_filter; /* TODO: unset m->filter_uptodate on success when we support this filter on BPF. */ - return hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value); + return update_match_strv(hashmap, sysattr, value); } _public_ int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match) { diff --git a/src/libsystemd/sd-device/device-util.c b/src/libsystemd/sd-device/device-util.c index 616c16c1fc4..e2209a0b609 100644 --- a/src/libsystemd/sd-device/device-util.c +++ b/src/libsystemd/sd-device/device-util.c @@ -5,7 +5,65 @@ #include "device-util.h" #include "path-util.h" -static bool device_match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) { +int update_match_strv(Hashmap **match_strv, const char *key, const char *value) { + char **strv; + int r; + + assert(match_strv); + assert(key); + + strv = hashmap_get(*match_strv, key); + if (strv) { + if (!value) { + char **v; + + if (strv_isempty(strv)) + return 0; + + /* Accept all value. Clear previous assignment. */ + + v = new0(char*, 1); + if (!v) + return -ENOMEM; + + strv_free_and_replace(strv, v); + } else { + if (strv_contains(strv, value)) + return 0; + + r = strv_extend(&strv, value); + if (r < 0) + return r; + } + + r = hashmap_update(*match_strv, key, strv); + if (r < 0) + return r; + + } else { + _cleanup_strv_free_ char **strv_alloc = NULL; + _cleanup_free_ char *key_alloc = NULL; + + key_alloc = strdup(key); + if (!key_alloc) + return -ENOMEM; + + strv_alloc = strv_new(value); + if (!strv_alloc) + return -ENOMEM; + + r = hashmap_ensure_put(match_strv, &string_hash_ops_free_strv_free, key_alloc, strv_alloc); + if (r < 0) + return r; + + TAKE_PTR(key_alloc); + TAKE_PTR(strv_alloc); + } + + return 1; +} + +static bool device_match_sysattr_value(sd_device *device, const char *sysattr, char * const *patterns) { const char *value; assert(device); @@ -14,27 +72,21 @@ static bool device_match_sysattr_value(sd_device *device, const char *sysattr, c if (sd_device_get_sysattr_value(device, sysattr, &value) < 0) return false; - if (!match_value) - return true; - - if (fnmatch(match_value, value, 0) == 0) - return true; - - return false; + return strv_fnmatch_or_empty(patterns, value, 0); } bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr) { + char * const *patterns; const char *sysattr; - const char *value; assert(device); - HASHMAP_FOREACH_KEY(value, sysattr, match_sysattr) - if (!device_match_sysattr_value(device, sysattr, value)) + HASHMAP_FOREACH_KEY(patterns, sysattr, match_sysattr) + if (!device_match_sysattr_value(device, sysattr, patterns)) return false; - HASHMAP_FOREACH_KEY(value, sysattr, nomatch_sysattr) - if (device_match_sysattr_value(device, sysattr, value)) + HASHMAP_FOREACH_KEY(patterns, sysattr, nomatch_sysattr) + if (device_match_sysattr_value(device, sysattr, patterns)) return false; return true; diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h index 4eda2abaf36..6dae8ef6f2f 100644 --- a/src/libsystemd/sd-device/device-util.h +++ b/src/libsystemd/sd-device/device-util.h @@ -82,5 +82,6 @@ #define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__) #define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__) +int update_match_strv(Hashmap **match_strv, const char *key, const char *value); bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr); bool device_match_parent(sd_device *device, Set *match_parent, Set *nomatch_parent);