]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vmspawn: search XDG_DATA_DIRS for QEMU firmware
authorPaul Meyer <katexochen0@gmail.com>
Wed, 6 May 2026 15:35:48 +0000 (17:35 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 7 May 2026 08:33:01 +0000 (10:33 +0200)
get_firmware_search_dirs() previously hardcoded /usr/share/qemu/firmware
as the only system-wide search path. That assumption breaks on
distributions that deliberately do not populate /usr/share, making
vmspawn fail: "Failed to find OVMF config: No such file or directory".
NixOS exposes those firmware locations through XDG_DATA_DIRS.

Extend the search list with XDG_DATA_HOME/XDG_DATA_DIRS. This is the
standard XDG mechanism and is already what QEMU itself uses for the same
descriptors, so behavior matches user expectations across tooling.

To avoid regressing setups where user has set XDG_DATA_DIRS to a custom
value that omits /usr/share, keep /usr/share/qemu/firmware as an
unconditional fallback.

Precedence is unchanged: XDG_CONFIG_HOME/qemu/firmware still wins
over /etc/qemu/firmware, which still wins over any shared-data dir.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Paul Meyer <katexochen0@gmail.com>
src/vmspawn/vmspawn-util.c

index 72187b6731a0a3562ad70ae228fe26ef60c24464..c5ab40a0d2055434e8575816e694b3d457bcc8eb 100644 (file)
@@ -254,7 +254,9 @@ static int get_firmware_search_dirs(char ***ret) {
         /* Search in:
          * - $XDG_CONFIG_HOME/qemu/firmware
          * - /etc/qemu/firmware
-         * - /usr/share/qemu/firmware
+         * - $XDG_DATA_HOME/qemu/firmware (default: ~/.local/share/qemu/firmware)
+         * - each entry in $XDG_DATA_DIRS suffixed with /qemu/firmware
+         *   (default: /usr/local/share/qemu/firmware, /usr/share/qemu/firmware)
          *
          * Prioritising entries in "more specific" directories */
 
@@ -264,10 +266,27 @@ static int get_firmware_search_dirs(char ***ret) {
                 return r;
 
         _cleanup_strv_free_ char **l = NULL;
-        l = strv_new(user_firmware_dir, "/etc/qemu/firmware", "/usr/share/qemu/firmware");
+        l = strv_new(user_firmware_dir, "/etc/qemu/firmware");
         if (!l)
                 return log_oom_debug();
 
+        _cleanup_strv_free_ char **data_dirs = NULL;
+        r = sd_path_lookup_strv(SD_PATH_SEARCH_SHARED, "/qemu/firmware", &data_dirs);
+        if (r < 0)
+                return r;
+
+        r = strv_extend_strv(&l, data_dirs, /* filter_duplicates = */ true);
+        if (r < 0)
+                return log_oom_debug();
+
+        /* Always include /usr/share/qemu/firmware as a final fallback,
+         * even if a custom $XDG_DATA_DIRS replaced it. */
+        r = strv_extend(&l, "/usr/share/qemu/firmware");
+        if (r < 0)
+                return log_oom_debug();
+
+        strv_uniq(l);
+
         *ret = TAKE_PTR(l);
         return 0;
 }
@@ -424,13 +443,8 @@ int find_ovmf_config(
         if (r < 0)
                 return r;
 
-        /* Search in:
-         * - $XDG_CONFIG_HOME/qemu/firmware
-         * - /etc/qemu/firmware
-         * - /usr/share/qemu/firmware
-         *
-         * Prioritising entries in "more specific" directories
-         */
+        /* Search paths are constructed by get_firmware_search_dirs(),
+         * prioritising entries in "more specific" directories. */
 
         r = list_ovmf_config(&conf_files);
         if (r < 0)