]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-enumerator.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-enumerator.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
96df036f
TG
2/***
3 This file is part of systemd.
4
5 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
6 Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
96df036f
TG
22#include "sd-device.h"
23
b5efdb8a 24#include "alloc-util.h"
96df036f 25#include "device-enumerator-private.h"
07630cea 26#include "device-util.h"
a0956174 27#include "dirent-util.h"
3ffd4af2 28#include "fd-util.h"
07630cea
LP
29#include "prioq.h"
30#include "set.h"
31#include "string-util.h"
32#include "strv.h"
33#include "util.h"
96df036f
TG
34
35#define DEVICE_ENUMERATE_MAX_DEPTH 256
36
37typedef enum DeviceEnumerationType {
38 DEVICE_ENUMERATION_TYPE_DEVICES,
39 DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
40 _DEVICE_ENUMERATION_TYPE_MAX,
41 _DEVICE_ENUMERATION_TYPE_INVALID = -1,
42} DeviceEnumerationType;
43
44struct sd_device_enumerator {
45 unsigned n_ref;
46
47 DeviceEnumerationType type;
48 Prioq *devices;
49 bool scan_uptodate;
50
51 Set *match_subsystem;
52 Set *nomatch_subsystem;
53 Hashmap *match_sysattr;
54 Hashmap *nomatch_sysattr;
55 Hashmap *match_property;
56 Set *match_sysname;
57 Set *match_tag;
58 sd_device *match_parent;
dee5e0b6 59 bool match_allow_uninitialized;
96df036f
TG
60};
61
62_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
4afd3348 63 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerator = NULL;
96df036f
TG
64
65 assert(ret);
66
67 enumerator = new0(sd_device_enumerator, 1);
68 if (!enumerator)
69 return -ENOMEM;
70
71 enumerator->n_ref = 1;
72 enumerator->type = _DEVICE_ENUMERATION_TYPE_INVALID;
73
1cc6c93a 74 *ret = TAKE_PTR(enumerator);
96df036f
TG
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);
96df036f
TG
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
54f0b4d9
TG
157 if (_value) {
158 value = strdup(_value);
159 if (!value)
160 return -ENOMEM;
161 }
96df036f
TG
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);
96df036f
TG
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
54f0b4d9
TG
190 if (_value) {
191 value = strdup(_value);
192 if (!value)
193 return -ENOMEM;
194 }
96df036f
TG
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
dee5e0b6 258_public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
96df036f
TG
259 assert_return(enumerator, -EINVAL);
260
dee5e0b6
TG
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;
96df036f
TG
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;
18ae3d98 281 bool delay_a, delay_b;
96df036f
TG
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. */
fbd0b64f 295 sound_a += STRLEN("/sound/card");
96df036f
TG
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 */
18ae3d98
DH
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;
96df036f
TG
324
325 return strcmp(devpath_a, devpath_b);
326}
327
19c9df44 328int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
96df036f
TG
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
5f529f4c 375 HASHMAP_FOREACH_KEY(value, sysattr, enumerator->nomatch_sysattr, i)
96df036f
TG
376 if (match_sysattr_value(device, sysattr, value))
377 return false;
378
5f529f4c 379 HASHMAP_FOREACH_KEY(value, sysattr, enumerator->match_sysattr, i)
96df036f
TG
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
5f529f4c 397 HASHMAP_FOREACH_KEY(value, property, enumerator->match_property, i) {
96df036f
TG
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) {
4afd3348 490 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
96df036f
TG
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) {
08232a02
TG
505 if (k != -ENODEV)
506 /* this is necessarily racey, so ignore missing devices */
507 r = k;
508
96df036f
TG
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 */
dee5e0b6 540 if (!enumerator->match_allow_uninitialized &&
96df036f
TG
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
19c9df44 557 k = device_enumerator_add_device(enumerator, device);
96df036f
TG
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;
25f027c5
ZJS
634 else
635 return log_error_errno(errno, "sd-device-enumerator: could not open tags directory %s: %m", path);
96df036f
TG
636 }
637
638 /* TODO: filter away subsystems? */
639
640 FOREACH_DIRENT_ALL(dent, dir, return -errno) {
4afd3348 641 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
96df036f
TG
642 const char *subsystem, *sysname;
643 int k;
644
645 if (dent->d_name[0] == '.')
646 continue;
647
648 k = sd_device_new_from_device_id(&device, dent->d_name);
649 if (k < 0) {
08232a02
TG
650 if (k != -ENODEV)
651 /* this is necessarily racy, so ignore missing devices */
652 r = k;
653
96df036f
TG
654 continue;
655 }
656
657 k = sd_device_get_subsystem(device, &subsystem);
658 if (k < 0) {
659 r = k;
660 continue;
661 }
662
663 if (!match_subsystem(enumerator, subsystem))
664 continue;
665
666 k = sd_device_get_sysname(device, &sysname);
667 if (k < 0) {
668 r = k;
669 continue;
670 }
671
672 if (!match_sysname(enumerator, sysname))
673 continue;
674
675 if (!match_parent(enumerator, device))
676 continue;
677
678 if (!match_property(enumerator, device))
679 continue;
680
681 if (!match_sysattr(enumerator, device))
682 continue;
683
19c9df44 684 k = device_enumerator_add_device(enumerator, device);
96df036f
TG
685 if (k < 0) {
686 r = k;
687 continue;
688 }
689 }
690
691 return r;
692}
693
694static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
695 const char *tag;
696 Iterator i;
3172836b 697 int r = 0;
96df036f
TG
698
699 assert(enumerator);
700
701 SET_FOREACH(tag, enumerator->match_tag, i) {
3172836b
TG
702 int k;
703
704 k = enumerator_scan_devices_tag(enumerator, tag);
705 if (k < 0)
706 r = k;
96df036f
TG
707 }
708
3172836b 709 return r;
96df036f
TG
710}
711
712static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
4afd3348 713 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
96df036f
TG
714 const char *subsystem, *sysname;
715 int r;
716
717 r = sd_device_new_from_syspath(&device, path);
08232a02
TG
718 if (r == -ENODEV)
719 /* this is necessarily racy, so ignore missing devices */
96df036f
TG
720 return 0;
721 else if (r < 0)
722 return r;
723
724 r = sd_device_get_subsystem(device, &subsystem);
9a9c7dc2
MM
725 if (r == -ENOENT)
726 return 0;
96df036f
TG
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
19c9df44 746 r = device_enumerator_add_device(enumerator, device);
96df036f
TG
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);
25f027c5
ZJS
759 if (!dir)
760 return log_debug_errno(errno, "sd-device-enumerate: could not open parent directory %s: %m", path);
96df036f
TG
761
762 FOREACH_DIRENT_ALL(dent, dir, return -errno) {
763 _cleanup_free_ char *child = NULL;
764 int k;
765
766 if (dent->d_name[0] == '.')
767 continue;
768
769 if (dent->d_type != DT_DIR)
770 continue;
771
605405c6 772 child = strjoin(path, "/", dent->d_name);
53fae771
ZJS
773 if (!child)
774 return -ENOMEM;
96df036f
TG
775
776 k = parent_add_child(enumerator, child);
777 if (k < 0)
778 r = k;
779
780 if (maxdepth > 0)
781 parent_crawl_children(enumerator, child, maxdepth - 1);
782 else
783 log_debug("device-enumerate: max depth reached, %s: ignoring devices", child);
784 }
785
786 return r;
787}
788
789static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
790 const char *path;
791 int r = 0, k;
792
793 r = sd_device_get_syspath(enumerator->match_parent, &path);
794 if (r < 0)
795 return r;
796
797 k = parent_add_child(enumerator, path);
798 if (k < 0)
799 r = k;
800
801 k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
802 if (k < 0)
803 r = k;
804
805 return r;
806}
807
808static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
809 int r = 0;
810
811 log_debug("device-enumerator: scan all dirs");
812
813 if (access("/sys/subsystem", F_OK) >= 0) {
814 /* we have /subsystem/, forget all the old stuff */
815 r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
e53fc357
LP
816 if (r < 0)
817 return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m");
96df036f
TG
818 } else {
819 int k;
820
821 k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
822 if (k < 0) {
823 log_debug_errno(k, "device-enumerator: failed to scan /sys/bus: %m");
824 r = k;
825 }
826
827 k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
828 if (k < 0) {
829 log_debug_errno(k, "device-enumerator: failed to scan /sys/class: %m");
830 r = k;
831 }
832 }
833
834 return r;
835}
836
837int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
838 sd_device *device;
3172836b 839 int r = 0, k;
96df036f
TG
840
841 assert(enumerator);
842
843 if (enumerator->scan_uptodate &&
844 enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
845 return 0;
846
847 while ((device = prioq_pop(enumerator->devices)))
848 sd_device_unref(device);
849
850 if (!set_isempty(enumerator->match_tag)) {
3172836b
TG
851 k = enumerator_scan_devices_tags(enumerator);
852 if (k < 0)
853 r = k;
96df036f 854 } else if (enumerator->match_parent) {
3172836b
TG
855 k = enumerator_scan_devices_children(enumerator);
856 if (k < 0)
857 r = k;
96df036f 858 } else {
3172836b
TG
859 k = enumerator_scan_devices_all(enumerator);
860 if (k < 0)
861 r = k;
96df036f
TG
862 }
863
864 enumerator->scan_uptodate = true;
865
3172836b 866 return r;
96df036f
TG
867}
868
869_public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
870 int r;
871
872 assert_return(enumerator, NULL);
873
874 r = device_enumerator_scan_devices(enumerator);
875 if (r < 0)
876 return NULL;
877
878 enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
879
880 return prioq_peek(enumerator->devices);
881}
882
883_public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
884 assert_return(enumerator, NULL);
885
886 if (!enumerator->scan_uptodate ||
887 enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES)
888 return NULL;
889
890 sd_device_unref(prioq_pop(enumerator->devices));
891
892 return prioq_peek(enumerator->devices);
893}
894
895int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
896 sd_device *device;
897 const char *subsysdir;
898 int r = 0, k;
899
900 assert(enumerator);
901
902 if (enumerator->scan_uptodate &&
903 enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
904 return 0;
905
906 while ((device = prioq_pop(enumerator->devices)))
907 sd_device_unref(device);
908
909 /* modules */
910 if (match_subsystem(enumerator, "module")) {
911 k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
912 if (k < 0) {
913 log_debug_errno(k, "device-enumerator: failed to scan modules: %m");
914 r = k;
915 }
916 }
917
918 if (access("/sys/subsystem", F_OK) >= 0)
919 subsysdir = "subsystem";
920 else
921 subsysdir = "bus";
922
923 /* subsystems (only buses support coldplug) */
924 if (match_subsystem(enumerator, "subsystem")) {
925 k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
926 if (k < 0) {
927 log_debug_errno(k, "device-enumerator: failed to scan subsystems: %m");
928 r = k;
929 }
930 }
931
932 /* subsystem drivers */
933 if (match_subsystem(enumerator, "drivers")) {
934 k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
935 if (k < 0) {
936 log_debug_errno(k, "device-enumerator: failed to scan drivers: %m");
937 r = k;
938 }
939 }
940
941 enumerator->scan_uptodate = true;
942
943 return r;
944}
945
946_public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
947 int r;
948
949 assert_return(enumerator, NULL);
950
951 r = device_enumerator_scan_subsystems(enumerator);
952 if (r < 0)
953 return NULL;
954
955 enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
956
957 return prioq_peek(enumerator->devices);
958}
959
960_public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
961 assert_return(enumerator, NULL);
962
963 if (enumerator->scan_uptodate ||
964 enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
965 return NULL;
966
967 sd_device_unref(prioq_pop(enumerator->devices));
968
969 return prioq_peek(enumerator->devices);
970}
971
972sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
973 assert_return(enumerator, NULL);
974
975 return prioq_peek(enumerator->devices);
976}
977
978sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
979 assert_return(enumerator, NULL);
980
981 sd_device_unref(prioq_pop(enumerator->devices));
982
983 return prioq_peek(enumerator->devices);
984}