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