From: Christian Brauner Date: Mon, 20 Apr 2026 07:28:54 +0000 (+0200) Subject: shared: extract disk-spec parsing into machine-util X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=258c66784527bdffc8df0a3ad8437926bda5894c;p=thirdparty%2Fsystemd.git shared: extract disk-spec parsing into machine-util Move the ImageFormat / DiskType enums and their string tables out of vmspawn's private settings header into a new src/shared/machine-util, and add parse_disk_spec() — the colon-prefix loop that turns "[FORMAT:][DISKTYPE:]PATH" into the two enums plus a normalized path. No behavior change for vmspawn. A follow-up machinectl attach-disk change accepts the same syntax and consumes the shared helper. Signed-off-by: Christian Brauner (Amutable) --- diff --git a/src/shared/machine-util.c b/src/shared/machine-util.c new file mode 100644 index 00000000000..fa5e46ace1e --- /dev/null +++ b/src/shared/machine-util.c @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "extract-word.h" +#include "machine-util.h" +#include "parse-argument.h" +#include "string-table.h" + +static const char *const image_format_table[_IMAGE_FORMAT_MAX] = { + [IMAGE_FORMAT_RAW] = "raw", + [IMAGE_FORMAT_QCOW2] = "qcow2", +}; + +DEFINE_STRING_TABLE_LOOKUP(image_format, ImageFormat); + +static const char *const disk_type_table[_DISK_TYPE_MAX] = { + [DISK_TYPE_VIRTIO_BLK] = "virtio-blk", + [DISK_TYPE_VIRTIO_SCSI] = "virtio-scsi", + [DISK_TYPE_NVME] = "nvme", + [DISK_TYPE_VIRTIO_SCSI_CDROM] = "scsi-cd", +}; + +DEFINE_STRING_TABLE_LOOKUP(disk_type, DiskType); + +/* Wire value for the io.systemd.VirtualMachineInstance.BlockDriver IDL enum. */ +static const char *const block_driver_table[_DISK_TYPE_MAX] = { + [DISK_TYPE_VIRTIO_BLK] = "virtio_blk", + [DISK_TYPE_VIRTIO_SCSI] = "scsi_hd", + [DISK_TYPE_NVME] = "nvme", + [DISK_TYPE_VIRTIO_SCSI_CDROM] = "scsi_cd", +}; + +DEFINE_STRING_TABLE_LOOKUP(block_driver, DiskType); + +/* QEMU -device driver name (e.g. "virtio-blk-pci"). */ +static const char *const qemu_device_driver_table[_DISK_TYPE_MAX] = { + [DISK_TYPE_VIRTIO_BLK] = "virtio-blk-pci", + [DISK_TYPE_VIRTIO_SCSI] = "scsi-hd", + [DISK_TYPE_NVME] = "nvme", + [DISK_TYPE_VIRTIO_SCSI_CDROM] = "scsi-cd", +}; + +DEFINE_STRING_TABLE_LOOKUP(qemu_device_driver, DiskType); + +int parse_disk_spec( + const char *arg, + ImageFormat *format, + DiskType *disk_type, + char **ret_path) { + + int r; + + assert(arg); + assert(format); + assert(disk_type); + assert(ret_path); + + ImageFormat parsed_format = *format; + DiskType parsed_disk_type = *disk_type; + const char *dp = arg; + + /* Format and disk-type vocabularies don't overlap, so prefixes may appear in any order. */ + for (;;) { + _cleanup_free_ char *word = NULL; + const char *save = dp; + + r = extract_first_word(&dp, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0 || !dp) { + /* No ':' remained after this word — rest is the path. */ + dp = save; + break; + } + + ImageFormat f = image_format_from_string(word); + if (f >= 0) { + parsed_format = f; + continue; + } + + DiskType dt = disk_type_from_string(word); + if (dt >= 0) { + parsed_disk_type = dt; + continue; + } + + /* Unknown prefix — rewind, remainder is the path. */ + dp = save; + break; + } + + _cleanup_free_ char *path = NULL; + r = parse_path_argument(dp, /* suppress_root= */ false, &path); + if (r < 0) + return r; + + *format = parsed_format; + *disk_type = parsed_disk_type; + *ret_path = TAKE_PTR(path); + return 0; +} diff --git a/src/shared/machine-util.h b/src/shared/machine-util.h new file mode 100644 index 00000000000..3937ce17037 --- /dev/null +++ b/src/shared/machine-util.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "shared-forward.h" + +typedef enum ImageFormat { + IMAGE_FORMAT_RAW, + IMAGE_FORMAT_QCOW2, + _IMAGE_FORMAT_MAX, + _IMAGE_FORMAT_INVALID = -EINVAL, +} ImageFormat; + +typedef enum DiskType { + DISK_TYPE_VIRTIO_BLK, + DISK_TYPE_VIRTIO_SCSI, + DISK_TYPE_NVME, + DISK_TYPE_VIRTIO_SCSI_CDROM, + _DISK_TYPE_MAX, + _DISK_TYPE_INVALID = -EINVAL, +} DiskType; + +DECLARE_STRING_TABLE_LOOKUP(image_format, ImageFormat); +DECLARE_STRING_TABLE_LOOKUP(disk_type, DiskType); +DECLARE_STRING_TABLE_LOOKUP(block_driver, DiskType); +DECLARE_STRING_TABLE_LOOKUP(qemu_device_driver, DiskType); + +/* Parse "[FORMAT:][DISKTYPE:]PATH"; *format and *disk_type are in-out. */ +int parse_disk_spec( + const char *arg, + ImageFormat *format, + DiskType *disk_type, + char **ret_path); diff --git a/src/shared/meson.build b/src/shared/meson.build index 741dbb60a45..56b823c50cd 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -133,6 +133,7 @@ shared_sources = files( 'machine-credential.c', 'machine-id-setup.c', 'machine-register.c', + 'machine-util.c', 'macvlan-util.c', 'main-func.c', 'metrics.c', diff --git a/src/vmspawn/vmspawn-settings.c b/src/vmspawn/vmspawn-settings.c index 9382172e2ca..502189e7bea 100644 --- a/src/vmspawn/vmspawn-settings.c +++ b/src/vmspawn/vmspawn-settings.c @@ -3,22 +3,6 @@ #include "string-table.h" #include "vmspawn-settings.h" -static const char *const image_format_table[_IMAGE_FORMAT_MAX] = { - [IMAGE_FORMAT_RAW] = "raw", - [IMAGE_FORMAT_QCOW2] = "qcow2", -}; - -DEFINE_STRING_TABLE_LOOKUP(image_format, ImageFormat); - -static const char *const disk_type_table[_DISK_TYPE_MAX] = { - [DISK_TYPE_VIRTIO_BLK] = "virtio-blk", - [DISK_TYPE_VIRTIO_SCSI] = "virtio-scsi", - [DISK_TYPE_NVME] = "nvme", - [DISK_TYPE_VIRTIO_SCSI_CDROM] = "scsi-cd", -}; - -DEFINE_STRING_TABLE_LOOKUP(disk_type, DiskType); - void extra_drive_context_done(ExtraDriveContext *ctx) { assert(ctx); diff --git a/src/vmspawn/vmspawn-settings.h b/src/vmspawn/vmspawn-settings.h index f02b499201e..596a66cecdd 100644 --- a/src/vmspawn/vmspawn-settings.h +++ b/src/vmspawn/vmspawn-settings.h @@ -1,24 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "machine-util.h" #include "shared-forward.h" -typedef enum ImageFormat { - IMAGE_FORMAT_RAW, - IMAGE_FORMAT_QCOW2, - _IMAGE_FORMAT_MAX, - _IMAGE_FORMAT_INVALID = -EINVAL, -} ImageFormat; - -typedef enum DiskType { - DISK_TYPE_VIRTIO_BLK, - DISK_TYPE_VIRTIO_SCSI, - DISK_TYPE_NVME, - DISK_TYPE_VIRTIO_SCSI_CDROM, - _DISK_TYPE_MAX, - _DISK_TYPE_INVALID = -EINVAL, -} DiskType; - typedef struct ExtraDrive { char *path; ImageFormat format; @@ -69,6 +54,4 @@ typedef enum SettingsMask { DECLARE_STRING_TABLE_LOOKUP(console_mode, ConsoleMode); DECLARE_STRING_TABLE_LOOKUP(console_transport, ConsoleTransport); -DECLARE_STRING_TABLE_LOOKUP(disk_type, DiskType); DECLARE_STRING_TABLE_LOOKUP(firmware, Firmware); -DECLARE_STRING_TABLE_LOOKUP(image_format, ImageFormat); diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index 01325bf9eb1..1b696f70144 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -752,39 +752,9 @@ static int parse_argv(int argc, char *argv[]) { OPTION_LONG("extra-drive", "[FORMAT:][DISKTYPE:]PATH", "Adds an additional disk to the VM"): { ImageFormat format = IMAGE_FORMAT_RAW; DiskType extra_disk_type = _DISK_TYPE_INVALID; - const char *dp = arg; - - /* Parse optional colon-separated prefixes. The format and disk type - * value sets don't overlap, so they can appear in any order. */ - for (;;) { - const char *colon = strchr(dp, ':'); - if (!colon) - break; - - _cleanup_free_ char *prefix = strndup(dp, colon - dp); - if (!prefix) - return log_oom(); - - ImageFormat f = image_format_from_string(prefix); - if (f >= 0) { - format = f; - dp = colon + 1; - continue; - } - - DiskType dt = disk_type_from_string(prefix); - if (dt >= 0) { - extra_disk_type = dt; - dp = colon + 1; - continue; - } - - /* Not a recognized prefix, treat the rest as the path */ - break; - } - _cleanup_free_ char *drive_path = NULL; - r = parse_path_argument(dp, /* suppress_root= */ false, &drive_path); + + r = parse_disk_spec(arg, &format, &extra_disk_type, &drive_path); if (r < 0) return r;