X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fudev%2Fudevadm-hwdb.c;h=d0cce84859aa4a38c28d2a89a03230a26d4fa6f2;hp=1e80b0d611c573b0a4098044195f497b1282d8fd;hb=872c8faaf2009422a91d227ae0b5c6f04c9d2c69;hpb=ff03aed06a42235a87a3d33e7d812be1e9c8161d diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 1e80b0d61..d0cce8485 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "util.h" #include "strbuf.h" @@ -84,14 +85,12 @@ static int trie_children_cmp(const void *v1, const void *v2) { static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) { struct trie_child_entry *child; - int err = 0; /* extend array, add new entry, sort for bisection */ child = realloc(node->children, (node->children_count + 1) * sizeof(struct trie_child_entry)); - if (!child) { - err = -ENOMEM; - goto out; - } + if (!child) + return -ENOMEM; + node->children = child; trie->children_count++; node->children[node->children_count].c = c; @@ -99,8 +98,8 @@ static int node_add_child(struct trie *trie, struct trie_node *node, struct trie node->children_count++; qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp); trie->nodes_count++; -out: - return err; + + return 0; } static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) { @@ -176,53 +175,51 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se const char *key, const char *value) { size_t i = 0; int err = 0; - struct trie_node _cleanup_free_ *child = NULL; for (;;) { size_t p; uint8_t c; + struct trie_node *child; for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) { - char *s; + _cleanup_free_ char *s = NULL; ssize_t off; + _cleanup_free_ struct trie_node *new_child = NULL; if (c == search[i + p]) continue; /* split node */ - child = calloc(sizeof(struct trie_node), 1); - if (!child) { - err = -ENOMEM; - goto out; - } + new_child = calloc(sizeof(struct trie_node), 1); + if (!new_child) + return -ENOMEM; /* move values from parent to child */ - child->prefix_off = node->prefix_off + p+1; - child->children = node->children; - child->children_count = node->children_count; - child->values = node->values; - child->values_count = node->values_count; + new_child->prefix_off = node->prefix_off + p+1; + new_child->children = node->children; + new_child->children_count = node->children_count; + new_child->values = node->values; + new_child->values_count = node->values_count; /* update parent; use strdup() because the source gets realloc()d */ s = strndup(trie->strings->buf + node->prefix_off, p); - if (!s) { - err = -ENOMEM; - goto out; - } + if (!s) + return -ENOMEM; + off = strbuf_add_string(trie->strings, s, p); - free(s); - if (off < 0) { - err = off; - goto out; - } + if (off < 0) + return off; + node->prefix_off = off; node->children = NULL; node->children_count = 0; node->values = NULL; node->values_count = 0; - err = node_add_child(trie, node, child, c); + err = node_add_child(trie, node, new_child, c); if (err) - goto out; + return err; + + new_child = NULL; /* avoid cleanup */ break; } i += p; @@ -237,28 +234,28 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se /* new child */ child = calloc(sizeof(struct trie_node), 1); - if (!child) { - err = -ENOMEM; - goto out; - } + if (!child) + return -ENOMEM; + off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1)); if (off < 0) { - err = off; - goto out; + free(child); + return off; } + child->prefix_off = off; err = node_add_child(trie, node, child, c); - if (err) - goto out; + if (err) { + free(child); + return err; + } + return trie_node_add_value(trie, child, key, value); } node = child; - child = NULL; /* avoid cleanup */ i++; } -out: - return err; } struct trie_f { @@ -306,8 +303,10 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) { int64_t child_off; child_off = trie_store_nodes(trie, node->children[i].child); - if (child_off < 0) + if (child_off < 0) { + free(children); return child_off; + } children[i].c = node->children[i].c; children[i].child_off = htole64(child_off); } @@ -406,66 +405,122 @@ out: return err; } -static int import_file(struct trie *trie, const char *filename) { +static int insert_data(struct trie *trie, struct udev_list *match_list, + char *line, const char *filename) { + char *value; + struct udev_list_entry *entry; + + value = strchr(line, '='); + if (!value) { + log_error("Error, key/value pair expected but got '%s' in '%s':\n", line, filename); + return -EINVAL; + } + + value[0] = '\0'; + value++; + + if (line[0] == '\0' || value[0] == '\0') { + log_error("Error, empty key or value '%s' in '%s':\n", line, filename); + return -EINVAL; + } + + udev_list_entry_foreach(entry, udev_list_get_entry(match_list)) + trie_insert(trie, trie->root, udev_list_entry_get_name(entry), line, value); + + return 0; +} + +static int import_file(struct udev *udev, struct trie *trie, const char *filename) { + enum { + HW_MATCH, + HW_DATA, + HW_NONE, + } state = HW_NONE; FILE *f; char line[LINE_MAX]; - char match[LINE_MAX]; - char cond[LINE_MAX]; + struct udev_list match_list; + + udev_list_init(udev, &match_list, false); f = fopen(filename, "re"); if (f == NULL) return -errno; - match[0] = '\0'; - cond[0] = '\0'; while (fgets(line, sizeof(line), f)) { size_t len; + char *pos; + /* comment line */ if (line[0] == '#') continue; - /* new line, new record */ - if (line[0] == '\n') { - match[0] = '\0'; - cond[0] = '\0'; - continue; - } + /* strip trailing comment */ + pos = strchr(line, '#'); + if (pos) + pos[0] = '\0'; - /* remove newline */ + /* strip trailing whitespace */ len = strlen(line); - if (len < 2) - continue; - line[len-1] = '\0'; + while (len > 0 && isspace(line[len-1])) + len--; + line[len] = '\0'; + + switch (state) { + case HW_NONE: + if (len == 0) + break; + + if (line[0] == ' ') { + log_error("Error, MATCH expected but got '%s' in '%s':\n", line, filename); + break; + } - /* start of new record */ - if (match[0] == '\0') { - strcpy(match, line); - cond[0] = '\0'; - continue; - } + /* start of record, first match */ + state = HW_MATCH; + udev_list_entry_add(&match_list, line, NULL); + break; - if (line[0] == '+') { - strcpy(cond, line); - continue; - } + case HW_MATCH: + if (len == 0) { + log_error("Error, DATA expected but got empty line in '%s':\n", filename); + state = HW_NONE; + udev_list_cleanup(&match_list); + break; + } - /* TODO: support +; skip the entire record until we support it */ - if (cond[0] != '\0') - continue; + /* another match */ + if (line[0] != ' ') { + udev_list_entry_add(&match_list, line, NULL); + break; + } - /* value lines */ - if (line[0] == ' ') { - char *value; + /* first data */ + state = HW_DATA; + insert_data(trie, &match_list, line, filename); + break; - value = strchr(line, '='); - if (!value) - continue; - value[0] = '\0'; - value++; - trie_insert(trie, trie->root, match, line, value); - } + case HW_DATA: + /* end of record */ + if (len == 0) { + state = HW_NONE; + udev_list_cleanup(&match_list); + break; + } + + if (line[0] != ' ') { + log_error("Error, DATA expected but got '%s' in '%s':\n", line, filename); + state = HW_NONE; + udev_list_cleanup(&match_list); + break; + } + + insert_data(trie, &match_list, line, filename); + break; + }; } + fclose(f); + udev_list_cleanup(&match_list); return 0; } @@ -553,7 +608,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { } STRV_FOREACH(f, files) { log_debug("reading file '%s'", *f); - import_file(trie, *f); + import_file(udev, trie, *f); } strv_free(files); @@ -593,7 +648,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, test, 0)) printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); - hwdb = udev_hwdb_unref(hwdb); + udev_hwdb_unref(hwdb); } } out: