+ /* fallback to search sys devices for the major/minor */
+ if (type == 'b')
+ udev_enumerate_add_match_subsystem(udev_enumerate, "block");
+ else if (type == 'c')
+ udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
+ udev_enumerate_scan_devices(udev_enumerate);
+ udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
+ struct udev_device *device_loop;
+
+ device_loop = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
+ if (device_loop != NULL) {
+ if (udev_device_get_devnum(device_loop) == devnum) {
+ if (type == 'b' && strcmp(udev_device_get_subsystem(device_loop), "block") != 0)
+ continue;
+ if (type == 'c' && strcmp(udev_device_get_subsystem(device_loop), "block") == 0)
+ continue;
+ device = device_loop;
+ break;
+ }
+ udev_device_unref(device_loop);
+ }
+ }
+ udev_enumerate_unref(udev_enumerate);
+ return device;
+}
+
+struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
+{
+ size_t sys_path_len;
+ char path_full[UTIL_PATH_SIZE];
+ char *path;
+ struct stat statbuf;
+
+ sys_path_len = util_strlcpy(path_full, udev_get_sys_path(udev), sizeof(path_full));
+ path = &path_full[sys_path_len];
+
+ if (strcmp(subsystem, "subsystem") == 0) {
+ util_strlcpy(path, "/subsystem/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+
+ util_strlcpy(path, "/bus/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+
+ util_strlcpy(path, "/class/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+ goto out;
+ }
+
+ if (strcmp(subsystem, "module") == 0) {
+ util_strlcpy(path, "/module/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+ goto out;
+ }
+
+ if (strcmp(subsystem, "drivers") == 0) {
+ char subsys[UTIL_NAME_SIZE];
+ char *driver;
+
+ util_strlcpy(subsys, sysname, sizeof(subsys));
+ driver = strchr(subsys, ':');
+ if (driver != NULL) {
+ driver[0] = '\0';
+ driver = &driver[1];
+ util_strlcpy(path, "/subsystem/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, subsys, sizeof(path_full) - sys_path_len);
+ util_strlcat(path, "/drivers/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, driver, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+
+ util_strlcpy(path, "/bus/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, subsys, sizeof(path_full) - sys_path_len);
+ util_strlcat(path, "/drivers/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, driver, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+ }
+ goto out;
+ }
+
+ util_strlcpy(path, "/subsystem/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, subsystem, sizeof(path_full) - sys_path_len);
+ util_strlcat(path, "/devices/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+
+ util_strlcpy(path, "/bus/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, subsystem, sizeof(path_full) - sys_path_len);
+ util_strlcat(path, "/devices/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+
+ util_strlcpy(path, "/class/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, subsystem, sizeof(path_full) - sys_path_len);
+ util_strlcat(path, "/", sizeof(path_full) - sys_path_len);
+ util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+ if (stat(path_full, &statbuf) == 0)
+ goto found;
+out:
+ return NULL;
+found:
+ return udev_device_new_from_syspath(udev, path_full);
+}
+
+static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
+{
+ struct udev_device *udev_device_parent = NULL;
+ char path[UTIL_PATH_SIZE];
+ const char *subdir;
+
+ /* follow "device" link in deprecated sys layout */
+ if (strncmp(udev_device->devpath, "/class/", 7) == 0 ||
+ strncmp(udev_device->devpath, "/block/", 7) == 0) {
+ util_strlcpy(path, udev_device->syspath, sizeof(path));
+ util_strlcat(path, "/device", sizeof(path));
+ if (util_resolve_sys_link(udev_device->udev, path, sizeof(path)) == 0)
+ udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
+ return udev_device_parent;
+ }
+
+ util_strlcpy(path, udev_device->syspath, sizeof(path));
+ subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];