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