From: Daan De Meyer Date: Fri, 15 Mar 2024 12:09:39 +0000 (+0100) Subject: Always mount context.root to /buildroot X-Git-Tag: v23~88^2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2513%2Fhead;p=thirdparty%2Fmkosi.git Always mount context.root to /buildroot Let's leak fewer host specific details into the sandbox by always mounting the image root directory to /buildroot in the sandbox. This also simplifies debugging as the image rootfs will always be at /rootfs instead of in some host specific path. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 47741e762..67cc46d43 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -404,7 +404,7 @@ def finalize_host_scripts( scripts["git"] = GIT_COMMAND for binary in ("useradd", "groupadd"): if find_binary(binary, root=context.config.tools()): - scripts[binary] = (binary, "--root", context.root) + scripts[binary] = (binary, "--root", "/buildroot") return finalize_scripts(scripts | dict(helpers), root=context.config.tools()) @@ -487,7 +487,7 @@ def run_prepare_scripts(context: Context, build: bool) -> None: DISTRIBUTION=str(context.config.distribution), RELEASE=context.config.release, ARCHITECTURE=str(context.config.architecture), - BUILDROOT=str(context.root), + BUILDROOT="/buildroot", SRCDIR="/work/src", CHROOT_SRCDIR="/work/src", PACKAGEDIR="/work/packages", @@ -517,7 +517,7 @@ def run_prepare_scripts(context: Context, build: bool) -> None: arg = "final" for script in context.config.prepare_scripts: - chroot = chroot_cmd(context.root, resolve=True) + chroot = chroot_cmd(resolve=True) helpers = { "mkosi-chroot": chroot, @@ -541,7 +541,7 @@ def run_prepare_scripts(context: Context, build: bool) -> None: Mount(script, "/work/prepare", ro=True), Mount(json, "/work/config.json", ro=True), Mount(cd, "/work/scripts", ro=True), - Mount(context.root, context.root), + Mount(context.root, "/buildroot"), *context.config.distribution.package_manager(context.config).mounts(context), ], options=["--dir", "/work/src", "--chdir", "/work/src"], @@ -558,7 +558,7 @@ def run_build_scripts(context: Context) -> None: DISTRIBUTION=str(context.config.distribution), RELEASE=context.config.release, ARCHITECTURE=str(context.config.architecture), - BUILDROOT=str(context.root), + BUILDROOT="/buildroot", DESTDIR="/work/dest", CHROOT_DESTDIR="/work/dest", OUTPUTDIR="/work/out", @@ -591,7 +591,7 @@ def run_build_scripts(context: Context) -> None: finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources, ): for script in context.config.build_scripts: - chroot = chroot_cmd(context.root, resolve=context.config.with_network) + chroot = chroot_cmd(resolve=context.config.with_network) helpers = { "mkosi-chroot": chroot, @@ -617,7 +617,7 @@ def run_build_scripts(context: Context) -> None: Mount(script, "/work/build-script", ro=True), Mount(json, "/work/config.json", ro=True), Mount(cd, "/work/scripts", ro=True), - Mount(context.root, context.root), + Mount(context.root, "/buildroot"), Mount(context.install_dir, "/work/dest"), Mount(context.staging, "/work/out"), *( @@ -645,7 +645,7 @@ def run_postinst_scripts(context: Context) -> None: DISTRIBUTION=str(context.config.distribution), RELEASE=context.config.release, ARCHITECTURE=str(context.config.architecture), - BUILDROOT=str(context.root), + BUILDROOT="/buildroot", OUTPUTDIR="/work/out", CHROOT_OUTPUTDIR="/work/out", SCRIPT="/work/postinst", @@ -666,7 +666,7 @@ def run_postinst_scripts(context: Context) -> None: finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources, ): for script in context.config.postinst_scripts: - chroot = chroot_cmd(context.root, resolve=context.config.with_network) + chroot = chroot_cmd(resolve=context.config.with_network) helpers = { "mkosi-chroot": chroot, @@ -690,7 +690,7 @@ def run_postinst_scripts(context: Context) -> None: Mount(script, "/work/postinst", ro=True), Mount(json, "/work/config.json", ro=True), Mount(cd, "/work/scripts", ro=True), - Mount(context.root, context.root), + Mount(context.root, "/buildroot"), Mount(context.staging, "/work/out"), *context.config.distribution.package_manager(context.config).mounts(context), ], @@ -708,7 +708,7 @@ def run_finalize_scripts(context: Context) -> None: DISTRIBUTION=str(context.config.distribution), RELEASE=context.config.release, ARCHITECTURE=str(context.config.architecture), - BUILDROOT=str(context.root), + BUILDROOT="/buildroot", OUTPUTDIR="/work/out", CHROOT_OUTPUTDIR="/work/out", SRCDIR="/work/src", @@ -729,7 +729,7 @@ def run_finalize_scripts(context: Context) -> None: finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources, ): for script in context.config.finalize_scripts: - chroot = chroot_cmd(context.root, resolve=context.config.with_network) + chroot = chroot_cmd(resolve=context.config.with_network) helpers = { "mkosi-chroot": chroot, @@ -753,7 +753,7 @@ def run_finalize_scripts(context: Context) -> None: Mount(script, "/work/finalize", ro=True), Mount(json, "/work/config.json", ro=True), Mount(cd, "/work/scripts", ro=True), - Mount(context.root, context.root), + Mount(context.root, "/buildroot"), Mount(context.staging, "/work/out"), *context.config.distribution.package_manager(context.config).mounts(context), ], @@ -960,9 +960,9 @@ def install_systemd_boot(context: Context) -> None: with complete_step("Installing systemd-boot…"): run( - ["bootctl", "install", "--root", context.root, "--all-architectures", "--no-variables"], + ["bootctl", "install", "--root=/buildroot", "--all-architectures", "--no-variables"], env={"SYSTEMD_ESP_PATH": "/efi", "SYSTEMD_XBOOTLDR_PATH": "/boot"}, - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)]), + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")]), ) if context.config.shim_bootloader != ShimBootloader.none: @@ -1276,10 +1276,10 @@ def grub_mkimage( run( [ mkimage, - "--directory", directory, + "--directory", "/grub", "--config", earlyconfig.name, "--prefix", f"/{context.config.distribution.grub_prefix()}", - "--output", output or (directory / "core.img"), + "--output", output or ("/grub/core.img"), "--format", target, *(["--sbat", str(sbat)] if sbat else []), *(["--disable-shim-lock"] if context.config.shim_bootloader == ShimBootloader.none else []), @@ -1308,8 +1308,9 @@ def grub_mkimage( ], sandbox=context.sandbox( mounts=[ - Mount(context.root, context.root), + Mount(directory, "/grub"), Mount(earlyconfig.name, earlyconfig.name, ro=True), + *([Mount(output.parent, output.parent)] if output else []), *([Mount(str(sbat), str(sbat), ro=True)] if sbat else []), ], ), @@ -1412,12 +1413,12 @@ def grub_bios_setup(context: Context, partitions: Sequence[Partition]) -> None: [ "sh", "-c", f"mount --bind {mountinfo.name} /proc/$$/mountinfo && exec $0 \"$@\"", setup, - "--directory", directory, + "--directory", "/grub", context.staging / context.config.output_with_format, ], sandbox=context.sandbox( mounts=[ - Mount(context.root, context.root), + Mount(directory, "/grub"), Mount(context.staging, context.staging), Mount(mountinfo.name, mountinfo.name), ], @@ -2046,8 +2047,8 @@ def find_entry_token(context: Context) -> str: ): return context.config.image_id or context.config.distribution.name - output = json.loads(run(["kernel-install", "--root", context.root, "--json=pretty", "inspect"], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root, ro=True)]), + output = json.loads(run(["kernel-install", "--root=/buildroot", "--json=pretty", "inspect"], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot", ro=True)]), stdout=subprocess.PIPE, env={"SYSTEMD_ESP_PATH": "/efi", "SYSTEMD_XBOOTLDR_PATH": "/boot"}).stdout) logging.debug(json.dumps(output, indent=4)) @@ -2747,8 +2748,8 @@ def run_depmod(context: Context, *, cache: bool = False) -> None: ) with complete_step(f"Running depmod for {kver}"): - run(["depmod", "--all", "--basedir", context.root, kver], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)])) + run(["depmod", "--all", "--basedir", "/buildroot", kver], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")])) def run_sysusers(context: Context) -> None: @@ -2757,8 +2758,8 @@ def run_sysusers(context: Context) -> None: return with complete_step("Generating system users"): - run(["systemd-sysusers", "--root", context.root], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)])) + run(["systemd-sysusers", "--root=/buildroot"], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")])) def run_tmpfiles(context: Context) -> None: @@ -2769,7 +2770,7 @@ def run_tmpfiles(context: Context) -> None: with complete_step("Generating volatile files"): cmdline = [ "systemd-tmpfiles", - f"--root={context.root}", + "--root=/buildroot", "--boot", "--create", "--remove", @@ -2779,7 +2780,7 @@ def run_tmpfiles(context: Context) -> None: sandbox = context.sandbox( mounts=[ - Mount(context.root, context.root), + Mount(context.root, "/buildroot"), # systemd uses acl.h to parse ACLs in tmpfiles snippets which uses the host's passwd so we have to # mount the image's passwd over it to make ACL parsing work. *finalize_passwd_mounts(context.root) @@ -2805,10 +2806,10 @@ def run_preset(context: Context) -> None: return with complete_step("Applying presets…"): - run(["systemctl", "--root", context.root, "preset-all"], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)])) - run(["systemctl", "--root", context.root, "--global", "preset-all"], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)])) + run(["systemctl", "--root=/buildroot", "preset-all"], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")])) + run(["systemctl", "--root=/buildroot", "--global", "preset-all"], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")])) def run_hwdb(context: Context) -> None: @@ -2820,8 +2821,8 @@ def run_hwdb(context: Context) -> None: return with complete_step("Generating hardware database"): - run(["systemd-hwdb", "--root", context.root, "--usr", "--strict", "update"], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)])) + run(["systemd-hwdb", "--root=/buildroot", "--usr", "--strict", "update"], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")])) # Remove any existing hwdb in /etc in favor of the one we just put in /usr. (context.root / "etc/udev/hwdb.bin").unlink(missing_ok=True) @@ -2867,8 +2868,8 @@ def run_firstboot(context: Context) -> None: return with complete_step("Applying first boot settings"): - run(["systemd-firstboot", "--root", context.root, "--force", *options], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)])) + run(["systemd-firstboot", "--root=/buildroot", "--force", *options], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")])) # Initrds generally don't ship with only /usr so there's not much point in putting the credentials in # /usr/lib/credstore. @@ -2888,8 +2889,8 @@ def run_selinux_relabel(context: Context) -> None: policy, fc, binpolicy = selinux with complete_step(f"Relabeling files using {policy} policy"): - run(["setfiles", "-mFr", context.root, "-c", binpolicy, fc, context.root], - sandbox=context.sandbox(mounts=[Mount(context.root, context.root)]), + run(["setfiles", "-mFr", "/buildroot", "-c", binpolicy, fc, "/buildroot"], + sandbox=context.sandbox(mounts=[Mount(context.root, "/buildroot")]), check=context.config.selinux_relabel == ConfigFeature.enabled) @@ -3033,8 +3034,8 @@ def make_image( mounts = [Mount(context.staging, context.staging)] if root: - cmdline += ["--root", root] - mounts += [Mount(root, root)] + cmdline += ["--root=/buildroot"] + mounts += [Mount(root, "/buildroot")] if not context.config.architecture.is_native(): cmdline += ["--architecture", str(context.config.architecture)] if not (context.staging / context.config.output_with_format).exists(): @@ -3210,7 +3211,7 @@ def make_esp(context: Context, uki: Path) -> list[Partition]: def make_extension_image(context: Context, output: Path) -> None: cmdline: list[PathString] = [ "systemd-repart", - "--root", context.root, + "--root=/buildroot", "--dry-run=no", "--no-pager", f"--offline={yes_no(context.config.repart_offline)}", @@ -3221,7 +3222,7 @@ def make_extension_image(context: Context, output: Path) -> None: ] mounts = [ Mount(output.parent, output.parent), - Mount(context.root, context.root, ro=True), + Mount(context.root, "/buildroot", ro=True), ] if not context.config.architecture.is_native(): diff --git a/mkosi/installer/apt.py b/mkosi/installer/apt.py index 117b9d9fb..fab81a8ec 100644 --- a/mkosi/installer/apt.py +++ b/mkosi/installer/apt.py @@ -52,7 +52,7 @@ class Apt(PackageManager): def scripts(cls, context: Context) -> dict[str, list[PathString]]: return { **{ - command: apivfs_cmd(context.root) + cls.cmd(context, command) for command in ( + command: apivfs_cmd() + cls.cmd(context, command) for command in ( "apt", "apt-cache", "apt-cdrom", @@ -133,10 +133,10 @@ class Apt(PackageManager): "-o", "Dir::Cache=/var/cache/apt", "-o", "Dir::State=/var/lib/apt", "-o", "Dir::Log=/var/log/apt", - "-o", f"Dir::State::Status={context.root / 'var/lib/dpkg/status'}", + "-o", "Dir::State::Status=/buildroot/var/lib/dpkg/status", "-o", f"Dir::Bin::DPkg={find_binary('dpkg', root=context.config.tools())}", "-o", "Debug::NoLocking=true", - "-o", f"DPkg::Options::=--root={context.root}", + "-o", "DPkg::Options::=--root=/buildroot", "-o", "DPkg::Options::=--force-unsafe-io", "-o", "DPkg::Options::=--force-architecture", "-o", "DPkg::Options::=--force-depends", @@ -184,9 +184,9 @@ class Apt(PackageManager): sandbox=( context.sandbox( network=True, - mounts=[Mount(context.root, context.root), *cls.mounts(context), *sources, *mounts], + mounts=[Mount(context.root, "/buildroot"), *cls.mounts(context), *sources, *mounts], options=["--dir", "/work/src", "--chdir", "/work/src"], - ) + (apivfs_cmd(context.root) if apivfs else []) + ) + (apivfs_cmd() if apivfs else []) ), env=context.config.environment, stdout=stdout, diff --git a/mkosi/installer/dnf.py b/mkosi/installer/dnf.py index 7b6fc0ede..2344ec926 100644 --- a/mkosi/installer/dnf.py +++ b/mkosi/installer/dnf.py @@ -39,8 +39,8 @@ class Dnf(PackageManager): @classmethod def scripts(cls, context: Context) -> dict[str, list[PathString]]: return { - "dnf": apivfs_cmd(context.root) + cls.cmd(context), - "rpm": apivfs_cmd(context.root) + rpm_cmd(context), + "dnf": apivfs_cmd() + cls.cmd(context), + "rpm": apivfs_cmd() + rpm_cmd(), "mkosi-install" : ["dnf", "install"], "mkosi-upgrade" : ["dnf", "upgrade"], "mkosi-remove" : ["dnf", "remove"], @@ -105,7 +105,7 @@ class Dnf(PackageManager): "--assumeyes", "--best", f"--releasever={context.config.release}", - f"--installroot={context.root}", + "--installroot=/buildroot", "--setopt=keepcache=1", "--setopt=logdir=/var/log", f"--setopt=cachedir=/var/cache/{cls.subdir(context.config)}", @@ -170,9 +170,9 @@ class Dnf(PackageManager): sandbox=( context.sandbox( network=True, - mounts=[Mount(context.root, context.root), *cls.mounts(context), *sources], + mounts=[Mount(context.root, "/buildroot"), *cls.mounts(context), *sources], options=["--dir", "/work/src", "--chdir", "/work/src"], - ) + (apivfs_cmd(context.root) if apivfs else []) + ) + (apivfs_cmd() if apivfs else []) ), env=context.config.environment, stdout=stdout, diff --git a/mkosi/installer/pacman.py b/mkosi/installer/pacman.py index e5faeff22..e700cd8f6 100644 --- a/mkosi/installer/pacman.py +++ b/mkosi/installer/pacman.py @@ -37,7 +37,7 @@ class Pacman(PackageManager): @classmethod def scripts(cls, context: Context) -> dict[str, list[PathString]]: return { - "pacman": apivfs_cmd(context.root) + cls.cmd(context), + "pacman": apivfs_cmd() + cls.cmd(context), "mkosi-install" : ["pacman", "--sync", "--needed"], "mkosi-upgrade" : ["pacman", "--sync", "--sysupgrade", "--needed"], "mkosi-remove" : ["pacman", "--remove", "--recursive", "--nosave"], @@ -128,14 +128,14 @@ class Pacman(PackageManager): def cmd(cls, context: Context) -> list[PathString]: return [ "pacman", - "--root", context.root, + "--root=/buildroot", "--logfile=/dev/null", "--dbpath=/var/lib/pacman", # Make sure pacman looks at our local repository first by putting it as the first cache directory. We mount # it read-only so the second directory will still be used for writing new cache entries. "--cachedir=/var/cache/pacman/mkosi", "--cachedir=/var/cache/pacman/pkg", - "--hookdir", context.root / "etc/pacman.d/hooks", + "--hookdir=/buildroot/etc/pacman.d/hooks", "--arch", context.config.distribution.architecture(context.config.architecture), "--color", "auto", "--noconfirm", @@ -160,9 +160,9 @@ class Pacman(PackageManager): sandbox=( context.sandbox( network=True, - mounts=[Mount(context.root, context.root), *cls.mounts(context), *sources], + mounts=[Mount(context.root, "/buildroot"), *cls.mounts(context), *sources], options=["--dir", "/work/src", "--chdir", "/work/src"], - ) + (apivfs_cmd(context.root) if apivfs else []) + ) + (apivfs_cmd() if apivfs else []) ), env=context.config.environment, stdout=stdout, diff --git a/mkosi/installer/rpm.py b/mkosi/installer/rpm.py index 6fb1daab9..c0e0fe78e 100644 --- a/mkosi/installer/rpm.py +++ b/mkosi/installer/rpm.py @@ -67,5 +67,5 @@ def setup_rpm(context: Context, *, dbpath: str = "/usr/lib/sysimage/rpm") -> Non ) -def rpm_cmd(context: Context) -> list[PathString]: - return ["env", "HOME=/", "rpm", "--root", context.root] +def rpm_cmd() -> list[PathString]: + return ["env", "HOME=/", "rpm", "--root=/buildroot"] diff --git a/mkosi/installer/zypper.py b/mkosi/installer/zypper.py index 422ff7743..329059b9e 100644 --- a/mkosi/installer/zypper.py +++ b/mkosi/installer/zypper.py @@ -38,8 +38,8 @@ class Zypper(PackageManager): ] return { - "zypper": apivfs_cmd(context.root) + cls.cmd(context), - "rpm" : apivfs_cmd(context.root) + rpm_cmd(context), + "zypper": apivfs_cmd() + cls.cmd(context), + "rpm" : apivfs_cmd() + rpm_cmd(), "mkosi-install" : install, "mkosi-upgrade" : ["zypper", "update"], "mkosi-remove" : ["zypper", "remove", "--clean-deps"], @@ -105,7 +105,7 @@ class Zypper(PackageManager): "ZYPP_CONF=/etc/zypp/zypp.conf", "HOME=/", "zypper", - f"--installroot={context.root}", + "--installroot=/buildroot", "--cache-dir=/var/cache/zypp", "--gpg-auto-import-keys" if context.config.repository_key_check else "--no-gpg-checks", "--non-interactive", @@ -131,9 +131,9 @@ class Zypper(PackageManager): sandbox=( context.sandbox( network=True, - mounts=[Mount(context.root, context.root), *cls.mounts(context), *sources], + mounts=[Mount(context.root, "/buildroot"), *cls.mounts(context), *sources], options=["--dir", "/work/src", "--chdir", "/work/src"], - ) + (apivfs_cmd(context.root) if apivfs else []) + ) + (apivfs_cmd() if apivfs else []) ), env=context.config.environment, stdout=stdout, diff --git a/mkosi/manifest.py b/mkosi/manifest.py index 4502dca06..9f0415673 100644 --- a/mkosi/manifest.py +++ b/mkosi/manifest.py @@ -105,13 +105,13 @@ class Manifest: c = run( [ "rpm", - f"--root={self.context.root}", + "--root=/buildroot", "--query", "--all", "--queryformat", r"%{NEVRA}\t%{SOURCERPM}\t%{NAME}\t%{ARCH}\t%{LONGSIZE}\t%{INSTALLTIME}\n", ], stdout=subprocess.PIPE, - sandbox=self.context.sandbox(mounts=[Mount(self.context.root, self.context.root)]), + sandbox=self.context.sandbox(mounts=[Mount(self.context.root, "/buildroot")]), ) packages = sorted(c.stdout.splitlines()) @@ -150,14 +150,14 @@ class Manifest: c = run( [ "rpm", - f"--root={self.context.root}", + "--root=/buildroot", "--query", "--changelog", nevra, ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, - sandbox=self.context.sandbox(mounts=[Mount(self.context.root, self.context.root, ro=True)]), + sandbox=self.context.sandbox(mounts=[Mount(self.context.root, "/buildroot", ro=True)]), ) changelog = c.stdout.strip() source = SourcePackageManifest(srpm, changelog) @@ -169,13 +169,13 @@ class Manifest: c = run( [ "dpkg-query", - f"--admindir={self.context.root / 'var/lib/dpkg'}", + "--admindir=/buildroot/var/lib/dpkg", "--show", "--showformat", r'${Package}\t${source:Package}\t${Version}\t${Architecture}\t${Installed-Size}\t${db-fsys:Last-Modified}\n', ], stdout=subprocess.PIPE, - sandbox=self.context.sandbox(mounts=[Mount(self.context.root, self.context.root, ro=True)]), + sandbox=self.context.sandbox(mounts=[Mount(self.context.root, "/buildroot", ro=True)]), ) packages = sorted(c.stdout.splitlines()) @@ -211,7 +211,7 @@ class Manifest: result = Apt.invoke( self.context, "changelog", - ["--quiet", "--quiet", "-o", f"Dir={self.context.root}", name], + ["--quiet", "--quiet", "-o", "Dir=/buildroot", name], stdout=subprocess.PIPE, ) source_package = SourcePackageManifest(source, result.stdout.strip()) diff --git a/mkosi/sandbox.py b/mkosi/sandbox.py index fdad185d6..e1c34b062 100644 --- a/mkosi/sandbox.py +++ b/mkosi/sandbox.py @@ -64,14 +64,14 @@ def have_effective_cap(capability: Capability) -> bool: return (int(hexcap, 16) & (1 << capability.value)) != 0 -def finalize_passwd_mounts(root: Path) -> list[Mount]: +def finalize_passwd_mounts(root: PathString) -> list[Mount]: """ If passwd or a related file exists in the apivfs directory, bind mount it over the host files while we run the command, to make sure that the command we run uses user/group information from the apivfs directory instead of from the host. """ return [ - Mount(root / "etc" / f, f"/etc/{f}", ro=True, required=False) + Mount(Path(root) / "etc" / f, f"/etc/{f}", ro=True, required=False) for f in ("passwd", "group", "shadow", "gshadow") ] @@ -239,43 +239,52 @@ def sandbox_cmd( return cmdline -def apivfs_cmd(root: Path) -> list[PathString]: +def apivfs_cmd() -> list[PathString]: return [ "bwrap", "--dev-bind", "/", "/", - "--tmpfs", root / "run", - "--tmpfs", root / "tmp", - "--bind", "/var/tmp", root / "var/tmp", - "--proc", root / "proc", - "--dev", root / "dev", + "--tmpfs", "/buildroot/run", + "--tmpfs", "/buildroot/tmp", + "--bind", "/var/tmp", "/buildroot/var/tmp", + "--proc", "/buildroot/proc", + "--dev", "/buildroot/dev", # Make sure /etc/machine-id is not overwritten by any package manager post install scripts. - "--ro-bind-try", root / "etc/machine-id", root / "etc/machine-id", + "--ro-bind-try", "/buildroot/etc/machine-id", "/buildroot/etc/machine-id", # Nudge gpg to create its sockets in /run by making sure /run/user/0 exists. - "--dir", root / "run/user/0", - *flatten(mount.options() for mount in finalize_passwd_mounts(root)), + "--dir", "/buildroot/run/user/0", + *flatten(mount.options() for mount in finalize_passwd_mounts("/buildroot")), "sh", "-c", - f"chmod 1777 {root / 'tmp'} {root / 'var/tmp'} {root / 'dev/shm'} && " - f"chmod 755 {root / 'run'} && " - # Make sure anything running in the root directory thinks it's in a container. $container can't always be - # accessed so we write /run/host/container-manager as well which is always accessible. - f"mkdir -m 755 {root}/run/host && echo mkosi >{root}/run/host/container-manager && " - "exec $0 \"$@\"", + " && ".join( + [ + "chmod 1777 /buildroot/tmp /buildroot/var/tmp /buildroot/dev/shm", + "chmod 755 /buildroot/run", + # Make sure anything running in the root directory thinks it's in a container. $container can't always + # be accessed so we write /run/host/container-manager as well which is always accessible. + "mkdir -m 755 /buildroot/run/host", + "echo mkosi >/buildroot/run/host/container-manager", + "exec $0 \"$@\"", + ] + ), ] -def chroot_cmd(root: Path, *, resolve: bool = False) -> list[PathString]: - return apivfs_cmd(root) + [ +def chroot_cmd(*, resolve: bool = False) -> list[PathString]: + return apivfs_cmd() + [ "sh", "-c", - f"trap 'rm -rf {root / 'work'}' EXIT && " - # /etc/resolv.conf can be a dangling symlink to /run/systemd/resolve/stub-resolv.conf. Bubblewrap tries to call - # mkdir() on each component of the path which means it will try to call - # mkdir(/run/systemd/resolve/stub-resolv.conf) which will fail unless /run/systemd/resolve exists already so - # we make sure that it already exists. - f"mkdir -p -m 755 {root / 'work'} {root / 'run/systemd'} {root / 'run/systemd/resolve'} && " - # No exec here because we need to clean up the /work directory afterwards. - f"$0 \"$@\"", + " && ".join( + [ + "trap 'rm -rf /buildroot/work' EXIT", + # /etc/resolv.conf can be a dangling symlink to /run/systemd/resolve/stub-resolv.conf. Bubblewrap tries + # to call mkdir() on each component of the path which means it will try to call + # mkdir(/run/systemd/resolve/stub-resolv.conf) which will fail unless /run/systemd/resolve exists + # already so we make sure that it already exists. + "mkdir -p -m 755 /buildroot/work /buildroot/run/systemd /buildroot/run/systemd/resolve", + # No exec here because we need to clean up the /work directory afterwards. + "$0 \"$@\"", + ] + ), "bwrap", - "--dev-bind", root, "/", + "--dev-bind", "/buildroot", "/", "--setenv", "container", "mkosi", "--setenv", "HOME", "/", "--setenv", "PATH", "/work/scripts:/usr/bin:/usr/sbin",