]>
Commit | Line | Data |
---|---|---|
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 |
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)); | |
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 | 90 | static 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 | 301 | static 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 | ||
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 | ||
af18705f YW |
318 | FOREACH_DEVICE(e, d) |
319 | test_sd_device_one(d); | |
320 | } | |
321 | ||
68da8adf | 322 | TEST(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 |
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 | ||
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 | 376 | static 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 | ||
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 | ||
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 |
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 | ||
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 | ||
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 | ||
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 |
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 | ||
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 |
534 | static 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 | ||
558 | TEST(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 |
605 | TEST(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 |
643 | TEST(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 | 695 | TEST(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 |
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; | |
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 | 794 | static 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 |
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"); | |
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 | 826 | static 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 | ||
833 | DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); |