]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/test-sd-device-monitor.c
update TODO
[thirdparty/systemd.git] / src / libsystemd / sd-device / test-sd-device-monitor.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdbool.h>
4 #include <unistd.h>
5
6 #include "sd-device.h"
7 #include "sd-event.h"
8
9 #include "device-monitor-private.h"
10 #include "device-private.h"
11 #include "device-util.h"
12 #include "macro.h"
13 #include "stat-util.h"
14 #include "string-util.h"
15 #include "tests.h"
16 #include "util.h"
17 #include "virt.h"
18
19 static int monitor_handler(sd_device_monitor *m, sd_device *d, void *userdata) {
20 const char *s, *syspath = userdata;
21
22 assert_se(sd_device_get_syspath(d, &s) >= 0);
23 assert_se(streq(s, syspath));
24
25 return sd_event_exit(sd_device_monitor_get_event(m), 100);
26 }
27
28 static void test_receive_device_fail(void) {
29 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
30 _cleanup_(sd_device_unrefp) sd_device *loopback = NULL;
31 const char *syspath;
32
33 log_info("/* %s */", __func__);
34
35 /* Try to send device with invalid action and without seqnum. */
36 assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
37 assert_se(device_add_property(loopback, "ACTION", "hoge") >= 0);
38
39 assert_se(sd_device_get_syspath(loopback, &syspath) >= 0);
40
41 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
42 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
43 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
44
45 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
46 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
47 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
48 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
49
50 assert_se(device_monitor_send_device(monitor_server, monitor_client, loopback) >= 0);
51 assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
52 }
53
54 static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool tag_filter, bool use_bpf) {
55 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
56 const char *syspath, *subsystem, *tag, *devtype = NULL;
57
58 log_device_info(device, "/* %s(subsystem_filter=%s, tag_filter=%s, use_bpf=%s) */", __func__,
59 true_false(subsystem_filter), true_false(tag_filter), true_false(use_bpf));
60
61 assert_se(sd_device_get_syspath(device, &syspath) >= 0);
62
63 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
64 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
65 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
66
67 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
68 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
69 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
70 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
71
72 if (subsystem_filter) {
73 assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
74 (void) sd_device_get_devtype(device, &devtype);
75 assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, devtype) >= 0);
76 }
77
78 if (tag_filter)
79 FOREACH_DEVICE_TAG(device, tag)
80 assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, tag) >= 0);
81
82 if ((subsystem_filter || tag_filter) && use_bpf)
83 assert_se(sd_device_monitor_filter_update(monitor_client) >= 0);
84
85 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
86 assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
87 }
88
89 static void test_subsystem_filter(sd_device *device) {
90 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
91 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
92 const char *syspath, *subsystem;
93 sd_device *d;
94
95 log_device_info(device, "/* %s */", __func__);
96
97 assert_se(sd_device_get_syspath(device, &syspath) >= 0);
98 assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
99
100 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
101 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
102 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
103
104 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
105 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
106 assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
107 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
108 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
109
110 assert_se(sd_device_enumerator_new(&e) >= 0);
111 assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, false) >= 0);
112 FOREACH_DEVICE(e, d) {
113 const char *p, *s;
114
115 assert_se(sd_device_get_syspath(d, &p) >= 0);
116 assert_se(sd_device_get_subsystem(d, &s) >= 0);
117
118 log_device_debug(d, "Sending device subsystem:%s syspath:%s", s, p);
119 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
120 }
121
122 log_device_info(device, "Sending device subsystem:%s syspath:%s", subsystem, syspath);
123 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
124 assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
125 }
126
127 static void test_tag_filter(sd_device *device) {
128 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
129 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
130 const char *syspath;
131 sd_device *d;
132
133 log_device_info(device, "/* %s */", __func__);
134
135 assert_se(sd_device_get_syspath(device, &syspath) >= 0);
136
137 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
138 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
139 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
140
141 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
142 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
143 assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, "TEST_SD_DEVICE_MONITOR") >= 0);
144 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
145 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
146
147 assert_se(sd_device_enumerator_new(&e) >= 0);
148 FOREACH_DEVICE(e, d) {
149 const char *p;
150
151 assert_se(sd_device_get_syspath(d, &p) >= 0);
152
153 log_device_debug(d, "Sending device syspath:%s", p);
154 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
155 }
156
157 log_device_info(device, "Sending device syspath:%s", syspath);
158 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
159 assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
160
161 }
162
163 static void test_sysattr_filter(sd_device *device, const char *sysattr) {
164 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
165 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
166 const char *syspath, *subsystem, *sysattr_value;
167 sd_device *d;
168
169 log_device_info(device, "/* %s(%s) */", __func__, sysattr);
170
171 assert_se(sd_device_get_syspath(device, &syspath) >= 0);
172 assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
173 assert_se(sd_device_get_sysattr_value(device, sysattr, &sysattr_value) >= 0);
174
175 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
176 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
177 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
178
179 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
180 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
181 /* The sysattr filter is not implemented in BPF yet, so the below device_monito_send_device()
182 * may cause EAGAIN. So, let's also filter devices with subsystem. */
183 assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
184 assert_se(sd_device_monitor_filter_add_match_sysattr(monitor_client, sysattr, sysattr_value, true) >= 0);
185 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
186 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
187
188 assert_se(sd_device_enumerator_new(&e) >= 0);
189 assert_se(sd_device_enumerator_add_match_sysattr(e, sysattr, sysattr_value, false) >= 0);
190 FOREACH_DEVICE(e, d) {
191 const char *p;
192
193 assert_se(sd_device_get_syspath(d, &p) >= 0);
194
195 log_device_debug(d, "Sending device syspath:%s", p);
196 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
197 }
198
199 log_device_info(device, "Sending device syspath:%s", syspath);
200 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
201 assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
202
203 }
204
205 static void test_parent_filter(sd_device *device) {
206 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
207 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
208 const char *syspath, *subsystem;
209 sd_device *parent, *d;
210 int r;
211
212 log_device_info(device, "/* %s */", __func__);
213
214 assert_se(sd_device_get_syspath(device, &syspath) >= 0);
215 assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
216 r = sd_device_get_parent(device, &parent);
217 if (r < 0)
218 return (void) log_device_info(device, "Device does not have parent, skipping.");
219
220 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
221 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
222 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
223
224 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
225 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
226 /* The parent filter is not implemented in BPF yet, so the below device_monito_send_device()
227 * may cause EAGAIN. So, let's also filter devices with subsystem. */
228 assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
229 assert_se(sd_device_monitor_filter_add_match_parent(monitor_client, parent, true) >= 0);
230 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
231 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
232
233 assert_se(sd_device_enumerator_new(&e) >= 0);
234 FOREACH_DEVICE(e, d) {
235 const char *p;
236
237 assert_se(sd_device_get_syspath(d, &p) >= 0);
238
239 log_device_debug(d, "Sending device syspath:%s", p);
240 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
241 }
242
243 log_device_info(device, "Sending device syspath:%s", syspath);
244 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
245 assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
246
247 }
248
249 static void test_sd_device_monitor_filter_remove(sd_device *device) {
250 _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
251 const char *syspath;
252
253 log_device_info(device, "/* %s */", __func__);
254
255 assert_se(sd_device_get_syspath(device, &syspath) >= 0);
256
257 assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
258 assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
259 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
260
261 assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
262 assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
263 assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
264 assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
265
266 assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, "hoge", NULL) >= 0);
267 assert_se(sd_device_monitor_filter_update(monitor_client) >= 0);
268
269 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
270 assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
271
272 assert_se(sd_device_monitor_filter_remove(monitor_client) >= 0);
273
274 assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0);
275 assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100);
276 }
277
278 static void test_device_copy_properties(sd_device *device) {
279 _cleanup_(sd_device_unrefp) sd_device *copy = NULL;
280
281 assert_se(device_shallow_clone(device, &copy) >= 0);
282 assert_se(device_copy_properties(copy, device) >= 0);
283
284 test_send_receive_one(copy, false, false, false);
285 }
286
287 int main(int argc, char *argv[]) {
288 _cleanup_(sd_device_unrefp) sd_device *loopback = NULL, *sda = NULL;
289 int r;
290
291 test_setup_logging(LOG_INFO);
292
293 if (getuid() != 0)
294 return log_tests_skipped("not root");
295
296 if (path_is_read_only_fs("/sys") > 0)
297 return log_tests_skipped("Running in container");
298
299 test_receive_device_fail();
300
301 assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
302 assert_se(device_add_property(loopback, "ACTION", "add") >= 0);
303 assert_se(device_add_property(loopback, "SEQNUM", "10") >= 0);
304 assert_se(device_add_tag(loopback, "TEST_SD_DEVICE_MONITOR", true) >= 0);
305
306 test_send_receive_one(loopback, false, false, false);
307 test_send_receive_one(loopback, true, false, false);
308 test_send_receive_one(loopback, false, true, false);
309 test_send_receive_one(loopback, true, true, false);
310 test_send_receive_one(loopback, true, false, true);
311 test_send_receive_one(loopback, false, true, true);
312 test_send_receive_one(loopback, true, true, true);
313
314 test_subsystem_filter(loopback);
315 test_tag_filter(loopback);
316 test_sysattr_filter(loopback, "ifindex");
317 test_sd_device_monitor_filter_remove(loopback);
318 test_device_copy_properties(loopback);
319
320 r = sd_device_new_from_subsystem_sysname(&sda, "block", "sda");
321 if (r < 0) {
322 log_info_errno(r, "Failed to create sd_device for sda, skipping remaining tests: %m");
323 return 0;
324 }
325
326 assert_se(device_add_property(sda, "ACTION", "change") >= 0);
327 assert_se(device_add_property(sda, "SEQNUM", "11") >= 0);
328
329 test_send_receive_one(sda, false, false, false);
330 test_send_receive_one(sda, true, false, false);
331 test_send_receive_one(sda, false, true, false);
332 test_send_receive_one(sda, true, true, false);
333 test_send_receive_one(sda, true, false, true);
334 test_send_receive_one(sda, false, true, true);
335 test_send_receive_one(sda, true, true, true);
336
337 test_parent_filter(sda);
338
339 return 0;
340 }