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