]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/test-sd-device.c
io.systemd.Unit.List fix context/runtime split (#38172)
[thirdparty/systemd.git] / src / libsystemd / sd-device / test-sd-device.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
9380d34c 2
9534d6c9 3#include <fcntl.h>
284ef480 4#include <unistd.h>
9534d6c9 5
5cdf13c7
DDM
6#include "sd-event.h"
7
e6f88287 8#include "device-internal.h"
9380d34c
YW
9#include "device-private.h"
10#include "device-util.h"
acfc2a1d 11#include "errno-util.h"
9534d6c9 12#include "fd-util.h"
687a92a1 13#include "fs-util.h"
68db4a0c 14#include "hashmap.h"
687a92a1
YW
15#include "mkdir.h"
16#include "mount-util.h"
a412a1b9 17#include "mountpoint-util.h"
e6f88287 18#include "nulstr-util.h"
209294ad 19#include "path-util.h"
687a92a1 20#include "process-util.h"
284ef480 21#include "rm-rf.h"
5cdf13c7 22#include "set.h"
f79fdea6 23#include "stat-util.h"
9380d34c
YW
24#include "string-util.h"
25#include "tests.h"
284ef480 26#include "tmpfile-util.h"
5342810b 27#include "udev-util.h"
9380d34c 28
687a92a1
YW
29TEST(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));
f245fa00
LB
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);
687a92a1
YW
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
af18705f 90static void test_sd_device_one(sd_device *d) {
209294ad 91 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
901fa9a4 92 const char *syspath, *sysname, *subsystem = NULL, *devname, *val;
209294ad 93 bool is_block = false;
af18705f
YW
94 dev_t devnum;
95 usec_t usec;
c7749367 96 int ifindex, r;
9380d34c 97
0f52a110
YW
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));
04d1fbd5
YW
101
102 log_info("%s(%s)", __func__, syspath);
103
0f52a110
YW
104 ASSERT_OK(sd_device_new_from_syspath(&dev, syspath));
105 ASSERT_OK(sd_device_get_syspath(dev, &val));
106 ASSERT_STREQ(syspath, val);
d9000d70 107 ASSERT_NULL(dev = sd_device_unref(dev));
ecbe9873 108
0f52a110
YW
109 ASSERT_OK(sd_device_new_from_path(&dev, syspath));
110 ASSERT_OK(sd_device_get_syspath(dev, &val));
111 ASSERT_STREQ(syspath, val);
d9000d70 112 ASSERT_NULL(dev = sd_device_unref(dev));
9380d34c 113
c7749367 114 r = sd_device_get_ifindex(d, &ifindex);
0f52a110
YW
115 if (r < 0)
116 ASSERT_ERROR(r, ENOENT);
117 else {
118 ASSERT_GT(ifindex, 0);
c7749367 119
bec2f4dc
YW
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
c7749367 128 r = sd_device_new_from_ifindex(&dev, ifindex);
0f52a110
YW
129 if (r < 0) {
130 ASSERT_ERROR(r, ENODEV);
c7749367
YW
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);
0f52a110
YW
134 } else {
135 ASSERT_OK(sd_device_get_syspath(dev, &val));
136 ASSERT_STREQ(syspath, val);
d9000d70 137 ASSERT_NULL(dev = sd_device_unref(dev));
c7749367
YW
138 }
139
140 /* This does not require the interface really exists on the network namespace.
141 * Hence, this should always succeed. */
0f52a110
YW
142 ASSERT_OK(sd_device_new_from_ifname(&dev, sysname));
143 ASSERT_OK(sd_device_get_syspath(dev, &val));
144 ASSERT_STREQ(syspath, val);
d9000d70 145 ASSERT_NULL(dev = sd_device_unref(dev));
0f52a110 146 }
c7749367 147
209294ad 148 r = sd_device_get_subsystem(d, &subsystem);
fc0cbed2 149 if (r < 0)
0f52a110 150 ASSERT_ERROR(r, ENOENT);
cd7c7115 151 else {
901fa9a4 152 const char *name, *id;
209294ad 153
44bc6f3c
YW
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
209294ad 159 name = sysname;
cd7c7115
YW
160
161 r = sd_device_new_from_subsystem_sysname(&dev, subsystem, name);
0f52a110 162 if (r < 0)
cd7c7115 163 ASSERT_ERROR(r, ETOOMANYREFS);
0f52a110
YW
164 else {
165 ASSERT_OK(sd_device_get_syspath(dev, &val));
166 ASSERT_STREQ(syspath, val);
d9000d70 167 ASSERT_NULL(dev = sd_device_unref(dev));
0f52a110 168 }
901fa9a4
YW
169
170 /* The device ID depends on subsystem. */
0f52a110 171 ASSERT_OK(sd_device_get_device_id(d, &id));
c7749367 172 r = sd_device_new_from_device_id(&dev, id);
0f52a110
YW
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);
d9000d70 183 ASSERT_NULL(dev = sd_device_unref(dev));
0f52a110 184 }
901fa9a4
YW
185
186 /* These require udev database, and reading database requires device ID. */
d9000d70 187 ASSERT_OK(r = sd_device_get_is_initialized(d));
901fa9a4
YW
188 if (r > 0) {
189 r = sd_device_get_usec_since_initialized(d, &usec);
0f52a110
YW
190 if (r < 0)
191 ASSERT_ERROR(r, ENODATA);
192 else
193 ASSERT_GT(usec, 0U);
194 }
901fa9a4
YW
195
196 r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
0f52a110
YW
197 if (r < 0)
198 ASSERT_ERROR(r, ENOENT);
fc0cbed2 199 }
209294ad 200
90732874 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
209294ad
YW
213 is_block = streq_ptr(subsystem, "block");
214
215 r = sd_device_get_devname(d, &devname);
0f52a110
YW
216 if (r < 0)
217 ASSERT_ERROR(r, ENOENT);
218 else {
209294ad 219 r = sd_device_new_from_devname(&dev, devname);
0f52a110
YW
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);
d9000d70 225 ASSERT_NULL(dev = sd_device_unref(dev));
0f52a110 226 }
209294ad
YW
227
228 r = sd_device_new_from_path(&dev, devname);
0f52a110
YW
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);
d9000d70 234 ASSERT_NULL(dev = sd_device_unref(dev));
9534d6c9 235
254d1313 236 _cleanup_close_ int fd = -EBADF;
9534d6c9 237 fd = sd_device_open(d, O_CLOEXEC| O_NONBLOCK | (is_block ? O_RDONLY : O_NOCTTY | O_PATH));
0f52a110
YW
238 ASSERT_TRUE(fd >= 0 || ERRNO_IS_NEG_PRIVILEGE(fd));
239 }
240 }
9380d34c 241
af18705f 242 r = sd_device_get_devnum(d, &devnum);
0f52a110
YW
243 if (r < 0)
244 ASSERT_ERROR(r, ENOENT);
245 else {
209294ad
YW
246 _cleanup_free_ char *p = NULL;
247
0f52a110 248 ASSERT_GT(major(devnum), 0U);
209294ad 249
0f52a110
YW
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);
d9000d70 253 ASSERT_NULL(dev = sd_device_unref(dev));
209294ad 254
0f52a110
YW
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);
d9000d70 259 ASSERT_NULL(dev = sd_device_unref(dev));
209294ad 260
0f52a110
YW
261 ASSERT_OK(sd_device_new_from_path(&dev, p));
262 ASSERT_OK(sd_device_get_syspath(dev, &val));
263 ASSERT_STREQ(syspath, val);
d9000d70 264 ASSERT_NULL(dev = sd_device_unref(dev));
0f52a110 265 }
9380d34c 266
0f52a110 267 ASSERT_OK(sd_device_get_devpath(d, &val));
9380d34c 268
0f52a110
YW
269 r = sd_device_get_devtype(d, NULL);
270 if (r < 0)
271 ASSERT_ERROR(r, ENOENT);
9380d34c 272
0f52a110
YW
273 r = sd_device_get_driver(d, NULL);
274 if (r < 0)
275 ASSERT_ERROR(r, ENOENT);
9380d34c 276
af18705f 277 r = sd_device_get_sysnum(d, &val);
0f52a110
YW
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
7543ae05 286 r = device_get_sysnum_unsigned(d, NULL);
0f52a110
YW
287 if (r < 0)
288 ASSERT_ERROR(r, ERANGE); /* sysnum may be too large. */
289 }
9380d34c 290
733529d8 291 r = sd_device_get_sysattr_value(d, "nsid", NULL);
0f52a110
YW
292 if (r < 0)
293 ASSERT_TRUE(ERRNO_IS_NEG_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL));
294 else {
48a511cf 295 unsigned x;
d9000d70
YW
296 ASSERT_OK(r = device_get_sysattr_unsigned(d, "nsid", &x));
297 ASSERT_EQ(x > 0, r > 0);
0f52a110 298 }
af18705f 299}
9380d34c 300
a9cded65 301static void exclude_problematic_devices(sd_device_enumerator *e) {
ff56124b
YW
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. */
0f52a110
YW
304 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "bdi", false));
305 ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
3284dd91
YW
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. */
0f52a110 308 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", false));
a9cded65
ZJS
309}
310
311TEST(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
af18705f
YW
318 FOREACH_DEVICE(e, d)
319 test_sd_device_one(d);
320}
321
68da8adf 322TEST(sd_device_enumerator_subsystems) {
af18705f 323 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
af18705f 324
0f52a110
YW
325 ASSERT_OK(sd_device_enumerator_new(&e));
326 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
af18705f
YW
327 FOREACH_SUBSYSTEM(e, d)
328 test_sd_device_one(d);
9380d34c
YW
329}
330
b1d72322
YW
331static 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
68db4a0c 337 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
b1d72322 338 unsigned n_new_dev = 0, n_removed_dev = 0;
a1af8372 339 sd_device *dev;
68db4a0c 340
0f52a110
YW
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*"));
68db4a0c
YW
344
345 FOREACH_DEVICE(e, d) {
346 const char *syspath;
b1d72322 347 sd_device *t;
68db4a0c 348
0f52a110 349 ASSERT_OK(sd_device_get_syspath(d, &syspath));
8ee08dc5 350 t = hashmap_remove(h, syspath);
68db4a0c 351
b1d72322 352 if (!t) {
8ee08dc5
YW
353 log_warning("New device found: subsystem:%s syspath:%s", subsystem, syspath);
354 n_new_dev++;
355 }
b1d72322 356
0f52a110 357 ASSERT_NULL(sd_device_unref(t));
68db4a0c
YW
358 }
359
a1af8372 360 HASHMAP_FOREACH(dev, h) {
b1d72322 361 const char *syspath;
8ee08dc5 362
0f52a110 363 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
b1d72322
YW
364 log_warning("Device removed: subsystem:%s syspath:%s", subsystem, syspath);
365 n_removed_dev++;
366
0f52a110 367 ASSERT_NULL(sd_device_unref(dev));
b1d72322
YW
368 }
369
370 hashmap_free(h);
371
372 *ret_n_new_dev = n_new_dev;
373 *ret_n_removed_dev = n_removed_dev;
68db4a0c
YW
374}
375
5342810b 376static bool test_sd_device_enumerator_filter_subsystem_trial(void) {
68db4a0c 377 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
5d2a48da 378 _cleanup_hashmap_free_ Hashmap *subsystems = NULL;
b1d72322 379 unsigned n_new_dev = 0, n_removed_dev = 0;
68db4a0c
YW
380 Hashmap *h;
381 char *s;
382
0f52a110
YW
383 ASSERT_NOT_NULL((subsystems = hashmap_new(&string_hash_ops)));
384 ASSERT_OK(sd_device_enumerator_new(&e));
a9cded65 385 exclude_problematic_devices(e);
68db4a0c
YW
386
387 FOREACH_DEVICE(e, d) {
388 const char *syspath, *subsystem;
389 int r;
390
0f52a110 391 ASSERT_OK(sd_device_get_syspath(d, &syspath));
68db4a0c
YW
392
393 r = sd_device_get_subsystem(d, &subsystem);
0f52a110
YW
394 if (r < 0) {
395 ASSERT_ERROR(r, ENOENT);
68db4a0c 396 continue;
0f52a110 397 }
68db4a0c
YW
398
399 h = hashmap_get(subsystems, subsystem);
400 if (!h) {
401 char *str;
0f52a110
YW
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));
68db4a0c
YW
405 }
406
0f52a110
YW
407 ASSERT_OK(hashmap_put(h, syspath, d));
408 ASSERT_NOT_NULL(sd_device_ref(d));
68db4a0c
YW
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))) {
b1d72322
YW
414 unsigned n, m;
415
416 test_sd_device_enumerator_filter_subsystem_one(s, TAKE_PTR(h), &n, &m);
68db4a0c 417 free(s);
b1d72322
YW
418
419 n_new_dev += n;
420 n_removed_dev += m;
68db4a0c 421 }
8ee08dc5
YW
422
423 if (n_new_dev > 0)
b1d72322
YW
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);
8ee08dc5 427
5342810b
YW
428 return n_new_dev + n_removed_dev == 0;
429}
430
431static 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
441static 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
448TEST(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
6cae57d9 452 if (!udev_available() || (access("/run/udev", F_OK) < 0 && errno == ENOENT)) {
0f52a110 453 ASSERT_TRUE(test_sd_device_enumerator_filter_subsystem_trial_many());
5342810b
YW
454 return;
455 }
456
457 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
0f52a110
YW
458 ASSERT_OK(sd_event_default(&event));
459 ASSERT_OK(sd_event_add_inotify(event, NULL, "/run/udev" , IN_DELETE, on_inotify, NULL));
5342810b
YW
460
461 if (udev_queue_is_empty() == 0) {
462 log_debug("udev queue is not empty, waiting for all queued events to be processed.");
0f52a110 463 ASSERT_OK(sd_event_loop(event));
5342810b 464 } else
0f52a110 465 ASSERT_TRUE(test_sd_device_enumerator_filter_subsystem_trial_many());
68db4a0c
YW
466}
467
50f9c507
YW
468TEST(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
0f52a110
YW
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));
50f9c507
YW
487}
488
489TEST(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
0f52a110
YW
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);
50f9c507
YW
507}
508
fe2a6dce
DDM
509TEST(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
0f52a110
YW
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*"));
fe2a6dce
DDM
519
520 /* Only one required match which should be satisfied. */
0f52a110
YW
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);
fe2a6dce
DDM
524
525 /* Now let's add a bunch of garbage properties which should not be satisfied. */
0f52a110
YW
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));
fe2a6dce 530
0f52a110 531 ASSERT_NULL(sd_device_enumerator_get_device_first(e));
fe2a6dce
DDM
532}
533
2d9c58d7
YW
534static void check_parent_match(sd_device_enumerator *e, sd_device *dev) {
535 const char *syspath;
536 bool found = false;
2d9c58d7 537
0f52a110 538 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
2d9c58d7
YW
539
540 FOREACH_DEVICE(e, d) {
541 const char *s;
542
0f52a110 543 ASSERT_OK(sd_device_get_syspath(d, &s));
2d9c58d7
YW
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. */
0f52a110
YW
553 ASSERT_FAIL(access(syspath, F_OK));
554 ASSERT_EQ(errno, ENOENT);
2d9c58d7
YW
555 }
556}
557
558TEST(sd_device_enumerator_add_match_parent) {
559 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
74cb65e4
ZJS
560 /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
561 unsigned iterations = 200;
2d9c58d7
YW
562 int r;
563
0f52a110
YW
564 ASSERT_OK(sd_device_enumerator_new(&e));
565 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
a9cded65 566 exclude_problematic_devices(e);
2d9c58d7
YW
567
568 if (!slow_tests_enabled())
0f52a110 569 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
2d9c58d7
YW
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
74cb65e4
ZJS
576 if (iterations-- == 0)
577 break;
578
0f52a110 579 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
2d9c58d7
YW
580
581 r = sd_device_get_parent(dev, &parent);
582 if (r < 0) {
0f52a110 583 ASSERT_TRUE(ERRNO_IS_NEG_DEVICE_ABSENT(r));
2d9c58d7
YW
584 continue;
585 }
586
587 log_debug("> %s", syspath);
588
0f52a110
YW
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));
2d9c58d7
YW
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) {
0f52a110 598 ASSERT_ERROR(r, ENOENT);
2d9c58d7
YW
599 continue;
600 }
601 check_parent_match(p, parent);
602 }
603}
604
7fd45eec
FG
605TEST(sd_device_enumerator_add_all_parents) {
606 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
ab1bd9da 607 int r;
7fd45eec
FG
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) {
ab1bd9da 621 ASSERT_OK_POSITIVE(device_is_subsystem_devtype(dev, "block", "partition"));
7fd45eec
FG
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() */
09e0ce80 628 ASSERT_OK(sd_device_enumerator_add_all_parents(e));
7fd45eec
FG
629
630 unsigned not_filtered_parent_count = 0;
631 FOREACH_DEVICE(e, dev) {
ab1bd9da
YW
632 ASSERT_OK(r = device_is_subsystem_devtype(dev, "block", "partition"));
633 if (r == 0)
7fd45eec
FG
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
fadc8c48
YW
643TEST(sd_device_get_child) {
644 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
74cb65e4
ZJS
645 /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
646 unsigned iterations = 3000;
fadc8c48
YW
647 int r;
648
0f52a110
YW
649 ASSERT_OK(sd_device_enumerator_new(&e));
650 ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
a9cded65 651 exclude_problematic_devices(e);
fadc8c48
YW
652
653 if (!slow_tests_enabled())
0f52a110 654 ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
fadc8c48
YW
655
656 FOREACH_DEVICE(e, dev) {
657 const char *syspath, *parent_syspath, *expected_suffix, *suffix;
a1af8372 658 sd_device *parent;
fadc8c48
YW
659 bool found = false;
660
0f52a110 661 ASSERT_OK(sd_device_get_syspath(dev, &syspath));
fadc8c48
YW
662
663 r = sd_device_get_parent(dev, &parent);
664 if (r < 0) {
0f52a110 665 ASSERT_TRUE(ERRNO_IS_NEG_DEVICE_ABSENT(r));
fadc8c48
YW
666 continue;
667 }
668
0f52a110
YW
669 ASSERT_OK(sd_device_get_syspath(parent, &parent_syspath));
670 ASSERT_NOT_NULL((expected_suffix = path_startswith(syspath, parent_syspath)));
fadc8c48
YW
671
672 log_debug("> %s", syspath);
673
674 FOREACH_DEVICE_CHILD_WITH_SUFFIX(parent, child, suffix) {
675 const char *s;
676
74cb65e4
ZJS
677 if (iterations-- == 0)
678 return;
679
0f52a110
YW
680 ASSERT_NOT_NULL(child);
681 ASSERT_NOT_NULL(suffix);
fadc8c48
YW
682
683 if (!streq(suffix, expected_suffix))
684 continue;
685
0f52a110
YW
686 ASSERT_OK(sd_device_get_syspath(child, &s));
687 ASSERT_STREQ(s, syspath);
fadc8c48
YW
688 found = true;
689 break;
690 }
0f52a110 691 ASSERT_TRUE(found);
fadc8c48
YW
692 }
693}
694
68da8adf 695TEST(sd_device_new_from_nulstr) {
e6f88287
YW
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;
cff31876 705 _cleanup_free_ char *nulstr_copy = NULL;
12e2b70f 706 const char *nulstr;
e6f88287
YW
707 size_t len;
708
0f52a110 709 ASSERT_OK(sd_device_new_from_syspath(&device, "/sys/class/net/lo"));
e6f88287
YW
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);
0f52a110
YW
715 ASSERT_OK(device_add_devlink(device, devlink));
716 ASSERT_TRUE(set_contains(device->devlinks, devlink));
e6f88287
YW
717 }
718
4bc4040b 719 /* For issue #23799 */
0f52a110
YW
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));
4bc4040b 724
e6f88287 725 /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
0f52a110
YW
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"));
4bc4040b 741
e6f88287
YW
742 NULSTR_FOREACH(devlink, devlinks) {
743 log_device_info(from_nulstr, "checking devlink: %s", devlink);
0f52a110 744 ASSERT_TRUE(set_contains(from_nulstr->devlinks, devlink));
e6f88287
YW
745 }
746}
747
284ef480
YW
748TEST(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;
284ef480
YW
751 int r;
752
0f52a110 753 ASSERT_OK(mkdtemp_malloc("/tmp/test-sd-device.XXXXXXX", &tmpdir));
284ef480 754
0f52a110
YW
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", "*"));
284ef480
YW
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
0f52a110 766 ASSERT_OK(sd_device_get_sysname(dev, &sysname));
284ef480
YW
767
768 log_debug("%s(%s)", __func__, sysname);
769
0f52a110
YW
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);
d9000d70 774 ASSERT_NULL(d = sd_device_unref(d));
284ef480 775
0f52a110 776 ASSERT_OK(sd_device_get_devname(dev, &devpath));
284ef480 777 r = sd_device_new_from_path(&d, devpath);
0f52a110
YW
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);
d9000d70 783 ASSERT_NULL(d = sd_device_unref(d));
0f52a110 784 }
284ef480 785
0f52a110
YW
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);
284ef480
YW
791 }
792}
793
4fe46c34 794static void test_devname_from_devnum_one(const char *path) {
f79fdea6
YW
795 _cleanup_free_ char *resolved = NULL;
796 struct stat st;
797
798 log_debug("> %s", path);
799
800 if (stat(path, &st) < 0) {
f79fdea6
YW
801 log_notice("Path %s not found, skipping test", path);
802 return;
803 }
804
0f52a110
YW
805 ASSERT_OK(devname_from_devnum(st.st_mode, st.st_rdev, &resolved));
806 ASSERT_TRUE(path_equal(path, resolved));
d9000d70 807 ASSERT_NULL(resolved = mfree(resolved));
0f52a110
YW
808 ASSERT_OK(devname_from_stat_rdev(&st, &resolved));
809 ASSERT_TRUE(path_equal(path, resolved));
f79fdea6
YW
810}
811
4fe46c34
YW
812TEST(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");
f79fdea6
YW
819
820 if (is_device_node("/run/systemd/inaccessible/blk") > 0) {
4fe46c34
YW
821 test_devname_from_devnum_one("/run/systemd/inaccessible/chr");
822 test_devname_from_devnum_one("/run/systemd/inaccessible/blk");
f79fdea6
YW
823 }
824}
825
a412a1b9 826static int intro(void) {
b409aacb 827 if (path_is_mount_point("/sys") <= 0)
a412a1b9
DDM
828 return log_tests_skipped("/sys is not mounted");
829
830 return EXIT_SUCCESS;
831}
832
833DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);