From ccd776ea697fa4df83c29d693142ade1d5569088 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 6 Dec 2024 00:28:13 +0000 Subject: [PATCH] Add mkosi-addon and kernel-install plugin Change mkosi-initrd to avoid adding local customizations (crypttab, kmods, fw) to the UKI by default, with an --host-only override. Add new mkosi-addon and kernel-install plugin to build local customizations into an EFI addon instead. This allows us to move closer to the desired goal of having universal UKIs, built by vendors, used together with locally built enhancements. --- .gitignore | 1 + README.md | 15 +- bin/mkosi-addon | 1 + kernel-install/51-mkosi-addon.install | 111 +++++++++++++ mkosi-addon | 1 + mkosi/__init__.py | 83 ++++++++-- mkosi/addon.py | 212 +++++++++++++++++++++++++ mkosi/config.py | 5 +- mkosi/initrd.py | 23 ++- mkosi/resources/man/mkosi-addon.1.md | 49 ++++++ mkosi/resources/man/mkosi-initrd.1.md | 4 + mkosi/resources/man/mkosi.1.md | 2 +- mkosi/resources/mkosi-addon/mkosi.conf | 22 +++ pyproject.toml | 2 + 14 files changed, 503 insertions(+), 28 deletions(-) create mode 120000 bin/mkosi-addon create mode 100755 kernel-install/51-mkosi-addon.install create mode 120000 mkosi-addon create mode 100644 mkosi/addon.py create mode 100644 mkosi/resources/man/mkosi-addon.1.md create mode 100644 mkosi/resources/mkosi-addon/mkosi.conf 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..e463dc499 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,8 @@ 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 +2085,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 +2150,53 @@ 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 +2638,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 +2774,8 @@ 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 +2796,8 @@ 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 +2844,8 @@ 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 +2862,8 @@ 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 +2905,8 @@ 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 +2925,8 @@ 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 +3786,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 +3800,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 +3851,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 +4608,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..88a9d9844 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,8 @@ 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/**/*",