libudev-hwdb.c revision 8232e39e7cf32071e11b3b04839e6c98fbc81d0f
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering/***
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering This file is part of systemd.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is free software; you can redistribute it and/or modify it
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering under the terms of the GNU Lesser General Public License as published by
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering (at your option) any later version.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering systemd is distributed in the hope that it will be useful, but
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Lesser General Public License for more details.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering You should have received a copy of the GNU Lesser General Public License
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering***/
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <stdio.h>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include <errno.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <string.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <inttypes.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <ctype.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <stdlib.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <fnmatch.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <getopt.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include <sys/mman.h>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include "libudev-private.h"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering#include "libudev-hwdb-def.h"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering/**
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * SECTION:libudev-hwdb
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * @short_description: retrieve properties from the hardware database
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Libudev hardware database interface.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering/**
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * udev_hwdb:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Opaque object representing the hardware database.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstruct udev_hwdb {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct udev *udev;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering int refcount;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering FILE *f;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct stat st;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering union {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct trie_header_f *head;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char *map;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering };
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct udev_list properties_list;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering};
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstruct linebuf {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering char bytes[LINE_MAX];
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t size;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t len;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering};
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic void linebuf_init(struct linebuf *buf) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering buf->size = 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering buf->len = 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const char *linebuf_get(struct linebuf *buf) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (buf->len + 1 >= sizeof(buf->bytes))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return NULL;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering buf->bytes[buf->len] = '\0';
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return buf->bytes;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (buf->len + len >= sizeof(buf->bytes))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return false;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering memcpy(buf->bytes + buf->len, s, len);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering buf->len += len;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return true;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic bool linebuf_add_char(struct linebuf *buf, char c)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering{
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (buf->len + 1 >= sizeof(buf->bytes))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return false;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering buf->bytes[buf->len++] = c;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return true;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic void linebuf_rem(struct linebuf *buf, size_t count) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering assert(buf->len >= count);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering buf->len -= count;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic void linebuf_rem_char(struct linebuf *buf) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_rem(buf, 1);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const struct trie_child_entry_f *trie_node_children(struct udev_hwdb *hwdb, const struct trie_node_f *node) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return (const struct trie_child_entry_f *)((const char *)node + le64toh(hwdb->head->node_size));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const struct trie_value_entry_f *trie_node_values(struct udev_hwdb *hwdb, const struct trie_node_f *node) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char *base = (const char *)node;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering base += le64toh(hwdb->head->node_size);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering base += node->children_count * le64toh(hwdb->head->child_entry_size);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return (const struct trie_value_entry_f *)base;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const struct trie_node_f *trie_node_from_off(struct udev_hwdb *hwdb, le64_t off) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return (const struct trie_node_f *)(hwdb->map + le64toh(off));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const char *trie_string(struct udev_hwdb *hwdb, le64_t off) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return hwdb->map + le64toh(off);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int trie_children_cmp_f(const void *v1, const void *v2) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const struct trie_child_entry_f *n1 = v1;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const struct trie_child_entry_f *n2 = v2;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return n1->c - n2->c;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const struct trie_node_f *node_lookup_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct trie_child_entry_f *child;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct trie_child_entry_f search;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering search.c = c;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering child = bsearch(&search, trie_node_children(hwdb, node), node->children_count,
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering le64toh(hwdb->head->child_entry_size), trie_children_cmp_f);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (child)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return trie_node_from_off(hwdb, child->child_off);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return NULL;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int hwdb_add_property(struct udev_hwdb *hwdb, const char *key, const char *value) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /*
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Silently ignore all properties which do not start with a
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * space; future extensions might use additional prefixes.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (key[0] != ' ')
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (udev_list_entry_add(&hwdb->properties_list, key+1, value) == NULL)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return -ENOMEM;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int trie_fnmatch_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, size_t p,
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct linebuf *buf, const char *search) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t len;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t i;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char *prefix;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering int err;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering prefix = trie_string(hwdb, node->prefix_off);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering len = strlen(prefix + p);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_add(buf, prefix + p, len);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (i = 0; i < node->children_count; i++) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i];
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_add_char(buf, child->c);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (err < 0)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return err;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_rem_char(buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (i = 0; i < le64toh(node->values_count); i++) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[i].key_off),
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering trie_string(hwdb, trie_node_values(hwdb, node)[i].value_off));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (err < 0)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return err;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_rem(buf, len);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int trie_search_f(struct udev_hwdb *hwdb, const char *search) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct linebuf buf;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const struct trie_node_f *node;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t i = 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering int err;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_init(&buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering while (node) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const struct trie_node_f *child;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering size_t p = 0;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering if (node->prefix_off) {
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering uint8_t c;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (c == '*' || c == '?' || c == '[')
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (c != search[i + p])
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering return 0;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering }
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering i += p;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering child = node_lookup_f(hwdb, node, '*');
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (child) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_add_char(&buf, '*');
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering if (err < 0)
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering return err;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering linebuf_rem_char(&buf);
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering }
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering child = node_lookup_f(hwdb, node, '?');
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering if (child) {
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering linebuf_add_char(&buf, '?');
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (err < 0)
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering return err;
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering linebuf_rem_char(&buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering child = node_lookup_f(hwdb, node, '[');
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (child) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_add_char(&buf, '[');
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (err < 0)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return err;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering linebuf_rem_char(&buf);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (search[i] == '\0') {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering size_t n;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (n = 0; n < le64toh(node->values_count); n++) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[n].key_off),
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering trie_string(hwdb, trie_node_values(hwdb, node)[n].value_off));
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (err < 0)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return err;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering child = node_lookup_f(hwdb, node, search[i]);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering node = child;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering i++;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering }
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return 0;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering}
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const char hwdb_bin_paths[] =
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering "/etc/udev/hwdb.bin\0"
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering UDEVLIBEXECDIR "/hwdb.bin\0";
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering/**
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * udev_hwdb_new:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * @udev: udev library context
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Create a hardware database context to query properties for devices.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering *
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Returns: a hwdb context.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering **/
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering struct udev_hwdb *hwdb;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char *hwdb_bin_path;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering const char sig[] = HWDB_SIG;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering hwdb = new0(struct udev_hwdb, 1);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (!hwdb)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return NULL;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering hwdb->refcount = 1;
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering udev_list_init(udev, &hwdb->properties_list, true);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* find hwdb.bin in hwdb_bin_paths */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
hwdb->f = fopen(hwdb_bin_path, "re");
if (hwdb->f)
break;
else if (errno == ENOENT)
continue;
else {
udev_dbg(udev, "error reading %s: %m", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
}
if (!hwdb->f) {
udev_dbg(udev, "hwdb.bin does not exist, please run udevadm hwdb --update");
udev_hwdb_unref(hwdb);
return NULL;
}
if (fstat(fileno(hwdb->f), &hwdb->st) < 0 ||
(size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8) {
udev_dbg(udev, "error reading %s: %m", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
if (hwdb->map == MAP_FAILED) {
udev_dbg(udev, "error mapping %s: %m", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
(size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
udev_dbg(udev, "error recognizing the format of %s", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
udev_dbg(udev, "=== trie on-disk ===\n");
udev_dbg(udev, "tool version: %"PRIu64, le64toh(hwdb->head->tool_version));
udev_dbg(udev, "file size: %8"PRIu64" bytes\n", hwdb->st.st_size);
udev_dbg(udev, "header size %8"PRIu64" bytes\n", le64toh(hwdb->head->header_size));
udev_dbg(udev, "strings %8"PRIu64" bytes\n", le64toh(hwdb->head->strings_len));
udev_dbg(udev, "nodes %8"PRIu64" bytes\n", le64toh(hwdb->head->nodes_len));
return hwdb;
}
/**
* udev_hwdb_ref:
* @hwdb: context
*
* Take a reference of a hwdb context.
*
* Returns: the passed enumeration context
**/
_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) {
if (!hwdb)
return NULL;
hwdb->refcount++;
return hwdb;
}
/**
* udev_hwdb_unref:
* @hwdb: context
*
* Drop a reference of a hwdb context. If the refcount reaches zero,
* all resources of the hwdb context will be released.
*
* Returns: #NULL
**/
_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
if (!hwdb)
return NULL;
hwdb->refcount--;
if (hwdb->refcount > 0)
return NULL;
if (hwdb->map)
munmap((void *)hwdb->map, hwdb->st.st_size);
if (hwdb->f)
fclose(hwdb->f);
udev_list_cleanup(&hwdb->properties_list);
free(hwdb);
return NULL;
}
bool udev_hwdb_validate(struct udev_hwdb *hwdb) {
bool found = false;
const char* p;
struct stat st;
if (!hwdb)
return false;
if (!hwdb->f)
return false;
/* if hwdb.bin doesn't exist anywhere, we need to update */
NULSTR_FOREACH(p, hwdb_bin_paths) {
if (stat(p, &st) >= 0) {
found = true;
break;
}
}
if (!found)
return true;
if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
return true;
return false;
}
/**
* udev_hwdb_get_properties_list_entry:
* @hwdb: context
* @modalias: modalias string
* @flags: (unused)
*
* Lookup a matching device in the hardware database. The lookup key is a
* modalias string, whose formats are defined for the Linux kernel modules.
* Examples are: pci:v00008086d00001C2D*, usb:v04F2pB221*. The first entry
* of a list of retrieved properties is returned.
*
* Returns: a udev_list_entry.
*/
_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags) {
int err;
if (!hwdb || !hwdb->f) {
errno = EINVAL;
return NULL;
}
udev_list_cleanup(&hwdb->properties_list);
err = trie_search_f(hwdb, modalias);
if (err < 0) {
errno = -err;
return NULL;
}
return udev_list_get_entry(&hwdb->properties_list);
}