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