From d7e5da770e4aff1d21e0a400de1aba22774a0e64 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 11 Jan 2024 14:07:20 +0100 Subject: [PATCH] Use grub binaries from tools tree instead of from image Let's give this another try and use grub tools from the tools tree instead of from the image. We also hardcode the grub prefix per distribution because if we use grub binaries from the tools tree there might not be any installed in the image itself which means we can't derive the prefix from the binaries in the image. --- .github/workflows/ci.yml | 9 ++++ mkosi/__init__.py | 54 ++++++------------- mkosi/distributions/__init__.py | 7 +++ mkosi/distributions/centos.py | 4 ++ mkosi/distributions/fedora.py | 4 ++ mkosi/distributions/opensuse.py | 4 ++ .../mkosi-tools/mkosi.conf.d/10-arch.conf | 1 + .../mkosi.conf.d/10-centos-fedora/mkosi.conf | 1 + .../mkosi.conf.d/10-debian-ubuntu.conf | 1 + .../mkosi-tools/mkosi.conf.d/10-opensuse.conf | 1 + 10 files changed, 47 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a29e9571e..5b6aa6d43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -150,6 +150,15 @@ jobs: QemuKvm=no EOF + # Work around for https://src.fedoraproject.org/rpms/grub2/pull-request/61 by disabling obsoletes. + tee mkosi/resources/mkosi-tools/mkosi.local.conf < mkosi/resources/mkosi-tools/mkosi.pkgmngr/etc/dnf/dnf.conf + # TODO: Remove once all distros have recent enough systemd that knows systemd.default_device_timeout_sec. mkdir -p mkosi-initrd/mkosi.extra/usr/lib/systemd/system.conf.d tee mkosi-initrd/mkosi.extra/usr/lib/systemd/system.conf.d/device-timeout.conf < Optional[Path]: return None -def find_grub_binary(context: Context, binary: str) -> Optional[Path]: +def find_grub_binary(binary: str, root: Path = Path("/")) -> Optional[Path]: assert "grub" in binary and "grub2" not in binary - return find_binary(binary, root=context.root) or find_binary(binary.replace("grub", "grub2"), root=context.root) - - -def find_grub_prefix(context: Context) -> Optional[str]: - path = find_grub_binary(context, "grub-mkimage") - if path is None: - return None - - return "grub2" if "grub2" in os.fspath(path) else "grub" + return find_binary(binary, binary.replace("grub", "grub2"), root=root) def want_grub_efi(context: Context) -> bool: @@ -1089,8 +1081,7 @@ def want_grub_bios(context: Context, partitions: Sequence[Partition] = ()) -> bo installed = True for binary in ("grub-mkimage", "grub-bios-setup"): - path = find_grub_binary(context, binary) - if path is not None: + if find_grub_binary(binary, root=context.config.tools()): continue if context.config.bootable == ConfigFeature.enabled: @@ -1102,11 +1093,7 @@ def want_grub_bios(context: Context, partitions: Sequence[Partition] = ()) -> bo def prepare_grub_config(context: Context) -> Optional[Path]: - prefix = find_grub_prefix(context) - if not prefix: - return None - - config = context.root / "efi" / prefix / "grub.cfg" + config = context.root / "efi" / context.config.distribution.grub_prefix() / "grub.cfg" with umask(~0o700): config.parent.mkdir(exist_ok=True) @@ -1123,9 +1110,6 @@ def prepare_grub_efi(context: Context) -> None: if not want_grub_efi(context): return - prefix = find_grub_prefix(context) - assert prefix - # Signed EFI grub shipped by distributions reads its configuration from /EFI//grub.cfg in # the ESP so let's put a shim there to redirect to the actual configuration file. earlyconfig = context.root / "efi/EFI" / context.config.distribution.name / "grub.cfg" @@ -1133,7 +1117,7 @@ def prepare_grub_efi(context: Context) -> None: earlyconfig.parent.mkdir(parents=True, exist_ok=True) # Read the actual config file from the root of the ESP. - earlyconfig.write_text(f"configfile /{prefix}/grub.cfg\n") + earlyconfig.write_text(f"configfile /{context.config.distribution.grub_prefix()}/grub.cfg\n") config = prepare_grub_config(context) assert config @@ -1214,24 +1198,21 @@ def prepare_grub_bios(context: Context, partitions: Sequence[Partition]) -> None # so we're forced to reimplement its functionality. Luckily that's pretty simple, run grub-mkimage to # generate the required core.img and copy the relevant files to the ESP. - mkimage = find_grub_binary(context, "grub-mkimage") + mkimage = find_grub_binary("grub-mkimage", root=context.config.tools()) assert mkimage directory = find_grub_bios_directory(context) assert directory - prefix = find_grub_prefix(context) - assert prefix - - dst = context.root / "efi" / prefix / "i386-pc" + dst = context.root / "efi" / context.config.distribution.grub_prefix() / "i386-pc" dst.mkdir(parents=True, exist_ok=True) with tempfile.NamedTemporaryFile("w", prefix="grub-early-config") as earlyconfig: earlyconfig.write( textwrap.dedent( f"""\ - search --no-floppy --set=root --file /{prefix}/grub.cfg - set prefix=($root)/{prefix} + search --no-floppy --set=root --file /{context.config.distribution.grub_prefix()}/grub.cfg + set prefix=($root)/{context.config.distribution.grub_prefix()} """ ) ) @@ -1243,7 +1224,7 @@ def prepare_grub_bios(context: Context, partitions: Sequence[Partition]) -> None mkimage, "--directory", directory, "--config", earlyconfig.name, - "--prefix", f"/{prefix}", + "--prefix", f"/{context.config.distribution.grub_prefix()}", "--output", dst / "core.img", "--format", "i386-pc", *(["--verbose"] if ARG_DEBUG.get() else []), @@ -1256,7 +1237,6 @@ def prepare_grub_bios(context: Context, partitions: Sequence[Partition]) -> None ], sandbox=context.sandbox( options=[ - "--ro-bind", context.root / "usr", "/usr", "--bind", context.root, context.root, "--ro-bind", earlyconfig.name, earlyconfig.name, ], @@ -1272,12 +1252,12 @@ def prepare_grub_bios(context: Context, partitions: Sequence[Partition]) -> None shutil.copy2(directory / "modinfo.sh", dst) shutil.copy2(directory / "boot.img", dst) - dst = context.root / "efi" / prefix / "fonts" + dst = context.root / "efi" / context.config.distribution.grub_prefix() / "fonts" with umask(~0o700): dst.mkdir(exist_ok=True) - for prefix in ("grub", "grub2"): - unicode = context.root / "usr/share" / prefix / "unicode.pf2" + for d in ("grub", "grub2"): + unicode = context.root / "usr/share" / d / "unicode.pf2" if unicode.exists(): shutil.copy2(unicode, dst) @@ -1286,12 +1266,9 @@ def install_grub_bios(context: Context, partitions: Sequence[Partition]) -> None if not want_grub_bios(context, partitions): return - setup = find_grub_binary(context, "grub-bios-setup") + setup = find_grub_binary("grub-bios-setup", root=context.config.tools()) assert setup - prefix = find_grub_prefix(context) - assert prefix - with ( complete_step("Installing grub boot loader…"), tempfile.NamedTemporaryFile(mode="w") as mountinfo, @@ -1310,13 +1287,12 @@ def install_grub_bios(context: Context, partitions: Sequence[Partition]) -> None [ "sh", "-c", f"mount --bind {mountinfo.name} /proc/$$/mountinfo && exec $0 \"$@\"", setup, - "--directory", context.root / "efi" / prefix / "i386-pc", + "--directory", context.root / "efi" / context.config.distribution.grub_prefix() / "i386-pc", *(["--verbose"] if ARG_DEBUG.get() else []), context.staging / context.config.output_with_format, ], sandbox=context.sandbox( options=[ - "--bind", context.root / "usr", "/usr", "--bind", context.root, context.root, "--bind", context.staging, context.staging, "--bind", mountinfo.name, mountinfo.name, diff --git a/mkosi/distributions/__init__.py b/mkosi/distributions/__init__.py index 4c289d5d0..2c4374ae6 100644 --- a/mkosi/distributions/__init__.py +++ b/mkosi/distributions/__init__.py @@ -63,6 +63,10 @@ class DistributionInstaller: def default_tools_tree_distribution(cls) -> Optional["Distribution"]: return None + @classmethod + def grub_prefix(cls) -> str: + return "grub" + class Distribution(StrEnum): # Please consult docs/distribution-policy.md and contact one @@ -136,6 +140,9 @@ class Distribution(StrEnum): def default_tools_tree_distribution(self) -> Optional["Distribution"]: return self.installer().default_tools_tree_distribution() + def grub_prefix(self) -> str: + return self.installer().grub_prefix() + def installer(self) -> type[DistributionInstaller]: modname = str(self).replace('-', '_') mod = importlib.import_module(f"mkosi.distributions.{modname}") diff --git a/mkosi/distributions/centos.py b/mkosi/distributions/centos.py index 929146e6a..e01cfb9c1 100644 --- a/mkosi/distributions/centos.py +++ b/mkosi/distributions/centos.py @@ -54,6 +54,10 @@ class Installer(DistributionInstaller): def default_tools_tree_distribution(cls) -> Distribution: return Distribution.fedora + @classmethod + def grub_prefix(cls) -> str: + return "grub2" + @classmethod def setup(cls, context: Context) -> None: if GenericVersion(context.config.release) <= 7: diff --git a/mkosi/distributions/fedora.py b/mkosi/distributions/fedora.py index c62298d76..8484d1859 100644 --- a/mkosi/distributions/fedora.py +++ b/mkosi/distributions/fedora.py @@ -36,6 +36,10 @@ class Installer(DistributionInstaller): def default_tools_tree_distribution(cls) -> Distribution: return Distribution.fedora + @classmethod + def grub_prefix(cls) -> str: + return "grub2" + @classmethod def setup(cls, context: Context) -> None: gpgurls = ( diff --git a/mkosi/distributions/opensuse.py b/mkosi/distributions/opensuse.py index aba3ff934..8b5fbfae1 100644 --- a/mkosi/distributions/opensuse.py +++ b/mkosi/distributions/opensuse.py @@ -37,6 +37,10 @@ class Installer(DistributionInstaller): def default_tools_tree_distribution(cls) -> Distribution: return Distribution.opensuse + @classmethod + def grub_prefix(cls) -> str: + return "grub2" + @classmethod def setup(cls, context: Context) -> None: release = context.config.release diff --git a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-arch.conf b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-arch.conf index ddbd1ede3..6ebc654d4 100644 --- a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-arch.conf +++ b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-arch.conf @@ -13,6 +13,7 @@ Packages= debian-archive-keyring edk2-ovmf erofs-utils + grub openssh pacman pesign diff --git a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-centos-fedora/mkosi.conf b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-centos-fedora/mkosi.conf index 95a4512d6..c1d042270 100644 --- a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-centos-fedora/mkosi.conf +++ b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-centos-fedora/mkosi.conf @@ -14,6 +14,7 @@ Packages= debian-keyring distribution-gpg-keys dnf-plugins-core + grub2-tools openssh-clients policycoreutils python3-cryptography diff --git a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-debian-ubuntu.conf b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-debian-ubuntu.conf index d002d98a4..a506728fc 100644 --- a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-debian-ubuntu.conf +++ b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-debian-ubuntu.conf @@ -13,6 +13,7 @@ Packages= curl debian-archive-keyring erofs-utils + grub2 libtss2-dev makepkg openssh-client diff --git a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-opensuse.conf b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-opensuse.conf index 25971a0d1..ce4040b99 100644 --- a/mkosi/resources/mkosi-tools/mkosi.conf.d/10-opensuse.conf +++ b/mkosi/resources/mkosi-tools/mkosi.conf.d/10-opensuse.conf @@ -12,6 +12,7 @@ Packages= dnf-plugins-core erofs-utils grep + grub2 openssh-clients ovmf pesign -- 2.47.2