debian-forge/osbuild/util/chroot.py
Achilleas Koutsou 3dbf389ebf util/chroot: add run() method to context class
Rename the ChrootProcDevSys class to just Chroot and add a run() method.
Calls now can be made using:

  with Chroot(root) as chroot:
      chroot.run(command)
2024-08-28 16:45:48 -07:00

50 lines
1.9 KiB
Python

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):
failed_umounts = []
for d in ["/proc", "/dev", "/sys"]:
if subprocess.run(["/usr/bin/umount", "--lazy", self.root + d], check=False).returncode != 0:
failed_umounts.append(d)
if failed_umounts:
print(f"Error unmounting paths from chroot: {failed_umounts}")
def run(self, cmd, **kwargs):
cmd = ["/usr/sbin/chroot", self.root] + cmd
# pylint: disable=subprocess-run-check
subprocess.run(cmd, **kwargs) # noqa: PLW1510