X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fudev%2Fudevadm-hwdb.c;h=ca1bf165a963a930fcbd301711c830568e97a2b4;hb=37d3ab1b7e114f0fb6dfb2e7273569b42794b76a;hp=52fe1d4ebc5c5fb45dfa2526a334dc0b0142e741;hpb=796b06c21b62d13c9021e2fbd9c58a5c6edb2764;p=elogind.git diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 52fe1d4eb..ca1bf165a 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -1,7 +1,7 @@ /*** This file is part of systemd. - Copyright 2012 Kay Sievers + Copyright 2012 Kay Sievers systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -27,7 +27,7 @@ #include "conf-files.h" #include "udev.h" -#include "udev-hwdb.h" +#include "libudev-hwdb-def.h" /* * Generic udev properties, key/value database based on modalias strings. @@ -35,7 +35,7 @@ */ static const char * const conf_file_dirs[] = { - SYSCONFDIR "/udev/hwdb.d", + "/etc/udev/hwdb.d", UDEVLIBEXECDIR "/hwdb.d", NULL }; @@ -135,19 +135,28 @@ static int trie_values_cmp(const void *v1, const void *v2, void *arg) { static int trie_node_add_value(struct trie *trie, struct trie_node *node, const char *key, const char *value) { - size_t k, v; + ssize_t k, v; struct trie_value_entry *val; - struct trie_value_entry search; k = strbuf_add_string(trie->strings, key, strlen(key)); + if (k < 0) + return k; v = strbuf_add_string(trie->strings, value, strlen(value)); + if (v < 0) + return v; - /* replace existing earlier key with new value */ - search.value_off = k; - val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie); - if (val) { - val->value_off = v; - return 0; + if (node->values_count) { + struct trie_value_entry search = { + .key_off = k, + .value_off = v, + }; + + val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie); + if (val) { + /* replace existing earlier key with new value */ + val->value_off = v; + return 0; + } } /* extend array, add new entry, sort for bisection */ @@ -282,7 +291,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) { .children_count = node->children_count, .values_count = htole64(node->values_count), }; - struct trie_child_entry_f *children; + struct trie_child_entry_f *children = NULL; int64_t node_off; if (node->children_count) { @@ -381,12 +390,15 @@ static int trie_store(struct trie *trie, const char *filename) { } log_debug("=== trie on-disk ===\n"); - log_debug("size: %8zi bytes\n", size); + log_debug("size: %8llu bytes\n", (unsigned long long)size); log_debug("header: %8zu bytes\n", sizeof(struct trie_header_f)); - log_debug("nodes: %8zu bytes (%8zi)\n", t.nodes_count * sizeof(struct trie_node_f), t.nodes_count); - log_debug("child pointers: %8zu bytes (%8zi)\n", t.children_count * sizeof(struct trie_child_entry_f), t.children_count); - log_debug("value pointers: %8zu bytes (%8zi)\n", t.values_count * sizeof(struct trie_value_entry_f), t.values_count); - log_debug("string store: %8zu bytes\n", trie->strings->len); + log_debug("nodes: %8llu bytes (%8llu)\n", + (unsigned long long)t.nodes_count * sizeof(struct trie_node_f), (unsigned long long)t.nodes_count); + log_debug("child pointers: %8llu bytes (%8llu)\n", + (unsigned long long)t.children_count * sizeof(struct trie_child_entry_f), (unsigned long long)t.children_count); + log_debug("value pointers: %8llu bytes (%8llu)\n", + (unsigned long long)t.values_count * sizeof(struct trie_value_entry_f), (unsigned long long)t.values_count); + log_debug("string store: %8llu bytes\n", (unsigned long long)trie->strings->len); log_debug("strings start: %8llu\n", (unsigned long long) t.strings_off); out: free(filename_tmp); @@ -397,12 +409,14 @@ static int import_file(struct trie *trie, const char *filename) { FILE *f; char line[LINE_MAX]; char match[LINE_MAX]; + char cond[LINE_MAX]; f = fopen(filename, "re"); if (f == NULL) return -errno; match[0] = '\0'; + cond[0] = '\0'; while (fgets(line, sizeof(line), f)) { size_t len; @@ -412,6 +426,7 @@ static int import_file(struct trie *trie, const char *filename) { /* new line, new record */ if (line[0] == '\n') { match[0] = '\0'; + cond[0] = '\0'; continue; } @@ -424,9 +439,19 @@ static int import_file(struct trie *trie, const char *filename) { /* start of new record */ if (match[0] == '\0') { strcpy(match, line); + cond[0] = '\0'; continue; } + if (line[0] == '+') { + strcpy(cond, line); + continue; + } + + /* TODO: support +; skip the entire record until we support it */ + if (cond[0] != '\0') + continue; + /* value lines */ if (line[0] == ' ') { char *value; @@ -444,27 +469,32 @@ static int import_file(struct trie *trie, const char *filename) { } static void help(void) { - printf("Usage: udevadm hwdb [--create] [--help]\n" + printf("Usage: udevadm hwdb OPTIONS\n" " --update update the hardware database\n" + " --test= query database and print result\n" + " --root= alternative root path in the filesystem\n" " --help\n\n"); } static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { static const struct option options[] = { { "update", no_argument, NULL, 'u' }, + { "root", required_argument, NULL, 'r' }, + { "test", required_argument, NULL, 't' }, { "help", no_argument, NULL, 'h' }, {} }; + const char *test = NULL; + const char *root = ""; bool update = false; - struct trie *trie; - char **files, **f; + struct trie *trie = NULL; int err; int rc = EXIT_SUCCESS; for (;;) { int option; - option = getopt_long(argc, argv, "ch", options, NULL); + option = getopt_long(argc, argv, "ut:r:h", options, NULL); if (option == -1) break; @@ -472,72 +502,106 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { case 'u': update = true; break; + case 't': + test = optarg; + break; + case 'r': + root = optarg; + break; case 'h': help(); return EXIT_SUCCESS; } } - if (!update) { + if (!update && !test) { help(); return EXIT_SUCCESS; } - trie = calloc(sizeof(struct trie), 1); - if (!trie) { - rc = EXIT_FAILURE; - goto out; - } + if (update) { + char **files, **f; + _cleanup_free_ char *hwdb_bin = NULL; - /* string store */ - trie->strings = strbuf_new(); - if (!trie->strings) { - rc = EXIT_FAILURE; - goto out; - } + trie = calloc(sizeof(struct trie), 1); + if (!trie) { + rc = EXIT_FAILURE; + goto out; + } - /* index */ - trie->root = calloc(sizeof(struct trie_node), 1); - if (!trie->root) { - rc = EXIT_FAILURE; - goto out; - } - trie->nodes_count++; + /* string store */ + trie->strings = strbuf_new(); + if (!trie->strings) { + rc = EXIT_FAILURE; + goto out; + } - err = conf_files_list_strv(&files, ".hwdb", (const char **)conf_file_dirs); - if (err < 0) { - log_error("failed to enumerate hwdb files: %s\n", strerror(-err)); - rc = EXIT_FAILURE; - goto out; - } - STRV_FOREACH(f, files) { - log_debug("reading file '%s'", *f); - import_file(trie, *f); - } - strv_free(files); - - strbuf_complete(trie->strings); - - log_debug("=== trie in-memory ===\n"); - log_debug("nodes: %8zu bytes (%8zu)\n", trie->nodes_count * sizeof(struct trie_node), trie->nodes_count); - log_debug("children arrays: %8zu bytes (%8zu)\n", trie->children_count * sizeof(struct trie_child_entry), trie->children_count); - log_debug("values arrays: %8zu bytes (%8zu)\n", trie->values_count * sizeof(struct trie_value_entry), trie->values_count); - log_debug("strings: %8zu bytes\n", trie->strings->len); - log_debug("strings incoming: %8zu bytes (%8zu)\n", trie->strings->in_len, trie->strings->in_count); - log_debug("strings dedup'ed: %8zu bytes (%8zu)\n", trie->strings->dedup_len, trie->strings->dedup_count); - - mkdir_parents(SYSCONFDIR "/udev/hwdb.bin", 0755); - err = trie_store(trie, SYSCONFDIR "/udev/hwdb.bin"); - if (err < 0) { - log_error("Failure writing hardware database '%s': %s", SYSCONFDIR "/udev/hwdb.bin", strerror(-err)); - rc = EXIT_FAILURE; + /* index */ + trie->root = calloc(sizeof(struct trie_node), 1); + if (!trie->root) { + rc = EXIT_FAILURE; + goto out; + } + trie->nodes_count++; + + err = conf_files_list_strv(&files, ".hwdb", root, (const char **)conf_file_dirs); + if (err < 0) { + log_error("failed to enumerate hwdb files: %s\n", strerror(-err)); + rc = EXIT_FAILURE; + goto out; + } + STRV_FOREACH(f, files) { + log_debug("reading file '%s'", *f); + import_file(trie, *f); + } + strv_free(files); + + strbuf_complete(trie->strings); + + log_debug("=== trie in-memory ===\n"); + log_debug("nodes: %8zu bytes (%8zu)\n", + trie->nodes_count * sizeof(struct trie_node), trie->nodes_count); + log_debug("children arrays: %8zu bytes (%8zu)\n", + trie->children_count * sizeof(struct trie_child_entry), trie->children_count); + log_debug("values arrays: %8zu bytes (%8zu)\n", + trie->values_count * sizeof(struct trie_value_entry), trie->values_count); + log_debug("strings: %8zu bytes\n", + trie->strings->len); + log_debug("strings incoming: %8zu bytes (%8zu)\n", + trie->strings->in_len, trie->strings->in_count); + log_debug("strings dedup'ed: %8zu bytes (%8zu)\n", + trie->strings->dedup_len, trie->strings->dedup_count); + + if (asprintf(&hwdb_bin, "%s/etc/udev/hwdb.bin", root) < 0) { + rc = EXIT_FAILURE; + goto out; + } + mkdir_parents(hwdb_bin, 0755); + err = trie_store(trie, hwdb_bin); + if (err < 0) { + log_error("Failure writing database %s: %s", hwdb_bin, strerror(-err)); + rc = EXIT_FAILURE; + } } + if (test) { + struct udev_hwdb *hwdb = udev_hwdb_new(udev); + + if (hwdb) { + struct udev_list_entry *entry; + + 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); + } + } out: - if (trie->root) - trie_node_cleanup(trie->root); - strbuf_cleanup(trie->strings); - free(trie); + if (trie) { + if (trie->root) + trie_node_cleanup(trie->root); + strbuf_cleanup(trie->strings); + free(trie); + } return rc; }