chiark / gitweb /
rules: zaptel - add "dialout" group
[elogind.git] / udev / lib / libudev-device.c
index 38af0e7c9411bb573c20d4a240d710fc2629c47a..0cb59212815459924f7319187ff7e5b0d81e9f21 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;
@@ -77,7 +79,7 @@ static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *f
        return util_path_encode(&filename[start], len - start);
 }
 
-static int device_read_db(struct udev_device *udev_device)
+int udev_device_read_db(struct udev_device *udev_device)
 {
        struct stat stats;
        char filename[UTIL_PATH_SIZE];
@@ -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);
@@ -218,11 +222,11 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
        return 0;
 }
 
-void udev_device_load_info(struct udev_device *device)
+static void device_load_info(struct udev_device *device)
 {
        device->info_loaded = 1;
        udev_device_read_uevent_file(device);
-       device_read_db(device);
+       udev_device_read_db(device);
 }
 
 void udev_device_set_info_loaded(struct udev_device *device)
@@ -501,9 +505,11 @@ static struct udev_device *device_new_from_parent(struct udev_device *udev_devic
            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)
+               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;
+                       if (udev_device_parent != NULL)
+                               return udev_device_parent;
+               }
        }
 
        util_strlcpy(path, udev_device->syspath, sizeof(path));
@@ -535,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;
@@ -603,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);
@@ -676,7 +692,7 @@ const char *udev_device_get_devnode(struct udev_device *udev_device)
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->devnode;
 }
 
@@ -721,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
@@ -739,7 +775,7 @@ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_list_get_entry(&udev_device->devlinks_list);
 }
 
@@ -766,7 +802,7 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        if (!udev_device->devlinks_uptodate) {
                char symlinks[UTIL_PATH_SIZE];
                struct udev_list_entry *list_entry;
@@ -804,7 +840,7 @@ dev_t udev_device_get_devnum(struct udev_device *udev_device)
        if (udev_device == NULL)
                return makedev(0, 0);
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->devnum;
 }
 
@@ -857,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';
@@ -956,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);
@@ -1154,7 +1206,7 @@ int udev_device_set_timeout(struct udev_device *udev_device, int timeout)
 int udev_device_get_event_timeout(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->event_timeout;
 }
 
@@ -1190,7 +1242,7 @@ int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
 int udev_device_get_num_fake_partitions(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->num_fake_partitions;
 }
 
@@ -1203,7 +1255,7 @@ int udev_device_set_num_fake_partitions(struct udev_device *udev_device, int num
 int udev_device_get_devlink_priority(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->devlink_priority;
 }
 
@@ -1216,7 +1268,7 @@ int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
 int udev_device_get_ignore_remove(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->ignore_remove;
 }