From 9edda1d163ca85fe97d39008dbd28950d74aec32 Mon Sep 17 00:00:00 2001 From: Achilleas Koutsou Date: Wed, 21 Aug 2024 12:29:50 +0200 Subject: [PATCH] osbuild/util: new module: chroot New chroot utility module that sets up a tree with the necessary virtual filesystems needed for running commands in the root tree in a similar environment as they would run in the build root. This is needed for some stages, but may also be used for all chroot calls to unify the setup and teardown of the root environment. The Chroot context class was previously part of the org.osbuild.dracut stage, which was the first stage to need this setup. --- osbuild/util/chroot.py | 41 +++++++++++++++++++++++++++++++++++++++ stages/org.osbuild.dracut | 34 ++------------------------------ 2 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 osbuild/util/chroot.py diff --git a/osbuild/util/chroot.py b/osbuild/util/chroot.py new file mode 100644 index 00000000..97154a6e --- /dev/null +++ b/osbuild/util/chroot.py @@ -0,0 +1,41 @@ +import os +import subprocess + + +class Chroot: + """ + Sets up mounts for the virtual filesystems inside a root tree, preparing it for running commands using chroot. This + should be used whenever a stage needs to run a command against the root tree but doesn't support a --root option or + similar. + Cleans up mounts when done. + + This mounts /proc, /dev, and /sys. + """ + + def __init__(self, root: str): + self.root = root + + def __enter__(self): + for d in ["/proc", "/dev", "/sys"]: + if not os.path.exists(self.root + d): + print(f"Making missing chroot directory: {d}") + os.makedirs(self.root + d) + + subprocess.check_call(["/usr/bin/mount", + "-t", "proc", + "-o", "nosuid,noexec,nodev", + "proc", f"{self.root}/proc"]) + subprocess.check_call(["/usr/bin/mount", + "-t", "devtmpfs", + "-o", "mode=0755,noexec,nosuid,strictatime", + "devtmpfs", f"{self.root}/dev"]) + subprocess.check_call(["/usr/bin/mount", + "-t", "sysfs", + "-o", "nosuid,noexec,nodev", + "sysfs", f"{self.root}/sys"]) + + return self + + def __exit__(self, exc_type, exc_value, tracebk): + for d in ["/proc", "/dev", "/sys"]: + subprocess.check_call(["/usr/bin/umount", self.root + d]) diff --git a/stages/org.osbuild.dracut b/stages/org.osbuild.dracut index 36f853fe..f4067168 100755 --- a/stages/org.osbuild.dracut +++ b/stages/org.osbuild.dracut @@ -1,9 +1,9 @@ #!/usr/bin/python3 -import os import subprocess import sys import osbuild.api +from osbuild.util.chroot import Chroot def yesno(name: str, value: bool) -> str: @@ -11,36 +11,6 @@ def yesno(name: str, value: bool) -> str: return f"--{prefix}{name}" -class DracutMounts: - """ - Setup the mounts inside a chroot root directory, which will be used - for running dracut inside it. Cleanup mounts when done. - This mounts /proc, /dev, and /sys. - """ - - def __init__(self, root: str): - self.root = root - - def __enter__(self): - for d in ["/proc", "/dev", "/sys"]: - if not os.path.exists(self.root + d): - print(f"Making missing dracut chroot directory: {d}") - os.makedirs(self.root + d) - - subprocess.check_call(["/usr/bin/mount", "-t", "proc", "-o", - "nosuid,noexec,nodev", "proc", f"{self.root}/proc"]) - subprocess.check_call(["/usr/bin/mount", "-t", "devtmpfs", "-o", - "mode=0755,noexec,nosuid,strictatime", "devtmpfs", f"{self.root}/dev"]) - subprocess.check_call(["/usr/bin/mount", "-t", "sysfs", "-o", - "nosuid,noexec,nodev", "sysfs", f"{self.root}/sys"]) - - return self - - def __exit__(self, exc_type, exc_value, tracebk): - for d in ["/proc", "/dev", "/sys"]: - subprocess.check_call(["/usr/bin/umount", self.root + d]) - - # pylint: disable=too-many-branches def main(tree, options): kernels = options["kernel"] @@ -113,7 +83,7 @@ def main(tree, options): if initoverlayfs: initfs_bin = "/usr/bin/initoverlayfs-install" - with DracutMounts(tree): + with Chroot(tree): subprocess.run(["/usr/sbin/chroot", tree, initfs_bin, "--no-hostonly", "--kver", kver]