1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "device-enumerator-private.h"
8 #include "device-internal.h"
9 #include "device-private.h"
10 #include "device-util.h"
11 #include "errno-util.h"
14 #include "nulstr-util.h"
15 #include "path-util.h"
17 #include "string-util.h"
19 #include "time-util.h"
20 #include "tmpfile-util.h"
22 static void test_sd_device_one(sd_device
*d
) {
23 _cleanup_(sd_device_unrefp
) sd_device
*dev
= NULL
;
24 const char *syspath
, *sysname
, *subsystem
= NULL
, *devname
, *val
;
25 bool is_block
= false;
30 assert_se(sd_device_get_syspath(d
, &syspath
) >= 0);
31 assert_se(path_startswith(syspath
, "/sys"));
32 assert_se(sd_device_get_sysname(d
, &sysname
) >= 0);
34 log_info("%s(%s)", __func__
, syspath
);
36 assert_se(sd_device_new_from_syspath(&dev
, syspath
) >= 0);
37 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
38 assert_se(streq(syspath
, val
));
39 dev
= sd_device_unref(dev
);
41 assert_se(sd_device_new_from_path(&dev
, syspath
) >= 0);
42 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
43 assert_se(streq(syspath
, val
));
44 dev
= sd_device_unref(dev
);
46 r
= sd_device_get_ifindex(d
, &ifindex
);
48 assert_se(ifindex
> 0);
50 r
= sd_device_new_from_ifindex(&dev
, ifindex
);
52 log_device_warning_errno(d
, r
,
53 "Failed to create sd-device object from ifindex %i. "
54 "Maybe running on a non-host network namespace.", ifindex
);
57 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
58 assert_se(streq(syspath
, val
));
59 dev
= sd_device_unref(dev
);
62 /* This does not require the interface really exists on the network namespace.
63 * Hence, this should always succeed. */
64 assert_se(sd_device_new_from_ifname(&dev
, sysname
) >= 0);
65 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
66 assert_se(streq(syspath
, val
));
67 dev
= sd_device_unref(dev
);
69 assert_se(r
== -ENOENT
);
71 r
= sd_device_get_subsystem(d
, &subsystem
);
73 assert_se(r
== -ENOENT
);
74 else if (!streq(subsystem
, "gpio")) { /* Unfortunately, there exist /sys/class/gpio and /sys/bus/gpio.
75 * Hence, sd_device_new_from_subsystem_sysname() and
76 * sd_device_new_from_device_id() may not work as expected. */
77 const char *name
, *id
;
79 if (streq(subsystem
, "drivers"))
80 name
= strjoina(d
->driver_subsystem
, ":", sysname
);
83 assert_se(sd_device_new_from_subsystem_sysname(&dev
, subsystem
, name
) >= 0);
84 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
85 assert_se(streq(syspath
, val
));
86 dev
= sd_device_unref(dev
);
88 /* The device ID depends on subsystem. */
89 assert_se(device_get_device_id(d
, &id
) >= 0);
90 r
= sd_device_new_from_device_id(&dev
, id
);
91 if (r
== -ENODEV
&& ifindex
> 0)
92 log_device_warning_errno(d
, r
,
93 "Failed to create sd-device object from device ID \"%s\". "
94 "Maybe running on a non-host network namespace.", id
);
97 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
98 assert_se(streq(syspath
, val
));
99 dev
= sd_device_unref(dev
);
102 /* These require udev database, and reading database requires device ID. */
103 r
= sd_device_get_is_initialized(d
);
105 r
= sd_device_get_usec_since_initialized(d
, &usec
);
106 assert_se((r
>= 0 && usec
> 0) || r
== -ENODATA
);
110 r
= sd_device_get_property_value(d
, "ID_NET_DRIVER", &val
);
111 assert_se(r
>= 0 || r
== -ENOENT
);
114 is_block
= streq_ptr(subsystem
, "block");
116 r
= sd_device_get_devname(d
, &devname
);
118 r
= sd_device_new_from_devname(&dev
, devname
);
120 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
121 assert_se(streq(syspath
, val
));
122 dev
= sd_device_unref(dev
);
124 assert_se(r
== -ENODEV
|| ERRNO_IS_PRIVILEGE(r
));
126 r
= sd_device_new_from_path(&dev
, devname
);
128 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
129 assert_se(streq(syspath
, val
));
130 dev
= sd_device_unref(dev
);
132 _cleanup_close_
int fd
= -1;
133 fd
= sd_device_open(d
, O_CLOEXEC
| O_NONBLOCK
| (is_block
? O_RDONLY
: O_NOCTTY
| O_PATH
));
134 assert_se(fd
>= 0 || ERRNO_IS_PRIVILEGE(fd
));
136 assert_se(r
== -ENODEV
|| ERRNO_IS_PRIVILEGE(r
));
138 assert_se(r
== -ENOENT
);
140 r
= sd_device_get_devnum(d
, &devnum
);
142 _cleanup_free_
char *p
= NULL
;
144 assert_se(major(devnum
) > 0);
146 assert_se(sd_device_new_from_devnum(&dev
, is_block
? 'b' : 'c', devnum
) >= 0);
147 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
148 assert_se(streq(syspath
, val
));
149 dev
= sd_device_unref(dev
);
151 assert_se(asprintf(&p
, "/dev/%s/%u:%u", is_block
? "block" : "char", major(devnum
), minor(devnum
)) >= 0);
152 assert_se(sd_device_new_from_devname(&dev
, p
) >= 0);
153 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
154 assert_se(streq(syspath
, val
));
155 dev
= sd_device_unref(dev
);
157 assert_se(sd_device_new_from_path(&dev
, p
) >= 0);
158 assert_se(sd_device_get_syspath(dev
, &val
) >= 0);
159 assert_se(streq(syspath
, val
));
160 dev
= sd_device_unref(dev
);
162 assert_se(r
== -ENOENT
);
164 assert_se(sd_device_get_devpath(d
, &val
) >= 0);
166 r
= sd_device_get_devtype(d
, &val
);
167 assert_se(r
>= 0 || r
== -ENOENT
);
169 r
= sd_device_get_driver(d
, &val
);
170 assert_se(r
>= 0 || r
== -ENOENT
);
172 r
= sd_device_get_sysnum(d
, &val
);
174 assert_se(val
> sysname
);
175 assert_se(val
< sysname
+ strlen(sysname
));
176 assert_se(in_charset(val
, DIGITS
));
177 assert_se(!ascii_isdigit(val
[-1]));
179 assert_se(r
== -ENOENT
);
181 r
= sd_device_get_sysattr_value(d
, "name_assign_type", &val
);
182 assert_se(r
>= 0 || ERRNO_IS_PRIVILEGE(r
) || IN_SET(r
, -ENOENT
, -EINVAL
));
185 TEST(sd_device_enumerator_devices
) {
186 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
189 assert_se(sd_device_enumerator_new(&e
) >= 0);
190 assert_se(sd_device_enumerator_allow_uninitialized(e
) >= 0);
191 /* On some CI environments, it seems some loop block devices and corresponding bdi devices sometimes
192 * disappear during running this test. Let's exclude them here for stability. */
193 assert_se(sd_device_enumerator_add_match_subsystem(e
, "bdi", false) >= 0);
194 assert_se(sd_device_enumerator_add_nomatch_sysname(e
, "loop*") >= 0);
195 /* On CentOS CI, systemd-networkd-tests.py may be running when this test is invoked. The networkd
196 * test creates and removes many network interfaces, and may interfere with this test. */
197 assert_se(sd_device_enumerator_add_match_subsystem(e
, "net", false) >= 0);
199 test_sd_device_one(d
);
202 TEST(sd_device_enumerator_subsystems
) {
203 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
206 assert_se(sd_device_enumerator_new(&e
) >= 0);
207 assert_se(sd_device_enumerator_allow_uninitialized(e
) >= 0);
208 FOREACH_SUBSYSTEM(e
, d
)
209 test_sd_device_one(d
);
212 static void test_sd_device_enumerator_filter_subsystem_one(
213 const char *subsystem
,
215 unsigned *ret_n_new_dev
,
216 unsigned *ret_n_removed_dev
) {
218 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
219 unsigned n_new_dev
= 0, n_removed_dev
= 0;
222 assert_se(sd_device_enumerator_new(&e
) >= 0);
223 assert_se(sd_device_enumerator_add_match_subsystem(e
, subsystem
, true) >= 0);
224 assert_se(sd_device_enumerator_add_nomatch_sysname(e
, "loop*") >= 0);
226 FOREACH_DEVICE(e
, d
) {
230 assert_se(sd_device_get_syspath(d
, &syspath
) >= 0);
231 t
= hashmap_remove(h
, syspath
);
234 log_warning("New device found: subsystem:%s syspath:%s", subsystem
, syspath
);
238 assert_se(!sd_device_unref(t
));
241 HASHMAP_FOREACH(d
, h
) {
244 assert_se(sd_device_get_syspath(d
, &syspath
) >= 0);
245 log_warning("Device removed: subsystem:%s syspath:%s", subsystem
, syspath
);
248 assert_se(!sd_device_unref(d
));
253 *ret_n_new_dev
= n_new_dev
;
254 *ret_n_removed_dev
= n_removed_dev
;
257 TEST(sd_device_enumerator_filter_subsystem
) {
258 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
259 _cleanup_(hashmap_freep
) Hashmap
*subsystems
;
260 unsigned n_new_dev
= 0, n_removed_dev
= 0;
265 assert_se(subsystems
= hashmap_new(&string_hash_ops
));
266 assert_se(sd_device_enumerator_new(&e
) >= 0);
267 /* See comments in TEST(sd_device_enumerator_devices). */
268 assert_se(sd_device_enumerator_add_match_subsystem(e
, "bdi", false) >= 0);
269 assert_se(sd_device_enumerator_add_nomatch_sysname(e
, "loop*") >= 0);
270 assert_se(sd_device_enumerator_add_match_subsystem(e
, "net", false) >= 0);
272 FOREACH_DEVICE(e
, d
) {
273 const char *syspath
, *subsystem
;
276 assert_se(sd_device_get_syspath(d
, &syspath
) >= 0);
278 r
= sd_device_get_subsystem(d
, &subsystem
);
279 assert_se(r
>= 0 || r
== -ENOENT
);
283 h
= hashmap_get(subsystems
, subsystem
);
286 assert_se(str
= strdup(subsystem
));
287 assert_se(h
= hashmap_new(&string_hash_ops
));
288 assert_se(hashmap_put(subsystems
, str
, h
) >= 0);
291 assert_se(hashmap_put(h
, syspath
, d
) >= 0);
292 assert_se(sd_device_ref(d
));
294 log_debug("Added subsystem:%s syspath:%s", subsystem
, syspath
);
297 while ((h
= hashmap_steal_first_key_and_value(subsystems
, (void**) &s
))) {
300 test_sd_device_enumerator_filter_subsystem_one(s
, TAKE_PTR(h
), &n
, &m
);
308 log_warning("%u new devices are found in re-scan", n_new_dev
);
309 if (n_removed_dev
> 0)
310 log_warning("%u devices removed in re-scan", n_removed_dev
);
312 /* Assume that not so many devices are plugged or unplugged. */
313 assert_se(n_new_dev
+ n_removed_dev
<= 10);
316 TEST(sd_device_enumerator_add_match_sysattr
) {
317 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
321 assert_se(sd_device_enumerator_new(&e
) >= 0);
322 assert_se(sd_device_enumerator_allow_uninitialized(e
) >= 0);
323 assert_se(sd_device_enumerator_add_match_subsystem(e
, "net", true) >= 0);
324 assert_se(sd_device_enumerator_add_match_sysattr(e
, "ifindex", "1", true) >= 0);
325 assert_se(sd_device_enumerator_add_match_sysattr(e
, "ifindex", "hoge", true) >= 0);
326 assert_se(sd_device_enumerator_add_match_sysattr(e
, "ifindex", "foo", true) >= 0);
327 assert_se(sd_device_enumerator_add_match_sysattr(e
, "ifindex", "bar", false) >= 0);
328 assert_se(sd_device_enumerator_add_match_sysattr(e
, "ifindex", "baz", false) >= 0);
330 dev
= sd_device_enumerator_get_device_first(e
);
332 assert_se(sd_device_get_ifindex(dev
, &ifindex
) >= 0);
333 assert_se(ifindex
== 1);
335 assert_se(!sd_device_enumerator_get_device_next(e
));
338 TEST(sd_device_enumerator_add_match_property
) {
339 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
343 assert_se(sd_device_enumerator_new(&e
) >= 0);
344 assert_se(sd_device_enumerator_allow_uninitialized(e
) >= 0);
345 assert_se(sd_device_enumerator_add_match_subsystem(e
, "net", true) >= 0);
346 assert_se(sd_device_enumerator_add_match_sysattr(e
, "ifindex", "1", true) >= 0);
347 assert_se(sd_device_enumerator_add_match_property(e
, "IFINDE*", "1*") >= 0);
348 assert_se(sd_device_enumerator_add_match_property(e
, "IFINDE*", "hoge") >= 0);
349 assert_se(sd_device_enumerator_add_match_property(e
, "IFINDE*", NULL
) >= 0);
350 assert_se(sd_device_enumerator_add_match_property(e
, "AAAAA", "BBBB") >= 0);
351 assert_se(sd_device_enumerator_add_match_property(e
, "FOOOO", NULL
) >= 0);
353 dev
= sd_device_enumerator_get_device_first(e
);
355 assert_se(sd_device_get_ifindex(dev
, &ifindex
) >= 0);
356 assert_se(ifindex
== 1);
359 TEST(sd_device_new_from_nulstr
) {
360 const char *devlinks
=
361 "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
362 "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0"
363 "/dev/disk/by-label/Arch\\x20Linux\0"
364 "/dev/disk/by-uuid/a07b87e5-4af5-4a59-bde9-yyyyyyyyyyyy\0"
365 "/dev/disk/by-partlabel/Arch\\x20Linux\0"
368 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
, *from_nulstr
= NULL
;
369 _cleanup_free_
char *nulstr_copy
= NULL
;
370 const char *devlink
, *nulstr
;
373 assert_se(sd_device_new_from_syspath(&device
, "/sys/class/net/lo") >= 0);
375 /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a
376 * test for generating and parsing nulstr. For issue #17772. */
377 NULSTR_FOREACH(devlink
, devlinks
) {
378 log_device_info(device
, "setting devlink: %s", devlink
);
379 assert_se(device_add_devlink(device
, devlink
) >= 0);
380 assert_se(set_contains(device
->devlinks
, devlink
));
383 /* For issue #23799 */
384 assert_se(device_add_tag(device
, "tag1", false) >= 0);
385 assert_se(device_add_tag(device
, "tag2", false) >= 0);
386 assert_se(device_add_tag(device
, "current-tag1", true) >= 0);
387 assert_se(device_add_tag(device
, "current-tag2", true) >= 0);
389 /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
390 assert_se(device_add_property_internal(device
, "SEQNUM", "1") >= 0);
391 assert_se(device_add_property_internal(device
, "ACTION", "change") >= 0);
393 assert_se(device_get_properties_nulstr(device
, &nulstr
, &len
) >= 0);
394 assert_se(nulstr_copy
= newdup(char, nulstr
, len
));
395 assert_se(device_new_from_nulstr(&from_nulstr
, nulstr_copy
, len
) >= 0);
397 assert_se(sd_device_has_tag(from_nulstr
, "tag1") == 1);
398 assert_se(sd_device_has_tag(from_nulstr
, "tag2") == 1);
399 assert_se(sd_device_has_tag(from_nulstr
, "current-tag1") == 1);
400 assert_se(sd_device_has_tag(from_nulstr
, "current-tag2") == 1);
401 assert_se(sd_device_has_current_tag(from_nulstr
, "tag1") == 0);
402 assert_se(sd_device_has_current_tag(from_nulstr
, "tag2") == 0);
403 assert_se(sd_device_has_current_tag(from_nulstr
, "current-tag1") == 1);
404 assert_se(sd_device_has_current_tag(from_nulstr
, "current-tag2") == 1);
406 NULSTR_FOREACH(devlink
, devlinks
) {
407 log_device_info(from_nulstr
, "checking devlink: %s", devlink
);
408 assert_se(set_contains(from_nulstr
->devlinks
, devlink
));
412 TEST(sd_device_new_from_path
) {
413 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
414 _cleanup_(rm_rf_physical_and_freep
) char *tmpdir
= NULL
;
418 assert_se(mkdtemp_malloc("/tmp/test-sd-device.XXXXXXX", &tmpdir
) >= 0);
420 assert_se(sd_device_enumerator_new(&e
) >= 0);
421 assert_se(sd_device_enumerator_allow_uninitialized(e
) >= 0);
422 assert_se(sd_device_enumerator_add_match_subsystem(e
, "block", true) >= 0);
423 assert_se(sd_device_enumerator_add_nomatch_sysname(e
, "loop*") >= 0);
424 assert_se(sd_device_enumerator_add_match_property(e
, "DEVNAME", "*") >= 0);
426 FOREACH_DEVICE(e
, dev
) {
427 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
428 const char *syspath
, *devpath
, *sysname
, *s
;
429 _cleanup_free_
char *path
= NULL
;
431 assert_se(sd_device_get_sysname(dev
, &sysname
) >= 0);
433 log_debug("%s(%s)", __func__
, sysname
);
435 assert_se(sd_device_get_syspath(dev
, &syspath
) >= 0);
436 assert_se(sd_device_new_from_path(&d
, syspath
) >= 0);
437 assert_se(sd_device_get_syspath(d
, &s
) >= 0);
438 assert_se(streq(s
, syspath
));
439 d
= sd_device_unref(d
);
441 assert_se(sd_device_get_devname(dev
, &devpath
) >= 0);
442 r
= sd_device_new_from_path(&d
, devpath
);
444 assert_se(sd_device_get_syspath(d
, &s
) >= 0);
445 assert_se(streq(s
, syspath
));
446 d
= sd_device_unref(d
);
448 assert_se(r
== -ENODEV
|| ERRNO_IS_PRIVILEGE(r
));
450 assert_se(path
= path_join(tmpdir
, sysname
));
451 assert_se(symlink(syspath
, path
) >= 0);
452 assert_se(sd_device_new_from_path(&d
, path
) >= 0);
453 assert_se(sd_device_get_syspath(d
, &s
) >= 0);
454 assert_se(streq(s
, syspath
));
458 DEFINE_TEST_MAIN(LOG_INFO
);