From: Daan De Meyer Date: Tue, 16 Jan 2024 13:21:52 +0000 (+0100) Subject: Make archive.py independent of Context X-Git-Tag: v20.2~15^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7dd4fc3ddbbdf3d98543beebdec6eaee9849005c;p=thirdparty%2Fmkosi.git Make archive.py independent of Context Let's make these functions slightly more generic by passing in a tools directory and a sandbox instead of the full Context object. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index f00bc8e30..4264fef7e 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -109,7 +109,11 @@ def mount_base_trees(context: Context) -> Iterator[None]: if path.is_dir(): bases += [path] elif path.suffix == ".tar": - extract_tar(context, path, d) + extract_tar( + path, d, + tools=context.config.tools(), + sandbox=context.sandbox(options=["--bind", d, d]), + ) bases += [d] elif path.suffix == ".raw": run(["systemd-dissect", "-M", path, d]) @@ -1344,7 +1348,12 @@ def install_tree( if src.is_dir() or (src.is_file() and target): copy() elif src.suffix == ".tar": - extract_tar(context, src, t) + extract_tar( + src, t, + tools=context.config.tools(), + # Make sure tar uses user/group information from the root directory instead of the host. + sandbox=context.sandbox(options=["--bind", dst, dst, *finalize_passwd_mounts(dst)]), + ) elif src.suffix == ".raw": run( ["systemd-dissect", "--copy-from", src, "/", t], @@ -1558,7 +1567,11 @@ def build_microcode_initrd(context: Context) -> Optional[Path]: for p in intel.iterdir(): f.write(p.read_bytes()) - make_cpio(context, root, microcode) + make_cpio( + root, microcode, + tools=context.config.tools(), + sandbox=context.sandbox(options=["--ro-bind", root, root]), + ) return microcode @@ -1569,14 +1582,16 @@ def build_kernel_modules_initrd(context: Context, kver: str) -> Path: return kmods make_cpio( - context, context.root, kmods, - gen_required_kernel_modules( + context.root, kmods, + files=gen_required_kernel_modules( context.root, kver, include=context.config.kernel_modules_initrd_include, exclude=context.config.kernel_modules_initrd_exclude, host=context.config.kernel_modules_initrd_include_host, sandbox=context.sandbox(options=["--ro-bind", context.root, context.root]), - ) + ), + tools=context.config.tools(), + sandbox=context.sandbox(options=["--ro-bind", context.root, context.root]), ) # Debian/Ubuntu do not compress their kernel modules, so we compress the initramfs instead. Note that @@ -1863,7 +1878,14 @@ def install_uki(context: Context, partitions: Sequence[Partition]) -> None: def make_uki(context: Context, stub: Path, kver: str, kimg: Path, output: Path) -> None: microcode = build_microcode_initrd(context) - make_cpio(context, context.root, context.workspace / "initrd") + make_cpio( + context.root, context.workspace / "initrd", + tools=context.config.tools(), + sandbox=context.sandbox( + # Make sure cpio uses user/group information from the root directory instead of the host. + options=["--ro-bind", context.root, context.root, *finalize_passwd_mounts(context.root)], + ), + ) maybe_compress(context, context.config.compress_output, context.workspace / "initrd", context.workspace / "initrd") initrds = [microcode] if microcode else [] @@ -2901,9 +2923,23 @@ def build_image(args: Args, config: Config) -> None: copy_initrd(context) if context.config.output_format == OutputFormat.tar: - make_tar(context, context.root, context.staging / context.config.output_with_format) + make_tar( + context.root, context.staging / context.config.output_with_format, + tools=context.config.tools(), + # Make sure tar uses user/group information from the root directory instead of the host. + sandbox=context.sandbox( + options=["--ro-bind", context.root, context.root, *finalize_passwd_mounts(context.root)], + ), + ) elif context.config.output_format == OutputFormat.cpio: - make_cpio(context, context.root, context.staging / context.config.output_with_format) + make_cpio( + context.root, context.staging / context.config.output_with_format, + tools=context.config.tools(), + # Make sure cpio uses user/group information from the root directory instead of the host. + sandbox=context.sandbox( + options=["--ro-bind", context.root, context.root, *finalize_passwd_mounts(context.root)], + ), + ) elif context.config.output_format == OutputFormat.uki: assert stub and kver and kimg make_uki(context, stub, kver, kimg, context.staging / context.config.output_with_format) diff --git a/mkosi/archive.py b/mkosi/archive.py index 4d420a850..a681d5a12 100644 --- a/mkosi/archive.py +++ b/mkosi/archive.py @@ -1,17 +1,16 @@ # SPDX-License-Identifier: LGPL-2.1+ import os -from collections.abc import Iterable +from collections.abc import Iterable, Sequence from pathlib import Path from typing import Optional -from mkosi.context import Context from mkosi.log import log_step from mkosi.run import find_binary, run -from mkosi.sandbox import finalize_passwd_mounts +from mkosi.types import PathString -def tar_binary(context: Context) -> str: +def tar_binary(*, tools: Path = Path("/")) -> str: # Some distros (Mandriva) install BSD tar as "tar", hence prefer # "gtar" if it exists, which should be GNU tar wherever it exists. # We are interested in exposing same behaviour everywhere hence @@ -19,11 +18,11 @@ def tar_binary(context: Context) -> str: # everywhere. In particular given the limited/different SELinux # support in BSD tar and the different command line syntax # compared to GNU tar. - return "gtar" if find_binary("gtar", root=context.config.tools()) else "tar" + return "gtar" if find_binary("gtar", root=tools) else "tar" -def cpio_binary(context: Context) -> str: - return "gcpio" if find_binary("gcpio", root=context.config.tools()) else "cpio" +def cpio_binary(*, tools: Path = Path("/")) -> str: + return "gcpio" if find_binary("gcpio", root=tools) else "cpio" def tar_exclude_apivfs_tmp() -> list[str]: @@ -37,13 +36,13 @@ def tar_exclude_apivfs_tmp() -> list[str]: ] -def make_tar(context: Context, src: Path, dst: Path) -> None: +def make_tar(src: Path, dst: Path, *, tools: Path = Path("/"), sandbox: Sequence[PathString] = ()) -> None: log_step(f"Creating tar archive {dst}…") with dst.open("wb") as f: run( [ - tar_binary(context), + tar_binary(tools=tools), "--create", "--file", "-", "--directory", src, @@ -60,19 +59,25 @@ def make_tar(context: Context, src: Path, dst: Path) -> None: ".", ], stdout=f, - # Make sure tar uses user/group information from the root directory instead of the host. - sandbox=context.sandbox(options=["--ro-bind", src, src, *finalize_passwd_mounts(src)]), + sandbox=sandbox, ) -def extract_tar(context: Context, src: Path, dst: Path, log: bool = True) -> None: +def extract_tar( + src: Path, + dst: Path, + *, + log: bool = True, + tools: Path = Path("/"), + sandbox: Sequence[PathString] = (), +) -> None: if log: log_step(f"Extracting tar archive {src}…") with src.open("rb") as f: run( [ - tar_binary(context), + tar_binary(tools=tools), "--extract", "--file", "-", "--directory", dst, @@ -88,12 +93,18 @@ def extract_tar(context: Context, src: Path, dst: Path, log: bool = True) -> Non *tar_exclude_apivfs_tmp(), ], stdin=f, - # Make sure tar uses user/group information from the root directory instead of the host. - sandbox=context.sandbox(options=["--bind", dst, dst, *finalize_passwd_mounts(dst)]), + sandbox=sandbox, ) -def make_cpio(context: Context, src: Path, dst: Path, files: Optional[Iterable[Path]] = None) -> None: +def make_cpio( + src: Path, + dst: Path, + *, + files: Optional[Iterable[Path]] = None, + tools: Path = Path("/"), + sandbox: Sequence[PathString] = (), +) -> None: if not files: files = src.rglob("*") files = sorted(files) @@ -103,7 +114,7 @@ def make_cpio(context: Context, src: Path, dst: Path, files: Optional[Iterable[P with dst.open("wb") as f: run( [ - cpio_binary(context), + cpio_binary(tools=tools), "--create", "--reproducible", "--null", @@ -114,5 +125,5 @@ def make_cpio(context: Context, src: Path, dst: Path, files: Optional[Iterable[P input="\0".join(os.fspath(f.relative_to(src)) for f in files), stdout=f, # Make sure cpio uses user/group information from the root directory instead of the host. - sandbox=context.sandbox(options=["--ro-bind", src, src, *finalize_passwd_mounts(dst)]), + sandbox=sandbox, ) diff --git a/mkosi/distributions/debian.py b/mkosi/distributions/debian.py index 43314825f..1001eb8d6 100644 --- a/mkosi/distributions/debian.py +++ b/mkosi/distributions/debian.py @@ -12,6 +12,7 @@ from mkosi.distributions import Distribution, DistributionInstaller, PackageType from mkosi.installer.apt import createrepo_apt, invoke_apt, setup_apt from mkosi.log import die from mkosi.run import run +from mkosi.sandbox import finalize_passwd_mounts from mkosi.util import umask @@ -147,7 +148,15 @@ class Installer(DistributionInstaller): tempfile.NamedTemporaryFile() as o ): run(["dpkg-deb", "--fsys-tarfile", "/dev/stdin"], stdin=i, stdout=o, sandbox=context.sandbox()) - extract_tar(context, Path(o.name), context.root, log=False) + extract_tar( + Path(o.name), context.root, + log=False, + tools=context.config.tools(), + # Make sure tar uses user/group information from the root directory instead of the host. + sandbox=context.sandbox( + options=["--bind", context.root, context.root, *finalize_passwd_mounts(context.root)], + ), + ) # Finally, run apt to properly install packages in the chroot without having to worry that maintainer # scripts won't find basic tools that they depend on. diff --git a/mkosi/distributions/gentoo.py b/mkosi/distributions/gentoo.py index e6dfe95bc..eca50d159 100644 --- a/mkosi/distributions/gentoo.py +++ b/mkosi/distributions/gentoo.py @@ -132,7 +132,11 @@ class Installer(DistributionInstaller): if not any(stage3.iterdir()): with complete_step(f"Extracting {stage3_tar.name} to {stage3}"): - extract_tar(context, stage3_tar, stage3) + extract_tar( + stage3_tar, stage3, + tools=context.config.tools(), + sandbox=context.sandbox(options=["--bind", context.root, context.root]), + ) for d in ("binpkgs", "distfiles", "repos/gentoo"): (context.cache_dir / d).mkdir(parents=True, exist_ok=True)