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