changes to support regular host os

Prepare proot-distro for supporting Linux distribution as host system.

1. Option --termux-home renamed to --shared-home, alias --termux-home
   kept.

2. If host environment is not Termux, hide all Termux-specific stuff.

3. Change location of data files on non-Termux environment.

4. Don't prompt to install proot when it doesn't exist on non-Termux
   environment, just show an error.
This commit is contained in:
Sylirre
2026-05-16 01:04:48 +00:00
parent 09c4fa4cbf
commit dcc659cd16
25 changed files with 248 additions and 171 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+55 -42
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
@@ -31,7 +31,7 @@ import shutil
import subprocess
import sys
from proot_distro.constants import PROGRAM_NAME
from proot_distro.constants import IS_TERMUX, PROGRAM_NAME
from proot_distro.colors import C, msg
from proot_distro.commands.install import command_install
from proot_distro.commands.remove import command_remove
@@ -51,7 +51,7 @@ from proot_distro.commands.help import command_help, _HELP_COMMANDS
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog=PROGRAM_NAME,
description="Manage Linux proot containers on Termux.",
description="Manage Linux proot containers.",
add_help=False,
)
parser.add_argument("-h", "--help", action="store_true")
@@ -103,10 +103,15 @@ def build_parser() -> argparse.ArgumentParser:
_p_login_ports.add_argument(
"--fix-low-ports", dest="redirect_ports", action="store_true"
)
p_login.add_argument("--isolated", action="store_true")
p_login.add_argument("--minimal", action="store_true")
p_login.add_argument(
"--termux-home", dest="termux_home", action="store_true"
if IS_TERMUX:
p_login.add_argument("--isolated", action="store_true")
p_login.add_argument("--minimal", action="store_true")
_p_login_shared_home = p_login.add_mutually_exclusive_group()
_p_login_shared_home.add_argument(
"--shared-home", dest="shared_home", action="store_true"
)
_p_login_shared_home.add_argument(
"--termux-home", dest="shared_home", action="store_true"
)
p_login.add_argument(
"--shared-tmp", dest="shared_tmp", action="store_true"
@@ -120,9 +125,10 @@ def build_parser() -> argparse.ArgumentParser:
p_login.add_argument(
"--no-link2symlink", dest="no_link2symlink", action="store_true"
)
p_login.add_argument(
"--no-sysvipc", dest="no_sysvipc", action="store_true"
)
if IS_TERMUX:
p_login.add_argument(
"--no-sysvipc", dest="no_sysvipc", action="store_true"
)
p_login.add_argument(
"--no-kill-on-exit", dest="no_kill_on_exit", action="store_true"
)
@@ -190,10 +196,15 @@ def build_parser() -> argparse.ArgumentParser:
p_run.add_argument(
"--redirect-ports", dest="redirect_ports", action="store_true"
)
p_run.add_argument("--isolated", action="store_true")
p_run.add_argument("--minimal", action="store_true")
p_run.add_argument(
"--termux-home", dest="termux_home", action="store_true"
if IS_TERMUX:
p_run.add_argument("--isolated", action="store_true")
p_run.add_argument("--minimal", action="store_true")
_p_run_shared_home = p_run.add_mutually_exclusive_group()
_p_run_shared_home.add_argument(
"--shared-home", dest="shared_home", action="store_true"
)
_p_run_shared_home.add_argument(
"--termux-home", dest="shared_home", action="store_true"
)
p_run.add_argument(
"--shared-tmp", dest="shared_tmp", action="store_true"
@@ -207,9 +218,10 @@ def build_parser() -> argparse.ArgumentParser:
p_run.add_argument(
"--no-link2symlink", dest="no_link2symlink", action="store_true"
)
p_run.add_argument(
"--no-sysvipc", dest="no_sysvipc", action="store_true"
)
if IS_TERMUX:
p_run.add_argument(
"--no-sysvipc", dest="no_sysvipc", action="store_true"
)
p_run.add_argument(
"--no-kill-on-exit", dest="no_kill_on_exit", action="store_true"
)
@@ -303,38 +315,39 @@ def main() -> None:
msg()
msg(f"{C['BRED']}Error: unable to find proot utility.{C['RST']}")
msg()
if sys.stdin.isatty():
sys.stderr.write(
f"{C['CYAN']}Would you like to install it now? [y/N] {C['RST']}"
)
sys.stderr.flush()
try:
answer = input().strip().lower()
except (EOFError, KeyboardInterrupt):
answer = ""
if answer in ("y", "yes"):
msg()
if IS_TERMUX:
if sys.stdin.isatty():
sys.stderr.write(
f"{C['CYAN']}Would you like to install it now? [y/N] {C['RST']}"
)
sys.stderr.flush()
try:
subprocess.run(
["pkg", "install", "-y", "-q", "proot"], check=True
)
except (subprocess.CalledProcessError, FileNotFoundError) as exc:
answer = input().strip().lower()
except (EOFError, KeyboardInterrupt):
answer = ""
if answer in ("y", "yes"):
msg()
msg(f"{C['BRED']}Error: failed to install proot: "
f"{exc}{C['RST']}")
try:
subprocess.run(
["pkg", "install", "-y", "-q", "proot"], check=True
)
except (subprocess.CalledProcessError, FileNotFoundError) as exc:
msg()
msg(f"{C['BRED']}Error: failed to install proot: "
f"{exc}{C['RST']}")
msg()
sys.exit(1)
else:
msg()
msg(f"{C['CYAN']}Install it manually with: "
f"{C['GREEN']}pkg install proot{C['RST']}")
msg()
sys.exit(1)
else:
msg()
msg(f"{C['CYAN']}Install it manually with: "
msg(f"{C['CYAN']}Install it with: "
f"{C['GREEN']}pkg install proot{C['RST']}")
msg()
sys.exit(1)
else:
msg(f"{C['CYAN']}Install it with: "
f"{C['GREEN']}pkg install proot{C['RST']}")
msg()
sys.exit(1)
sys.exit(1)
if len(sys.argv) < 2 or sys.argv[1] in (
"-h", "--help", "help", "hel", "he", "h"
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+78 -65
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
@@ -31,6 +31,7 @@ import shutil
import textwrap
from proot_distro.constants import (
IS_TERMUX,
PROGRAM_NAME,
PROGRAM_VERSION,
RUNTIME_DIR,
@@ -494,10 +495,13 @@ _HELP_PAGES = {
"configured in /etc/passwd. Alternatively user can specify "
"a custom command to use instead of default shell after "
"command line separator ('--')."
"\n\n"
"By default container is not isolated from the host file"
"system. It is highly discouraged to run destructive commands "
"unless isolated mode enabled."
+ (
"\n\n"
"By default container is not isolated from the host file"
"system. It is highly discouraged to run destructive commands "
"unless isolated mode enabled."
if IS_TERMUX else ""
)
),
"options": [
("--help", "Show this help."),
@@ -507,37 +511,40 @@ _HELP_PAGES = {
"(22 -> 2022, 80 -> 2080, etc). Port shift offset is "
"hardcoded into proot executable itself and can't be "
f"configured through {PROGRAM_NAME}."),
("--isolated",
"Enable Isolated Mode. No host file system bindings created "
"unless using QEMU user mode emulation or user manually "
"requested specific directories to be bound."),
("--minimal",
"Enable Isolated Mode with bare mimimum proot configuration. "
"Only /dev, /proc and /sys are bound. All proot extensions "
"except link2symlink are disabled. No /proc system data "
"workarounds, no kernel release override. Specific features "
"may only be enabled through command line options. Could show "
"higher performance than in other modes."),
("--termux-home",
"Bind Termux home directory into the container. Takes "
"priority over Isolated Mode. Already included in default mode."),
*([("--isolated",
"Enable Isolated Mode. No host file system bindings created "
"unless using QEMU user mode emulation or user manually "
"requested specific directories to be bound.")] if IS_TERMUX else []),
*([("--minimal",
"Enable Isolated Mode with bare mimimum proot configuration. "
"Only /dev, /proc and /sys are bound. All proot extensions "
"except link2symlink are disabled. No /proc system data "
"workarounds, no kernel release override. Specific features "
"may only be enabled through command line options. Could show "
"higher performance than in other modes.")] if IS_TERMUX else []),
("--shared-home",
"Bind host home directory into the container."
+ (" Takes priority over Isolated Mode."
" Already included in default mode." if IS_TERMUX else "")),
("--shared-tmp",
"Bind Termux tmp directory to /tmp. Takes priority over "
"Isolated Mode. Already included in default mode."),
"Bind host tmp directory to /tmp."
+ (" Takes priority over Isolated Mode."
" Already included in default mode." if IS_TERMUX else "")),
("--shared-x11",
"Bind Termux X11 socket directory to /tmp/.X11-unix. "
"Takes priority over Isolated Mode. Inherited by --shared-tmp. "
"Already included in default mode."),
"Bind host X11 socket directory to /tmp/.X11-unix."
+ (" Takes priority over Isolated Mode."
" Inherited by --shared-tmp."
" Already included in default mode." if IS_TERMUX else "")),
("--bind [SRC:DEST]",
"Custom filesystem binding. Can be specified multiple "
"times. Takes priority over Isolated Mode."),
"Custom filesystem binding. Can be specified multiple times."
+ (" Takes priority over Isolated Mode." if IS_TERMUX else "")),
("--no-link2symlink",
"Disable hardlink emulation by proot. Recommended only for "
"devices with SELinux in permissive mode."),
("--no-sysvipc",
"Disable System V IPC emulation by proot. Recommended only "
"for devices where kernel has this feature enabled and "
"SELinux set to permissive mode."),
*([("--no-sysvipc",
"Disable System V IPC emulation by proot. Recommended only "
"for devices where kernel has this feature enabled and "
"SELinux set to permissive mode.")] if IS_TERMUX else []),
("--no-kill-on-exit",
"Hang indefinitely until all session processes exit."),
("--emulator [FILE]",
@@ -557,7 +564,7 @@ _HELP_PAGES = {
"paste into a terminal."),
],
"footer": [
{
*([{
"title": "HOST BINDINGS",
"intro": (
"Without --isolated, the following host paths "
@@ -578,18 +585,21 @@ _HELP_PAGES = {
("/system_ext", None),
("/vendor", None),
],
},
}] if IS_TERMUX else []),
{
"title": "NOTES",
"intro": (
"If host utilities like termux-api do not work, "
"ensure that PATH includes Termux bin directory as "
"well as special environment variables such as "
"ANDROID_ART_ROOT, ANDROID_DATA, ANDROID_I18N_ROOT, "
"ANDROID_ROOT, ANDROID_TZDATA_ROOT, BOOTCLASSPATH, "
"EXTERNAL_STORAGE. Valid values can be retrieved "
"through Termux shell."
"\n\n"
(
"If host utilities like termux-api do not work, "
"ensure that PATH includes Termux bin directory as "
"well as special environment variables such as "
"ANDROID_ART_ROOT, ANDROID_DATA, ANDROID_I18N_ROOT, "
"ANDROID_ROOT, ANDROID_TZDATA_ROOT, BOOTCLASSPATH, "
"EXTERNAL_STORAGE. Valid values can be retrieved "
"through Termux shell."
"\n\n"
if IS_TERMUX else ""
) +
"PRoot-Distro does not guarantee that everything "
"inside given distribution will work flawlessly "
"and is not responsible for that. Thus it is not "
@@ -695,37 +705,40 @@ _HELP_PAGES = {
"(22 -> 2022, 80 -> 2080, etc). Port shift offset is "
"hardcoded into proot executable itself and can't be "
f"configured through {PROGRAM_NAME}."),
("--isolated",
"Enable Isolated Mode. No host file system bindings created "
"unless using QEMU user mode emulation or user manually "
"requested specific directories to be bound."),
("--minimal",
"Enable Isolated Mode with bare mimimum proot configuration. "
"Only /dev, /proc and /sys are bound. All proot extensions "
"except link2symlink are disabled. No /proc system data "
"workarounds, no kernel release override. Specific features "
"may only be enabled through command line options. Could show "
"higher performance than in other modes."),
("--termux-home",
"Bind Termux home directory into the container. Takes "
"priority over Isolated Mode. Already included in default mode."),
*([("--isolated",
"Enable Isolated Mode. No host file system bindings created "
"unless using QEMU user mode emulation or user manually "
"requested specific directories to be bound.")] if IS_TERMUX else []),
*([("--minimal",
"Enable Isolated Mode with bare mimimum proot configuration. "
"Only /dev, /proc and /sys are bound. All proot extensions "
"except link2symlink are disabled. No /proc system data "
"workarounds, no kernel release override. Specific features "
"may only be enabled through command line options. Could show "
"higher performance than in other modes.")] if IS_TERMUX else []),
("--shared-home",
"Bind host home directory into the container."
+ (" Takes priority over Isolated Mode."
" Already included in default mode." if IS_TERMUX else "")),
("--shared-tmp",
"Bind Termux tmp directory to /tmp. Takes priority over "
"Isolated Mode. Already included in default mode."),
"Bind host tmp directory to /tmp."
+ (" Takes priority over Isolated Mode."
" Already included in default mode." if IS_TERMUX else "")),
("--shared-x11",
"Bind Termux X11 socket directory to /tmp/.X11-unix. "
"Takes priority over Isolated Mode. Inherited by --shared-tmp. "
"Already included in default mode."),
"Bind host X11 socket directory to /tmp/.X11-unix."
+ (" Takes priority over Isolated Mode."
" Inherited by --shared-tmp."
" Already included in default mode." if IS_TERMUX else "")),
("--bind [SRC:DEST]",
"Custom filesystem binding. Can be specified multiple "
"times. Takes priority over Isolated Mode."),
"Custom filesystem binding. Can be specified multiple times."
+ (" Takes priority over Isolated Mode." if IS_TERMUX else "")),
("--no-link2symlink",
"Disable hardlink emulation by proot. Recommended only for "
"devices with SELinux in permissive mode."),
("--no-sysvipc",
"Disable System V IPC emulation by proot. Recommended only "
"for devices where kernel has this feature enabled and "
"SELinux set to permissive mode."),
*([("--no-sysvipc",
"Disable System V IPC emulation by proot. Recommended only "
"for devices where kernel has this feature enabled and "
"SELinux set to permissive mode.")] if IS_TERMUX else []),
("--no-kill-on-exit",
"Hang indefinitely until all session processes exit."),
("--emulator [FILE]",
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+35 -32
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
@@ -35,6 +35,7 @@ import sys
from proot_distro.constants import (
CONTAINERS_DIR,
IS_TERMUX,
LEGACY_ROOTFS_DIR,
PREFIX,
TERMUX_HOME,
@@ -309,7 +310,7 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
redirect_ports = getattr(args, "redirect_ports", False)
isolated = getattr(args, "isolated", False)
minimal = getattr(args, "minimal", False)
use_termux_home = getattr(args, "termux_home", False)
use_shared_home = getattr(args, "shared_home", False)
shared_tmp = getattr(args, "shared_tmp", False)
shared_x11 = getattr(args, "shared_x11", False)
no_link2symlink = getattr(args, "no_link2symlink", False)
@@ -434,8 +435,9 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
else:
# Baseline guest env. Always exported on every login.
child_env["PATH"] = DEFAULT_PATH_ENV
child_env["MOZ_FAKE_NO_SANDBOX"] = "1"
child_env["PULSE_SERVER"] = "127.0.0.1"
if IS_TERMUX:
child_env["MOZ_FAKE_NO_SANDBOX"] = "1"
child_env["PULSE_SERVER"] = "127.0.0.1"
# Image-defined Env entries. Blocked vars cannot be overridden.
for entry in _read_manifest_env(container_dir):
@@ -443,8 +445,8 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
if key and key not in _IMAGE_ENV_BLOCKED:
child_env[key] = val
# Android system vars exported only when not running --isolated.
if not isolated:
# Android system vars exported only on Termux and when not --isolated.
if IS_TERMUX and not isolated:
for var in (
"ANDROID_ART_ROOT", "ANDROID_DATA", "ANDROID_I18N_ROOT",
"ANDROID_ROOT", "ANDROID_RUNTIME_ROOT",
@@ -519,14 +521,14 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
else:
inner = [login_shell, "-l"]
if not minimal:
if IS_TERMUX and not minimal:
setup_fake_sysdata(rootfs)
# Ensure Termux bin is always last in PATH so guest tools can invoke
# host Termux utilities. Skipped in --isolated and --minimal modes where
# PREFIX is not bound into the guest. De-duplicates any existing
# occurrence first.
if not isolated and not minimal:
if IS_TERMUX and not isolated and not minimal:
termux_bin = f"{PREFIX}/bin"
components = [
c for c in child_env.get("PATH", "").split(":")
@@ -535,7 +537,7 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
components.append(termux_bin)
child_env["PATH"] = ":".join(components)
if dist_type == "normal" and not isolated and not minimal:
if dist_type == "normal" and IS_TERMUX and not isolated and not minimal:
_inject_termux_profile(rootfs)
# Architecture detection.
@@ -577,7 +579,7 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
if dist_type != "termux" and not no_link2symlink:
proot_args.append("--link2symlink")
if not no_sysvipc and not minimal:
if IS_TERMUX and not no_sysvipc and not minimal:
proot_args.append("--sysvipc")
_ARCH_UNAME_M = {
@@ -587,7 +589,7 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
"x86_64": "x86_64",
"riscv64": "riscv64",
}
if not minimal:
if IS_TERMUX and not minimal:
uname_m = _ARCH_UNAME_M.get(target_arch, os.uname().machine)
proot_args.append(
f"--kernel-release=\\Linux\\{hostname}\\{kernel_release}"
@@ -606,26 +608,27 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
if not minimal:
if dist_type != "termux":
proot_args += [
"--bind=/dev/urandom:/dev/random",
"--bind=/proc/self/fd:/dev/fd",
]
for i, name in ((0, "stdin"), (1, "stdout"), (2, "stderr")):
if os.path.exists(f"/proc/self/fd/{i}"):
proot_args.append(f"--bind=/proc/self/fd/{i}:/dev/{name}")
if IS_TERMUX:
proot_args += [
"--bind=/dev/urandom:/dev/random",
"--bind=/proc/self/fd:/dev/fd",
]
for i, name in ((0, "stdin"), (1, "stdout"), (2, "stderr")):
if os.path.exists(f"/proc/self/fd/{i}"):
proot_args.append(f"--bind=/proc/self/fd/{i}:/dev/{name}")
proot_args.append(f"--bind={rootfs}/sys/.empty:/sys/fs/selinux")
proot_args += fake_proc_bindings(rootfs)
proot_args.append(f"--bind={rootfs}/sys/.empty:/sys/fs/selinux")
proot_args += fake_proc_bindings(rootfs)
tmp_dir = os.path.join(rootfs, "tmp")
os.makedirs(tmp_dir, exist_ok=True)
try:
os.chmod(tmp_dir, 0o1777)
except OSError:
pass
proot_args.append(f"--bind={tmp_dir}:/dev/shm")
tmp_dir = os.path.join(rootfs, "tmp")
os.makedirs(tmp_dir, exist_ok=True)
try:
os.chmod(tmp_dir, 0o1777)
except OSError:
pass
proot_args.append(f"--bind={tmp_dir}:/dev/shm")
if not isolated:
if IS_TERMUX and not isolated:
for data_dir in (
"/data/app", "/data/dalvik-cache",
"/data/misc/apexdata/com.android.art/dalvik-cache",
@@ -655,12 +658,12 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
proot_args += _storage_bindings()
if dist_type == "termux" or not isolated or need_emu:
if IS_TERMUX and (dist_type == "termux" or not isolated or need_emu):
proot_args += _system_bindings()
if dist_type != "termux":
proot_args.append(f"--bind={PREFIX}")
if use_termux_home:
if use_shared_home:
if dist_type == "termux":
proot_args.append(f"--bind={TERMUX_HOME}:{_TERMUX_HOME_INNER}")
elif login_user == "root":
@@ -668,10 +671,10 @@ def command_login(args, configs: dict) -> None: # noqa: ARG001
else:
proot_args.append(f"--bind={TERMUX_HOME}:{login_home}")
if shared_tmp and dist_type != "termux":
if IS_TERMUX and shared_tmp and dist_type != "termux":
proot_args.append(f"--bind={PREFIX}/tmp:/tmp")
if shared_x11 and dist_type != "termux":
if IS_TERMUX and shared_x11 and dist_type != "termux":
proot_args.append(f"--bind={PREFIX}/tmp/.X11-unix:/tmp/.X11-unix")
for bnd in custom_binds:
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+59 -11
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
@@ -19,11 +19,13 @@
#
# Architecture: All global constants and path variables for proot-distro.
# Paths are rooted under TERMUX_PREFIX (env var), which defaults to the
# standard Termux installation prefix. Changing this env var allows running
# proot-distro against a custom Termux installation.
# On Termux/Android, paths are rooted under TERMUX_PREFIX (env var). On a
# regular Linux host, XDG base directories (~/.local/share, ~/.cache) are
# used instead. IS_TERMUX is computed once at import time and drives both
# path selection and runtime behaviour (e.g. isolated-mode default).
import os
import platform
from importlib.metadata import version, PackageNotFoundError
PROGRAM_NAME = "proot-distro"
@@ -38,6 +40,34 @@ os.umask(0o022)
# Keep LD_PRELOAD for restoring after proot invocations.
_SAVED_LD_PRELOAD = os.environ.get("LD_PRELOAD", "")
# ---------------------------------------------------------------------------
# Termux / Android detection
# ---------------------------------------------------------------------------
def _detect_termux() -> bool:
"""Return True when running inside Termux on Android."""
# Termux-specific env var — always set by the Termux shell.
if os.environ.get("TERMUX_PREFIX"):
return True
# Standard Android system env var present in every Android process.
if os.environ.get("ANDROID_ROOT"):
return True
# platform.platform() reports "android" on Python builds for Android.
try:
if "android" in platform.platform().lower():
return True
except Exception:
pass
# /system/build.prop exists on every Android device.
if os.path.isfile("/system/build.prop"):
return True
return False
IS_TERMUX: bool = _detect_termux()
# ---------------------------------------------------------------------------
# Paths
# ---------------------------------------------------------------------------
@@ -48,8 +78,18 @@ PREFIX = os.environ.get(
TERMUX_HOME = os.environ.get("HOME", "/data/data/com.termux/files/home")
TERMUX_APP_PACKAGE = os.environ.get("TERMUX_APP_PACKAGE", "com.termux")
RUNTIME_DIR = os.path.join(PREFIX, "var", "lib", "proot-distro")
DOWNLOAD_CACHE_DIR = os.path.join(RUNTIME_DIR, "dlcache")
if IS_TERMUX:
RUNTIME_DIR = os.path.join(PREFIX, "var", "lib", "proot-distro")
DOWNLOAD_CACHE_DIR = os.path.join(RUNTIME_DIR, "dlcache")
else:
_xdg_data = os.environ.get("XDG_DATA_HOME") or os.path.join(
os.path.expanduser("~"), ".local", "share"
)
_xdg_cache = os.environ.get("XDG_CACHE_HOME") or os.path.join(
os.path.expanduser("~"), ".cache"
)
RUNTIME_DIR = os.path.join(_xdg_data, "proot-distro")
DOWNLOAD_CACHE_DIR = os.path.join(_xdg_cache, "proot-distro")
# New container storage layout: containers/<name>/manifest.json + rootfs/
CONTAINERS_DIR = os.path.join(RUNTIME_DIR, "containers")
@@ -67,11 +107,19 @@ MANIFEST_CACHE_DIR = os.path.join(DOWNLOAD_CACHE_DIR, "manifests")
DEFAULT_PRIMARY_NS = "8.8.8.8"
DEFAULT_SECONDARY_NS = "8.8.4.4"
DEFAULT_PATH_ENV = (
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
":/usr/local/games:/usr/games"
f":{PREFIX}/bin:/system/bin:/system/xbin"
)
if IS_TERMUX:
DEFAULT_PATH_ENV = (
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
":/usr/local/games:/usr/games"
f":{PREFIX}/bin:/system/bin:/system/xbin"
)
else:
DEFAULT_PATH_ENV = (
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
":/usr/local/games:/usr/games"
)
DEFAULT_FAKE_KERNEL_RELEASE = "6.17.0-PRoot-Distro"
DEFAULT_FAKE_KERNEL_VERSION = (
"#1 SMP PREEMPT_DYNAMIC Fri, 10 Oct 2025 00:00:00 +0000"
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Proot-Distro - manage proot containers on Termux.
# Proot-Distro - manage proot containers.
#
# Created by Sylirre <sylirre@termux.dev> for Termux project.
# Development assisted by Claude Code (https://claude.ai/code).