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