]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/device-enumerator.c
Merge pull request #22791 from keszybz/bootctl-invert-order
[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 enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
551 _cleanup_closedir_ DIR *dir = NULL;
552 char *path;
553 int k, r = 0;
554
555 assert(enumerator);
556 assert(basedir);
557
558 path = strjoina("/sys/", basedir, "/");
559
560 if (subdir1)
561 path = strjoina(path, subdir1, "/");
562
563 if (subdir2)
564 path = strjoina(path, subdir2, "/");
565
566 dir = opendir(path);
567 if (!dir)
568 /* this is necessarily racey, so ignore missing directories */
569 return (errno == ENOENT && (subdir1 || subdir2)) ? 0 : -errno;
570
571 FOREACH_DIRENT_ALL(de, dir, return -errno) {
572 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
573 char syspath[strlen(path) + 1 + strlen(de->d_name) + 1];
574
575 if (de->d_name[0] == '.')
576 continue;
577
578 if (!match_sysname(enumerator, de->d_name))
579 continue;
580
581 (void) sprintf(syspath, "%s%s", path, de->d_name);
582
583 k = sd_device_new_from_syspath(&device, syspath);
584 if (k < 0) {
585 if (k != -ENODEV)
586 /* this is necessarily racey, so ignore missing devices */
587 r = k;
588
589 continue;
590 }
591
592 k = match_initialized(enumerator, device);
593 if (k <= 0) {
594 if (k < 0)
595 r = k;
596 continue;
597 }
598
599 if (!device_match_parent(device, enumerator->match_parent, NULL))
600 continue;
601
602 if (!match_tag(enumerator, device))
603 continue;
604
605 if (!match_property(enumerator, device))
606 continue;
607
608 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
609 continue;
610
611 k = device_enumerator_add_device(enumerator, device);
612 if (k < 0)
613 r = k;
614 }
615
616 return r;
617 }
618
619 static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
620 const char *subsystem_match;
621
622 assert(enumerator);
623
624 if (!subsystem)
625 return false;
626
627 SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem)
628 if (fnmatch(subsystem_match, subsystem, 0) == 0)
629 return false;
630
631 if (set_isempty(enumerator->match_subsystem))
632 return true;
633
634 SET_FOREACH(subsystem_match, enumerator->match_subsystem)
635 if (fnmatch(subsystem_match, subsystem, 0) == 0)
636 return true;
637
638 return false;
639 }
640
641 static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
642 _cleanup_closedir_ DIR *dir = NULL;
643 char *path;
644 int r = 0;
645
646 path = strjoina("/sys/", basedir);
647
648 dir = opendir(path);
649 if (!dir)
650 return -errno;
651
652 log_debug("sd-device-enumerator: Scanning %s", path);
653
654 FOREACH_DIRENT_ALL(de, dir, return -errno) {
655 int k;
656
657 if (de->d_name[0] == '.')
658 continue;
659
660 if (!match_subsystem(enumerator, subsystem ? : de->d_name))
661 continue;
662
663 k = enumerator_scan_dir_and_add_devices(enumerator, basedir, de->d_name, subdir);
664 if (k < 0)
665 r = k;
666 }
667
668 return r;
669 }
670
671 static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
672 _cleanup_closedir_ DIR *dir = NULL;
673 char *path;
674 int r = 0;
675
676 assert(enumerator);
677 assert(tag);
678
679 path = strjoina("/run/udev/tags/", tag);
680
681 dir = opendir(path);
682 if (!dir) {
683 if (errno != ENOENT)
684 return log_debug_errno(errno, "sd-device-enumerator: Failed to open tags directory %s: %m", path);
685 return 0;
686 }
687
688 /* TODO: filter away subsystems? */
689
690 FOREACH_DIRENT_ALL(de, dir, return -errno) {
691 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
692 const char *subsystem, *sysname;
693 int k;
694
695 if (de->d_name[0] == '.')
696 continue;
697
698 k = sd_device_new_from_device_id(&device, de->d_name);
699 if (k < 0) {
700 if (k != -ENODEV)
701 /* this is necessarily racy, so ignore missing devices */
702 r = k;
703
704 continue;
705 }
706
707 k = sd_device_get_subsystem(device, &subsystem);
708 if (k < 0) {
709 if (k != -ENOENT)
710 /* this is necessarily racy, so ignore missing devices */
711 r = k;
712 continue;
713 }
714
715 if (!match_subsystem(enumerator, subsystem))
716 continue;
717
718 k = sd_device_get_sysname(device, &sysname);
719 if (k < 0) {
720 r = k;
721 continue;
722 }
723
724 if (!match_sysname(enumerator, sysname))
725 continue;
726
727 if (!device_match_parent(device, enumerator->match_parent, NULL))
728 continue;
729
730 if (!match_property(enumerator, device))
731 continue;
732
733 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
734 continue;
735
736 k = device_enumerator_add_device(enumerator, device);
737 if (k < 0) {
738 r = k;
739 continue;
740 }
741 }
742
743 return r;
744 }
745
746 static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
747 const char *tag;
748 int r = 0;
749
750 assert(enumerator);
751
752 SET_FOREACH(tag, enumerator->match_tag) {
753 int k;
754
755 k = enumerator_scan_devices_tag(enumerator, tag);
756 if (k < 0)
757 r = k;
758 }
759
760 return r;
761 }
762
763 static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
764 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
765 const char *subsystem, *sysname;
766 int r;
767
768 r = sd_device_new_from_syspath(&device, path);
769 if (r == -ENODEV)
770 /* this is necessarily racy, so ignore missing devices */
771 return 0;
772 else if (r < 0)
773 return r;
774
775 r = sd_device_get_subsystem(device, &subsystem);
776 if (r == -ENOENT)
777 return 0;
778 if (r < 0)
779 return r;
780
781 if (!match_subsystem(enumerator, subsystem))
782 return 0;
783
784 r = sd_device_get_sysname(device, &sysname);
785 if (r < 0)
786 return r;
787
788 if (!match_sysname(enumerator, sysname))
789 return 0;
790
791 if (!match_property(enumerator, device))
792 return 0;
793
794 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
795 return 0;
796
797 r = device_enumerator_add_device(enumerator, device);
798 if (r < 0)
799 return r;
800
801 return 1;
802 }
803
804 static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
805 _cleanup_closedir_ DIR *dir = NULL;
806 int r = 0;
807
808 dir = opendir(path);
809 if (!dir)
810 return log_debug_errno(errno, "sd-device-enumerator: Failed to open parent directory %s: %m", path);
811
812 FOREACH_DIRENT_ALL(de, dir, return -errno) {
813 _cleanup_free_ char *child = NULL;
814 int k;
815
816 if (de->d_name[0] == '.')
817 continue;
818
819 if (de->d_type != DT_DIR)
820 continue;
821
822 child = path_join(path, de->d_name);
823 if (!child)
824 return -ENOMEM;
825
826 k = parent_add_child(enumerator, child);
827 if (k < 0)
828 r = k;
829
830 if (maxdepth > 0)
831 parent_crawl_children(enumerator, child, maxdepth - 1);
832 else
833 log_debug("sd-device-enumerator: Max depth reached, %s: ignoring devices", child);
834 }
835
836 return r;
837 }
838
839 static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
840 const char *path;
841 int r = 0, k;
842
843 SET_FOREACH(path, enumerator->match_parent) {
844 k = parent_add_child(enumerator, path);
845 if (k < 0)
846 r = k;
847
848 k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
849 if (k < 0)
850 r = k;
851 }
852
853 return r;
854 }
855
856 static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
857 int k, r = 0;
858
859 log_debug("sd-device-enumerator: Scan all dirs");
860
861 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
862 if (k < 0)
863 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
864
865 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
866 if (k < 0)
867 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
868
869 return r;
870 }
871
872 int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
873 int r = 0, k;
874
875 assert(enumerator);
876
877 if (enumerator->scan_uptodate &&
878 enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
879 return 0;
880
881 device_enumerator_unref_devices(enumerator);
882
883 if (!set_isempty(enumerator->match_tag)) {
884 k = enumerator_scan_devices_tags(enumerator);
885 if (k < 0)
886 r = k;
887 } else if (enumerator->match_parent) {
888 k = enumerator_scan_devices_children(enumerator);
889 if (k < 0)
890 r = k;
891 } else {
892 k = enumerator_scan_devices_all(enumerator);
893 if (k < 0)
894 r = k;
895 }
896
897 enumerator->scan_uptodate = true;
898 enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
899
900 return r;
901 }
902
903 _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
904 assert_return(enumerator, NULL);
905
906 if (device_enumerator_scan_devices(enumerator) < 0)
907 return NULL;
908
909 if (enumerator_sort_devices(enumerator) < 0)
910 return NULL;
911
912 enumerator->current_device_index = 0;
913
914 if (enumerator->n_devices == 0)
915 return NULL;
916
917 return enumerator->devices[0];
918 }
919
920 _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
921 assert_return(enumerator, NULL);
922
923 if (!enumerator->scan_uptodate ||
924 !enumerator->sorted ||
925 enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
926 enumerator->current_device_index + 1 >= enumerator->n_devices)
927 return NULL;
928
929 return enumerator->devices[++enumerator->current_device_index];
930 }
931
932 int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
933 int r = 0, k;
934
935 assert(enumerator);
936
937 if (enumerator->scan_uptodate &&
938 enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
939 return 0;
940
941 device_enumerator_unref_devices(enumerator);
942
943 /* modules */
944 if (match_subsystem(enumerator, "module")) {
945 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
946 if (k < 0)
947 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
948 }
949
950 /* subsystems (only buses support coldplug) */
951 if (match_subsystem(enumerator, "subsystem")) {
952 k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
953 if (k < 0)
954 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
955 }
956
957 /* subsystem drivers */
958 if (match_subsystem(enumerator, "drivers")) {
959 k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
960 if (k < 0)
961 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
962 }
963
964 enumerator->scan_uptodate = true;
965 enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
966
967 return r;
968 }
969
970 _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
971 assert_return(enumerator, NULL);
972
973 if (device_enumerator_scan_subsystems(enumerator) < 0)
974 return NULL;
975
976 if (enumerator_sort_devices(enumerator) < 0)
977 return NULL;
978
979 enumerator->current_device_index = 0;
980
981 if (enumerator->n_devices == 0)
982 return NULL;
983
984 return enumerator->devices[0];
985 }
986
987 _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
988 assert_return(enumerator, NULL);
989
990 if (!enumerator->scan_uptodate ||
991 !enumerator->sorted ||
992 enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
993 enumerator->current_device_index + 1 >= enumerator->n_devices)
994 return NULL;
995
996 return enumerator->devices[++enumerator->current_device_index];
997 }
998
999 int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator) {
1000 int r = 0, k;
1001
1002 assert(enumerator);
1003
1004 if (enumerator->scan_uptodate &&
1005 enumerator->type == DEVICE_ENUMERATION_TYPE_ALL)
1006 return 0;
1007
1008 device_enumerator_unref_devices(enumerator);
1009
1010 if (!set_isempty(enumerator->match_tag)) {
1011 k = enumerator_scan_devices_tags(enumerator);
1012 if (k < 0)
1013 r = k;
1014 } else if (enumerator->match_parent) {
1015 k = enumerator_scan_devices_children(enumerator);
1016 if (k < 0)
1017 r = k;
1018 } else {
1019 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
1020 if (k < 0)
1021 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
1022
1023 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
1024 if (k < 0)
1025 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
1026
1027 if (match_subsystem(enumerator, "module")) {
1028 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
1029 if (k < 0)
1030 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
1031 }
1032 if (match_subsystem(enumerator, "subsystem")) {
1033 k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
1034 if (k < 0)
1035 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
1036 }
1037
1038 if (match_subsystem(enumerator, "drivers")) {
1039 k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
1040 if (k < 0)
1041 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
1042 }
1043 }
1044
1045 enumerator->scan_uptodate = true;
1046 enumerator->type = DEVICE_ENUMERATION_TYPE_ALL;
1047
1048 return r;
1049 }
1050
1051 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
1052 assert_return(enumerator, NULL);
1053
1054 if (!enumerator->scan_uptodate)
1055 return NULL;
1056
1057 if (enumerator_sort_devices(enumerator) < 0)
1058 return NULL;
1059
1060 enumerator->current_device_index = 0;
1061
1062 if (enumerator->n_devices == 0)
1063 return NULL;
1064
1065 return enumerator->devices[0];
1066 }
1067
1068 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
1069 assert_return(enumerator, NULL);
1070
1071 if (!enumerator->scan_uptodate ||
1072 !enumerator->sorted ||
1073 enumerator->current_device_index + 1 >= enumerator->n_devices)
1074 return NULL;
1075
1076 return enumerator->devices[++enumerator->current_device_index];
1077 }
1078
1079 sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
1080 assert(enumerator);
1081 assert(ret_n_devices);
1082
1083 if (!enumerator->scan_uptodate)
1084 return NULL;
1085
1086 if (enumerator_sort_devices(enumerator) < 0)
1087 return NULL;
1088
1089 *ret_n_devices = enumerator->n_devices;
1090 return enumerator->devices;
1091 }