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