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