/***
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
#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.
*/
static const char * const conf_file_dirs[] = {
- SYSCONFDIR "/udev/hwdb.d",
+ "/etc/udev/hwdb.d",
UDEVLIBEXECDIR "/hwdb.d",
NULL
};
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 */
.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) {
}
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);
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;
/* new line, new record */
if (line[0] == '\n') {
match[0] = '\0';
+ cond[0] = '\0';
continue;
}
/* 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;
}
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"
+ " --root=<path> 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;
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, 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;
}