summaryrefslogtreecommitdiff
path: root/src/hwdb/hwdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hwdb/hwdb.c')
-rw-r--r--src/hwdb/hwdb.c91
1 files changed, 62 insertions, 29 deletions
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 446de3a2fc..be4ef5f9e9 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -17,21 +17,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <ctype.h>
#include <getopt.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "util.h"
-#include "strbuf.h"
+#include "alloc-util.h"
#include "conf-files.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "verbs.h"
-#include "build.h"
-
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "hwdb-internal.h"
#include "hwdb-util.h"
+#include "label.h"
+#include "mkdir.h"
+#include "selinux-util.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "verbs.h"
/*
* Generic udev properties, key/value database based on modalias strings.
@@ -80,6 +85,8 @@ struct trie_child_entry {
struct trie_value_entry {
size_t key_off;
size_t value_off;
+ size_t filename_off;
+ size_t line_number;
};
static int trie_children_cmp(const void *v1, const void *v2) {
@@ -152,9 +159,11 @@ static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
}
static int trie_node_add_value(struct trie *trie, struct trie_node *node,
- const char *key, const char *value) {
- ssize_t k, v;
+ const char *key, const char *value,
+ const char *filename, size_t line_number) {
+ ssize_t k, v, fn;
struct trie_value_entry *val;
+ int r;
k = strbuf_add_string(trie->strings, key, strlen(key));
if (k < 0)
@@ -162,6 +171,9 @@ static int trie_node_add_value(struct trie *trie, struct trie_node *node,
v = strbuf_add_string(trie->strings, value, strlen(value));
if (v < 0)
return v;
+ fn = strbuf_add_string(trie->strings, filename, strlen(filename));
+ if (v < 0)
+ return v;
if (node->values_count) {
struct trie_value_entry search = {
@@ -171,8 +183,20 @@ static int trie_node_add_value(struct trie *trie, struct trie_node *node,
val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
if (val) {
+ /*
+ * At this point we have 2 identical properties on the same match-string. We
+ * strictly order them by filename+line-number, since we know the dynamic
+ * runtime lookup does the same for multiple matching nodes.
+ */
+ r = strcmp(filename, trie->strings->buf + val->filename_off);
+ if (r < 0 ||
+ (r == 0 && line_number < val->line_number))
+ return 0;
+
/* replace existing earlier key with new value */
val->value_off = v;
+ val->filename_off = fn;
+ val->line_number = line_number;
return 0;
}
}
@@ -185,13 +209,16 @@ static int trie_node_add_value(struct trie *trie, struct trie_node *node,
node->values = val;
node->values[node->values_count].key_off = k;
node->values[node->values_count].value_off = v;
+ node->values[node->values_count].filename_off = fn;
+ node->values[node->values_count].line_number = line_number;
node->values_count++;
qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
return 0;
}
static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
- const char *key, const char *value) {
+ const char *key, const char *value,
+ const char *filename, uint64_t line_number) {
size_t i = 0;
int err = 0;
@@ -245,7 +272,7 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
c = search[i];
if (c == '\0')
- return trie_node_add_value(trie, node, key, value);
+ return trie_node_add_value(trie, node, key, value, filename, line_number);
child = node_lookup(node, c);
if (!child) {
@@ -269,7 +296,7 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
return err;
}
- return trie_node_add_value(trie, child, key, value);
+ return trie_node_add_value(trie, child, key, value, filename, line_number);
}
node = child;
@@ -298,7 +325,7 @@ static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
for (i = 0; i < node->children_count; i++)
trie->strings_off += sizeof(struct trie_child_entry_f);
for (i = 0; i < node->values_count; i++)
- trie->strings_off += sizeof(struct trie_value_entry_f);
+ trie->strings_off += sizeof(struct trie_value_entry2_f);
}
static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
@@ -344,12 +371,14 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
/* append values array */
for (i = 0; i < node->values_count; i++) {
- struct trie_value_entry_f v = {
+ struct trie_value_entry2_f v = {
.key_off = htole64(trie->strings_off + node->values[i].key_off),
.value_off = htole64(trie->strings_off + node->values[i].value_off),
+ .filename_off = htole64(trie->strings_off + node->values[i].filename_off),
+ .line_number = htole64(node->values[i].line_number),
};
- fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f);
+ fwrite(&v, sizeof(struct trie_value_entry2_f), 1, trie->f);
trie->values_count++;
}
@@ -370,7 +399,7 @@ static int trie_store(struct trie *trie, const char *filename) {
.header_size = htole64(sizeof(struct trie_header_f)),
.node_size = htole64(sizeof(struct trie_node_f)),
.child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
- .value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
+ .value_entry_size = htole64(sizeof(struct trie_value_entry2_f)),
};
int err;
@@ -426,14 +455,15 @@ static int trie_store(struct trie *trie, const char *filename) {
log_debug("child pointers: %8"PRIu64" bytes (%8"PRIu64")",
t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
log_debug("value pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.values_count * sizeof(struct trie_value_entry_f), t.values_count);
+ t.values_count * sizeof(struct trie_value_entry2_f), t.values_count);
log_debug("string store: %8zu bytes", trie->strings->len);
log_debug("strings start: %8"PRIu64, t.strings_off);
return 0;
}
-static int insert_data(struct trie *trie, char **match_list, char *line, const char *filename) {
+static int insert_data(struct trie *trie, char **match_list, char *line,
+ const char *filename, size_t line_number) {
char *value, **entry;
value = strchr(line, '=');
@@ -455,7 +485,7 @@ static int insert_data(struct trie *trie, char **match_list, char *line, const c
}
STRV_FOREACH(entry, match_list)
- trie_insert(trie, trie->root, *entry, line, value);
+ trie_insert(trie, trie->root, *entry, line, value, filename, line_number);
return 0;
}
@@ -469,6 +499,7 @@ static int import_file(struct trie *trie, const char *filename) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
_cleanup_strv_free_ char **match_list = NULL;
+ size_t line_number = 0;
char *match = NULL;
int r;
@@ -480,6 +511,8 @@ static int import_file(struct trie *trie, const char *filename) {
size_t len;
char *pos;
+ ++line_number;
+
/* comment line */
if (line[0] == '#')
continue;
@@ -541,7 +574,7 @@ static int import_file(struct trie *trie, const char *filename) {
/* first data */
state = HW_DATA;
- insert_data(trie, match_list, line, filename);
+ insert_data(trie, match_list, line, filename, line_number);
break;
case HW_DATA:
@@ -559,7 +592,7 @@ static int import_file(struct trie *trie, const char *filename) {
break;
}
- insert_data(trie, match_list, line, filename);
+ insert_data(trie, match_list, line, filename, line_number);
break;
};
}
@@ -568,7 +601,7 @@ static int import_file(struct trie *trie, const char *filename) {
}
static int hwdb_query(int argc, char *argv[], void *userdata) {
- _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
+ _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
const char *key, *value;
const char *modalias;
int r;
@@ -640,12 +673,12 @@ static int hwdb_update(int argc, char *argv[], void *userdata) {
if (!hwdb_bin)
return -ENOMEM;
- mkdir_parents(hwdb_bin, 0755);
+ mkdir_parents_label(hwdb_bin, 0755);
r = trie_store(trie, hwdb_bin);
if (r < 0)
return log_error_errno(r, "Failure writing database %s: %m", hwdb_bin);
- return 0;
+ return label_fix(hwdb_bin, false, false);
}
static void help(void) {
@@ -688,9 +721,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USR:
arg_hwdb_bin_dir = UDEVLIBEXECDIR;
@@ -731,6 +762,8 @@ int main (int argc, char *argv[]) {
if (r <= 0)
goto finish;
+ mac_selinux_init();
+
r = hwdb_main(argc, argv);
finish: