2 * libudev - interface to udev device information
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
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.
22 #include <sys/param.h>
25 #include "libudev-private.h"
28 * SECTION:libudev-enumerate
29 * @short_description: lookup and sort sys devices
31 * Lookup devices in the sys filesystem, filter devices by properties,
32 * and return a sorted list of devices.
43 * Opaque object representing one device lookup/sort context.
45 struct udev_enumerate {
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;
63 * @udev: udev library context
65 * Returns: an enumeration context
67 struct udev_enumerate *udev_enumerate_new(struct udev *udev)
69 struct udev_enumerate *udev_enumerate;
71 udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
72 if (udev_enumerate == 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;
88 * @udev_enumerate: context
90 * Take a reference of a enumeration context.
92 * Returns: the passed enumeration context
94 struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
96 if (udev_enumerate == NULL)
98 udev_enumerate->refcount++;
99 return udev_enumerate;
103 * udev_enumerate_unref:
104 * @udev_enumerate: context
106 * Drop a reference of an enumeration context. If the refcount reaches zero,
107 * all resources of the enumeration context will be released.
109 void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
113 if (udev_enumerate == NULL)
115 udev_enumerate->refcount--;
116 if (udev_enumerate->refcount > 0)
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);
132 * udev_enumerate_get_udev:
133 * @udev_enumerate: context
135 * Returns: the udev library context.
137 struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
139 if (udev_enumerate == NULL)
141 return udev_enumerate->udev;
144 static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
147 struct syspath *entry;
149 /* double array size if needed */
150 if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
154 add = udev_enumerate->devices_max;
157 buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
160 udev_enumerate->devices = buf;
161 udev_enumerate->devices_max += add;
164 path = strdup(syspath);
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;
175 static int syspath_cmp(const void *p1, const void *p2)
177 const struct syspath *path1 = p1;
178 const struct syspath *path2 = p2;
182 len = MIN(path1->len, path2->len);
183 ret = memcmp(path1->syspath, path2->syspath, len);
185 if (path1->len < path2->len)
187 else if (path1->len > path2->len)
193 static int devices_delay(struct udev *udev, const char *syspath)
195 static const char *delay_device_list[] = {
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);
214 * udev_enumerate_get_list_entry:
215 * @udev_enumerate: context
217 * Returns: the first entry of the sorted list of device paths.
219 struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
221 if (udev_enumerate == NULL)
223 if (!udev_enumerate->devices_uptodate) {
226 struct syspath *prev = NULL;
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);
231 max = udev_enumerate->devices_cur;
232 for (i = 0; i < max; i++) {
233 struct syspath *entry = &udev_enumerate->devices[i];
235 /* skip duplicated entries */
237 entry->len == prev->len &&
238 memcmp(entry->syspath, prev->syspath, entry->len) == 0)
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);
248 udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
249 entry->syspath, NULL, 0, 0);
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];
255 udev_list_entry_add(udev_enumerate->udev, &udev_enumerate->devices_list,
256 entry->syspath, NULL, 0, 0);
257 free(entry->syspath);
259 udev_enumerate->devices_cur = max;
261 udev_enumerate->devices_uptodate = true;
263 return udev_list_get_entry(&udev_enumerate->devices_list);
267 * udev_enumerate_add_match_subsystem:
268 * @udev_enumerate: context
269 * @subsystem: filter for a subsystem of the device to include in the list
271 * Returns: 0 on success, otherwise a negative error value.
273 int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
275 if (udev_enumerate == NULL)
277 if (subsystem == NULL)
279 if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
280 &udev_enumerate->subsystem_match_list, subsystem, NULL, 1, 0) == NULL)
286 * udev_enumerate_add_nomatch_subsystem:
287 * @udev_enumerate: context
288 * @subsystem: filter for a subsystem of the device to exclude from the list
290 * Returns: 0 on success, otherwise a negative error value.
292 int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
294 if (udev_enumerate == NULL)
296 if (subsystem == NULL)
298 if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
299 &udev_enumerate->subsystem_nomatch_list, subsystem, NULL, 1, 0) == NULL)
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
310 * Returns: 0 on success, otherwise a negative error value.
312 int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
314 if (udev_enumerate == NULL)
318 if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
319 &udev_enumerate->sysattr_match_list, sysattr, value, 0, 0) == NULL)
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
330 * Returns: 0 on success, otherwise a negative error value.
332 int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
334 if (udev_enumerate == NULL)
338 if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
339 &udev_enumerate->sysattr_nomatch_list, sysattr, value, 0, 0) == NULL)
344 static int match_sysattr_value(struct udev *udev, const char *syspath, const char *sysattr, const char *match_val)
346 struct udev_device *device;
347 const char *val = NULL;
350 device = udev_device_new_from_syspath(udev, syspath);
353 val = udev_device_get_sysattr_value(device, sysattr);
356 if (match_val == NULL) {
360 if (fnmatch(match_val, val, 0) == 0) {
365 udev_device_unref(device);
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
375 * Returns: 0 on success, otherwise a negative error value.
377 int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
379 if (udev_enumerate == NULL)
381 if (property == NULL)
383 if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
384 &udev_enumerate->properties_match_list, property, value, 0, 0) == NULL)
390 * udev_enumerate_add_match_sysname:
391 * @udev_enumerate: context
392 * @sysname: filter for the name of the device to include in the list
394 * Returns: 0 on success, otherwise a negative error value.
396 int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
398 if (udev_enumerate == NULL)
402 if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
403 &udev_enumerate->sysname_match_list, sysname, NULL, 1, 0) == NULL)
408 static int match_sysattr(struct udev_enumerate *udev_enumerate, const char *syspath)
410 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
411 struct udev_list_entry *list_entry;
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)))
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)))
434 static int match_property(struct udev_enumerate *udev_enumerate, const char *syspath)
436 struct udev_device *dev;
437 struct udev_list_entry *list_entry;
440 /* no match always matches */
441 if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
444 /* no device does not match */
445 dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
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;
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);
460 if (fnmatch(match_key, dev_key, 0) != 0)
462 if (match_value == NULL && dev_value == NULL) {
466 if (match_value == NULL || dev_value == NULL)
468 if (fnmatch(match_value, dev_value, 0) == 0) {
475 udev_device_unref(dev);
479 static int match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
481 struct udev_list_entry *list_entry;
483 if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
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)
494 static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
495 const char *basedir, const char *subdir1, const char *subdir2)
497 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
498 char path[UTIL_PATH_SIZE];
505 l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
507 l = util_strpcpyl(&s, l, "/", subdir1, NULL);
509 l = util_strpcpyl(&s, l, "/", subdir2, NULL);
513 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
514 char syspath[UTIL_PATH_SIZE];
515 char filename[UTIL_PATH_SIZE];
518 if (dent->d_name[0] == '.')
520 if (!match_sysname(udev_enumerate, dent->d_name))
523 util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
524 if (lstat(syspath, &statbuf) != 0)
526 if (S_ISREG(statbuf.st_mode))
528 if (S_ISLNK(statbuf.st_mode))
529 util_resolve_sys_link(udev, syspath, sizeof(syspath));
531 util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
532 if (stat(filename, &statbuf) != 0)
534 if (!match_sysattr(udev_enumerate, syspath))
536 if (!match_property(udev_enumerate, syspath))
538 syspath_add(udev_enumerate, syspath);
544 static int match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
546 struct udev_list_entry *list_entry;
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)
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)
562 static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
564 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
566 char path[UTIL_PATH_SIZE];
570 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
574 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
575 if (dent->d_name[0] == '.')
577 if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
579 scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
586 * udev_enumerate_add_syspath:
587 * @udev_enumerate: context
588 * @syspath: path of a device
590 * Add a device to the list of devices, to retrieve it back sorted in dependency order.
592 * Returns: 0 on success, otherwise a negative error value.
594 int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
596 struct udev_device *udev_device;
598 if (udev_enumerate == NULL)
602 /* resolve to real syspath */
603 udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
604 if (udev_device == NULL)
606 syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
607 udev_device_unref(udev_device);
612 * udev_enumerate_scan_devices:
613 * @udev_enumerate: udev enumeration context
615 * Returns: 0 on success, otherwise a negative error value.
617 int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
619 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
620 char base[UTIL_PATH_SIZE];
623 if (udev_enumerate == NULL)
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);
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");
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");
652 * udev_enumerate_scan_subsystems:
653 * @udev_enumerate: udev enumeration context
655 * Returns: 0 on success, otherwise a negative error value.
657 int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
659 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
660 char base[UTIL_PATH_SIZE];
662 const char *subsysdir;
664 if (udev_enumerate == NULL)
666 util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
667 if (stat(base, &statbuf) == 0)
668 subsysdir = "subsystem";
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);
675 if (match_subsystem(udev_enumerate, "drivers")) {
676 dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
677 scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");