mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
Merge pull request #33032 from yuwata/sd-device-monitor-low-level-api
sd-device-monitor: expose low-level functions
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user