summaryrefslogtreecommitdiff
path: root/src/libudev/libudev-monitor.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2018-08-24 17:00:40 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2018-09-11 12:45:21 +0900
commit759d9f3f8d07af2940bb3783acc3985ee47adfa5 (patch)
tree07808d8e8d533312f91e9a97e036b2d2cfa70534 /src/libudev/libudev-monitor.c
parent5e1e4c247b5cacfa52eb44f76cfbeac16f30e54a (diff)
downloadsystemd-759d9f3f8d07af2940bb3783acc3985ee47adfa5.tar.gz
libudev-monitor: use Hashmap or Set to store filters
Diffstat (limited to 'src/libudev/libudev-monitor.c')
-rw-r--r--src/libudev/libudev-monitor.c190
1 files changed, 114 insertions, 76 deletions
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c
index 8ea4a2947e..02ee1f4969 100644
--- a/src/libudev/libudev-monitor.c
+++ b/src/libudev/libudev-monitor.c
@@ -17,10 +17,12 @@
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
+#include "hashmap.h"
#include "libudev-device-internal.h"
#include "libudev-private.h"
#include "missing.h"
#include "mount-util.h"
+#include "set.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
@@ -45,8 +47,8 @@ struct udev_monitor {
union sockaddr_union snl_trusted_sender;
union sockaddr_union snl_destination;
socklen_t addrlen;
- struct udev_list filter_subsystem_list;
- struct udev_list filter_tag_list;
+ Hashmap *subsystem_filter;
+ Set *tag_filter;
bool bound;
};
@@ -164,9 +166,6 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
}
}
- udev_list_init(udev, &udev_monitor->filter_subsystem_list, false);
- udev_list_init(udev, &udev_monitor->filter_tag_list, true);
-
return TAKE_PTR(udev_monitor);
}
@@ -224,20 +223,18 @@ static void bpf_jmp(struct sock_filter *ins, unsigned *i,
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
-{
- struct sock_filter ins[512];
+_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) {
+ struct sock_filter ins[512] = {};
struct sock_fprog filter;
- unsigned i;
- struct udev_list_entry *list_entry;
- int err;
+ const char *subsystem, *devtype, *tag;
+ unsigned i = 0;
+ Iterator it;
- if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL &&
- udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
- return 0;
+ assert_return(udev_monitor, -EINVAL);
- memzero(ins, sizeof(ins));
- i = 0;
+ if (hashmap_isempty(udev_monitor->subsystem_filter) &&
+ set_isempty(udev_monitor->tag_filter))
+ return 0;
/* load magic in A */
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
@@ -246,17 +243,12 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
/* wrong magic, pass packet */
bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
- if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) {
- int tag_matches;
-
- /* count tag matches, to calculate end of tag match block */
- tag_matches = 0;
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))
- tag_matches++;
+ if (!set_isempty(udev_monitor->tag_filter)) {
+ int tag_matches = set_size(udev_monitor->tag_filter);
/* add all tags matches */
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
- uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry));
+ SET_FOREACH(tag, udev_monitor->tag_filter, it) {
+ uint64_t tag_bloom_bits = util_string_bloom64(tag);
uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
@@ -281,23 +273,23 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
}
/* add all subsystem matches */
- if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) {
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
- uint32_t hash = util_string_hash32(udev_list_entry_get_name(list_entry));
+ if (!hashmap_isempty(udev_monitor->subsystem_filter)) {
+ HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, it) {
+ uint32_t hash = util_string_hash32(subsystem);
/* load device subsystem value in A */
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash));
- if (udev_list_entry_get_value(list_entry) == NULL) {
+ if (!devtype) {
/* jump if subsystem does not match */
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
} else {
+ hash = util_string_hash32(devtype);
+
/* jump if subsystem does not match */
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
-
/* load device devtype value in A */
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash));
/* jump if value does not match */
- hash = util_string_hash32(udev_list_entry_get_value(list_entry));
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
}
@@ -316,11 +308,14 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
/* install filter */
- memzero(&filter, sizeof(filter));
- filter.len = i;
- filter.filter = ins;
- err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
- return err < 0 ? -errno : 0;
+ filter = (struct sock_fprog) {
+ .len = i,
+ .filter = ins,
+ };
+ if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
+ return -errno;
+
+ return 0;
}
int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
@@ -395,8 +390,8 @@ static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor)
assert(udev_monitor);
udev_monitor_disconnect(udev_monitor);
- udev_list_cleanup(&udev_monitor->filter_subsystem_list);
- udev_list_cleanup(&udev_monitor->filter_tag_list);
+ hashmap_free_free_free(udev_monitor->subsystem_filter);
+ set_free_free(udev_monitor->tag_filter);
return mfree(udev_monitor);
}
@@ -451,41 +446,49 @@ _public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
return udev_monitor->sock;
}
-static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
-{
- struct udev_list_entry *list_entry;
+static int passes_filter(struct udev_monitor *udev_monitor, sd_device *device) {
+ const char *tag, *subsystem, *devtype, *s, *d = NULL;
+ Iterator i;
+ int r;
- if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(device, -EINVAL);
+
+ if (hashmap_isempty(udev_monitor->subsystem_filter))
goto tag;
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
- const char *subsys = udev_list_entry_get_name(list_entry);
- const char *dsubsys = udev_device_get_subsystem(udev_device);
- const char *devtype;
- const char *ddevtype;
- if (!streq(dsubsys, subsys))
+ r = sd_device_get_subsystem(device, &s);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_devtype(device, &d);
+ if (r < 0 && r != -ENOENT)
+ return r;
+
+ HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, i) {
+ if (!streq(s, subsystem))
continue;
- devtype = udev_list_entry_get_value(list_entry);
- if (devtype == NULL)
+ if (!devtype)
goto tag;
- ddevtype = udev_device_get_devtype(udev_device);
- if (ddevtype == NULL)
+
+ if (!d)
continue;
- if (streq(ddevtype, devtype))
+
+ if (streq(d, devtype))
goto tag;
}
+
return 0;
tag:
- if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
+ if (set_isempty(udev_monitor->tag_filter))
return 1;
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
- const char *tag = udev_list_entry_get_name(list_entry);
- if (udev_device_has_tag(udev_device, tag))
+ SET_FOREACH(tag, udev_monitor->tag_filter, i)
+ if (sd_device_has_tag(device, tag) > 0)
return 1;
- }
+
return 0;
}
@@ -630,7 +633,7 @@ retry:
udev_device_set_is_initialized(udev_device);
/* skip device, if it does not pass the current filter */
- if (!passes_filter(udev_monitor, udev_device)) {
+ if (!passes_filter(udev_monitor, udev_device->device)) {
struct pollfd pfd[1];
int rc;
@@ -749,14 +752,32 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
-{
- if (udev_monitor == NULL)
- return -EINVAL;
- if (subsystem == NULL)
- return -EINVAL;
- if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL)
+_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) {
+ _cleanup_free_ char *s = NULL, *d = NULL;
+ int r;
+
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(subsystem, -EINVAL);
+
+ s = strdup(subsystem);
+ if (!s)
return -ENOMEM;
+
+ if (devtype) {
+ d = strdup(devtype);
+ if (!d)
+ return -ENOMEM;
+ }
+
+ r = hashmap_ensure_allocated(&udev_monitor->subsystem_filter, NULL);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(udev_monitor->subsystem_filter, s, d);
+ if (r < 0)
+ return r;
+
+ s = d = NULL;
return 0;
}
@@ -772,14 +793,28 @@ _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
-{
- if (udev_monitor == NULL)
- return -EINVAL;
- if (tag == NULL)
- return -EINVAL;
- if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL)
+_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(tag, -EINVAL);
+
+ t = strdup(tag);
+ if (!t)
return -ENOMEM;
+
+ r = set_ensure_allocated(&udev_monitor->tag_filter, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(udev_monitor->tag_filter, t);
+ if (r == -EEXIST)
+ return 0;
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(t);
return 0;
}
@@ -791,11 +826,14 @@ _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
-{
+_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) {
static const struct sock_fprog filter = { 0, NULL };
- udev_list_cleanup(&udev_monitor->filter_subsystem_list);
+ assert_return(udev_monitor, -EINVAL);
+
+ udev_monitor->subsystem_filter = hashmap_free_free_free(udev_monitor->subsystem_filter);
+ udev_monitor->tag_filter = set_free_free(udev_monitor->tag_filter);
+
if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
return -errno;