libudev-hwdb.c revision 8232e39e7cf32071e11b3b04839e6c98fbc81d0f
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering This file is part of systemd.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering Copyright 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
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 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 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 * SECTION:libudev-hwdb
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * @short_description: retrieve properties from the hardware database
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Libudev hardware database interface.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Opaque object representing the hardware database.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic void linebuf_init(struct linebuf *buf) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const char *linebuf_get(struct linebuf *buf) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (buf->len + len >= sizeof(buf->bytes))
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic bool linebuf_add_char(struct linebuf *buf, char c)
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic void linebuf_rem(struct linebuf *buf, size_t count) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic void linebuf_rem_char(struct linebuf *buf) {
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 Poetteringstatic const struct trie_value_entry_f *trie_node_values(struct udev_hwdb *hwdb, const struct trie_node_f *node) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering base += node->children_count * le64toh(hwdb->head->child_entry_size);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return (const struct trie_value_entry_f *)base;
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 Poetteringstatic const char *trie_string(struct udev_hwdb *hwdb, le64_t off) {
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 Poetteringstatic const struct trie_node_f *node_lookup_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, uint8_t 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 return trie_node_from_off(hwdb, child->child_off);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic int hwdb_add_property(struct udev_hwdb *hwdb, const char *key, const char *value) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Silently ignore all properties which do not start with a
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * space; future extensions might use additional prefixes.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (udev_list_entry_add(&hwdb->properties_list, key+1, value) == NULL)
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 prefix = trie_string(hwdb, node->prefix_off);
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 err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
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 Poetteringstatic int trie_search_f(struct udev_hwdb *hwdb, const char *search) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering if (c != search[i + p])
dea7b6b043f0cd9e34ee719b9b612c3a4776387eLennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
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 child = node_lookup_f(hwdb, node, search[i]);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poetteringstatic const char hwdb_bin_paths[] =
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * udev_hwdb_new:
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * @udev: udev library context
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Create a hardware database context to query properties for devices.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering * Returns: a hwdb context.
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering udev_list_init(udev, &hwdb->properties_list, true);
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering /* find hwdb.bin in hwdb_bin_paths */
84ac7bea360cd369df26910e9685a7eed2327088Lennart Poettering NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
if (hwdb->f)
return NULL;
if (!hwdb->f) {
return NULL;
return NULL;
return NULL;
return NULL;
return hwdb;
if (!hwdb)
return NULL;
return hwdb;
if (!hwdb)
return NULL;
return NULL;
if (hwdb->f)
return NULL;
bool found = false;
if (!hwdb)
if (!hwdb->f)
found = true;
if (!found)
_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags) {
int err;
return NULL;
if (err < 0) {
return NULL;