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