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