]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/device-enumerator.c
string-util: add strstrafter()
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-enumerator.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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-filter.h"
11 #include "device-util.h"
12 #include "dirent-util.h"
13 #include "fd-util.h"
14 #include "set.h"
15 #include "sort-util.h"
16 #include "string-util.h"
17 #include "strv.h"
18
19 typedef enum DeviceEnumerationType {
20 DEVICE_ENUMERATION_TYPE_DEVICES,
21 DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
22 DEVICE_ENUMERATION_TYPE_ALL,
23 _DEVICE_ENUMERATION_TYPE_MAX,
24 _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
25 } DeviceEnumerationType;
26
27 struct sd_device_enumerator {
28 unsigned n_ref;
29
30 DeviceEnumerationType type;
31 Hashmap *devices_by_syspath;
32 sd_device **devices;
33 size_t n_devices, current_device_index;
34 bool scan_uptodate;
35 bool sorted;
36
37 char **prioritized_subsystems;
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 *nomatch_sysname;
45 Set *match_tag;
46 Set *match_parent;
47 MatchInitializedType match_initialized;
48 };
49
50 _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
51 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerator = NULL;
52
53 assert(ret);
54
55 enumerator = new(sd_device_enumerator, 1);
56 if (!enumerator)
57 return -ENOMEM;
58
59 *enumerator = (sd_device_enumerator) {
60 .n_ref = 1,
61 .type = _DEVICE_ENUMERATION_TYPE_INVALID,
62 .match_initialized = MATCH_INITIALIZED_COMPAT,
63 };
64
65 *ret = TAKE_PTR(enumerator);
66
67 return 0;
68 }
69
70 static void device_unref_many(sd_device **devices, size_t n) {
71 assert(devices || n == 0);
72
73 for (size_t i = 0; i < n; i++)
74 sd_device_unref(devices[i]);
75 }
76
77 static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) {
78 assert(enumerator);
79
80 hashmap_clear_with_destructor(enumerator->devices_by_syspath, sd_device_unref);
81 device_unref_many(enumerator->devices, enumerator->n_devices);
82 enumerator->devices = mfree(enumerator->devices);
83 enumerator->n_devices = 0;
84 }
85
86 static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
87 assert(enumerator);
88
89 device_enumerator_unref_devices(enumerator);
90
91 hashmap_free(enumerator->devices_by_syspath);
92 strv_free(enumerator->prioritized_subsystems);
93 set_free(enumerator->match_subsystem);
94 set_free(enumerator->nomatch_subsystem);
95 hashmap_free(enumerator->match_sysattr);
96 hashmap_free(enumerator->nomatch_sysattr);
97 hashmap_free(enumerator->match_property);
98 set_free(enumerator->match_sysname);
99 set_free(enumerator->nomatch_sysname);
100 set_free(enumerator->match_tag);
101 set_free(enumerator->match_parent);
102
103 return mfree(enumerator);
104 }
105
106 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free);
107
108 int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
109 int r;
110
111 assert(enumerator);
112 assert(subsystem);
113
114 if (strv_contains(enumerator->prioritized_subsystems, subsystem))
115 return 0;
116
117 r = strv_extend(&enumerator->prioritized_subsystems, subsystem);
118 if (r < 0)
119 return r;
120
121 enumerator->scan_uptodate = false;
122
123 return 1;
124 }
125
126 _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
127 Set **set;
128 int r;
129
130 assert_return(enumerator, -EINVAL);
131 assert_return(subsystem, -EINVAL);
132
133 if (match)
134 set = &enumerator->match_subsystem;
135 else
136 set = &enumerator->nomatch_subsystem;
137
138 r = set_put_strdup(set, subsystem);
139 if (r <= 0)
140 return r;
141
142 enumerator->scan_uptodate = false;
143
144 return 1;
145 }
146
147 _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match) {
148 Hashmap **hashmap;
149 int r;
150
151 assert_return(enumerator, -EINVAL);
152 assert_return(sysattr, -EINVAL);
153
154 if (match)
155 hashmap = &enumerator->match_sysattr;
156 else
157 hashmap = &enumerator->nomatch_sysattr;
158
159 r = update_match_strv(hashmap, sysattr, value, /* clear_on_null = */ true);
160 if (r <= 0)
161 return r;
162
163 enumerator->scan_uptodate = false;
164
165 return 1;
166 }
167
168 _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value) {
169 int r;
170
171 assert_return(enumerator, -EINVAL);
172 assert_return(property, -EINVAL);
173
174 r = update_match_strv(&enumerator->match_property, property, value, /* clear_on_null = */ false);
175 if (r <= 0)
176 return r;
177
178 enumerator->scan_uptodate = false;
179
180 return 1;
181 }
182
183 static int device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname, bool match) {
184 int r;
185
186 assert_return(enumerator, -EINVAL);
187 assert_return(sysname, -EINVAL);
188
189 r = set_put_strdup(match ? &enumerator->match_sysname : &enumerator->nomatch_sysname, sysname);
190 if (r <= 0)
191 return r;
192
193 enumerator->scan_uptodate = false;
194
195 return 1;
196 }
197
198 _public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
199 return device_enumerator_add_match_sysname(enumerator, sysname, true);
200 }
201
202 _public_ int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, const char *sysname) {
203 return device_enumerator_add_match_sysname(enumerator, sysname, false);
204 }
205
206 _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
207 int r;
208
209 assert_return(enumerator, -EINVAL);
210 assert_return(tag, -EINVAL);
211
212 r = set_put_strdup(&enumerator->match_tag, tag);
213 if (r <= 0)
214 return r;
215
216 enumerator->scan_uptodate = false;
217
218 return 1;
219 }
220
221 int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
222 const char *path;
223 int r;
224
225 assert(enumerator);
226 assert(parent);
227
228 r = sd_device_get_syspath(parent, &path);
229 if (r < 0)
230 return r;
231
232 r = set_put_strdup(&enumerator->match_parent, path);
233 if (r <= 0)
234 return r;
235
236 enumerator->scan_uptodate = false;
237
238 return 1;
239 }
240
241 _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
242 assert_return(enumerator, -EINVAL);
243 assert_return(parent, -EINVAL);
244
245 set_clear(enumerator->match_parent);
246
247 return device_enumerator_add_match_parent_incremental(enumerator, parent);
248 }
249
250 _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
251 assert_return(enumerator, -EINVAL);
252
253 enumerator->match_initialized = MATCH_INITIALIZED_ALL;
254
255 enumerator->scan_uptodate = false;
256
257 return 1;
258 }
259
260 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) {
261 assert_return(enumerator, -EINVAL);
262 assert_return(type >= 0 && type < _MATCH_INITIALIZED_MAX, -EINVAL);
263
264 enumerator->match_initialized = type;
265
266 enumerator->scan_uptodate = false;
267
268 return 1;
269 }
270
271 static int sound_device_compare(const char *devpath_a, const char *devpath_b) {
272 const char *sound_a, *sound_b;
273 size_t prefix_len;
274
275 assert(devpath_a);
276 assert(devpath_b);
277
278 /* For sound cards the control device must be enumerated last to make sure it's the final
279 * device node that gets ACLs applied. Applications rely on this fact and use ACL changes on
280 * the control node as an indicator that the ACL change of the entire sound card completed. The
281 * kernel makes this guarantee when creating those devices, and hence we should too when
282 * enumerating them. */
283
284 sound_a = strstrafter(devpath_a, "/sound/card");
285 if (!sound_a)
286 return 0;
287
288 sound_a = strchr(devpath_a, '/');
289 if (!sound_a)
290 return 0;
291
292 prefix_len = sound_a - devpath_a;
293
294 if (!strneq(devpath_a, devpath_b, prefix_len))
295 return 0;
296
297 sound_b = devpath_b + prefix_len;
298
299 return CMP(!!startswith(sound_a, "/controlC"),
300 !!startswith(sound_b, "/controlC"));
301 }
302
303 static bool devpath_is_late_block(const char *devpath) {
304 assert(devpath);
305
306 return strstr(devpath, "/block/md") || strstr(devpath, "/block/dm-");
307 }
308
309 static int device_compare(sd_device * const *a, sd_device * const *b) {
310 const char *devpath_a, *devpath_b;
311 int r;
312
313 assert(a);
314 assert(b);
315 assert(*a);
316 assert(*b);
317
318 assert_se(sd_device_get_devpath(*(sd_device**) a, &devpath_a) >= 0);
319 assert_se(sd_device_get_devpath(*(sd_device**) b, &devpath_b) >= 0);
320
321 r = sound_device_compare(devpath_a, devpath_b);
322 if (r != 0)
323 return r;
324
325 /* md and dm devices are enumerated after all other devices */
326 r = CMP(devpath_is_late_block(devpath_a), devpath_is_late_block(devpath_b));
327 if (r != 0)
328 return r;
329
330 return path_compare(devpath_a, devpath_b);
331 }
332
333 static int enumerator_sort_devices(sd_device_enumerator *enumerator) {
334 size_t n_sorted = 0, n = 0;
335 sd_device **devices;
336 sd_device *device;
337 int r;
338
339 assert(enumerator);
340
341 if (enumerator->sorted)
342 return 0;
343
344 devices = new(sd_device*, hashmap_size(enumerator->devices_by_syspath));
345 if (!devices)
346 return -ENOMEM;
347
348 STRV_FOREACH(prioritized_subsystem, enumerator->prioritized_subsystems) {
349
350 for (;;) {
351 const char *syspath;
352 size_t m = n;
353
354 HASHMAP_FOREACH_KEY(device, syspath, enumerator->devices_by_syspath) {
355 _cleanup_free_ char *p = NULL;
356 const char *subsys;
357
358 if (sd_device_get_subsystem(device, &subsys) < 0)
359 continue;
360
361 if (!streq(subsys, *prioritized_subsystem))
362 continue;
363
364 devices[n++] = sd_device_ref(device);
365
366 for (;;) {
367 _cleanup_free_ char *q = NULL;
368
369 r = path_extract_directory(p ?: syspath, &q);
370 if (r == -EADDRNOTAVAIL)
371 break;
372 if (r < 0)
373 goto failed;
374
375 device = hashmap_get(enumerator->devices_by_syspath, q);
376 if (device)
377 devices[n++] = sd_device_ref(device);
378
379 free_and_replace(p, q);
380 }
381
382 break;
383 }
384
385 /* We cannot remove multiple entries in the loop HASHMAP_FOREACH_KEY() above. */
386 for (size_t i = m; i < n; i++) {
387 r = sd_device_get_syspath(devices[i], &syspath);
388 if (r < 0)
389 goto failed;
390
391 assert_se(hashmap_remove(enumerator->devices_by_syspath, syspath) == devices[i]);
392 sd_device_unref(devices[i]);
393 }
394
395 if (m == n)
396 break;
397 }
398
399 typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
400 n_sorted = n;
401 }
402
403 HASHMAP_FOREACH(device, enumerator->devices_by_syspath)
404 devices[n++] = sd_device_ref(device);
405
406 /* Move all devices back to the hashmap. Otherwise, devices added by
407 * udev_enumerate_add_syspath() -> device_enumerator_add_device() may not be listed. */
408 for (size_t i = 0; i < n_sorted; i++) {
409 const char *syspath;
410
411 r = sd_device_get_syspath(devices[i], &syspath);
412 if (r < 0)
413 goto failed;
414
415 r = hashmap_put(enumerator->devices_by_syspath, syspath, devices[i]);
416 if (r < 0)
417 goto failed;
418 assert(r > 0);
419
420 sd_device_ref(devices[i]);
421 }
422
423 typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
424
425 device_unref_many(enumerator->devices, enumerator->n_devices);
426
427 enumerator->n_devices = n;
428 free_and_replace(enumerator->devices, devices);
429
430 enumerator->sorted = true;
431 return 0;
432
433 failed:
434 device_unref_many(devices, n);
435 free(devices);
436 return r;
437 }
438
439 int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
440 const char *syspath;
441 int r;
442
443 assert_return(enumerator, -EINVAL);
444 assert_return(device, -EINVAL);
445
446 r = sd_device_get_syspath(device, &syspath);
447 if (r < 0)
448 return r;
449
450 r = hashmap_ensure_put(&enumerator->devices_by_syspath, &string_hash_ops, syspath, device);
451 if (IN_SET(r, -EEXIST, 0))
452 return 0;
453 if (r < 0)
454 return r;
455
456 sd_device_ref(device);
457
458 enumerator->sorted = false;
459 return 1;
460 }
461
462 static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
463 const char *property_pattern;
464 char * const *value_patterns;
465
466 assert(enumerator);
467 assert(device);
468
469 /* Unlike device_match_sysattr(), this accepts device that has at least one matching property. */
470
471 if (hashmap_isempty(enumerator->match_property))
472 return true;
473
474 HASHMAP_FOREACH_KEY(value_patterns, property_pattern, enumerator->match_property) {
475 const char *property, *value;
476
477 FOREACH_DEVICE_PROPERTY(device, property, value) {
478 if (fnmatch(property_pattern, property, 0) != 0)
479 continue;
480
481 if (strv_fnmatch(value_patterns, value))
482 return true;
483 }
484 }
485
486 return false;
487 }
488
489 static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
490 const char *tag;
491
492 assert(enumerator);
493 assert(device);
494
495 SET_FOREACH(tag, enumerator->match_tag)
496 if (!sd_device_has_tag(device, tag))
497 return false;
498
499 return true;
500 }
501
502 static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
503 assert(enumerator);
504 assert(sysname);
505
506 return set_fnmatch(enumerator->match_sysname, enumerator->nomatch_sysname, sysname);
507 }
508
509 static int match_initialized(sd_device_enumerator *enumerator, sd_device *device) {
510 int r;
511
512 assert(enumerator);
513 assert(device);
514
515 if (enumerator->match_initialized == MATCH_INITIALIZED_ALL)
516 return true;
517
518 r = sd_device_get_is_initialized(device);
519 if (r == -ENOENT) /* this is necessarily racey, so ignore missing devices */
520 return false;
521 if (r < 0)
522 return r;
523
524 if (enumerator->match_initialized == MATCH_INITIALIZED_COMPAT) {
525 /* only devices that have no devnode/ifindex or have a db entry are accepted. */
526 if (r > 0)
527 return true;
528
529 if (sd_device_get_devnum(device, NULL) >= 0)
530 return false;
531
532 if (sd_device_get_ifindex(device, NULL) >= 0)
533 return false;
534
535 return true;
536 }
537
538 return (enumerator->match_initialized == MATCH_INITIALIZED_NO) == (r == 0);
539 }
540
541 static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
542 assert(enumerator);
543
544 if (!subsystem)
545 return false;
546
547 return set_fnmatch(enumerator->match_subsystem, enumerator->nomatch_subsystem, subsystem);
548 }
549
550 typedef enum MatchFlag {
551 MATCH_SYSNAME = 1u << 0,
552 MATCH_SUBSYSTEM = 1u << 1,
553 MATCH_PARENT = 1u << 2,
554 MATCH_TAG = 1u << 3,
555
556 MATCH_ALL = (1u << 4) - 1,
557 } MatchFlag;
558
559 static int test_matches(
560 sd_device_enumerator *enumerator,
561 sd_device *device,
562 MatchFlag flags) {
563
564 int r;
565
566 assert(enumerator);
567 assert(device);
568
569 if (FLAGS_SET(flags, MATCH_SYSNAME)) {
570 const char *sysname;
571
572 r = sd_device_get_sysname(device, &sysname);
573 if (r < 0)
574 return r;
575
576 if (!match_sysname(enumerator, sysname))
577 return false;
578 }
579
580 if (FLAGS_SET(flags, MATCH_SUBSYSTEM)) {
581 const char *subsystem;
582
583 r = sd_device_get_subsystem(device, &subsystem);
584 if (r == -ENOENT)
585 return false;
586 if (r < 0)
587 return r;
588
589 if (!match_subsystem(enumerator, subsystem))
590 return false;
591 }
592
593 if (FLAGS_SET(flags, MATCH_PARENT) &&
594 !device_match_parent(device, enumerator->match_parent, NULL))
595 return false;
596
597 if (FLAGS_SET(flags, MATCH_TAG) &&
598 !match_tag(enumerator, device))
599 return false;
600
601 r = match_initialized(enumerator, device);
602 if (r <= 0)
603 return r;
604
605 if (!match_property(enumerator, device))
606 return false;
607
608 if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
609 return false;
610
611 return true;
612 }
613
614 static int enumerator_add_parent_devices(
615 sd_device_enumerator *enumerator,
616 sd_device *device,
617 MatchFlag flags) {
618
619 int k, r = 0;
620
621 assert(enumerator);
622 assert(device);
623
624 for (;;) {
625 k = sd_device_get_parent(device, &device);
626 if (k == -ENOENT) /* Reached the top? */
627 break;
628 if (k < 0) {
629 r = k;
630 break;
631 }
632
633 k = test_matches(enumerator, device, flags);
634 if (k < 0) {
635 r = k;
636 break;
637 }
638 if (k == 0)
639 continue;
640
641 k = device_enumerator_add_device(enumerator, device);
642 if (k < 0) {
643 r = k;
644 break;
645 }
646 if (k == 0) /* Exists already? Then no need to go further up. */
647 break;
648 }
649
650 return r;
651 }
652
653 int device_enumerator_add_parent_devices(sd_device_enumerator *enumerator, sd_device *device) {
654 return enumerator_add_parent_devices(enumerator, device, MATCH_ALL & (~MATCH_PARENT));
655 }
656
657 static bool relevant_sysfs_subdir(const struct dirent *de) {
658 assert(de);
659
660 if (de->d_name[0] == '.')
661 return false;
662
663 /* Also filter out regular files and such, i.e. stuff that definitely isn't a kobject path. (Note
664 * that we rely on the fact that sysfs fills in d_type here, i.e. doesn't do DT_UNKNOWN) */
665 return IN_SET(de->d_type, DT_DIR, DT_LNK);
666 }
667
668 static int enumerator_scan_dir_and_add_devices(
669 sd_device_enumerator *enumerator,
670 const char *basedir,
671 const char *subdir1,
672 const char *subdir2) {
673
674 _cleanup_closedir_ DIR *dir = NULL;
675 char *path;
676 int k, r = 0;
677
678 assert(enumerator);
679 assert(basedir);
680
681 path = strjoina("/sys/", basedir, "/");
682
683 if (subdir1)
684 path = strjoina(path, subdir1, "/");
685
686 if (subdir2)
687 path = strjoina(path, subdir2, "/");
688
689 dir = opendir(path);
690 if (!dir) {
691 bool ignore = errno == ENOENT;
692
693 /* this is necessarily racey, so ignore missing directories */
694 log_debug_errno(errno,
695 "sd-device-enumerator: Failed to open directory %s%s: %m",
696 path, ignore ? ", ignoring" : "");
697 return ignore ? 0 : -errno;
698 }
699
700 FOREACH_DIRENT_ALL(de, dir, return -errno) {
701 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
702 char syspath[strlen(path) + 1 + strlen(de->d_name) + 1];
703
704 if (!relevant_sysfs_subdir(de))
705 continue;
706
707 if (!match_sysname(enumerator, de->d_name))
708 continue;
709
710 (void) sprintf(syspath, "%s%s", path, de->d_name);
711
712 k = sd_device_new_from_syspath(&device, syspath);
713 if (k < 0) {
714 if (k != -ENODEV)
715 /* this is necessarily racey, so ignore missing devices */
716 r = k;
717
718 continue;
719 }
720
721 k = test_matches(enumerator, device, MATCH_ALL & (~MATCH_SYSNAME)); /* sysname is already tested. */
722 if (k <= 0) {
723 if (k < 0)
724 r = k;
725 continue;
726 }
727
728 k = device_enumerator_add_device(enumerator, device);
729 if (k < 0)
730 r = k;
731
732 /* Also include all potentially matching parent devices in the enumeration. These are things
733 * like root busses — e.g. /sys/devices/pci0000:00/ or /sys/devices/pnp0/, which ar not
734 * linked from /sys/class/ or /sys/bus/, hence pick them up explicitly here. */
735 k = enumerator_add_parent_devices(enumerator, device, MATCH_ALL);
736 if (k < 0)
737 r = k;
738 }
739
740 return r;
741 }
742
743 static int enumerator_scan_dir(
744 sd_device_enumerator *enumerator,
745 const char *basedir,
746 const char *subdir,
747 const char *subsystem) {
748
749 _cleanup_closedir_ DIR *dir = NULL;
750 char *path;
751 int r = 0;
752
753 path = strjoina("/sys/", basedir);
754
755 dir = opendir(path);
756 if (!dir) {
757 bool ignore = errno == ENOENT;
758
759 log_debug_errno(errno,
760 "sd-device-enumerator: Failed to open directory %s%s: %m",
761 path, ignore ? ", ignoring" : "");
762 return ignore ? 0 : -errno;
763 }
764
765 FOREACH_DIRENT_ALL(de, dir, return -errno) {
766 int k;
767
768 if (!relevant_sysfs_subdir(de))
769 continue;
770
771 if (!match_subsystem(enumerator, subsystem ?: de->d_name))
772 continue;
773
774 k = enumerator_scan_dir_and_add_devices(enumerator, basedir, de->d_name, subdir);
775 if (k < 0)
776 r = k;
777 }
778
779 return r;
780 }
781
782 static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
783 _cleanup_closedir_ DIR *dir = NULL;
784 char *path;
785 int r = 0;
786
787 assert(enumerator);
788 assert(tag);
789
790 path = strjoina("/run/udev/tags/", tag);
791
792 dir = opendir(path);
793 if (!dir) {
794 bool ignore = errno == ENOENT;
795
796 log_debug_errno(errno,
797 "sd-device-enumerator: Failed to open directory %s%s: %m",
798 path, ignore ? ", ignoring" : "");
799 return ignore ? 0 : -errno;
800 }
801
802 /* TODO: filter away subsystems? */
803
804 FOREACH_DIRENT_ALL(de, dir, return -errno) {
805 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
806 int k;
807
808 if (de->d_name[0] == '.')
809 continue;
810
811 k = sd_device_new_from_device_id(&device, de->d_name);
812 if (k < 0) {
813 if (k != -ENODEV)
814 /* this is necessarily racy, so ignore missing devices */
815 r = k;
816
817 continue;
818 }
819
820 /* Generated from tag, hence not necessary to check tag again. */
821 k = test_matches(enumerator, device, MATCH_ALL & (~MATCH_TAG));
822 if (k < 0)
823 r = k;
824 if (k <= 0)
825 continue;
826
827 k = device_enumerator_add_device(enumerator, device);
828 if (k < 0) {
829 r = k;
830 continue;
831 }
832 }
833
834 return r;
835 }
836
837 static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
838 const char *tag;
839 int r = 0;
840
841 assert(enumerator);
842
843 SET_FOREACH(tag, enumerator->match_tag) {
844 int k;
845
846 k = enumerator_scan_devices_tag(enumerator, tag);
847 if (k < 0)
848 r = k;
849 }
850
851 return r;
852 }
853
854 static int parent_add_child(sd_device_enumerator *enumerator, const char *path, MatchFlag flags) {
855 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
856 int r;
857
858 r = sd_device_new_from_syspath(&device, path);
859 if (r == -ENODEV)
860 /* this is necessarily racy, so ignore missing devices */
861 return 0;
862 else if (r < 0)
863 return r;
864
865 r = test_matches(enumerator, device, flags);
866 if (r <= 0)
867 return r;
868
869 return device_enumerator_add_device(enumerator, device);
870 }
871
872 static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, Set **stack) {
873 _cleanup_closedir_ DIR *dir = NULL;
874 int r = 0;
875
876 assert(enumerator);
877 assert(path);
878 assert(stack);
879
880 dir = opendir(path);
881 if (!dir) {
882 bool ignore = errno == ENOENT;
883
884 log_debug_errno(errno,
885 "sd-device-enumerator: Failed to open directory %s%s: %m",
886 path, ignore ? ", ignoring" : "");
887 return ignore ? 0 : -errno;
888 }
889
890 FOREACH_DIRENT_ALL(de, dir, return -errno) {
891 _cleanup_free_ char *child = NULL;
892 int k;
893
894 if (de->d_name[0] == '.')
895 continue;
896
897 if (de->d_type != DT_DIR)
898 continue;
899
900 child = path_join(path, de->d_name);
901 if (!child)
902 return -ENOMEM;
903
904 /* Let's check sysname filter earlier. The other tests require the sd-device object created
905 * from the path, thus much costly. */
906 if (match_sysname(enumerator, de->d_name)) {
907 k = parent_add_child(enumerator, child, MATCH_ALL & (~(MATCH_SYSNAME|MATCH_PARENT)));
908 if (k < 0)
909 r = k;
910 }
911
912 k = set_ensure_consume(stack, &path_hash_ops_free, TAKE_PTR(child));
913 if (k < 0)
914 r = k;
915 }
916
917 return r;
918 }
919
920 static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
921 _cleanup_set_free_ Set *stack = NULL;
922 const char *path;
923 int r = 0, k;
924
925 assert(enumerator);
926
927 SET_FOREACH(path, enumerator->match_parent) {
928 k = parent_add_child(enumerator, path, MATCH_ALL & (~MATCH_PARENT));
929 if (k < 0)
930 r = k;
931
932 k = parent_crawl_children(enumerator, path, &stack);
933 if (k < 0)
934 r = k;
935 }
936
937 for (;;) {
938 _cleanup_free_ char *p = NULL;
939
940 p = set_steal_first(stack);
941 if (!p)
942 return r;
943
944 k = parent_crawl_children(enumerator, p, &stack);
945 if (k < 0)
946 r = k;
947 }
948 }
949
950 static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
951 int k, r = 0;
952
953 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
954 if (k < 0)
955 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
956
957 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
958 if (k < 0)
959 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
960
961 return r;
962 }
963
964 int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
965 int r = 0, k;
966
967 assert(enumerator);
968
969 if (enumerator->scan_uptodate &&
970 enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
971 return 0;
972
973 device_enumerator_unref_devices(enumerator);
974
975 if (!set_isempty(enumerator->match_tag)) {
976 k = enumerator_scan_devices_tags(enumerator);
977 if (k < 0)
978 r = k;
979 } else if (enumerator->match_parent) {
980 k = enumerator_scan_devices_children(enumerator);
981 if (k < 0)
982 r = k;
983 } else {
984 k = enumerator_scan_devices_all(enumerator);
985 if (k < 0)
986 r = k;
987 }
988
989 enumerator->scan_uptodate = true;
990 enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
991
992 return r;
993 }
994
995 _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
996 assert_return(enumerator, NULL);
997
998 if (device_enumerator_scan_devices(enumerator) < 0)
999 return NULL;
1000
1001 if (enumerator_sort_devices(enumerator) < 0)
1002 return NULL;
1003
1004 enumerator->current_device_index = 0;
1005
1006 if (enumerator->n_devices == 0)
1007 return NULL;
1008
1009 return enumerator->devices[0];
1010 }
1011
1012 _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
1013 assert_return(enumerator, NULL);
1014
1015 if (!enumerator->scan_uptodate ||
1016 !enumerator->sorted ||
1017 enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
1018 enumerator->current_device_index + 1 >= enumerator->n_devices)
1019 return NULL;
1020
1021 return enumerator->devices[++enumerator->current_device_index];
1022 }
1023
1024 int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
1025 int r = 0, k;
1026
1027 assert(enumerator);
1028
1029 if (enumerator->scan_uptodate &&
1030 enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
1031 return 0;
1032
1033 device_enumerator_unref_devices(enumerator);
1034
1035 /* modules */
1036 if (match_subsystem(enumerator, "module")) {
1037 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
1038 if (k < 0)
1039 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
1040 }
1041
1042 /* subsystems (only buses support coldplug) */
1043 if (match_subsystem(enumerator, "subsystem")) {
1044 k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
1045 if (k < 0)
1046 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
1047 }
1048
1049 /* subsystem drivers */
1050 if (match_subsystem(enumerator, "drivers")) {
1051 k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
1052 if (k < 0)
1053 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
1054 }
1055
1056 enumerator->scan_uptodate = true;
1057 enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
1058
1059 return r;
1060 }
1061
1062 _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
1063 assert_return(enumerator, NULL);
1064
1065 if (device_enumerator_scan_subsystems(enumerator) < 0)
1066 return NULL;
1067
1068 if (enumerator_sort_devices(enumerator) < 0)
1069 return NULL;
1070
1071 enumerator->current_device_index = 0;
1072
1073 if (enumerator->n_devices == 0)
1074 return NULL;
1075
1076 return enumerator->devices[0];
1077 }
1078
1079 _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
1080 assert_return(enumerator, NULL);
1081
1082 if (!enumerator->scan_uptodate ||
1083 !enumerator->sorted ||
1084 enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
1085 enumerator->current_device_index + 1 >= enumerator->n_devices)
1086 return NULL;
1087
1088 return enumerator->devices[++enumerator->current_device_index];
1089 }
1090
1091 int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator) {
1092 int r;
1093
1094 assert(enumerator);
1095
1096 if (enumerator->scan_uptodate &&
1097 enumerator->type == DEVICE_ENUMERATION_TYPE_ALL)
1098 return 0;
1099
1100 device_enumerator_unref_devices(enumerator);
1101
1102 if (!set_isempty(enumerator->match_tag))
1103 r = enumerator_scan_devices_tags(enumerator);
1104 else if (enumerator->match_parent)
1105 r = enumerator_scan_devices_children(enumerator);
1106 else {
1107 int k;
1108
1109 r = enumerator_scan_devices_all(enumerator);
1110
1111 if (match_subsystem(enumerator, "module")) {
1112 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
1113 if (k < 0)
1114 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
1115 }
1116 if (match_subsystem(enumerator, "subsystem")) {
1117 k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
1118 if (k < 0)
1119 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
1120 }
1121
1122 if (match_subsystem(enumerator, "drivers")) {
1123 k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
1124 if (k < 0)
1125 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
1126 }
1127 }
1128
1129 enumerator->scan_uptodate = true;
1130 enumerator->type = DEVICE_ENUMERATION_TYPE_ALL;
1131
1132 return r;
1133 }
1134
1135 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
1136 assert_return(enumerator, NULL);
1137
1138 if (!enumerator->scan_uptodate)
1139 return NULL;
1140
1141 if (enumerator_sort_devices(enumerator) < 0)
1142 return NULL;
1143
1144 enumerator->current_device_index = 0;
1145
1146 if (enumerator->n_devices == 0)
1147 return NULL;
1148
1149 return enumerator->devices[0];
1150 }
1151
1152 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
1153 assert_return(enumerator, NULL);
1154
1155 if (!enumerator->scan_uptodate ||
1156 !enumerator->sorted ||
1157 enumerator->current_device_index + 1 >= enumerator->n_devices)
1158 return NULL;
1159
1160 return enumerator->devices[++enumerator->current_device_index];
1161 }
1162
1163 sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
1164 assert(enumerator);
1165 assert(ret_n_devices);
1166
1167 if (!enumerator->scan_uptodate)
1168 return NULL;
1169
1170 if (enumerator_sort_devices(enumerator) < 0)
1171 return NULL;
1172
1173 *ret_n_devices = enumerator->n_devices;
1174 return enumerator->devices;
1175 }