chiark / gitweb /
udevadm: trigger - add --sysname-match=
[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 static int devices_delay(struct udev *udev, const char *syspath)
194 {
195         static const char *delay_device_list[] = {
196                 "/block/md",
197                 "/block/dm-",
198                 NULL
199         };
200         size_t len;
201         int i;
202
203         len = strlen(udev_get_sys_path(udev));
204         for (i = 0; delay_device_list[i] != NULL; i++) {
205                 if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
206                         dbg(udev, "delaying: %s\n", syspath);
207                         return 1;
208                 }
209         }
210         return 0;
211 }
212
213 /**
214  * udev_enumerate_get_list_entry:
215  * @udev_enumerate: context
216  *
217  * Returns: the first entry of the sorted list of device paths.
218  */
219 struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
220 {
221         if (udev_enumerate == NULL)
222                 return NULL;
223         if (!udev_enumerate->devices_uptodate) {
224                 unsigned int i;
225                 unsigned int max;
226                 struct syspath *prev = NULL;
227
228                 udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
229                 qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
230
231                 max = udev_enumerate->devices_cur;
232                 for (i = 0; i < max; i++) {
233                         struct syspath *entry = &udev_enumerate->devices[i];
234
235                         /* skip duplicated entries */
236                         if (prev != NULL &&
237                             entry->len == prev->len &&
238                             memcmp(entry->syspath, prev->syspath, entry->len) == 0)
239                                 continue;
240                         prev = entry;
241
242                         /* skip to be delayed devices, and add them to the end of the list */
243                         if (devices_delay(udev_enumerate->udev, entry->syspath)) {
244                                 syspath_add(udev_enumerate, entry->syspath);
245                                 continue;
246                         }
247
248                         udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
249                                             entry->syspath, NULL, 0, 0);
250                 }
251                 /* add and cleanup delayed devices from end of list */
252                 for (i = max; i < udev_enumerate->devices_cur; i++) {
253                         struct syspath *entry = &udev_enumerate->devices[i];
254
255                         udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
256                                             entry->syspath, NULL, 0, 0);
257                         free(entry->syspath);
258                 }
259                 udev_enumerate->devices_cur = max;
260
261                 udev_enumerate->devices_uptodate = true;
262         }
263         return udev_list_get_entry(&udev_enumerate->devices_list);
264 }
265
266 /**
267  * udev_enumerate_add_match_subsystem:
268  * @udev_enumerate: context
269  * @subsystem: filter for a subsystem of the device to include in the list
270  *
271  * Returns: 0 on success, otherwise a negative error value.
272  */
273 int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
274 {
275         if (udev_enumerate == NULL)
276                 return -EINVAL;
277         if (subsystem == NULL)
278                 return 0;
279         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
280                                 &udev_enumerate->subsystem_match_list, subsystem, NULL, 1, 0) == NULL)
281                 return -ENOMEM;
282         return 0;
283 }
284
285 /**
286  * udev_enumerate_add_nomatch_subsystem:
287  * @udev_enumerate: context
288  * @subsystem: filter for a subsystem of the device to exclude from the list
289  *
290  * Returns: 0 on success, otherwise a negative error value.
291  */
292 int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
293 {
294         if (udev_enumerate == NULL)
295                 return -EINVAL;
296         if (subsystem == NULL)
297                 return 0;
298         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
299                                 &udev_enumerate->subsystem_nomatch_list, subsystem, NULL, 1, 0) == NULL)
300                 return -ENOMEM;
301         return 0;
302 }
303
304 /**
305  * udev_enumerate_add_match_sysattr:
306  * @udev_enumerate: context
307  * @sysattr: filter for a sys attribute at the device to include in the list
308  * @value: optional value of the sys attribute
309  *
310  * Returns: 0 on success, otherwise a negative error value.
311  */
312 int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
313 {
314         if (udev_enumerate == NULL)
315                 return -EINVAL;
316         if (sysattr == NULL)
317                 return 0;
318         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
319                            &udev_enumerate->sysattr_match_list, sysattr, value, 0, 0) == NULL)
320                 return -ENOMEM;
321         return 0;
322 }
323
324 /**
325  * udev_enumerate_add_nomatch_sysattr:
326  * @udev_enumerate: context
327  * @sysattr: filter for a sys attribute at the device to exclude from the list
328  * @value: optional value of the sys attribute
329  *
330  * Returns: 0 on success, otherwise a negative error value.
331  */
332 int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
333 {
334         if (udev_enumerate == NULL)
335                 return -EINVAL;
336         if (sysattr == NULL)
337                 return 0;
338         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
339                            &udev_enumerate->sysattr_nomatch_list, sysattr, value, 0, 0) == NULL)
340                 return -ENOMEM;
341         return 0;
342 }
343
344 static int match_sysattr_value(struct udev *udev, const char *syspath, const char *sysattr, const char *match_val)
345 {
346         struct udev_device *device;
347         const char *val = NULL;
348         bool match = false;
349
350         device = udev_device_new_from_syspath(udev, syspath);
351         if (device == NULL)
352                 return -EINVAL;
353         val = udev_device_get_sysattr_value(device, sysattr);
354         if (val == NULL)
355                 goto exit;
356         if (match_val == NULL) {
357                 match = true;
358                 goto exit;
359         }
360         if (fnmatch(match_val, val, 0) == 0) {
361                 match = true;
362                 goto exit;
363         }
364 exit:
365         udev_device_unref(device);
366         return match;
367 }
368
369 /**
370  * udev_enumerate_add_match_property:
371  * @udev_enumerate: context
372  * @property: filter for a property of the device to include in the list
373  * @value: value of the property
374  *
375  * Returns: 0 on success, otherwise a negative error value.
376  */
377 int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
378 {
379         if (udev_enumerate == NULL)
380                 return -EINVAL;
381         if (property == NULL)
382                 return 0;
383         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
384                                 &udev_enumerate->properties_match_list, property, value, 0, 0) == NULL)
385                 return -ENOMEM;
386         return 0;
387 }
388
389 /**
390  * udev_enumerate_add_match_sysname:
391  * @udev_enumerate: context
392  * @sysname: filter for the name of the device to include in the list
393  *
394  * Returns: 0 on success, otherwise a negative error value.
395  */
396 int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
397 {
398         if (udev_enumerate == NULL)
399                 return -EINVAL;
400         if (sysname == NULL)
401                 return 0;
402         if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
403                                 &udev_enumerate->sysname_match_list, sysname, NULL, 1, 0) == NULL)
404                 return -ENOMEM;
405         return 0;
406 }
407
408 static int match_sysattr(struct udev_enumerate *udev_enumerate, const char *syspath)
409 {
410         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
411         struct udev_list_entry *list_entry;
412
413         /* skip list */
414         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
415                 if (match_sysattr_value(udev, syspath,
416                                      udev_list_entry_get_name(list_entry),
417                                      udev_list_entry_get_value(list_entry)))
418                         return 0;
419         }
420         /* include list */
421         if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
422                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
423                         /* anything that does not match, will make it FALSE */
424                         if (!match_sysattr_value(udev, syspath,
425                                               udev_list_entry_get_name(list_entry),
426                                               udev_list_entry_get_value(list_entry)))
427                                 return 0;
428                 }
429                 return 1;
430         }
431         return 1;
432 }
433
434 static int match_property(struct udev_enumerate *udev_enumerate, const char *syspath)
435 {
436         struct udev_device *dev;
437         struct udev_list_entry *list_entry;
438         int match = false;
439
440         /* no match always matches */
441         if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
442                 return 1;
443
444         /* no device does not match */
445         dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
446         if (dev == NULL)
447                 return 0;
448
449         /* loop over matches */
450         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
451                 const char *match_key = udev_list_entry_get_name(list_entry);
452                 const char *match_value = udev_list_entry_get_value(list_entry);
453                 struct udev_list_entry *property_entry;
454
455                 /* loop over device properties */
456                 udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
457                         const char *dev_key = udev_list_entry_get_name(property_entry);
458                         const char *dev_value = udev_list_entry_get_value(property_entry);
459
460                         if (fnmatch(match_key, dev_key, 0) != 0)
461                                 continue;
462                         if (match_value == NULL && dev_value == NULL) {
463                                 match = true;
464                                 goto out;
465                         }
466                         if (match_value == NULL || dev_value == NULL)
467                                 continue;
468                         if (fnmatch(match_value, dev_value, 0) == 0) {
469                                 match = true;
470                                 goto out;
471                         }
472                 }
473         }
474 out:
475         udev_device_unref(dev);
476         return match;
477 }
478
479 static int match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
480 {
481         struct udev_list_entry *list_entry;
482
483         if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
484                 return 1;
485
486         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
487                 if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
488                         continue;
489                 return 1;
490         }
491         return 0;
492 }
493
494 static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
495                                     const char *basedir, const char *subdir1, const char *subdir2)
496 {
497         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
498         char path[UTIL_PATH_SIZE];
499         size_t l;
500         char *s;
501         DIR *dir;
502         struct dirent *dent;
503
504         s = path;
505         l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
506         if (subdir1 != NULL)
507                 l = util_strpcpyl(&s, l, "/", subdir1, NULL);
508         if (subdir2 != NULL)
509                 l = util_strpcpyl(&s, l, "/", subdir2, NULL);
510         dir = opendir(path);
511         if (dir == NULL)
512                 return -1;
513         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
514                 char syspath[UTIL_PATH_SIZE];
515                 char filename[UTIL_PATH_SIZE];
516                 struct stat statbuf;
517
518                 if (dent->d_name[0] == '.')
519                         continue;
520                 if (!match_sysname(udev_enumerate, dent->d_name))
521                         continue;
522
523                 util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
524                 if (lstat(syspath, &statbuf) != 0)
525                         continue;
526                 if (S_ISREG(statbuf.st_mode))
527                         continue;
528                 if (S_ISLNK(statbuf.st_mode))
529                         util_resolve_sys_link(udev, syspath, sizeof(syspath));
530
531                 util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
532                 if (stat(filename, &statbuf) != 0)
533                         continue;
534                 if (!match_sysattr(udev_enumerate, syspath))
535                         continue;
536                 if (!match_property(udev_enumerate, syspath))
537                         continue;
538                 syspath_add(udev_enumerate, syspath);
539         }
540         closedir(dir);
541         return 0;
542 }
543
544 static int match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
545 {
546         struct udev_list_entry *list_entry;
547
548         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
549                 if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
550                         return 0;
551         }
552         if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
553                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
554                         if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
555                                 return 1;
556                 }
557                 return 0;
558         }
559         return 1;
560 }
561
562 static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
563 {
564         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
565
566         char path[UTIL_PATH_SIZE];
567         DIR *dir;
568         struct dirent *dent;
569
570         util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
571         dir = opendir(path);
572         if (dir == NULL)
573                 return -1;
574         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
575                 if (dent->d_name[0] == '.')
576                         continue;
577                 if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
578                         continue;
579                 scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
580         }
581         closedir(dir);
582         return 0;
583 }
584
585 /**
586  * udev_enumerate_add_syspath:
587  * @udev_enumerate: context
588  * @syspath: path of a device
589  *
590  * Add a device to the list of devices, to retrieve it back sorted in dependency order.
591  *
592  * Returns: 0 on success, otherwise a negative error value.
593  */
594 int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
595 {
596         struct udev_device *udev_device;
597
598         if (udev_enumerate == NULL)
599                 return -EINVAL;
600         if (syspath == NULL)
601                 return 0;
602         /* resolve to real syspath */
603         udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
604         if (udev_device == NULL)
605                 return -EINVAL;
606         syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
607         udev_device_unref(udev_device);
608         return 0;
609 }
610
611 /**
612  * udev_enumerate_scan_devices:
613  * @udev_enumerate: udev enumeration context
614  *
615  * Returns: 0 on success, otherwise a negative error value.
616  **/
617 int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
618 {
619         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
620         char base[UTIL_PATH_SIZE];
621         struct stat statbuf;
622
623         if (udev_enumerate == NULL)
624                 return -EINVAL;
625         util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
626         if (stat(base, &statbuf) == 0) {
627                 /* we have /subsystem/, forget all the old stuff */
628                 dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
629                 scan_dir(udev_enumerate, "subsystem", "devices", NULL);
630         } else {
631                 dbg(udev, "searching '/bus/*/devices/*' dir\n");
632                 scan_dir(udev_enumerate, "bus", "devices", NULL);
633                 dbg(udev, "searching '/class/*' dir\n");
634                 scan_dir(udev_enumerate, "class", NULL, NULL);
635                 /* if block isn't a class, scan /block/ */
636                 util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/class/block", NULL);
637                 if (stat(base, &statbuf) != 0) {
638                         if (match_subsystem(udev_enumerate, "block")) {
639                                 dbg(udev, "searching '/block/*' dir\n");
640                                 /* scan disks */
641                                 scan_dir_and_add_devices(udev_enumerate, "block", NULL, NULL);
642                                 /* scan partitions */
643                                 dbg(udev, "searching '/block/*/*' dir\n");
644                                 scan_dir(udev_enumerate, "block", NULL, "block");
645                         }
646                 }
647         }
648         return 0;
649 }
650
651 /**
652  * udev_enumerate_scan_subsystems:
653  * @udev_enumerate: udev enumeration context
654  *
655  * Returns: 0 on success, otherwise a negative error value.
656  **/
657 int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
658 {
659         struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
660         char base[UTIL_PATH_SIZE];
661         struct stat statbuf;
662         const char *subsysdir;
663
664         if (udev_enumerate == NULL)
665                 return -EINVAL;
666         util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
667         if (stat(base, &statbuf) == 0)
668                 subsysdir = "subsystem";
669         else
670                 subsysdir = "bus";
671         if (match_subsystem(udev_enumerate, "subsystem")) {
672                 dbg(udev, "searching '%s/*' dir\n", subsysdir);
673                 scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
674         }
675         if (match_subsystem(udev_enumerate, "drivers")) {
676                 dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
677                 scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
678         }
679         return 0;
680 }