chiark / gitweb /
remove unused variable
[elogind.git] / src / udev / udevadm-hwdb.c
index 3e849aaed6c7eda6e44f68ae7d4529ace5d06484..61a3b081994dc0566f4baed441811c87aa01c244 100644 (file)
@@ -21,6 +21,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <string.h>
+#include <ctype.h>
 
 #include "util.h"
 #include "strbuf.h"
@@ -302,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);
         }
@@ -402,100 +405,150 @@ 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;
+                        }
+
+                        /* first data */
+                        state = HW_DATA;
+                        insert_data(trie, &match_list, line, filename);
+                        break;
 
-                /* value lines */
-                if (line[0] == ' ') {
-                        char *value;
+                case HW_DATA:
+                        /* end of record */
+                        if (len == 0) {
+                                state = HW_NONE;
+                                udev_list_cleanup(&match_list);
+                                break;
+                        }
 
-                        value = strchr(line, '=');
-                        if (!value)
-                                continue;
-                        value[0] = '\0';
-                        value++;
-                        trie_insert(trie, trie->root, match, line, value);
-                }
+                        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;
 }
 
 static void help(void) {
         printf("Usage: udevadm hwdb OPTIONS\n"
-               "  --update            update the hardware database\n"
-               "  --test=<modalias>   query database and print result\n"
-               "  --root=<path>       alternative root path in the filesystem\n"
-               "  --help\n\n");
+               "  -u,--update          update the hardware database\n"
+               "  -t,--test=MODALIAS   query database and print result\n"
+               "  -r,--root=PATH       alternative root path in the filesystem\n"
+               "  -h,--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' },
+                { "update", no_argument,       NULL, 'u' },
+                { "test",   required_argument, NULL, 't' },
+                { "root",   required_argument, NULL, 'r' },
+                { "help",   no_argument,       NULL, 'h' },
                 {}
         };
         const char *test = NULL;
         const char *root = "";
         bool update = false;
         struct trie *trie = NULL;
-        int err;
+        int err, c;
         int rc = EXIT_SUCCESS;
 
-        for (;;) {
-                int option;
-
-                option = getopt_long(argc, argv, "ut:r:h", options, NULL);
-                if (option == -1)
-                        break;
-
-                switch (option) {
+        while ((c = getopt_long(argc, argv, "ut:r:h", options, NULL)) >= 0)
+                switch(c) {
                 case 'u':
                         update = true;
                         break;
@@ -508,12 +561,15 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
                 case 'h':
                         help();
                         return EXIT_SUCCESS;
+                case '?':
+                        return EXIT_FAILURE;
+                default:
+                        assert_not_reached("Unknown option");
                 }
-        }
 
         if (!update && !test) {
-                help();
-                return EXIT_SUCCESS;
+                log_error("Either --update or --test must be used");
+                return EXIT_FAILURE;
         }
 
         if (update) {
@@ -549,7 +605,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);
 
@@ -589,7 +645,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: