sd-hwdb.c revision 8927b1dad2d4a7330174cb924090b4635a2547fb
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen This file is part of systemd.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Copyright 2012 Kay Sievers <kay@vrfy.org>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Copyright 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen systemd is free software; you can redistribute it and/or modify it
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen under the terms of the GNU Lesser General Public License as published by
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (at your option) any later version.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen systemd is distributed in the hope that it will be useful, but
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Lesser General Public License for more details.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen You should have received a copy of the GNU Lesser General Public License
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char *map;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void linebuf_init(struct linebuf *buf) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const char *linebuf_get(struct linebuf *buf) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic bool linebuf_add_char(struct linebuf *buf, char c)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void linebuf_rem(struct linebuf *buf, size_t count) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void linebuf_rem_char(struct linebuf *buf) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const struct trie_child_entry_f *trie_node_children(sd_hwdb *hwdb, const struct trie_node_f *node) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return (const struct trie_child_entry_f *)((const char *)node + le64toh(hwdb->head->node_size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const struct trie_value_entry_f *trie_node_values(sd_hwdb *hwdb, const struct trie_node_f *node) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen base += node->children_count * le64toh(hwdb->head->child_entry_size);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return (const struct trie_value_entry_f *)base;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const struct trie_node_f *trie_node_from_off(sd_hwdb *hwdb, le64_t off) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return (const struct trie_node_f *)(hwdb->map + le64toh(off));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const char *trie_string(sd_hwdb *hwdb, le64_t off) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int trie_children_cmp_f(const void *v1, const void *v2) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen child = bsearch(&search, trie_node_children(hwdb, node), node->children_count,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen le64toh(hwdb->head->child_entry_size), trie_children_cmp_f);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return trie_node_from_off(hwdb, child->child_off);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int hwdb_add_property(sd_hwdb *hwdb, const char *key, const char *value) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * Silently ignore all properties which do not start with a
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * space; future extensions might use additional prefixes.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = ordered_hashmap_replace(hwdb->properties, key, (char*)value);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t p,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i];
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < le64toh(node->values_count); i++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[i].key_off),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen trie_string(hwdb, trie_node_values(hwdb, node)[i].value_off));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int trie_search_f(sd_hwdb *hwdb, const char *search) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (c != search[i + p])
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (n = 0; n < le64toh(node->values_count); n++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[n].key_off),
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen trie_string(hwdb, trie_node_values(hwdb, node)[n].value_off));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const char hwdb_bin_paths[] =
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* find hwdb.bin in hwdb_bin_paths */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("hwdb.bin does not exist, please run udevadm hwdb --update");
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return log_debug_errno(errno, "error mapping %s: %m", hwdb_bin_path);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen (size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("error recognizing the format of %s", hwdb_bin_path);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("tool version: %"PRIu64, le64toh(hwdb->head->tool_version));
1fa2f38f0f011010bf57522b42fcc168856a7003Zbigniew Jędrzejewski-Szmek log_debug("file size: %8"PRIi64" bytes", hwdb->st.st_size);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("header size %8"PRIu64" bytes", le64toh(hwdb->head->header_size));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("strings %8"PRIu64" bytes", le64toh(hwdb->head->strings_len));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("nodes %8"PRIu64" bytes", le64toh(hwdb->head->nodes_len));
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen bool found = false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char* p;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* if hwdb.bin doesn't exist anywhere, we need to update */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int properties_prepare(sd_hwdb *hwdb, const char *modalias) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen value = ordered_hashmap_get(hwdb->properties, key);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann const void *k;