]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-hwdb: order properties by origin 4199/head
authorDavid Herrmann <dh.herrmann@gmail.com>
Wed, 21 Sep 2016 13:16:00 +0000 (15:16 +0200)
committerDavid Herrmann <dh.herrmann@gmail.com>
Wed, 21 Sep 2016 13:18:28 +0000 (15:18 +0200)
If we find duplicates in a property-lookup, make sure to order them by
their origin. That is, matches defined "later" take precedence over
earlier matches. The "later"-order is defined by file-name + line-number
combination. That is, if a match is defined below another one in the
same hwdb file, it takes precedence, same as if it is defined in a file
ordered after another one.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
src/libsystemd/sd-hwdb/sd-hwdb.c

index fb9522959f461eb71b250c756f90741a2b64964c..488e101ea8a697f8dee92b0acb82de495ac3487d 100644 (file)
@@ -141,12 +141,13 @@ static const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_
         return NULL;
 }
 
-static int hwdb_add_property(sd_hwdb *hwdb, const char *key, const char *value) {
+static int hwdb_add_property(sd_hwdb *hwdb, const struct trie_value_entry_f *entry) {
+        const char *key;
         int r;
 
         assert(hwdb);
-        assert(key);
-        assert(value);
+
+        key = trie_string(hwdb, entry->key_off);
 
         /*
          * Silently ignore all properties which do not start with a
@@ -157,11 +158,25 @@ static int hwdb_add_property(sd_hwdb *hwdb, const char *key, const char *value)
 
         key++;
 
+        if (le64toh(hwdb->head->value_entry_size) >= sizeof(struct trie_value_entry2_f)) {
+                const struct trie_value_entry2_f *old, *entry2;
+
+                entry2 = (const struct trie_value_entry2_f *)entry;
+                old = ordered_hashmap_get(hwdb->properties, key);
+                if (old) {
+                        /* on duplicates, we order by filename and line-number */
+                        r = strcmp(trie_string(hwdb, entry2->filename_off), trie_string(hwdb, old->filename_off));
+                        if (r < 0 ||
+                            (r == 0 && entry2->line_number < old->line_number))
+                                return 0;
+                }
+        }
+
         r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops);
         if (r < 0)
                 return r;
 
-        r = ordered_hashmap_replace(hwdb->properties, key, (char*)value);
+        r = ordered_hashmap_replace(hwdb->properties, key, (void *)entry);
         if (r < 0)
                 return r;
 
@@ -193,8 +208,7 @@ static int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t
 
         if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0)
                 for (i = 0; i < le64toh(node->values_count); i++) {
-                        err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_value(hwdb, node, i)->key_off),
-                                                trie_string(hwdb, trie_node_value(hwdb, node, i)->value_off));
+                        err = hwdb_add_property(hwdb, trie_node_value(hwdb, node, i));
                         if (err < 0)
                                 return err;
                 }
@@ -259,8 +273,7 @@ static int trie_search_f(sd_hwdb *hwdb, const char *search) {
                         size_t n;
 
                         for (n = 0; n < le64toh(node->values_count); n++) {
-                                err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_value(hwdb, node, n)->key_off),
-                                                        trie_string(hwdb, trie_node_value(hwdb, node, n)->value_off));
+                                err = hwdb_add_property(hwdb, trie_node_value(hwdb, node, n));
                                 if (err < 0)
                                         return err;
                         }
@@ -415,7 +428,7 @@ static int properties_prepare(sd_hwdb *hwdb, const char *modalias) {
 }
 
 _public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) {
-        const char *value;
+        const struct trie_value_entry_f *entry;
         int r;
 
         assert_return(hwdb, -EINVAL);
@@ -427,11 +440,11 @@ _public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, c
         if (r < 0)
                 return r;
 
-        value = ordered_hashmap_get(hwdb->properties, key);
-        if (!value)
+        entry = ordered_hashmap_get(hwdb->properties, key);
+        if (!entry)
                 return -ENOENT;
 
-        *_value = value;
+        *_value = trie_string(hwdb, entry->value_off);
 
         return 0;
 }
@@ -454,8 +467,8 @@ _public_ int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) {
 }
 
 _public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
+        const struct trie_value_entry_f *entry;
         const void *k;
-        void *v;
 
         assert_return(hwdb, -EINVAL);
         assert_return(key, -EINVAL);
@@ -464,12 +477,12 @@ _public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **val
         if (hwdb->properties_modified)
                 return -EAGAIN;
 
-        ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, &v, &k);
+        ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, (void **)&entry, &k);
         if (!k)
                 return 0;
 
         *key = k;
-        *value = v;
+        *value = trie_string(hwdb, entry->value_off);
 
         return 1;
 }