+static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
+{
+ struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+ struct udev_list_entry *list_entry;
+
+ /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
+ udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
+ DIR *dir;
+ struct dirent *dent;
+ char path[UTIL_PATH_SIZE];
+
+ util_strscpyl(path, sizeof(path), udev_get_run_path(udev), "/tags/",
+ udev_list_entry_get_name(list_entry), NULL);
+ dir = opendir(path);
+ if (dir == NULL)
+ continue;
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ struct udev_device *dev;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ dev = udev_device_new_from_id_filename(udev_enumerate->udev, dent->d_name);
+ if (dev == NULL)
+ continue;
+
+ if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
+ goto nomatch;
+ if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
+ goto nomatch;
+ if (!match_parent(udev_enumerate, dev))
+ goto nomatch;
+ if (!match_property(udev_enumerate, dev))
+ goto nomatch;
+ if (!match_sysattr(udev_enumerate, dev))
+ goto nomatch;
+
+ syspath_add(udev_enumerate, udev_device_get_syspath(dev));
+nomatch:
+ udev_device_unref(dev);
+ }
+ closedir(dir);
+ }
+ return 0;
+}
+
+static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
+{
+ struct udev_device *dev;
+
+ dev = udev_device_new_from_syspath(enumerate->udev, path);
+ if (dev == NULL)
+ return -ENODEV;
+
+ if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
+ return 0;
+ if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
+ return 0;
+ if (!match_property(enumerate, dev))
+ return 0;
+ if (!match_sysattr(enumerate, dev))
+ return 0;
+
+ syspath_add(enumerate, udev_device_get_syspath(dev));
+ udev_device_unref(dev);
+ return 1;
+}
+
+static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
+{
+ DIR *d;
+ struct dirent *dent;
+
+ d = opendir(path);
+ if (d == NULL)
+ return -errno;
+
+ for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
+ char *child;
+
+ if (dent->d_name[0] == '.')
+ continue;
+ if (dent->d_type != DT_DIR)
+ continue;
+ if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
+ continue;
+ parent_add_child(enumerate, child);
+ if (maxdepth > 0)
+ parent_crawl_children(enumerate, child, maxdepth-1);
+ free(child);
+ }
+
+ closedir(d);
+ return 0;
+}
+
+static int scan_devices_children(struct udev_enumerate *enumerate)
+{
+ const char *path;
+
+ path = udev_device_get_syspath(enumerate->parent_match);
+ parent_add_child(enumerate, path);
+ return parent_crawl_children(enumerate, path, 256);
+}
+
+static int scan_devices_all(struct udev_enumerate *udev_enumerate)