chiark / gitweb /
udevadm: enumerate - update prev pointer properly
[elogind.git] / 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_node sysattr_match_list;
49         struct udev_list_node sysattr_nomatch_list;
50         struct udev_list_node subsystem_match_list;
51         struct udev_list_node subsystem_nomatch_list;
52         struct udev_list_node sysname_match_list;
53         struct udev_list_node properties_match_list;
54         struct udev_list_node tags_match_list;
55         struct udev_list_node devices_list;
56         struct syspath *devices;
57         unsigned int devices_cur;
58         unsigned int devices_max;
59         bool devices_uptodate:1;
60         bool match_is_initialized;
61 };
62
63 /**
64  * udev_enumerate_new:
65  * @udev: udev library context
66  *
67  * Returns: an enumeration context
68  **/
69 struct udev_enumerate *udev_enumerate_new(struct udev *udev)
70 {
71         struct udev_enumerate *udev_enumerate;
72
73         udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
74         if (udev_enumerate == NULL)
75                 return NULL;
76         udev_enumerate->refcount = 1;
77         udev_enumerate->udev = udev;
78         udev_list_init(&udev_enumerate->sysattr_match_list);
79         udev_list_init(&udev_enumerate->sysattr_nomatch_list);
80         udev_list_init(&udev_enumerate->subsystem_match_list);
81         udev_list_init(&udev_enumerate->subsystem_nomatch_list);
82         udev_list_init(&udev_enumerate->sysname_match_list);
83         udev_list_init(&udev_enumerate->properties_match_list);
84         udev_list_init(&udev_enumerate->tags_match_list);
85         udev_list_init(&udev_enumerate->devices_list);
86         return udev_enumerate;
87 }
88
89 /**
90  * udev_enumerate_ref:
91  * @udev_enumerate: context
92  *
93  * Take a reference of a enumeration context.
94  *
95  * Returns: the passed enumeration context
96  **/
97 struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
98 {
99         if (udev_enumerate == NULL)
100                 return NULL;
101         udev_enumerate->refcount++;
102         return udev_enumerate;
103 }
104
105 /**
106  * udev_enumerate_unref:
107  * @udev_enumerate: context
108  *
109  * Drop a reference of an enumeration context. If the refcount reaches zero,
110  * all resources of the enumeration context will be released.
111  **/
112 void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
113 {
114         unsigned int i;
115
116         if (udev_enumerate == NULL)
117                 return;
118         udev_enumerate->refcount--;
119         if (udev_enumerate->refcount > 0)
120                 return;
121         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_match_list);
122         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_nomatch_list);
123         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_match_list);
124         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_nomatch_list);
125         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysname_match_list);
126         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->properties_match_list);
127         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->tags_match_list);
128         udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
129         for (i = 0; i < udev_enumerate->devices_cur; i++)
130                 free(udev_enumerate->devices[i].syspath);
131         free(udev_enumerate->devices);
132         free(udev_enumerate);
133 }
134
135 /**
136  * udev_enumerate_get_udev:
137  * @udev_enumerate: context
138  *
139  * Returns: the udev library context.
140  */
141 struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
142 {
143         if (udev_enumerate == NULL)
144                 return NULL;
145         return udev_enumerate->udev;
146 }
147
148 static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
149 {
150         char *path;
151         struct syspath *entry;
152
153         /* double array size if needed */
154         if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
155                 struct syspath *buf;
156                 unsigned int add;
157
158                 add = udev_enumerate->devices_max;
159                 if (add < 1024)
160                         add = 1024;
161                 buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
162                 if (buf == NULL)
163                         return -ENOMEM;
164                 udev_enumerate->devices = buf;
165                 udev_enumerate->devices_max += add;
166         }
167
168         path = strdup(syspath);
169         if (path == NULL)
170                 return -ENOMEM;
171         entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
172         entry->syspath = path;
173         entry->len = strlen(path);
174         udev_enumerate->devices_cur++;
175         udev_enumerate->devices_uptodate = false;
176         return 0;
177 }
178
179 static int syspath_cmp(const void *p1, const void *p2)
180 {
181         const struct syspath *path1 = p1;
182         const struct syspath *path2 = p2;
183         size_t len;
184         int ret;
185
186         len = MIN(path1->len, path2->len);
187         ret = memcmp(path1->syspath, path2->syspath, len);
188         if (ret == 0) {
189                 if (path1->len < path2->len)
190                         ret = -1;
191                 else if (path1->len > path2->len)
192                         ret = 1;
193         }
194         return ret;
195 }
196
197 /* For devices that should be moved to the absolute end of the list */
198 static bool devices_delay_end(struct udev *udev, const char *syspath)
199 {
200         static const char *delay_device_list[] = {
201                 "/block/md",
202                 "/block/dm-",
203                 NULL
204         };
205         size_t len;
206         int i;
207
208         len = strlen(udev_get_sys_path(udev));
209         for (i = 0; delay_device_list[i] != NULL; i++) {
210                 if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
211                         dbg(udev, "delaying: %s\n", syspath);
212                         return true;
213                 }
214         }
215         return false;
216 }
217
218 /* For devices that should just be moved a little bit later, just
219  * before the point where some common path prefix changes. Returns the
220  * number of characters that make up that common prefix */
221 static size_t devices_delay_later(struct udev *udev, const char *syspath)
222 {
223         const char *c;
224
225         /* For sound cards the control device must be enumerated last
226          * to make sure it's the final device node that gets ACLs
227          * applied. Applications rely on this fact and use ACL changes
228          * on the control node as an indicator that the ACL change of
229          * the entire sound card completed. The kernel makes this
230          * guarantee when creating those devices, and hence we should
231          * too when enumerating them. */
232
233         if ((c = strstr(syspath, "/sound/card"))) {
234                 c += 11;
235                 c += strcspn(c, "/");
236
237                 if (strncmp(c, "/controlC", 9) == 0)
238                         return c - syspath + 1;
239         }
240
241         return 0;
242 }
243
244 /**
245  * udev_enumerate_get_list_entry:
246  * @udev_enumerate: context
247  *
248  * Returns: the first entry of the sorted list of device paths.
249  */
250 struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
251 {
252         if (udev_enumerate == NULL)
253                 return NULL;
254         if (!udev_enumerate->devices_uptodate) {
255                 unsigned int i;
256                 unsigned int max;
257                 struct syspath *prev = NULL, *move_later = NULL;
258                 size_t move_later_prefix = 0;
259
260                 udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
261                 qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
262
263                 max = udev_enumerate->devices_cur;
264                 for (i = 0; i < max; i++) {
265                         struct syspath *entry = &udev_enumerate->devices[i];
266
267                         /* skip duplicated entries */
268                         if (prev != NULL &&
269                             entry->len == prev->len &&
270                             memcmp(entry->syspath, prev->syspath, entry->len) == 0)
271                                 continue;
272                         prev = entry;
273
274                         /* skip to be delayed devices, and add them to the end of the list */
275                         if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
276                                 syspath_add(udev_enumerate, entry->syspath);
277                                 /* need to update prev here for the case realloc() gives
278                                    a different address */
279                                 prev = &udev_enumerate->devices[i];
280                                 continue;
281                         }
282
283                         /* skip to be delayed devices, and move the to
284                          * the point where the prefix changes. We can
285                          * only move one item at a time. */
286                         if (!move_later) {
287                                 move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
288
289                                 if (move_later_prefix > 0) {
290                                         move_later = entry;
291                                         continue;
292                                 }
293                         }
294
295                         if (move_later &&
296                             strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) {
297
298                                 udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
299                                             move_later->syspath, NULL, 0, 0);
300                                 move_later = NULL;
301                         }
302
303                         udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
304                                             entry->syspath, NULL, 0, 0);
305                 }
306
307                 if (move_later)
308                         udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
309                                             move_later->syspath, NULL, 0, 0);
310
311                 /* add and cleanup delayed devices from end of list */
312                 for (i = max; i < udev_enumerate->devices_cur; i++) {
313                         struct syspath *entry = &udev_enumerate->devices[i];
314
315                         udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
316                                             entry->syspath, NULL, 0, 0);
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  * Returns: 0 on success, otherwise a negative error value.
332  */
333 int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
334 {
335         if (udev_enumerate == NULL)
336                 return -EINVAL;
337         if (subsystem == NULL)
338                 return 0;
339         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
340                                 &udev_enumerate->subsystem_match_list, subsystem, NULL, 1, 0) == NULL)
341                 return -ENOMEM;
342         return 0;
343 }
344
345 /**
346  * udev_enumerate_add_nomatch_subsystem:
347  * @udev_enumerate: context
348  * @subsystem: filter for a subsystem of the device to exclude from the list
349  *
350  * Returns: 0 on success, otherwise a negative error value.
351  */
352 int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
353 {
354         if (udev_enumerate == NULL)
355                 return -EINVAL;
356         if (subsystem == NULL)
357                 return 0;
358         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
359                                 &udev_enumerate->subsystem_nomatch_list, subsystem, NULL, 1, 0) == NULL)
360                 return -ENOMEM;
361         return 0;
362 }
363
364 /**
365  * udev_enumerate_add_match_sysattr:
366  * @udev_enumerate: context
367  * @sysattr: filter for a sys attribute at the device to include in the list
368  * @value: optional value of the sys attribute
369  *
370  * Returns: 0 on success, otherwise a negative error value.
371  */
372 int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
373 {
374         if (udev_enumerate == NULL)
375                 return -EINVAL;
376         if (sysattr == NULL)
377                 return 0;
378         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
379                            &udev_enumerate->sysattr_match_list, sysattr, value, 0, 0) == NULL)
380                 return -ENOMEM;
381         return 0;
382 }
383
384 /**
385  * udev_enumerate_add_nomatch_sysattr:
386  * @udev_enumerate: context
387  * @sysattr: filter for a sys attribute at the device to exclude from the list
388  * @value: optional value of the sys attribute
389  *
390  * Returns: 0 on success, otherwise a negative error value.
391  */
392 int udev_enumerate_add_nomatch_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_get_udev(udev_enumerate),
399                            &udev_enumerate->sysattr_nomatch_list, sysattr, value, 0, 0) == NULL)
400                 return -ENOMEM;
401         return 0;
402 }
403
404 static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
405 {
406         const char *val = NULL;
407         bool match = false;
408
409         val = udev_device_get_sysattr_value(dev, sysattr);
410         if (val == NULL)
411                 goto exit;
412         if (match_val == NULL) {
413                 match = true;
414                 goto exit;
415         }
416         if (fnmatch(match_val, val, 0) == 0) {
417                 match = true;
418                 goto exit;
419         }
420 exit:
421         return match;
422 }
423
424 /**
425  * udev_enumerate_add_match_property:
426  * @udev_enumerate: context
427  * @property: filter for a property of the device to include in the list
428  * @value: value of the property
429  *
430  * Returns: 0 on success, otherwise a negative error value.
431  */
432 int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
433 {
434         if (udev_enumerate == NULL)
435                 return -EINVAL;
436         if (property == NULL)
437                 return 0;
438         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
439                                 &udev_enumerate->properties_match_list, property, value, 0, 0) == NULL)
440                 return -ENOMEM;
441         return 0;
442 }
443
444 /**
445  * udev_enumerate_add_match_tag:
446  * @udev_enumerate: context
447  * @tag: filter for a tag of the device to include in the list
448  *
449  * Returns: 0 on success, otherwise a negative error value.
450  */
451 int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
452 {
453         if (udev_enumerate == NULL)
454                 return -EINVAL;
455         if (tag == NULL)
456                 return 0;
457         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
458                                 &udev_enumerate->tags_match_list, tag, NULL, 1, 0) == NULL)
459                 return -ENOMEM;
460         return 0;
461 }
462
463 /**
464  * udev_enumerate_add_match_is_initialized:
465  * @udev_enumerate: context
466  *
467  * Match only devices which udev has set up already. This makes
468  * sure, that the device node permissions and context are properly set
469  * and that network devices are fully renamed.
470  *
471  * Usually, devices which are found in the kernel but not already
472  * handled by udev, have still pending events. Services should subscribe
473  * to monitor events and wait for these devices to become ready, instead
474  * of using uninitialized devices.
475  *
476  * For now, this will not affect devices which do not have a device node
477  * and are not network interfaces.
478  *
479  * Returns: 0 on success, otherwise a negative error value.
480  */
481 int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
482 {
483         if (udev_enumerate == NULL)
484                 return -EINVAL;
485         udev_enumerate->match_is_initialized = true;
486         return 0;
487 }
488
489 /**
490  * udev_enumerate_add_match_sysname:
491  * @udev_enumerate: context
492  * @sysname: filter for the name of the device to include in the list
493  *
494  * Returns: 0 on success, otherwise a negative error value.
495  */
496 int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
497 {
498         if (udev_enumerate == NULL)
499                 return -EINVAL;
500         if (sysname == NULL)
501                 return 0;
502         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
503                                 &udev_enumerate->sysname_match_list, sysname, NULL, 1, 0) == NULL)
504                 return -ENOMEM;
505         return 0;
506 }
507
508 static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
509 {
510         struct udev_list_entry *list_entry;
511
512         /* skip list */
513         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
514                 if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
515                                         udev_list_entry_get_value(list_entry)))
516                         return false;
517         }
518         /* include list */
519         if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
520                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
521                         /* anything that does not match, will make it FALSE */
522                         if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
523                                                  udev_list_entry_get_value(list_entry)))
524                                 return false;
525                 }
526                 return true;
527         }
528         return true;
529 }
530
531 static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
532 {
533         struct udev_list_entry *list_entry;
534         bool match = false;
535
536         /* no match always matches */
537         if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
538                 return true;
539
540         /* loop over matches */
541         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
542                 const char *match_key = udev_list_entry_get_name(list_entry);
543                 const char *match_value = udev_list_entry_get_value(list_entry);
544                 struct udev_list_entry *property_entry;
545
546                 /* loop over device properties */
547                 udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
548                         const char *dev_key = udev_list_entry_get_name(property_entry);
549                         const char *dev_value = udev_list_entry_get_value(property_entry);
550
551                         if (fnmatch(match_key, dev_key, 0) != 0)
552                                 continue;
553                         if (match_value == NULL && dev_value == NULL) {
554                                 match = true;
555                                 goto out;
556                         }
557                         if (match_value == NULL || dev_value == NULL)
558                                 continue;
559                         if (fnmatch(match_value, dev_value, 0) == 0) {
560                                 match = true;
561                                 goto out;
562                         }
563                 }
564         }
565 out:
566         return match;
567 }
568
569 static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
570 {
571         struct udev_list_entry *list_entry;
572
573         /* no match always matches */
574         if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
575                 return true;
576
577         /* loop over matches */
578         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
579                 if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
580                         return false;
581
582         return true;
583 }
584
585 static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
586 {
587         struct udev_list_entry *list_entry;
588
589         if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
590                 return true;
591
592         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
593                 if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
594                         continue;
595                 return true;
596         }
597         return false;
598 }
599
600 static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
601                                     const char *basedir, const char *subdir1, const char *subdir2)
602 {
603         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
604         char path[UTIL_PATH_SIZE];
605         size_t l;
606         char *s;
607         DIR *dir;
608         struct dirent *dent;
609
610         s = path;
611         l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
612         if (subdir1 != NULL)
613                 l = util_strpcpyl(&s, l, "/", subdir1, NULL);
614         if (subdir2 != NULL)
615                 util_strpcpyl(&s, l, "/", subdir2, NULL);
616         dir = opendir(path);
617         if (dir == NULL)
618                 return -ENOENT;
619         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
620                 char syspath[UTIL_PATH_SIZE];
621                 struct udev_device *dev;
622
623                 if (dent->d_name[0] == '.')
624                         continue;
625
626                 if (!match_sysname(udev_enumerate, dent->d_name))
627                         continue;
628
629                 util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
630                 dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
631                 if (dev == NULL)
632                         continue;
633
634                 if (udev_enumerate->match_is_initialized) {
635                         /*
636                          * All devices with a device node or network interfaces
637                          * possibly need udev to adjust the device node permission
638                          * or context, or rename the interface before it can be
639                          * reliably used from other processes.
640                          *
641                          * For now, we can only check these types of devices, we
642                          * might not store a database, and have no way to find out
643                          * for all other types of devices.
644                          */
645                         if (!udev_device_get_is_initialized(dev) &&
646                             (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
647                                 goto nomatch;
648                 }
649                 if (!match_tag(udev_enumerate, dev))
650                         goto nomatch;
651                 if (!match_property(udev_enumerate, dev))
652                         goto nomatch;
653                 if (!match_sysattr(udev_enumerate, dev))
654                         goto nomatch;
655
656                 syspath_add(udev_enumerate, udev_device_get_syspath(dev));
657 nomatch:
658                 udev_device_unref(dev);
659         }
660         closedir(dir);
661         return 0;
662 }
663
664 static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
665 {
666         struct udev_list_entry *list_entry;
667
668         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
669                 if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
670                         return false;
671         }
672         if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
673                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
674                         if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
675                                 return true;
676                 }
677                 return false;
678         }
679         return true;
680 }
681
682 static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
683 {
684         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
685
686         char path[UTIL_PATH_SIZE];
687         DIR *dir;
688         struct dirent *dent;
689
690         util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
691         dir = opendir(path);
692         if (dir == NULL)
693                 return -1;
694         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
695                 if (dent->d_name[0] == '.')
696                         continue;
697                 if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
698                         continue;
699                 scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
700         }
701         closedir(dir);
702         return 0;
703 }
704
705 /**
706  * udev_enumerate_add_syspath:
707  * @udev_enumerate: context
708  * @syspath: path of a device
709  *
710  * Add a device to the list of devices, to retrieve it back sorted in dependency order.
711  *
712  * Returns: 0 on success, otherwise a negative error value.
713  */
714 int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
715 {
716         struct udev_device *udev_device;
717
718         if (udev_enumerate == NULL)
719                 return -EINVAL;
720         if (syspath == NULL)
721                 return 0;
722         /* resolve to real syspath */
723         udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
724         if (udev_device == NULL)
725                 return -EINVAL;
726         syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
727         udev_device_unref(udev_device);
728         return 0;
729 }
730
731 /**
732  * udev_enumerate_scan_devices:
733  * @udev_enumerate: udev enumeration context
734  *
735  * Returns: 0 on success, otherwise a negative error value.
736  **/
737 int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
738 {
739         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
740         char base[UTIL_PATH_SIZE];
741         struct stat statbuf;
742
743         if (udev_enumerate == NULL)
744                 return -EINVAL;
745
746         if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) {
747                 struct udev_list_entry *list_entry;
748
749                 /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
750                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
751                         DIR *dir;
752                         struct dirent *dent;
753                         char path[UTIL_PATH_SIZE];
754
755                         util_strscpyl(path, sizeof(path), udev_get_dev_path(udev), "/.udev/tags/",
756                                       udev_list_entry_get_name(list_entry), NULL);
757                         dir = opendir(path);
758                         if (dir == NULL)
759                                 continue;
760                         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
761                                 struct udev_device *dev;
762
763                                 if (dent->d_name[0] == '.')
764                                         continue;
765
766                                 dev = udev_device_new_from_id_filename(udev_enumerate->udev, dent->d_name);
767                                 if (dev == NULL)
768                                         continue;
769                                 syspath_add(udev_enumerate, udev_device_get_syspath(dev));
770                                 udev_device_unref(dev);
771                         }
772                         closedir(dir);
773                 }
774         } else {
775                 util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
776                 if (stat(base, &statbuf) == 0) {
777                         /* we have /subsystem/, forget all the old stuff */
778                         dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
779                         scan_dir(udev_enumerate, "subsystem", "devices", NULL);
780                 } else {
781                 dbg(udev, "searching '/bus/*/devices/*' dir\n");
782                         scan_dir(udev_enumerate, "bus", "devices", NULL);
783                         dbg(udev, "searching '/class/*' dir\n");
784                         scan_dir(udev_enumerate, "class", NULL, NULL);
785                 }
786         }
787
788         return 0;
789 }
790
791 /**
792  * udev_enumerate_scan_subsystems:
793  * @udev_enumerate: udev enumeration context
794  *
795  * Returns: 0 on success, otherwise a negative error value.
796  **/
797 int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
798 {
799         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
800         char base[UTIL_PATH_SIZE];
801         struct stat statbuf;
802         const char *subsysdir;
803
804         if (udev_enumerate == NULL)
805                 return -EINVAL;
806
807         util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
808         if (stat(base, &statbuf) == 0)
809                 subsysdir = "subsystem";
810         else
811                 subsysdir = "bus";
812         if (match_subsystem(udev_enumerate, "subsystem")) {
813                 dbg(udev, "searching '%s/*' dir\n", subsysdir);
814                 scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
815         }
816         if (match_subsystem(udev_enumerate, "drivers")) {
817                 dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
818                 scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
819         }
820         return 0;
821 }