]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/device-enumerator.c
udevadm: info: also show parent devices by --tree
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-enumerator.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4 #include <unistd.h>
5
6 #include "sd-device.h"
7
8 #include "alloc-util.h"
9 #include "device-enumerator-private.h"
10 #include "device-util.h"
11 #include "dirent-util.h"
12 #include "fd-util.h"
13 #include "set.h"
14 #include "sort-util.h"
15 #include "string-util.h"
16 #include "strv.h"
17
18 #define DEVICE_ENUMERATE_MAX_DEPTH 256
19
20 typedef enum DeviceEnumerationType {
21 DEVICE_ENUMERATION_TYPE_DEVICES,
22 DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
23 DEVICE_ENUMERATION_TYPE_ALL,
24 _DEVICE_ENUMERATION_TYPE_MAX,
25 _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
26 } DeviceEnumerationType;
27
28 struct sd_device_enumerator {
29 unsigned n_ref;
30
31 DeviceEnumerationType type;
32 Hashmap *devices_by_syspath;
33 sd_device **devices;
34 size_t n_devices, current_device_index;
35 bool scan_uptodate;
36 bool sorted;
37
38 char **prioritized_subsystems;
39 Set *match_subsystem;
40 Set *nomatch_subsystem;
41 Hashmap *match_sysattr;
42 Hashmap *nomatch_sysattr;
43 Hashmap *match_property;
44 Set *match_sysname;
45 Set *match_tag;
46 Set *match_parent;
47 MatchInitializedType match_initialized;
48 };
49
50 _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
51 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerator = NULL;
52
53 assert(ret);
54
55 enumerator = new(sd_device_enumerator, 1);
56 if (!enumerator)
57 return -ENOMEM;
58
59 *enumerator = (sd_device_enumerator) {
60 .n_ref = 1,
61 .type = _DEVICE_ENUMERATION_TYPE_INVALID,
62 .match_initialized = MATCH_INITIALIZED_COMPAT,
63 };
64
65 *ret = TAKE_PTR(enumerator);
66
67 return 0;
68 }
69
70 static void device_unref_many(sd_device **devices, size_t n) {
71 assert(devices || n == 0);
72
73 for (size_t i = 0; i < n; i++)
74 sd_device_unref(devices[i]);
75 }
76
77 static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) {
78 assert(enumerator);
79
80 hashmap_clear_with_destructor(enumerator->devices_by_syspath, sd_device_unref);
81 device_unref_many(enumerator->devices, enumerator->n_devices);
82 enumerator->devices = mfree(enumerator->devices);
83 enumerator->n_devices = 0;
84 }
85
86 static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
87 assert(enumerator);
88
89 device_enumerator_unref_devices(enumerator);
90
91 hashmap_free(enumerator->devices_by_syspath);
92 strv_free(enumerator->prioritized_subsystems);
93 set_free(enumerator->match_subsystem);
94 set_free(enumerator->nomatch_subsystem);
95 hashmap_free(enumerator->match_sysattr);
96 hashmap_free(enumerator->nomatch_sysattr);
97 hashmap_free(enumerator->match_property);
98 set_free(enumerator->match_sysname);
99 set_free(enumerator->match_tag);
100 set_free(enumerator->match_parent);
101
102 return mfree(enumerator);
103 }
104
105 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free);
106
107 int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
108 int r;
109
110 assert(enumerator);
111 assert(subsystem);
112
113 if (strv_contains(enumerator->prioritized_subsystems, subsystem))
114 return 0;
115
116 r = strv_extend(&enumerator->prioritized_subsystems, subsystem);
117 if (r < 0)
118 return r;
119
120 enumerator->scan_uptodate = false;
121
122 return 1;
123 }
124
125 _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
126 Set **set;
127 int r;
128
129 assert_return(enumerator, -EINVAL);
130 assert_return(subsystem, -EINVAL);
131
132 if (match)
133 set = &enumerator->match_subsystem;
134 else
135 set = &enumerator->nomatch_subsystem;
136
137 r = set_put_strdup(set, subsystem);
138 if (r <= 0)
139 return r;
140
141 enumerator->scan_uptodate = false;
142
143 return 1;
144 }
145
146 _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match) {
147 Hashmap **hashmap;
148 int r;
149
150 assert_return(enumerator, -EINVAL);
151 assert_return(sysattr, -EINVAL);
152
153 if (match)
154 hashmap = &enumerator->match_sysattr;
155 else
156 hashmap = &enumerator->nomatch_sysattr;
157
158 /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
159 * multiple times with the same sysattr but different value. */
160 r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
161 if (r <= 0)
162 return r;
163
164 enumerator->scan_uptodate = false;
165
166 return 1;
167 }
168
169 _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value) {
170 int r;
171
172 assert_return(enumerator, -EINVAL);
173 assert_return(property, -EINVAL);
174
175 /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
176 * multiple times with the same property but different value. */
177 r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
178 if (r <= 0)
179 return r;
180
181 enumerator->scan_uptodate = false;
182
183 return 1;
184 }
185
186 _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
187 int r;
188
189 assert_return(enumerator, -EINVAL);
190 assert_return(sysname, -EINVAL);
191
192 r = set_put_strdup(&enumerator->match_sysname, sysname);
193 if (r <= 0)
194 return r;
195
196 enumerator->scan_uptodate = false;
197
198 return 1;
199 }
200
201 _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
202 int r;
203
204 assert_return(enumerator, -EINVAL);
205 assert_return(tag, -EINVAL);
206
207 r = set_put_strdup(&enumerator->match_tag, tag);
208 if (r <= 0)
209 return r;
210
211 enumerator->scan_uptodate = false;
212
213 return 1;
214 }
215
216 int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
217 const char *path;
218 int r;
219
220 assert(enumerator);
221 assert(parent);
222
223 r = sd_device_get_syspath(parent, &path);
224 if (r < 0)
225 return r;
226
227 r = set_put_strdup(&enumerator->match_parent, path);
228 if (r <= 0)
229 return r;
230
231 enumerator->scan_uptodate = false;
232
233 return 1;
234 }
235
236 _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
237 assert_return(enumerator, -EINVAL);
238 assert_return(parent, -EINVAL);
239
240 set_clear(enumerator->match_parent);
241
242 return device_enumerator_add_match_parent_incremental(enumerator, parent);
243 }
244
245 _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
246 assert_return(enumerator, -EINVAL);
247
248 enumerator->match_initialized = MATCH_INITIALIZED_ALL;
249
250 enumerator->scan_uptodate = false;
251
252 return 1;
253 }
254
255 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) {
256 assert_return(enumerator, -EINVAL);
257 assert_return(type >= 0 && type < _MATCH_INITIALIZED_MAX, -EINVAL);
258
259 enumerator->match_initialized = type;
260
261 enumerator->scan_uptodate = false;
262
263 return 1;
264 }
265
266 static int sound_device_compare(const char *devpath_a, const char *devpath_b) {
267 const char *sound_a, *sound_b;
268 size_t prefix_len;
269
270 assert(devpath_a);
271 assert(devpath_b);
272
273 /* For sound cards the control device must be enumerated last to make sure it's the final
274 * device node that gets ACLs applied. Applications rely on this fact and use ACL changes on
275 * the control node as an indicator that the ACL change of the entire sound card completed. The
276 * kernel makes this guarantee when creating those devices, and hence we should too when
277 * enumerating them. */
278
279 sound_a = strstr(devpath_a, "/sound/card");
280 if (!sound_a)
281 return 0;
282
283 sound_a += STRLEN("/sound/card");
284 sound_a = strchr(devpath_a, '/');
285 if (!sound_a)
286 return 0;
287
288 prefix_len = sound_a - devpath_a;
289
290 if (!strneq(devpath_a, devpath_b, prefix_len))
291 return 0;
292
293 sound_b = devpath_b + prefix_len;
294
295 return CMP(!!startswith(sound_a, "/controlC"),
296 !!startswith(sound_b, "/controlC"));
297 }
298
299 static bool devpath_is_late_block(const char *devpath) {
300 assert(devpath);
301
302 return strstr(devpath, "/block/md") || strstr(devpath, "/block/dm-");
303 }
304
305 static int device_compare(sd_device * const *a, sd_device * const *b) {
306 const char *devpath_a, *devpath_b;
307 int r;
308
309 assert(a);
310 assert(b);
311 assert(*a);
312 assert(*b);
313
314 assert_se(sd_device_get_devpath(*(sd_device**) a, &devpath_a) >= 0);
315 assert_se(sd_device_get_devpath(*(sd_device**) b, &devpath_b) >= 0);
316
317 r = sound_device_compare(devpath_a, devpath_b);
318 if (r != 0)
319 return r;
320
321 /* md and dm devices are enumerated after all other devices */
322 r = CMP(devpath_is_late_block(devpath_a), devpath_is_late_block(devpath_b));
323 if (r != 0)
324 return r;
325
326 return path_compare(devpath_a, devpath_b);
327 }
328
329 static int enumerator_sort_devices(sd_device_enumerator *enumerator) {
330 size_t n_sorted = 0, n = 0;
331 sd_device **devices;
332 sd_device *device;
333 int r;
334
335 assert(enumerator);
336
337 if (enumerator->sorted)
338 return 0;
339
340 devices = new(sd_device*, hashmap_size(enumerator->devices_by_syspath));
341 if (!devices)
342 return -ENOMEM;
343
344 STRV_FOREACH(prioritized_subsystem, enumerator->prioritized_subsystems) {
345
346 for (;;) {
347 const char *syspath;
348 size_t m = n;
349
350 HASHMAP_FOREACH_KEY(device, syspath, enumerator->devices_by_syspath) {
351 _cleanup_free_ char *p = NULL;
352 const char *subsys;
353
354 if (sd_device_get_subsystem(device, &subsys) < 0)
355 continue;
356
357 if (!streq(subsys, *prioritized_subsystem))
358 continue;
359
360 devices[n++] = sd_device_ref(device);
361
362 for (;;) {
363 _cleanup_free_ char *q = NULL;
364
365 r = path_extract_directory(p ?: syspath, &q);
366 if (r == -EADDRNOTAVAIL)
367 break;
368 if (r < 0)
369 goto failed;
370
371 device = hashmap_get(enumerator->devices_by_syspath, q);
372 if (device)
373 devices[n++] = sd_device_ref(device);
374
375 free_and_replace(p, q);
376 }
377
378 break;
379 }
380
381 /* We cannot remove multiple entries in the loop HASHMAP_FOREACH_KEY() above. */
382 for (size_t i = m; i < n; i++) {
383 r = sd_device_get_syspath(devices[i], &syspath);
384 if (r < 0)
385 goto failed;
386
387 assert_se(hashmap_remove(enumerator->devices_by_syspath, syspath) == devices[i]);
388 sd_device_unref(devices[i]);
389 }
390
391 if (m == n)
392 break;
393 }
394
395 typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
396 n_sorted = n;
397 }
398
399 HASHMAP_FOREACH(device, enumerator->devices_by_syspath)
400 devices[n++] = sd_device_ref(device);
401
402 /* Move all devices back to the hashmap. Otherwise, devices added by
403 * udev_enumerate_add_syspath() -> device_enumerator_add_device() may not be listed. */
404 for (size_t i = 0; i < n_sorted; i++) {
405 const char *syspath;
406
407 r = sd_device_get_syspath(devices[i], &syspath);
408 if (r < 0)
409 goto failed;
410
411 r = hashmap_put(enumerator->devices_by_syspath, syspath, devices[i]);
412 if (r < 0)
413 goto failed;
414 assert(r > 0);
415
416 sd_device_ref(devices[i]);
417 }
418
419 typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
420
421 device_unref_many(enumerator->devices, enumerator->n_devices);
422
423 enumerator->n_devices = n;
424 free_and_replace(enumerator->devices, devices);
425
426 enumerator->sorted = true;
427 return 0;
428
429 failed:
430 device_unref_many(devices, n);
431 free(devices);
432 return r;
433 }
434
435 int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
436 const char *syspath;
437 int r;
438
439 assert_return(enumerator, -EINVAL);
440 assert_return(device, -EINVAL);
441
442 r = sd_device_get_syspath(device, &syspath);
443 if (r < 0)
444 return r;
445
446 r = hashmap_ensure_put(&enumerator->devices_by_syspath, &string_hash_ops, syspath, device);
447 if (IN_SET(r, -EEXIST, 0))
448 return 0;
449 if (r < 0)
450 return r;
451
452 sd_device_ref(device);
453
454 enumerator->sorted = false;
455 return 1;
456 }
457
458 static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
459 const char *property;
460 const char *value;
461
462 assert(enumerator);
463 assert(device);
464
465 if (hashmap_isempty(enumerator->match_property))
466 return true;
467
468 HASHMAP_FOREACH_KEY(value, property, enumerator->match_property) {
469 const char *property_dev, *value_dev;
470
471 FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
472 if (fnmatch(property, property_dev, 0) != 0)
473 continue;
474
475 if (!value && !value_dev)
476 return true;
477
478 if (!value || !value_dev)
479 continue;
480
481 if (fnmatch(value, value_dev, 0) == 0)
482 return true;
483 }
484 }
485
486 return false;
487 }
488
489 static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
490 const char *tag;
491
492 assert(enumerator);
493 assert(device);
494
495 SET_FOREACH(tag, enumerator->match_tag)
496 if (!sd_device_has_tag(device, tag))
497 return false;
498
499 return true;
500 }
501
502 static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
503 const char *sysname_match;
504
505 assert(enumerator);
506 assert(sysname);
507
508 if (set_isempty(enumerator->match_sysname))
509 return true;
510
511 SET_FOREACH(sysname_match, enumerator->match_sysname)
512 if (fnmatch(sysname_match, sysname, 0) == 0)
513 return true;
514
515 return false;
516 }
517
518 static int match_initialized(sd_device_enumerator *enumerator, sd_device *device) {
519 int r;
520
521 assert(enumerator);
522 assert(device);
523
524 if (enumerator->match_initialized == MATCH_INITIALIZED_ALL)
525 return true;
526
527 r = sd_device_get_is_initialized(device);
528 if (r == -ENOENT) /* this is necessarily racey, so ignore missing devices */
529 return false;
530 if (r < 0)
531 return r;
532
533 if (enumerator->match_initialized == MATCH_INITIALIZED_COMPAT) {
534 /* only devices that have no devnode/ifindex or have a db entry are accepted. */
535 if (r > 0)
536 return true;
537
538 if (sd_device_get_devnum(device, NULL) >= 0)
539 return true;
540
541 if (sd_device_get_ifindex(device, NULL) >= 0)
542 return true;
543
544 return false;
545 }
546
547 return (enumerator->match_initialized == MATCH_INITIALIZED_NO) == (r == 0);
548 }
549
550 static int test_matches(
551 sd_device_enumerator *enumerator,
552 sd_device *device,
553 bool ignore_parent_match) {
554
555 int r;
556
557 assert(enumerator);
558 assert(device);
559
560 /* Checks all matches, except for the sysname match (which the caller should check beforehand) */
561
562 r = match_initialized(enumerator, device);
563 if (r <= 0)
564 return r;
565
566 if (!ignore_parent_match &&
567 !device_match_parent(device, enumerator->match_parent, NULL))
568 return false;
569
570 if (!match_tag(enumerator, device))
571 return false;
572
573 if (!match_property(enumerator, device))
574 return false;
575
576 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
577 return false;
578
579 return true;
580 }
581
582 static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
583 const char *subsystem_match;
584
585 assert(enumerator);
586
587 if (!subsystem)
588 return false;
589
590 SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem)
591 if (fnmatch(subsystem_match, subsystem, 0) == 0)
592 return false;
593
594 if (set_isempty(enumerator->match_subsystem))
595 return true;
596
597 SET_FOREACH(subsystem_match, enumerator->match_subsystem)
598 if (fnmatch(subsystem_match, subsystem, 0) == 0)
599 return true;
600
601 return false;
602 }
603
604 static int enumerator_add_parent_devices(
605 sd_device_enumerator *enumerator,
606 sd_device *device,
607 bool ignore_parent_match) {
608
609 int k, r = 0;
610
611 assert(enumerator);
612 assert(device);
613
614 for (;;) {
615 const char *ss, *usn;
616
617 k = sd_device_get_parent(device, &device);
618 if (k == -ENOENT) /* Reached the top? */
619 break;
620 if (k < 0) {
621 r = k;
622 break;
623 }
624
625 k = sd_device_get_subsystem(device, &ss);
626 if (k == -ENOENT) /* Has no subsystem? */
627 continue;
628 if (k < 0) {
629 r = k;
630 break;
631 }
632
633 if (!match_subsystem(enumerator, ss))
634 continue;
635
636 k = sd_device_get_sysname(device, &usn);
637 if (k < 0) {
638 r = k;
639 break;
640 }
641
642 if (!match_sysname(enumerator, usn))
643 continue;
644
645 k = test_matches(enumerator, device, ignore_parent_match);
646 if (k < 0) {
647 r = k;
648 break;
649 }
650 if (k == 0)
651 continue;
652
653 k = device_enumerator_add_device(enumerator, device);
654 if (k < 0) {
655 r = k;
656 break;
657 }
658 if (k == 0) /* Exists already? Then no need to go further up. */
659 break;
660 }
661
662 return r;
663 }
664
665 int device_enumerator_add_parent_devices(sd_device_enumerator *enumerator, sd_device *device) {
666 return enumerator_add_parent_devices(enumerator, device, /* ignore_parent_match = */ true);
667 }
668
669 static bool relevant_sysfs_subdir(const struct dirent *de) {
670 assert(de);
671
672 if (de->d_name[0] == '.')
673 return false;
674
675 /* Also filter out regular files and such, i.e. stuff that definitely isn't a kobject path. (Note
676 * that we rely on the fact that sysfs fills in d_type here, i.e. doesn't do DT_UNKNOWN) */
677 return IN_SET(de->d_type, DT_DIR, DT_LNK);
678 }
679
680 static int enumerator_scan_dir_and_add_devices(
681 sd_device_enumerator *enumerator,
682 const char *basedir,
683 const char *subdir1,
684 const char *subdir2) {
685
686 _cleanup_closedir_ DIR *dir = NULL;
687 char *path;
688 int k, r = 0;
689
690 assert(enumerator);
691 assert(basedir);
692
693 path = strjoina("/sys/", basedir, "/");
694
695 if (subdir1)
696 path = strjoina(path, subdir1, "/");
697
698 if (subdir2)
699 path = strjoina(path, subdir2, "/");
700
701 dir = opendir(path);
702 if (!dir)
703 /* this is necessarily racey, so ignore missing directories */
704 return (errno == ENOENT && (subdir1 || subdir2)) ? 0 : -errno;
705
706 FOREACH_DIRENT_ALL(de, dir, return -errno) {
707 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
708 char syspath[strlen(path) + 1 + strlen(de->d_name) + 1];
709
710 if (!relevant_sysfs_subdir(de))
711 continue;
712
713 if (!match_sysname(enumerator, de->d_name))
714 continue;
715
716 (void) sprintf(syspath, "%s%s", path, de->d_name);
717
718 k = sd_device_new_from_syspath(&device, syspath);
719 if (k < 0) {
720 if (k != -ENODEV)
721 /* this is necessarily racey, so ignore missing devices */
722 r = k;
723
724 continue;
725 }
726
727 k = test_matches(enumerator, device, /* ignore_parent_match = */ false);
728 if (k <= 0) {
729 if (k < 0)
730 r = k;
731 continue;
732 }
733
734 k = device_enumerator_add_device(enumerator, device);
735 if (k < 0)
736 r = k;
737
738 /* Also include all potentially matching parent devices in the enumeration. These are things
739 * like root busses — e.g. /sys/devices/pci0000:00/ or /sys/devices/pnp0/, which ar not
740 * linked from /sys/class/ or /sys/bus/, hence pick them up explicitly here. */
741 k = enumerator_add_parent_devices(enumerator, device, /* ignore_parent_match = */ false);
742 if (k < 0)
743 r = k;
744 }
745
746 return r;
747 }
748
749 static int enumerator_scan_dir(
750 sd_device_enumerator *enumerator,
751 const char *basedir,
752 const char *subdir,
753 const char *subsystem) {
754
755 _cleanup_closedir_ DIR *dir = NULL;
756 char *path;
757 int r = 0;
758
759 path = strjoina("/sys/", basedir);
760
761 dir = opendir(path);
762 if (!dir)
763 return -errno;
764
765 log_debug("sd-device-enumerator: Scanning %s", path);
766
767 FOREACH_DIRENT_ALL(de, dir, return -errno) {
768 int k;
769
770 if (!relevant_sysfs_subdir(de))
771 continue;
772
773 if (!match_subsystem(enumerator, subsystem ? : de->d_name))
774 continue;
775
776 k = enumerator_scan_dir_and_add_devices(enumerator, basedir, de->d_name, subdir);
777 if (k < 0)
778 r = k;
779 }
780
781 return r;
782 }
783
784 static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
785 _cleanup_closedir_ DIR *dir = NULL;
786 char *path;
787 int r = 0;
788
789 assert(enumerator);
790 assert(tag);
791
792 path = strjoina("/run/udev/tags/", tag);
793
794 dir = opendir(path);
795 if (!dir) {
796 if (errno != ENOENT)
797 return log_debug_errno(errno, "sd-device-enumerator: Failed to open tags directory %s: %m", path);
798 return 0;
799 }
800
801 /* TODO: filter away subsystems? */
802
803 FOREACH_DIRENT_ALL(de, dir, return -errno) {
804 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
805 const char *subsystem, *sysname;
806 int k;
807
808 if (de->d_name[0] == '.')
809 continue;
810
811 k = sd_device_new_from_device_id(&device, de->d_name);
812 if (k < 0) {
813 if (k != -ENODEV)
814 /* this is necessarily racy, so ignore missing devices */
815 r = k;
816
817 continue;
818 }
819
820 k = sd_device_get_subsystem(device, &subsystem);
821 if (k < 0) {
822 if (k != -ENOENT)
823 /* this is necessarily racy, so ignore missing devices */
824 r = k;
825 continue;
826 }
827
828 if (!match_subsystem(enumerator, subsystem))
829 continue;
830
831 k = sd_device_get_sysname(device, &sysname);
832 if (k < 0) {
833 r = k;
834 continue;
835 }
836
837 if (!match_sysname(enumerator, sysname))
838 continue;
839
840 if (!device_match_parent(device, enumerator->match_parent, NULL))
841 continue;
842
843 if (!match_property(enumerator, device))
844 continue;
845
846 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
847 continue;
848
849 k = device_enumerator_add_device(enumerator, device);
850 if (k < 0) {
851 r = k;
852 continue;
853 }
854 }
855
856 return r;
857 }
858
859 static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
860 const char *tag;
861 int r = 0;
862
863 assert(enumerator);
864
865 SET_FOREACH(tag, enumerator->match_tag) {
866 int k;
867
868 k = enumerator_scan_devices_tag(enumerator, tag);
869 if (k < 0)
870 r = k;
871 }
872
873 return r;
874 }
875
876 static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
877 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
878 const char *subsystem, *sysname;
879 int r;
880
881 r = sd_device_new_from_syspath(&device, path);
882 if (r == -ENODEV)
883 /* this is necessarily racy, so ignore missing devices */
884 return 0;
885 else if (r < 0)
886 return r;
887
888 r = sd_device_get_subsystem(device, &subsystem);
889 if (r == -ENOENT)
890 return 0;
891 if (r < 0)
892 return r;
893
894 if (!match_subsystem(enumerator, subsystem))
895 return 0;
896
897 r = sd_device_get_sysname(device, &sysname);
898 if (r < 0)
899 return r;
900
901 if (!match_sysname(enumerator, sysname))
902 return 0;
903
904 if (!match_property(enumerator, device))
905 return 0;
906
907 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
908 return 0;
909
910 r = device_enumerator_add_device(enumerator, device);
911 if (r < 0)
912 return r;
913
914 return 1;
915 }
916
917 static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
918 _cleanup_closedir_ DIR *dir = NULL;
919 int r = 0;
920
921 dir = opendir(path);
922 if (!dir)
923 return log_debug_errno(errno, "sd-device-enumerator: Failed to open parent directory %s: %m", path);
924
925 FOREACH_DIRENT_ALL(de, dir, return -errno) {
926 _cleanup_free_ char *child = NULL;
927 int k;
928
929 if (de->d_name[0] == '.')
930 continue;
931
932 if (de->d_type != DT_DIR)
933 continue;
934
935 child = path_join(path, de->d_name);
936 if (!child)
937 return -ENOMEM;
938
939 k = parent_add_child(enumerator, child);
940 if (k < 0)
941 r = k;
942
943 if (maxdepth > 0)
944 parent_crawl_children(enumerator, child, maxdepth - 1);
945 else
946 log_debug("sd-device-enumerator: Max depth reached, %s: ignoring devices", child);
947 }
948
949 return r;
950 }
951
952 static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
953 const char *path;
954 int r = 0, k;
955
956 SET_FOREACH(path, enumerator->match_parent) {
957 k = parent_add_child(enumerator, path);
958 if (k < 0)
959 r = k;
960
961 k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
962 if (k < 0)
963 r = k;
964 }
965
966 return r;
967 }
968
969 static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
970 int k, r = 0;
971
972 log_debug("sd-device-enumerator: Scan all dirs");
973
974 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
975 if (k < 0)
976 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
977
978 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
979 if (k < 0)
980 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
981
982 return r;
983 }
984
985 int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
986 int r = 0, k;
987
988 assert(enumerator);
989
990 if (enumerator->scan_uptodate &&
991 enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
992 return 0;
993
994 device_enumerator_unref_devices(enumerator);
995
996 if (!set_isempty(enumerator->match_tag)) {
997 k = enumerator_scan_devices_tags(enumerator);
998 if (k < 0)
999 r = k;
1000 } else if (enumerator->match_parent) {
1001 k = enumerator_scan_devices_children(enumerator);
1002 if (k < 0)
1003 r = k;
1004 } else {
1005 k = enumerator_scan_devices_all(enumerator);
1006 if (k < 0)
1007 r = k;
1008 }
1009
1010 enumerator->scan_uptodate = true;
1011 enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
1012
1013 return r;
1014 }
1015
1016 _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
1017 assert_return(enumerator, NULL);
1018
1019 if (device_enumerator_scan_devices(enumerator) < 0)
1020 return NULL;
1021
1022 if (enumerator_sort_devices(enumerator) < 0)
1023 return NULL;
1024
1025 enumerator->current_device_index = 0;
1026
1027 if (enumerator->n_devices == 0)
1028 return NULL;
1029
1030 return enumerator->devices[0];
1031 }
1032
1033 _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
1034 assert_return(enumerator, NULL);
1035
1036 if (!enumerator->scan_uptodate ||
1037 !enumerator->sorted ||
1038 enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
1039 enumerator->current_device_index + 1 >= enumerator->n_devices)
1040 return NULL;
1041
1042 return enumerator->devices[++enumerator->current_device_index];
1043 }
1044
1045 int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
1046 int r = 0, k;
1047
1048 assert(enumerator);
1049
1050 if (enumerator->scan_uptodate &&
1051 enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
1052 return 0;
1053
1054 device_enumerator_unref_devices(enumerator);
1055
1056 /* modules */
1057 if (match_subsystem(enumerator, "module")) {
1058 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
1059 if (k < 0)
1060 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
1061 }
1062
1063 /* subsystems (only buses support coldplug) */
1064 if (match_subsystem(enumerator, "subsystem")) {
1065 k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
1066 if (k < 0)
1067 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
1068 }
1069
1070 /* subsystem drivers */
1071 if (match_subsystem(enumerator, "drivers")) {
1072 k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
1073 if (k < 0)
1074 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
1075 }
1076
1077 enumerator->scan_uptodate = true;
1078 enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
1079
1080 return r;
1081 }
1082
1083 _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
1084 assert_return(enumerator, NULL);
1085
1086 if (device_enumerator_scan_subsystems(enumerator) < 0)
1087 return NULL;
1088
1089 if (enumerator_sort_devices(enumerator) < 0)
1090 return NULL;
1091
1092 enumerator->current_device_index = 0;
1093
1094 if (enumerator->n_devices == 0)
1095 return NULL;
1096
1097 return enumerator->devices[0];
1098 }
1099
1100 _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
1101 assert_return(enumerator, NULL);
1102
1103 if (!enumerator->scan_uptodate ||
1104 !enumerator->sorted ||
1105 enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
1106 enumerator->current_device_index + 1 >= enumerator->n_devices)
1107 return NULL;
1108
1109 return enumerator->devices[++enumerator->current_device_index];
1110 }
1111
1112 int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator) {
1113 int r;
1114
1115 assert(enumerator);
1116
1117 if (enumerator->scan_uptodate &&
1118 enumerator->type == DEVICE_ENUMERATION_TYPE_ALL)
1119 return 0;
1120
1121 device_enumerator_unref_devices(enumerator);
1122
1123 if (!set_isempty(enumerator->match_tag))
1124 r = enumerator_scan_devices_tags(enumerator);
1125 else if (enumerator->match_parent)
1126 r = enumerator_scan_devices_children(enumerator);
1127 else {
1128 int k;
1129
1130 r = enumerator_scan_devices_all(enumerator);
1131
1132 if (match_subsystem(enumerator, "module")) {
1133 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
1134 if (k < 0)
1135 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
1136 }
1137 if (match_subsystem(enumerator, "subsystem")) {
1138 k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
1139 if (k < 0)
1140 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
1141 }
1142
1143 if (match_subsystem(enumerator, "drivers")) {
1144 k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
1145 if (k < 0)
1146 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
1147 }
1148 }
1149
1150 enumerator->scan_uptodate = true;
1151 enumerator->type = DEVICE_ENUMERATION_TYPE_ALL;
1152
1153 return r;
1154 }
1155
1156 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
1157 assert_return(enumerator, NULL);
1158
1159 if (!enumerator->scan_uptodate)
1160 return NULL;
1161
1162 if (enumerator_sort_devices(enumerator) < 0)
1163 return NULL;
1164
1165 enumerator->current_device_index = 0;
1166
1167 if (enumerator->n_devices == 0)
1168 return NULL;
1169
1170 return enumerator->devices[0];
1171 }
1172
1173 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
1174 assert_return(enumerator, NULL);
1175
1176 if (!enumerator->scan_uptodate ||
1177 !enumerator->sorted ||
1178 enumerator->current_device_index + 1 >= enumerator->n_devices)
1179 return NULL;
1180
1181 return enumerator->devices[++enumerator->current_device_index];
1182 }
1183
1184 sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
1185 assert(enumerator);
1186 assert(ret_n_devices);
1187
1188 if (!enumerator->scan_uptodate)
1189 return NULL;
1190
1191 if (enumerator_sort_devices(enumerator) < 0)
1192 return NULL;
1193
1194 *ret_n_devices = enumerator->n_devices;
1195 return enumerator->devices;
1196 }