sd-hwdb.c revision f0c4b1c3fd827b429ba36aa45fd39e0a023cbf2c
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering/***
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering This file is part of systemd.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Copyright 2012 Kay Sievers <kay@vrfy.org>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Copyright 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering systemd is free software; you can redistribute it and/or modify it
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering under the terms of the GNU Lesser General Public License as published by
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering (at your option) any later version.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering systemd is distributed in the hope that it will be useful, but
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Lesser General Public License for more details.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering You should have received a copy of the GNU Lesser General Public License
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering***/
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <stdio.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <errno.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <string.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <inttypes.h>
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell#include <ctype.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <stdlib.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <fnmatch.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <getopt.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <sys/mman.h>
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "sd-hwdb.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "hashmap.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "refcnt.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "hwdb-util.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "hwdb-internal.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstruct sd_hwdb {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering RefCount n_ref;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int refcount;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering FILE *f;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct stat st;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering union {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct trie_header_f *head;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char *map;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering };
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering char *modalias;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering OrderedHashmap *properties;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Iterator properties_iterator;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering bool properties_modified;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering};
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstruct linebuf {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering char bytes[LINE_MAX];
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t size;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering};
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void linebuf_init(struct linebuf *buf) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering buf->size = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering buf->len = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const char *linebuf_get(struct linebuf *buf) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (buf->len + 1 >= sizeof(buf->bytes))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering buf->bytes[buf->len] = '\0';
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return buf->bytes;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic bool linebuf_add(struct linebuf *buf, const char *s, size_t len) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (buf->len + len >= sizeof(buf->bytes))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return false;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering memcpy(buf->bytes + buf->len, s, len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering buf->len += len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic bool linebuf_add_char(struct linebuf *buf, char c)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering{
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (buf->len + 1 >= sizeof(buf->bytes))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return false;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering buf->bytes[buf->len++] = c;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void linebuf_rem(struct linebuf *buf, size_t count) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(buf->len >= count);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering buf->len -= count;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void linebuf_rem_char(struct linebuf *buf) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_rem(buf, 1);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const struct trie_child_entry_f *trie_node_children(sd_hwdb *hwdb, const struct trie_node_f *node) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return (const struct trie_child_entry_f *)((const char *)node + le64toh(hwdb->head->node_size));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const struct trie_value_entry_f *trie_node_values(sd_hwdb *hwdb, const struct trie_node_f *node) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char *base = (const char *)node;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering base += le64toh(hwdb->head->node_size);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering base += node->children_count * le64toh(hwdb->head->child_entry_size);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return (const struct trie_value_entry_f *)base;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const struct trie_node_f *trie_node_from_off(sd_hwdb *hwdb, le64_t off) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return (const struct trie_node_f *)(hwdb->map + le64toh(off));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const char *trie_string(sd_hwdb *hwdb, le64_t off) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return hwdb->map + le64toh(off);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int trie_children_cmp_f(const void *v1, const void *v2) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const struct trie_child_entry_f *n1 = v1;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const struct trie_child_entry_f *n2 = v2;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return n1->c - n2->c;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct trie_child_entry_f *child;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct trie_child_entry_f search;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering search.c = c;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering child = bsearch(&search, trie_node_children(hwdb, node), node->children_count,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering le64toh(hwdb->head->child_entry_size), trie_children_cmp_f);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (child)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return trie_node_from_off(hwdb, child->child_off);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int hwdb_add_property(sd_hwdb *hwdb, const char *key, const char *value) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(hwdb);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(key);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(value);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /*
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering * Silently ignore all properties which do not start with a
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering * space; future extensions might use additional prefixes.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (key[0] != ' ')
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering key++;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = ordered_hashmap_replace(hwdb->properties, key, (char*)value);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb->properties_modified = true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t p,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct linebuf *buf, const char *search) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t i;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char *prefix;
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poettering int err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering prefix = trie_string(hwdb, node->prefix_off);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering len = strlen(prefix + p);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_add(buf, prefix + p, len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering for (i = 0; i < node->children_count; i++) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i];
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_add_char(buf, child->c);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (err < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_rem_char(buf);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering for (i = 0; i < le64toh(node->values_count); i++) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[i].key_off),
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering trie_string(hwdb, trie_node_values(hwdb, node)[i].value_off));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (err < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_rem(buf, len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int trie_search_f(sd_hwdb *hwdb, const char *search) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct linebuf buf;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const struct trie_node_f *node;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t i = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_init(&buf);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering while (node) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const struct trie_node_f *child;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t p = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (node->prefix_off) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint8_t c;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (c == '*' || c == '?' || c == '[')
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (c != search[i + p])
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering i += p;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering child = node_lookup_f(hwdb, node, '*');
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (child) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_add_char(&buf, '*');
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (err < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_rem_char(&buf);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering child = node_lookup_f(hwdb, node, '?');
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (child) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_add_char(&buf, '?');
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (err < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_rem_char(&buf);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering child = node_lookup_f(hwdb, node, '[');
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (child) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_add_char(&buf, '[');
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (err < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering linebuf_rem_char(&buf);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (search[i] == '\0') {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t n;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering for (n = 0; n < le64toh(node->values_count); n++) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[n].key_off),
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering trie_string(hwdb, trie_node_values(hwdb, node)[n].value_off));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (err < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return err;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poettering child = node_lookup_f(hwdb, node, search[i]);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering node = child;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering i++;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const char hwdb_bin_paths[] =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering "/etc/systemd/hwdb/hwdb.bin\0"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering "/etc/udev/hwdb.bin\0"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering "/usr/lib/systemd/hwdb/hwdb.bin\0"
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek#ifdef HAVE_SPLIT_USR
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering "/lib/systemd/hwdb/hwdb.bin\0"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#endif
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering UDEVLIBEXECDIR "/hwdb.bin\0";
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering_public_ int sd_hwdb_new(sd_hwdb **ret) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char *hwdb_bin_path;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char sig[] = HWDB_SIG;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(ret, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb = new0(sd_hwdb, 1);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!hwdb)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOMEM;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb->n_ref = REFCNT_INIT;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* find hwdb.bin in hwdb_bin_paths */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb->f = fopen(hwdb_bin_path, "re");
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (hwdb->f)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering else if (errno == ENOENT)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering continue;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering else
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!hwdb->f) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("hwdb.bin does not exist, please run udevadm hwdb --update");
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOENT;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (fstat(fileno(hwdb->f), &hwdb->st) < 0 ||
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering (size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (hwdb->map == MAP_FAILED)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return log_debug_errno(errno, "error mapping %s: %m", hwdb_bin_path);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering (size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("error recognizing the format of %s", hwdb_bin_path);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EINVAL;;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("=== trie on-disk ===");
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("tool version: %"PRIu64, le64toh(hwdb->head->tool_version));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("file size: %8"PRIu64" bytes", hwdb->st.st_size);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("header size %8"PRIu64" bytes", le64toh(hwdb->head->header_size));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("strings %8"PRIu64" bytes", le64toh(hwdb->head->strings_len));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_debug("nodes %8"PRIu64" bytes", le64toh(hwdb->head->nodes_len));
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering *ret = hwdb;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb = NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering_public_ sd_hwdb *sd_hwdb_ref(sd_hwdb *hwdb) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(hwdb, NULL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_se(REFCNT_INC(hwdb->n_ref) >= 2);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return hwdb;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering_public_ sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (hwdb && REFCNT_DEC(hwdb->n_ref) == 0) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (hwdb->map)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering munmap((void *)hwdb->map, hwdb->st.st_size);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (hwdb->f)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering fclose(hwdb->f);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering free(hwdb->modalias);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering ordered_hashmap_free(hwdb->properties);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering free(hwdb);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringbool hwdb_validate(sd_hwdb *hwdb) {
2b43f939a4b3ad5aeb2650868b0234ff42ec0045Lennart Poettering bool found = false;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char* p;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct stat st;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!hwdb)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return false;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!hwdb->f)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return false;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* if hwdb.bin doesn't exist anywhere, we need to update */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering NULSTR_FOREACH(p, hwdb_bin_paths) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (stat(p, &st) >= 0) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering found = true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!found)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return false;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int properties_prepare(sd_hwdb *hwdb, const char *modalias) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering _cleanup_free_ char *mod = NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(hwdb);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(modalias);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (streq_ptr(modalias, hwdb->modalias))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering mod = strdup(modalias);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!mod)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOMEM;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering ordered_hashmap_clear(hwdb->properties);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb->properties_modified = true;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = trie_search_f(hwdb, modalias);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering free(hwdb->modalias);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering hwdb->modalias = mod;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering mod = NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
b2e6df73aa508cc09b1b536a2fb9f90f152b89faZbigniew Jędrzejewski-Szmek
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering_public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const char *value;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(hwdb, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(hwdb->f, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(modalias, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(_value, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = properties_prepare(hwdb, modalias);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering value = ordered_hashmap_get(hwdb->properties, key);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!value)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOENT;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering *_value = value;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering_public_ int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
assert_return(hwdb, -EINVAL);
assert_return(hwdb->f, -EINVAL);
assert_return(modalias, -EINVAL);
r = properties_prepare(hwdb, modalias);
if (r < 0)
return r;
hwdb->properties_modified = false;
hwdb->properties_iterator = ITERATOR_FIRST;
return 0;
}
_public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) {
const void *k, *v;
assert_return(hwdb, -EINVAL);
assert_return(key, -EINVAL);
assert_return(value, -EINVAL);
if (hwdb->properties_modified)
return -EAGAIN;
v = ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, &k);
if (!k)
return 0;
*key = k;
*value = v;
return 1;
}