--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
'machine-credential.c',
'machine-id-setup.c',
'machine-register.c',
+ 'machine-util.c',
'macvlan-util.c',
'main-func.c',
'metrics.c',
#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);
/* 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;
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);
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;