chiark / gitweb /
libudev: use 4096 bytes buffer for attribute reading
[elogind.git] / udev / lib / libudev-device.c
index c4714e4088d1a8dc6f1b5b0cc774fab307bf6e12..fc881fb3fdacf27c5d194de6da0825254bc96df8 100644 (file)
@@ -40,6 +40,7 @@ struct udev_device {
        const char *sysnum;
        char *devnode;
        char *subsystem;
+       char *devtype;
        char *driver;
        char *action;
        char *devpath_old;
@@ -59,6 +60,7 @@ struct udev_device {
        dev_t devnum;
        unsigned int parent_set:1;
        unsigned int subsystem_set:1;
+       unsigned int devtype_set:1;
        unsigned int devlinks_uptodate:1;
        unsigned int envp_uptodate:1;
        unsigned int driver_set:1;
@@ -204,7 +206,9 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
                        continue;
                pos[0] = '\0';
 
-               if (strncmp(line, "MAJOR=", 6) == 0)
+               if (strncmp(line, "DEVTYPE=", 8) == 0)
+                       udev_device_set_devtype(udev_device, &line[8]);
+               else if (strncmp(line, "MAJOR=", 6) == 0)
                        maj = strtoull(&line[6], NULL, 10);
                else if (strncmp(line, "MINOR=", 6) == 0)
                        min = strtoull(&line[6], NULL, 10);
@@ -537,17 +541,26 @@ 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 *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
 {
        struct udev_device *parent;
 
+       if (subsystem == NULL)
+               return NULL;
+
        parent = udev_device_get_parent(udev_device);
        while (parent != NULL) {
                const char *parent_subsystem;
+               const char *parent_devtype;
 
                parent_subsystem = udev_device_get_subsystem(parent);
-               if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0)
-                       break;
+               if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) {
+                       if (devtype == NULL)
+                               break;
+                       parent_devtype = udev_device_get_devtype(parent);
+                       if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0)
+                               break;
+               }
                parent = udev_device_get_parent(parent);
        }
        return parent;
@@ -605,6 +618,7 @@ void udev_device_unref(struct udev_device *udev_device)
        free(udev_device->sysname);
        free(udev_device->devnode);
        free(udev_device->subsystem);
+       free(udev_device->devtype);
        udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
        udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list);
        free(udev_device->action);
@@ -723,6 +737,26 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device)
        return udev_device->subsystem;
 }
 
+/**
+ * udev_device_get_devtype:
+ * @udev_device: udev device
+ *
+ * Retrieve the devtype string of the udev device.
+ *
+ * Returns: the devtype name of the udev device, or #NULL if it can not be determined
+ **/
+const char *udev_device_get_devtype(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->devtype_set) {
+               udev_device->devtype_set = 1;
+               if (!udev_device->info_loaded)
+                       udev_device_read_uevent_file(udev_device);
+       }
+       return udev_device->devtype;
+}
+
 /**
  * udev_device_get_devlinks_list_entry:
  * @udev_device: udev device
@@ -828,7 +862,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
 {
        struct udev_list_entry *list_entry;
        char path[UTIL_PATH_SIZE];
-       char value[UTIL_NAME_SIZE];
+       char value[4096];
        struct stat statbuf;
        int fd;
        ssize_t size;
@@ -859,11 +893,16 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
        }
 
        if (S_ISLNK(statbuf.st_mode)) {
-               /* links return the last element of the target path */
                char target[UTIL_NAME_SIZE];
                int len;
                char *pos;
 
+               /* some core links return the last element of the target path */
+               if (strcmp(sysattr, "driver") != 0 &&
+                   strcmp(sysattr, "subsystem") != 0 &&
+                   strcmp(sysattr, "module") != 0)
+                       goto out;
+
                len = readlink(path, target, sizeof(target));
                if (len > 0) {
                        target[len] = '\0';
@@ -958,6 +997,17 @@ int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsy
        return 0;
 }
 
+int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype)
+{
+       free(udev_device->devtype);
+       udev_device->devtype = strdup(devtype);
+       if (udev_device->devtype == NULL)
+               return -ENOMEM;
+       udev_device->devtype_set = 1;
+       udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
+       return 0;
+}
+
 int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode)
 {
        free(udev_device->devnode);
@@ -1009,6 +1059,20 @@ struct udev_list_entry *udev_device_add_property_from_string(struct udev_device
        return udev_device_add_property(udev_device, name, val);
 }
 
+const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
+{
+       struct udev_list_entry *list_entry;
+
+       if (udev_device == NULL)
+               return NULL;
+       if (key == NULL)
+               return NULL;
+
+       list_entry = udev_device_get_properties_list_entry(udev_device);
+       list_entry =  udev_list_entry_get_by_name(list_entry, key);
+       return udev_list_entry_get_value(list_entry);
+}
+
 #define ENVP_SIZE                      128
 #define MONITOR_BUF_SIZE               4096
 static int update_envp_monitor_buf(struct udev_device *udev_device)