]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/test-sd-device.c
7a1c40ca744cea15f51e2f364d82e7dc5c862440
[thirdparty/systemd.git] / src / libsystemd / sd-device / test-sd-device.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4 #include <unistd.h>
5
6 #include "sd-event.h"
7
8 #include "device-internal.h"
9 #include "device-private.h"
10 #include "device-util.h"
11 #include "errno-util.h"
12 #include "fd-util.h"
13 #include "fs-util.h"
14 #include "hashmap.h"
15 #include "mkdir.h"
16 #include "mount-util.h"
17 #include "mountpoint-util.h"
18 #include "nulstr-util.h"
19 #include "path-util.h"
20 #include "process-util.h"
21 #include "rm-rf.h"
22 #include "set.h"
23 #include "stat-util.h"
24 #include "string-util.h"
25 #include "tests.h"
26 #include "tmpfile-util.h"
27 #include "udev-util.h"
28
29 TEST(mdio_bus) {
30 int r;
31
32 /* For issue #37711 */
33
34 if (getuid() != 0)
35 return (void) log_tests_skipped("not running as root");
36
37 ASSERT_OK(r = safe_fork("(mdio_bus)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_WAIT|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL));
38 if (r == 0) {
39 const char *syspath = "/sys/bus/mdio_bus/drivers/Qualcomm Atheros AR8031!AR8033";
40 const char *id = "+drivers:mdio_bus:Qualcomm Atheros AR8031!AR8033";
41
42 struct {
43 int (*getter)(sd_device*, const char**);
44 const char *val;
45 } table[] = {
46 { sd_device_get_syspath, syspath },
47 { sd_device_get_device_id, id },
48 { sd_device_get_subsystem, "drivers" },
49 { sd_device_get_driver_subsystem, "mdio_bus" },
50 { sd_device_get_sysname, "Qualcomm Atheros AR8031/AR8033" },
51 };
52
53 ASSERT_OK_ERRNO(setenv("SYSTEMD_DEVICE_VERIFY_SYSFS", "0", /* overwrite = */ false));
54 ASSERT_OK(mount_nofollow_verbose(LOG_ERR, "tmpfs", "/sys/bus/", "tmpfs", 0, NULL));
55 r = mkdir_p(syspath, 0755);
56 if (ERRNO_IS_NEG_PRIVILEGE(r)) {
57 log_tests_skipped("Lacking privileges to create %s", syspath);
58 _exit(EXIT_SUCCESS);
59 }
60 ASSERT_OK(r);
61
62 _cleanup_free_ char *uevent = path_join(syspath, "uevent");
63 ASSERT_NOT_NULL(uevent);
64 ASSERT_OK(touch(uevent));
65
66 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
67 ASSERT_OK(sd_device_new_from_syspath(&dev, syspath));
68
69 FOREACH_ELEMENT(t, table) {
70 const char *v;
71
72 ASSERT_OK(t->getter(dev, &v));
73 ASSERT_STREQ(v, t->val);
74 }
75
76 dev = sd_device_unref(dev);
77 ASSERT_OK(sd_device_new_from_device_id(&dev, id));
78
79 FOREACH_ELEMENT(t, table) {
80 const char *v;
81
82 ASSERT_OK(t->getter(dev, &v));
83 ASSERT_STREQ(v, t->val);
84 }
85
86 _exit(EXIT_SUCCESS);
87 }
88 }
89
90 static void test_sd_device_one(sd_device *d) {
91 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
92 const char *syspath, *sysname, *subsystem = NULL, *devname, *val;
93 bool is_block = false;
94 dev_t devnum;
95 usec_t usec;
96 int ifindex, r;
97
98 ASSERT_OK(sd_device_get_syspath(d, &syspath));
99 ASSERT_NOT_NULL(path_startswith(syspath, "/sys"));
100 ASSERT_OK(sd_device_get_sysname(d, &sysname));
101
102 log_info("%s(%s)", __func__, syspath);
103
104 ASSERT_OK(sd_device_new_from_syspath(&dev, syspath));
105 ASSERT_OK(sd_device_get_syspath(dev, &val));
106 ASSERT_STREQ(syspath, val);
107 ASSERT_NULL(dev = sd_device_unref(dev));
108
109 ASSERT_OK(sd_device_new_from_path(&dev, syspath));
110 ASSERT_OK(sd_device_get_syspath(dev, &val));
111 ASSERT_STREQ(syspath, val);
112 ASSERT_NULL(dev = sd_device_unref(dev));
113
114 r = sd_device_get_ifindex(d, &ifindex);
115 if (r < 0)
116 ASSERT_ERROR(r, ENOENT);
117 else {
118 ASSERT_GT(ifindex, 0);
119
120 const char *ifname;
121 ASSERT_OK(device_get_ifname(d, &ifname));
122 ASSERT_NOT_NULL(endswith(syspath, ifname));
123 if (strchr(sysname, '/'))
124 ASSERT_FALSE(streq(ifname, sysname));
125 else
126 ASSERT_STREQ(ifname, sysname);
127
128 r = sd_device_new_from_ifindex(&dev, ifindex);
129 if (r < 0) {
130 ASSERT_ERROR(r, ENODEV);
131 log_device_warning_errno(d, r,
132 "Failed to create sd-device object from ifindex %i. "
133 "Maybe running on a non-host network namespace.", ifindex);
134 } else {
135 ASSERT_OK(sd_device_get_syspath(dev, &val));
136 ASSERT_STREQ(syspath, val);
137 ASSERT_NULL(dev = sd_device_unref(dev));
138 }
139
140 /* This does not require the interface really exists on the network namespace.
141 * Hence, this should always succeed. */
142 ASSERT_OK(sd_device_new_from_ifname(&dev, sysname));
143 ASSERT_OK(sd_device_get_syspath(dev, &val));
144 ASSERT_STREQ(syspath, val);
145 ASSERT_NULL(dev = sd_device_unref(dev));
146 }
147
148 r = sd_device_get_subsystem(d, &subsystem);
149 if (r < 0)
150 ASSERT_ERROR(r, ENOENT);
151 else {
152 const char *name, *id;
153
154 if (streq(subsystem, "drivers")) {
155 const char *driver_subsystem;
156 ASSERT_OK(sd_device_get_driver_subsystem(d, &driver_subsystem));
157 name = strjoina(driver_subsystem, ":", sysname);
158 } else
159 name = sysname;
160
161 r = sd_device_new_from_subsystem_sysname(&dev, subsystem, name);
162 if (r < 0)
163 ASSERT_ERROR(r, ETOOMANYREFS);
164 else {
165 ASSERT_OK(sd_device_get_syspath(dev, &val));
166 ASSERT_STREQ(syspath, val);
167 ASSERT_NULL(dev = sd_device_unref(dev));
168 }
169
170 /* The device ID depends on subsystem. */
171 ASSERT_OK(sd_device_get_device_id(d, &id));
172 r = sd_device_new_from_device_id(&dev, id);
173 if (r < 0) {
174 if (r == -ENODEV && ifindex > 0)
175 log_device_warning_errno(d, r,
176 "Failed to create sd-device object from device ID \"%s\". "
177 "Maybe running on a non-host network namespace.", id);
178 else
179 ASSERT_ERROR(r, ETOOMANYREFS);
180 } else {
181 ASSERT_OK(sd_device_get_syspath(dev, &val));
182 ASSERT_STREQ(syspath, val);
183 ASSERT_NULL(dev = sd_device_unref(dev));
184 }
185
186 /* These require udev database, and reading database requires device ID. */
187 ASSERT_OK(r = sd_device_get_is_initialized(d));
188 if (r > 0) {
189 r = sd_device_get_usec_since_initialized(d, &usec);
190 if (r < 0)
191 ASSERT_ERROR(r, ENODATA);
192 else
193 ASSERT_GT(usec, 0U);
194 }
195
196 r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
197 if (r < 0)
198 ASSERT_ERROR(r, ENOENT);
199 }
200
201 if (streq(subsystem, "drm")) {
202 const char *edid_content;
203 size_t edid_size = 0;
204
205 r = sd_device_get_sysattr_value_with_size(d, "edid", &edid_content, &edid_size);
206 if (r < 0)
207 ASSERT_ERROR(r, ENOENT);
208
209 /* at least 128 if monitor is connected, otherwise 0 */
210 ASSERT_TRUE(edid_size == 0 || edid_size >= 128);
211 }
212
213 is_block = streq_ptr(subsystem, "block");
214
215 r = sd_device_get_devname(d, &devname);
216 if (r < 0)
217 ASSERT_ERROR(r, ENOENT);
218 else {
219 r = sd_device_new_from_devname(&dev, devname);
220 if (r < 0)
221 ASSERT_TRUE(r == -ENODEV || ERRNO_IS_NEG_PRIVILEGE(r));
222 else {
223 ASSERT_OK(sd_device_get_syspath(dev, &val));
224 ASSERT_STREQ(syspath, val);
225 ASSERT_NULL(dev = sd_device_unref(dev));
226 }
227
228 r = sd_device_new_from_path(&dev, devname);
229 if (r < 0)
230 ASSERT_TRUE(r == -ENODEV || ERRNO_IS_NEG_PRIVILEGE(r));
231 else {
232 ASSERT_OK(sd_device_get_syspath(dev, &val));
233 ASSERT_STREQ(syspath, val);
234 ASSERT_NULL(dev = sd_device_unref(dev));
235
236 _cleanup_close_ int fd = -EBADF;
237 fd = sd_device_open(d, O_CLOEXEC| O_NONBLOCK | (is_block ? O_RDONLY : O_NOCTTY | O_PATH));
238 ASSERT_TRUE(fd >= 0 || ERRNO_IS_NEG_PRIVILEGE(fd));
239 }
240 }
241
242 r = sd_device_get_devnum(d, &devnum);
243 if (r < 0)
244 ASSERT_ERROR(r, ENOENT);
245 else {
246 _cleanup_free_ char *p = NULL;
247
248 ASSERT_GT(major(devnum), 0U);
249
250 ASSERT_OK(sd_device_new_from_devnum(&dev, is_block ? 'b' : 'c', devnum));
251 ASSERT_OK(sd_device_get_syspath(dev, &val));
252 ASSERT_STREQ(syspath, val);
253 ASSERT_NULL(dev = sd_device_unref(dev));
254
255 ASSERT_OK(asprintf(&p, "/dev/%s/%u:%u", is_block ? "block" : "char", major(devnum), minor(devnum)));
256 ASSERT_OK(sd_device_new_from_devname(&dev, p));
257 ASSERT_OK(sd_device_get_syspath(dev, &val));
258 ASSERT_STREQ(syspath, val);
259 ASSERT_NULL(dev = sd_device_unref(dev));
260
261 ASSERT_OK(sd_device_new_from_path(&dev, p));
262 ASSERT_OK(sd_device_get_syspath(dev, &val));
263 ASSERT_STREQ(syspath, val);
264 ASSERT_NULL(dev = sd_device_unref(dev));
265 }
266
267 ASSERT_OK(sd_device_get_devpath(d, &val));
268
269 r = sd_device_get_devtype(d, NULL);
270 if (r < 0)
271 ASSERT_ERROR(r, ENOENT);
272
273 r = sd_device_get_driver(d, NULL);
274 if (r < 0)
275 ASSERT_ERROR(r, ENOENT);
276
277 r = sd_device_get_sysnum(d, &val);
278 if (r < 0)
279 ASSERT_ERROR(r, ENOENT);
280 else {
281 ASSERT_TRUE(val > sysname);
282 ASSERT_TRUE(val < sysname + strlen(sysname));
283 ASSERT_TRUE(in_charset(val, DIGITS));
284 ASSERT_FALSE(ascii_isdigit(val[-1]));
285
286 r = device_get_sysnum_unsigned(d, NULL);
287 if (r < 0)
288 ASSERT_ERROR(r, ERANGE); /* sysnum may be too large. */
289 }
290
291 r = sd_device_get_sysattr_value(d, "nsid", NULL);
292 if (r < 0)
293 ASSERT_TRUE(ERRNO_IS_NEG_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL));
294 else {
295 unsigned x;
296 ASSERT_OK(r = device_get_sysattr_unsigned(d, "nsid", &x));
297 ASSERT_EQ(x > 0, r > 0);
298 }
299 }
300
301 static void exclude_problematic_devices(sd_device_enumerator *e) {
302 /* On some CI environments, it seems some loop block devices and corresponding bdi devices sometimes
303 * disappear during running this test. Let's exclude them here for stability. */
304 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "bdi", false));
305 ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
306 /* On CentOS CI, systemd-networkd-tests.py may be running when this test is invoked. The networkd
307 * test creates and removes many network interfaces, and may interfere with this test. */
308 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", false));
309 }
310
311 TEST(sd_device_enumerator_devices) {
312 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
313
314 ASSERT_OK(sd_device_enumerator_new(&e));
315 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
316 exclude_problematic_devices(e);
317
318 FOREACH_DEVICE(e, d)
319 test_sd_device_one(d);
320 }
321
322 TEST(sd_device_enumerator_subsystems) {
323 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
324
325 ASSERT_OK(sd_device_enumerator_new(&e));
326 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
327 FOREACH_SUBSYSTEM(e, d)
328 test_sd_device_one(d);
329 }
330
331 static void test_sd_device_enumerator_filter_subsystem_one(
332 const char *subsystem,
333 Hashmap *h,
334 unsigned *ret_n_new_dev,
335 unsigned *ret_n_removed_dev) {
336
337 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
338 unsigned n_new_dev = 0, n_removed_dev = 0;
339 sd_device *dev;
340
341 ASSERT_OK(sd_device_enumerator_new(&e));
342 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, subsystem, true));
343 ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
344
345 FOREACH_DEVICE(e, d) {
346 const char *syspath;
347 sd_device *t;
348
349 ASSERT_OK(sd_device_get_syspath(d, &syspath));
350 t = hashmap_remove(h, syspath);
351
352 if (!t) {
353 log_warning("New device found: subsystem:%s syspath:%s", subsystem, syspath);
354 n_new_dev++;
355 }
356
357 ASSERT_NULL(sd_device_unref(t));
358 }
359
360 HASHMAP_FOREACH(dev, h) {
361 const char *syspath;
362
363 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
364 log_warning("Device removed: subsystem:%s syspath:%s", subsystem, syspath);
365 n_removed_dev++;
366
367 ASSERT_NULL(sd_device_unref(dev));
368 }
369
370 hashmap_free(h);
371
372 *ret_n_new_dev = n_new_dev;
373 *ret_n_removed_dev = n_removed_dev;
374 }
375
376 static bool test_sd_device_enumerator_filter_subsystem_trial(void) {
377 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
378 _cleanup_hashmap_free_ Hashmap *subsystems = NULL;
379 unsigned n_new_dev = 0, n_removed_dev = 0;
380 Hashmap *h;
381 char *s;
382
383 ASSERT_NOT_NULL((subsystems = hashmap_new(&string_hash_ops)));
384 ASSERT_OK(sd_device_enumerator_new(&e));
385 exclude_problematic_devices(e);
386
387 FOREACH_DEVICE(e, d) {
388 const char *syspath, *subsystem;
389 int r;
390
391 ASSERT_OK(sd_device_get_syspath(d, &syspath));
392
393 r = sd_device_get_subsystem(d, &subsystem);
394 if (r < 0) {
395 ASSERT_ERROR(r, ENOENT);
396 continue;
397 }
398
399 h = hashmap_get(subsystems, subsystem);
400 if (!h) {
401 char *str;
402 ASSERT_NOT_NULL((str = strdup(subsystem)));
403 ASSERT_NOT_NULL((h = hashmap_new(&string_hash_ops)));
404 ASSERT_OK(hashmap_put(subsystems, str, h));
405 }
406
407 ASSERT_OK(hashmap_put(h, syspath, d));
408 ASSERT_NOT_NULL(sd_device_ref(d));
409
410 log_debug("Added subsystem:%s syspath:%s", subsystem, syspath);
411 }
412
413 while ((h = hashmap_steal_first_key_and_value(subsystems, (void**) &s))) {
414 unsigned n, m;
415
416 test_sd_device_enumerator_filter_subsystem_one(s, TAKE_PTR(h), &n, &m);
417 free(s);
418
419 n_new_dev += n;
420 n_removed_dev += m;
421 }
422
423 if (n_new_dev > 0)
424 log_warning("%u new devices are found in re-scan", n_new_dev);
425 if (n_removed_dev > 0)
426 log_warning("%u devices removed in re-scan", n_removed_dev);
427
428 return n_new_dev + n_removed_dev == 0;
429 }
430
431 static bool test_sd_device_enumerator_filter_subsystem_trial_many(void) {
432 for (unsigned i = 0; i < 20; i++) {
433 log_debug("%s(): trial %u", __func__, i);
434 if (test_sd_device_enumerator_filter_subsystem_trial())
435 return true;
436 }
437
438 return false;
439 }
440
441 static int on_inotify(sd_event_source *s, const struct inotify_event *event, void *userdata) {
442 if (test_sd_device_enumerator_filter_subsystem_trial_many())
443 return sd_event_exit(sd_event_source_get_event(s), 0);
444
445 return sd_event_exit(sd_event_source_get_event(s), -EBUSY);
446 }
447
448 TEST(sd_device_enumerator_filter_subsystem) {
449 /* The test test_sd_device_enumerator_filter_subsystem_trial() is quite racy. Let's run the function
450 * several times after the udev queue becomes empty. */
451
452 if (!udev_available() || (access("/run/udev", F_OK) < 0 && errno == ENOENT)) {
453 ASSERT_TRUE(test_sd_device_enumerator_filter_subsystem_trial_many());
454 return;
455 }
456
457 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
458 ASSERT_OK(sd_event_default(&event));
459 ASSERT_OK(sd_event_add_inotify(event, NULL, "/run/udev" , IN_DELETE, on_inotify, NULL));
460
461 if (udev_queue_is_empty() == 0) {
462 log_debug("udev queue is not empty, waiting for all queued events to be processed.");
463 ASSERT_OK(sd_event_loop(event));
464 } else
465 ASSERT_TRUE(test_sd_device_enumerator_filter_subsystem_trial_many());
466 }
467
468 TEST(sd_device_enumerator_add_match_sysattr) {
469 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
470 sd_device *dev;
471 int ifindex;
472
473 ASSERT_OK(sd_device_enumerator_new(&e));
474 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
475 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", true));
476 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true));
477 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "hoge", true));
478 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "foo", true));
479 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "bar", false));
480 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "baz", false));
481
482 ASSERT_NOT_NULL((dev = sd_device_enumerator_get_device_first(e)));
483 ASSERT_OK(sd_device_get_ifindex(dev, &ifindex));
484 ASSERT_EQ(ifindex, 1);
485
486 ASSERT_NULL(sd_device_enumerator_get_device_next(e));
487 }
488
489 TEST(sd_device_enumerator_add_match_property) {
490 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
491 sd_device *dev;
492 int ifindex;
493
494 ASSERT_OK(sd_device_enumerator_new(&e));
495 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
496 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", true));
497 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true));
498 ASSERT_OK(sd_device_enumerator_add_match_property(e, "IFINDE*", "1*"));
499 ASSERT_OK(sd_device_enumerator_add_match_property(e, "IFINDE*", "hoge"));
500 ASSERT_OK(sd_device_enumerator_add_match_property(e, "IFINDE*", NULL));
501 ASSERT_OK(sd_device_enumerator_add_match_property(e, "AAAAA", "BBBB"));
502 ASSERT_OK(sd_device_enumerator_add_match_property(e, "FOOOO", NULL));
503
504 ASSERT_NOT_NULL((dev = sd_device_enumerator_get_device_first(e)));
505 ASSERT_OK(sd_device_get_ifindex(dev, &ifindex));
506 ASSERT_EQ(ifindex, 1);
507 }
508
509 TEST(sd_device_enumerator_add_match_property_required) {
510 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
511 sd_device *dev;
512 int ifindex;
513
514 ASSERT_OK(sd_device_enumerator_new(&e));
515 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
516 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", true));
517 ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true));
518 ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "IFINDE*", "1*"));
519
520 /* Only one required match which should be satisfied. */
521 ASSERT_NOT_NULL((dev = sd_device_enumerator_get_device_first(e)));
522 ASSERT_OK(sd_device_get_ifindex(dev, &ifindex));
523 ASSERT_EQ(ifindex, 1);
524
525 /* Now let's add a bunch of garbage properties which should not be satisfied. */
526 ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "IFINDE*", "hoge"));
527 ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "IFINDE*", NULL));
528 ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "AAAAA", "BBBB"));
529 ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "FOOOO", NULL));
530
531 ASSERT_NULL(sd_device_enumerator_get_device_first(e));
532 }
533
534 static void check_parent_match(sd_device_enumerator *e, sd_device *dev) {
535 const char *syspath;
536 bool found = false;
537
538 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
539
540 FOREACH_DEVICE(e, d) {
541 const char *s;
542
543 ASSERT_OK(sd_device_get_syspath(d, &s));
544 if (streq(s, syspath)) {
545 found = true;
546 break;
547 }
548 }
549
550 if (!found) {
551 log_device_debug(dev, "not enumerated, already removed??");
552 /* If the original device not found, then the device should be already removed. */
553 ASSERT_FAIL(access(syspath, F_OK));
554 ASSERT_EQ(errno, ENOENT);
555 }
556 }
557
558 TEST(sd_device_enumerator_add_match_parent) {
559 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
560 /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
561 unsigned iterations = 200;
562 int r;
563
564 ASSERT_OK(sd_device_enumerator_new(&e));
565 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
566 exclude_problematic_devices(e);
567
568 if (!slow_tests_enabled())
569 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
570
571 FOREACH_DEVICE(e, dev) {
572 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *p = NULL;
573 const char *syspath;
574 sd_device *parent;
575
576 if (iterations-- == 0)
577 break;
578
579 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
580
581 r = sd_device_get_parent(dev, &parent);
582 if (r < 0) {
583 ASSERT_TRUE(ERRNO_IS_NEG_DEVICE_ABSENT(r));
584 continue;
585 }
586
587 log_debug("> %s", syspath);
588
589 ASSERT_OK(sd_device_enumerator_new(&p));
590 ASSERT_OK(sd_device_enumerator_allow_uninitialized(p));
591 ASSERT_OK(sd_device_enumerator_add_match_parent(p, parent));
592
593 check_parent_match(p, dev);
594
595 /* If the device does not have subsystem, then it is not enumerated. */
596 r = sd_device_get_subsystem(parent, NULL);
597 if (r < 0) {
598 ASSERT_ERROR(r, ENOENT);
599 continue;
600 }
601 check_parent_match(p, parent);
602 }
603 }
604
605 TEST(sd_device_enumerator_add_all_parents) {
606 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
607 int r;
608
609 /* STEP 1: enumerate all block devices without all_parents() */
610 ASSERT_OK(sd_device_enumerator_new(&e));
611 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
612
613 /* filter in only a subsystem */
614 ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
615 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
616 ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition"));
617
618 unsigned devices_count_with_parents = 0;
619 unsigned devices_count_without_parents = 0;
620 FOREACH_DEVICE(e, dev) {
621 ASSERT_OK_POSITIVE(device_is_subsystem_devtype(dev, "block", "partition"));
622 devices_count_without_parents++;
623 }
624
625 log_debug("found %u devices", devices_count_without_parents);
626
627 /* STEP 2: enumerate again with all_parents() */
628 ASSERT_OK(sd_device_enumerator_add_all_parents(e));
629
630 unsigned not_filtered_parent_count = 0;
631 FOREACH_DEVICE(e, dev) {
632 ASSERT_OK(r = device_is_subsystem_devtype(dev, "block", "partition"));
633 if (r == 0)
634 not_filtered_parent_count++;
635 devices_count_with_parents++;
636 }
637 log_debug("found %u devices out of %u that would have been excluded without all_parents()",
638 not_filtered_parent_count,
639 devices_count_with_parents);
640 ASSERT_EQ(devices_count_with_parents, devices_count_without_parents + not_filtered_parent_count);
641 }
642
643 TEST(sd_device_get_child) {
644 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
645 /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
646 unsigned iterations = 3000;
647 int r;
648
649 ASSERT_OK(sd_device_enumerator_new(&e));
650 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
651 exclude_problematic_devices(e);
652
653 if (!slow_tests_enabled())
654 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
655
656 FOREACH_DEVICE(e, dev) {
657 const char *syspath, *parent_syspath, *expected_suffix, *suffix;
658 sd_device *parent;
659 bool found = false;
660
661 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
662
663 r = sd_device_get_parent(dev, &parent);
664 if (r < 0) {
665 ASSERT_TRUE(ERRNO_IS_NEG_DEVICE_ABSENT(r));
666 continue;
667 }
668
669 ASSERT_OK(sd_device_get_syspath(parent, &parent_syspath));
670 ASSERT_NOT_NULL((expected_suffix = path_startswith(syspath, parent_syspath)));
671
672 log_debug("> %s", syspath);
673
674 FOREACH_DEVICE_CHILD_WITH_SUFFIX(parent, child, suffix) {
675 const char *s;
676
677 if (iterations-- == 0)
678 return;
679
680 ASSERT_NOT_NULL(child);
681 ASSERT_NOT_NULL(suffix);
682
683 if (!streq(suffix, expected_suffix))
684 continue;
685
686 ASSERT_OK(sd_device_get_syspath(child, &s));
687 ASSERT_STREQ(s, syspath);
688 found = true;
689 break;
690 }
691 ASSERT_TRUE(found);
692 }
693 }
694
695 TEST(sd_device_new_from_nulstr) {
696 const char *devlinks =
697 "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
698 "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0"
699 "/dev/disk/by-label/Arch\\x20Linux\0"
700 "/dev/disk/by-uuid/a07b87e5-4af5-4a59-bde9-yyyyyyyyyyyy\0"
701 "/dev/disk/by-partlabel/Arch\\x20Linux\0"
702 "\0";
703
704 _cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL;
705 _cleanup_free_ char *nulstr_copy = NULL;
706 const char *nulstr;
707 size_t len;
708
709 ASSERT_OK(sd_device_new_from_syspath(&device, "/sys/class/net/lo"));
710
711 /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a
712 * test for generating and parsing nulstr. For issue #17772. */
713 NULSTR_FOREACH(devlink, devlinks) {
714 log_device_info(device, "setting devlink: %s", devlink);
715 ASSERT_OK(device_add_devlink(device, devlink));
716 ASSERT_TRUE(set_contains(device->devlinks, devlink));
717 }
718
719 /* For issue #23799 */
720 ASSERT_OK(device_add_tag(device, "tag1", false));
721 ASSERT_OK(device_add_tag(device, "tag2", false));
722 ASSERT_OK(device_add_tag(device, "current-tag1", true));
723 ASSERT_OK(device_add_tag(device, "current-tag2", true));
724
725 /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
726 ASSERT_OK(device_add_property_internal(device, "SEQNUM", "1"));
727 ASSERT_OK(device_add_property_internal(device, "ACTION", "change"));
728
729 ASSERT_OK(device_get_properties_nulstr(device, &nulstr, &len));
730 ASSERT_NOT_NULL((nulstr_copy = newdup(char, nulstr, len)));
731 ASSERT_OK(device_new_from_nulstr(&from_nulstr, nulstr_copy, len));
732
733 ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "tag1"));
734 ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "tag2"));
735 ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "current-tag1"));
736 ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "current-tag2"));
737 ASSERT_OK_ZERO(sd_device_has_current_tag(from_nulstr, "tag1"));
738 ASSERT_OK_ZERO(sd_device_has_current_tag(from_nulstr, "tag2"));
739 ASSERT_OK_POSITIVE(sd_device_has_current_tag(from_nulstr, "current-tag1"));
740 ASSERT_OK_POSITIVE(sd_device_has_current_tag(from_nulstr, "current-tag2"));
741
742 NULSTR_FOREACH(devlink, devlinks) {
743 log_device_info(from_nulstr, "checking devlink: %s", devlink);
744 ASSERT_TRUE(set_contains(from_nulstr->devlinks, devlink));
745 }
746 }
747
748 TEST(sd_device_new_from_path) {
749 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
750 _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
751 int r;
752
753 ASSERT_OK(mkdtemp_malloc("/tmp/test-sd-device.XXXXXXX", &tmpdir));
754
755 ASSERT_OK(sd_device_enumerator_new(&e));
756 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
757 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
758 ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
759 ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVNAME", "*"));
760
761 FOREACH_DEVICE(e, dev) {
762 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
763 const char *syspath, *devpath, *sysname, *s;
764 _cleanup_free_ char *path = NULL;
765
766 ASSERT_OK(sd_device_get_sysname(dev, &sysname));
767
768 log_debug("%s(%s)", __func__, sysname);
769
770 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
771 ASSERT_OK(sd_device_new_from_path(&d, syspath));
772 ASSERT_OK(sd_device_get_syspath(d, &s));
773 ASSERT_STREQ(s, syspath);
774 ASSERT_NULL(d = sd_device_unref(d));
775
776 ASSERT_OK(sd_device_get_devname(dev, &devpath));
777 r = sd_device_new_from_path(&d, devpath);
778 if (r < 0)
779 ASSERT_TRUE(r == -ENODEV || ERRNO_IS_NEG_PRIVILEGE(r));
780 else {
781 ASSERT_OK(sd_device_get_syspath(d, &s));
782 ASSERT_STREQ(s, syspath);
783 ASSERT_NULL(d = sd_device_unref(d));
784 }
785
786 ASSERT_NOT_NULL((path = path_join(tmpdir, sysname)));
787 ASSERT_OK_ERRNO(symlink(syspath, path));
788 ASSERT_OK(sd_device_new_from_path(&d, path));
789 ASSERT_OK(sd_device_get_syspath(d, &s));
790 ASSERT_STREQ(s, syspath);
791 }
792 }
793
794 static void test_devname_from_devnum_one(const char *path) {
795 _cleanup_free_ char *resolved = NULL;
796 struct stat st;
797
798 log_debug("> %s", path);
799
800 if (stat(path, &st) < 0) {
801 log_notice("Path %s not found, skipping test", path);
802 return;
803 }
804
805 ASSERT_OK(devname_from_devnum(st.st_mode, st.st_rdev, &resolved));
806 ASSERT_TRUE(path_equal(path, resolved));
807 ASSERT_NULL(resolved = mfree(resolved));
808 ASSERT_OK(devname_from_stat_rdev(&st, &resolved));
809 ASSERT_TRUE(path_equal(path, resolved));
810 }
811
812 TEST(devname_from_devnum) {
813 test_devname_from_devnum_one("/dev/null");
814 test_devname_from_devnum_one("/dev/zero");
815 test_devname_from_devnum_one("/dev/full");
816 test_devname_from_devnum_one("/dev/random");
817 test_devname_from_devnum_one("/dev/urandom");
818 test_devname_from_devnum_one("/dev/tty");
819
820 if (is_device_node("/run/systemd/inaccessible/blk") > 0) {
821 test_devname_from_devnum_one("/run/systemd/inaccessible/chr");
822 test_devname_from_devnum_one("/run/systemd/inaccessible/blk");
823 }
824 }
825
826 static int intro(void) {
827 if (path_is_mount_point("/sys") <= 0)
828 return log_tests_skipped("/sys is not mounted");
829
830 return EXIT_SUCCESS;
831 }
832
833 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);