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