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