udevadm-hwdb.c revision e32a4e1ef4c61561b08f50f73f82587bdc946b40
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/***
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering This file is part of systemd.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is free software; you can redistribute it and/or modify it
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers under the terms of the GNU Lesser General Public License as published by
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (at your option) any later version.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is distributed in the hope that it will be useful, but
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Lesser General Public License for more details.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering You should have received a copy of the GNU Lesser General Public License
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering***/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <stdlib.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <unistd.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <getopt.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <string.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "strbuf.h"
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include "conf-files.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "udev.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "libudev-hwdb-def.h"
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen/*
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen * Generic udev properties, key/value database based on modalias strings.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * Uses a Patricia/radix trie to index all matches for efficient lookup.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic const char * const conf_file_dirs[] = {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/etc/udev/hwdb.d",
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers UDEVLIBEXECDIR "/hwdb.d",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering NULL
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering};
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering/* in-memory trie objects */
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallacestruct trie {
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering struct trie_node *root;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct strbuf *strings;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t nodes_count;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t children_count;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t values_count;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering};
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstruct trie_node {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* prefix, common part for all children of this node */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t prefix_off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* sorted array of pointers to children nodes */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct trie_child_entry *children;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering uint8_t children_count;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* sorted array of key/value pairs */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct trie_value_entry *values;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t values_count;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering};
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers/* children array item with char (0-255) index */
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstruct trie_child_entry {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers uint8_t c;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers struct trie_node *child;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers};
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers/* value array item with key/value pairs */
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstruct trie_value_entry {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t key_off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t value_off;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers};
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sieversstatic int trie_children_cmp(const void *v1, const void *v2) {
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers const struct trie_child_entry *n1 = v1;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers const struct trie_child_entry *n2 = v2;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers return n1->c - n2->c;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers}
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sieversstatic int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers struct trie_child_entry *child;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers int err = 0;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers /* extend array, add new entry, sort for bisection */
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers child = realloc(node->children, (node->children_count + 1) * sizeof(struct trie_child_entry));
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers if (!child) {
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers err = -ENOMEM;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers node->children = child;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->children_count++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering node->children[node->children_count].c = c;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers node->children[node->children_count].child = node_child;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers node->children_count++;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers trie->nodes_count++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringout:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return err;
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering}
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstatic struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers struct trie_child_entry *child;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers struct trie_child_entry search;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers search.c = c;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers child = bsearch(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers if (child)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return child->child;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return NULL;
2af32104c47dadf426f2e7697cd7382520476fc5Lennart Poettering}
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sieversstatic void trie_node_cleanup(struct trie_node *node) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t i;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
2af32104c47dadf426f2e7697cd7382520476fc5Lennart Poettering for (i = 0; i < node->children_count; i++)
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers trie_node_cleanup(node->children[i].child);
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers free(node->children);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free(node->values);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers free(node);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstatic int trie_values_cmp(const void *v1, const void *v2, void *arg) {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers const struct trie_value_entry *val1 = v1;
7f35b7bc4a241e9aa3b1512fd345cbf5b2e5a782Kay Sievers const struct trie_value_entry *val2 = v2;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers struct trie *trie = arg;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers return strcmp(trie->strings->buf + val1->key_off,
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers trie->strings->buf + val2->key_off);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
bd5ce8e9fc10a593822344c098ccbe8c47fe34e9Lennart Poetteringstatic int trie_node_add_value(struct trie *trie, struct trie_node *node,
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers const char *key, const char *value) {
bd5ce8e9fc10a593822344c098ccbe8c47fe34e9Lennart Poettering ssize_t k, v;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct trie_value_entry *val;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering k = strbuf_add_string(trie->strings, key, strlen(key));
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers if (k < 0)
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers return k;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers v = strbuf_add_string(trie->strings, value, strlen(value));
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers if (v < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return v;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers if (node->values_count) {
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers struct trie_value_entry search = {
e2fd5e5ba281a22886fa3797dc6265cca670448bKay Sievers .key_off = k,
e2fd5e5ba281a22886fa3797dc6265cca670448bKay Sievers .value_off = v,
e2fd5e5ba281a22886fa3797dc6265cca670448bKay Sievers };
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers if (val) {
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers /* replace existing earlier key with new value */
2af32104c47dadf426f2e7697cd7382520476fc5Lennart Poettering val->value_off = v;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers return 0;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers }
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers }
2af32104c47dadf426f2e7697cd7382520476fc5Lennart Poettering
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers /* extend array, add new entry, sort for bisection */
3062c15117ab6eac5e8b3a3ceb5351ec22ea4481Lennart Poettering val = realloc(node->values, (node->values_count + 1) * sizeof(struct trie_value_entry));
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers if (!val)
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers return -ENOMEM;
3062c15117ab6eac5e8b3a3ceb5351ec22ea4481Lennart Poettering trie->values_count++;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers node->values = val;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers node->values[node->values_count].key_off = k;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers node->values[node->values_count].value_off = v;
2af32104c47dadf426f2e7697cd7382520476fc5Lennart Poettering node->values_count++;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers return 0;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers}
2af32104c47dadf426f2e7697cd7382520476fc5Lennart Poettering
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sieversstatic int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
3062c15117ab6eac5e8b3a3ceb5351ec22ea4481Lennart Poettering const char *key, const char *value) {
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers size_t i = 0;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers int err = 0;
3062c15117ab6eac5e8b3a3ceb5351ec22ea4481Lennart Poettering
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers for (;;) {
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers size_t p;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers uint8_t c;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers struct trie_node *child;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char *s;
e9dd9f9547350c7dc0473583b5c2228dc8f0ab76Jason St. John ssize_t off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (c == search[i + p])
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* split node */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen child = calloc(sizeof(struct trie_node), 1);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!child) {
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek err = -ENOMEM;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers goto out;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers /* move values from parent to child */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers child->prefix_off = node->prefix_off + p+1;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers child->children = node->children;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers child->children_count = node->children_count;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers child->values = node->values;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers child->values_count = node->values_count;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers /* update parent; use strdup() because the source gets realloc()d */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering s = strndup(trie->strings->buf + node->prefix_off, p);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!s) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = -ENOMEM;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers goto out;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers }
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers off = strbuf_add_string(trie->strings, s, p);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers free(s);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (off < 0) {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers err = off;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering node->prefix_off = off;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers node->children = NULL;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers node->children_count = 0;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers node->values = NULL;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers node->values_count = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = node_add_child(trie, node, child, c);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (err)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto out;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen break;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering i += p;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering c = search[i];
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (c == '\0')
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return trie_node_add_value(trie, node, key, value);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering child = node_lookup(node, c);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!child) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering ssize_t off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* new child */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering child = calloc(sizeof(struct trie_node), 1);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!child) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = -ENOMEM;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto out;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (off < 0) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen err = off;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto out;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen child->prefix_off = off;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen err = node_add_child(trie, node, child, c);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (err)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto out;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return trie_node_add_value(trie, child, key, value);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen node = child;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen i++;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringout:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return err;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstruct trie_f {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering FILE *f;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen struct trie *trie;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen uint64_t strings_off;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen uint64_t nodes_count;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen uint64_t children_count;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen uint64_t values_count;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen};
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen/* calculate the storage space for the nodes, children arrays, value arrays */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersenstatic void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen uint64_t i;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (i = 0; i < node->children_count; i++)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie_store_nodes_size(trie, node->children[i].child);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen trie->strings_off += sizeof(struct trie_node_f);
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering for (i = 0; i < node->children_count; i++)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->strings_off += sizeof(struct trie_child_entry_f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (i = 0; i < node->values_count; i++)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->strings_off += sizeof(struct trie_value_entry_f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering uint64_t i;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering struct trie_node_f n = {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .prefix_off = htole64(trie->strings_off + node->prefix_off),
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering .children_count = node->children_count,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .values_count = htole64(node->values_count),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering };
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen struct trie_child_entry_f *children = NULL;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen int64_t node_off;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (node->children_count) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen children = new0(struct trie_child_entry_f, node->children_count);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!children)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return -ENOMEM;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen /* post-order recursion */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen for (i = 0; i < node->children_count; i++) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen int64_t child_off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering child_off = trie_store_nodes(trie, node->children[i].child);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (child_off < 0)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return child_off;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering children[i].c = node->children[i].c;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering children[i].child_off = htole64(child_off);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* write node */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering node_off = ftello(trie->f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering trie->nodes_count++;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* append children array */
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering if (node->children_count) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->children_count += node->children_count;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen free(children);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen /* append values array */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen for (i = 0; i < node->values_count; i++) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen struct trie_value_entry_f v = {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen .key_off = htole64(trie->strings_off + node->values[i].key_off),
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering .value_off = htole64(trie->strings_off + node->values[i].value_off),
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen };
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen trie->values_count++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return node_off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
f75cb30bf97f623417cc7ee4b1bcc5c36cdbeb20Dave Reisnerstatic int trie_store(struct trie *trie, const char *filename) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct trie_f t = {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .trie = trie,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering };
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char *filename_tmp;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int64_t pos;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int64_t root_off;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int64_t size;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct trie_header_f h = {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .signature = HWDB_SIG,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .tool_version = htole64(atoi(VERSION)),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .header_size = htole64(sizeof(struct trie_header_f)),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .node_size = htole64(sizeof(struct trie_node_f)),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering };
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int err;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* calculate size of header, nodes, children entries, value entries */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering t.strings_off = sizeof(struct trie_header_f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie_store_nodes_size(&t, trie->root);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = fopen_temporary(filename , &t.f, &filename_tmp);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (err < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return err;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fchmod(fileno(t.f), 0444);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* write nodes */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering root_off = trie_store_nodes(&t, trie->root);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h.nodes_root_off = htole64(root_off);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering pos = ftello(t.f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* write string buffer */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h.strings_len = htole64(trie->strings->len);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* write header */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = ftello(t.f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h.file_size = htole64(size);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fseeko(t.f, 0, SEEK_SET);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = ferror(t.f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (err)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = -errno;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fclose(t.f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (err < 0 || rename(filename_tmp, filename) < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering unlink(filename_tmp);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("=== trie on-disk ===\n");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("size: %8llu bytes\n", (unsigned long long)size);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("header: %8zu bytes\n", sizeof(struct trie_header_f));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("nodes: %8llu bytes (%8llu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (unsigned long long)t.nodes_count * sizeof(struct trie_node_f), (unsigned long long)t.nodes_count);
857a493d55f94731394e4d9f61ffce661858e9a0Lennart Poettering log_debug("child pointers: %8llu bytes (%8llu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (unsigned long long)t.children_count * sizeof(struct trie_child_entry_f), (unsigned long long)t.children_count);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("value pointers: %8llu bytes (%8llu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (unsigned long long)t.values_count * sizeof(struct trie_value_entry_f), (unsigned long long)t.values_count);
857a493d55f94731394e4d9f61ffce661858e9a0Lennart Poettering log_debug("string store: %8llu bytes\n", (unsigned long long)trie->strings->len);
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen log_debug("strings start: %8llu\n", (unsigned long long) t.strings_off);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringout:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free(filename_tmp);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return err;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int import_file(struct trie *trie, const char *filename) {
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering FILE *f;
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering char line[LINE_MAX];
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char match[LINE_MAX];
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char cond[LINE_MAX];
c978343015c787713651dff571acb5207367f5f2Lennart Poettering
c978343015c787713651dff571acb5207367f5f2Lennart Poettering f = fopen(filename, "re");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (f == NULL)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -errno;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen match[0] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering cond[0] = '\0';
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering while (fgets(line, sizeof(line), f)) {
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering size_t len;
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering if (line[0] == '#')
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering continue;
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* new line, new record */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (line[0] == '\n') {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering match[0] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering cond[0] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* remove newline */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering len = strlen(line);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (len < 2)
c978343015c787713651dff571acb5207367f5f2Lennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering line[len-1] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* start of new record */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (match[0] == '\0') {
c978343015c787713651dff571acb5207367f5f2Lennart Poettering strcpy(match, line);
c978343015c787713651dff571acb5207367f5f2Lennart Poettering cond[0] = '\0';
c978343015c787713651dff571acb5207367f5f2Lennart Poettering continue;
c978343015c787713651dff571acb5207367f5f2Lennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
c978343015c787713651dff571acb5207367f5f2Lennart Poettering if (line[0] == '+') {
c978343015c787713651dff571acb5207367f5f2Lennart Poettering strcpy(cond, line);
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* TODO: support +; skip the entire record until we support it */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (cond[0] != '\0')
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* value lines */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (line[0] == ' ') {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char *value;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering value = strchr(line, '=');
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!value)
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering value[0] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering value++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie_insert(trie, trie->root, match, line, value);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fclose(f);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return 0;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen}
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic void help(void) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering printf("Usage: udevadm hwdb OPTIONS\n"
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen " --update update the hardware database\n"
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen " --test <modalias> query database and print result\n"
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen " --help\n\n");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssenstatic int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen static const struct option options[] = {
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen { "update", no_argument, NULL, 'u' },
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen { "test", required_argument, NULL, 't' },
c978343015c787713651dff571acb5207367f5f2Lennart Poettering { "help", no_argument, NULL, 'h' },
c978343015c787713651dff571acb5207367f5f2Lennart Poettering {}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering };
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering const char *test = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bool update = false;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct trie *trie = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int err;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int rc = EXIT_SUCCESS;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (;;) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int option;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering option = getopt_long(argc, argv, "ut:h", options, NULL);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (option == -1)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering break;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering switch (option) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering case 'u':
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering update = true;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen break;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering case 't':
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering test = optarg;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering break;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering case 'h':
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering help();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return EXIT_SUCCESS;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!update && !test) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering help();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return EXIT_SUCCESS;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (update) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char **files, **f;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie = calloc(sizeof(struct trie), 1);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!trie) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering rc = EXIT_FAILURE;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* string store */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->strings = strbuf_new();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!trie->strings) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering rc = EXIT_FAILURE;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* index */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->root = calloc(sizeof(struct trie_node), 1);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!trie->root) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering rc = EXIT_FAILURE;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->nodes_count++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = conf_files_list_strv(&files, ".hwdb", (const char **)conf_file_dirs);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (err < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("failed to enumerate hwdb files: %s\n", strerror(-err));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering rc = EXIT_FAILURE;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto out;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering STRV_FOREACH(f, files) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("reading file '%s'", *f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering import_file(trie, *f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strv_free(files);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strbuf_complete(trie->strings);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("=== trie in-memory ===\n");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("nodes: %8zu bytes (%8zu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("children arrays: %8zu bytes (%8zu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("values arrays: %8zu bytes (%8zu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("strings: %8zu bytes\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->strings->len);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("strings incoming: %8zu bytes (%8zu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->strings->in_len, trie->strings->in_count);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("strings dedup'ed: %8zu bytes (%8zu)\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie->strings->dedup_len, trie->strings->dedup_count);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering mkdir_parents(HWDB_BIN, 0755);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering err = trie_store(trie, HWDB_BIN);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (err < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("Failure writing hardware database '%s': %s",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering HWDB_BIN, strerror(-err));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering rc = EXIT_FAILURE;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (test) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct udev_hwdb *hwdb = udev_hwdb_new(udev);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (hwdb) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct udev_list_entry *entry;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, test, 0))
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner hwdb = udev_hwdb_unref(hwdb);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringout:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (trie) {
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering if (trie->root)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering trie_node_cleanup(trie->root);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strbuf_cleanup(trie->strings);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen free(trie);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return rc;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringconst struct udevadm_cmd udevadm_hwdb = {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen .name = "hwdb",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering .cmd = adm_hwdb,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen .help = "maintain the hardware database index",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering};
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering