chiark / gitweb /
fix compilation with --enable-debug
[elogind.git] / libudev / libudev-device.c
index 75cc61c5fc6a56be038c28896bd1e9069ebceaec..5811490a34599cbfdb4078938bda213a33c405fa 100644 (file)
@@ -60,6 +60,7 @@ struct udev_device {
        struct udev_list_node devlinks_list;
        struct udev_list_node properties_list;
        struct udev_list_node sysattr_list;
+       struct udev_list_node tags_list;
        unsigned long long int seqnum;
        int event_timeout;
        int timeout;
@@ -68,19 +69,21 @@ struct udev_device {
        dev_t devnum;
        int watch_handle;
        int maj, min;
-       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;
-       unsigned int info_loaded:1;
-       unsigned int ignore_remove:1;
+       bool parent_set;
+       bool subsystem_set;
+       bool devtype_set;
+       bool devlinks_uptodate;
+       bool envp_uptodate;
+       bool tags_uptodate;
+       bool driver_set;
+       bool info_loaded;
+       bool db_loaded;
+       bool uevent_loaded;
 };
 
 struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
 {
-       udev_device->envp_uptodate = 0;
+       udev_device->envp_uptodate = false;
        if (value == NULL) {
                struct udev_list_entry *list_entry;
 
@@ -150,6 +153,26 @@ void udev_device_add_property_from_string_parse(struct udev_device *udev_device,
                }
                if (slink[0] != '\0')
                        udev_device_add_devlink(udev_device, slink, 0);
+       } else if (strncmp(property, "TAGS=", 5) == 0) {
+               char tags[UTIL_PATH_SIZE];
+               char *next;
+
+               util_strscpy(tags, sizeof(tags), &property[5]);
+               next = strchr(tags, ':');
+               if (next != NULL) {
+                       next++;
+                       while (next[0] != '\0') {
+                               char *tag;
+
+                               tag = next;
+                               next = strchr(tag, ':');
+                               if (next == NULL)
+                                       break;
+                               next[0] = '\0';
+                               next++;
+                               udev_device_add_tag(udev_device, tag);
+                       }
+               }
        } else if (strncmp(property, "DRIVER=", 7) == 0) {
                udev_device_set_driver(udev_device, &property[7]);
        } else if (strncmp(property, "ACTION=", 7) == 0) {
@@ -209,6 +232,9 @@ int udev_device_read_db(struct udev_device *udev_device)
        char line[UTIL_LINE_SIZE];
        FILE *f;
 
+       if (udev_device->db_loaded)
+               return 0;
+
        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/",
                      udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
 
@@ -223,12 +249,11 @@ int udev_device_read_db(struct udev_device *udev_device)
                char *next;
 
                target_len = readlink(filename, target, sizeof(target));
-               if (target_len > 0)
-                       target[target_len] = '\0';
-               else {
-                       dbg(udev_device->udev, "error reading db link %s: %m\n", filename);
+               if (target_len <= 0 || target_len == sizeof(target)) {
+                       info(udev_device->udev, "error reading db link %s: %m\n", filename);
                        return -1;
                }
+               target[target_len] = '\0';
 
                next = strchr(target, ' ');
                if (next != NULL) {
@@ -254,11 +279,13 @@ int udev_device_read_db(struct udev_device *udev_device)
                return 0;
        }
 
-       f = fopen(filename, "r");
+       f = fopen(filename, "re");
        if (f == NULL) {
                dbg(udev_device->udev, "error reading db file %s: %m\n", filename);
                return -1;
        }
+       udev_device->db_loaded = true;
+
        while (fgets(line, sizeof(line), f)) {
                ssize_t len;
                const char *val;
@@ -283,12 +310,12 @@ int udev_device_read_db(struct udev_device *udev_device)
                case 'T':
                        udev_device_set_event_timeout(udev_device, atoi(val));
                        break;
-               case 'R':
-                       udev_device_set_ignore_remove(udev_device, atoi(val));
-                       break;
                case 'E':
                        udev_device_add_property_from_string(udev_device, val);
                        break;
+               case 'G':
+                       udev_device_add_tag(udev_device, val);
+                       break;
                case 'W':
                        udev_device_set_watch_handle(udev_device, atoi(val));
                        break;
@@ -308,10 +335,14 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
        int maj = 0;
        int min = 0;
 
+       if (udev_device->uevent_loaded)
+               return 0;
+
        util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
-       f = fopen(filename, "r");
+       f = fopen(filename, "re");
        if (f == NULL)
                return -1;
+       udev_device->uevent_loaded = true;
 
        while (fgets(line, sizeof(line), f)) {
                char *pos;
@@ -334,21 +365,13 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
        }
 
        udev_device->devnum = makedev(maj, min);
-
        fclose(f);
        return 0;
 }
 
-static void device_load_info(struct udev_device *device)
-{
-       device->info_loaded = 1;
-       udev_device_read_uevent_file(device);
-       udev_device_read_db(device);
-}
-
 void udev_device_set_info_loaded(struct udev_device *device)
 {
-       device->info_loaded = 1;
+       device->info_loaded = true;
 }
 
 struct udev_device *udev_device_new(struct udev *udev)
@@ -367,6 +390,7 @@ struct udev_device *udev_device_new(struct udev *udev)
        udev_list_init(&udev_device->devlinks_list);
        udev_list_init(&udev_device->properties_list);
        udev_list_init(&udev_device->sysattr_list);
+       udev_list_init(&udev_device->tags_list);
        udev_device->event_timeout = -1;
        udev_device->watch_handle = -1;
        /* copy global properties */
@@ -425,7 +449,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
        util_strscpy(path, sizeof(path), syspath);
        util_resolve_sys_link(udev, path, sizeof(path));
 
-       if (strncmp(&syspath[len], "/devices/", 9) == 0) {
+       if (strncmp(&path[len], "/devices/", 9) == 0) {
                char file[UTIL_PATH_SIZE];
 
                /* all "devices" require a "uevent" file */
@@ -653,7 +677,7 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->parent_set) {
-               udev_device->parent_set = 1;
+               udev_device->parent_set = true;
                udev_device->parent_device = device_new_from_parent(udev_device);
        }
        if (udev_device->parent_device != NULL)
@@ -763,12 +787,13 @@ void udev_device_unref(struct udev_device *udev_device)
        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);
+       udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
+       udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list);
        free(udev_device->action);
        free(udev_device->driver);
        free(udev_device->devpath_old);
        free(udev_device->sysname_old);
        free(udev_device->knodename);
-       udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
        free(udev_device->envp);
        free(udev_device->monitor_buf);
        dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
@@ -847,7 +872,7 @@ const char *udev_device_get_devnode(struct udev_device *udev_device)
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               device_load_info(udev_device);
+               udev_device_read_db(udev_device);
        return udev_device->devnode;
 }
 
@@ -867,7 +892,7 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device)
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->subsystem_set) {
-               udev_device->subsystem_set = 1;
+               udev_device->subsystem_set = true;
                /* read "subsystem" link */
                if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
                        udev_device_set_subsystem(udev_device, subsystem);
@@ -905,9 +930,8 @@ 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);
+               udev_device->devtype_set = true;
+               udev_device_read_uevent_file(udev_device);
        }
        return udev_device->devtype;
 }
@@ -930,13 +954,13 @@ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               device_load_info(udev_device);
+               udev_device_read_db(udev_device);
        return udev_list_get_entry(&udev_device->devlinks_list);
 }
 
 void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
 {
-       udev_device->devlinks_uptodate = 0;
+       udev_device->devlinks_uptodate = false;
        udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
 }
 
@@ -956,13 +980,15 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
 {
        if (udev_device == NULL)
                return NULL;
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
+       if (!udev_device->info_loaded) {
+               udev_device_read_uevent_file(udev_device);
+               udev_device_read_db(udev_device);
+       }
        if (!udev_device->devlinks_uptodate) {
                char symlinks[UTIL_PATH_SIZE];
                struct udev_list_entry *list_entry;
 
-               udev_device->devlinks_uptodate = 1;
+               udev_device->devlinks_uptodate = true;
                list_entry = udev_device_get_devlinks_list_entry(udev_device);
                if (list_entry != NULL) {
                        char *s;
@@ -975,6 +1001,21 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
                        udev_device_add_property(udev_device, "DEVLINKS", symlinks);
                }
        }
+       if (!udev_device->tags_uptodate) {
+               udev_device->tags_uptodate = true;
+               if (udev_device_get_tags_list_entry(udev_device) != NULL) {
+                       char tags[UTIL_PATH_SIZE];
+                       struct udev_list_entry *list_entry;
+                       char *s;
+                       size_t l;
+
+                       s = tags;
+                       l = util_strpcpyl(&s, sizeof(tags), ":", NULL);
+                       udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
+                               l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL);
+                       udev_device_add_property(udev_device, "TAGS", tags);
+               }
+       }
        return udev_list_get_entry(&udev_device->properties_list);
 }
 
@@ -991,7 +1032,7 @@ const char *udev_device_get_driver(struct udev_device *udev_device)
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->driver_set) {
-               udev_device->driver_set = 1;
+               udev_device->driver_set = true;
                if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) > 0)
                        udev_device->driver = strdup(driver);
        }
@@ -1009,7 +1050,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)
-               device_load_info(udev_device);
+               udev_device_read_uevent_file(udev_device);
        return udev_device->devnum;
 }
 
@@ -1099,16 +1140,18 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
                        goto out;
 
                len = readlink(path, target, sizeof(target));
-               if (len > 0) {
-                       target[len] = '\0';
-                       pos = strrchr(target, '/');
-                       if (pos != NULL) {
-                               pos = &pos[1];
-                               dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos);
-                               list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0);
-                               val = udev_list_entry_get_value(list_entry);
-                       }
+               if (len <= 0 || len == sizeof(target))
+                       goto out;
+               target[len] = '\0';
+
+               pos = strrchr(target, '/');
+               if (pos != NULL) {
+                       pos = &pos[1];
+                       dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos);
+                       list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0);
+                       val = udev_list_entry_get_value(list_entry);
                }
+
                goto out;
        }
 
@@ -1121,7 +1164,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
                goto out;
 
        /* read attribute value */
-       fd = open(path, O_RDONLY);
+       fd = open(path, O_RDONLY|O_CLOEXEC);
        if (fd < 0) {
                dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
                goto out;
@@ -1187,7 +1230,7 @@ int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsy
        udev_device->subsystem = strdup(subsystem);
        if (udev_device->subsystem == NULL)
                return -ENOMEM;
-       udev_device->subsystem_set = 1;
+       udev_device->subsystem_set = true;
        udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
        return 0;
 }
@@ -1198,7 +1241,7 @@ int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype
        udev_device->devtype = strdup(devtype);
        if (udev_device->devtype == NULL)
                return -ENOMEM;
-       udev_device->devtype_set = 1;
+       udev_device->devtype_set = true;
        udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
        return 0;
 }
@@ -1219,7 +1262,7 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink
 {
        struct udev_list_entry *list_entry;
 
-       udev_device->devlinks_uptodate = 0;
+       udev_device->devlinks_uptodate = false;
        list_entry = udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, 1, 0);
        if (list_entry == NULL)
                return -ENOMEM;
@@ -1228,6 +1271,53 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink
        return 0;
 }
 
+int udev_device_add_tag(struct udev_device *udev_device, const char *tag)
+{
+       if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL)
+               return -EINVAL;
+       udev_device->tags_uptodate = false;
+       if (udev_list_entry_add(udev_device->udev, &udev_device->tags_list, tag, NULL, 1, 0) != NULL)
+               return 0;
+       return -ENOMEM;
+}
+
+void udev_device_cleanup_tags_list(struct udev_device *udev_device)
+{
+       udev_device->tags_uptodate = false;
+       udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list);
+}
+
+/**
+ * udev_device_get_tags_list_entry:
+ * @udev_device: udev device
+ *
+ * Retrieve the list of tags attached to the udev device. The next
+ * list entry can be retrieved with udev_list_entry_next(),
+ * which returns #NULL if no more entries exist. The tag string
+ * can be retrieved from the list entry by udev_list_get_name().
+ *
+ * Returns: the first entry of the tag list
+ **/
+struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_list_get_entry(&udev_device->tags_list);
+}
+
+int udev_device_has_tag(struct udev_device *udev_device, const char *tag)
+{
+       struct udev_list_entry *list_entry;
+
+       if (!udev_device->info_loaded)
+               udev_device_read_db(udev_device);
+       list_entry = udev_device_get_tags_list_entry(udev_device);
+       list_entry =  udev_list_entry_get_by_name(list_entry, tag);
+       if (list_entry != NULL)
+               return 1;
+       return 0;
+}
+
 #define ENVP_SIZE                      128
 #define MONITOR_BUF_SIZE               4096
 static int update_envp_monitor_buf(struct udev_device *udev_device)
@@ -1276,7 +1366,7 @@ static int update_envp_monitor_buf(struct udev_device *udev_device)
        }
        udev_device->envp[i] = NULL;
        udev_device->monitor_buf_len = s - udev_device->monitor_buf;
-       udev_device->envp_uptodate = 1;
+       udev_device->envp_uptodate = true;
        dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
            i, udev_device->monitor_buf_len);
        return 0;
@@ -1315,7 +1405,7 @@ int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
        udev_device->driver = strdup(driver);
        if (udev_device->driver == NULL)
                return -ENOMEM;
-       udev_device->driver_set = 1;
+       udev_device->driver_set = true;
        udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
        return 0;
 }
@@ -1388,7 +1478,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)
-               device_load_info(udev_device);
+               udev_device_read_db(udev_device);
        return udev_device->event_timeout;
 }
 
@@ -1424,7 +1514,7 @@ int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
 int udev_device_get_devlink_priority(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               device_load_info(udev_device);
+               udev_device_read_db(udev_device);
        return udev_device->devlink_priority;
 }
 
@@ -1434,23 +1524,10 @@ int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
        return 0;
 }
 
-int udev_device_get_ignore_remove(struct udev_device *udev_device)
-{
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->ignore_remove;
-}
-
-int udev_device_set_ignore_remove(struct udev_device *udev_device, int ignore)
-{
-       udev_device->ignore_remove = ignore;
-       return 0;
-}
-
 int udev_device_get_watch_handle(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               device_load_info(udev_device);
+               udev_device_read_db(udev_device);
        return udev_device->watch_handle;
 }