From: Daan De Meyer Date: Thu, 27 Mar 2025 16:26:42 +0000 (+0100) Subject: sandbox: Allow taking bind source paths relative to the sandbox root X-Git-Tag: v26~289^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=204d2a5136cad09d01aefe62e4b9bf51ac84c705;p=thirdparty%2Fmkosi.git sandbox: Allow taking bind source paths relative to the sandbox root --- diff --git a/mkosi/resources/man/mkosi-sandbox.1.md b/mkosi/resources/man/mkosi-sandbox.1.md index 1f3ffcba5..4289a1a0b 100644 --- a/mkosi/resources/man/mkosi-sandbox.1.md +++ b/mkosi/resources/man/mkosi-sandbox.1.md @@ -42,7 +42,9 @@ host system. `--bind SRC DST` : The source path `SRC` is recursively bind mounted to `DST` in the sandbox. The mountpoint is created in the sandbox if it does not yet exist. Any missing parent - directories in the sandbox are created as well. + directories in the sandbox are created as well. The source path may optionally be + prefixed with a `+` character. If so, the source path is interpreted relative to the + sandbox root directory instead of the host root directory. `--bind-try SRC DST` : Like `--bind`, but doesn't fail if the source path doesn't exist. diff --git a/mkosi/sandbox.py b/mkosi/sandbox.py index 46621aa4a..c79b48739 100755 --- a/mkosi/sandbox.py +++ b/mkosi/sandbox.py @@ -566,8 +566,9 @@ def pack_file_descriptors() -> int: class FSOperation: - def __init__(self, dst: str) -> None: + def __init__(self, dst: str, *, relative: bool = False) -> None: self.dst = dst + self.relative = relative def execute(self, oldroot: str, newroot: str) -> None: raise NotImplementedError() @@ -592,6 +593,7 @@ class FSOperation: m != n and m.readonly == n.readonly and m.required == n.required + and m.relative == n.relative and is_relative_to(m.src, n.src) and is_relative_to(m.dst, n.dst) and os.path.relpath(m.src, n.src) == os.path.relpath(m.dst, n.dst) @@ -600,16 +602,17 @@ class FSOperation: ] # Make sure bind mounts override other operations on the same destination by appending them - # to the rest and depending on python's stable sort behavior. - return sorted([*rest, *optimized], key=lambda fsop: splitpath(fsop.dst)) + # to the rest and depending on python's stable sort behavior. Additionally, relative operations + # always go last. + return sorted([*rest, *optimized], key=lambda fsop: (fsop.relative, splitpath(fsop.dst))) class BindOperation(FSOperation): - def __init__(self, src: str, dst: str, *, readonly: bool, required: bool) -> None: + def __init__(self, src: str, dst: str, *, readonly: bool, required: bool, relative: bool) -> None: self.src = src self.readonly = readonly self.required = required - super().__init__(dst) + super().__init__(dst, relative=relative) def __hash__(self) -> int: return hash((splitpath(self.src), splitpath(self.dst), self.readonly, self.required)) @@ -618,7 +621,7 @@ class BindOperation(FSOperation): return isinstance(other, BindOperation) and self.__hash__() == other.__hash__() def execute(self, oldroot: str, newroot: str) -> None: - src = chase(oldroot, self.src) + src = chase(newroot if self.relative else oldroot, self.src) if not os.path.exists(src) and not self.required: return @@ -907,7 +910,16 @@ def main() -> None: elif arg in ("--bind", "--ro-bind", "--bind-try", "--ro-bind-try"): readonly = arg.startswith("--ro") required = not arg.endswith("-try") - fsops.append(BindOperation(argv.pop(), argv.pop(), readonly=readonly, required=required)) + src = argv.pop() + fsops.append( + BindOperation( + src.removeprefix("+"), + argv.pop(), + readonly=readonly, + required=required, + relative=src.startswith("+"), + ) + ) elif arg == "--symlink": fsops.append(SymlinkOperation(argv.pop(), argv.pop())) elif arg == "--write":