return (self.source, prefix / os.fspath(self.target).lstrip("/") if self.target else prefix)
+@dataclasses.dataclass(frozen=True)
+class QemuDrive:
+ id: str
+ size: int
+ directory: Optional[Path]
+ options: Optional[str]
+
+
class SecureBootSignTool(StrEnum):
auto = enum.auto()
sbsign = enum.auto()
return config_match_version(value, version)
-def config_parse_bytes(value: Optional[str], old: Optional[int] = None) -> Optional[int]:
- if not value:
- return None
-
+def parse_bytes(value: str) -> int:
if value.endswith("G"):
factor = 1024**3
elif value.endswith("M"):
return result
+def config_parse_bytes(value: Optional[str], old: Optional[int] = None) -> Optional[int]:
+ if not value:
+ return None
+
+ return parse_bytes(value)
+
+
def config_parse_profile(value: Optional[str], old: Optional[int] = None) -> Optional[str]:
if not value:
return None
return value
+def parse_drive(value: str) -> QemuDrive:
+ parts = value.split(":", maxsplit=3)
+ if not parts or not parts[0]:
+ die(f"No ID specified for drive '{value}'")
+
+ if len(parts) < 2:
+ die(f"Missing size in drive '{value}")
+
+ if len(parts) > 4:
+ die(f"Too many components in drive '{value}")
+
+ id = parts[0]
+ if not is_valid_filename(id):
+ die(f"Unsupported path character in drive id '{id}'")
+
+ size = parse_bytes(parts[1])
+
+ directory = parse_path(parts[2]) if len(parts) > 2 and parts[2] else None
+ options = parts[3] if len(parts) > 3 and parts[3] else None
+
+ return QemuDrive(id=id, size=size, directory=directory, options=options)
+
+
@dataclasses.dataclass(frozen=True)
class MkosiConfigSetting:
dest: str
qemu_cdrom: bool
qemu_firmware: QemuFirmware
qemu_kernel: Optional[Path]
+ qemu_drives: list[QemuDrive]
qemu_args: list[str]
image: Optional[str]
parse=config_make_path_parser(),
help="Specify the kernel to use for qemu direct kernel boot",
),
+ MkosiConfigSetting(
+ dest="qemu_drives",
+ long="--qemu-drive",
+ metavar="DRIVE",
+ section="Host",
+ parse=config_make_list_parser(delimiter=" ", parse=parse_drive),
+ help="Specify a qemu drive that mkosi should create and pass to qemu",
+ ),
MkosiConfigSetting(
dest="qemu_args",
metavar="ARGS",
def str_tuple_transformer(strtup: list[str], fieldtype: list[tuple[str, ...]]) -> tuple[str, ...]:
return tuple(strtup)
+ def config_drive_transformer(drives: list[dict[str, Any]], fieldtype: type[QemuDrive]) -> list[QemuDrive]:
+ # TODO: exchange for TypeGuard and list comprehension once on 3.10
+ ret = []
+ for d in drives:
+ assert "id" in d
+ assert "size" in d
+ assert "directory" in d
+ assert "options" in d
+ ret.append(
+ QemuDrive(
+ id=d["id"],
+ size=int(d["size"]),
+ directory=Path(d["directory"]) if d["directory"] else None,
+ options=d["options"],
+ )
+ )
+ return ret
+
transformers = {
Path: path_transformer,
Optional[Path]: optional_path_transformer,
list[ManifestFormat]: enum_list_transformer,
Verb: enum_transformer,
DocFormat: enum_transformer,
+ list[QemuDrive]: config_drive_transformer,
}
def json_transformer(key: str, val: Any) -> Any:
addr, notifications = stack.enter_context(vsock_notify_handler())
cmdline += ["-smbios", f"type=11,value=io.systemd.credential:vmm.notify_socket={addr}"]
+ for drive in config.qemu_drives:
+ file = stack.enter_context(
+ tempfile.NamedTemporaryFile(dir=drive.directory or "/var/tmp", prefix=f"mkosi-drive-{drive.id}")
+ )
+ file.truncate(drive.size)
+ os.chown(file.name, INVOKING_USER.uid, INVOKING_USER.gid)
+
+ arg = f"if=none,id={drive.id},file={file.name},format=raw"
+ if drive.options:
+ arg += f",{drive.options}"
+
+ cmdline += ["-drive", arg]
+
cmdline += config.qemu_args
cmdline += args.cmdline
configured firmware, qemu might boot the kernel itself or using the
configured firmware.
+`QemuDrives=`, `--qemu-drive=`
+
+: Add a qemu drive. Takes a colon-delimited string of format
+ `<id>:<size>[:<directory>[:<options>]]`. `id` specifies the qemu id we
+ assign to the drive. This can be used as the `drive=` property in
+ various qemu devices. `size` specifies the size of the drive. This
+ takes a size in bytes. Additionally, the suffixes `K`, `M` and `G` can
+ be used to specify a size in kilobytes, megabytes and gigabytes
+ respectively. `directory` optionally specifies the directory in which
+ to create the file backing the drive. `options` optionally specifies
+ extra comma-delimited properties which are passed verbatime to qemu's
+ `-drive` option.
+
`QemuArgs=`
: Space-delimited list of additional arguments to pass when invoking