diff --git a/pyproject.toml b/pyproject.toml index 7152d34..8bc6c9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "zenlib" -version = "3.1.3" +version = "3.1.4" authors = [ { name="Desultory", email="dev@pyl.onl" }, ] diff --git a/src/zenlib/namespace/namespace.py b/src/zenlib/namespace/namespace.py index 3d9d0b6..9cb4b52 100644 --- a/src/zenlib/namespace/namespace.py +++ b/src/zenlib/namespace/namespace.py @@ -1,4 +1,4 @@ -from os import CLONE_NEWNS, CLONE_NEWUSER, getlogin, unshare +from os import CLONE_NEWNS, CLONE_NEWUSER, getlogin, unshare, getuid from subprocess import CalledProcessError, run @@ -19,11 +19,32 @@ def get_id_map(username=None, id_type="uid"): raise ValueError(f"User {username} not found in /etc/sub{id_type}") +def write_id_map(id_type, pid, *args, failures=0): + if id_type not in ("uid", "gid"): + raise ValueError("id_type must be 'uid' or 'gid") + + map_file = f"/proc/{pid}/uid_map" if id_type == "uid" else f"/proc/{pid}/gid_map" + + # Get id, nsid, count tuples from args + map_contents = [f"{id} {nsid} {count}" for id, nsid, count in zip(*[iter(args)] * 3)] + + try: + with open(map_file, "w") as f: + f.write("\n".join(map_contents)) + except PermissionError as e: + if failures > 5: + raise e + new_id_map(id_type, pid, *args, failures=failures + 1) + def new_id_map(id_type, pid, id, nsid, count=1, *args, failures=0): if id_type not in ("uid", "gid"): raise ValueError("id_type must be 'uid' or 'gid") - cmd_args = [f"new{id_type}map", str(pid), str(id), str(nsid), str(count), *map(str, args)] + + if getuid() == 0: + return write_id_map(id_type, pid, id, nsid, count, *args) + try: + cmd_args = [f"new{id_type}map", str(pid), str(id), str(nsid), str(count), *map(str, args)] return run(cmd_args, check=True, capture_output=True) except CalledProcessError as e: if failures > 5: