#!/usr/bin/python3
# Copyright 2024 Helmut Grohne <helmut@subdivi.de>
# SPDX-License-Identifier: LGPL-2.0-or-later

"""Perform something like an unprivileged chroot via a user and mount
namespace. This is similar to "unshare --map-auto --mount-proc --root=$1", but
it also mounts /sys and /dev and performs a full pivot_root that cannot be
escaped using chroot.
"""

import os
import pathlib
import sys

if __file__.split("/")[-2:-1] == ["examples"]:
    sys.path.insert(0, "/".join(__file__.split("/")[:-2]))

import linuxnamespaces


def main() -> None:
    chrootdir = pathlib.Path(sys.argv[1])
    assert chrootdir.is_dir()

    subuids = linuxnamespaces.IDAllocation.loadsubid("uid")
    subgids = linuxnamespaces.IDAllocation.loadsubid("gid")
    uidmap = subuids.allocatemap(65536)
    gidmap = subgids.allocatemap(65536)

    linuxnamespaces.unshare_user_idmap(
        [uidmap],
        [gidmap],
        linuxnamespaces.CloneFlags.NEWUSER | linuxnamespaces.CloneFlags.NEWNS,
    )

    os.setregid(0, 0)
    os.setreuid(0, 0)

    linuxnamespaces.bind_mount(chrootdir, "/mnt", recursive=True)
    linuxnamespaces.bind_mount("/proc", "/mnt/proc", recursive=True)
    linuxnamespaces.bind_mount("/sys", "/mnt/sys", recursive=True)
    linuxnamespaces.populate_dev("/mnt/dev", pts="host")
    os.chdir("/mnt")
    linuxnamespaces.pivot_root(".", ".")
    linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH)
    if len(sys.argv) > 2:
        os.execvp(sys.argv[2], sys.argv[2:])
    else:
        os.execvp(os.environ["SHELL"], [os.environ["SHELL"]])


if __name__ == "__main__":
    main()
