Merge pull request #33032 from yuwata/sd-device-monitor-low-level-api

sd-device-monitor: expose low-level functions
This commit is contained in:
Yu Watanabe
2024-08-02 12:41:53 +09:00
committed by GitHub
11 changed files with 527 additions and 395 deletions

View File

@@ -1767,3 +1767,38 @@ int vsock_get_local_cid(unsigned *ret) {
return 0;
}
int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups) {
_cleanup_free_ uint32_t *groups = NULL;
socklen_t len = 0, old_len;
assert(fd >= 0);
/* This returns ENOPROTOOPT if the kernel is older than 4.2. */
if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len) < 0)
return -errno;
if (len == 0)
goto finalize;
groups = new0(uint32_t, len);
if (!groups)
return -ENOMEM;
old_len = len;
if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len) < 0)
return -errno;
if (old_len != len)
return -EIO;
finalize:
if (ret_len)
*ret_len = len;
if (ret_groups)
*ret_groups = TAKE_PTR(groups);
return 0;
}

View File

@@ -396,3 +396,5 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
#define SOMAXCONN_DELUXE INT_MAX
int vsock_get_local_cid(unsigned *ret);
int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups);

View File

@@ -1044,4 +1044,7 @@ global:
sd_varlink_take_fd;
sd_varlink_unref;
sd_varlink_wait;
sd_device_monitor_is_running;
sd_device_monitor_get_fd;
sd_device_monitor_receive;
} LIBSYSTEMD_256;

View File

@@ -5,6 +5,8 @@
#include "sd-device.h"
#include "socket-util.h"
typedef enum MonitorNetlinkGroup {
MONITOR_GROUP_NONE,
MONITOR_GROUP_KERNEL,
@@ -14,9 +16,6 @@ typedef enum MonitorNetlinkGroup {
} MonitorNetlinkGroup;
int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, int fd);
int device_monitor_disconnect(sd_device_monitor *m);
int device_monitor_get_address(sd_device_monitor *m, union sockaddr_union *ret);
int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor *sender);
int device_monitor_enable_receiving(sd_device_monitor *m);
int device_monitor_get_fd(sd_device_monitor *m);
int device_monitor_send_device(sd_device_monitor *m, sd_device_monitor *destination, sd_device *device);
int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret);
int device_monitor_send(sd_device_monitor *m, const union sockaddr_union *destination, sd_device *device);

View File

@@ -20,11 +20,11 @@
#include "fd-util.h"
#include "format-util.h"
#include "hashmap.h"
#include "io-util.h"
#include "iovec-util.h"
#include "missing_socket.h"
#include "mountpoint-util.h"
#include "set.h"
#include "socket-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
@@ -45,7 +45,6 @@ struct sd_device_monitor {
int sock;
union sockaddr_union snl;
union sockaddr_union snl_trusted_sender;
bool bound;
UIDRange *mapped_userns_uid_range;
@@ -57,6 +56,10 @@ struct sd_device_monitor {
Set *nomatch_parent_filter;
bool filter_uptodate;
bool multicast_group_dropped;
size_t multicast_group_len;
uint32_t *multicast_groups;
sd_event *event;
sd_event_source *event_source;
char *description;
@@ -101,12 +104,19 @@ static int monitor_set_nl_address(sd_device_monitor *m) {
return 0;
}
int device_monitor_get_address(sd_device_monitor *m, union sockaddr_union *ret) {
assert(m);
assert(ret);
*ret = m->snl;
return 0;
}
int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor *sender) {
assert(m);
assert(sender);
m->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
return 0;
return device_monitor_get_address(sender, &m->snl_trusted_sender);
}
_public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size) {
@@ -115,15 +125,8 @@ _public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, siz
return fd_set_rcvbuf(m->sock, size, false);
}
int device_monitor_disconnect(sd_device_monitor *m) {
assert(m);
m->sock = safe_close(m->sock);
return 0;
}
int device_monitor_get_fd(sd_device_monitor *m) {
assert(m);
_public_ int sd_device_monitor_get_fd(sd_device_monitor *m) {
assert_return(m, -EINVAL);
return m->sock;
}
@@ -170,17 +173,24 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
*m = (sd_device_monitor) {
.n_ref = 1,
.sock = fd >= 0 ? fd : TAKE_FD(sock),
.bound = fd >= 0,
.snl.nl.nl_family = AF_NETLINK,
.snl.nl.nl_groups = group,
};
if (fd >= 0) {
r = monitor_set_nl_address(m);
if (r < 0) {
log_monitor_errno(m, r, "Failed to set netlink address: %m");
goto fail;
}
if (fd < 0) {
/* enable receiving of sender credentials */
r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
if (r < 0)
return log_monitor_errno(m, r, "Failed to set socket option SO_PASSCRED: %m");
if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0)
return log_monitor_errno(m, errno, "Failed to bind monitoring socket: %m");
}
r = monitor_set_nl_address(m);
if (r < 0) {
log_monitor_errno(m, r, "Failed to set netlink address: %m");
goto fail;
}
if (DEBUG_LOGGING) {
@@ -231,22 +241,66 @@ fail:
/* Let's unset the socket fd in the monitor object before we destroy it so that the fd passed in is
* not closed on failure. */
if (fd >= 0)
m->sock = -1;
m->sock = -EBADF;
return r;
}
_public_ int sd_device_monitor_new(sd_device_monitor **ret) {
return device_monitor_new_full(ret, MONITOR_GROUP_UDEV, -1);
return device_monitor_new_full(ret, MONITOR_GROUP_UDEV, -EBADF);
}
_public_ int sd_device_monitor_is_running(sd_device_monitor *m) {
if (!m)
return 0;
return sd_event_source_get_enabled(m->event_source, NULL);
}
static int device_monitor_update_multicast_groups(sd_device_monitor *m, bool add) {
int r, opt = add ? NETLINK_ADD_MEMBERSHIP : NETLINK_DROP_MEMBERSHIP;
assert(m);
assert(m->sock >= 0);
for (size_t i = 0; i < m->multicast_group_len; i++)
for (unsigned j = 0; j < sizeof(uint32_t) * 8; j++)
if (m->multicast_groups[i] & (1U << j)) {
unsigned group = i * sizeof(uint32_t) * 8 + j + 1;
/* group is "unsigned", but netlink(7) says the argument is "int". */
r = setsockopt_int(m->sock, SOL_NETLINK, opt, group);
if (r < 0)
return r;
}
return 0;
}
_public_ int sd_device_monitor_stop(sd_device_monitor *m) {
int r;
assert_return(m, -EINVAL);
assert_return(m->sock >= 0, -ESTALE);
m->event_source = sd_event_source_unref(m->event_source);
(void) device_monitor_disconnect(m);
if (!m->multicast_group_dropped) {
m->multicast_group_len = 0;
m->multicast_groups = mfree(m->multicast_groups);
return 0;
/* Save multicast groups. */
r = netlink_socket_get_multicast_groups(m->sock, &m->multicast_group_len, &m->multicast_groups);
if (r < 0 && r != -ENOPROTOOPT)
return r;
/* Leave from all multicast groups to prevent the buffer is filled. */
r = device_monitor_update_multicast_groups(m, /* add = */ false);
if (r < 0)
return r;
m->multicast_group_dropped = true;
}
return sd_event_source_set_enabled(m->event_source, SD_EVENT_OFF);
}
static int device_monitor_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@@ -254,7 +308,7 @@ static int device_monitor_event_handler(sd_event_source *s, int fd, uint32_t rev
_unused_ _cleanup_(log_context_unrefp) LogContext *c = NULL;
sd_device_monitor *m = ASSERT_PTR(userdata);
if (device_monitor_receive_device(m, &device) <= 0)
if (sd_device_monitor_receive(m, &device) <= 0)
return 0;
if (log_context_enabled())
@@ -270,6 +324,7 @@ _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_han
int r;
assert_return(m, -EINVAL);
assert_return(m->sock >= 0, -ESTALE);
if (!m->event) {
r = sd_device_monitor_attach_event(m, NULL);
@@ -277,26 +332,48 @@ _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_han
return r;
}
r = device_monitor_enable_receiving(m);
r = sd_device_monitor_filter_update(m);
if (r < 0)
return r;
return log_monitor_errno(m, r, "Failed to update filter: %m");
m->callback = callback;
m->userdata = userdata;
r = sd_event_add_io(m->event, &m->event_source, m->sock, EPOLLIN, device_monitor_event_handler, m);
if (!m->event_source) {
/* The monitor has never started. Add IO event source. */
r = sd_event_add_io(m->event, &m->event_source, m->sock, EPOLLIN, device_monitor_event_handler, m);
if (r < 0)
return r;
(void) sd_event_source_set_description(m->event_source, m->description ?: "sd-device-monitor");
return 0;
}
r = sd_device_monitor_is_running(m);
if (r < 0)
return r;
if (r == 0) {
/* If the monitor was previously started but now it is stopped, flush anything queued during
* the monitor is stopped. */
r = flush_fd(m->sock);
if (r < 0)
return r;
(void) sd_event_source_set_description(m->event_source, m->description ?: "sd-device-monitor");
/* Then, join the saved broadcast groups again. */
r = device_monitor_update_multicast_groups(m, /* add = */ true);
if (r < 0)
return r;
return 0;
m->multicast_group_dropped = false;
}
return sd_event_source_set_enabled(m->event_source, SD_EVENT_ON);
}
_public_ int sd_device_monitor_detach_event(sd_device_monitor *m) {
assert_return(m, -EINVAL);
(void) sd_device_monitor_stop(m);
m->event_source = sd_event_source_unref(m->event_source);
m->event = sd_event_unref(m->event);
return 0;
@@ -354,38 +431,11 @@ _public_ int sd_device_monitor_get_description(sd_device_monitor *m, const char
return 0;
}
int device_monitor_enable_receiving(sd_device_monitor *m) {
int r;
assert(m);
r = sd_device_monitor_filter_update(m);
if (r < 0)
return log_monitor_errno(m, r, "Failed to update filter: %m");
if (!m->bound) {
/* enable receiving of sender credentials */
r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
if (r < 0)
return log_monitor_errno(m, r, "Failed to set socket option SO_PASSCRED: %m");
if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0)
return log_monitor_errno(m, errno, "Failed to bind monitoring socket: %m");
m->bound = true;
r = monitor_set_nl_address(m);
if (r < 0)
return log_monitor_errno(m, r, "Failed to set address: %m");
}
return 0;
}
static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
assert(m);
(void) sd_device_monitor_detach_event(m);
m->sock = safe_close(m->sock);
uid_range_free(m->mapped_userns_uid_range);
free(m->description);
@@ -395,6 +445,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
hashmap_free(m->nomatch_sysattr_filter);
set_free(m->match_parent_filter);
set_free(m->nomatch_parent_filter);
free(m->multicast_groups);
return mfree(m);
}
@@ -486,7 +537,7 @@ static bool check_sender_uid(sd_device_monitor *m, uid_t uid) {
return false;
}
int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
_public_ int sd_device_monitor_receive(sd_device_monitor *m, sd_device **ret) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
_cleanup_free_ uint8_t *buf_alloc = NULL;
union {
@@ -511,8 +562,8 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
bool is_initialized = false;
int r;
assert(m);
assert(ret);
assert_return(m, -EINVAL);
assert_return(ret, -EINVAL);
n = next_datagram_size_fd(m->sock);
if (n < 0) {
@@ -610,9 +661,10 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
r = passes_filter(m, device);
if (r < 0)
return log_device_monitor_errno(device, m, r, "Failed to check received device passing filter: %m");
if (r == 0)
if (r == 0) {
log_device_monitor(device, m, "Received device does not pass filter, ignoring.");
else
*ret = NULL;
} else
*ret = TAKE_PTR(device);
return r;
@@ -634,9 +686,9 @@ static uint64_t string_bloom64(const char *str) {
return bits;
}
int device_monitor_send_device(
int device_monitor_send(
sd_device_monitor *m,
sd_device_monitor *destination,
const union sockaddr_union *destination,
sd_device *device) {
monitor_netlink_header nlh = {
@@ -652,7 +704,7 @@ int device_monitor_send_device(
.msg_iovlen = 2,
};
/* default destination for sending */
union sockaddr_union default_destination = {
static const union sockaddr_union default_destination = {
.nl.nl_family = AF_NETLINK,
.nl.nl_groups = MONITOR_GROUP_UDEV,
};
@@ -702,7 +754,7 @@ int device_monitor_send_device(
* If we send to a multicast group, we will get
* ECONNREFUSED, which is expected.
*/
smsg.msg_name = destination ? &destination->snl : &default_destination;
smsg.msg_name = (struct sockaddr_nl*) &(destination ?: &default_destination)->nl;
smsg.msg_namelen = sizeof(struct sockaddr_nl);
count = sendmsg(m->sock, &smsg, 0);
if (count < 0) {

View File

@@ -9,6 +9,7 @@
#include "device-monitor-private.h"
#include "device-private.h"
#include "device-util.h"
#include "io-util.h"
#include "macro.h"
#include "mountpoint-util.h"
#include "path-util.h"
@@ -17,285 +18,382 @@
#include "tests.h"
#include "virt.h"
static void prepare_loopback(sd_device **ret) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
ASSERT_OK(sd_device_new_from_syspath(&dev, "/sys/class/net/lo"));
ASSERT_OK(device_add_property(dev, "ACTION", "add"));
ASSERT_OK(device_add_property(dev, "SEQNUM", "10"));
ASSERT_OK(device_add_tag(dev, "TEST_SD_DEVICE_MONITOR", true));
*ret = TAKE_PTR(dev);
}
static int prepare_sda(sd_device **ret) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
int r;
r = sd_device_new_from_subsystem_sysname(&dev, "block", "sda");
if (r < 0)
return r;
ASSERT_OK(device_add_property(dev, "ACTION", "change"));
ASSERT_OK(device_add_property(dev, "SEQNUM", "11"));
*ret = TAKE_PTR(dev);
return 0;
}
static int monitor_handler(sd_device_monitor *m, sd_device *d, void *userdata) {
const char *s, *syspath = userdata;
assert_se(sd_device_get_syspath(d, &s) >= 0);
assert_se(streq(s, syspath));
ASSERT_OK(sd_device_get_syspath(d, &s));
ASSERT_TRUE(streq(s, syspath));
return sd_event_exit(sd_device_monitor_get_event(m), 100);
}
static void test_receive_device_fail(void) {
static void prepare_monitor(sd_device_monitor **ret_server, sd_device_monitor **ret_client, union sockaddr_union *ret_address) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_unrefp) sd_device *loopback = NULL;
ASSERT_OK(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1));
ASSERT_OK(sd_device_monitor_set_description(monitor_server, "sender"));
ASSERT_OK(sd_device_monitor_start(monitor_server, NULL, NULL));
ASSERT_OK(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1));
ASSERT_OK(sd_device_monitor_set_description(monitor_client, "client"));
ASSERT_OK(device_monitor_allow_unicast_sender(monitor_client, monitor_server));
ASSERT_OK(device_monitor_get_address(monitor_client, ret_address));
*ret_server = TAKE_PTR(monitor_server);
*ret_client = TAKE_PTR(monitor_client);
}
static void send_by_enumerator(
sd_device_monitor *monitor_server,
const union sockaddr_union *address,
sd_device_enumerator *e,
size_t n,
const char *syspath_filter) {
size_t i = 0;
FOREACH_DEVICE(e, d) {
const char *p, *s;
ASSERT_OK(sd_device_get_syspath(d, &p));
ASSERT_OK(sd_device_get_subsystem(d, &s));
if (syspath_filter && path_startswith(p, syspath_filter))
continue;
ASSERT_OK(device_add_property(d, "ACTION", "add"));
ASSERT_OK(device_add_property(d, "SEQNUM", "10"));
log_device_debug(d, "Sending device subsystem:%s syspath:%s", s, p);
ASSERT_OK(device_monitor_send(monitor_server, address, d));
/* The sysattr and parent filters are not implemented in BPF yet. So, sending multiple
* devices may fills up buffer and device_monitor_send() may return EAGAIN. Let's send only a
* few devices here, which should be filtered out by the receiver. */
if (n != SIZE_MAX && ++i >= n)
break;
}
}
TEST(sd_device_monitor_is_running) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
ASSERT_EQ(sd_device_monitor_is_running(NULL), 0);
ASSERT_OK(device_monitor_new_full(&m, MONITOR_GROUP_NONE, -1));
ASSERT_EQ(sd_device_monitor_is_running(m), 0);
ASSERT_OK(sd_device_monitor_start(m, NULL, NULL));
ASSERT_EQ(sd_device_monitor_is_running(m), 1);
ASSERT_OK(sd_device_monitor_stop(m));
ASSERT_EQ(sd_device_monitor_is_running(m), 0);
}
TEST(sd_device_monitor_start_stop) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
union sockaddr_union sa;
const char *syspath;
log_info("/* %s */", __func__);
prepare_loopback(&device);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
prepare_monitor(&monitor_server, &monitor_client, &sa);
/* Sending devices before starting client. */
ASSERT_OK(sd_device_enumerator_new(&e));
send_by_enumerator(monitor_server, &sa, e, 5, syspath);
/* sd_device_monitor_start() can be called multiple times. */
ASSERT_OK(sd_device_monitor_start(monitor_client, NULL, NULL));
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
/* Sending devices after client being started. */
send_by_enumerator(monitor_server, &sa, e, 5, syspath);
/* sd_device_monitor_stop() can be called multiple times. */
ASSERT_OK(sd_device_monitor_stop(monitor_client));
ASSERT_OK(sd_device_monitor_stop(monitor_client));
/* Sending devices before restarting client. */
send_by_enumerator(monitor_server, &sa, e, 5, syspath);
/* Restart monitor, and check if the previously sent devices are ignored. */
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
TEST(refuse_invalid_device) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_unrefp) sd_device *loopback = NULL;
union sockaddr_union sa;
const char *syspath;
/* Try to send device with invalid action and without seqnum. */
assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
assert_se(device_add_property(loopback, "ACTION", "hoge") >= 0);
ASSERT_OK(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo"));
ASSERT_OK(device_add_property(loopback, "ACTION", "hoge"));
assert_se(sd_device_get_syspath(loopback, &syspath) >= 0);
ASSERT_OK(sd_device_get_syspath(loopback, &syspath));
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
prepare_monitor(&monitor_server, &monitor_client, &sa);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(device_monitor_send_device(monitor_server, monitor_client, loopback) >= 0);
assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(device_monitor_send(monitor_server, &sa, loopback));
ASSERT_OK(sd_event_run(sd_device_monitor_get_event(monitor_client), 0));
}
static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool tag_filter, bool use_bpf) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
const char *syspath, *subsystem, *devtype = NULL;
union sockaddr_union sa;
log_device_info(device, "/* %s(subsystem_filter=%s, tag_filter=%s, use_bpf=%s) */", __func__,
true_false(subsystem_filter), true_false(tag_filter), true_false(use_bpf));
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
prepare_monitor(&monitor_server, &monitor_client, &sa);
if (subsystem_filter) {
assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
ASSERT_OK(sd_device_get_subsystem(device, &subsystem));
(void) sd_device_get_devtype(device, &devtype);
assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, devtype) >= 0);
ASSERT_OK(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, devtype));
}
if (tag_filter)
FOREACH_DEVICE_TAG(device, tag)
assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, tag) >= 0);
ASSERT_OK(sd_device_monitor_filter_add_match_tag(monitor_client, tag));
if ((subsystem_filter || tag_filter) && use_bpf)
assert_se(sd_device_monitor_filter_update(monitor_client) >= 0);
ASSERT_OK(sd_device_monitor_filter_update(monitor_client));
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
static void test_subsystem_filter(sd_device *device) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
const char *syspath, *subsystem;
log_device_info(device, "/* %s */", __func__);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, false) >= 0);
FOREACH_DEVICE(e, d) {
const char *p, *s;
assert_se(sd_device_get_syspath(d, &p) >= 0);
assert_se(sd_device_get_subsystem(d, &s) >= 0);
assert_se(device_add_property(d, "ACTION", "add") >= 0);
assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
log_device_debug(d, "Sending device subsystem:%s syspath:%s", s, p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
}
log_device_info(device, "Sending device subsystem:%s syspath:%s", subsystem, syspath);
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
}
static void test_tag_filter(sd_device *device) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
const char *syspath;
log_device_info(device, "/* %s */", __func__);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, "TEST_SD_DEVICE_MONITOR") >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
FOREACH_DEVICE(e, d) {
const char *p;
assert_se(sd_device_get_syspath(d, &p) >= 0);
assert_se(device_add_property(d, "ACTION", "add") >= 0);
assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
log_device_debug(d, "Sending device syspath:%s", p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
}
log_device_info(device, "Sending device syspath:%s", syspath);
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
}
static void test_sysattr_filter(sd_device *device, const char *sysattr) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
const char *syspath, *sysattr_value;
log_device_info(device, "/* %s(%s) */", __func__, sysattr);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(sd_device_get_sysattr_value(device, sysattr, &sysattr_value) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_filter_add_match_sysattr(monitor_client, sysattr, sysattr_value, true) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
assert_se(sd_device_enumerator_add_match_sysattr(e, sysattr, sysattr_value, false) >= 0);
FOREACH_DEVICE(e, d) {
const char *p;
assert_se(sd_device_get_syspath(d, &p) >= 0);
assert_se(device_add_property(d, "ACTION", "add") >= 0);
assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
log_device_debug(d, "Sending device syspath:%s", p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
/* The sysattr filter is not implemented in BPF yet. So, sending multiple devices may fills up
* buffer and device_monitor_send_device() may return EAGAIN. Let's send one device here,
* which should be filtered out by the receiver. */
break;
}
log_device_info(device, "Sending device syspath:%s", syspath);
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
}
static void test_parent_filter(sd_device *device) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
const char *syspath, *parent_syspath;
sd_device *parent;
int r;
log_device_info(device, "/* %s */", __func__);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
r = sd_device_get_parent(device, &parent);
if (r < 0)
return (void) log_device_info(device, "Device does not have parent, skipping.");
assert_se(sd_device_get_syspath(parent, &parent_syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_filter_add_match_parent(monitor_client, parent, true) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(sd_device_enumerator_new(&e) >= 0);
FOREACH_DEVICE(e, d) {
const char *p;
assert_se(sd_device_get_syspath(d, &p) >= 0);
if (path_startswith(p, parent_syspath))
continue;
assert_se(device_add_property(d, "ACTION", "add") >= 0);
assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
log_device_debug(d, "Sending device syspath:%s", p);
assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
/* The parent filter is not implemented in BPF yet. So, sending multiple devices may fills up
* buffer and device_monitor_send_device() may return EAGAIN. Let's send one device here,
* which should be filtered out by the receiver. */
break;
}
log_device_info(device, "Sending device syspath:%s", syspath);
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
}
static void test_sd_device_monitor_filter_remove(sd_device *device) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
const char *syspath;
log_device_info(device, "/* %s */", __func__);
assert_se(sd_device_get_syspath(device, &syspath) >= 0);
assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, "hoge", NULL) >= 0);
assert_se(sd_device_monitor_filter_update(monitor_client) >= 0);
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
assert_se(sd_device_monitor_filter_remove(monitor_client) >= 0);
assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
}
int main(int argc, char *argv[]) {
TEST(sd_device_monitor_send_receive) {
_cleanup_(sd_device_unrefp) sd_device *loopback = NULL, *sda = NULL;
int r;
test_setup_logging(LOG_INFO);
prepare_loopback(&loopback);
test_send_receive_one(loopback, false, false, false);
test_send_receive_one(loopback, true, false, false);
test_send_receive_one(loopback, false, true, false);
test_send_receive_one(loopback, true, true, false);
test_send_receive_one(loopback, true, false, true);
test_send_receive_one(loopback, false, true, true);
test_send_receive_one(loopback, true, true, true);
r = prepare_sda(&sda);
if (r < 0)
return (void) log_tests_skipped_errno(r, "Failed to create sd_device for sda");
test_send_receive_one(sda, false, false, false);
test_send_receive_one(sda, true, false, false);
test_send_receive_one(sda, false, true, false);
test_send_receive_one(sda, true, true, false);
test_send_receive_one(sda, true, false, true);
test_send_receive_one(sda, false, true, true);
test_send_receive_one(sda, true, true, true);
}
TEST(sd_device_monitor_filter_add_match_subsystem_devtype) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *syspath, *subsystem;
union sockaddr_union sa;
prepare_loopback(&device);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
ASSERT_OK(sd_device_get_subsystem(device, &subsystem));
prepare_monitor(&monitor_server, &monitor_client, &sa);
ASSERT_OK(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL));
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(sd_device_enumerator_new(&e));
ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, subsystem, false));
send_by_enumerator(monitor_server, &sa, e, SIZE_MAX, NULL);
log_device_info(device, "Sending device subsystem:%s syspath:%s", subsystem, syspath);
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
TEST(sd_device_monitor_filter_add_match_tag) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
union sockaddr_union sa;
const char *syspath;
prepare_loopback(&device);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
prepare_monitor(&monitor_server, &monitor_client, &sa);
ASSERT_OK(sd_device_monitor_filter_add_match_tag(monitor_client, "TEST_SD_DEVICE_MONITOR"));
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(sd_device_enumerator_new(&e));
send_by_enumerator(monitor_server, &sa, e, SIZE_MAX, NULL);
log_device_info(device, "Sending device syspath:%s", syspath);
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
TEST(sd_device_monitor_filter_add_match_sysattr) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
static const char *sysattr = "ifindex";
const char *syspath, *sysattr_value;
union sockaddr_union sa;
prepare_loopback(&device);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
ASSERT_OK(sd_device_get_sysattr_value(device, sysattr, &sysattr_value));
prepare_monitor(&monitor_server, &monitor_client, &sa);
ASSERT_OK(sd_device_monitor_filter_add_match_sysattr(monitor_client, sysattr, sysattr_value, true));
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(sd_device_enumerator_new(&e));
ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, sysattr, sysattr_value, false));
send_by_enumerator(monitor_server, &sa, e, 5, NULL);
log_device_info(device, "Sending device syspath:%s", syspath);
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
TEST(sd_device_monitor_add_match_parent) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *syspath, *parent_syspath;
union sockaddr_union sa;
sd_device *parent;
int r;
r = prepare_sda(&device);
if (r < 0)
return (void) log_tests_skipped_errno(r, "Failed to create sd_device for sda");
ASSERT_OK(sd_device_get_syspath(device, &syspath));
r = sd_device_get_parent(device, &parent);
if (r < 0)
return (void) log_tests_skipped("sda does not have parent");
ASSERT_OK(sd_device_get_syspath(parent, &parent_syspath));
prepare_monitor(&monitor_server, &monitor_client, &sa);
ASSERT_OK(sd_device_monitor_filter_add_match_parent(monitor_client, parent, true));
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(sd_device_enumerator_new(&e));
send_by_enumerator(monitor_server, &sa, e, 5, parent_syspath);
log_device_info(device, "Sending device syspath:%s", syspath);
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
TEST(sd_device_monitor_filter_remove) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
union sockaddr_union sa;
const char *syspath;
prepare_loopback(&device);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
prepare_monitor(&monitor_server, &monitor_client, &sa);
ASSERT_OK(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, "hoge", NULL));
ASSERT_OK(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath));
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_OK(sd_event_run(sd_device_monitor_get_event(monitor_client), 0));
ASSERT_OK(sd_device_monitor_filter_remove(monitor_client));
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_EQ(sd_event_loop(sd_device_monitor_get_event(monitor_client)), 100);
}
TEST(sd_device_monitor_receive) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
union sockaddr_union sa;
const char *syspath;
int fd, r;
prepare_loopback(&device);
ASSERT_OK(sd_device_get_syspath(device, &syspath));
prepare_monitor(&monitor_server, &monitor_client, &sa);
ASSERT_OK(device_monitor_send(monitor_server, &sa, device));
ASSERT_OK(fd = sd_device_monitor_get_fd(monitor_client));
for (;;) {
r = fd_wait_for_event(fd, POLLIN, 10 * USEC_PER_SEC);
if (r == -EINTR)
continue;
ASSERT_GT(r, 0);
break;
}
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
ASSERT_GT(sd_device_monitor_receive(monitor_client, &dev), 0);
const char *s;
ASSERT_OK(sd_device_get_syspath(dev, &s));
ASSERT_TRUE(streq(s, syspath));
}
static int intro(void) {
if (getuid() != 0)
return log_tests_skipped("not root");
@@ -305,44 +403,10 @@ int main(int argc, char *argv[]) {
if (path_is_read_only_fs("/sys") > 0)
return log_tests_skipped("Running in container");
test_receive_device_fail();
if (access("/sys/class/net/lo", F_OK) < 0)
return log_tests_skipped_errno(errno, "Loopback network interface 'lo' does not exist");
assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
assert_se(device_add_property(loopback, "ACTION", "add") >= 0);
assert_se(device_add_property(loopback, "SEQNUM", "10") >= 0);
assert_se(device_add_tag(loopback, "TEST_SD_DEVICE_MONITOR", true) >= 0);
test_send_receive_one(loopback, false, false, false);
test_send_receive_one(loopback, true, false, false);
test_send_receive_one(loopback, false, true, false);
test_send_receive_one(loopback, true, true, false);
test_send_receive_one(loopback, true, false, true);
test_send_receive_one(loopback, false, true, true);
test_send_receive_one(loopback, true, true, true);
test_subsystem_filter(loopback);
test_tag_filter(loopback);
test_sysattr_filter(loopback, "ifindex");
test_sd_device_monitor_filter_remove(loopback);
r = sd_device_new_from_subsystem_sysname(&sda, "block", "sda");
if (r < 0) {
log_info_errno(r, "Failed to create sd_device for sda, skipping remaining tests: %m");
return 0;
}
assert_se(device_add_property(sda, "ACTION", "change") >= 0);
assert_se(device_add_property(sda, "SEQNUM", "11") >= 0);
test_send_receive_one(sda, false, false, false);
test_send_receive_one(sda, true, false, false);
test_send_receive_one(sda, false, true, false);
test_send_receive_one(sda, true, true, false);
test_send_receive_one(sda, true, false, true);
test_send_receive_one(sda, false, true, true);
test_send_receive_one(sda, true, true, true);
test_parent_filter(sda);
return 0;
return EXIT_SUCCESS;
}
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);

View File

@@ -17,36 +17,21 @@
static int broadcast_groups_get(sd_netlink *nl) {
_cleanup_free_ uint32_t *groups = NULL;
socklen_t len = 0, old_len;
size_t len;
int r;
assert(nl);
assert(nl->fd >= 0);
if (getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len) < 0) {
if (errno != ENOPROTOOPT)
return -errno;
r = netlink_socket_get_multicast_groups(nl->fd, &len, &groups);
if (r == -ENOPROTOOPT) {
nl->broadcast_group_dont_leave = true;
return 0;
}
if (r < 0)
return r;
if (len == 0)
return 0;
groups = new0(uint32_t, len);
if (!groups)
return -ENOMEM;
old_len = len;
if (getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len) < 0)
return -errno;
if (old_len != len)
return -EIO;
for (unsigned i = 0; i < len; i++)
for (size_t i = 0; i < len; i++)
for (unsigned j = 0; j < sizeof(uint32_t) * 8; j++)
if (groups[i] & (1U << j)) {
unsigned group = i * sizeof(uint32_t) * 8 + j + 1;

View File

@@ -109,14 +109,12 @@ _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) {
* udev_monitor_enable_receiving:
* @udev_monitor: the monitor which should receive events
*
* Binds the @udev_monitor socket to the event source.
* Deprecated, and alias of udev_monitor_filter_update().
*
* Returns: 0 on success, otherwise a negative error value.
*/
_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) {
assert_return(udev_monitor, -EINVAL);
return device_monitor_enable_receiving(udev_monitor->monitor);
return udev_monitor_filter_update(udev_monitor);
}
/**
@@ -188,7 +186,7 @@ _public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) {
assert_return(udev_monitor, -EINVAL);
return device_monitor_get_fd(udev_monitor->monitor);
return sd_device_monitor_get_fd(udev_monitor->monitor);
}
static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) {
@@ -199,13 +197,13 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_
for (;;) {
/* r == 0 means a device is received but it does not pass the current filter. */
r = device_monitor_receive_device(udev_monitor->monitor, ret);
r = sd_device_monitor_receive(udev_monitor->monitor, ret);
if (r != 0)
return r;
for (;;) {
/* Wait for next message */
r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0);
r = fd_wait_for_event(sd_device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0);
if (r == -EINTR)
continue;
if (r < 0)

View File

@@ -142,6 +142,7 @@ int sd_device_monitor_new(sd_device_monitor **ret);
sd_device_monitor *sd_device_monitor_ref(sd_device_monitor *m);
sd_device_monitor *sd_device_monitor_unref(sd_device_monitor *m);
int sd_device_monitor_get_fd(sd_device_monitor *m);
int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size);
int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event);
int sd_device_monitor_detach_event(sd_device_monitor *m);
@@ -149,8 +150,10 @@ sd_event *sd_device_monitor_get_event(sd_device_monitor *m);
sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *m);
int sd_device_monitor_set_description(sd_device_monitor *m, const char *description);
int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret);
int sd_device_monitor_is_running(sd_device_monitor *m);
int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata);
int sd_device_monitor_stop(sd_device_monitor *m);
int sd_device_monitor_receive(sd_device_monitor *m, sd_device **ret);
int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype);
int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag);

View File

@@ -84,7 +84,7 @@ typedef struct Worker {
Manager *manager;
pid_t pid;
sd_event_source *child_event_source;
sd_device_monitor *monitor;
union sockaddr_union address;
WorkerState state;
Event *event;
} Worker;
@@ -125,7 +125,6 @@ static Worker *worker_free(Worker *worker) {
hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
sd_event_source_unref(worker->child_event_source);
sd_device_monitor_unref(worker->monitor);
event_free(worker->event);
return mfree(worker);
@@ -173,18 +172,18 @@ static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_
assert(worker_monitor);
assert(pid > 1);
/* close monitor, but keep address around */
device_monitor_disconnect(worker_monitor);
worker = new(Worker, 1);
if (!worker)
return -ENOMEM;
*worker = (Worker) {
.monitor = sd_device_monitor_ref(worker_monitor),
.pid = pid,
};
r = device_monitor_get_address(worker_monitor, &worker->address);
if (r < 0)
return r;
r = sd_event_add_child(manager->event, &worker->child_event_source, pid, WEXITED, on_sigchld, worker);
if (r < 0)
return r;
@@ -398,10 +397,6 @@ static int worker_spawn(Manager *manager, Event *event) {
if (r < 0)
return log_error_errno(r, "Worker: Failed to set unicast sender: %m");
r = device_monitor_enable_receiving(worker_monitor);
if (r < 0)
return log_error_errno(r, "Worker: Failed to enable receiving of device: %m");
r = safe_fork("(udev-worker)", FORK_DEATHSIG_SIGTERM, &pid);
if (r < 0) {
event->state = EVENT_QUEUED;
@@ -455,7 +450,7 @@ static int event_run(Event *event) {
if (worker->state != WORKER_IDLE)
continue;
r = device_monitor_send_device(manager->monitor, worker->monitor, event->dev);
r = device_monitor_send(manager->monitor, &worker->address, event->dev);
if (r < 0) {
log_device_error_errno(event->dev, r, "Worker ["PID_FMT"] did not accept message, killing the worker: %m",
worker->pid);
@@ -1262,10 +1257,6 @@ int manager_init(Manager *manager, int fd_ctrl, int fd_uevent) {
(void) sd_device_monitor_set_description(manager->monitor, "manager");
r = device_monitor_enable_receiving(manager->monitor);
if (r < 0)
return log_error_errno(r, "Failed to bind netlink socket: %m");
manager->log_level = log_get_max_level();
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);

View File

@@ -272,7 +272,7 @@ void udev_broadcast_result(sd_device_monitor *monitor, sd_device *dev, EventResu
}
}
r = device_monitor_send_device(monitor, NULL, dev);
r = device_monitor_send(monitor, NULL, dev);
if (r < 0)
log_device_warning_errno(dev, r,
"Failed to broadcast event to libudev listeners, ignoring: %m");