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