chiark / gitweb /
libudev: device - add device lookup by subsystem:sysname
[elogind.git] / udev / lib / libudev-device.c
index a512537140b19ff76ab46d55518ab4a2d5077f0f..0cb992c9eacb34472957abc44cf8c2c92c0896f9 100644 (file)
@@ -83,6 +83,7 @@ static int device_read_db(struct udev_device *udev_device)
        if ((stats.st_mode & S_IFMT) == S_IFLNK) {
                char target[UTIL_PATH_SIZE];
                int target_len;
+               char *next;
 
                target_len = readlink(filename, target, sizeof(target));
                if (target_len > 0)
@@ -91,8 +92,29 @@ static int device_read_db(struct udev_device *udev_device)
                        info(udev_device->udev, "error reading db link %s: %m\n", filename);
                        return -1;
                }
+
+               next = strchr(target, ' ');
+               if (next != NULL) {
+                       next[0] = '\0';
+                       next = &next[1];
+               }
                if (asprintf(&udev_device->devnode, "%s/%s", udev_get_dev_path(udev_device->udev), target) < 0)
                        return -ENOMEM;
+               while (next != NULL) {
+                       char linkname[UTIL_PATH_SIZE];
+                       const char *lnk;
+
+                       lnk = next;
+                       next = strchr(next, ' ');
+                       if (next != NULL) {
+                               next[0] = '\0';
+                               next = &next[1];
+                       }
+                       util_strlcpy(linkname, udev_get_dev_path(udev_device->udev), sizeof(linkname));
+                       util_strlcat(linkname, "/", sizeof(linkname));
+                       util_strlcat(linkname, lnk, sizeof(linkname));
+                       device_add_devlink(udev_device, linkname);
+               }
                info(udev_device->udev, "device %p filled with db symlink data '%s'\n", udev_device, udev_device->devnode);
                return 0;
        }
@@ -359,6 +381,94 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de
        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;
@@ -404,6 +514,22 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
        return udev_device->parent_device;
 }
 
+struct udev_device *udev_device_get_parent_with_subsystem(struct udev_device *udev_device, const char *subsystem)
+{
+       struct udev_device *parent;
+
+       parent = udev_device_get_parent(udev_device);
+       while (parent != NULL) {
+               const char *parent_subsystem;
+
+               parent_subsystem = udev_device_get_subsystem(parent);
+               if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0)
+                       break;
+               parent = udev_device_get_parent(parent);
+       }
+       return parent;
+}
+
 /**
  * udev_device_get_udev:
  * @udev_device: udev device