libudev-hwdb.c revision f2d433e178df7df01a836e95775261e1d85ec60d
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2012 Kay Sievers <kay.sievers@vrfy.org>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdio.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <errno.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <string.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <inttypes.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <ctype.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <stdlib.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <fnmatch.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <getopt.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <sys/mman.h>
c34255bdb217c2a1d3ac6348252437ab8be9ca46Lennart Poettering
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering#include "libudev-private.h"
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering#include "libudev-hwdb-def.h"
6482f6269c87d2249e52e889a63adbdd50f2d691Ronny Chevalier
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/**
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * SECTION:libudev-hwdb
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * @short_description: retrieve properties from the hardware database
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Libudev hardware database interface.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/**
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * udev_hwdb:
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt *
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt * Opaque object representing the hardware database.
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstruct udev_hwdb {
d3e84ddb885e9d5f0ae9930eb905910e3a81f157Lennart Poettering struct udev *udev;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int refcount;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering FILE *f;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct stat st;
afc6adb5ec7e73bc13156c43f52fb015cd80cc68Lennart Poettering union {
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering struct trie_header_f *head;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *map;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering };
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct udev_list properties_list;
cde93897cdefdd7c7f66c400a61e42ceee5f6a46Lennart Poettering};
cde93897cdefdd7c7f66c400a61e42ceee5f6a46Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstruct linebuf {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char bytes[LINE_MAX];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t size;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t len;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering};
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void linebuf_init(struct linebuf *buf) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering buf->size = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering buf->len = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const char *linebuf_get(struct linebuf *buf) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (buf->len + 1 >= sizeof(buf->bytes))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
d3e84ddb885e9d5f0ae9930eb905910e3a81f157Lennart Poettering buf->bytes[buf->len] = '\0';
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return buf->bytes;
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering}
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poetteringstatic bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering if (buf->len + len >= sizeof(buf->bytes))
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering return false;
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering memcpy(buf->bytes + buf->len, s, len);
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering buf->len += len;
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering return true;
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic bool linebuf_add_char(struct linebuf *buf, char c)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering{
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (buf->len + 1 >= sizeof(buf->bytes))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return false;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering buf->bytes[buf->len++] = c;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void linebuf_rem(struct linebuf *buf, size_t count) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(buf->len >= count);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering buf->len -= count;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void linebuf_rem_char(struct linebuf *buf) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering linebuf_rem(buf, 1);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const struct trie_child_entry_f *trie_node_children(struct udev_hwdb *hwdb, const struct trie_node_f *node) {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt return (const struct trie_child_entry_f *)((const char *)node + le64toh(hwdb->head->node_size));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const struct trie_value_entry_f *trie_node_values(struct udev_hwdb *hwdb, const struct trie_node_f *node) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *base = (const char *)node;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering base += le64toh(hwdb->head->node_size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering base += node->children_count * le64toh(hwdb->head->child_entry_size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return (const struct trie_value_entry_f *)base;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poetteringstatic const struct trie_node_f *trie_node_from_off(struct udev_hwdb *hwdb, le64_t off) {
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering return (const struct trie_node_f *)(hwdb->map + le64toh(off));
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering}
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const char *trie_string(struct udev_hwdb *hwdb, le64_t off) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return hwdb->map + le64toh(off);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int trie_children_cmp_f(const void *v1, const void *v2) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const struct trie_child_entry_f *n1 = v1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const struct trie_child_entry_f *n2 = v2;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return n1->c - n2->c;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic const struct trie_node_f *node_lookup_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct trie_child_entry_f *child;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct trie_child_entry_f search;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering search.c = c;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering child = bsearch(&search, trie_node_children(hwdb, node), node->children_count,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(hwdb->head->child_entry_size), trie_children_cmp_f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (child)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return trie_node_from_off(hwdb, child->child_off);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int hwdb_add_property(struct udev_hwdb *hwdb, const char *key, const char *value) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* TODO: add sub-matches (+) against DMI data */
76b543756ef69ce69784d571aefe8de65eaeb331Lennart Poettering if (key[0] != ' ')
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return 0;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (udev_list_entry_add(&hwdb->properties_list, key+1, value) == NULL)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENOMEM;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering return 0;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt}
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int trie_fnmatch_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, size_t p,
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering struct linebuf *buf, const char *search) {
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt size_t len;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt size_t i;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const char *prefix;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering int err;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt prefix = trie_string(hwdb, node->prefix_off);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering len = strlen(prefix + p);
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering linebuf_add(buf, prefix + p, len);
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering for (i = 0; i < node->children_count; i++) {
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i];
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering linebuf_add_char(buf, child->c);
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering if (err < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return err;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering linebuf_rem_char(buf);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (node->values_count && fnmatch(linebuf_get(buf), search, 0) == 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (i = 0; i < node->values_count; i++) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[i].key_off),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering trie_string(hwdb, trie_node_values(hwdb, node)[i].value_off));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (err < 0)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return err;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering linebuf_rem(buf, len);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int trie_search_f(struct udev_hwdb *hwdb, const char *search) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct linebuf buf;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const struct trie_node_f *node;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering size_t i = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int err;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt linebuf_init(&buf);
943aca8efb39453e3994ccdd1e08534b788c5aeeLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering while (node) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering const struct trie_node_f *child;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering size_t p = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
11b90e69e5620c2483b019340eff121d504db115Lennart Poettering if (node->prefix_off) {
11b90e69e5620c2483b019340eff121d504db115Lennart Poettering uint8_t c;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (c == '*' || c == '?' || c == '[')
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (c != search[i + p])
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering i += p;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering child = node_lookup_f(hwdb, node, '*');
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (child) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering linebuf_add_char(&buf, '*');
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (err < 0)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return err;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering linebuf_rem_char(&buf);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering child = node_lookup_f(hwdb, node, '?');
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (child) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering linebuf_add_char(&buf, '?');
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (err < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return err;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering linebuf_rem_char(&buf);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering child = node_lookup_f(hwdb, node, '[');
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (child) {
5bb658a1784a0fd4f0f32adb4b1fb636ff503f7dKay Sievers linebuf_add_char(&buf, '[');
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (err < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return err;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering linebuf_rem_char(&buf);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt }
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (search[i] == '\0') {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t n;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (n = 0; n < node->values_count; n++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[n].key_off),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering trie_string(hwdb, trie_node_values(hwdb, node)[n].value_off));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (err < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return err;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
71fda00f320379f5cbee8e118848de98caaa229dLennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering child = node_lookup_f(hwdb, node, search[i]);
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering node = child;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/**
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * udev_hwdb_new:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * @udev: udev library context
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * Create a hardware database context to query properties for devices.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Returns: a hwdb context.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering **/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct udev_hwdb *hwdb;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char sig[] = HWDB_SIG;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb = new0(struct udev_hwdb, 1);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb->refcount = 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_list_init(udev, &hwdb->properties_list, true);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb->f = fopen("/etc/udev/hwdb.bin", "re");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!hwdb->f) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_debug("error reading /etc/udev/hwdb.bin: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_hwdb_unref(hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering if (fstat(fileno(hwdb->f), &hwdb->st) < 0 ||
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering (size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("error reading /etc/udev/hwdb.bin: %m");
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering udev_hwdb_unref(hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering }
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering if (hwdb->map == MAP_FAILED) {
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering log_debug("error mapping /etc/udev/hwdb.bin: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_hwdb_unref(hwdb);
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering return NULL;
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering }
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering (size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering log_debug("error recognizing the format of /etc/udev/hwdb.bin");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_hwdb_unref(hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("=== trie on-disk ===\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("tool version: %llu", (unsigned long long)le64toh(hwdb->head->tool_version));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("file size: %8llu bytes\n", (unsigned long long)hwdb->st.st_size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("header size %8llu bytes\n", (unsigned long long)le64toh(hwdb->head->header_size));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("strings %8llu bytes\n", (unsigned long long)le64toh(hwdb->head->strings_len));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("nodes %8llu bytes\n", (unsigned long long)le64toh(hwdb->head->nodes_len));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return hwdb;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/**
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * udev_hwdb_ref:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * @hwdb: context
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Take a reference of a hwdb context.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Returns: the passed enumeration context
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering **/
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!hwdb)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering hwdb->refcount++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return hwdb;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering}
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/**
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * udev_hwdb_unref:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * @hwdb: context
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Drop a reference of a hwdb context. If the refcount reaches zero,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * all resources of the hwdb context will be released.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * Returns: the passed hwdb context if it has still an active reference, or #NULL otherwise.
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt **/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!hwdb)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek hwdb->refcount--;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (hwdb->refcount > 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return hwdb;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (hwdb->f)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fclose(hwdb->f);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (hwdb->map)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering munmap((void *)hwdb->map, hwdb->st.st_size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering udev_list_cleanup(&hwdb->properties_list);
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek free(hwdb);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringbool udev_hwdb_validate(struct udev_hwdb *hwdb) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct stat st;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!hwdb)
return false;
if (!hwdb->f)
return false;
if (fstat(fileno(hwdb->f), &st) < 0)
return true;
if (ts_usec(&hwdb->st.st_mtim) != ts_usec(&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->f) {
errno = EINVAL;
return NULL;
}
err = trie_search_f(hwdb, modalias);
if (err < 0) {
errno = -err;
return NULL;
}
return udev_list_get_entry(&hwdb->properties_list);
}