vmspawn: search XDG_DATA_DIRS for QEMU firmware

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>
This commit is contained in:
Paul Meyer
2026-05-07 10:33:01 +02:00
committed by Zbigniew Jędrzejewski-Szmek
parent f0a171d1d8
commit 67e23e0e05
+23 -9
View 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)