]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/udevadm-hwdb.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / udev / udevadm-hwdb.c
index 61a3b081994dc0566f4baed441811c87aa01c244..ba7a15e6e9d07b7c9256ab3b68c86bbd6e90d2fc 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <unistd.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 "fileio.h"
+#include "fs-util.h"
+#include "hwdb-internal.h"
+#include "hwdb-util.h"
+#include "label.h"
+#include "mkdir.h"
+#include "strbuf.h"
+#include "string-util.h"
 #include "udev.h"
-#include "libudev-hwdb-def.h"
+#include "util.h"
 
 /*
  * Generic udev properties, key/value database based on modalias strings.
@@ -190,7 +196,7 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
                                 continue;
 
                         /* split node */
-                        new_child = calloc(sizeof(struct trie_node), 1);
+                        new_child = new0(struct trie_node, 1);
                         if (!new_child)
                                 return -ENOMEM;
 
@@ -233,7 +239,7 @@ static int trie_insert(struct trie *trie, struct trie_node *node, const char *se
                         ssize_t off;
 
                         /* new child */
-                        child = calloc(sizeof(struct trie_node), 1);
+                        child = new0(struct trie_node, 1);
                         if (!child)
                                 return -ENOMEM;
 
@@ -341,13 +347,13 @@ static int trie_store(struct trie *trie, const char *filename) {
         struct trie_f t = {
                 .trie = trie,
         };
-        char *filename_tmp;
+        _cleanup_free_ char *filename_tmp = NULL;
         int64_t pos;
         int64_t root_off;
         int64_t size;
         struct trie_header_f h = {
                 .signature = HWDB_SIG,
-                .tool_version = htole64(atoi(VERSION)),
+                .tool_version = htole64(atoi(PACKAGE_VERSION)),
                 .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)),
@@ -359,13 +365,14 @@ static int trie_store(struct trie *trie, const char *filename) {
         t.strings_off = sizeof(struct trie_header_f);
         trie_store_nodes_size(&t, trie->root);
 
-        err = fopen_temporary(filename , &t.f, &filename_tmp);
+        err = fopen_temporary(filename, &t.f, &filename_tmp);
         if (err < 0)
                 return err;
         fchmod(fileno(t.f), 0444);
 
         /* write nodes */
-        fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET);
+        if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
+                goto error_fclose;
         root_off = trie_store_nodes(&t, trie->root);
         h.nodes_root_off = htole64(root_off);
         pos = ftello(t.f);
@@ -378,30 +385,40 @@ static int trie_store(struct trie *trie, const char *filename) {
         /* write header */
         size = ftello(t.f);
         h.file_size = htole64(size);
-        fseeko(t.f, 0, SEEK_SET);
+        if (fseeko(t.f, 0, SEEK_SET < 0))
+                goto error_fclose;
         fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
-        err = ferror(t.f);
-        if (err)
-                err = -errno;
+
+        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;
+
+        /* write succeeded */
         fclose(t.f);
-        if (err < 0 || rename(filename_tmp, filename) < 0) {
-                unlink(filename_tmp);
-                goto out;
-        }
 
-        log_debug("=== trie on-disk ===\n");
-        log_debug("size:             %8llu bytes\n", (unsigned long long)size);
-        log_debug("header:           %8zu bytes\n", sizeof(struct trie_header_f));
-        log_debug("nodes:            %8llu bytes (%8llu)\n",
-                  (unsigned long long)t.nodes_count * sizeof(struct trie_node_f), (unsigned long long)t.nodes_count);
-        log_debug("child pointers:   %8llu bytes (%8llu)\n",
-                  (unsigned long long)t.children_count * sizeof(struct trie_child_entry_f), (unsigned long long)t.children_count);
-        log_debug("value pointers:   %8llu bytes (%8llu)\n",
-                  (unsigned long long)t.values_count * sizeof(struct trie_value_entry_f), (unsigned long long)t.values_count);
-        log_debug("string store:     %8llu bytes\n", (unsigned long long)trie->strings->len);
-        log_debug("strings start:    %8llu\n", (unsigned long long) t.strings_off);
-out:
-        free(filename_tmp);
+        log_debug("=== trie on-disk ===");
+        log_debug("size:             %8"PRIi64" bytes", size);
+        log_debug("header:           %8zu bytes", sizeof(struct trie_header_f));
+        log_debug("nodes:            %8"PRIu64" bytes (%8"PRIu64")",
+                  t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
+        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);
+        log_debug("string store:     %8zu bytes", trie->strings->len);
+        log_debug("strings start:    %8"PRIu64, t.strings_off);
+
+        return 0;
+
+ error_fclose:
+        err = -errno;
+        fclose(t.f);
+        unlink(filename_tmp);
         return err;
 }
 
@@ -412,15 +429,19 @@ static int insert_data(struct trie *trie, struct udev_list *match_list,
 
         value = strchr(line, '=');
         if (!value) {
-                log_error("Error, key/value pair expected but got '%s' in '%s':\n", line, filename);
+                log_error("Error, key/value pair expected but got '%s' in '%s':", line, filename);
                 return -EINVAL;
         }
 
         value[0] = '\0';
         value++;
 
+        /* libudev requires properties to start with a space */
+        while (isblank(line[0]) && isblank(line[1]))
+                line++;
+
         if (line[0] == '\0' || value[0] == '\0') {
-                log_error("Error, empty key or value '%s' in '%s':\n", line, filename);
+                log_error("Error, empty key or value '%s' in '%s':", line, filename);
                 return -EINVAL;
         }
 
@@ -471,7 +492,7 @@ static int import_file(struct udev *udev, struct trie *trie, const char *filenam
                                 break;
 
                         if (line[0] == ' ') {
-                                log_error("Error, MATCH expected but got '%s' in '%s':\n", line, filename);
+                                log_error("Error, MATCH expected but got '%s' in '%s':", line, filename);
                                 break;
                         }
 
@@ -482,7 +503,7 @@ static int import_file(struct udev *udev, struct trie *trie, const char *filenam
 
                 case HW_MATCH:
                         if (len == 0) {
-                                log_error("Error, DATA expected but got empty line in '%s':\n", filename);
+                                log_error("Error, DATA expected but got empty line in '%s':", filename);
                                 state = HW_NONE;
                                 udev_list_cleanup(&match_list);
                                 break;
@@ -508,7 +529,7 @@ static int import_file(struct udev *udev, struct trie *trie, const char *filenam
                         }
 
                         if (line[0] != ' ') {
-                                log_error("Error, DATA expected but got '%s' in '%s':\n", line, filename);
+                                log_error("Error, DATA expected but got '%s' in '%s':", line, filename);
                                 state = HW_NONE;
                                 udev_list_cleanup(&match_list);
                                 break;
@@ -527,14 +548,20 @@ static int import_file(struct udev *udev, struct trie *trie, const char *filenam
 static void help(void) {
         printf("Usage: udevadm hwdb OPTIONS\n"
                "  -u,--update          update the hardware database\n"
+               "  --usr                generate in " UDEVLIBEXECDIR " instead of /etc/udev\n"
                "  -t,--test=MODALIAS   query database and print result\n"
                "  -r,--root=PATH       alternative root path in the filesystem\n"
                "  -h,--help\n\n");
 }
 
 static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
+        enum {
+                ARG_USR = 0x100,
+        };
+
         static const struct option options[] = {
                 { "update", no_argument,       NULL, 'u' },
+                { "usr",    no_argument,       NULL, ARG_USR },
                 { "test",   required_argument, NULL, 't' },
                 { "root",   required_argument, NULL, 'r' },
                 { "help",   no_argument,       NULL, 'h' },
@@ -542,6 +569,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
         };
         const char *test = NULL;
         const char *root = "";
+        const char *hwdb_bin_dir = "/etc/udev";
         bool update = false;
         struct trie *trie = NULL;
         int err, c;
@@ -552,6 +580,9 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
                 case 'u':
                         update = true;
                         break;
+                case ARG_USR:
+                        hwdb_bin_dir = UDEVLIBEXECDIR;
+                        break;
                 case 't':
                         test = optarg;
                         break;
@@ -576,7 +607,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
                 char **files, **f;
                 _cleanup_free_ char *hwdb_bin = NULL;
 
-                trie = calloc(sizeof(struct trie), 1);
+                trie = new0(struct trie, 1);
                 if (!trie) {
                         rc = EXIT_FAILURE;
                         goto out;
@@ -590,16 +621,16 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
                 }
 
                 /* index */
-                trie->root = calloc(sizeof(struct trie_node), 1);
+                trie->root = new0(struct trie_node, 1);
                 if (!trie->root) {
                         rc = EXIT_FAILURE;
                         goto out;
                 }
                 trie->nodes_count++;
 
-                err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
+                err = conf_files_list_strv(&files, ".hwdb", root, 0, conf_file_dirs);
                 if (err < 0) {
-                        log_error("failed to enumerate hwdb files: %s\n", strerror(-err));
+                        log_error_errno(err, "failed to enumerate hwdb files: %m");
                         rc = EXIT_FAILURE;
                         goto out;
                 }
@@ -611,41 +642,47 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
 
                 strbuf_complete(trie->strings);
 
-                log_debug("=== trie in-memory ===\n");
-                log_debug("nodes:            %8zu bytes (%8zu)\n",
+                log_debug("=== trie in-memory ===");
+                log_debug("nodes:            %8zu bytes (%8zu)",
                           trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
-                log_debug("children arrays:  %8zu bytes (%8zu)\n",
+                log_debug("children arrays:  %8zu bytes (%8zu)",
                           trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
-                log_debug("values arrays:    %8zu bytes (%8zu)\n",
+                log_debug("values arrays:    %8zu bytes (%8zu)",
                           trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
-                log_debug("strings:          %8zu bytes\n",
+                log_debug("strings:          %8zu bytes",
                           trie->strings->len);
-                log_debug("strings incoming: %8zu bytes (%8zu)\n",
+                log_debug("strings incoming: %8zu bytes (%8zu)",
                           trie->strings->in_len, trie->strings->in_count);
-                log_debug("strings dedup'ed: %8zu bytes (%8zu)\n",
+                log_debug("strings dedup'ed: %8zu bytes (%8zu)",
                           trie->strings->dedup_len, trie->strings->dedup_count);
 
-                if (asprintf(&hwdb_bin, "%s/etc/udev/hwdb.bin", root) < 0) {
+                hwdb_bin = strjoin(root, "/", hwdb_bin_dir, "/hwdb.bin");
+                if (!hwdb_bin) {
                         rc = EXIT_FAILURE;
                         goto out;
                 }
-                mkdir_parents(hwdb_bin, 0755);
+
+                mkdir_parents_label(hwdb_bin, 0755);
+
                 err = trie_store(trie, hwdb_bin);
                 if (err < 0) {
-                        log_error("Failure writing database %s: %s", hwdb_bin, strerror(-err));
+                        log_error_errno(err, "Failure writing database %s: %m", hwdb_bin);
                         rc = EXIT_FAILURE;
                 }
+
+                label_fix(hwdb_bin, false, false);
         }
 
         if (test) {
-                struct udev_hwdb *hwdb = udev_hwdb_new(udev);
+                _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
+                int r;
 
-                if (hwdb) {
-                        struct udev_list_entry *entry;
+                r = sd_hwdb_new(&hwdb);
+                if (r >= 0) {
+                        const char *key, *value;
 
-                        udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, test, 0))
-                                printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
-                        udev_hwdb_unref(hwdb);
+                        SD_HWDB_FOREACH_PROPERTY(hwdb, test, key, value)
+                                printf("%s=%s\n", key, value);
                 }
         }
 out:
@@ -661,5 +698,4 @@ out:
 const struct udevadm_cmd udevadm_hwdb = {
         .name = "hwdb",
         .cmd = adm_hwdb,
-        .help = "maintain the hardware database index",
 };