hwdb.c revision 3f6fd1ba65f962702753c4ad284b588e59689a23
/***
This file is part of systemd.
Copyright 2012 Kay Sievers <kay@vrfy.org>
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <ctype.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include "conf-files.h"
#include "hwdb-internal.h"
#include "hwdb-util.h"
#include "mkdir.h"
#include "strbuf.h"
#include "strv.h"
#include "util.h"
#include "verbs.h"
/*
*/
static const char *arg_hwdb_bin_dir = "/etc/udev";
static const char *arg_root = "";
static const char * const conf_file_dirs[] = {
UDEVLIBEXECDIR "/hwdb.d",
};
/* in-memory trie objects */
struct trie {
};
struct trie_node {
/* prefix, common part for all children of this node */
/* sorted array of pointers to children nodes */
struct trie_child_entry *children;
struct trie_value_entry *values;
};
/* children array item with char (0-255) index */
struct trie_child_entry {
uint8_t c;
};
struct trie_value_entry {
};
}
static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
struct trie_child_entry *child;
/* extend array, add new entry, sort for bisection */
if (!child)
return -ENOMEM;
trie->children_count++;
node->children_count++;
trie->nodes_count++;
return 0;
}
struct trie_child_entry *child;
struct trie_child_entry search;
search.c = c;
child = bsearch(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
if (child)
return NULL;
}
size_t i;
for (i = 0; i < node->children_count; i++)
}
if (!trie)
return;
}
}
ssize_t k, v;
struct trie_value_entry *val;
if (k < 0)
return k;
if (v < 0)
return v;
if (node->values_count) {
struct trie_value_entry search = {
.key_off = k,
.value_off = v,
};
val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
if (val) {
/* replace existing earlier key with new value */
return 0;
}
}
/* extend array, add new entry, sort for bisection */
if (!val)
return -ENOMEM;
trie->values_count++;
node->values_count++;
return 0;
}
size_t i = 0;
int err = 0;
for (;;) {
size_t p;
uint8_t c;
_cleanup_free_ char *s = NULL;
if (c == search[i + p])
continue;
/* split node */
if (!new_child)
return -ENOMEM;
/* move values from parent to child */
/* update parent; use strdup() because the source gets realloc()d */
if (!s)
return -ENOMEM;
if (off < 0)
return off;
node->children_count = 0;
node->values_count = 0;
if (err < 0)
return err;
break;
}
i += p;
c = search[i];
if (c == '\0')
if (!child) {
/* new child */
if (!child)
return -ENOMEM;
if (off < 0) {
return off;
}
if (err < 0) {
return err;
}
}
i++;
}
}
struct trie_f {
FILE *f;
};
/* calculate the storage space for the nodes, children arrays, value arrays */
uint64_t i;
for (i = 0; i < node->children_count; i++)
for (i = 0; i < node->children_count; i++)
for (i = 0; i < node->values_count; i++)
}
uint64_t i;
struct trie_node_f n = {
};
if (node->children_count) {
if (!children)
return -ENOMEM;
}
/* post-order recursion */
for (i = 0; i < node->children_count; i++) {
if (child_off < 0) {
return child_off;
}
}
/* write node */
trie->nodes_count++;
/* append children array */
if (node->children_count) {
}
/* append values array */
for (i = 0; i < node->values_count; i++) {
struct trie_value_entry_f v = {
};
trie->values_count++;
}
return node_off;
}
struct trie_f t = {
};
struct trie_header_f h = {
};
int err;
/* calculate size of header, nodes, children entries, value entries */
t.strings_off = sizeof(struct trie_header_f);
if (err < 0)
return err;
/* write nodes */
if (err < 0) {
fclose(t.f);
return -errno;
}
/* write string buffer */
/* write header */
if (err < 0) {
fclose(t.f);
return -errno;
}
if (err)
fclose(t.f);
}
log_debug("=== trie on-disk ===");
return 0;
}
if (!value) {
return -EINVAL;
}
value[0] = '\0';
value++;
/* libudev requires properties to start with a space */
line++;
return -EINVAL;
}
return 0;
}
enum {
int r;
if (!f)
return -errno;
char *pos;
/* comment line */
if (line[0] == '#')
continue;
/* strip trailing comment */
if (pos)
pos[0] = '\0';
/* strip trailing whitespace */
len--;
switch (state) {
case HW_NONE:
if (len == 0)
break;
if (line[0] == ' ') {
break;
}
/* start of record, first match */
if (!match)
return -ENOMEM;
if (r < 0)
return r;
break;
case HW_MATCH:
if (len == 0) {
break;
}
/* another match */
if (line[0] != ' ') {
if (!match)
return -ENOMEM;
if (r < 0)
return r;
break;
}
/* first data */
break;
case HW_DATA:
/* end of record */
if (len == 0) {
break;
}
if (line[0] != ' ') {
break;
}
break;
};
}
return 0;
}
const char *modalias;
int r;
r = sd_hwdb_new(&hwdb);
if (r < 0)
return r;
return 0;
}
char **files, **f;
int r;
if (!trie)
return -ENOMEM;
/* string store */
return -ENOMEM;
/* index */
return -ENOMEM;
trie->nodes_count++;
if (r < 0)
return log_error_errno(r, "failed to enumerate hwdb files: %m");
STRV_FOREACH(f, files) {
log_debug("reading file '%s'", *f);
import_file(trie, *f);
}
log_debug("=== trie in-memory ===");
log_debug("nodes: %8zu bytes (%8zu)",
log_debug("children arrays: %8zu bytes (%8zu)",
log_debug("values arrays: %8zu bytes (%8zu)",
log_debug("strings: %8zu bytes",
log_debug("strings incoming: %8zu bytes (%8zu)",
log_debug("strings dedup'ed: %8zu bytes (%8zu)",
if (!hwdb_bin)
return -ENOMEM;
if (r < 0)
return 0;
}
static void help(void) {
printf("Usage: %s OPTIONS COMMAND\n\n"
"Update or query the hardware database.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -r --root=PATH Alternative root path in the filesystem\n\n"
"Commands:\n"
" update Update the hwdb database\n"
" query MODALIAS Query database and print result\n",
}
enum {
ARG_VERSION = 0x100,
};
{}
};
int c;
switch(c) {
case 'h':
help();
return 0;
case ARG_VERSION:
return version();
case ARG_USR:
break;
case 'r':
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unknown option");
}
}
return 1;
}
{},
};
}
int r;
log_open();
if (r <= 0)
goto finish;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}