-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Termux execution environment
The following docs details how execution and dynamic linking happens in Termux, including issues/errors related to them and what path related environment variables are exported by Android and Termux by default.
- Execution
- Termux App Child Process Forking
- Execution Errors
- Dynamic Library Linking
- Dynamic Library Linking Errors
- Listing and Searching Libraries and Symbols
- Path Environment Variables
- Path Environment Variables Exported By Android
- Path Environment Variables Exported By Termux
Termux executes programs natively on Android host OS by default, without any emulation or containerization (docker/VM/chroot/proot), and uses the Android host kernel underneath, which is based on Linux kernel, and does not use a custom kernel. Programs are compiled with Android NDK
and dynamically linked against Android system bionic
(1, 2) libraries under /system/lib[64]
, which also provides libc
as C standard library. Programs are not linked against glibc
(1, 2) like done on other linux distros, like debian
, and hence there are differences between the two, i.e bionic
is not as featured and ported programs may require patches. Check here for some differences.
However, support for emulation is also optionally available for the user with proot
(1, 2, 3, 4) and qemu
(1, 2) without root
, and also for chroot
(1, 2, 3) with root
.
For info on how Termux app forks child processes from its main app
process to run foreground terminals (TermuxSessions
) or a background tasks (TermuxTasks
), check Termux App Child Process Forking section below.
For info on execution errors, check Execution Errors section below.
For info on $PATH
, $LD_LIBRARY_PATH
, $LD_PRELOAD
environment variables exported by Android and Termux for execution and dynamic linking, check Path Environment Variables, Path Environment Variables Exported By Android, Path Environment Variables Exported By Termux.
For info on Android and Termux filesystems, and Termux private app data directory, check Termux Filesystem Layout docs.
Termux packages in the app bootstrap (1, 2), primary packages repository and its mirrors are specifically compiled for the rootfs
directory /data/data/com.termux/files
, based on the Termux app package name com.termux
and the expected private app data directory /data/data/com.termux
android would assign to the app on installation if its installed on the primary user 0
of the device. These packages would not work for any other app package name or a different app data or rootfs
directory, and packages must be compiled specifically for any such changes, like in case forking the app with a different package name or installing Termux app on a secondary user, work profile or adoptable storage. In addition to the rootfs
directory, the core
and apps
directories are also used by the Termux apps and certain packages for certain things. During build time, the termux-packages
build-package.sh
scripts loads the app package name and directory paths that are set in properties.sh
, which are primarily defined by the $TERMUX_APP__PACKAGE_NAME
, $TERMUX_APP__DATA_DIR
, $TERMUX__PROJECT_DIR
, $TERMUX__CORE_DIR
, $TERMUX__APPS_DIR
, $TERMUX__ROOTFS
, $TERMUX__HOME
, and $TERMUX__PREFIX
variables. Check Build environment and Building packages docs for more info on how packages are built.
For info on which packages are available on Termux app installation by default and how they are built, check bootstrap docs.
When Android starts an Termux app, it only creates a single main app
process for it with the process name that equals its package name com.termux
. (1, 2) Moreover, no additional service process
or isolatedProcess
are used by Termux.
When Termux app needs to start foreground terminals (TermuxSessions
) or background tasks (TermuxTasks
), to run a shell, binary or script command, it forks a child process from its main app
process and then calls one of the exec()
family of functions in the child process to replace it with the desired command. These child processes are called phantom processes internally by Android, i.e any process that has been forked from the main app
process and is now either a child of the app
process or of init
process, check Phantom, Cached And Empty Processes docs for more info on phantom processes.
The exec()
family of functions are declared in unistd.h
and implemented by exec.cpp
in android bionic
libc
library. The exec()
functions are wrappers around the execve()
system call listed in syscalls(2)
provided by the android/linux kernel, which can also be directly called with the syscall(2)
library function declared in unistd.h
. Note that there is also a execve()
wrapper in unistd.h
around the execve()
system call.
The termux-exec
library is also loaded with $LD_PRELOAD
when commands are executed, which overrides the entire exec()
family of functions, but will not override direct calls to the execve()
system call via syscall(2)
, which is usually not directly called by programs. It overrides the functions to solve the issues related to App Data File Execute Restrictions and Linux vs Termux bin
paths when exec-ing files in Termux. Check termux-exec
exec()
docs for more info.
See also:
- exec (system call) wiki
unistd.h
POSIX specexecve
POSIX specexecve(2)
linux manexec(3)
linux manexec(3p)
linux manfork
POSIX specfork(2)
linux man
Termux uses Runtime.exec()
for TermuxTasks
and execvp()
for TermuxSessions
to fork processes from its main app
process. The new child processes that are started may then call the exec()
family of functions to fork even more nested child processes.
The Runtime.exec()
is the Java
API that forks a child processes and calls execvpe()
. The parent of the child process remains the main app
process itself.
Termux uses this for running background TermuxTasks
, which are managed by the foreground TermuxService
. These background tasks can be sent via the RUN_COMMAND Intent
and by Termux plugins like termux-boot
, termux-tasker
and termux-widget
. They show as <n> tasks
in the Termux
notification.
Call stack: Runtime.exec()
-> ProcessBuilder.start()
-> ProcessImpl.start()
-> UNIXProcess()
-> UNIXProcess_md.forkAndExec()
-> UNIXProcess_md.startChild()
(note on forking for clone()
, vfork()
and fork()
usage) -> UNIXProcess_md.childProcess()
-> UNIXProcess_md.JDK_execvpe()
-> exec.execvpe()
The execvp()
is part of the native exec()
family of functions that replaces the current process image with a new process image. This can be called by the child process that has been spawned from the app
process after it calls fork()
. These functions can be called in native c/c++
code via JNI
by an app.
Termux uses this for running foreground TermuxSessions
, which are managed by the foreground TermuxService
. The TermuxSession
creates a TerminalSession
that calls create_subprocess
via JNI
defined in termux.c
, which then calls fork()
and the child process calls execvp()
. By default, if no custom command is passed to run in the TerminalSession
, the /data/data/com.termux/files/usr/bin/login
script is called, which runs exec "$SHELL"
to replace itself with the login
shell defined, which defaults to /data/data/com.termux/files/usr/bin/bash
.
The daemon()
function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons. The child process forked from the parent process basically detaches itself from the parent so that it is no longer its parent process (ppid
) and is inherited by the init
(pid
1
) process.
Termux app does not start daemons itself but it can be done by programs that may be started by users themselves, like with sshd
and crond
commands. If sshd
command is run, the ps
output will show sshd
to have init
(pid
1
) as the ppid
, instead of pid
of its original parent bash
. These daemons have a higher chance of getting killed since there are no longer attached to the app
process. Optionally, processes may not be daemonized (like by running sshd -D
) and kept in the foreground so that they are still tied to the app
process as that would make it less likely for them to get killed, assuming phantom process killer has been disabled. Some vendors also have additional daemon process killers.
The following issues may occur when executing files in termux.
- File Execution And Special File Features Not Allowed In External Storage
- Some Files Cannot Be Executed Under
/system/bin
$PATH
contains incompatible directory paths- App Data File Execute Restrictions
- Linux vs Termux
bin
paths
The shared/public/primary external storage for internal sd card or for external sd card in device slot formatted as adoptable storage is mounted at /storage/emulated/<user_id>
(or its shortcut /sdcard
), and reliable secondary external storage for external sd card in device slot formatted as portable storage are mounted at /storage/XXXX-XXXX
. These mounts emulate the fat32
filesystem and use the sdcardfs
(1) or fuse
(1, 2) filesystems depending on Android version/build, (1, 2) and use the noexec
mount
flag. These mounts and are accessible to apps with direct file-access if storage permission (1, 2) is granted or via SAF APIs. The Android/data
and Android/obb
directories are mounted with a tmpfs
filesystem and also have the noexec
mount
flag. (1)
The reliable secondary external storage for external sd card in device slot is initially mounted at /mnt/media_rw/XXXX-XXXX
with their original filesystem before being mounted at /storage/XXXX-XXXX
with an emulated filesystem. The unreliable secondary external storages, like for USB OTG drives are only mounted at /mnt/media_rw/XXXX-XXXX
with their original filesystem, but not mounted at /storage/XXXX-XXXX
with an emulated filesystem. These initial mounts primarily only support the exfat
(1, 2) and related filesystems, or in some cases the ext4
(1, 2) filesystem, and also use the noexec
mount
flag. The /mnt/media_rw/XXXX-XXXX
mounts for reliable storages are not accessible to apps without root access. The /mnt/media_rw/XXXX-XXXX
mounts for unreliable storages are accessible to apps with root access, or with the MANAGE_EXTERNAL_STORAGE
permission on Android >= 12
. (1)
Following are some of the features not supported by external storage filesystems like at /sdcard
//storage/emulated/0
that emulate a fat
filesystem, which are supported by other filesystems that are commonly used on Linux distros and for Android private app data directory, like ext4
or f2fs
filesystems.
-
Files cannot be executed directly with their path due to the
noexec
mount
flag, like with/sdcard/file
or./file
. However, if the file is script file instead of a binary file, then it can be passed to its respective shell for it to be executed, like withbash /sdcard/script
. However, it is highly recommended to not execute files on public storages that can be accessed by other apps as it is a huge security risk, since other malicious apps could modify such files and when user executes them in Termux, malicious code could run in Termux user context, or evenroot
user context if Termux app has been granted root permissions. - No hard or soft symlink files can be created.
- Files do support modifications of file permissions or ownership attributes.
-
Filenames are case insensitive, i.e
foo
andFOO
andFoO
, etc would be considered the same file.
Due, to these issues, using external storage directories will cause problems for certain programs, like creating git
repositories or building software that require special features, check termux/termux-app#3385
and termux/termux-app#3777
.
However, the Termux private app data directory is not mounted with the noexec
mount
flag, and is usually the ext4
or f2fs
filesystem, which supports symlinks and other file attributes. This directory is also not accessible to any other app by default and is safe to use, unless access is explicitly granted by user to it by installing a sharedUserId
plugin app or via Storage Access Framework (SAF) or Termux APIs.
It is highly recommended to only keep Termux files under its $HOME
(~/
) or $TERMUX__PREFIX
directories, but not ~/storage
directories as directories under it would be symlinks to external storage directories created by termux-setup-storage
.
The Android system provided executables that primarily exist under /system/bin
cannot all be executed by all apps and users as Android has different protections in place.
-
The files are assigned different ownership and permissions (DAC) by Android. This prevents some executables from being executed by app processes or even the
shell
user. Most files have theroot:shell
ownership andrwxr-xr-x
permissions, allowingread
andexecute
byother
users. However, some files likesecilc
anduncrypt
haveroot:root
ownership and do not allowother
users toexecute
them, including theshell
user. Some files like,run-as
haveroot:shell
ownership, butrwxr-x---
permissions, preventing anyother
user thanroot
orshell
toexecute
them. Attempting to execute such files with the wrong user would result in thePermission denied
error. -
The files are assigned different SeLinux file context types (MAC) by Android. (1) There are around
92
different context types on Android14
. Different SeLinux policies exist for different process context types which define whether a process can execute a file with a specific file context. (1, 2, 3) This prevents some executables from being executed by app processes or even theshell
user. For example,auditctl
requires executing it as theroot
user. Attempting to execute such files with the wrong user will result in theinaccessible or not found
error and a SeLinuxavc
denied message will be logged inlogcat
, likeavc: denied { getattr } for path="/system/bin/auditctl" dev="dm-6" ino=161 scontext=u:r:shell:s0 tcontext=u:object_r:auditctl_exec:s0 tclass=file
. Getting file attributes, like withls
will also fail for such files if not running as allowed user likeroot
. There are also SeLinux policies other than for process/file context types that trigger other errors, like for thecmd
command. -
There are additional internal checks during execution for calling
uid
and calling packages as well. Some commands can only be executed by privileged users likeroot
orshell
, likeam
command can only be executed by them on Android>= 14
. Some commands, like ones that are run throughsvc
may require a package name, and cannot be executed asroot
, since it does not have a package name, and requires running them as theshell
user, which does have thecom.android.shell
package name. -
The are additional internal checks during execution for whether the process has been granted a permission to be able to run the specified command. The permissions are declared in the Android framework
AndroidManifest.xml
underRuntime permissions
orInstall permissions
sections.
The shell
(2000
) user for the com.android.shell
app package, and for commands that are run with adb shell
(here shell
refers to CLI, not the user) is a privileged user on Android that is allowed to run a lot of things and make lot of changes, however, it is generally not as privileged as the root user, other than when a package name is required. It has additional SeLinux policies that allow it to execute certain commands that cannot be executed by untrusted app processes, like ones that give it access to call specific android internal services. (1, 2, 3) It also has additional permissions granted to it by default by Android that are checked when certain commands are run, like for cmd
, am
, pm
and svc
commands.
Following is a truncated list of executables under /system/bin
that are available on Android 14
, only some of the commonly used commands are listed for brevity.
# /system/bin/ls -1lZ /system/bin | /system/bin/sed -E 's/^([^ ]+)[ ]+[^ ]+[ ]+([^ ]+[ ]+[^ ]+[ ]+[^ ]+)[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+(.*)$/\1 \2 \3/' | sort -k4
-rwxr-xr-x root shell u:object_r:auditctl_exec:s auditctl
-rwxr-xr-x root shell u:object_r:blkid_exec:s blkid
-rwxr-xr-x root shell u:object_r:e2fs_exec:s make_f2fs
-rwxr-xr-x root shell u:object_r:fsck_exec:s e2fsck
-rwxr-xr-x root shell u:object_r:logcat_exec:s logcat
-r-xr-x--- logd logd u:object_r:logd_exec:s logd
-rwxr-xr-x root shell u:object_r:mtp_exec:s mtpd
-rwxr-xr-x root shell u:object_r:netd_exec:s netd
-rwxr-x--- root shell u:object_r:runas_exec:s run-as
-rwxr-xr-x root shell u:object_r:sdcardd_exec:s sdcard
-rwxr-xr-x root shell u:object_r:shell_exec:s sh
-rwxr-x--- root shell u:object_r:simpleperf_app_runner_exec:s simpleperf_app_runner
-rwxr-xr-x root shell u:object_r:storaged_exec:s storaged
-rwxr-xr-x root shell u:object_r:system_file:s am
lrwxrwxrwx root shell u:object_r:system_file:s app_process -> app_process64
-rwxr-xr-x root shell u:object_r:system_file:s appops
-rwxr-xr-x root shell u:object_r:system_file:s awk
-rwxr-xr-x root shell u:object_r:system_file:s bc
-rwxr-xr-x root shell u:object_r:system_file:s bmgr
lrwxrwxrwx root shell u:object_r:system_file:s cat -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chattr -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chcon -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chgrp -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chmod -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chown -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chroot -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s chrt -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s cmd
-rwxr-xr-x root shell u:object_r:system_file:s content
lrwxrwxrwx root shell u:object_r:system_file:s cp -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s cut -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s date -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s dd -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s debuggerd
-rwxr-xr-x root shell u:object_r:system_file:s device_config
lrwxrwxrwx root shell u:object_r:system_file:s dmesg -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s dpm
-rwxr-xr-x root shell u:object_r:system_file:s dumpsys
lrwxrwxrwx root shell u:object_r:system_file:s echo -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s env -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s file -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s find -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s flock -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s getconf -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s getenforce -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s getevent -> toolbox
lrwxrwxrwx root shell u:object_r:system_file:s getprop -> toolbox
lrwxrwxrwx root shell u:object_r:system_file:s grep -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s groups -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s gsi_tool
lrwxrwxrwx root shell u:object_r:system_file:s id -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s ime
-rwxr-xr-x root shell u:object_r:system_file:s input
lrwxrwxrwx root shell u:object_r:system_file:s linker_asan -> /apex/com.android.runtime/bin/linker
lrwxrwxrwx root shell u:object_r:system_file:s linker_asan64 -> /apex/com.android.runtime/bin/linker64
lrwxrwxrwx root shell u:object_r:system_file:s linker_hwasan64 -> /apex/com.android.runtime/bin/linker64
lrwxrwxrwx root shell u:object_r:system_file:s ln -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s ls -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s lsattr -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s lsof -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s lspci -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s lsusb -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s monkey
lrwxrwxrwx root shell u:object_r:system_file:s mount -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s mountpoint -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s mv -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s nice -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s nohup -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s nsenter -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s pidof -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s ping
-rwxr-xr-x root shell u:object_r:system_file:s ping6
-rwxr-xr-x root shell u:object_r:system_file:s pm
lrwxrwxrwx root shell u:object_r:system_file:s printf -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s ps -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s pwd -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s readelf -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s readlink -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s realpath -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s reboot
lrwxrwxrwx root shell u:object_r:system_file:s restorecon -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s rm -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s screencap
-rwxr-xr-x root shell u:object_r:system_file:s screenrecord
-rwx------ root root u:object_r:system_file:s secilc
lrwxrwxrwx root shell u:object_r:system_file:s sed -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s sendevent -> toybox
-rwxr-xr-x root shell u:object_r:system_file:s service
lrwxrwxrwx root shell u:object_r:system_file:s setenforce -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s setprop -> toolbox
-rwxr-xr-x root shell u:object_r:system_file:s settings
lrwxrwxrwx root shell u:object_r:system_file:s start -> toolbox
lrwxrwxrwx root shell u:object_r:system_file:s stat -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s stop -> toolbox
-rwxr-xr-x root shell u:object_r:system_file:s svc
lrwxrwxrwx root shell u:object_r:system_file:s top -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s umount -> toybox
lrwxrwxrwx root shell u:object_r:system_file:s uname -> toybox
lrwxrwxrwx root shell u:object_r:system_linker_exec:s linker -> /apex/com.android.runtime/bin/linker
lrwxrwxrwx root shell u:object_r:system_linker_exec:s linker64 -> /apex/com.android.runtime/bin/linker64
-rwxr-xr-x root shell u:object_r:tcpdump_exec:s tcpdump
-rwxr-xr-x root shell u:object_r:toolbox_exec:s toolbox
-rwxr-xr-x root shell u:object_r:toolbox_exec:s toybox
-rwxr-x--- root root u:object_r:uncrypt_exec:s uncrypt
-rwxr-xr-x root shell u:object_r:zygote_exec:s app_process32
-rwxr-xr-x root shell u:object_r:zygote_exec:s app_process64
By default, Termux exports only termux bin path(s) /data/data/com.termux/files/usr/bin
in the $PATH
variable for Android >= 7
and /data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/bin/applets
for Android < 7
, but not the /system/bin
path for Android system bin path, since normally, users should only use termux provided binaries.
If system provided binaries need to be executed, then /system/bin
can be either be set or appended at end of $PATH
, like /data/data/com.termux/files/usr/bin:/system/bin
.
However, if Termux app is using targetSdkVersion
>= 29
with the termux-exec
system_linker_exec
workaround and a system command under /system/bin
is executed and $PATH
is set to or contains $TERMUX__PREFIX/bin
before /system/bin
, then commands may fail. Termux provides wrappers under $TERMUX__PREFIX/bin
for some system commands, like for /system/bin/cmd
. (1, 2) If the utilities like /system/bin/am
, /system/bin/pm
and /system/bin/settings
that run cmd
command themselves are executed without $LD_PRELOAD
being set, then $TERMUX__PREFIX/bin/cmd
wrapper will attempted to be executed instead of the real /system/bin/cmd
, which will fail with the Permission denied
error and a SeLinux avc
denied message will be logged in logcat
, like avc: denied { execute_no_trans } for path="/data/data/com.termux/files/usr/bin/cmd" dev="dm-55" ino=46573 scontext=u:r:untrusted_app:s0:c29,c257,c512,c768 tcontext=u:object_r:app_data_file:s0:c29,c257,c512,c768 tclass=file permissive=0 app=com.termux
due to App Data File Execute Restrictions
for $TERMUX__PREFIX/bin/cmd
being engaged. For example, if out="$(LD_PRELOAD= /system/bin/pm path com.termux 2>&1 </dev/null)"; echo "$out"
is executed. However, if $LD_PRELOAD
was set to termux-exec
, then it would hook the exec()
call to bypass the restriction, but that's generally not advisable to be set when running system commands. See also termux/termux-tools@be50057f
.
To prevent such issues, make sure termux bin paths do not exist in $PATH
when running system binaries, like by:
- Setting it manually in current process environment before running the command with
PATH=/system/bin
. - Setting it temporarily for a single command with
LD_LIBRARY_PATH= LD_PRELOAD= PATH=/system/bin command [args...]
. - Use
tudo
andsudo
commands with the-A
or-AA
flags.
If Termux app is running on Android >= 10
and uses targetSdkVersion
>= 29
, then as part of Android W^X
restrictions with the 0dd738d8
commit via SeLinux policies, it will not be able to exec()
its app data files, like under the /data/data/<package_name>
(for user 0
) directory.
Check App Data File Execute Restrictions
android docs for more information on the W^X
restrictions, including that apply to other app domains.
Check termux-exec
App Data File Execute Restrictions
docs for more info on a working workaround using system_linker_exec
.
If binaries under /bin
or /usr/bin
directories or scripts with /bin/*
or /usr/bin/*
shebang interpreter paths are executed without termux-exec
being set in $LD_PRELOAD
, they will either fail to execute with No such file or directory
errors or will execute the android system binaries under /system/bin/*
(as /bin
is a symlink to /system/bin
) if the same filename exists, instead of executing binaries under the Termux bin
path /data/data/com.termux/files/usr/bin
. Check termux-exec
Linux vs Termux
bin paths
and termux-tasker
Termux Environment
docs for more info.
The dynamic linker is the part of the operating system that loads and links the shared libraries needed by an executable when it is executed. The kernel is normally responsible for loading both the executable and the dynamic linker. When a execve()
system call is made for an ELF
executable, the kernel loads the executable file, then reads the path to the dynamic linker from the PT_INTERP
entry in ELF
program header table and then attempts to load and execute this other executable binary for the dynamic linker, which then loads the initial executable image and all the dynamically-linked libraries on which it depends and starts the executable. For binaries built for Android, PT_INTERP
specifies the path to /system/bin/linker64
for 64-bit binaries and /system/bin/linker
for 32-bit binaries. The ELF
file headers can be checked with the readelf
command, like readelf --program-headers --dynamic /path/to/executable
.
For Android, libraries are opened and loaded by the system linker (/system/bin/linker[64]
) as per the following order. Check ld.so
and dlopen
man page and Android system linker source (1, 2, 3, 4, 5, 6, 7) for more info.
- If library name contains a path separator
/
like for a relative or absolute path, then it is attempted to be directly opened. - Else if library name does not contain a path separator
/
, then following directory paths are searched in-order non-recursively for file with the samebasename
as the library name:- The directory paths in the
$LD_LIBRARY_PATH
environment variable. - The directory paths in the
DT_RUNPATH
dynamic section attribute of the binary, if present, but only for library dependency is listed asDT_NEEDED
. - The default system library paths like
/system/lib64
,/system/lib
.
- The directory paths in the
Note that for android, if full library path contains !/
, then system linker assumes that the library file may exist inside a zip
/apk
file and will attempt to open the library inside the zip
file before opening full library path itself. (1, 2). For example /path/to/foo.apk!/lib/arm64/bar.so
would open the lib/arm64/bar.so
library inside the /path/to/foo.apk
apk
file.
The DT_RPATH
dynamic section attribute of the binary and the ld
cache file (/etc/ld.so.cache
) like other systems is not used.
For info on dynamic linking errors, check Dynamic Library Linking Errors section below.
For info on $PATH
, $LD_LIBRARY_PATH
, $LD_PRELOAD
environment variables exported by Android and Termux for execution and dynamic linking, check Path Environment Variables, Path Environment Variables Exported By Android, Path Environment Variables Exported By Termux.
If opening, loading and linking the library fails, then the system linker will generate error the CANNOT LINK EXECUTABLE
error, with sub errors like library <library> not found
and cannot locate symbol <symbol> referenced by <executable/dependency_library>
, etc. Following are the possible reasons in Termux for linker errors.
- Package dependencies are outdated
$LD_LIBRARY_PATH
contains incompatible directory paths- System Libraries are missing
Termux packages use a rolling release update model. All packages must be upgraded together and partial upgrades are not supported in Termux, which are supported on some other Linux distributions.
If a package is upgraded and its dependency packages are not, then linker errors may trigger. This is because the updated package may be requiring different libraries or different symbols in libraries than the one provided by the old dependency library currently installed. So all executables and their dependency libraries may require being upto date to be compatible.
To prevent or fix such issues, upgrade all packages.
pkg upgrade
The pkg
command is a wrapper script in Termux around the apt
or pacman
package managers, depending on the package manager being used by the user in the Termux rootfs.
The pkg
command depends on curl
, so if curl
gets broken, then instead run apt update && apt full-upgrade
if using apt
and pacman -Syu
if using pacman
.
If apt
or pacman
itself gets broken, then their package and dependency deb
/tar
files will have to be manually downloaded from the termux main
packages repository and then installed. Otherwise, $TERMUX__PREFIX
can be deleted or the Termux app reinstalled, but that will result in all Termux package data being lost and will require reinstalling packages again, though $HOME
can be preserved if just deleting $TERMUX__PREFIX
.
As detailed in above sections:
- Android
>= 7
, the$LD_LIBRARY_PATH
variable must not contain$TERMUX__PREFIX/lib
or/system/lib[64]
paths. - Android
< 7
, the$LD_LIBRARY_PATH
variable must only contain$TERMUX__PREFIX/lib
when executing a termux executable under$TERMUX__ROOTFS
, and must not contain$TERMUX__PREFIX/lib
or/system/lib[64]
paths when executing an android provided executable, like under/system
partition.
This is because if $LD_LIBRARY_PATH
is set, then the wrong library may be selected by the linker when searching instead of as per DT_RUNPATH
or default system libraries. To fix this:
- Do not set
$LD_LIBRARY_PATH
in the environment, like with shell rc files (~/.bashrc
,~/.profile
, etc). - Unset it in the current process environment before running the command with
unset LD_LIBRARY_PATH
. - Just unset it temporarily for a single command with
LD_LIBRARY_PATH= command [args...]
.
Unsetting both $LD_LIBRARY_PATH
and $LD_PRELOAD
is especially necessary for android system commands under /system/bin
, like with LD_LIBRARY_PATH= LD_PRELOAD= command [args...]
, the termux provided wrappers under $TERMUX__PREFIX/bin
for some system commands already do this. (1, 2) The tudo
and sudo
commands can also be used with the -A
or -AA
flags.
The ffmpeg
executable is one example for this. Check Listing and Searching Libraries and Symbols docs for info on the helper functions used below.
The termux ffmpeg
depends on system provided libgui.so
, which recursively depends on system provided libEGL.so
itself. If $LD_LIBRARY_PATH
contains $TERMUX__PREFIX/lib
, then the wrong termux provided libEGL.so
library from the libglvnd
package at $TERMUX__PREFIX/lib/libEGL.so
would get selected instead of the system provided one at /system/lib64/libgui.so
, which will not contain the required eglDestroySyncKHR
symbol, causing a linker error.
$ LD_LIBRARY_PATH="$TERMUX__PREFIX/lib" ffmpeg
CANNOT LINK EXECUTABLE "ffmpeg": cannot locate symbol "eglDestroySyncKHR" referenced by "/system/lib64/libgui.so"...
$ LD_LIBRARY_PATH="$TERMUX__PREFIX/lib:/system/lib64:/system/lib" ffmpeg
CANNOT LINK EXECUTABLE "ffmpeg": cannot locate symbol "eglDestroySyncKHR" referenced by "/system/lib64/libgui.so"...
$ search_dynamic_symbol " eglDestroySyncKHR" 3
/system/lib64/libEGL.so
000000000001b5cc T eglDestroySyncKHR
--
/system/lib/libEGL.so
000130e8 T eglDestroySyncKHR
$ list_library_dependencies "/system/lib64/libgui.so" 1 | grep libEGL
libEGL.so => /system/lib64/libEGL.so
$ dpkg -S "$TERMUX__PREFIX/lib/libEGL.so"
libglvnd: /data/data/com.termux/files/usr/lib/libEGL.so
$ list_dynamic_symbols "$TERMUX__PREFIX/lib/libEGL.so" | grep " eglDestroySyncKHR"
The termux ffmpeg
depends on termux provided libavformat.so
from the ffmpeg
package, which recursively depends on termux provided libssh.so
itself from the libssh
package. If $LD_LIBRARY_PATH
contains /system/lib64:/system/lib
, then the wrong system provided libssh.so
library at /system/lib64/libssh.so
would get selected instead of the termux provided one at $TERMUX__PREFIX/lib/libssh.so
, which will not contain the required sftp_read
symbol, causing a linker error.
$ LD_LIBRARY_PATH="/system/lib64:/system/lib" ffmpeg
CANNOT LINK EXECUTABLE "ffmpeg": cannot locate symbol "sftp_read" referenced by "/data/data/com.termux/files/usr/lib/libavformat.so.60.3.100"...
$ search_dynamic_symbol "sftp_read@" 3
/data/data/com.termux/files/usr/lib/libssh.so
000000000005b81c T sftp_read@@LIBSSH_4_5_0
$ list_library_dependencies "$TERMUX__PREFIX/lib/libavformat.so" 1 | grep libssh
libssh.so => /data/data/com.termux/files/usr/lib/libssh.so
$ dpkg -S "$TERMUX__PREFIX/lib/libavformat.so"
ffmpeg: /data/data/com.termux/files/usr/lib/libavformat.so
$ dpkg -S "$TERMUX__PREFIX/lib/libssh.so"
libssh: /data/data/com.termux/files/usr/lib/libssh.so
$ search_dynamic_library libssh.so 3
/data/data/com.termux/files/usr/lib/libssh.so
/system/lib64/libssh.so
Termux packages may depend on android system libraries that are considered stable APIs by NDK
. These vary depending on Android version, and can be checked by reading /system/etc/public.libraries.txt
on a specific device. Check NDK
(Stable APIs docs, meta/system_libs.json
, build/core/system_libs.mk
, build/cmake/system_libs.cmake
), system core (/etc/public.libraries.android.txt
), system linker (linker_translate_path.cpp
), and ART
(buildbot-build.sh
) for more info.
The libraries are assumed to exist on all Android devices depending on Android version, but may not exist on emulated Termux environments, like termux-docker
. This causes linker errors for certain packages if a required library is not available.
For example, ffmpeg
executable depends on libandroid.so
, which isn't available in termux-docker
and requires installing the libandroid-stub
package to be able to execute the ffmpeg
command. The libandroid-stub
package installs a stub version of the library at $TERMUX__PREFIX/lib/libandroid.so
, which also does not depend on any other system libraries. Check libandroid-stub
package build.sh
, f3043a2e
, 807c36d1
, termux/termux-packages#16680
and termux/termux-packages#16902
for more info.
# /etc/public.libraries.android.txt
# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
libandroid.so
libaaudio.so
libamidi.so
libbinder_ndk.so
libc.so
libcamera2ndk.so
libclang_rt.hwasan-aarch64-android.so 64 nopreload
libdl.so
libEGL.so
libGLESv1_CM.so
libGLESv2.so
libGLESv3.so
libicu.so
libicui18n.so
libicuuc.so
libjnigraphics.so
liblog.so
libmediandk.so
libm.so
libnativehelper.so
libnativewindow.so
libneuralnetworks.so nopreload
libOpenMAXAL.so
libOpenSLES.so
libRS.so
libstdc++.so
libsync.so
libvulkan.so
libwebviewchromium_plat_support.so
libz.so
The following methods can be used after exporting them in a bash
shell to list and search libraries or their symbols. Copy and paste them in the terminal or source
them, like by adding them to ~/.bashrc
and starting a new interactive bash
shell.
For the search_*
methods, the mode
parameter should be between 1-3
inclusive.
- If
1
is passed, only$TERMUX__PREFIX
paths are searched. - If
2
is passed, only/system/lib[64]
paths are searched. - If
3
is passed, both$TERMUX__PREFIX
and/system/lib[64]
paths are searched.
# search_dynamic_library library_name_regex mode [additional_grep_options]
search_dynamic_library() {
local library="$1"; local mode="$2"; shift 2;
[ -z "$library" ] && { echo "library not passed." 1>&2; return 1; };
case "$mode" in ''|*[!1-3]*) echo "mode '$mode' passed is invalid. It must be between 1-3." 1>&2; return 1;;esac
local -a paths=();
{ [ "$mode" = "1" ] || [ "$mode" = "3" ]; } && paths+=("${TERMUX__PREFIX:-$PREFIX}");
{ [ "$mode" = "2" ] || [ "$mode" = "3" ]; } && { [ -d "/system/lib64" ] && paths+=("/system/lib64"); paths+=("/system/lib"); };
find "${paths[@]}" -name "*.so" -print 2>/dev/null | grep -E "$@" -- "$library"
}
# search_static_library library_name_regex mode [additional_grep_options]
search_static_library() {
local library="$1"; local mode="$2"; shift 2;
[ -z "$library" ] && { echo "library not passed." 1>&2; return 1; };
case "$mode" in ''|*[!1-3]*) echo "mode '$mode' passed is invalid. It must be between 1-3." 1>&2; return 1;;esac
local -a paths=();
{ [ "$mode" = "1" ] || [ "$mode" = "3" ]; } && paths+=("${TERMUX__PREFIX:-$PREFIX}");
{ [ "$mode" = "2" ] || [ "$mode" = "3" ]; } && { [ -d "/system/lib64" ] && paths+=("/system/lib64"); paths+=("/system/lib"); };
find "${paths[@]}" -name "*.a" -print 2>/dev/null | grep -E "$@" -- "$library"
}
# search_dynamic_symbol symbol_name_regex mode [additional_nm_options]
search_dynamic_symbol() {
local symbol="$1"; local mode="$2"; shift 2;
[ -z "$symbol" ] && { echo "symbol not passed." 1>&2; return 1; };
case "$mode" in ''|*[!1-3]*) echo "mode '$mode' passed is invalid. It must be between 1-3." 1>&2; return 1;;esac
local -a paths=();
{ [ "$mode" = "1" ] || [ "$mode" = "3" ]; } && paths+=("${TERMUX__PREFIX:-$PREFIX}");
{ [ "$mode" = "2" ] || [ "$mode" = "3" ]; } && { [ -d "/system/lib64" ] && paths+=("/system/lib64"); paths+=("/system/lib"); };
{ while IFS= read -r -d '' lib; do echo "$lib"; nm --dynamic --extern-only --defined-only --demangle "$@" -- "$lib" 2>/dev/null | grep -E -- "$symbol" | grep -v " U "; done < <(find "${paths[@]}" -name "*.so" -print0 2>/dev/null); } | grep -E -B 1 -- "$symbol"
}
# search_static_symbol symbol_name_regex mode [additional_nm_options]
search_static_symbol() {
local symbol="$1"; local mode="$2"; shift 2;
[ -z "$symbol" ] && { echo "symbol not passed." 1>&2; return 1; };
case "$mode" in ''|*[!1-3]*) echo "mode '$mode' passed is invalid. It must be between 1-3." 1>&2; return 1;;esac
local -a paths=();
{ [ "$mode" = "1" ] || [ "$mode" = "3" ]; } && paths+=("${TERMUX__PREFIX:-$PREFIX}");
{ [ "$mode" = "2" ] || [ "$mode" = "3" ]; } && { [ -d "/system/lib64" ] && paths+=("/system/lib64"); paths+=("/system/lib"); };
{ while IFS= read -r -d '' lib; do echo "$lib"; nm --demangle --defined-only "$@" -- "$lib" 2>/dev/null | grep -E -- "$symbol" | grep -v " U "; done < <(find "${paths[@]}" -name "*.a" -print0 2>/dev/null); } | grep -E -B 1 -- "$symbol"
}
# list_dynamic_symbols library_path [additional_nm_options]
list_dynamic_symbols() {
local library="$1"; shift 1;
[ -z "$library" ] && { echo "library not passed." 1>&2; return 1; };
nm --dynamic --extern-only --defined-only --demangle "$@" -- "$library"
}
# list_static_symbols library_path [additional_nm_options]
list_static_symbols() {
local library="$1"; shift 1;
[ -z "$library" ] && { echo "library not passed." 1>&2; return 1; };
nm --demangle --defined-only "$@" -- "$library"
}
# list_library_dependencies library_path recursive
list_library_dependencies() {
local library="$1"; local recursive="$2"; shift 2;
[ -z "$library" ] && { echo "library not passed." 1>&2; return 1; };
case "$recursive" in ''|*[!0-1]*) echo "recursive '$recursive' passed is invalid. It must be 0 or 1." 1>&2; return 1;;esac
if [ "$recursive" = "0" ]; then readelf --dynamic -- "$library" | grep -F "(NEEDED)" | sed -E 's/^.*Shared library: \[(.*)\]$/\1/'; else ldd -- "$library"; fi
}
Examples
# Search `foo.so` dynamic library in both `$TERMUX__PREFIX` and `/system/lib[64]` paths
search_dynamic_library foo.so 3
# Search `foo.a` static library in only `$TERMUX__PREFIX`
search_static_library foo.a 1
# Search `bar` dynamic library symbol in both `$TERMUX__PREFIX` and `/system/lib[64]` paths
search_dynamic_symbol "bar" 3
# Search `bar` static library symbol in only `/system/lib[64]` paths
search_static_symbol "bar" 2
# List `libtermux-api.so` dynamic library symbols
list_dynamic_symbols "$TERMUX__PREFIX/lib/libtermux-api.so"
# List `libtermux-api.a` static library symbols
list_static_symbols "$TERMUX__PREFIX/lib/libtermux-api.a"
# List `bash` direct dynamic library dependencies
list_library_dependencies "$TERMUX__PREFIX/bin/bash" 0
# List `bash` recursive dynamic library dependencies
list_library_dependencies "$TERMUX__PREFIX/bin/bash" 1
The $HOME
variable is for the user's home directory. (1)
The $PATH
, $LD_LIBRARY_PATH
and $LD_PRELOAD
variables are part of the environment of processes/shells on Unix-like systems. (1, 2)
The $PATH
variable is for the list of directory paths separated with colons :
that certain functions and utilities use in searching for an executable file known only by a file basename
. The list of directory paths is searched from beginning to end, by checking the path formed by concatenating a directory path, a path separator /
, and the executable file basename
, and the first file found, if any, with execute permission is executed. (1)
The $LD_LIBRARY_PATH
variable is for the list of directory paths separated with colons :
that should be searched for dynamic/shared library files that are dependencies of executables or libraries to be linked against. The list of directory paths is searched from beginning to end, by checking the path formed by concatenating a directory path, a path separator /
, and the library file basename
, and the first file found, if any, with read permission is opened. (1)
The $LD_PRELOAD
variable is for the list of ELF shared object paths separated with colons :
to be loaded before all others. This feature can be used to selectively override functions in other shared objects. (1)
Check Termux filesystem layout docs (including Android Paths section) for more info on the Android filesystem directories.
The Android filesystem rootfs and home ($HOME
) directory exists at /
.
The Android system provided executables primarily exist under /system/bin
that are part of AOSP itself that should exist on all devices depending on Android version as detailed by Android shell_and_utilities
docs. The core utilities are primarily provided by toybox
(1, 2, 3) for Android >= 6
and toolbox
(1) for Android < 6
and mostly have limited features compared to GNU
coreutils
provided by Termux and other linux distros, like debian
. Moreover, older android versions do not have all the utilities or their features are missing or are severely broken. Additional apex, vendor or product partition specific (1, 2, 3), or custom ROM specific executables may exist under additional paths like /apex
, /vendor
, /product
or under /sbin
and /system/xbin
directories.
The Android system provided shared libraries exist under /system/lib64
and/or /system/lib
(or instead under /apex/*/lib
) depending on if Android is 64-bit
or 32-bit
. Additional libraries may exist under /odm/lib[64]
, /vendor/lib[64]
, /data/asan/system/lib[64]
, /data/asan/odm/lib[64]
and /data/asan/vendor/lib[64]
. The executables compiled for Android system do not use DT_RUNPATH
or $LD_LIBRARY_PATH
, and rely on linker
to search in default library paths listed earlier. Check ld.so
and dlopen
man page and Android system linker (/system/bin/linker[64]
) source for more info.
The Android system does not provide any $LD_PRELOAD
library.
Check following source links for info for which other environmental variables are exported by Android via init
startup.
- https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:frameworks/base/core/java/android/os/Environment.java
- https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:system/core/rootdir/init.environ.rc.in
- https://cs.android.com/android/_/android/platform/system/core/+/refs/tags/android-14.0.0_r1:rootdir/init.rc;l=1022
- https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:packages/modules/SdkExtensions/derive_classpath/derive_classpath.cpp;l=147
- https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/include/paths.h
The Android system exports path variables with the following default values for shells started for adb
and for app environments depending on the Android version. For info on $PATH
, $LD_LIBRARY_PATH
, $LD_PRELOAD
environment variables, check Path Environment Variables.
-
$HOME
:/
. (1) -
$PATH
: (1)- Android
>= 11
:/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
(1, 2) - Android
>= 10
:/sbin:/system/sbin:/product/bin:/apex/com.android.runtime/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
(1) - Android
>= 9
:/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
(1) - Android
>= 8
:/sbin:/system/sbin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin
(1) - Android
< 8
:/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
(1, 2)
- Android
-
$LD_LIBRARY_PATH
: Not set by default. (1) -
$LD_PRELOAD
: Not set by default.
Check Termux filesystem layout docs (including Termux Paths and File Path Limits sections) and properties.sh
file for more info on the Termux filesystem directories and variables.
As mentioned in the Execution section, termux packages are specifically compiled for the Termux rootfs
directory /data/data/com.termux/files
($TERMUX__ROOTFS
), based on the Termux app package name com.termux
and the expected private app data directory /data/data/com.termux
android would assign to the app on installation if its installed on the primary user 0
of the device, as that would be the only directory that an app can access and place its files in and execute files from, which are also kept private from other apps as well for security reasons, The app data directory path assigned by Android will be different if the app package name is changed, or app is installed on a secondary user, work profile or adoptable storage and so Termux app must be installed in primary user 0
, unless all its packages are re-compiled for the changes done.
The Termux provided executables currently primarily exist under /data/data/com.termux/files/usr/bin
($TERMUX__PREFIX/bin
). Some packages, like busybox
, may have their executables under /data/data/com.termux/files/usr/bin/applets
($TERMUX__PREFIX/bin/applets
). The core utilities are provided by GNU
coreutils
to have a consistent experience with other linux distros, like debian
.
The Termux provided shared libraries exist under /data/data/com.termux/files/usr/lib
($TERMUX__PREFIX/lib
). The executables are compiled with DT_RUNPATH
for Android >= 7
and do not use $LD_LIBRARY_PATH
. For Android 5
and 6
, $LD_LIBRARY_PATH
is used. The RUNPATH
value can be checked with readelf -d $TERMUX__PREFIX/bin/<executable>
. Check ld.so
and dlopen
man page, termux-packages
build infrastructure termux_setup_toolchain
(c508560e
, b997c4ea
), termux clang
package (a4a2aa58
, d3f8fea1
, 3b316cfc
), termux-packages
build infrastructure termux-elf-cleaner
and termux-elf-cleaner
source (623f314c
) for more info.
The Termux provided $LD_PRELOAD
library implemented by termux-exec
exists at /data/data/com.termux/files/usr/lib/libtermux-exec.so
($TERMUX__PREFIX/lib/libtermux-exec.so
).
Check following source links for info for which other environmental variables are exported by Termux app via TermuxShellEnvironment.getEnvironment()
method.
- https://github.com/termux/termux-app/blob/master/termux-shared/src/main/java/com/termux/shared/termux/shell/command/environment/TermuxShellEnvironment.java
- https://github.com/termux/termux-app/blob/master/termux-shared/src/main/java/com/termux/shared/termux/shell/command/environment/TermuxAppShellEnvironment.java
- https://github.com/termux/termux-app/blob/master/termux-shared/src/main/java/com/termux/shared/termux/shell/command/environment/TermuxShellCommandShellEnvironment.java
- https://github.com/termux/termux-app/blob/master/termux-shared/src/main/java/com/termux/shared/shell/command/environment/ShellCommandShellEnvironment.java
- https://github.com/termux/termux-app/blob/master/termux-shared/src/main/java/com/termux/shared/shell/command/environment/AndroidShellEnvironment.java
- https://github.com/termux/termux-app/blob/master/termux-shared/src/main/java/com/termux/shared/shell/command/environment/UnixShellEnvironment.java
The Termux app via TermuxShellEnvironment
class exports the $PATH
and $LD_LIBRARY_PATH
variables for shells started with the following default values. The $TERMUX__PREFIX/bin/login
script exports the $LD_PRELOAD
variable currently and is the only core variable that is not exported by the Termux app. For info on $PATH
, $LD_LIBRARY_PATH
, $LD_PRELOAD
environment variables, check Path Environment Variables.
The following $TERMUX__
scoped variables are for the currently running Termux rootfs/app environment and should not be changed by programs and are only available for Termux app version >= 0.119.0
.
-
$TERMUX_APP__DATA_DIR
:/data/data/com.termux
. (1) (Added in Termux appv0119.0
) -
$TERMUX__PROJECT_DIR
:/data/data/com.termux/termux
. (1) (Added in Termux appv0119.0
) -
$TERMUX__CORE_DIR
:/data/data/com.termux/termux/core
. (1) (Added in Termux appv0119.0
) -
$TERMUX__APPS_DIR
:/data/data/com.termux/termux/apps
. (1) (Added in Termux appv0119.0
) -
$TERMUX__CACHE_DIR
:/data/data/com.termux/cache
. (1) (Added in Termux appv0119.0
) -
$TERMUX__ROOTFS
:/data/data/com.termux/files
. (1) (Added in Termux appv0119.0
) -
$TERMUX__HOME
:/data/data/com.termux/files/home
. (1) (Added in Termux appv0119.0
) -
$HOME
:/data/data/com.termux/files/home
. (1) -
$TERMUX__PREFIX
:/data/data/com.termux/files/usr
. (1) (Added in Termux appv0119.0
) -
$PREFIX
:/data/data/com.termux/files/usr
. (1) (Deprecated in Termux appv0119.0
) -
$PATH
: (1)- Android
>= 7
:/data/data/com.termux/files/usr/bin
- Android
< 7
:/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/bin/applets
- Android
-
$LD_LIBRARY_PATH
: (1)- Android
>= 7
: Not set by default. - Android
< 7
:/data/data/com.termux/files/usr/lib
- Android
-
$LD_PRELOAD
:/data/data/com.termux/files/usr/lib/libtermux-exec.so