Merge pull request #24244 from yuwata/device-enumerator

sd-device-enumerator: fix sysattr match
This commit is contained in:
Yu Watanabe
2022-08-09 04:57:48 +09:00
committed by GitHub
7 changed files with 126 additions and 33 deletions

View File

@@ -4,6 +4,7 @@
#include "hash-funcs.h"
#include "path-util.h"
#include "strv.h"
void string_hash_func(const char *p, struct siphash *state) {
siphash24_compress(p, strlen(p) + 1, state);
@@ -15,6 +16,9 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
char, string_hash_func, string_compare_func, free,
void, free);
DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free,
char, string_hash_func, string_compare_func, free,
char*, strv_free);
void path_hash_func(const char *q, struct siphash *state) {
bool add_slash = false;

View File

@@ -78,6 +78,7 @@ void string_hash_func(const char *p, struct siphash *state);
extern const struct hash_ops string_hash_ops;
extern const struct hash_ops string_hash_ops_free;
extern const struct hash_ops string_hash_ops_free_free;
extern const struct hash_ops string_hash_ops_free_strv_free;
void path_hash_func(const char *p, struct siphash *state);
extern const struct hash_ops path_hash_ops;

View File

@@ -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, /* clear_on_null = */ true);
if (r <= 0)
return r;
@@ -174,9 +172,7 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume
assert_return(enumerator, -EINVAL);
assert_return(property, -EINVAL);
/* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
* multiple times with the same property but different value. */
r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
r = update_match_strv(&enumerator->match_property, property, value, /* clear_on_null = */ false);
if (r <= 0)
return r;
@@ -466,29 +462,25 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
}
static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
const char *property;
const char *value;
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))
return true;
HASHMAP_FOREACH_KEY(value, property, enumerator->match_property) {
const char *property_dev, *value_dev;
HASHMAP_FOREACH_KEY(value_patterns, property_pattern, enumerator->match_property) {
const char *property, *value;
FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
if (fnmatch(property, property_dev, 0) != 0)
FOREACH_DEVICE_PROPERTY(device, property, value) {
if (fnmatch(property_pattern, property, 0) != 0)
continue;
if (!value && !value_dev)
return true;
if (!value || !value_dev)
continue;
if (fnmatch(value, value_dev, 0) == 0)
if (strv_fnmatch(value_patterns, value))
return true;
}
}

View File

@@ -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, /* clear_on_null = */ true);
}
_public_ int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match) {

View File

@@ -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, bool clear_on_null) {
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) || !clear_on_null)
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;

View File

@@ -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 clear_on_null);
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);

View File

@@ -310,6 +310,49 @@ TEST(sd_device_enumerator_filter_subsystem) {
assert_se(n_new_dev + n_removed_dev <= 10);
}
TEST(sd_device_enumerator_add_match_sysattr) {
_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_sysattr(e, "ifindex", "hoge", true) >= 0);
assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "foo", true) >= 0);
assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "bar", false) >= 0);
assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "baz", false) >= 0);
dev = sd_device_enumerator_get_device_first(e);
assert_se(dev);
assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
assert_se(ifindex == 1);
assert_se(!sd_device_enumerator_get_device_next(e));
}
TEST(sd_device_enumerator_add_match_property) {
_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(e, "IFINDE*", "1*") >= 0);
assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", "hoge") >= 0);
assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", NULL) >= 0);
assert_se(sd_device_enumerator_add_match_property(e, "AAAAA", "BBBB") >= 0);
assert_se(sd_device_enumerator_add_match_property(e, "FOOOO", NULL) >= 0);
dev = sd_device_enumerator_get_device_first(e);
assert_se(dev);
assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
assert_se(ifindex == 1);
}
TEST(sd_device_new_from_nulstr) {
const char *devlinks =
"/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"