]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/device-enumerator.c
sd-boot+bootctl: invert order of entries w/o sort-key
[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_MAX,
24 _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
25 } DeviceEnumerationType;
26
27 struct sd_device_enumerator {
28 unsigned n_ref;
29
30 DeviceEnumerationType type;
31 sd_device **devices;
32 size_t n_devices, current_device_index;
33 bool scan_uptodate;
34
35 Set *match_subsystem;
36 Set *nomatch_subsystem;
37 Hashmap *match_sysattr;
38 Hashmap *nomatch_sysattr;
39 Hashmap *match_property;
40 Set *match_sysname;
41 Set *match_tag;
42 Set *match_parent;
43 bool match_allow_uninitialized;
44 };
45
46 _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
47 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerator = NULL;
48
49 assert(ret);
50
51 enumerator = new(sd_device_enumerator, 1);
52 if (!enumerator)
53 return -ENOMEM;
54
55 *enumerator = (sd_device_enumerator) {
56 .n_ref = 1,
57 .type = _DEVICE_ENUMERATION_TYPE_INVALID,
58 };
59
60 *ret = TAKE_PTR(enumerator);
61
62 return 0;
63 }
64
65 static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
66 assert(enumerator);
67
68 for (size_t i = 0; i < enumerator->n_devices; i++)
69 sd_device_unref(enumerator->devices[i]);
70
71 free(enumerator->devices);
72 set_free(enumerator->match_subsystem);
73 set_free(enumerator->nomatch_subsystem);
74 hashmap_free(enumerator->match_sysattr);
75 hashmap_free(enumerator->nomatch_sysattr);
76 hashmap_free(enumerator->match_property);
77 set_free(enumerator->match_sysname);
78 set_free(enumerator->match_tag);
79 set_free(enumerator->match_parent);
80
81 return mfree(enumerator);
82 }
83
84 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free);
85
86 _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
87 Set **set;
88 int r;
89
90 assert_return(enumerator, -EINVAL);
91 assert_return(subsystem, -EINVAL);
92
93 if (match)
94 set = &enumerator->match_subsystem;
95 else
96 set = &enumerator->nomatch_subsystem;
97
98 r = set_put_strdup(set, subsystem);
99 if (r <= 0)
100 return r;
101
102 enumerator->scan_uptodate = false;
103
104 return 1;
105 }
106
107 _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match) {
108 Hashmap **hashmap;
109 int r;
110
111 assert_return(enumerator, -EINVAL);
112 assert_return(sysattr, -EINVAL);
113
114 if (match)
115 hashmap = &enumerator->match_sysattr;
116 else
117 hashmap = &enumerator->nomatch_sysattr;
118
119 /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
120 * multiple times with the same sysattr but different value. */
121 r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
122 if (r <= 0)
123 return r;
124
125 enumerator->scan_uptodate = false;
126
127 return 1;
128 }
129
130 _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value) {
131 int r;
132
133 assert_return(enumerator, -EINVAL);
134 assert_return(property, -EINVAL);
135
136 /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
137 * multiple times with the same property but different value. */
138 r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
139 if (r <= 0)
140 return r;
141
142 enumerator->scan_uptodate = false;
143
144 return 1;
145 }
146
147 _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
148 int r;
149
150 assert_return(enumerator, -EINVAL);
151 assert_return(sysname, -EINVAL);
152
153 r = set_put_strdup(&enumerator->match_sysname, sysname);
154 if (r <= 0)
155 return r;
156
157 enumerator->scan_uptodate = false;
158
159 return 1;
160 }
161
162 _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
163 int r;
164
165 assert_return(enumerator, -EINVAL);
166 assert_return(tag, -EINVAL);
167
168 r = set_put_strdup(&enumerator->match_tag, tag);
169 if (r <= 0)
170 return r;
171
172 enumerator->scan_uptodate = false;
173
174 return 1;
175 }
176
177 int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
178 const char *path;
179 int r;
180
181 assert(enumerator);
182 assert(parent);
183
184 r = sd_device_get_syspath(parent, &path);
185 if (r < 0)
186 return r;
187
188 r = set_put_strdup(&enumerator->match_parent, path);
189 if (r <= 0)
190 return r;
191
192 enumerator->scan_uptodate = false;
193
194 return 1;
195 }
196
197 _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
198 assert_return(enumerator, -EINVAL);
199 assert_return(parent, -EINVAL);
200
201 set_clear(enumerator->match_parent);
202
203 return device_enumerator_add_match_parent_incremental(enumerator, parent);
204 }
205
206 _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
207 assert_return(enumerator, -EINVAL);
208
209 enumerator->match_allow_uninitialized = true;
210
211 enumerator->scan_uptodate = false;
212
213 return 1;
214 }
215
216 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
217 assert_return(enumerator, -EINVAL);
218
219 enumerator->match_allow_uninitialized = false;
220
221 enumerator->scan_uptodate = false;
222
223 return 1;
224 }
225
226 static int device_compare(sd_device * const *_a, sd_device * const *_b) {
227 sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b;
228 const char *devpath_a, *devpath_b, *sound_a;
229 bool delay_a, delay_b;
230 int r;
231
232 assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
233 assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
234
235 sound_a = strstr(devpath_a, "/sound/card");
236 if (sound_a) {
237 /* For sound cards the control device must be enumerated last to
238 * make sure it's the final device node that gets ACLs applied.
239 * Applications rely on this fact and use ACL changes on the
240 * control node as an indicator that the ACL change of the
241 * entire sound card completed. The kernel makes this guarantee
242 * when creating those devices, and hence we should too when
243 * enumerating them. */
244 sound_a += STRLEN("/sound/card");
245 sound_a = strchr(sound_a, '/');
246
247 if (sound_a) {
248 unsigned prefix_len;
249
250 prefix_len = sound_a - devpath_a;
251
252 if (strneq(devpath_a, devpath_b, prefix_len)) {
253 const char *sound_b;
254
255 sound_b = devpath_b + prefix_len;
256
257 r = CMP(!!startswith(sound_a, "/controlC"),
258 !!startswith(sound_b, "/controlC"));
259 if (r != 0)
260 return r;
261 }
262 }
263 }
264
265 /* md and dm devices are enumerated after all other devices */
266 delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-");
267 delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-");
268 r = CMP(delay_a, delay_b);
269 if (r != 0)
270 return r;
271
272 return strcmp(devpath_a, devpath_b);
273 }
274
275 int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
276 assert_return(enumerator, -EINVAL);
277 assert_return(device, -EINVAL);
278
279 if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_devices + 1))
280 return -ENOMEM;
281
282 enumerator->devices[enumerator->n_devices++] = sd_device_ref(device);
283
284 return 0;
285 }
286
287 static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
288 const char *property;
289 const char *value;
290
291 assert(enumerator);
292 assert(device);
293
294 if (hashmap_isempty(enumerator->match_property))
295 return true;
296
297 HASHMAP_FOREACH_KEY(value, property, enumerator->match_property) {
298 const char *property_dev, *value_dev;
299
300 FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
301 if (fnmatch(property, property_dev, 0) != 0)
302 continue;
303
304 if (!value && !value_dev)
305 return true;
306
307 if (!value || !value_dev)
308 continue;
309
310 if (fnmatch(value, value_dev, 0) == 0)
311 return true;
312 }
313 }
314
315 return false;
316 }
317
318 static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
319 const char *tag;
320
321 assert(enumerator);
322 assert(device);
323
324 SET_FOREACH(tag, enumerator->match_tag)
325 if (!sd_device_has_tag(device, tag))
326 return false;
327
328 return true;
329 }
330
331 static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
332 const char *sysname_match;
333
334 assert(enumerator);
335 assert(sysname);
336
337 if (set_isempty(enumerator->match_sysname))
338 return true;
339
340 SET_FOREACH(sysname_match, enumerator->match_sysname)
341 if (fnmatch(sysname_match, sysname, 0) == 0)
342 return true;
343
344 return false;
345 }
346
347 static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
348 _cleanup_closedir_ DIR *dir = NULL;
349 char *path;
350 int r = 0;
351
352 assert(enumerator);
353 assert(basedir);
354
355 path = strjoina("/sys/", basedir, "/");
356
357 if (subdir1)
358 path = strjoina(path, subdir1, "/");
359
360 if (subdir2)
361 path = strjoina(path, subdir2, "/");
362
363 dir = opendir(path);
364 if (!dir)
365 /* this is necessarily racey, so ignore missing directories */
366 return (errno == ENOENT && (subdir1 || subdir2)) ? 0 : -errno;
367
368 FOREACH_DIRENT_ALL(de, dir, return -errno) {
369 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
370 char syspath[strlen(path) + 1 + strlen(de->d_name) + 1];
371 int initialized, k;
372
373 if (de->d_name[0] == '.')
374 continue;
375
376 if (!match_sysname(enumerator, de->d_name))
377 continue;
378
379 (void) sprintf(syspath, "%s%s", path, de->d_name);
380
381 k = sd_device_new_from_syspath(&device, syspath);
382 if (k < 0) {
383 if (k != -ENODEV)
384 /* this is necessarily racey, so ignore missing devices */
385 r = k;
386
387 continue;
388 }
389
390 initialized = sd_device_get_is_initialized(device);
391 if (initialized < 0) {
392 if (initialized != -ENOENT)
393 /* this is necessarily racey, so ignore missing devices */
394 r = initialized;
395
396 continue;
397 }
398
399 /*
400 * All devices with a device node or network interfaces
401 * possibly need udev to adjust the device node permission
402 * or context, or rename the interface before it can be
403 * reliably used from other processes.
404 *
405 * For now, we can only check these types of devices, we
406 * might not store a database, and have no way to find out
407 * for all other types of devices.
408 */
409 if (!enumerator->match_allow_uninitialized &&
410 !initialized &&
411 (sd_device_get_devnum(device, NULL) >= 0 ||
412 sd_device_get_ifindex(device, NULL) >= 0))
413 continue;
414
415 if (!device_match_parent(device, enumerator->match_parent, NULL))
416 continue;
417
418 if (!match_tag(enumerator, device))
419 continue;
420
421 if (!match_property(enumerator, device))
422 continue;
423
424 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
425 continue;
426
427 k = device_enumerator_add_device(enumerator, device);
428 if (k < 0)
429 r = k;
430 }
431
432 return r;
433 }
434
435 static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
436 const char *subsystem_match;
437
438 assert(enumerator);
439
440 if (!subsystem)
441 return false;
442
443 SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem)
444 if (fnmatch(subsystem_match, subsystem, 0) == 0)
445 return false;
446
447 if (set_isempty(enumerator->match_subsystem))
448 return true;
449
450 SET_FOREACH(subsystem_match, enumerator->match_subsystem)
451 if (fnmatch(subsystem_match, subsystem, 0) == 0)
452 return true;
453
454 return false;
455 }
456
457 static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
458 _cleanup_closedir_ DIR *dir = NULL;
459 char *path;
460 int r = 0;
461
462 path = strjoina("/sys/", basedir);
463
464 dir = opendir(path);
465 if (!dir)
466 return -errno;
467
468 log_debug("sd-device-enumerator: Scanning %s", path);
469
470 FOREACH_DIRENT_ALL(de, dir, return -errno) {
471 int k;
472
473 if (de->d_name[0] == '.')
474 continue;
475
476 if (!match_subsystem(enumerator, subsystem ? : de->d_name))
477 continue;
478
479 k = enumerator_scan_dir_and_add_devices(enumerator, basedir, de->d_name, subdir);
480 if (k < 0)
481 r = k;
482 }
483
484 return r;
485 }
486
487 static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
488 _cleanup_closedir_ DIR *dir = NULL;
489 char *path;
490 int r = 0;
491
492 assert(enumerator);
493 assert(tag);
494
495 path = strjoina("/run/udev/tags/", tag);
496
497 dir = opendir(path);
498 if (!dir) {
499 if (errno != ENOENT)
500 return log_debug_errno(errno, "sd-device-enumerator: Failed to open tags directory %s: %m", path);
501 return 0;
502 }
503
504 /* TODO: filter away subsystems? */
505
506 FOREACH_DIRENT_ALL(de, dir, return -errno) {
507 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
508 const char *subsystem, *sysname;
509 int k;
510
511 if (de->d_name[0] == '.')
512 continue;
513
514 k = sd_device_new_from_device_id(&device, de->d_name);
515 if (k < 0) {
516 if (k != -ENODEV)
517 /* this is necessarily racy, so ignore missing devices */
518 r = k;
519
520 continue;
521 }
522
523 k = sd_device_get_subsystem(device, &subsystem);
524 if (k < 0) {
525 if (k != -ENOENT)
526 /* this is necessarily racy, so ignore missing devices */
527 r = k;
528 continue;
529 }
530
531 if (!match_subsystem(enumerator, subsystem))
532 continue;
533
534 k = sd_device_get_sysname(device, &sysname);
535 if (k < 0) {
536 r = k;
537 continue;
538 }
539
540 if (!match_sysname(enumerator, sysname))
541 continue;
542
543 if (!device_match_parent(device, enumerator->match_parent, NULL))
544 continue;
545
546 if (!match_property(enumerator, device))
547 continue;
548
549 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
550 continue;
551
552 k = device_enumerator_add_device(enumerator, device);
553 if (k < 0) {
554 r = k;
555 continue;
556 }
557 }
558
559 return r;
560 }
561
562 static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
563 const char *tag;
564 int r = 0;
565
566 assert(enumerator);
567
568 SET_FOREACH(tag, enumerator->match_tag) {
569 int k;
570
571 k = enumerator_scan_devices_tag(enumerator, tag);
572 if (k < 0)
573 r = k;
574 }
575
576 return r;
577 }
578
579 static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
580 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
581 const char *subsystem, *sysname;
582 int r;
583
584 r = sd_device_new_from_syspath(&device, path);
585 if (r == -ENODEV)
586 /* this is necessarily racy, so ignore missing devices */
587 return 0;
588 else if (r < 0)
589 return r;
590
591 r = sd_device_get_subsystem(device, &subsystem);
592 if (r == -ENOENT)
593 return 0;
594 if (r < 0)
595 return r;
596
597 if (!match_subsystem(enumerator, subsystem))
598 return 0;
599
600 r = sd_device_get_sysname(device, &sysname);
601 if (r < 0)
602 return r;
603
604 if (!match_sysname(enumerator, sysname))
605 return 0;
606
607 if (!match_property(enumerator, device))
608 return 0;
609
610 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
611 return 0;
612
613 r = device_enumerator_add_device(enumerator, device);
614 if (r < 0)
615 return r;
616
617 return 1;
618 }
619
620 static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
621 _cleanup_closedir_ DIR *dir = NULL;
622 int r = 0;
623
624 dir = opendir(path);
625 if (!dir)
626 return log_debug_errno(errno, "sd-device-enumerator: Failed to open parent directory %s: %m", path);
627
628 FOREACH_DIRENT_ALL(de, dir, return -errno) {
629 _cleanup_free_ char *child = NULL;
630 int k;
631
632 if (de->d_name[0] == '.')
633 continue;
634
635 if (de->d_type != DT_DIR)
636 continue;
637
638 child = path_join(path, de->d_name);
639 if (!child)
640 return -ENOMEM;
641
642 k = parent_add_child(enumerator, child);
643 if (k < 0)
644 r = k;
645
646 if (maxdepth > 0)
647 parent_crawl_children(enumerator, child, maxdepth - 1);
648 else
649 log_debug("sd-device-enumerator: Max depth reached, %s: ignoring devices", child);
650 }
651
652 return r;
653 }
654
655 static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
656 const char *path;
657 int r = 0, k;
658
659 SET_FOREACH(path, enumerator->match_parent) {
660 k = parent_add_child(enumerator, path);
661 if (k < 0)
662 r = k;
663
664 k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
665 if (k < 0)
666 r = k;
667 }
668
669 return r;
670 }
671
672 static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
673 int r = 0;
674
675 log_debug("sd-device-enumerator: Scan all dirs");
676
677 if (access("/sys/subsystem", F_OK) >= 0) {
678 /* we have /subsystem/, forget all the old stuff */
679 r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
680 if (r < 0)
681 return log_debug_errno(r, "sd-device-enumerator: Failed to scan /sys/subsystem: %m");
682 } else {
683 int k;
684
685 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
686 if (k < 0)
687 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
688
689 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
690 if (k < 0)
691 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
692 }
693
694 return r;
695 }
696
697 static void device_enumerator_dedup_devices(sd_device_enumerator *enumerator) {
698 sd_device **a, **b, **end;
699
700 assert(enumerator);
701
702 if (enumerator->n_devices <= 1)
703 return;
704
705 a = enumerator->devices + 1;
706 b = enumerator->devices;
707 end = enumerator->devices + enumerator->n_devices;
708
709 for (; a < end; a++) {
710 const char *devpath_a, *devpath_b;
711
712 assert_se(sd_device_get_devpath(*a, &devpath_a) >= 0);
713 assert_se(sd_device_get_devpath(*b, &devpath_b) >= 0);
714
715 if (path_equal(devpath_a, devpath_b))
716 sd_device_unref(*a);
717 else
718 *(++b) = *a;
719 }
720
721 enumerator->n_devices = b - enumerator->devices + 1;
722 }
723
724 int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
725 int r = 0, k;
726
727 assert(enumerator);
728
729 if (enumerator->scan_uptodate &&
730 enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
731 return 0;
732
733 for (size_t i = 0; i < enumerator->n_devices; i++)
734 sd_device_unref(enumerator->devices[i]);
735
736 enumerator->n_devices = 0;
737
738 if (!set_isempty(enumerator->match_tag)) {
739 k = enumerator_scan_devices_tags(enumerator);
740 if (k < 0)
741 r = k;
742 } else if (enumerator->match_parent) {
743 k = enumerator_scan_devices_children(enumerator);
744 if (k < 0)
745 r = k;
746 } else {
747 k = enumerator_scan_devices_all(enumerator);
748 if (k < 0)
749 r = k;
750 }
751
752 typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
753 device_enumerator_dedup_devices(enumerator);
754
755 enumerator->scan_uptodate = true;
756 enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
757
758 return r;
759 }
760
761 _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
762 int r;
763
764 assert_return(enumerator, NULL);
765
766 r = device_enumerator_scan_devices(enumerator);
767 if (r < 0)
768 return NULL;
769
770 enumerator->current_device_index = 0;
771
772 if (enumerator->n_devices == 0)
773 return NULL;
774
775 return enumerator->devices[0];
776 }
777
778 _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
779 assert_return(enumerator, NULL);
780
781 if (!enumerator->scan_uptodate ||
782 enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
783 enumerator->current_device_index + 1 >= enumerator->n_devices)
784 return NULL;
785
786 return enumerator->devices[++enumerator->current_device_index];
787 }
788
789 int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
790 const char *subsysdir;
791 int r = 0, k;
792
793 assert(enumerator);
794
795 if (enumerator->scan_uptodate &&
796 enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
797 return 0;
798
799 for (size_t i = 0; i < enumerator->n_devices; i++)
800 sd_device_unref(enumerator->devices[i]);
801
802 enumerator->n_devices = 0;
803
804 /* modules */
805 if (match_subsystem(enumerator, "module")) {
806 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
807 if (k < 0)
808 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
809 }
810
811 if (access("/sys/subsystem", F_OK) >= 0)
812 subsysdir = "subsystem";
813 else
814 subsysdir = "bus";
815
816 /* subsystems (only buses support coldplug) */
817 if (match_subsystem(enumerator, "subsystem")) {
818 k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
819 if (k < 0)
820 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
821 }
822
823 /* subsystem drivers */
824 if (match_subsystem(enumerator, "drivers")) {
825 k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
826 if (k < 0)
827 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
828 }
829
830 typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
831 device_enumerator_dedup_devices(enumerator);
832
833 enumerator->scan_uptodate = true;
834 enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
835
836 return r;
837 }
838
839 _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
840 int r;
841
842 assert_return(enumerator, NULL);
843
844 r = device_enumerator_scan_subsystems(enumerator);
845 if (r < 0)
846 return NULL;
847
848 enumerator->current_device_index = 0;
849
850 if (enumerator->n_devices == 0)
851 return NULL;
852
853 return enumerator->devices[0];
854 }
855
856 _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
857 assert_return(enumerator, NULL);
858
859 if (!enumerator->scan_uptodate ||
860 enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
861 enumerator->current_device_index + 1 >= enumerator->n_devices)
862 return NULL;
863
864 return enumerator->devices[++enumerator->current_device_index];
865 }
866
867 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
868 assert_return(enumerator, NULL);
869
870 if (!enumerator->scan_uptodate)
871 return NULL;
872
873 enumerator->current_device_index = 0;
874
875 if (enumerator->n_devices == 0)
876 return NULL;
877
878 return enumerator->devices[0];
879 }
880
881 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
882 assert_return(enumerator, NULL);
883
884 if (!enumerator->scan_uptodate ||
885 enumerator->current_device_index + 1 >= enumerator->n_devices)
886 return NULL;
887
888 return enumerator->devices[++enumerator->current_device_index];
889 }
890
891 sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
892 assert(enumerator);
893 assert(ret_n_devices);
894
895 if (!enumerator->scan_uptodate)
896 return NULL;
897
898 *ret_n_devices = enumerator->n_devices;
899 return enumerator->devices;
900 }