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