diff --git a/.gitignore b/.gitignore index b6e54df8a..eef237602 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.cache-pre-inst .cache .mkosi.1 +.mkosi-addon.1 .mkosi-initrd.1 .mkosi-sandbox.1 .mypy_cache/ diff --git a/README.md b/README.md index 1990dfdf3..fb8862517 100644 --- a/README.md +++ b/README.md @@ -80,15 +80,16 @@ mkosi binary and is not to be considered a public API. ## kernel-install plugin -mkosi can also be used as a kernel-install plugin to build initrds. To -enable this feature, install `kernel-install/50-mkosi.install` -into `/usr/lib/kernel/install.d`. Extra distro configuration for the -initrd can be configured in `/usr/lib/mkosi-initrd`. Users can add their -own customizations in `/etc/mkosi-initrd`. +mkosi can also be used as a kernel-install plugin to build initrds and addons. +To enable these features, install `kernel-install/50-mkosi.install` and +`kernel-install/51-mkosi-addon.install` into `/usr/lib/kernel/install.d`. +Extra distro configuration for the initrd can be configured in +`/usr/lib/mkosi-initrd`. Users can add their own customizations in +`/etc/mkosi-initrd` and `/etc/mkosi-addon`. Once installed, the mkosi plugin can be enabled by writing -`initrd_generator=mkosi-initrd` to `/usr/lib/kernel/install.conf` or to -`/etc/kernel/install.conf`. +`initrd_generator=mkosi-initrd` and `layout=uki` to `/usr/lib/kernel/install.conf` +or to `/etc/kernel/install.conf`. # Hacking on mkosi diff --git a/bin/mkosi-addon b/bin/mkosi-addon new file mode 120000 index 000000000..b5f44fa8e --- /dev/null +++ b/bin/mkosi-addon @@ -0,0 +1 @@ +mkosi \ No newline at end of file diff --git a/kernel-install/51-mkosi-addon.install b/kernel-install/51-mkosi-addon.install new file mode 100755 index 000000000..8a2036a5c --- /dev/null +++ b/kernel-install/51-mkosi-addon.install @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +import argparse +import dataclasses +import logging +import os +import sys +import tempfile +from pathlib import Path +from typing import Optional + +from mkosi import identify_cpu +from mkosi.archive import make_cpio +from mkosi.config import OutputFormat +from mkosi.log import die, log_setup +from mkosi.run import run, uncaught_exception_handler +from mkosi.sandbox import __version__, umask +from mkosi.types import PathString + + +@dataclasses.dataclass(frozen=True) +class Context: + command: str + kernel_version: str + entry_dir: Path + kernel_image: Path + staging_area: Path + layout: str + image_type: str + verbose: bool + + +def we_are_wanted(context: Context) -> bool: + return context.layout == "uki" + + +def mandatory_variable(name: str) -> str: + try: + return os.environ[name] + except KeyError: + die(f"${name} must be set in the environment") + + +@uncaught_exception_handler() +def main() -> None: + log_setup() + + parser = argparse.ArgumentParser( + description="kernel-install plugin to build local addon for initrd/cmdline/ucode", + allow_abbrev=False, + usage="51-mkosi-addon.install COMMAND KERNEL_VERSION ENTRY_DIR KERNEL_IMAGE…", + ) + + parser.add_argument( + "command", + metavar="COMMAND", + help="The action to perform. Only 'add' is supported.", + ) + parser.add_argument( + "kernel_version", + metavar="KERNEL_VERSION", + help="Kernel version string", + ) + parser.add_argument( + "entry_dir", + metavar="ENTRY_DIR", + type=Path, + nargs="?", + help="Type#1 entry directory (ignored)", + ) + parser.add_argument( + "kernel_image", + metavar="KERNEL_IMAGE", + type=Path, + nargs="?", + help="Kernel image", + ) + parser.add_argument( + "--version", + action="version", + version=f"mkosi {__version__}", + ) + + context = Context( + **vars(parser.parse_args()), + staging_area=Path(mandatory_variable("KERNEL_INSTALL_STAGING_AREA")), + layout=mandatory_variable("KERNEL_INSTALL_LAYOUT"), + image_type=mandatory_variable("KERNEL_INSTALL_IMAGE_TYPE"), + verbose=int(os.getenv("KERNEL_INSTALL_VERBOSE", 0)) > 0, + ) + + if context.command != "add" or not context.layout == "uki": + return + + cmdline: list[PathString] = [ + "mkosi-addon", + "--output", "mkosi-local.addon.efi", + "--output-dir", context.staging_area / "uki.efi.extra.d", + ] # fmt: skip + + if context.verbose: + cmdline += ["--debug"] + + logging.info(f"Building mkosi-local.addon.efi") + + run(cmdline, stdin=sys.stdin, stdout=sys.stdout) + + +if __name__ == "__main__": + main() diff --git a/mkosi-addon b/mkosi-addon new file mode 120000 index 000000000..c8442ca02 --- /dev/null +++ b/mkosi-addon @@ -0,0 +1 @@ +mkosi/resources/mkosi-addon \ No newline at end of file diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 4e4f3aff0..8771282e5 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -194,7 +194,7 @@ def remove_files(context: Context) -> None: def install_distribution(context: Context) -> None: - if context.config.base_trees: + if context.config.base_trees or context.config.output_format == OutputFormat.addon: if not context.config.packages: return @@ -288,7 +288,7 @@ def remove_packages(context: Context) -> None: def check_root_populated(context: Context) -> None: - if context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.output_format in (OutputFormat.sysext, OutputFormat.confext, OutputFormat.addon): return """Check that the root was populated by looking for a os-release file.""" @@ -308,7 +308,11 @@ def configure_os_release(context: Context) -> None: if not (context.config.image_id or context.config.image_version or context.config.hostname): return - if context.config.overlay or context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.overlay or context.config.output_format in ( + OutputFormat.sysext, + OutputFormat.confext, + OutputFormat.addon, + ): return for candidate in ["usr/lib/os-release", "usr/lib/initrd-release", "etc/os-release"]: @@ -2084,7 +2088,7 @@ def install_kernel(context: Context, partitions: Sequence[Partition]) -> None: # single-file images have the benefit that they can be signed like normal EFI binaries, and can # encode everything necessary to boot a specific root device, including the root hash. - if context.config.output_format in (OutputFormat.uki, OutputFormat.esp): + if context.config.output_format in (OutputFormat.uki, OutputFormat.esp, OutputFormat.addon): return if context.config.bootable == ConfigFeature.disabled: @@ -2149,6 +2153,51 @@ def make_uki( extract_pe_section(context, output, ".initrd", context.staging / context.config.output_split_initrd) +def make_addon(context: Context, microcodes: list[Path], output: Path) -> None: + make_cpio(context.root, context.workspace / "initrd", sandbox=context.sandbox) + maybe_compress( + context, context.config.compress_output, context.workspace / "initrd", context.workspace / "initrd" + ) + + arch = context.config.architecture.to_efi() + stub = Path(f"/usr/lib/systemd/boot/efi/addon{arch}.efi.stub") + if not stub.exists(): + die("sd-stub not found") + + arguments: list[PathString] = [ + "--initrd", + workdir(context.workspace / "initrd"), + ] + options: list[PathString] = [ + "--ro-bind", + context.workspace / "initrd", + workdir(context.workspace / "initrd"), + ] + + if microcodes: + # new .ucode section support? + check_ukify( + context.config, + version="256~devel", + reason="build addon with .ucode section support", + hint=("Use ToolsTree=default to download most required tools including ukify " "automatically"), + ) + + for microcode in microcodes: + arguments += ["--microcode", workdir(microcode)] + options += ["--ro-bind", microcode, workdir(microcode)] + + with complete_step(f"Generating PE addon {output}"): + run_ukify( + context, + stub, + output, + cmdline=context.config.kernel_command_line, + arguments=arguments, + options=options, + ) + + def compressor_command(context: Context, compression: Compression) -> list[PathString]: """Returns a command suitable for compressing archives.""" @@ -2590,7 +2639,7 @@ def check_tools(config: Config, verb: Verb) -> None: check_tool(config, "depmod", reason="generate kernel module dependencies") if want_efi(config): - if config.unified_kernel_image_profiles: + if config.unified_kernel_image_profiles or config.output_format == OutputFormat.addon: check_ukify( config, version="257~devel", @@ -2726,7 +2775,11 @@ def configure_ssh(context: Context) -> None: def configure_initrd(context: Context) -> None: - if context.config.overlay or context.config.output_format.is_extension_image(): + if ( + context.config.overlay + or context.config.output_format.is_extension_image() + or context.config.output_format == OutputFormat.addon + ): return if ( @@ -2747,7 +2800,11 @@ def configure_initrd(context: Context) -> None: def configure_clock(context: Context) -> None: - if context.config.overlay or context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.overlay or context.config.output_format in ( + OutputFormat.sysext, + OutputFormat.confext, + OutputFormat.addon, + ): return with umask(~0o644): @@ -2794,7 +2851,11 @@ def run_depmod(context: Context, *, cache: bool = False) -> None: def run_sysusers(context: Context) -> None: - if context.config.overlay or context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.overlay or context.config.output_format in ( + OutputFormat.sysext, + OutputFormat.confext, + OutputFormat.addon, + ): return if not context.config.find_binary("systemd-sysusers"): @@ -2811,7 +2872,11 @@ def run_sysusers(context: Context) -> None: def run_tmpfiles(context: Context) -> None: - if context.config.overlay or context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.overlay or context.config.output_format in ( + OutputFormat.sysext, + OutputFormat.confext, + OutputFormat.addon, + ): return if not context.config.find_binary("systemd-tmpfiles"): @@ -2853,7 +2918,11 @@ def run_tmpfiles(context: Context) -> None: def run_preset(context: Context) -> None: - if context.config.overlay or context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.overlay or context.config.output_format in ( + OutputFormat.sysext, + OutputFormat.confext, + OutputFormat.addon, + ): return if not context.config.find_binary("systemctl"): @@ -2872,7 +2941,11 @@ def run_preset(context: Context) -> None: def run_hwdb(context: Context) -> None: - if context.config.overlay or context.config.output_format in (OutputFormat.sysext, OutputFormat.confext): + if context.config.overlay or context.config.output_format in ( + OutputFormat.sysext, + OutputFormat.confext, + OutputFormat.addon, + ): return if not context.config.find_binary("systemd-hwdb"): @@ -3732,6 +3805,8 @@ def build_image(context: Context) -> None: ) elif context.config.output_format == OutputFormat.cpio: make_cpio(context.root, context.staging / context.config.output_with_format, sandbox=context.sandbox) + elif context.config.output_format == OutputFormat.addon: + make_addon(context, microcode, context.staging / context.config.output_with_format) elif context.config.output_format == OutputFormat.uki: assert stub and kver and kimg make_uki(context, stub, kver, kimg, microcode, context.staging / context.config.output_with_format) @@ -3744,7 +3819,7 @@ def build_image(context: Context) -> None: elif context.config.output_format == OutputFormat.directory: context.root.rename(context.staging / context.config.output_with_format) - if context.config.output_format not in (OutputFormat.uki, OutputFormat.esp): + if context.config.output_format not in (OutputFormat.uki, OutputFormat.esp, OutputFormat.addon): maybe_compress( context, context.config.compress_output, @@ -3795,7 +3870,7 @@ def run_sandbox(args: Args, config: Config) -> None: def run_shell(args: Args, config: Config) -> None: opname = "acquire shell in" if args.verb == Verb.shell else "boot" - if config.output_format in (OutputFormat.tar, OutputFormat.cpio): + if config.output_format in (OutputFormat.tar, OutputFormat.cpio, OutputFormat.addon): die(f"Sorry, can't {opname} a {config.output_format} archive.") if config.output_format.use_outer_compression() and config.compress_output: die(f"Sorry, can't {opname} a compressed image.") @@ -4552,6 +4627,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None: if args.verb == Verb.documentation: if args.cmdline: manual = { + "addon": "mkosi-addon", "initrd": "mkosi-initrd", "sandbox": "mkosi-sandbox", "news": "mkosi.news", diff --git a/mkosi/addon.py b/mkosi/addon.py new file mode 100644 index 000000000..43371aabd --- /dev/null +++ b/mkosi/addon.py @@ -0,0 +1,212 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +import argparse +import contextlib +import os +import platform +import shutil +import sys +import tempfile +from pathlib import Path +from typing import cast + +import mkosi.resources +from mkosi.config import DocFormat, OutputFormat +from mkosi.documentation import show_docs +from mkosi.log import log_notice, log_setup +from mkosi.run import find_binary, run, uncaught_exception_handler +from mkosi.sandbox import __version__, umask +from mkosi.tree import copy_tree +from mkosi.types import PathString +from mkosi.util import resource_path + + +@uncaught_exception_handler() +def main() -> None: + log_setup() + + parser = argparse.ArgumentParser( + prog="mkosi-addon", + description="Build initrd/cmdline/ucode addon for the current system using mkosi", + allow_abbrev=False, + usage="mkosi-addon [options...]", + ) + + parser.add_argument( + "--kernel-version", + metavar="KERNEL_VERSION", + help="Kernel version string", + default=platform.uname().release, + ) + parser.add_argument( + "-o", + "--output", + metavar="NAME", + help="Output name", + default="mkosi-local.addon.efi", + ) + parser.add_argument( + "-O", + "--output-dir", + metavar="DIR", + help="Output directory", + default="", + ) + parser.add_argument( + "--debug", + help="Turn on debugging output", + action="store_true", + default=False, + ) + parser.add_argument( + "--debug-shell", + help="Spawn debug shell if a sandboxed command fails", + action="store_true", + default=False, + ) + parser.add_argument( + "-D", + "--show-documentation", + help="Show the man page", + action="store_true", + default=False, + ) + parser.add_argument( + "--version", + action="version", + version=f"mkosi {__version__}", + ) + + args = parser.parse_args() + + if args.show_documentation: + with resource_path(mkosi.resources) as r: + show_docs("mkosi-addon", DocFormat.all(), resources=r) + return + + with ( + tempfile.TemporaryDirectory() as staging_dir, + tempfile.TemporaryDirectory() as sandbox_tree, + ): + cmdline: list[PathString] = [ + "mkosi", + "--force", + "--directory", "", + f"--format={str(OutputFormat.addon)}", + "--output", args.output, + "--output-directory", staging_dir, + "--build-sources", "", + "--include=mkosi-addon", + ] # fmt: skip + + cmdline += [ + "--extra-tree", f"/usr/lib/modules/{args.kernel_version}:/usr/lib/modules/{args.kernel_version}", + "--extra-tree=/usr/lib/firmware:/usr/lib/firmware", + "--remove-files=/usr/lib/firmware/*-ucode", + "--kernel-modules-exclude=.*", + "--kernel-modules-include=host", + ] # fmt: skip + + if args.debug: + cmdline += ["--debug"] + if args.debug_shell: + cmdline += ["--debug-shell"] + + if os.getuid() == 0: + cmdline += [ + "--workspace-dir=/var/tmp", + "--package-cache-dir=/var", + "--cache-only=metadata", + "--output-mode=600", + ] + + for d in ( + "/usr/lib/mkosi-addon", + "/usr/local/lib/mkosi-addon", + "/run/mkosi-addon", + "/etc/mkosi-addon", + ): + if Path(d).exists(): + cmdline += ["--include", d] + + # Make sure we don't use any of mkosi's default repositories. + for p in ( + "yum.repos.d/mkosi.repo", + "apt/sources.list.d/mkosi.sources", + "zypp/repos.d/mkosi.repo", + "pacman.conf", + ): + (Path(sandbox_tree) / "etc" / p).parent.mkdir(parents=True, exist_ok=True) + (Path(sandbox_tree) / "etc" / p).touch() + + # Copy in the host's package manager configuration. + for p in ( + "dnf", + "yum.repos.d/", + "apt", + "zypp", + "pacman.conf", + "pacman.d/", + ): + if not (Path("/etc") / p).exists(): + continue + + (Path(sandbox_tree) / "etc" / p).parent.mkdir(parents=True, exist_ok=True) + if (Path("/etc") / p).resolve().is_file(): + shutil.copy2(Path("/etc") / p, Path(sandbox_tree) / "etc" / p) + else: + shutil.copytree( + Path("/etc") / p, + Path(sandbox_tree) / "etc" / p, + ignore=shutil.ignore_patterns("gnupg"), + dirs_exist_ok=True, + ) + + cmdline += ["--sandbox-tree", sandbox_tree] + + # Generate crypttab with all the x-initrd.attach entries + if Path("/etc/crypttab").exists(): + crypttab = [ + line + for line in Path("/etc/crypttab").read_text().splitlines() + if ( + len(entry := line.split()) >= 4 + and not entry[0].startswith("#") + and "x-initrd.attach" in entry[3] + ) + ] + print(crypttab) + if crypttab: + with (Path(staging_dir) / "crypttab").open("w") as f: + f.write("# Automatically generated by mkosi-addon\n") + f.write("\n".join(crypttab)) + cmdline += ["--extra-tree", f"{staging_dir}/crypttab:/etc/crypttab"] + + if Path("/etc/kernel/cmdline").exists(): + cmdline += ["--kernel-command-line", Path("/etc/kernel/cmdline").read_text()] + + # Prefer dnf as dnf5 has not yet officially replaced it and there's a much bigger chance that there + # will be a populated dnf cache directory. + run( + cmdline, + stdin=sys.stdin, + stdout=sys.stdout, + env={"MKOSI_DNF": dnf.name} if (dnf := find_binary("dnf", "dnf5")) else {}, + ) + + if args.output_dir: + with umask(~0o700) if os.getuid() == 0 else cast(umask, contextlib.nullcontext()): + Path(args.output_dir).mkdir(parents=True, exist_ok=True) + else: + args.output_dir = Path.cwd() + + log_notice(f"Copying {staging_dir}/{args.output} to {args.output_dir}/{args.output}") + # mkosi symlinks the expected output image, so dereference it + copy_tree( + Path(f"{staging_dir}/{args.output}").resolve(), + Path(f"{args.output_dir}/{args.output}"), + ) + + +if __name__ == "__main__": + main() diff --git a/mkosi/config.py b/mkosi/config.py index e1aaf05ef..da77c508e 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -178,6 +178,7 @@ class SecureBootSignTool(StrEnum): class OutputFormat(StrEnum): + addon = enum.auto() confext = enum.auto() cpio = enum.auto() directory = enum.auto() @@ -192,6 +193,7 @@ class OutputFormat(StrEnum): def extension(self) -> str: return { + OutputFormat.addon: ".addon.efi", OutputFormat.confext: ".raw", OutputFormat.cpio: ".cpio", OutputFormat.disk: ".raw", @@ -809,7 +811,13 @@ def config_parse_mode(value: Optional[str], old: Optional[int]) -> Optional[int] def config_default_compression(namespace: argparse.Namespace) -> Compression: - if namespace.output_format in (OutputFormat.tar, OutputFormat.cpio, OutputFormat.uki, OutputFormat.esp): + if namespace.output_format in ( + OutputFormat.tar, + OutputFormat.cpio, + OutputFormat.uki, + OutputFormat.esp, + OutputFormat.addon, + ): if namespace.distribution == Distribution.ubuntu and namespace.release == "focal": return Compression.xz else: diff --git a/mkosi/initrd.py b/mkosi/initrd.py index 951768c3e..14efd01ab 100644 --- a/mkosi/initrd.py +++ b/mkosi/initrd.py @@ -51,6 +51,12 @@ def main() -> None: help="Output format (CPIO archive, UKI or local directory)", default="cpio", ) + parser.add_argument( + "--host-only", + help="Enable customizations for the host system", + action="store_true", + default=False, + ) parser.add_argument( "-o", "--output", @@ -108,15 +114,20 @@ def main() -> None: "--format", args.format, "--output", args.output, "--output-directory", staging_dir, - "--extra-tree", f"/usr/lib/modules/{args.kernel_version}:/usr/lib/modules/{args.kernel_version}", - "--extra-tree=/usr/lib/firmware:/usr/lib/firmware", - "--remove-files=/usr/lib/firmware/*-ucode", - "--kernel-modules-exclude=.*", - "--kernel-modules-include=host", "--build-sources", "", "--include=mkosi-initrd", ] # fmt: skip + if args.host_only: + cmdline += [ + "--extra-tree", + f"/usr/lib/modules/{args.kernel_version}:/usr/lib/modules/{args.kernel_version}", + "--extra-tree=/usr/lib/firmware:/usr/lib/firmware", + "--remove-files=/usr/lib/firmware/*-ucode", + "--kernel-modules-exclude=.*", + "--kernel-modules-include=host", + ] # fmt: skip + if args.kernel_image: cmdline += [ "--extra-tree", f"{args.kernel_image}:/usr/lib/modules/{args.kernel_version}/vmlinuz", @@ -181,7 +192,7 @@ def main() -> None: cmdline += ["--sandbox-tree", sandbox_tree] # Generate crypttab with all the x-initrd.attach entries - if Path("/etc/crypttab").exists(): + if args.host_only and Path("/etc/crypttab").exists(): crypttab = [ line for line in Path("/etc/crypttab").read_text().splitlines() diff --git a/mkosi/resources/man/mkosi-addon.1.md b/mkosi/resources/man/mkosi-addon.1.md new file mode 100644 index 000000000..891ab5b73 --- /dev/null +++ b/mkosi/resources/man/mkosi-addon.1.md @@ -0,0 +1,49 @@ +% mkosi-addon(1) +% +% + +# NAME + +mkosi-addon — Build addons for unified kernel images for the current system +using mkosi + +# SYNOPSIS + +`mkosi-addon [options…]` + +# DESCRIPTION + +`mkosi-addon` is wrapper on top of `mkosi` to simplify the generation of +addons containing customizations for a Unified Kernel Images specific for the +current running system. Will include entries in `/etc/crypttab` marked with +`x-initrd.attach`, `/etc/kernel/cmdline`, kernel modules, firmwares and microcode +for the running hardware. + +# OPTIONS + +`--kernel-version=` +: Kernel version where to look for the kernel modules to include. Defaults to + the kernel version of the running system (`uname -r`). + +`--output=`, `-o` +: Name to use for the generated output addon. Defaults to + `mkosi-local.addon.efi`. + +`--output-dir=`, `-O` +: Path to a directory where to place all generated artifacts. Defaults to the + current working directory. + +`--debug=` +: Enable additional debugging output. + +`--debug-shell=` +: Spawn debug shell in sandbox if a sandboxed command fails. + +`--version` +: Show package version. + +`--help`, `-h` +: Show brief usage information. + +# SEE ALSO +`mkosi(1)` diff --git a/mkosi/resources/man/mkosi-initrd.1.md b/mkosi/resources/man/mkosi-initrd.1.md index d7322b87e..44cf96f35 100644 --- a/mkosi/resources/man/mkosi-initrd.1.md +++ b/mkosi/resources/man/mkosi-initrd.1.md @@ -35,6 +35,10 @@ initrds and Unified Kernel Images for the current running system. : Path to a directory where to place all generated artifacts. Defaults to the current working directory. +`--host-only` +: Embed artifacts specific to the host where the build is being performed. + Kernel modules, firmware and /etc/crypttab will be included in the UKI. + `--debug=` : Enable additional debugging output. diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index d2ff8a9b0..535011ff1 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -565,7 +565,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, compression means the image cannot be started directly but needs to be decompressed first. This also means that the `shell`, `boot`, `qemu` verbs are not available when this option is used. Implied for `tar`, `cpio`, `uki`, - `esp`, and `oci`. + `esp`, `oci`, and `addon`. `CompressLevel=`, `--compress-level=` : Configure the compression level to use. Takes an integer. The possible diff --git a/mkosi/resources/mkosi-addon/mkosi.conf b/mkosi/resources/mkosi-addon/mkosi.conf new file mode 100644 index 000000000..00a1cb717 --- /dev/null +++ b/mkosi/resources/mkosi-addon/mkosi.conf @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[Distribution] +Distribution=custom + +[Output] +Output=initrd.addon +Format=addon +ManifestFormat= +SplitArtifacts= + +[Content] +Bootable=no +MakeInitrd=yes +CleanPackageMetadata=yes + +RemoveFiles= + # Including kernel images in the initrd is generally not useful. + # This also stops mkosi from extracting the kernel image out of the image as a separate output. + /usr/lib/modules/*/vmlinuz* + /usr/lib/modules/*/vmlinux* + /usr/lib/modules/*/System.map diff --git a/pyproject.toml b/pyproject.toml index 7426a7a78..0011fb89f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ bootable = [ mkosi = "mkosi.__main__:main" mkosi-initrd = "mkosi.initrd:main" mkosi-sandbox = "mkosi.sandbox:main" +mkosi-addon = "mkosi.addon:main" [tool.setuptools] packages = [ @@ -35,6 +36,7 @@ packages = [ "mkosi.resources" = [ "completion.*", "man/*", + "mkosi-addon/**/*", "mkosi-initrd/**/*", "mkosi-tools/**/*", "mkosi-vm/**/*",