chiark / gitweb /
hwdb: fix usage
[elogind.git] / src / udev / udevadm-hwdb.c
index 52fe1d4ebc5c5fb45dfa2526a334dc0b0142e741..00c0d3d4c4ac5dba15aabc7782ec6651cda189b7 100644 (file)
@@ -1,7 +1,7 @@
 /***
   This file is part of systemd.
 
-  Copyright 2012 Kay Sievers <kay.sievers@vrfy.org>
+  Copyright 2012 Kay Sievers <kay@vrfy.org>
 
   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,29 @@ 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 <modalias>   query database and print result\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' },
+                { "test", required_argument, NULL, 't' },
                 { "help", no_argument, NULL, 'h' },
                 {}
         };
+        const char *test = NULL;
         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:h", options, NULL);
                 if (option == -1)
                         break;
 
@@ -472,72 +499,99 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
                 case 'u':
                         update = true;
                         break;
+                case 't':
+                        test = 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;
 
-        /* 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", (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(HWDB_BIN, 0755);
+                err = trie_store(trie, HWDB_BIN);
+                if (err < 0) {
+                        log_error("Failure writing hardware 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;
 }