From: Paul Meyer Date: Wed, 6 May 2026 15:35:48 +0000 (+0200) Subject: vmspawn: search XDG_DATA_DIRS for QEMU firmware X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=67e23e0e050fca0279fc6045de20ed05b0b97bee;p=thirdparty%2Fsystemd.git 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 Signed-off-by: Paul Meyer --- diff --git a/src/vmspawn/vmspawn-util.c b/src/vmspawn/vmspawn-util.c index 72187b6731a..c5ab40a0d20 100644 --- a/src/vmspawn/vmspawn-util.c +++ b/src/vmspawn/vmspawn-util.c @@ -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)