We currently use the absolute path of these binaries in the helper. This has some advantages but given that we control the inputs for PATH in general it seems unnecessary. We are also slightly inconsistent about this in the codebase but favor the non absolute path version. A quick count: ``` $ git grep '"chroot"'|wc -l 13 $ git grep '"/usr/sbin/chroot"'|grep -v test_|wc -l 8 ``` for `mount` and `umount` it seems this is the only place that uses the absolute path. It's not an important change but it has the nice property that it allows us to use e.g. `testutil.mock_command()` in our tests and it would be nice to be consistent.
49 lines
1.7 KiB
Python
49 lines
1.7 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.run(["mount", "-t", "proc", "-o", "nosuid,noexec,nodev",
|
|
"proc", f"{self.root}/proc"],
|
|
check=True)
|
|
|
|
subprocess.run(["mount", "-t", "devtmpfs", "-o", "mode=0755,noexec,nosuid,strictatime",
|
|
"devtmpfs", f"{self.root}/dev"],
|
|
check=True)
|
|
|
|
subprocess.run(["mount", "-t", "sysfs", "-o", "nosuid,noexec,nodev",
|
|
"sysfs", f"{self.root}/sys"],
|
|
check=True)
|
|
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, tracebk):
|
|
failed_umounts = []
|
|
for d in ["/proc", "/dev", "/sys"]:
|
|
if subprocess.run(["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 = ["chroot", self.root] + cmd
|
|
# pylint: disable=subprocess-run-check
|
|
return subprocess.run(cmd, **kwargs) # noqa: PLW1510
|