23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen/***
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen This file is part of systemd.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
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
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
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
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***/
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <fnmatch.h>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include <inttypes.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdio.h>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include <stdlib.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <string.h>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include <sys/mman.h>
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "sd-hwdb.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "hashmap.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#include "hwdb-internal.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "hwdb-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "refcnt.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstruct sd_hwdb {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen RefCount n_ref;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int refcount;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen FILE *f;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct stat st;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen union {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct trie_header_f *head;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char *map;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen };
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen char *modalias;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen OrderedHashmap *properties;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen Iterator properties_iterator;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen bool properties_modified;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen};
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstruct linebuf {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen char bytes[LINE_MAX];
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t size;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t len;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen};
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void linebuf_init(struct linebuf *buf) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen buf->size = 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen buf->len = 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const char *linebuf_get(struct linebuf *buf) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (buf->len + 1 >= sizeof(buf->bytes))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen buf->bytes[buf->len] = '\0';
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return buf->bytes;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (buf->len + len >= sizeof(buf->bytes))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen memcpy(buf->bytes + buf->len, s, len);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen buf->len += len;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poetteringstatic bool linebuf_add_char(struct linebuf *buf, char c) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (buf->len + 1 >= sizeof(buf->bytes))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen buf->bytes[buf->len++] = c;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void linebuf_rem(struct linebuf *buf, size_t count) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(buf->len >= count);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen buf->len -= count;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic void linebuf_rem_char(struct linebuf *buf) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_rem(buf, 1);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
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 Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const struct trie_value_entry_f *trie_node_values(sd_hwdb *hwdb, const struct trie_node_f *node) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char *base = (const char *)node;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen base += le64toh(hwdb->head->node_size);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen base += node->children_count * le64toh(hwdb->head->child_entry_size);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return (const struct trie_value_entry_f *)base;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
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 Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const char *trie_string(sd_hwdb *hwdb, le64_t off) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return hwdb->map + le64toh(off);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int trie_children_cmp_f(const void *v1, const void *v2) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const struct trie_child_entry_f *n1 = v1;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const struct trie_child_entry_f *n2 = v2;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return n1->c - n2->c;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct trie_child_entry_f *child;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct trie_child_entry_f search;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen search.c = 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 if (child)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return trie_node_from_off(hwdb, child->child_off);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int hwdb_add_property(sd_hwdb *hwdb, const char *key, const char *value) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(hwdb);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(key);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(value);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /*
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * Silently ignore all properties which do not start with a
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen * space; future extensions might use additional prefixes.
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (key[0] != ' ')
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen key++;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = ordered_hashmap_replace(hwdb->properties, key, (char*)value);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->properties_modified = true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t p,
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct linebuf *buf, const char *search) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t len;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t i;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char *prefix;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen prefix = trie_string(hwdb, node->prefix_off);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen len = strlen(prefix + p);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_add(buf, prefix + p, len);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (i = 0; i < node->children_count; i++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i];
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_add_char(buf, child->c);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (err < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_rem_char(buf);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
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 Gundersen if (err < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_rem(buf, len);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int trie_search_f(sd_hwdb *hwdb, const char *search) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct linebuf buf;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const struct trie_node_f *node;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t i = 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_init(&buf);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen while (node) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const struct trie_node_f *child;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t p = 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (node->prefix_off) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen uint8_t c;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (c == '*' || c == '?' || c == '[')
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (c != search[i + p])
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i += p;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen child = node_lookup_f(hwdb, node, '*');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (child) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_add_char(&buf, '*');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (err < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_rem_char(&buf);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen child = node_lookup_f(hwdb, node, '?');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (child) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_add_char(&buf, '?');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (err < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_rem_char(&buf);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen child = node_lookup_f(hwdb, node, '[');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (child) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_add_char(&buf, '[');
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (err < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen linebuf_rem_char(&buf);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (search[i] == '\0') {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen size_t n;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
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 Gundersen if (err < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return err;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen child = node_lookup_f(hwdb, node, search[i]);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen node = child;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen i++;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic const char hwdb_bin_paths[] =
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering "/etc/systemd/hwdb/hwdb.bin\0"
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering "/etc/udev/hwdb.bin\0"
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering "/usr/lib/systemd/hwdb/hwdb.bin\0"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#ifdef HAVE_SPLIT_USR
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering "/lib/systemd/hwdb/hwdb.bin\0"
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen#endif
52efd56a6369e19c2400a42981a197cd2eef924aLennart Poettering UDEVLIBEXECDIR "/hwdb.bin\0";
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_new(sd_hwdb **ret) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char *hwdb_bin_path;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char sig[] = HWDB_SIG;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(ret, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb = new0(sd_hwdb, 1);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!hwdb)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -ENOMEM;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->n_ref = REFCNT_INIT;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* find hwdb.bin in hwdb_bin_paths */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->f = fopen(hwdb_bin_path, "re");
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (hwdb->f)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen else if (errno == ENOENT)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen continue;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen else
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!hwdb->f) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("hwdb.bin does not exist, please run udevadm hwdb --update");
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -ENOENT;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (fstat(fileno(hwdb->f), &hwdb->st) < 0 ||
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
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (hwdb->map == MAP_FAILED)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return log_debug_errno(errno, "error mapping %s: %m", hwdb_bin_path);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
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);
7e518afab9fb55b8052f68888210927259275560Thomas Hindoe Paaboel Andersen return -EINVAL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen log_debug("=== trie on-disk ===");
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
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen *ret = hwdb;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb = NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ sd_hwdb *sd_hwdb_ref(sd_hwdb *hwdb) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(hwdb, NULL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_se(REFCNT_INC(hwdb->n_ref) >= 2);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return hwdb;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb) {
f0c4b1c3fd827b429ba36aa45fd39e0a023cbf2cTom Gundersen if (hwdb && REFCNT_DEC(hwdb->n_ref) == 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (hwdb->map)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen munmap((void *)hwdb->map, hwdb->st.st_size);
74ca738f6a01fb5fc19c5c3899f5cb1fdc1d7f68Lennart Poettering safe_fclose(hwdb->f);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen free(hwdb->modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen ordered_hashmap_free(hwdb->properties);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen free(hwdb);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenbool hwdb_validate(sd_hwdb *hwdb) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen bool found = false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char* p;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen struct stat st;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!hwdb)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!hwdb->f)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen /* if hwdb.bin doesn't exist anywhere, we need to update */
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen NULSTR_FOREACH(p, hwdb_bin_paths) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (stat(p, &st) >= 0) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen found = true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen break;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen }
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!found)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersenstatic int properties_prepare(sd_hwdb *hwdb, const char *modalias) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen _cleanup_free_ char *mod = NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(hwdb);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert(modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (streq_ptr(modalias, hwdb->modalias))
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen mod = strdup(modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!mod)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -ENOMEM;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen ordered_hashmap_clear(hwdb->properties);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->properties_modified = true;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = trie_search_f(hwdb, modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen free(hwdb->modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->modalias = mod;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen mod = NULL;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen const char *value;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(hwdb, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(hwdb->f, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(modalias, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(_value, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = properties_prepare(hwdb, modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen value = ordered_hashmap_get(hwdb->properties, key);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!value)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -ENOENT;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen *_value = value;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) {
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen int r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(hwdb, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(hwdb->f, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(modalias, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen r = properties_prepare(hwdb, modalias);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (r < 0)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return r;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->properties_modified = false;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen hwdb->properties_iterator = ITERATOR_FIRST;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen_public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann const void *k;
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann void *v;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(hwdb, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(key, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen assert_return(value, -EINVAL);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (hwdb->properties_modified)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return -EAGAIN;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
8927b1dad2d4a7330174cb924090b4635a2547fbDavid Herrmann ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, &v, &k);
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen if (!k)
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 0;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen *key = k;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen *value = v;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen return 1;
23fbe14f503c1e98292efc4ba1238adb7dc38d80Tom Gundersen}