chiark / gitweb /
libudev: list - use bit flags for 'sort' and 'unique'
[elogind.git] / udev / udev-rules.c
index d38c9ff4ff333c14a6bd8c3b1085d3b6197a6483..892d8f27a76b0c07dfb9c1b1bde214b104393a4f 100644 (file)
@@ -731,7 +731,7 @@ static int import_property_from_string(struct udev_device *dev, char *line)
                entry = udev_device_add_property(dev, key, val);
                /* store in db, skip private keys */
                if (key[0] != '.')
-                       udev_list_entry_set_flags(entry, 1);
+                       udev_list_entry_set_num(entry, true);
        }
        return 0;
 }
@@ -800,7 +800,7 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
                        entry = udev_device_add_property(dev, key, val);
                        /* store in db, skip private keys */
                        if (key[0] != '.')
-                               udev_list_entry_set_flags(entry, 1);
+                               udev_list_entry_set_num(entry, true);
                }
        }
        return 0;
@@ -1719,6 +1719,7 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s
 static int add_matching_files(struct udev *udev, struct udev_list_node *file_list, const char *dirname, const char *suffix)
 {
        DIR *dir;
+       struct dirent *dent;
        char filename[UTIL_PATH_SIZE];
 
        dbg(udev, "open directory '%s'\n", dirname);
@@ -1728,13 +1729,7 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis
                return -1;
        }
 
-       for (;;) {
-               struct dirent *dent;
-
-               dent = readdir(dir);
-               if (dent == NULL || dent->d_name[0] == '\0')
-                       break;
-
+       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
                if (dent->d_name[0] == '.')
                        continue;
 
@@ -1750,7 +1745,12 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis
                }
                util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
                dbg(udev, "put file '%s' into list\n", filename);
-               udev_list_entry_add(udev, file_list, filename, NULL, 1, 1);
+               /*
+                * the basename is the key, the filename the value
+                * identical basenames from different directories overwrite each other
+                * entries are sorted after basename
+                */
+               udev_list_entry_add(udev, file_list, dent->d_name, filename, UDEV_LIST_UNIQUE|UDEV_LIST_SORT);
        }
 
        closedir(dir);
@@ -1761,7 +1761,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
 {
        struct udev_rules *rules;
        struct udev_list_node file_list;
-       struct udev_list_entry *file_loop, *file_tmp;
+       struct udev_list_entry *file_loop;
        struct token end_token;
 
        rules = calloc(1, sizeof(struct udev_rules));
@@ -1804,78 +1804,38 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
        memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
        rules->trie_nodes_cur = 1;
 
-       if (udev_get_rules_path(udev) != NULL) {
-               /* custom rules location for testing */
-               add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
-       } else {
-               char filename[PATH_MAX];
-               struct udev_list_node sort_list;
-               struct udev_list_entry *sort_loop, *sort_tmp;
+       if (udev_get_rules_path(udev) == NULL) {
+               char filename[UTIL_PATH_SIZE];
 
-               /* read user/custom rules */
+               /* /lib/udev -- default/package rules */
+               add_matching_files(udev, &file_list, LIBEXECDIR "/rules.d", ".rules");
+
+               /* /etc/udev -- system-specific/user/admin rules */
                add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules");
 
-               /* read dynamic/temporary rules */
+               /* /run/udev -- throw-away/temporary rules */
                util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
-               udev_list_init(&sort_list);
-               add_matching_files(udev, &sort_list, filename, ".rules");
-
-               /* read default rules */
-               add_matching_files(udev, &sort_list, LIBEXECDIR "/rules.d", ".rules");
-
-               /* sort all rules files by basename into list of files */
-               udev_list_entry_foreach_safe(sort_loop, sort_tmp, udev_list_get_entry(&sort_list)) {
-                       const char *sort_name = udev_list_entry_get_name(sort_loop);
-                       const char *sort_base = strrchr(sort_name, '/');
-
-                       if (sort_base == NULL)
-                               continue;
-                       /* sort entry into existing list */
-                       udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
-                               const char *file_name = udev_list_entry_get_name(file_loop);
-                               const char *file_base = strrchr(file_name, '/');
-
-                               if (file_base == NULL)
-                                       continue;
-                               if (strcmp(file_base, sort_base) == 0) {
-                                       info(udev, "rule file basename '%s' already added, ignoring '%s'\n",
-                                            file_name, sort_name);
-                                       udev_list_entry_delete(sort_loop);
-                                       sort_loop = NULL;
-                                       break;
-                               }
-                               if (strcmp(file_base, sort_base) > 0) {
-                                       /* found later file, insert before */
-                                       udev_list_entry_remove(sort_loop);
-                                       udev_list_entry_insert_before(sort_loop, file_loop);
-                                       sort_loop = NULL;
-                                       break;
-                               }
-                       }
-                       /* current file already handled */
-                       if (sort_loop == NULL)
-                               continue;
-                       /* no later file, append to end of list */
-                       udev_list_entry_remove(sort_loop);
-                       udev_list_entry_append(sort_loop, &file_list);
-               }
+               add_matching_files(udev, &file_list, filename, ".rules");
+       } else {
+               /* custom rules files location for testing */
+               add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
        }
 
        /* add all filenames to the string buffer */
        udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
-               const char *filename = udev_list_entry_get_name(file_loop);
+               const char *filename = udev_list_entry_get_value(file_loop);
                unsigned int filename_off;
 
                filename_off = add_string(rules, filename);
                /* the offset in the rule is limited to unsigned short */
                if (filename_off < USHRT_MAX)
-                       udev_list_entry_set_flags(file_loop, filename_off);
+                       udev_list_entry_set_num(file_loop, filename_off);
        }
 
-       /* parse list of files */
-       udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
-               const char *filename = udev_list_entry_get_name(file_loop);
-               unsigned int filename_off = udev_list_entry_get_flags(file_loop);
+       /* parse all rules files */
+       udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
+               const char *filename = udev_list_entry_get_value(file_loop);
+               unsigned int filename_off = udev_list_entry_get_num(file_loop);
                struct stat st;
 
                if (stat(filename, &st) != 0) {
@@ -1891,8 +1851,8 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
                        continue;
                }
                parse_file(rules, filename, filename_off);
-               udev_list_entry_delete(file_loop);
        }
+       udev_list_cleanup_entries(udev, &file_list);
 
        memset(&end_token, 0x00, sizeof(struct token));
        end_token.type = TK_END;
@@ -2366,7 +2326,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                        struct udev_list_entry *entry;
 
                                        entry = udev_device_add_property(event->dev, key, value);
-                                       udev_list_entry_set_flags(entry, 1);
+                                       udev_list_entry_set_num(entry, true);
                                } else {
                                        if (cur->key.op != OP_NOMATCH)
                                                goto nomatch;
@@ -2394,7 +2354,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                                        if (pos[0] == '\0' || isspace(pos[0])) {
                                                                /* we import simple flags as 'FLAG=1' */
                                                                entry = udev_device_add_property(event->dev, key, "1");
-                                                               udev_list_entry_set_flags(entry, 1);
+                                                               udev_list_entry_set_num(entry, true);
                                                                imported = true;
                                                        } else if (pos[0] == '=') {
                                                                const char *value;
@@ -2405,7 +2365,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                                                        pos++;
                                                                pos[0] = '\0';
                                                                entry = udev_device_add_property(event->dev, key, value);
-                                                               udev_list_entry_set_flags(entry, 1);
+                                                               udev_list_entry_set_num(entry, true);
                                                                imported = true;
                                                        }
                                                }
@@ -2550,7 +2510,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                        entry = udev_device_add_property(event->dev, name, temp_value);
                                        /* store in db, skip private keys */
                                        if (name[0] != '.')
-                                               udev_list_entry_set_flags(entry, 1);
+                                               udev_list_entry_set_num(entry, true);
                                } else {
                                        udev_device_add_property(event->dev, name, NULL);
                                }
@@ -2669,9 +2629,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                     &rules->buf[rule->rule.filename_off],
                                     rule->rule.filename_line);
                                list_entry = udev_list_entry_add(event->udev, &event->run_list,
-                                                                &rules->buf[cur->key.value_off], NULL, 1, 0);
+                                                                &rules->buf[cur->key.value_off], NULL, UDEV_LIST_UNIQUE);
                                if (cur->key.fail_on_error)
-                                       udev_list_entry_set_flags(list_entry, 1);
+                                       udev_list_entry_set_num(list_entry, true);
                                break;
                        }
                case TK_A_GOTO: