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