chiark / gitweb /
fix logic on-demand loading logic for db and uevent
[elogind.git] / libudev / libudev-device.c
index fe4588015cc4519d65446cb287278276e611f371..3f441d099921da31a76382fa4a3351ec6c2764ee 100644 (file)
@@ -60,28 +60,30 @@ 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;
-       int num_fake_partitions;
        int devlink_priority;
        int refcount;
        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;
 
@@ -151,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) {
@@ -210,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);
 
@@ -224,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) {
@@ -260,6 +284,8 @@ int udev_device_read_db(struct udev_device *udev_device)
                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;
@@ -284,15 +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 'A':
-                       udev_device_set_num_fake_partitions(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;
@@ -312,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");
        if (f == NULL)
                return -1;
+       udev_device->uevent_loaded = true;
 
        while (fgets(line, sizeof(line), f)) {
                char *pos;
@@ -338,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)
@@ -371,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 */
@@ -429,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 */
@@ -463,10 +483,9 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
  * @devnum: device major/minor number
  *
  * Create new udev device, and fill in information from the sys
- * device and the udev database entry. The device is looked up
- * by its major/minor number. Character and block device numbers
- * are not unique across the two types, they do not share the same
- * range of numbers.
+ * device and the udev database entry. The device is looked-up
+ * by its major/minor number and type. Character and block device
+ * numbers are not unique across the two types.
  *
  * The initial refcount is 1, and needs to be decremented to
  * release the resources of the udev device.
@@ -497,10 +516,9 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de
  * @subsystem: the subsystem of the device
  * @sysname: the name of the device
  *
- * Create new udev device, and fill in information from the sys
- * device and the udev database entry. The device is looked up
- * by the subsystem and name string of the device, like "mem",
- * "zero", or "block", "sda".
+ * Create new udev device, and fill in information from the sys device
+ * and the udev database entry. The device is looked up by the subsystem
+ * and name string of the device, like "mem" / "zero", or "block" / "sda".
  *
  * The initial refcount is 1, and needs to be decremented to
  * release the resources of the udev device.
@@ -659,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)
@@ -769,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);
@@ -853,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;
 }
 
@@ -873,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);
@@ -911,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;
 }
@@ -936,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);
 }
 
@@ -962,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;
@@ -981,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);
 }
 
@@ -997,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);
        }
@@ -1015,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;
 }
 
@@ -1105,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;
        }
 
@@ -1193,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;
 }
@@ -1204,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;
 }
@@ -1225,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;
@@ -1234,6 +1271,40 @@ 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);
+}
+
+struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
+{
+       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)
@@ -1282,7 +1353,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;
@@ -1321,7 +1392,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;
 }
@@ -1394,7 +1465,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;
 }
 
@@ -1427,23 +1498,10 @@ int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
        return 0;
 }
 
-int udev_device_get_num_fake_partitions(struct udev_device *udev_device)
-{
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->num_fake_partitions;
-}
-
-int udev_device_set_num_fake_partitions(struct udev_device *udev_device, int num)
-{
-       udev_device->num_fake_partitions = num;
-       return 0;
-}
-
 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;
 }
 
@@ -1453,23 +1511,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;
 }