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