]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vmspawn: use fstab.extra credential for runtime mounts instead of kernel cmdline
authorDaan De Meyer <daan@amutable.com>
Fri, 27 Mar 2026 14:58:35 +0000 (14:58 +0000)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 2 Apr 2026 14:03:29 +0000 (16:03 +0200)
Switch runtime virtiofs mount configuration from systemd.mount-extra=
kernel command line parameters to the fstab.extra credential. This
avoids consuming kernel command line space (which is limited) and
matches the approach used by mkosi.

Each mount is added as an fstab entry in the format:
  {tag} {destination} virtiofs {ro|rw},x-initrd.mount

If the user already specified a fstab.extra credential via
--set-credential= or --load-credential=, the virtiofs mount entries
are appended to it rather than conflicting.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
src/basic/escape.c
src/basic/escape.h
src/vmspawn/vmspawn.c

index e1771bf4322781d356cdcbe1c54915b4bef23f42..9af8efacc7423e0a9786b8f740825cb3b2e87178 100644 (file)
@@ -447,10 +447,10 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl
                                                       FLAGS_SET(flags, XESCAPE_FORCE_ELLIPSIS));
 }
 
-char* octescape(const char *s, size_t len) {
+char* octescape_full(const char *s, size_t len, const char *bad) {
         char *buf, *t;
 
-        /* Escapes \ and " chars, in \nnn style escaping. */
+        /* Escapes all chars in bad, in addition to \ and " chars, in \nnn octal style escaping. */
 
         assert(s || len == 0);
 
@@ -467,7 +467,7 @@ char* octescape(const char *s, size_t len) {
         for (size_t i = 0; i < len; i++) {
                 uint8_t u = (uint8_t) s[i];
 
-                if (u < ' ' || u >= 127 || IN_SET(u, '\\', '"')) {
+                if (u < ' ' || u >= 127 || IN_SET(u, '\\', '"') || (bad && strchr(bad, u))) {
                         *(t++) = '\\';
                         *(t++) = '0' + (u >> 6);
                         *(t++) = '0' + ((u >> 3) & 7);
index a8b68fa75c2776baaff4e8e28805c9ca74d84c93..625758f2f4c9f038903290dbf2ba4741a1f3c12c 100644 (file)
@@ -59,7 +59,10 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
 static inline char* xescape(const char *s, const char *bad) {
         return xescape_full(s, bad, SIZE_MAX, 0);
 }
-char* octescape(const char *s, size_t len);
+char* octescape_full(const char *s, size_t len, const char *bad);
+static inline char* octescape(const char *s, size_t len) {
+        return octescape_full(s, len, NULL);
+}
 char* decescape(const char *s, size_t len, const char *bad) _nonnull_if_nonzero_(1, 2);
 char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFlags flags);
 
index ff76c5e4d30e323a0eb9333297afc9b383447958..e14d2bb5f36cd5fd7aea4b22599b2754a3a6d459 100644 (file)
@@ -3033,6 +3033,8 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                         return log_oom();
         }
 
+        _cleanup_free_ char *fstab_extra = NULL;
+
         for (size_t j = 0; j < arg_runtime_mounts.n_mounts; j++) {
                 RuntimeMount *m = arg_runtime_mounts.mounts + j;
                 _cleanup_free_ char *listen_address = NULL;
@@ -3079,15 +3081,39 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                 if (r < 0)
                         return r;
 
-                _cleanup_free_ char *clean_target = xescape(m->target, "\":");
-                if (!clean_target)
+                /* fstab uses whitespace as field separator, so octal-escape spaces in paths */
+                _cleanup_free_ char *escaped_target = octescape_full(m->target, SIZE_MAX, " \t");
+                if (!escaped_target)
                         return log_oom();
 
-                if (strv_extendf(&arg_kernel_cmdline_extra, "systemd.mount-extra=\"%s:%s:virtiofs:%s\"",
-                                 id, clean_target, m->read_only ? "ro" : "rw") < 0)
+                if (strextendf(&fstab_extra, "%s %s virtiofs %s,x-initrd.mount\n",
+                               id, escaped_target, m->read_only ? "ro" : "rw") < 0)
                         return log_oom();
         }
 
+        if (fstab_extra) {
+                /* If the user already specified a fstab.extra credential, combine it with ours */
+                MachineCredential *existing = machine_credential_find(&arg_credentials, "fstab.extra");
+                if (existing) {
+                        _cleanup_free_ char *combined = NULL;
+
+                        if (existing->size > 0 && existing->data[existing->size - 1] != '\n')
+                                r = asprintf(&combined, "%.*s\n%s", (int) existing->size, existing->data, fstab_extra);
+                        else
+                                r = asprintf(&combined, "%.*s%s", (int) existing->size, existing->data, fstab_extra);
+                        if (r < 0)
+                                return log_oom();
+
+                        erase_and_free(existing->data);
+                        existing->data = TAKE_PTR(combined);
+                        existing->size = r;
+                } else {
+                        r = machine_credential_add(&arg_credentials, "fstab.extra", fstab_extra, SIZE_MAX);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
         _cleanup_(rm_rf_physical_and_freep) char *smbios_dir = NULL;
         r = mkdtemp_malloc("/var/tmp/vmspawn-smbios-XXXXXX", &smbios_dir);
         if (r < 0)