Subject: [WIP PATCH gnome-team v2 1/3] gnu: eudev: Update libudev version to 251.

From: Vivien Kraus <[email-masked]>
Date: Tue, 19 Sep 2023 13:23:22 +0200

Support for version 251 is only provided as a merge request for now:

https://github.com/eudev-project/eudev/pull/253

This merge request bumps the eudev version to 3.2.14, but it has not been
released yet.

Eudev now has a hardware database that installs descriptions of hardware in
/etc, but they should go to /lib prior to being used. I added a phase to copy
all the /etc files to /lib.

I submitted 3 patches to make udev hwdb more guix-friendly, fused in
eudev-hwdb-bin-path.patch. libudev requires an indexed binary file that knows
about all devices, and this file is generated by udevadm hwdb --update -o
<prefix>/lib/udev/hwdb.bin. This udevadm hwdb command respects the
UDEV_HWDB_PATH to collect all entries for the hwdb. Then, libudev can use
UDEV_HWDB_BIN to select the database at run-time.

I think everything could work out for Guix if we add a new profile hook that:
1. Calls udevadm hwdb --update -o <profile>/lib/udev/hwdb.bin;
2. Set UDEV_HWDB_BIN to <profile>/lib/udev/hwdb.bin.

Unfortunately, I don’t know how to do that profile hook thing. Do you have
pointers?

* gnu/packages/linux.scm (eudev): Update to v3.2.12, but bump version to
3.2.14.beta.
[#:phases] <allow-eudev-hwdb>: New phase.
<build-hwdb>: Update accordingly.
[search-paths]: Add UDEV_HWDB_PATH.
* gnu/packages/patches/eudev-bump-to-251.patch: New file.
* gnu/packages/patches/eudev-hwdb-bin-path.patch: New file.
* gnu/packages/linux.scm (eudev): Use them here.
* gnu/local.mk (dist_patch_DATA): Register them here.
---
 gnu/local.mk                                  |   2 +
 gnu/packages/linux.scm                        |  32 +-
 gnu/packages/patches/eudev-bump-to-251.patch  | 134 ++++++++
 .../patches/eudev-hwdb-bin-path.patch         | 309 ++++++++++++++++++
 4 files changed, 463 insertions(+), 14 deletions(-)
 create mode 100644 gnu/packages/patches/eudev-bump-to-251.patch
 create mode 100644 gnu/packages/patches/eudev-hwdb-bin-path.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 72c9954492..6c98ede191 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1127,6 +1127,8 @@ dist_patch_DATA =						\
   %D%/packages/patches/esmini-use-pkgconfig.patch		\
   %D%/packages/patches/esmtp-add-lesmtp.patch		\
   %D%/packages/patches/eudev-rules-directory.patch		\
+  %D%/packages/patches/eudev-bump-to-251.patch		\
+  %D%/packages/patches/eudev-hwdb-bin-path.patch		\
   %D%/packages/patches/exercism-disable-self-update.patch	\
   %D%/packages/patches/extempore-unbundle-external-dependencies.patch	\
   %D%/packages/patches/extundelete-e2fsprogs-1.44.patch		\
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 85e3d9845d..5ea44e886e 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -4265,16 +4265,18 @@ (define-public eudev
   ;; The post-systemd fork, maintained by Gentoo.
   (package
     (name "eudev")
-    (version "3.2.11")
+    (version "3.2.14.beta")
     (source (origin
               (method git-fetch)
               (uri (git-reference (url "https://github.com/gentoo/eudev")
-                                  (commit (string-append "v" version))))
+                                  (commit "v3.2.12")))
               (file-name (git-file-name name version))
               (sha256
                (base32
-                "0dzaqwjnl55f69ird57wb6skahc6l7zs1slsrzqqfhww33icp6av"))
-              (patches (search-patches "eudev-rules-directory.patch"))))
+                "0wpckjxzsb4wkj3pwnw14zmp3z8ivf03hjbgs838q5gfridpxnf7"))
+              (patches (search-patches "eudev-rules-directory.patch"
+                                       "eudev-bump-to-251.patch"
+                                       "eudev-hwdb-bin-path.patch"))))
     (build-system gnu-build-system)
     (arguments
      (list
@@ -4297,18 +4299,20 @@ (define-public eudev
                 (substitute* (string-append #$output "/lib/libudev.la")
                   (("old_library=.*")
                    "old_library=''\n")))))
-          (add-after 'install 'build-hwdb
+          (add-after 'install 'allow-eudev-hwdb
             (lambda _
-              ;; Build OUT/etc/udev/hwdb.bin.  This allows 'lsusb' and
-              ;; similar tools to display product names.
-              ;;
-              ;; XXX: This can't be done when cross-compiling. Find another way
-              ;; to generate hwdb.bin for cross-built systems.
-              #$@(if (%current-target-system)
-                     #~(#t)
-                     #~((invoke (string-append #$output "/bin/udevadm")
-                                "hwdb" "--update"))))))
+              ;; eudev distributes the hwdb, but each file has to be enabled
+              ;; by being copied under /lib/udev/hwdb.d. We accept all of
+              ;; them.
+              (symlink (string-append #$output "/etc/udev/hwdb.d")
+                       (string-append #$output "/lib/udev/hwdb.d")))))
        #:configure-flags #~(list "--enable-manpages")))
+    (search-paths
+      (list (search-path-specification
+              (variable "UDEV_HWDB_PATH")
+              (files '("lib/udev/hwdb.d")))))
+    ;; FIXME: there needs to be a profile hook that calls udevadm hwdb
+    ;; --update -o <profile>/lib/udev/hwdb.bin
     (native-inputs
      (list autoconf
            automake
diff --git a/gnu/packages/patches/eudev-bump-to-251.patch b/gnu/packages/patches/eudev-bump-to-251.patch
new file mode 100644
index 0000000000..96a73f4ede
--- /dev/null
+++ b/gnu/packages/patches/eudev-bump-to-251.patch
@@ -0,0 +1,134 @@
+From 4d29151078c351569767dfef490a29e379afd430 Mon Sep 17 00:00:00 2001
+Message-ID: <[email-masked]>
+In-Reply-To: <[email-masked]>
+References: <[email-masked]>
+From: Boian Bonev <[email-masked]>
+Date: Tue, 30 May 2023 16:16:33 +0000
+Subject: [PATCH 1/1] Update as per IRC discussion
+
+Bump udev version to 251
+
+Export dummies for
+
+ - udev_device_has_current_tag
+ - udev_device_get_current_tags_list_entry
+
+since the current eudev device database does not support the concept of
+current tags
+
+bump version to 3.2.14
+---
+ README.md                    | 18 ++++++++++++------
+ configure.ac                 |  4 ++--
+ src/libudev/libudev-device.c | 11 +++++++++++
+ src/libudev/libudev.h        |  2 ++
+ src/libudev/libudev.sym      |  6 ++++++
+ 5 files changed, 33 insertions(+), 8 deletions(-)
+
+diff --git a/README.md b/README.md
+index 848ef3348..6016380ba 100644
+--- a/README.md
++++ b/README.md
+@@ -1,11 +1,17 @@
+-This git repo is a fork of git://anongit.freedesktop.org/systemd/systemd
+-with the aim of isolating udev from any particular flavor of system
+-initialization.  In this case, the isolation is from systemd.
++**eudev** is a standalone dynamic and persistent device naming support (aka
++userspace devfs) daemon that runs independently from the init system.
++**eudev** strives to remain init system and linux distribution neutral. It is
++currently used as the devfs manager for more than a dozen different linux
++distributions.
++
++This git repo is a fork of git://anongit.freedesktop.org/systemd/systemd with
++the aim of isolating udev from any particular flavor of system initialization.
++In this case, the isolation is from systemd.
+ 
+ This is a project started by Gentoo developers and testing was initially being
+-done mostly on OpenRC.  We welcome contribution from others using a variety of
+-system initializations to ensure eudev remains system initialization and
+-distribution neutral.  On 2021-08-20 Gentoo decided to abandon eudev and a new
++done mostly on OpenRC. We welcome contribution from others using a variety of
++system initializations to ensure **eudev** remains system initialization and
++distribution neutral. On 2021-08-20 Gentoo decided to abandon eudev and a new
+ project was established on 2021-09-14 by Alpine, Devuan and Gentoo
+ contributors (alphabetical order).
+ 
+diff --git a/configure.ac b/configure.ac
+index 3e31b0ebc..0d9a135bc 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,6 +1,6 @@
+ AC_PREREQ([2.68])
+-AC_INIT([eudev],[3.2.12],[https://github.com/gentoo/eudev/issues])
+-AC_SUBST(UDEV_VERSION, 243)
++AC_INIT([eudev],[3.2.14],[https://github.com/gentoo/eudev/issues])
++AC_SUBST(UDEV_VERSION, 251)
+ AC_CONFIG_SRCDIR([src/udev/udevd.c])
+ 
+ AC_USE_SYSTEM_EXTENSIONS
+diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
+index ac67ce846..7d7a6622e 100644
+--- a/src/libudev/libudev-device.c
++++ b/src/libudev/libudev-device.c
+@@ -1819,6 +1819,12 @@ _public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_dev
+         return udev_list_get_entry(&udev_device->tags_list);
+ }
+ 
++_public_ struct udev_list_entry *udev_device_get_current_tags_list_entry(struct udev_device *udev_device)
++{
++        // TODO: eudev database does not support current tags
++        return udev_device_get_tags_list_entry(udev_device);
++}
++
+ /**
+  * udev_device_has_tag:
+  * @udev_device: udev device
+@@ -1842,6 +1848,11 @@ _public_ int udev_device_has_tag(struct udev_device *udev_device, const char *ta
+         return false;
+ }
+ 
++_public_ int udev_device_has_current_tag(struct udev_device *udev_device, const char *tag) {
++        // TODO: eudev database does not support current tags
++        return udev_device_has_tag(udev_device, tag);
++}
++
+ #define ENVP_SIZE                        128
+ #define MONITOR_BUF_SIZE                4096
+ static int update_envp_monitor_buf(struct udev_device *udev_device)
+diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h
+index 8491d2b81..0202964d6 100644
+--- a/src/libudev/libudev.h
++++ b/src/libudev/libudev.h
+@@ -100,6 +100,7 @@ int udev_device_get_is_initialized(struct udev_device *udev_device);
+ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
+ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
+ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
++struct udev_list_entry *udev_device_get_current_tags_list_entry(struct udev_device *udev_device);
+ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
+ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
+ const char *udev_device_get_driver(struct udev_device *udev_device);
+@@ -110,6 +111,7 @@ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device
+ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
+ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
+ int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
++int udev_device_has_current_tag(struct udev_device *udev_device, const char *tag);
+ 
+ /*
+  * udev_monitor
+diff --git a/src/libudev/libudev.sym b/src/libudev/libudev.sym
+index 76726fca7..d56c2aeab 100644
+--- a/src/libudev/libudev.sym
++++ b/src/libudev/libudev.sym
+@@ -118,3 +118,9 @@ global:
+         udev_queue_flush;
+         udev_queue_get_fd;
+ } LIBUDEV_199;
++
++LIBUDEV_247 {
++global:
++        udev_device_has_current_tag;
++        udev_device_get_current_tags_list_entry;
++} LIBUDEV_215;
+-- 
+2.41.0
+
diff --git a/gnu/packages/patches/eudev-hwdb-bin-path.patch b/gnu/packages/patches/eudev-hwdb-bin-path.patch
new file mode 100644
index 0000000000..f6fa91dad0
--- /dev/null
+++ b/gnu/packages/patches/eudev-hwdb-bin-path.patch
@@ -0,0 +1,309 @@
+From 097290727d6e16aa2e5859e3cd6f0c5ea4c47101 Mon Sep 17 00:00:00 2001
+Message-ID: <[email-masked]>
+From: Vivien Kraus <[email-masked]>
+Date: Tue, 26 Sep 2023 18:17:34 +0200
+Subject: [PATCH] Improvements for Guix
+
+---
+This is the combination of:
+
+  - https://github.com/eudev-project/eudev/pull/262
+  - https://github.com/eudev-project/eudev/pull/263
+  - https://github.com/eudev-project/eudev/pull/264
+
+ src/libudev/libudev-hwdb.c |  37 +++++++++--
+ src/libudev/libudev.h      |   4 +-
+ src/udev/udevadm-hwdb.c    | 127 +++++++++++++++++++++++++++++++++----
+ 3 files changed, 149 insertions(+), 19 deletions(-)
+
+diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c
+index 62029e2b2..f7212c519 100644
+--- a/src/libudev/libudev-hwdb.c
++++ b/src/libudev/libudev-hwdb.c
+@@ -47,6 +47,7 @@ struct udev_hwdb {
+         struct udev *udev;
+         int refcount;
+ 
++        char *bin_paths;
+         FILE *f;
+         struct stat st;
+         union {
+@@ -256,10 +257,28 @@ static int trie_search_f(struct udev_hwdb *hwdb, const char *search) {
+         return 0;
+ }
+ 
+-static const char hwdb_bin_paths[] =
+-    "/etc/udev/hwdb.bin\0"
+-    UDEV_LIBEXEC_DIR "/hwdb.bin\0";
+-
++static char *get_hwdb_bin_paths (void) {
++        static const char default_locations[] =
++          "/etc/udev/hwdb.bin\0"
++          UDEV_LIBEXEC_DIR "/hwdb.bin\0";
++        const char *by_env = getenv("UDEV_HWDB_BIN");
++        if (by_env != NULL) {
++                char *path = malloc(strlen(by_env) + 1
++                                    + sizeof (default_locations));
++                if (path != NULL) {
++                        memcpy(path, by_env, strlen(by_env) + 1);
++                        memcpy(path + strlen(by_env) + 1,
++                               default_locations,
++                               sizeof (default_locations));
++                }
++                return path;
++        }
++        char *path = malloc(sizeof (default_locations));
++        if (path != NULL) {
++                memcpy(path, default_locations, sizeof (default_locations));
++        }
++        return path;
++}
+ 
+ /**
+  * udev_hwdb_new:
+@@ -282,7 +301,12 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
+         udev_list_init(udev, &hwdb->properties_list, true);
+ 
+         /* find hwdb.bin in hwdb_bin_paths */
+-        NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
++        hwdb->bin_paths = get_hwdb_bin_paths();
++        if (hwdb->bin_paths == NULL) {
++                udev_hwdb_unref(hwdb);
++                return NULL;
++        }
++        NULSTR_FOREACH(hwdb_bin_path, hwdb->bin_paths) {
+                 hwdb->f = fopen(hwdb_bin_path, "re");
+                 if (hwdb->f)
+                         break;
+@@ -363,6 +387,7 @@ _public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
+                 return NULL;
+         if (hwdb->map)
+                 munmap((void *)hwdb->map, hwdb->st.st_size);
++        free(hwdb->bin_paths);
+         if (hwdb->f)
+                 fclose(hwdb->f);
+         udev_list_cleanup(&hwdb->properties_list);
+@@ -381,7 +406,7 @@ bool udev_hwdb_validate(struct udev_hwdb *hwdb) {
+                 return false;
+ 
+         /* if hwdb.bin doesn't exist anywhere, we need to update */
+-        NULSTR_FOREACH(p, hwdb_bin_paths) {
++        NULSTR_FOREACH(p, hwdb->bin_paths) {
+                 if (stat(p, &st) >= 0) {
+                         found = true;
+                         break;
+diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h
+index 8491d2b81..e4bc18970 100644
+--- a/src/libudev/libudev.h
++++ b/src/libudev/libudev.h
+@@ -185,7 +185,9 @@ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev
+ /*
+  *  udev_hwdb
+  *
+- *  access to the static hardware properties database
++ *  access to the static hardware properties database; the database to
++ *  use can be overriden by setting the UDEV_HWDB_BIN environment
++ *  variable to its file name
+  */
+ struct udev_hwdb;
+ struct udev_hwdb *udev_hwdb_new(struct udev *udev);
+diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
+index d14a3434f..c2214dc91 100644
+--- a/src/udev/udevadm-hwdb.c
++++ b/src/udev/udevadm-hwdb.c
+@@ -35,11 +35,69 @@
+  * Uses a Patricia/radix trie to index all matches for efficient lookup.
+  */
+ 
+-static const char * const conf_file_dirs[] = {
+-        UDEV_HWDB_DIR,
+-        UDEV_LIBEXEC_DIR "/hwdb.d",
+-        NULL
+-};
++static ssize_t follow_path (const char *path_variable, char **destination, size_t max) {
++        size_t n = 0;
++        if (path_variable != NULL) {
++                while (path_variable[0] == ':') {
++                      path_variable++;
++                }
++                while (path_variable[0] != '\0') {
++                        const char *end = strchr(path_variable, ':');
++                        if (end == NULL) {
++                                end = path_variable + strlen(path_variable);
++                        }
++                        if (n < max) {
++                                destination[n] = strndup(path_variable, end - path_variable);
++                                if (destination[n] == NULL) {
++                                        return -ENOMEM;
++                                }
++                        }
++                        n++;
++                        path_variable = end;
++                        while (path_variable[0] == ':') {
++                                path_variable++;
++                        }
++                }
++        }
++        if (n < max) {
++                destination[n] = NULL;
++        }
++        return n;
++}
++
++static char ** list_conf_file_dirs (void) {
++        static const char *main_hwdb_dir = UDEV_HWDB_DIR;
++        static const char *libexec_dir = UDEV_LIBEXEC_DIR "/hwdb.d";
++        const char *path_variable = getenv ("UDEV_HWDB_PATH");
++        ssize_t path_length = 0;
++        if (path_variable != NULL) {
++                path_length = follow_path(path_variable, NULL, 0);
++                if (path_length < 0) {
++                      return NULL;
++                }
++        }
++        char **all_dirs = malloc((path_length + 2 + 1) * sizeof (char *));
++        if (all_dirs == NULL) {
++                return NULL;
++        }
++        for (ssize_t i = 0; i < path_length + 2 + 1; i++) {
++                all_dirs[i] = NULL;
++        }
++        ssize_t error = follow_path(path_variable, all_dirs, path_length + 1);
++        all_dirs[path_length] = strdup(main_hwdb_dir);
++        all_dirs[path_length + 1] = strdup(libexec_dir);
++        all_dirs[path_length + 2] = NULL;
++        if (error < 0
++            || all_dirs[path_length] == NULL
++            || all_dirs[path_length + 1] == NULL) {
++                for (ssize_t i = 0; i < path_length + 2 + 1; i++) {
++                        free(all_dirs[i]);
++                }
++                free(all_dirs);
++                all_dirs = NULL;
++        }
++        return all_dirs;
++}
+ 
+ /* in-memory trie objects */
+ struct trie {
+@@ -564,10 +622,15 @@ 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"
++               "  -o,--output=.../hwdb.bin generate in .../hwdb.bin instead of /etc/udev/hwdb.bin\n"
+                "  --usr                generate in " UDEV_LIBEXEC_DIR " 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");
++               "  -h,--help\n"
++               "\n"
++               "The HWDB is searched in the UDEV_HWDB_PATH search path, "
++               UDEV_HWDB_DIR ", and " UDEV_LIBEXEC_DIR "/hwdb.d.\n"
++               "\n");
+ }
+ 
+ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
+@@ -578,6 +641,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
+         static const struct option options[] = {
+                 { "update", no_argument,       NULL, 'u' },
+                 { "usr",    no_argument,       NULL, ARG_USR },
++                { "output", required_argument, NULL, 'o' },
+                 { "test",   required_argument, NULL, 't' },
+                 { "root",   required_argument, NULL, 'r' },
+                 { "help",   no_argument,       NULL, 'h' },
+@@ -585,19 +649,37 @@ 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;
+         int rc = EXIT_SUCCESS;
+ 
+-        while ((c = getopt_long(argc, argv, "ut:r:h", options, NULL)) >= 0)
++        _cleanup_free_ char *hwdb_bin = strdup("/etc/udev/hwdb.bin");
++        if (hwdb_bin == NULL) {
++                rc = EXIT_FAILURE;
++                goto out;
++        }
++
++        while ((c = getopt_long(argc, argv, "uo:t:r:h", options, NULL)) >= 0)
+                 switch(c) {
+                 case 'u':
+                         update = true;
+                         break;
+                 case ARG_USR:
+-                        hwdb_bin_dir = UDEV_LIBEXEC_DIR;
++                        free(hwdb_bin);
++                        hwdb_bin = strdup(UDEV_LIBEXEC_DIR "/hwdb.bin");
++                        if (hwdb_bin == NULL) {
++                                rc = EXIT_FAILURE;
++                                goto out;
++                        }
++                        break;
++                case 'o':
++                        free(hwdb_bin);
++                        hwdb_bin = strdup(optarg);
++                        if (hwdb_bin == NULL) {
++                                rc = EXIT_FAILURE;
++                                goto out;
++                        }
+                         break;
+                 case 't':
+                         test = optarg;
+@@ -619,9 +701,18 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
+                 return EXIT_FAILURE;
+         }
+ 
++        if (root) {
++                char *full_hwdb_bin = strjoin(root, "/", hwdb_bin, NULL);
++                if (full_hwdb_bin == NULL) {
++                        rc = EXIT_FAILURE;
++                        goto out;
++                }
++                free (hwdb_bin);
++                hwdb_bin = full_hwdb_bin;
++        }
++
+         if (update) {
+                 char **files, **f;
+-                _cleanup_free_ char *hwdb_bin = NULL;
+ 
+                 trie = new0(struct trie, 1);
+                 if (!trie) {
+@@ -644,7 +735,20 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
+                 }
+                 trie->nodes_count++;
+ 
+-                err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
++                char **conf_file_dirs = list_conf_file_dirs ();
++                if (conf_file_dirs == NULL) {
++                        rc = EXIT_FAILURE;
++                        goto out;
++                }
++                err = conf_files_list_strv(&files, ".hwdb", root,
++                                           (const char * const*) conf_file_dirs);
++                size_t dir_to_cleanup = 0;
++                for (dir_to_cleanup = 0;
++                     conf_file_dirs[dir_to_cleanup] != NULL;
++                     dir_to_cleanup++) {
++                        free (conf_file_dirs[dir_to_cleanup]);
++                }
++                free (conf_file_dirs);
+                 if (err < 0) {
+                         log_error_errno(err, "failed to enumerate hwdb files: %m");
+                         rc = EXIT_FAILURE;
+@@ -672,7 +776,6 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
+                 log_debug("strings dedup'ed: %8zu bytes (%8zu)",
+                           trie->strings->dedup_len, trie->strings->dedup_count);
+ 
+-                hwdb_bin = strjoin(root, "/", hwdb_bin_dir, "/hwdb.bin", NULL);
+                 if (!hwdb_bin) {
+                         rc = EXIT_FAILURE;
+                         goto out;
+
+base-commit: 0d86dd9a2a57d5d0809de6395dc36abe515818b5
+-- 
+2.41.0
+
-- 
2.41.0