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