]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/hwdb-util.c
Merge pull request #32993 from poettering/cryptenroll-no-pcr
[thirdparty/systemd.git] / src / shared / hwdb-util.c
index 1ec861f76fe11b2d485f0d4264b47e739ad9e40b..d96902c7f26fe737eb1f38f6340c55dcad9c5384 100644 (file)
@@ -6,12 +6,13 @@
 
 #include "alloc-util.h"
 #include "conf-files.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
 #include "hwdb-internal.h"
 #include "hwdb-util.h"
-#include "label.h"
+#include "label-util.h"
 #include "mkdir-label.h"
 #include "nulstr-util.h"
 #include "path-util.h"
@@ -21,8 +22,7 @@
 #include "strv.h"
 #include "tmpfile-util.h"
 
-static const char *default_hwdb_bin_dir = "/etc/udev";
-static const char * const conf_file_dirs[] = {
+static const char* const conf_file_dirs[] = {
         "/etc/udev/hwdb.d",
         UDEVLIBEXECDIR "/hwdb.d",
         NULL
@@ -194,7 +194,7 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
 
         for (size_t i = 0;; i++) {
                 size_t p;
-                uint8_t c;
+                char c;
                 struct trie_node *child;
 
                 for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
@@ -275,7 +275,6 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
 }
 
 struct trie_f {
-        FILE *f;
         struct trie *trie;
         uint64_t strings_off;
 
@@ -296,15 +295,14 @@ static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node, b
                 trie->strings_off += compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f);
 }
 
-static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, bool compat) {
-        struct trie_node_f n = {
-                .prefix_off = htole64(trie->strings_off + node->prefix_off),
-                .children_count = node->children_count,
-                .values_count = htole64(node->values_count),
-        };
+static int64_t trie_store_nodes(struct trie_f *trie, FILE *f, struct trie_node *node, bool compat) {
         _cleanup_free_ struct trie_child_entry_f *children = NULL;
         int64_t node_off;
 
+        assert(trie);
+        assert(f);
+        assert(node);
+
         if (node->children_count) {
                 children = new(struct trie_child_entry_f, node->children_count);
                 if (!children)
@@ -315,7 +313,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
         for (uint64_t i = 0; i < node->children_count; i++) {
                 int64_t child_off;
 
-                child_off = trie_store_nodes(trie, node->children[i].child, compat);
+                child_off = trie_store_nodes(trie, f, node->children[i].child, compat);
                 if (child_off < 0)
                         return child_off;
 
@@ -325,14 +323,20 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
                 };
         }
 
+        struct trie_node_f n = {
+                .prefix_off = htole64(trie->strings_off + node->prefix_off),
+                .children_count = node->children_count,
+                .values_count = htole64(node->values_count),
+        };
+
         /* write node */
-        node_off = ftello(trie->f);
-        fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
+        node_off = ftello(f);
+        fwrite(&n, sizeof(struct trie_node_f), 1, f);
         trie->nodes_count++;
 
         /* append children array */
         if (node->children_count) {
-                fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
+                fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, f);
                 trie->children_count += node->children_count;
         }
 
@@ -346,7 +350,7 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
                         .file_priority = htole16(node->values[i].file_priority),
                 };
 
-                fwrite(&v, compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f), 1, trie->f);
+                fwrite(&v, compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f), 1, f);
         }
         trie->values_count += node->values_count;
 
@@ -356,11 +360,26 @@ static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, boo
 static int trie_store(struct trie *trie, const char *filename, bool compat) {
         struct trie_f t = {
                 .trie = trie,
+                .strings_off = sizeof(struct trie_header_f),
         };
-        _cleanup_free_ char *filename_tmp = NULL;
-        int64_t pos;
-        int64_t root_off;
-        int64_t size;
+        _cleanup_(unlink_and_freep) char *filename_tmp = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        int64_t pos, root_off, size;
+        int r;
+
+        assert(trie);
+        assert(filename);
+
+        /* calculate size of header, nodes, children entries, value entries */
+        trie_store_nodes_size(&t, trie->root, compat);
+
+        r = fopen_tmpfile_linkable(filename, O_WRONLY|O_CLOEXEC, &filename_tmp, &f);
+        if (r < 0)
+                return r;
+
+        if (fchmod(fileno(f), 0444) < 0)
+                return -errno;
+
         struct trie_header_f h = {
                 .signature = HWDB_SIG,
                 .tool_version = htole64(PROJECT_VERSION),
@@ -369,48 +388,32 @@ static int trie_store(struct trie *trie, const char *filename, bool compat) {
                 .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
                 .value_entry_size = htole64(compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f)),
         };
-        int r;
-
-        /* calculate size of header, nodes, children entries, value entries */
-        t.strings_off = sizeof(struct trie_header_f);
-        trie_store_nodes_size(&t, trie->root, compat);
-
-        r = fopen_temporary(filename, &t.f, &filename_tmp);
-        if (r < 0)
-                return r;
-        (void) fchmod(fileno(t.f), 0444);
 
         /* write nodes */
-        if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
-                goto error_fclose;
+        if (fseeko(f, sizeof(struct trie_header_f), SEEK_SET) < 0)
+                return -errno;
 
-        root_off = trie_store_nodes(&t, trie->root, compat);
+        root_off = trie_store_nodes(&t, f, trie->root, compat);
         h.nodes_root_off = htole64(root_off);
-        pos = ftello(t.f);
+        pos = ftello(f);
         h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
 
         /* write string buffer */
-        fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
+        fwrite(trie->strings->buf, trie->strings->len, 1, f);
         h.strings_len = htole64(trie->strings->len);
 
         /* write header */
-        size = ftello(t.f);
+        size = ftello(f);
         h.file_size = htole64(size);
-        if (fseeko(t.f, 0, SEEK_SET) < 0)
-                goto error_fclose;
-        fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
-
-        if (ferror(t.f))
-                goto error_fclose;
-        if (fflush(t.f) < 0)
-                goto error_fclose;
-        if (fsync(fileno(t.f)) < 0)
-                goto error_fclose;
-        if (rename(filename_tmp, filename) < 0)
-                goto error_fclose;
+        if (fseeko(f, 0, SEEK_SET) < 0)
+                return -errno;
+        fwrite(&h, sizeof(struct trie_header_f), 1, f);
+
+        r = flink_tmpfile(f, filename_tmp, filename, LINK_TMPFILE_REPLACE|LINK_TMPFILE_SYNC);
+        if (r < 0)
+                return r;
 
         /* write succeeded */
-        fclose(t.f);
 
         log_debug("=== trie on-disk ===");
         log_debug("size:             %8"PRIi64" bytes", size);
@@ -424,12 +427,6 @@ static int trie_store(struct trie *trie, const char *filename, bool compat) {
         log_debug("string store:     %8zu bytes", trie->strings->len);
         log_debug("strings start:    %8"PRIu64, t.strings_off);
         return 0;
-
- error_fclose:
-        r = -errno;
-        fclose(t.f);
-        (void) unlink(filename_tmp);
-        return r;
 }
 
 static int insert_data(struct trie *trie, char **match_list, char *line, const char *filename,
@@ -487,7 +484,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
                 if (r == 0)
                         break;
 
-                line_number ++;
+                line_number++;
 
                 /* comment line */
                 if (line[0] == '#')
@@ -591,6 +588,10 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
          * source. If true, then hwdb.bin will be created without the information. systemd-hwdb command
          * should set the argument false, and 'udevadm hwdb' command should set it true. */
 
+        hwdb_bin = path_join(root, hwdb_bin_dir ?: "/etc/udev", "hwdb.bin");
+        if (!hwdb_bin)
+                return -ENOMEM;
+
         trie = new0(struct trie, 1);
         if (!trie)
                 return -ENOMEM;
@@ -611,6 +612,18 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
         if (err < 0)
                 return log_error_errno(err, "Failed to enumerate hwdb files: %m");
 
+        if (strv_isempty(files)) {
+                if (unlink(hwdb_bin) < 0) {
+                        if (errno != ENOENT)
+                                return log_error_errno(errno, "Failed to remove compiled hwdb database %s: %m", hwdb_bin);
+
+                        log_info("No hwdb files found, skipping.");
+                } else
+                        log_info("No hwdb files found, compiled hwdb database %s removed.", hwdb_bin);
+
+                return 0;
+        }
+
         STRV_FOREACH(f, files) {
                 log_debug("Reading file \"%s\"", *f);
                 err = import_file(trie, *f, file_priority++, compat);
@@ -634,10 +647,6 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
         log_debug("strings dedup'ed: %8zu bytes (%8zu)",
                   trie->strings->dedup_len, trie->strings->dedup_count);
 
-        hwdb_bin = path_join(root, hwdb_bin_dir ?: default_hwdb_bin_dir, "hwdb.bin");
-        if (!hwdb_bin)
-                return -ENOMEM;
-
         (void) mkdir_parents_label(hwdb_bin, 0755);
         err = trie_store(trie, hwdb_bin, compat);
         if (err < 0)
@@ -652,7 +661,7 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
 
 int hwdb_query(const char *modalias, const char *root) {
         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
-        const char *key, *value, *p;
+        const char *key, *value;
         int r;
 
         assert(modalias);
@@ -680,9 +689,8 @@ int hwdb_query(const char *modalias, const char *root) {
         return 0;
 }
 
-bool hwdb_validate(sd_hwdb *hwdb) {
+bool hwdb_should_reload(sd_hwdb *hwdb) {
         bool found = false;
-        const char* p;
         struct stat st;
 
         if (!hwdb)
@@ -703,3 +711,16 @@ bool hwdb_validate(sd_hwdb *hwdb) {
                 return true;
         return false;
 }
+
+int hwdb_bypass(void) {
+        int r;
+
+        r = getenv_bool("SYSTEMD_HWDB_UPDATE_BYPASS");
+        if (r < 0 && r != -ENXIO)
+                log_debug_errno(r, "Failed to parse $SYSTEMD_HWDB_UPDATE_BYPASS, assuming no.");
+        if (r <= 0)
+                return false;
+
+        log_debug("$SYSTEMD_HWDB_UPDATE_BYPASS is enabled, skipping execution.");
+        return true;
+}