1/***
2  This file is part of systemd.
3
4  Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5
6  systemd is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Lesser General Public License as published by
8  the Free Software Foundation; either version 2.1 of the License, or
9  (at your option) any later version.
10
11  systemd is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public License
17  along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <stddef.h>
23#include <unistd.h>
24#include <errno.h>
25#include <string.h>
26#include <dirent.h>
27#include <fnmatch.h>
28#include <stdbool.h>
29#include <sys/stat.h>
30#include <sys/param.h>
31#include <sys/sysmacros.h>
32
33#include "libudev.h"
34#include "libudev-private.h"
35
36/**
37 * SECTION:libudev-enumerate
38 * @short_description: lookup and sort sys devices
39 *
40 * Lookup devices in the sys filesystem, filter devices by properties,
41 * and return a sorted list of devices.
42 */
43
44struct syspath {
45        char *syspath;
46        size_t len;
47};
48
49/**
50 * udev_enumerate:
51 *
52 * Opaque object representing one device lookup/sort context.
53 */
54struct udev_enumerate {
55        struct udev *udev;
56        int refcount;
57        struct udev_list sysattr_match_list;
58        struct udev_list sysattr_nomatch_list;
59        struct udev_list subsystem_match_list;
60        struct udev_list subsystem_nomatch_list;
61        struct udev_list sysname_match_list;
62        struct udev_list properties_match_list;
63        struct udev_list tags_match_list;
64        struct udev_device *parent_match;
65        struct udev_list devices_list;
66        struct syspath *devices;
67        unsigned int devices_cur;
68        unsigned int devices_max;
69        bool devices_uptodate:1;
70        bool match_is_initialized;
71};
72
73/**
74 * udev_enumerate_new:
75 * @udev: udev library context
76 *
77 * Create an enumeration context to scan /sys.
78 *
79 * Returns: an enumeration context.
80 **/
81_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
82{
83        struct udev_enumerate *udev_enumerate;
84
85        if (udev == NULL)
86                return NULL;
87        udev_enumerate = new0(struct udev_enumerate, 1);
88        if (udev_enumerate == NULL)
89                return NULL;
90        udev_enumerate->refcount = 1;
91        udev_enumerate->udev = udev;
92        udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
93        udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
94        udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
95        udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
96        udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
97        udev_list_init(udev, &udev_enumerate->properties_match_list, false);
98        udev_list_init(udev, &udev_enumerate->tags_match_list, true);
99        udev_list_init(udev, &udev_enumerate->devices_list, false);
100        return udev_enumerate;
101}
102
103/**
104 * udev_enumerate_ref:
105 * @udev_enumerate: context
106 *
107 * Take a reference of a enumeration context.
108 *
109 * Returns: the passed enumeration context
110 **/
111_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
112{
113        if (udev_enumerate == NULL)
114                return NULL;
115        udev_enumerate->refcount++;
116        return udev_enumerate;
117}
118
119/**
120 * udev_enumerate_unref:
121 * @udev_enumerate: context
122 *
123 * Drop a reference of an enumeration context. If the refcount reaches zero,
124 * all resources of the enumeration context will be released.
125 *
126 * Returns: #NULL
127 **/
128_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
129{
130        unsigned int i;
131
132        if (udev_enumerate == NULL)
133                return NULL;
134        udev_enumerate->refcount--;
135        if (udev_enumerate->refcount > 0)
136                return NULL;
137        udev_list_cleanup(&udev_enumerate->sysattr_match_list);
138        udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
139        udev_list_cleanup(&udev_enumerate->subsystem_match_list);
140        udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list);
141        udev_list_cleanup(&udev_enumerate->sysname_match_list);
142        udev_list_cleanup(&udev_enumerate->properties_match_list);
143        udev_list_cleanup(&udev_enumerate->tags_match_list);
144        udev_device_unref(udev_enumerate->parent_match);
145        udev_list_cleanup(&udev_enumerate->devices_list);
146        for (i = 0; i < udev_enumerate->devices_cur; i++)
147                free(udev_enumerate->devices[i].syspath);
148        free(udev_enumerate->devices);
149        free(udev_enumerate);
150        return NULL;
151}
152
153/**
154 * udev_enumerate_get_udev:
155 * @udev_enumerate: context
156 *
157 * Get the udev library context.
158 *
159 * Returns: a pointer to the context.
160 */
161_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
162{
163        if (udev_enumerate == NULL)
164                return NULL;
165        return udev_enumerate->udev;
166}
167
168static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
169{
170        char *path;
171        struct syspath *entry;
172
173        /* double array size if needed */
174        if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
175                struct syspath *buf;
176                unsigned int add;
177
178                add = udev_enumerate->devices_max;
179                if (add < 1024)
180                        add = 1024;
181                buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
182                if (buf == NULL)
183                        return -ENOMEM;
184                udev_enumerate->devices = buf;
185                udev_enumerate->devices_max += add;
186        }
187
188        path = strdup(syspath);
189        if (path == NULL)
190                return -ENOMEM;
191        entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
192        entry->syspath = path;
193        entry->len = strlen(path);
194        udev_enumerate->devices_cur++;
195        udev_enumerate->devices_uptodate = false;
196        return 0;
197}
198
199static int syspath_cmp(const void *p1, const void *p2)
200{
201        const struct syspath *path1 = p1;
202        const struct syspath *path2 = p2;
203        size_t len;
204        int ret;
205
206        len = MIN(path1->len, path2->len);
207        ret = memcmp(path1->syspath, path2->syspath, len);
208        if (ret == 0) {
209                if (path1->len < path2->len)
210                        ret = -1;
211                else if (path1->len > path2->len)
212                        ret = 1;
213        }
214        return ret;
215}
216
217/* For devices that should be moved to the absolute end of the list */
218static bool devices_delay_end(struct udev *udev, const char *syspath)
219{
220        static const char *delay_device_list[] = {
221                "/block/md",
222                "/block/dm-",
223                NULL
224        };
225        int i;
226
227        for (i = 0; delay_device_list[i] != NULL; i++) {
228                if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL)
229                        return true;
230        }
231        return false;
232}
233
234/* For devices that should just be moved a little bit later, just
235 * before the point where some common path prefix changes. Returns the
236 * number of characters that make up that common prefix */
237static size_t devices_delay_later(struct udev *udev, const char *syspath)
238{
239        const char *c;
240
241        /* For sound cards the control device must be enumerated last
242         * to make sure it's the final device node that gets ACLs
243         * applied. Applications rely on this fact and use ACL changes
244         * on the control node as an indicator that the ACL change of
245         * the entire sound card completed. The kernel makes this
246         * guarantee when creating those devices, and hence we should
247         * too when enumerating them. */
248
249        if ((c = strstr(syspath, "/sound/card"))) {
250                c += 11;
251                c += strcspn(c, "/");
252
253                if (startswith(c, "/controlC"))
254                        return c - syspath + 1;
255        }
256
257        return 0;
258}
259
260/**
261 * udev_enumerate_get_list_entry:
262 * @udev_enumerate: context
263 *
264 * Get the first entry of the sorted list of device paths.
265 *
266 * Returns: a udev_list_entry.
267 */
268_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
269{
270        if (udev_enumerate == NULL)
271                return NULL;
272        if (!udev_enumerate->devices_uptodate) {
273                unsigned int i;
274                int move_later = -1;
275                unsigned int max;
276                struct syspath *prev = NULL;
277                size_t move_later_prefix = 0;
278
279                udev_list_cleanup(&udev_enumerate->devices_list);
280                qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
281
282                max = udev_enumerate->devices_cur;
283                for (i = 0; i < max; i++) {
284                        struct syspath *entry = &udev_enumerate->devices[i];
285
286                        /* skip duplicated entries */
287                        if (prev != NULL &&
288                            entry->len == prev->len &&
289                            memcmp(entry->syspath, prev->syspath, entry->len) == 0)
290                                continue;
291                        prev = entry;
292
293                        /* skip to be delayed devices, and add them to the end of the list */
294                        if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
295                                syspath_add(udev_enumerate, entry->syspath);
296                                /* need to update prev here for the case realloc() gives a different address */
297                                prev = &udev_enumerate->devices[i];
298                                continue;
299                        }
300
301                        /* skip to be delayed devices, and move the to
302                         * the point where the prefix changes. We can
303                         * only move one item at a time. */
304                        if (move_later == -1) {
305                                move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
306
307                                if (move_later_prefix > 0) {
308                                        move_later = i;
309                                        continue;
310                                }
311                        }
312
313                        if ((move_later >= 0) &&
314                             !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) {
315
316                                udev_list_entry_add(&udev_enumerate->devices_list,
317                                                    udev_enumerate->devices[move_later].syspath, NULL);
318                                move_later = -1;
319                        }
320
321                        udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
322                }
323
324                if (move_later >= 0)
325                        udev_list_entry_add(&udev_enumerate->devices_list,
326                                            udev_enumerate->devices[move_later].syspath, NULL);
327
328                /* add and cleanup delayed devices from end of list */
329                for (i = max; i < udev_enumerate->devices_cur; i++) {
330                        struct syspath *entry = &udev_enumerate->devices[i];
331
332                        udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
333                        free(entry->syspath);
334                }
335                udev_enumerate->devices_cur = max;
336
337                udev_enumerate->devices_uptodate = true;
338        }
339        return udev_list_get_entry(&udev_enumerate->devices_list);
340}
341
342/**
343 * udev_enumerate_add_match_subsystem:
344 * @udev_enumerate: context
345 * @subsystem: filter for a subsystem of the device to include in the list
346 *
347 * Match only devices belonging to a certain kernel subsystem.
348 *
349 * Returns: 0 on success, otherwise a negative error value.
350 */
351_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
352{
353        if (udev_enumerate == NULL)
354                return -EINVAL;
355        if (subsystem == NULL)
356                return 0;
357        if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
358                return -ENOMEM;
359        return 0;
360}
361
362/**
363 * udev_enumerate_add_nomatch_subsystem:
364 * @udev_enumerate: context
365 * @subsystem: filter for a subsystem of the device to exclude from the list
366 *
367 * Match only devices not belonging to a certain kernel subsystem.
368 *
369 * Returns: 0 on success, otherwise a negative error value.
370 */
371_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
372{
373        if (udev_enumerate == NULL)
374                return -EINVAL;
375        if (subsystem == NULL)
376                return 0;
377        if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL)
378                return -ENOMEM;
379        return 0;
380}
381
382/**
383 * udev_enumerate_add_match_sysattr:
384 * @udev_enumerate: context
385 * @sysattr: filter for a sys attribute at the device to include in the list
386 * @value: optional value of the sys attribute
387 *
388 * Match only devices with a certain /sys device attribute.
389 *
390 * Returns: 0 on success, otherwise a negative error value.
391 */
392_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
393{
394        if (udev_enumerate == NULL)
395                return -EINVAL;
396        if (sysattr == NULL)
397                return 0;
398        if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL)
399                return -ENOMEM;
400        return 0;
401}
402
403/**
404 * udev_enumerate_add_nomatch_sysattr:
405 * @udev_enumerate: context
406 * @sysattr: filter for a sys attribute at the device to exclude from the list
407 * @value: optional value of the sys attribute
408 *
409 * Match only devices not having a certain /sys device attribute.
410 *
411 * Returns: 0 on success, otherwise a negative error value.
412 */
413_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
414{
415        if (udev_enumerate == NULL)
416                return -EINVAL;
417        if (sysattr == NULL)
418                return 0;
419        if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL)
420                return -ENOMEM;
421        return 0;
422}
423
424static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
425{
426        const char *val = NULL;
427        bool match = false;
428
429        val = udev_device_get_sysattr_value(dev, sysattr);
430        if (val == NULL)
431                goto exit;
432        if (match_val == NULL) {
433                match = true;
434                goto exit;
435        }
436        if (fnmatch(match_val, val, 0) == 0) {
437                match = true;
438                goto exit;
439        }
440exit:
441        return match;
442}
443
444/**
445 * udev_enumerate_add_match_property:
446 * @udev_enumerate: context
447 * @property: filter for a property of the device to include in the list
448 * @value: value of the property
449 *
450 * Match only devices with a certain property.
451 *
452 * Returns: 0 on success, otherwise a negative error value.
453 */
454_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
455{
456        if (udev_enumerate == NULL)
457                return -EINVAL;
458        if (property == NULL)
459                return 0;
460        if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
461                return -ENOMEM;
462        return 0;
463}
464
465/**
466 * udev_enumerate_add_match_tag:
467 * @udev_enumerate: context
468 * @tag: filter for a tag of the device to include in the list
469 *
470 * Match only devices with a certain tag.
471 *
472 * Returns: 0 on success, otherwise a negative error value.
473 */
474_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
475{
476        if (udev_enumerate == NULL)
477                return -EINVAL;
478        if (tag == NULL)
479                return 0;
480        if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL)
481                return -ENOMEM;
482        return 0;
483}
484
485/**
486 * udev_enumerate_add_match_parent:
487 * @udev_enumerate: context
488 * @parent: parent device where to start searching
489 *
490 * Return the devices on the subtree of one given device. The parent
491 * itself is included in the list.
492 *
493 * A reference for the device is held until the udev_enumerate context
494 * is cleaned up.
495 *
496 * Returns: 0 on success, otherwise a negative error value.
497 */
498_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent)
499{
500        if (udev_enumerate == NULL)
501                return -EINVAL;
502        if (parent == NULL)
503                return 0;
504        if (udev_enumerate->parent_match != NULL)
505                udev_device_unref(udev_enumerate->parent_match);
506        udev_enumerate->parent_match = udev_device_ref(parent);
507        return 0;
508}
509
510/**
511 * udev_enumerate_add_match_is_initialized:
512 * @udev_enumerate: context
513 *
514 * Match only devices which udev has set up already. This makes
515 * sure, that the device node permissions and context are properly set
516 * and that network devices are fully renamed.
517 *
518 * Usually, devices which are found in the kernel but not already
519 * handled by udev, have still pending events. Services should subscribe
520 * to monitor events and wait for these devices to become ready, instead
521 * of using uninitialized devices.
522 *
523 * For now, this will not affect devices which do not have a device node
524 * and are not network interfaces.
525 *
526 * Returns: 0 on success, otherwise a negative error value.
527 */
528_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
529{
530        if (udev_enumerate == NULL)
531                return -EINVAL;
532        udev_enumerate->match_is_initialized = true;
533        return 0;
534}
535
536/**
537 * udev_enumerate_add_match_sysname:
538 * @udev_enumerate: context
539 * @sysname: filter for the name of the device to include in the list
540 *
541 * Match only devices with a given /sys device name.
542 *
543 * Returns: 0 on success, otherwise a negative error value.
544 */
545_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
546{
547        if (udev_enumerate == NULL)
548                return -EINVAL;
549        if (sysname == NULL)
550                return 0;
551        if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL)
552                return -ENOMEM;
553        return 0;
554}
555
556static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
557{
558        struct udev_list_entry *list_entry;
559
560        /* skip list */
561        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
562                if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
563                                        udev_list_entry_get_value(list_entry)))
564                        return false;
565        }
566        /* include list */
567        if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
568                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
569                        /* anything that does not match, will make it FALSE */
570                        if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
571                                                 udev_list_entry_get_value(list_entry)))
572                                return false;
573                }
574                return true;
575        }
576        return true;
577}
578
579static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
580{
581        struct udev_list_entry *list_entry;
582        bool match = false;
583
584        /* no match always matches */
585        if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
586                return true;
587
588        /* loop over matches */
589        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
590                const char *match_key = udev_list_entry_get_name(list_entry);
591                const char *match_value = udev_list_entry_get_value(list_entry);
592                struct udev_list_entry *property_entry;
593
594                /* loop over device properties */
595                udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
596                        const char *dev_key = udev_list_entry_get_name(property_entry);
597                        const char *dev_value = udev_list_entry_get_value(property_entry);
598
599                        if (fnmatch(match_key, dev_key, 0) != 0)
600                                continue;
601                        if (match_value == NULL && dev_value == NULL) {
602                                match = true;
603                                goto out;
604                        }
605                        if (match_value == NULL || dev_value == NULL)
606                                continue;
607                        if (fnmatch(match_value, dev_value, 0) == 0) {
608                                match = true;
609                                goto out;
610                        }
611                }
612        }
613out:
614        return match;
615}
616
617static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
618{
619        struct udev_list_entry *list_entry;
620
621        /* no match always matches */
622        if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
623                return true;
624
625        /* loop over matches */
626        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
627                if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
628                        return false;
629
630        return true;
631}
632
633static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
634{
635        if (udev_enumerate->parent_match == NULL)
636                return true;
637
638        return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match));
639}
640
641static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
642{
643        struct udev_list_entry *list_entry;
644
645        if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
646                return true;
647
648        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
649                if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
650                        continue;
651                return true;
652        }
653        return false;
654}
655
656static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
657                                    const char *basedir, const char *subdir1, const char *subdir2)
658{
659        char path[UTIL_PATH_SIZE];
660        size_t l;
661        char *s;
662        DIR *dir;
663        struct dirent *dent;
664
665        s = path;
666        l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
667        if (subdir1 != NULL)
668                l = strpcpyl(&s, l, "/", subdir1, NULL);
669        if (subdir2 != NULL)
670                strpcpyl(&s, l, "/", subdir2, NULL);
671        dir = opendir(path);
672        if (dir == NULL)
673                return -ENOENT;
674        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
675                char syspath[UTIL_PATH_SIZE];
676                struct udev_device *dev;
677
678                if (dent->d_name[0] == '.')
679                        continue;
680
681                if (!match_sysname(udev_enumerate, dent->d_name))
682                        continue;
683
684                strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
685                dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
686                if (dev == NULL)
687                        continue;
688
689                if (udev_enumerate->match_is_initialized) {
690                        /*
691                         * All devices with a device node or network interfaces
692                         * possibly need udev to adjust the device node permission
693                         * or context, or rename the interface before it can be
694                         * reliably used from other processes.
695                         *
696                         * For now, we can only check these types of devices, we
697                         * might not store a database, and have no way to find out
698                         * for all other types of devices.
699                         */
700                        if (!udev_device_get_is_initialized(dev) &&
701                            (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
702                                goto nomatch;
703                }
704                if (!match_parent(udev_enumerate, dev))
705                        goto nomatch;
706                if (!match_tag(udev_enumerate, dev))
707                        goto nomatch;
708                if (!match_property(udev_enumerate, dev))
709                        goto nomatch;
710                if (!match_sysattr(udev_enumerate, dev))
711                        goto nomatch;
712
713                syspath_add(udev_enumerate, udev_device_get_syspath(dev));
714nomatch:
715                udev_device_unref(dev);
716        }
717        closedir(dir);
718        return 0;
719}
720
721static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
722{
723        struct udev_list_entry *list_entry;
724
725        if (!subsystem)
726                return false;
727
728        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
729                if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
730                        return false;
731        }
732
733        if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
734                udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
735                        if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
736                                return true;
737                }
738                return false;
739        }
740
741        return true;
742}
743
744static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
745{
746        char path[UTIL_PATH_SIZE];
747        DIR *dir;
748        struct dirent *dent;
749
750        strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
751        dir = opendir(path);
752        if (dir == NULL)
753                return -1;
754        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
755                if (dent->d_name[0] == '.')
756                        continue;
757                if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
758                        continue;
759                scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
760        }
761        closedir(dir);
762        return 0;
763}
764
765/**
766 * udev_enumerate_add_syspath:
767 * @udev_enumerate: context
768 * @syspath: path of a device
769 *
770 * Add a device to the list of devices, to retrieve it back sorted in dependency order.
771 *
772 * Returns: 0 on success, otherwise a negative error value.
773 */
774_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
775{
776        struct udev_device *udev_device;
777
778        if (udev_enumerate == NULL)
779                return -EINVAL;
780        if (syspath == NULL)
781                return 0;
782        /* resolve to real syspath */
783        udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
784        if (udev_device == NULL)
785                return -EINVAL;
786        syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
787        udev_device_unref(udev_device);
788        return 0;
789}
790
791static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
792{
793        struct udev_list_entry *list_entry;
794
795        /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
796        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
797                DIR *dir;
798                struct dirent *dent;
799                char path[UTIL_PATH_SIZE];
800
801                strscpyl(path, sizeof(path), UDEV_ROOT_RUN "/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
802                dir = opendir(path);
803                if (dir == NULL)
804                        continue;
805                for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
806                        struct udev_device *dev;
807
808                        if (dent->d_name[0] == '.')
809                                continue;
810
811                        dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
812                        if (dev == NULL)
813                                continue;
814
815                        if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
816                                goto nomatch;
817                        if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
818                                goto nomatch;
819                        if (!match_parent(udev_enumerate, dev))
820                                goto nomatch;
821                        if (!match_property(udev_enumerate, dev))
822                                goto nomatch;
823                        if (!match_sysattr(udev_enumerate, dev))
824                                goto nomatch;
825
826                        syspath_add(udev_enumerate, udev_device_get_syspath(dev));
827nomatch:
828                        udev_device_unref(dev);
829                }
830                closedir(dir);
831        }
832        return 0;
833}
834
835static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
836{
837        struct udev_device *dev;
838        int r = 0;
839
840        dev = udev_device_new_from_syspath(enumerate->udev, path);
841        if (dev == NULL)
842                return -ENODEV;
843
844        if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
845                goto nomatch;
846        if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
847                goto nomatch;
848        if (!match_property(enumerate, dev))
849                goto nomatch;
850        if (!match_sysattr(enumerate, dev))
851                goto nomatch;
852
853        syspath_add(enumerate, udev_device_get_syspath(dev));
854        r = 1;
855
856nomatch:
857        udev_device_unref(dev);
858        return r;
859}
860
861static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
862{
863        DIR *d;
864        struct dirent *dent;
865
866        d = opendir(path);
867        if (d == NULL)
868                return -errno;
869
870        for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
871                char *child;
872
873                if (dent->d_name[0] == '.')
874                        continue;
875                if (dent->d_type != DT_DIR)
876                        continue;
877                if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
878                        continue;
879                parent_add_child(enumerate, child);
880                if (maxdepth > 0)
881                        parent_crawl_children(enumerate, child, maxdepth-1);
882                free(child);
883        }
884
885        closedir(d);
886        return 0;
887}
888
889static int scan_devices_children(struct udev_enumerate *enumerate)
890{
891        const char *path;
892
893        path = udev_device_get_syspath(enumerate->parent_match);
894        parent_add_child(enumerate, path);
895        return parent_crawl_children(enumerate, path, 256);
896}
897
898static int scan_devices_all(struct udev_enumerate *udev_enumerate)
899{
900        struct stat statbuf;
901
902        if (stat("/sys/subsystem", &statbuf) == 0) {
903                /* we have /subsystem/, forget all the old stuff */
904                scan_dir(udev_enumerate, "subsystem", "devices", NULL);
905        } else {
906                scan_dir(udev_enumerate, "bus", "devices", NULL);
907                scan_dir(udev_enumerate, "class", NULL, NULL);
908        }
909        return 0;
910}
911
912/**
913 * udev_enumerate_scan_devices:
914 * @udev_enumerate: udev enumeration context
915 *
916 * Scan /sys for all devices which match the given filters. No matches
917 * will return all currently available devices.
918 *
919 * Returns: 0 on success, otherwise a negative error value.
920 **/
921_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
922{
923        if (udev_enumerate == NULL)
924                return -EINVAL;
925
926        /* efficiently lookup tags only, we maintain a reverse-index */
927        if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
928                return scan_devices_tags(udev_enumerate);
929
930        /* walk the subtree of one parent device only */
931        if (udev_enumerate->parent_match != NULL)
932                return scan_devices_children(udev_enumerate);
933
934        /* scan devices of all subsystems */
935        return scan_devices_all(udev_enumerate);
936}
937
938/**
939 * udev_enumerate_scan_subsystems:
940 * @udev_enumerate: udev enumeration context
941 *
942 * Scan /sys for all kernel subsystems, including buses, classes, drivers.
943 *
944 * Returns: 0 on success, otherwise a negative error value.
945 **/
946_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
947{
948        struct stat statbuf;
949        const char *subsysdir;
950
951        if (udev_enumerate == NULL)
952                return -EINVAL;
953
954        /* all kernel modules */
955        if (match_subsystem(udev_enumerate, "module"))
956                scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
957
958        if (stat("/sys/subsystem", &statbuf) == 0)
959                subsysdir = "subsystem";
960        else
961                subsysdir = "bus";
962
963        /* all subsystems (only buses support coldplug) */
964        if (match_subsystem(udev_enumerate, "subsystem"))
965                scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
966
967        /* all subsystem drivers */
968        if (match_subsystem(udev_enumerate, "drivers"))
969                scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
970        return 0;
971}
972