From: Kai Lüke Date: Mon, 13 Apr 2026 12:21:39 +0000 (+0900) Subject: vmspawn: Support RUNTIME_DIRECTORY again X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F41619%2Fhead;p=thirdparty%2Fsystemd.git vmspawn: Support RUNTIME_DIRECTORY again In ccecae0efd ("vmspawn: use machine name in runtime directory path") support for RUNTIME_DIRECTORY was dropped which makes it difficult to run systemd-vmspawn in a service unit which doesn't have write access to the regular /run but should use its own managed RUNTIME_DIRECTORY. What worked before was --keep-unit --system but we can't use XDG_RUNTIME_DIR and --user because then --keep-unit breaks which we need because it can't create a scope as there is no session. Switch back to runtime_directory which handles RUNTIME_DIRECTORY and tells us whether we should use it as is without later cleanup or if we need to use the regular path where we create and delete the directory ourselves. --- diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index c1b913217a7..fe7d307a637 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -2387,7 +2387,13 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) { return log_oom(); /* Create our runtime directory. We need this for the QEMU config file, TPM state, virtiofsd - * sockets, runtime mounts, and SSH key material. */ + * sockets, runtime mounts, and SSH key material. + * + * Use runtime_directory() (not _generic()) so that when vmspawn runs in a systemd service + * with RuntimeDirectory= set, we pick up $RUNTIME_DIRECTORY and place our stuff into the + * directory the service manager prepared for us. When the env var is unset, we fall back + * to /run/systemd/vmspawn// (or the $XDG_RUNTIME_DIR equivalent in user scope) + * and take care of creation and destruction ourselves. */ _cleanup_free_ char *runtime_dir = NULL, *runtime_dir_suffix = NULL; _cleanup_(rm_rf_physical_and_freep) char *runtime_dir_destroy = NULL; @@ -2395,21 +2401,27 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) { if (!runtime_dir_suffix) return log_oom(); - r = runtime_directory_generic(arg_runtime_scope, runtime_dir_suffix, &runtime_dir); + r = runtime_directory(arg_runtime_scope, runtime_dir_suffix, &runtime_dir); if (r < 0) return log_error_errno(r, "Failed to determine runtime directory: %m"); - - /* If a previous vmspawn instance was killed without cleanup (e.g. SIGKILL), the directory may - * already exist with stale contents. This is harmless: varlink's sockaddr_un_unlink() removes stale - * sockets before bind(), and other files (QEMU config, SSH keys) are created fresh. This matches - * nspawn's approach of not proactively cleaning stale runtime directories. */ - r = mkdir_p(runtime_dir, 0755); - if (r < 0) - return log_error_errno(r, "Failed to create runtime directory '%s': %m", runtime_dir); - - runtime_dir_destroy = strdup(runtime_dir); - if (!runtime_dir_destroy) - return log_oom(); + if (r > 0) { + /* $RUNTIME_DIRECTORY was not set, so we got the fallback path and need to create and + * clean up the directory ourselves. + * + * If a previous vmspawn instance was killed without cleanup (e.g. SIGKILL), the directory may + * already exist with stale contents. This is harmless: varlink's sockaddr_un_unlink() removes stale + * sockets before bind(), and other files (QEMU config, SSH keys) are created fresh. This matches + * nspawn's approach of not proactively cleaning stale runtime directories. */ + r = mkdir_p(runtime_dir, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create runtime directory '%s': %m", runtime_dir); + + runtime_dir_destroy = strdup(runtime_dir); + if (!runtime_dir_destroy) + return log_oom(); + } + /* When $RUNTIME_DIRECTORY is set the service manager created the directory for us and + * will destroy it (or preserve it, per RuntimeDirectoryPreserve=) when the service stops. */ log_debug("Using runtime directory: %s", runtime_dir);