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