summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2025-07-02 07:08:56 +0200
committerHelmut Grohne <helmut@subdivi.de>2025-07-02 07:08:56 +0200
commit58dca9beea23e4e18c67f6f13838f5a895ca150f (patch)
treec3400ea0bb116b055e860b00e553cd6ffc4d1b8a /examples
parent7bc68c5bee3741183e4a5b170b8e34ce779bcfff (diff)
downloadpython-linuxnamespaces-58dca9beea23e4e18c67f6f13838f5a895ca150f.tar.gz
unschroot_proc: support additional mountsHEADmain
By using bindfs, we may perform id-mapped bind mounts to share e.g. a user-owned ccache with sbuild.
Diffstat (limited to 'examples')
-rwxr-xr-xexamples/unschroot_proc.py100
1 files changed, 69 insertions, 31 deletions
diff --git a/examples/unschroot_proc.py b/examples/unschroot_proc.py
index 5894680..dc5cc94 100755
--- a/examples/unschroot_proc.py
+++ b/examples/unschroot_proc.py
@@ -24,6 +24,7 @@ import configparser
import contextlib
import errno
import functools
+import itertools
import os
import pathlib
import pwd
@@ -168,6 +169,50 @@ class SourceChroot(ChrootBase):
assert False, f"unexpected chroot configuration {self.config!r}"
return data
+ async def mount_fuse(
+ self,
+ proxy: asyncvarlink.VarlinkInterfaceProxy,
+ device: str,
+ target: str,
+ subtype: str,
+ options: list[str],
+ ) -> None:
+ """Mount a single fuse filesystem in the proxied process."""
+ driver = {
+ "bind": "bindfs",
+ "erofs": "erofsfuse",
+ "ext4": "fuse2fs",
+ "squashfs": "squashfuse",
+ }[subtype]
+ with (
+ await proxy.MountFuse(
+ source=device,
+ target=target,
+ options={
+ "rootmode": "040755",
+ "user_id": 0,
+ "group_id": 0,
+ "allow_other": None,
+ },
+ fstype=subtype,
+ ) as mountres,
+ mountres["fusefd"] as fusefd,
+ ):
+ @linuxnamespaces.run_in_fork.now
+ def _() -> None:
+ close_all_but([0, 1, 2, fusefd])
+ os.execvp(
+ driver,
+ [
+ driver,
+ *itertools.chain.from_iterable(
+ zip(itertools.repeat("-o"), options)
+ ),
+ str(pathlib.Path(device).expanduser()),
+ f"/dev/fd/{fusefd.fileno()}",
+ ],
+ )
+
async def mount(
self,
proxy: asyncvarlink.VarlinkInterfaceProxy,
@@ -197,37 +242,9 @@ class SourceChroot(ChrootBase):
],
)
case ["fuse", subtype]:
- driver = {
- "erofs": "erofsfuse",
- "ext4": "fuse2fs",
- "squashfs": "squashfuse",
- }[subtype]
- device = pathlib.Path(self.config["rootfsdev"])
- with (
- await proxy.MountFuse(
- source=str(device),
- target="lower",
- options={
- "rootmode": "040755",
- "user_id": 0,
- "group_id": 0,
- "allow_other": None,
- },
- fstype=subtype,
- ) as mountres,
- mountres["fusefd"] as fusefd,
- ):
- @linuxnamespaces.run_in_fork.now
- def _() -> None:
- close_all_but([0, 1, 2, fusefd])
- os.execvp(
- driver,
- [
- driver,
- str(device.expanduser()),
- f"/dev/fd/{fusefd.fileno()}",
- ],
- )
+ await self.mount_fuse(
+ proxy, self.config["rootfsdev"], "lower", subtype, []
+ )
case _:
raise NotImplementedError("unsupported rootfstype")
if self.config.get("overlayfs"):
@@ -251,6 +268,27 @@ class SourceChroot(ChrootBase):
extra["comptype"] = "zst"
with tar.expanduser().open("rb") as tarf:
await proxy.ExtractTar(tar=tarf, **extra)
+ for mount in self.config.get("mounts", "").split():
+ [device, target, fstypestr, *options] = mount.split(",")
+ fstype = fstypestr.split(".", 1)
+ match fstype:
+ case ['bind']:
+ readonly = False
+ if options == ["ro"]:
+ readonly = True
+ elif options:
+ raise NotImplementedError(
+ "unsupported bind mount option"
+ )
+ await proxy.BindMount(
+ source=str(pathlib.Path(device).expanduser()),
+ target=target,
+ readonly=readonly,
+ )
+ case ['fuse', subtype]:
+ await self.mount_fuse(
+ proxy, device, target, subtype, options
+ )
class SessionChroot(ChrootBase):