#!/data/data/com.termux/files/usr/bin/bash

# Title:         sudo
# Description:   A wrapper script to execute commands as the
#                'root (superuser)' user in the Termux app, like to
#                drop to an interactive shell for any of the supported
#                shells, or to execute shell script files or their
#                text passed as an argument.
# Homepage:      https://github.com/agnostic-apollo/sudo
# SPDX-License-Identifier: MIT
# Usage:         Run "sudo --help" for detailed list of usages.
# Bash version:  4.1 or higher
# Credits:       https://gitlab.com/st42/termux-sudo
#                https://github.com/cswl/tsu
SUDO__VERSION="1.2.0"
[ "$SUDO__VERSION" = @"SUDO_PKG__VERSION"@ ] && \
SUDO__VERSION=1.0.0



if [ -z "${BASH_VERSION:-}" ]; then
    echo "The 'sudo' script must be run from a 'bash' shell."; return 64 2>/dev/null|| exit 64 # EX__USAGE
fi



##
# Function to set termux env variables.
#
# `sudo_set_termux_env_variables`
##
sudo_set_termux_env_variables() {

# Use path environment variables under the `TERMUX_` env root scope
# exported by the Termux app version `>= v0.119.0`, otherwise fallback
# to paths replaced during build time by termux-packages build
# infrastructure. If running on older app versions, or not building
# sudo with termux-packages, like for the `master` branch and GitHub
# releases, then use default path for current termux app for the
# `com.termux` package, but this will not work for termux forks.
local termux_rootfs_default="/data/data/com.termux/files"

TERMUX__LNAME="termux"
[ "$TERMUX__LNAME" = @"TERMUX__LNAME"@ ] && \
TERMUX__LNAME="termux"

TERMUX_APP__NAME="Termux"
[ "$TERMUX_APP__NAME" = @"TERMUX_APP__NAME"@ ] && \
TERMUX_APP__NAME="Termux"

TERMUX_ENV__SS_TERMUX="_"
[ "$TERMUX_ENV__SS_TERMUX" = @"TERMUX_ENV__SS_TERMUX"@ ] && \
TERMUX_ENV__SS_TERMUX="_"

TERMUX_ENV__S_TERMUX="TERMUX__"
[ "$TERMUX_ENV__S_TERMUX" = @"TERMUX_ENV__S_TERMUX"@ ] && \
TERMUX_ENV__S_TERMUX="TERMUX__"

TERMUX_ENV__SS_TERMUX_APP="APP__"
[ "$TERMUX_ENV__SS_TERMUX_APP" = @"TERMUX_ENV__SS_TERMUX_APP"@ ] && \
TERMUX_ENV__SS_TERMUX_APP="APP__"


termux_core__bash__termux_scoped_env_variable get-value "TERMUX_ROOTFS" \
    ss="$TERMUX_ENV__SS_TERMUX" "ROOTFS" r+='^((/)|((/[^/]+)+))$' "/data/data/com.termux/files" "$termux_rootfs_default" || return $?

termux_core__bash__termux_scoped_env_variable get-value "TERMUX_HOME" \
    ss="$TERMUX_ENV__SS_TERMUX" "HOME" r+='^(/[^/]+)+$' "/data/data/com.termux/files/home" "$termux_rootfs_default/home" || return $?

termux_core__bash__termux_scoped_env_variable get-value "TERMUX_PREFIX" \
    ss="$TERMUX_ENV__SS_TERMUX" "PREFIX" r+='^(/[^/]+)+$' "/data/data/com.termux/files/usr" "$termux_rootfs_default/usr" || return $?

termux_core__bash__termux_scoped_env_variable get-name "TERMUX_PREFIX__N" \
    ss="$TERMUX_ENV__SS_TERMUX" "PREFIX" || return $?


if [[ ! -x "$TERMUX_ROOTFS" ]] && [[ "$SUDO_SKIP_ON_NOOP_COMMAND" != "1" ]]; then
    sudo_log_errors "The TERMUX_ROOTFS '$TERMUX_ROOTFS' path not found or is not executable. Are you running in $TERMUX_APP__NAME app on Android?"
    return 1
fi

# Set variables to readonly to prevent modification by sudo.config
for var in TERMUX_ENV__SS_TERMUX TERMUX_ENV__S_TERMUX TERMUX_ROOTFS TERMUX_HOME TERMUX_PREFIX TERMUX_PREFIX__N; do
    readonly ${var}
done

}

##
# Function to set sudo default variables.
#
# `sudo_set_sudo_default_variables`
##
sudo_set_sudo_default_variables() {

### Set User Modifiable Variables Start
### It is highly advisable to use the sudo.config file instead to modify the default values

# Set SUDO_SHELL_HOME which will be used as sudo shell home directory
[ -n "$SUDO__SHELL_HOME" ] && CUSTOM_SUDO_SHELL_HOME_SET=1
SUDO_SHELL_HOME="${SUDO__SHELL_HOME:-$TERMUX_HOME/.suroot}" # Default: `$TERMUX_HOME/.suroot`
# SUDO_SHELL_HOME="${SUDO_SHELL_HOME:-$TERMUX_HOME}" # Use '$TERMUX_HOME' as sudo shell home

# Set SUDO_POST_SHELL_HOME which will be used as sudo post shell home directory
[ -n "$SUDO__POST_SHELL_HOME" ] && CUSTOM_SUDO_POST_SHELL_HOME_SET=1
SUDO_POST_SHELL_HOME="${SUDO__POST_SHELL_HOME:-$TERMUX_HOME/.suroot}" # Default: `$TERMUX_HOME/.suroot`
# SUDO_POST_SHELL_HOME="${SUDO__POST_SHELL_HOME:-$TERMUX_HOME}" # Use '$TERMUX_HOME' as sudo post shell home

# Set the prompt string 1 for the sudo shell
SUDO_SHELL_PS1="${SUDO__SHELL_PS1:-# }" # Default: `# `

# Set the prompt string 1 for the sudo post shell
SUDO_POST_SHELL_PS1="${SUDO__POST_SHELL_PS1:-# }" # Default: `# `

# Set any additional paths you want to export other than termux bin, android bin and su bin paths,
# separated with colons `:`
# The string must not start or end with or contain two consecutive colons ':'
# the `--export-paths` option will override this value
SUDO_ADDITIONAL_PATHS_TO_EXPORT="${SUDO__ADDITIONAL_PATHS_TO_EXPORT:-}" # Default: ``

# Set to "1" or pass "-L" as argument if you want to automatically export all the paths that already exist
# in the PATH variable at the moment the sudo command is run
# the default paths mentioned above and any path in SUDO_ADDITIONAL_PATHS_TO_EXPORT are always exported
SUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE="${SUDO__EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE:-0}" # Default: `0`

# Set any additional ld library paths you want to export other than termux lib and android lib paths,
# separated with colons `:`
# The string must not start or end with or contain two consecutive colons ':'
# the `--export-ld-lib-paths` option will override this value
SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT="${SUDO__ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT:-}" # Default: ``

# Set to "1" or pass "-P" as argument if you want to automatically export all the paths that already exist
# in the LD_LIBRARY_PATH variable at the moment the sudo command is run
# The default paths mentioned above and any path in SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT are always exported
SUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE="${SUDO__EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE:-0}" # Default: `0`

# Set to 1 if you want to automatically create rc files for interactive shells, otherwise 0
SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES="${SUDO__SHELLS_AUTOMATICALLY_CREATE_RC_FILES:-1}" # Default: `1`

# Set to 1 if you want to automatically create history files for interactive shells, otherwise 0
SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES="${SUDO__SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES:-1}" # Default: `1`

# Set to 1 if you want to store command history for interactive shells, otherwise 0
SUDO_SHELLS_HISTORY_ENABLED="${SUDO__SHELLS_HISTORY_ENABLED:-1}" # Default: `1`

# Set absolute path for su binary to use instead of searching for it in default search paths.
# This can be used if path is not in search paths or all paths in it should not be checked.
SUDO_SU_PATH="${SUDO__SU_PATH:-}" # Default: ``


# for f in SUDO_SHELL_HOME SUDO_POST_SHELL_HOME SUDO_SHELL_PS1 SUDO_POST_SHELL_PS1 SUDO_ADDITIONAL_PATHS_TO_EXPORT SUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT SUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES SUDO_SHELLS_HISTORY_ENABLED SUDO_SU_PATH; do echo "$f=\`${!f}\`"; done; echo $'\n'

### Set User Modifiable Variables End


### Set Default Variables Start
# The following variables must not be modified unless you know what you are doing

SUDO_MAX_LOG_LEVEL=5 # Default: `5` (VVVERBOSE=5)
# shellcheck disable=SC2153
SUDO_LOG_LEVEL="$SUDO__LOG_LEVEL"
{ [[ ! "${SUDO_LOG_LEVEL:-}" =~ ^[0-9]+$ ]] || [[ "$SUDO_LOG_LEVEL" -gt "$SUDO_MAX_LOG_LEVEL" ]]; } && \
SUDO_LOG_LEVEL=1 # Default: `1` (OFF=0, NORMAL=1, DEBUG=2, VERBOSE=3, VVERBOSE=4 and VVVERBOSE=5)
SUDO_LOG_ARGS="${SUDO__LOG_ARGS:-0}" # Default: `0` (Export or manually set to `1` if you want to debug arguments received)

SUDO_NOOP_COMMAND=0 # Default: `0`
SUDO_DRY_RUN=0 # Default: `0`
COMMAND_TYPE="path" # Default: `path`
COMMAND_TYPE_PATH_FORCED=0 # Default: `0`
A_FLAG_PASSED=0 # Default: `0`
T_FLAG_PASSED=0 # Default: `0`

ROOTFS_PREVIOUS_STATE_RO=0 # Default to `0` (true)
SYSTEM_PREVIOUS_STATE_RO=0 # Default to `0` (true)
ROOTFS_PARTITION_RW_DEPENDENT_PATHS="" # Default: ``
SYSTEM_PARTITION_RW_DEPENDENT_PATHS="" # Default: ``
ROOTFS_PARTITION_MM_DEPENDENT_PATHS="" # Default: ``
SYSTEM_PARTITION_MM_DEPENDENT_PATHS="" # Default: ``

SAME_SUDO_POST_SHELL_AS_SUDO_SHELL=0 # Default: `0`
SAME_SUDO_POST_SHELL_HOME_AS_SUDO_SHELL_HOME=0 # Default: `0`
PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES=0 # Default: `0`
EXEC_SUDO_SHELL=0 # Default: `0`
DISABLE_PRESERVE_ENVIRONMENT_FOR_SU=0 # Default: `0`
DISABLE_STDIN_FOR_CORE_SCRIPT=0 # Default: `0`
RUN_CORE_SCRIPT_IN_BACKGROUND=0 # Default: `0`
EXIT_EARLY_IF_CORE_SCRIPT_FAILS=0 # Default: `0`
GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=0 # Default: `0`
CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE=0 # Default: `0`
DECODE_CORE_SCRIPT_CONTENT=0 # Default: `0`
DO_NOT_DELETE_SUDO_TEMP_DIRECTORY_ON_EXIT=0 # Default: `0`
REMOVE_PREVIOUS_SUDO_TEMP_FILES=0 # Default: `0`
USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION=0 # Default: `0`
DO_NOT_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO=0 # Default: `0`
FORCE_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO=0 # Default: `0`
HOLD_AFTER_SUDO=0 # Default: `0`
HOLD_ONLY_ON_FAILURE=0 # Default: `0`
SLEEP_AFTER_SUDO=0 # Default: `0`
SLEEP_ONLY_ON_FAILURE=0 # Default: `0`
DISABLE_ARGUMENTS_LOGGING=0 # Default: `0`
SET_SUDO_SHELL_TERMINAL_TITLE=0 # Default: `0`
PATH_PRIORITY="default" # Default: `default`
SET_SECONDARY_PRIORITY_PATHS=1 # Default: `1`
SET_SECONDARY_PATHS=1 # Default: `1`

SUDO_SHELL="" # Default: ``
SUDO_SHELL_BASENAME="" # Default: ``
SUDO_SHELL_PARENT_DIR="" # Default: ``
SUDO_POST_SHELL="" # Default: ``
SUDO_POST_SHELL_BASENAME="" # Default: ``
SUDO_POST_SHELL_PARENT_DIR="" # Default: ``
SUDO_SHELL_RCFILE="" # Default: ``
SUDO_POST_SHELL_RCFILE="" # Default: ``
SUDO_SHELL_HISTFILE="" # Default: ``
SUDO_POST_SHELL_HISTFILE="" # Default: ``
SUDO_TEMP_DIRECTORY="" # Default: ``
SUDO_TEMP_DIRECTORY_PREFIX=".sudo.temp" # Default: `.sudo.temp`
SUDO_CORE_SCRIPT_TEMP_FILENAME="" # Default: ``
SUDO_CORE_SCRIPT_REDIRECT_MODE="" # Default: ``
SUDO_SHELL_WORKING_DIR="" # Default: ``
SUDO_SHELL_TERMINAL_TITLE="" # Default: ``
ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN="" # Default: ``
ADDITIONAL_SUDO_SHELL_POST_COMMANDS_TO_RUN="" # Default: ``
ADDITIONAL_SUDO_POST_SHELL_PRE_COMMANDS_TO_RUN="" # Default: ``
ADDITIONAL_SUDO_POST_SHELL_POST_COMMANDS_TO_RUN="" # Default: ``
SUDO_SHELL_STDIN_STRING="" # Default: ``
SUDO_POST_SHELL_STDIN_STRING="" # Default: ``
SUDO_SUPPORTED_SHELLS="" # Default: ``
SUDO_SUPPORTED_POST_SHELLS="" # Default: ``
SLEEP_TIME_AFTER_SUDO="" # Default: ``
HOLD_STRING_AFTER_SUDO="" # Default: ``
SUDO_XARGS_PATH="" # Default: ``
COMMA_ALTERNATIVE="‚" # Default: `‚` (U+201A, &sbquo;, &#8218;, single low-9 quotation mark)
SUDO_ARG_MAX_SAFE_LIMIT=122880 # Default: `122880` (120KB, value should be in bytes)

SUDO_SUPPORTED_INTERACTIVE_SHELLS="bash zsh dash sh fish python ruby pry node perl lua5.2 lua5.3 lua5.4 php python2 ksh"
SUDO_SUPPORTED_SCRIPT_SHELLS="bash zsh dash sh fish python ruby node perl lua5.2 lua5.3 lua5.4 php python2 ksh"
SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT="dash sh node php"

declare -ga SUDO_COMMAND=()
declare -ga SHELL_COMMAND=()
declare -ga SHELL_INTERACTIVE_COMMAND=()
declare -ga SUDO_SHELL_COMMAND=()
declare -ga SUDO_SHELL_INTERACTIVE_COMMAND=()
declare -ga SUDO_POST_SHELL_INTERACTIVE_COMMAND=()

declare -ga SHELL_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS=()

# Set regexes for validation
VALID_NUMBER_REGEX='^[0-9]+$'
VALID_ABSOLUTE_PATH_REGEX='^(/[^/]+)+$'
VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX='^((/)|((/[^/]+)+))$'
VALID_PATH_IN_ROOTFS_PARTITION_REGEX='^/[^/]*/?$'
VALID_PATH_IN_SYSTEM_PARTITION_REGEX='^/system/.*'
VALID_SU_MOUNT_MASTER_OPTION_PREFIXED_STRING='^[ \t]*(--mount-master|-mm)[ \t]*'

# Set termux and android env variables
TERMUX_BIN="$TERMUX_PREFIX/bin"
TERMUX_BIN_APPLETS="$TERMUX_PREFIX/bin/applets"
TERMUX_LD_LIBRARY_PATH="$TERMUX_PREFIX/lib"
TERMUX_LD_PRELOAD="$TERMUX_LD_LIBRARY_PATH/libtermux-exec.so"
TMPDIR="$TERMUX_PREFIX/tmp"
SYS_XBIN="/system/xbin"
SYS_BIN="/system/bin"
BASH_SHELL_PATH="$TERMUX_BIN/bash"
TERM="xterm-256color"

# Termux is currently an english-only environment
LANG="en_US.UTF-8"

### Set Default Variables End

}

function sudo_log() { local log_level="${1}"; shift; if [[ "$SUDO_LOG_LEVEL" -ge $log_level ]]; then echo "$@"; fi }
function sudo_log_literal() { local log_level="${1}"; shift; if [[ "$SUDO_LOG_LEVEL" -ge $log_level ]]; then echo -e "$@"; fi }
function sudo_log_errors() { echo "$@" 1>&2; }
function sudo_log_args() { if [[ $SUDO_LOG_ARGS == "1" ]]; then echo "$@"; fi }
function sudo_log_arg_errors() { echo "$@" 1>&2; }

# Enable the following line if you want to log function runtimes with the '-vv' option
#sudo_start_time=$(date +%s%3N); function sudo_log_literal() { local log_level="${1}"; shift; if [[ "$SUDO_LOG_LEVEL" -ge $log_level ]]; then if [[ "$*" == *"Running"* ]]; then sudo_end_time=$(date +%s%3N); run_time=$((sudo_end_time-sudo_start_time)); echo -e "Runtime $run_time\n"; sudo_start_time=$(date +%s%3N); fi; echo -e "$@"; fi }



##
# `sudo_main` [`<argument...>`]
##
sudo_main() {

    local return_value

    if [[ $# -eq 0 ]] || \
        [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "--help-extra" ]] || \
        [[ "$1" == "--version" ]]; then
        SUDO_SKIP_ON_NOOP_COMMAND=1
    else
        SUDO_SKIP_ON_NOOP_COMMAND=0
    fi

    # Set termux env variables
    sudo_set_termux_env_variables || return $?

    # If `sudo.config` exists, source it.
    SUDO_CONFIG_FILE_PATH="$TERMUX_HOME/.config/sudo/sudo.config"
    SUDO_CONFIG_FILE_SOURCED=0
    if [[ "$SUDO_SKIP_ON_NOOP_COMMAND" != "1" ]] && \
        [ -f "$SUDO_CONFIG_FILE_PATH" ] && [ -r "$SUDO_CONFIG_FILE_PATH" ]; then
        # Set variables provided for `sudo.config`.
        SUDO__TERMUX_ROOTFS="$TERMUX_ROOTFS"
        SUDO__TERMUX_HOME="$TERMUX_HOME"
        SUDO__TERMUX_PREFIX="$TERMUX_PREFIX"

        # shellcheck source=sudo.config
        source "$SUDO_CONFIG_FILE_PATH" || return $?
        SUDO_CONFIG_FILE_SOURCED=1
    fi

    # Set sudo default variables.
    # They are set by a function so that default variables are not
    # overridden by the `sudo.config` file if its sourced.
    # However, the user modifiable variables will only be set if the
    # `sudo.config` didn't already set them or if they were not
    # already exported.
    sudo_set_sudo_default_variables || return $?


    # Set pre required variables to be used by this script
    if [[ "$SUDO_SKIP_ON_NOOP_COMMAND" != "1" ]]; then
        sudo_set_pre_required_variables || return $?
    fi


    # Process the command arguments passed to the script
    sudo_process_script_arguments "$@" || return $?

    [ "$SUDO_NOOP_COMMAND" = "1" ] && return 0

    # Validate COMMAND_TYPE
    if [ -z "$COMMAND_TYPE" ]; then
        sudo_show_help
        return_value=0
    elif [[ "$COMMAND_TYPE" != *,* ]] && [[ ",su,asu,path,script," == *",$COMMAND_TYPE,"* ]]; then
        sudo_run
        return_value=$?
    else
        sudo_log_errors "Unknown command type $COMMAND_TYPE"
        sudo_exit_on_args_error || return $?
    fi

    sudo_run_pre_exit_commands $return_value

    return $return_value

}

sudo_run() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo"

    # If `sudo.config` was sourced.
    if [[ "$SUDO_CONFIG_FILE_SOURCED" == "1" ]]; then
        sudo_log 3 "config was sourced from ~/.config/sudo/sudo.config"
    fi

    SUDO_SCRIPT_PATH="$(readlink -f -- "${BASH_SOURCE[0]}")"
    return_value=$?
    if [ $return_value -ne 0 ] || [[ ! "$SUDO_SCRIPT_PATH" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "Failure while finding SUDO_SCRIPT_PATH"
        sudo_log_errors "SUDO_SCRIPT_PATH='$SUDO_SCRIPT_PATH'"
        if [ $return_value -eq 0 ]; then
            return_value=1
        fi
        return $return_value
    fi

    export SUDO_SCRIPT_PATH



    # If COMMAND_TYPE equals "su" or "asu"
    if [[ "$COMMAND_TYPE" == "su" ]] || [[ "$COMMAND_TYPE" == "asu" ]]; then
        SUDO_SUPPORTED_SHELLS="$SUDO_SUPPORTED_INTERACTIVE_SHELLS"

        # The arguments passed to '--shell-options' are meant for interactive shell
        SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS=()

        interactive_sudo_shell_required=1
    # If COMMAND_TYPE equals "path"
    elif [[ "$COMMAND_TYPE" == "path" ]]; then
        SUDO_SUPPORTED_SHELLS="bash"

        # Unset SUDO_SHELL so that it defaults to bash in sudo_set_sudo_shell
        SUDO_SHELL=""

        # Ignore any shell options that are passed
        SUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS=()

        interactive_sudo_shell_required=0
    # If COMMAND_TYPE equals "script"
    elif [[ "$COMMAND_TYPE" == "script" ]]; then
        SUDO_SUPPORTED_SHELLS="$SUDO_SUPPORTED_SCRIPT_SHELLS"
        SUDO_SUPPORTED_POST_SHELLS="$SUDO_SUPPORTED_INTERACTIVE_SHELLS"

        interactive_sudo_shell_required=0
    else
        sudo_log_errors "COMMAND_TYPE '$COMMAND_TYPE' not handled while running sudo command in 'sudo_run'"
        return 1
    fi

    # If COMMAND_TYPE equals "script"
    if [[ "$COMMAND_TYPE" == "script" ]]; then
        # If DISABLE_STDIN_FOR_CORE_SCRIPT is enabled or stdin is not available while running this script,
        # then force enable DISABLE_STDIN_FOR_CORE_SCRIPT
        if [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]] || [ ! -t 0 ]; then
            DISABLE_STDIN_FOR_CORE_SCRIPT=1
        else
            DISABLE_STDIN_FOR_CORE_SCRIPT=0
        fi
    fi


    # If RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled and COMMAND_TYPE equals "script"
    if [[ "$RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]] && [[ "$COMMAND_TYPE" == "script" ]]; then
        # If SAME_SUDO_POST_SHELL_HOME_AS_SUDO_SHELL_HOME is enabled
        if [[ "$SAME_SUDO_POST_SHELL_HOME_AS_SUDO_SHELL_HOME" == "1" ]]; then
            # Override SUDO_POST_SHELL_HOME
            SUDO_POST_SHELL_HOME="$SUDO_SHELL_HOME"
        fi
    else
        # Unset SUDO_POST_SHELL_HOME so that SUDO_POST_SHELL variables are not set
        SUDO_POST_SHELL_HOME=""
    fi


    # Test if bash shell executable file exists at BASH_SHELL_PATH
    # This is to ensure that bash shell is always the default shell if '--shell` and '--post-shell' options are not passed
    # and the shell is automatically validated so that it doesn't have to again in sudo_set_sudo_shell and sudo_set_sudo_post_shell
    # Bash shell is also needed by the 'su --shell' command
    # sudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
    sudo_run_file_type_tests_on_path "BASH_SHELL_PATH" "$BASH_SHELL_PATH" 1 1 1 "frx" || return $?

    # Set SU and SU_BIN_PATH
    sudo_set_su_variables || return $?

    # Set required variables to be used by this script
    sudo_set_required_variables || return $?

    # Set priority_dependent_variables with termux priority
    sudo_set_priority_dependent_variables "termux" || return $?

    # Export variables and functions to be used by this script
    sudo_export_or_unexport_shared_variables_for_su export || return $?

    # Set SU_ENV_COMMAND
    sudo_set_su_env_command || return $?



    # Set SUDO_SHELL and SUDO_SHELL_BASENAME
    sudo_set_sudo_shell || return $?

    # If COMMAND_TYPE does not equal "path"
    # COMMAND_TYPE "path" does not use an interactive shell so no need to set these
    if [[ "$COMMAND_TYPE" != "path" ]]; then
        # Set SUDO_SHELL_RCFILE and SUDO_SHELL_RCFILE_VALUE to be sourced when SUDO_SHELL is run
        sudo_set_sudo_shell_rcfile || return $?

        # Set SUDO_SHELL_HISTFILE
        sudo_set_sudo_shell_histfile || return $?
    fi

    # Set SUDO_SHELL_COMMAND and SUDO_SHELL_INTERACTIVE_COMMAND command to be run
    sudo_set_sudo_shell_command || return $?



    # If SUDO_POST_SHELL_HOME is set
    if [ -n "$SUDO_POST_SHELL_HOME" ]; then
        # If SAME_SUDO_POST_SHELL_AS_SUDO_SHELL is enabled
        if [[ "$SAME_SUDO_POST_SHELL_AS_SUDO_SHELL" == "1" ]]; then
            # Override SUDO_POST_SHELL
            SUDO_POST_SHELL="$SUDO_SHELL"
        fi

        # Set SUDO_POST_SHELL and SUDO_POST_SHELL_BASENAME
        sudo_set_sudo_post_shell || return $?

        # Set SUDO_POST_SHELL_RCFILE and SUDO_POST_SHELL_RCFILE_VALUE to be sourced when SUDO_POST_SHELL is run
        sudo_set_sudo_post_shell_rcfile || return $?

        # Set SUDO_POST_SHELL_HISTFILE file
        sudo_set_sudo_post_shell_histfile || return $?

        # Set SUDO_POST_SHELL_INTERACTIVE_COMMAND command to be run
        sudo_set_sudo_post_shell_command || return $?
    fi



    # If COMMAND_TYPE equals "path"
    if [[ "$COMMAND_TYPE" == "path" ]]; then
        # Set SUDO_PATH_COMMAND
        sudo_set_sudo_command_path || return $?
    fi



    # Set PRE_SUDO_SHELL_COMMANDS_TO_RUN
    sudo_set_pre_sudo_shell_commands_to_run || return $?

    # If SUDO_POST_SHELL_HOME is set
    if [ -n "$SUDO_POST_SHELL_HOME" ]; then
        # Set PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN
        sudo_set_pre_sudo_post_shell_commands_to_run || return $?
    fi



    # Set traps to run commands before exiting sudo
    set_sudo_traps "sudo_trap" || return $?



    # Create SUDO_SHELL_HOME, SUDO_SHELL_RCFILE, SUDO_SHELL_HISTFILE and/or
    # SUDO_POST_SHELL_HOME, SUDO_POST_SHELL_RCFILE, SUDO_POST_SHELL_HISTFILE
    # and SUDO_SHELL_WORKING_DIR if missing
    # and SUDO_TEMP_DIRECTORY if required
    # Android rootfs "/" partition and/or system "/system" partition may be remounted
    # as rw if they are to be used for SUDO_SHELL_HOME, SUDO_POST_SHELL_HOME or SUDO_SHELL_WORKING_DIR
    sudo_setup_sudo_shell_home_and_working_environment_wrapper
    return_value=$?
    if [ $return_value -ne 0 ]; then
        return $return_value
    fi



    # Set SU_RUN_COMMAND
    sudo_set_su_run_command || return $?

    # Run sudo command depending on command type

    local SUDO_EXIT_CODE=0

    BASH_SHELL_COMMAND=("$BASH_SHELL_PATH" "--noprofile" "--norc")
    printf -v "BASH_SHELL_COMMAND_STRING" "%q " "${BASH_SHELL_COMMAND[@]}"

    # If COMMAND_TYPE equals "su" or "asu"
    if [[ "$COMMAND_TYPE" == "su" ]] || [[ "$COMMAND_TYPE" == "asu" ]]; then

        # If SUDO_SHELL_INTERACTIVE_COMMAND is not set
        if [ ${#SUDO_SHELL_INTERACTIVE_COMMAND[@]} -eq 0 ]; then
            sudo_log_errors "SUDO_SHELL_INTERACTIVE_COMMAND is not set while running sudo $COMMAND_TYPE command in 'sudo_run'"
            return 1
        fi

        # Unexport variables not to be used by su anymore
        sudo_export_or_unexport_shared_variables_for_su unexport || return $?


        # Set SUDO_COMMAND_TO_RUN to run su that will run PRE_SUDO_SHELL_COMMANDS_TO_RUN commands and then
        # Start an interactive SUDO_SHELL
        SUDO_COMMAND_TO_RUN="$SU_RUN_COMMAND $PRE_SUDO_SHELL_COMMANDS_TO_RUN"
        printf -v "SUDO_SHELL_INTERACTIVE_COMMAND_STRING" "$SUDO_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT" "${SUDO_SHELL_INTERACTIVE_COMMAND[@]}"
        SUDO_COMMAND_TO_RUN+="$SUDO_SHELL_INTERACTIVE_COMMAND_STRING"

        # If SUDO_SHELL_STDIN_STRING is set
        if [ -n "$SUDO_SHELL_STDIN_STRING" ]; then
            # If SUDO_SHELL_BASENAME is in SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
            if [[ " $SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $SUDO_SHELL_BASENAME "* ]]; then
                # Pass SUDO_SHELL_STDIN_STRING as stdin with a herestring to SUDO_SHELL
                SUDO_COMMAND_TO_RUN+=' <<<'"'${SUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"
            else
                # Pass SUDO_SHELL_STDIN_STRING as stdin with process substitution to SUDO_SHELL
                SUDO_COMMAND_TO_RUN+=' < <(printf "%s" '"'${SUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"')'
            fi
        fi

        # If EXEC_SUDO_SHELL is enabled, then prepend "exec"
        if [[ "$EXEC_SUDO_SHELL" == "1" ]]; then
            SUDO_COMMAND_TO_RUN="exec $SUDO_COMMAND_TO_RUN"
        fi


        sudo_log_literal 3 "\n\n\nRunning sudo $COMMAND_TYPE commmand"
        sudo_log 2 $'\n'"SUDO_COMMAND_TO_RUN=\`$SUDO_COMMAND_TO_RUN\`"

        # If SUDO_DRY_RUN is not enabled
        if [[ "$SUDO_DRY_RUN" != "1" ]]; then
            # Run SUDO_COMMAND_TO_RUN
            sudo_unset_pre_su_variables
            $SUDO_COMMAND_TO_RUN
            SUDO_EXIT_CODE=$?
            sudo_set_post_su_variables
        fi


    # If COMMAND_TYPE equals "path"
    elif [[ "$COMMAND_TYPE" == "path" ]]; then

        # Set script to run in SUDO_PATH_COMMAND_TO_RUN
        sudo_set_sudo_path_command || return $?

        # Unexport variables not to be used by su anymore
        sudo_export_or_unexport_shared_variables_for_su unexport || return $?


        # Set SUDO_COMMAND_TO_RUN to run su that will run PRE_SUDO_SHELL_COMMANDS_TO_RUN commands and then
        # Run the SUDO_PATH_COMMAND_TO_RUN
        SUDO_COMMAND_TO_RUN="$SU_RUN_COMMAND $PRE_SUDO_SHELL_COMMANDS_TO_RUN"

        # If EXEC_SUDO_SHELL is enabled, then prepend "exec"
        if [[ "$EXEC_SUDO_SHELL" == "1" ]]; then
            SUDO_COMMAND_TO_RUN="exec $SUDO_COMMAND_TO_RUN"
        fi

        # Pass the SUDO_PATH_FD_PATH to the BASH_SHELL as an argument
        SUDO_COMMAND_TO_RUN+="$BASH_SHELL_COMMAND_STRING \"$SUDO_PATH_FD_PATH\""


        sudo_log_literal 3 "\n\n\nRunning sudo $COMMAND_TYPE commmand"
        sudo_log 2 $'\n'"SUDO_COMMAND_TO_RUN=\`$SUDO_COMMAND_TO_RUN\`"

        # If DISABLE_ARGUMENTS_LOGGING is not enabled
        if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
            sudo_log 2 $'\n'"SUDO_PATH_COMMAND_TO_RUN=\`$SUDO_PATH_COMMAND_TO_RUN\`"
        fi

        # If SUDO_DRY_RUN is not enabled
        if [[ "$SUDO_DRY_RUN" != "1" ]]; then
            # Run SUDO_COMMAND_TO_RUN
            sudo_unset_pre_su_variables
            $SUDO_COMMAND_TO_RUN
            SUDO_EXIT_CODE=$?
            sudo_set_post_su_variables
        fi

        # If SUDO_PATH_FD is set, then close it
        if [ -n "${SUDO_PATH_FD:-}" ]; then
            exec {SUDO_PATH_FD}<&-
            SUDO_PATH_FD=""
        fi


    # If COMMAND_TYPE equals "script"
    elif [[ "$COMMAND_TYPE" == "script" ]]; then

        # If SUDO_SHELL_COMMAND is not set
        if [ ${#SUDO_SHELL_COMMAND[@]} -eq 0 ]; then
            sudo_log_errors "SUDO_SHELL_COMMAND is not set while running sudo $COMMAND_TYPE command in 'sudo_run'"
            return 1
        fi

        # If RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled and SUDO_POST_SHELL_INTERACTIVE_COMMAND is not set
        if [[ "$RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]] && [ ${#SUDO_POST_SHELL_INTERACTIVE_COMMAND[@]} -eq 0 ]; then
            sudo_log_errors "SUDO_POST_SHELL_INTERACTIVE_COMMAND is not set while running sudo $COMMAND_TYPE command in 'sudo_run'"
            return 1
        fi

        # Set script to run in SUDO_SCRIPT_COMMAND_TO_RUN
        sudo_set_sudo_script_command || return $?

        # Unexport variables not to be used by su anymore
        sudo_export_or_unexport_shared_variables_for_su unexport || return $?


        # Set SUDO_COMMAND_TO_RUN to run su that will run the SUDO_SCRIPT_COMMAND_TO_RUN
        SUDO_COMMAND_TO_RUN="$SU_RUN_COMMAND "

        # If EXEC_SUDO_SHELL is enabled, then prepend "exec"
        if [[ "$EXEC_SUDO_SHELL" == "1" ]]; then
            SUDO_COMMAND_TO_RUN="exec $SUDO_COMMAND_TO_RUN"
        fi

        # Pass the SUDO_SCRIPT_FD_PATH to the BASH_SHELL as an argument
        SUDO_COMMAND_TO_RUN+="$BASH_SHELL_COMMAND_STRING \"$SUDO_SCRIPT_FD_PATH\""


        sudo_log_literal 3 "\n\n\nRunning sudo $COMMAND_TYPE commmand"
        sudo_log 2 $'\n'"SUDO_COMMAND_TO_RUN=\`$SUDO_COMMAND_TO_RUN\`"

        # If DISABLE_ARGUMENTS_LOGGING is not enabled
        if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
            sudo_log 2 $'\n'"SUDO_SCRIPT_COMMAND_TO_RUN=\`$SUDO_SCRIPT_COMMAND_TO_RUN\`"
        fi

        # If SUDO_DRY_RUN is not enabled
        if [[ "$SUDO_DRY_RUN" != "1" ]]; then
            # Run SUDO_COMMAND_TO_RUN
            sudo_unset_pre_su_variables
            $SUDO_COMMAND_TO_RUN
            SUDO_EXIT_CODE=$?
            sudo_set_post_su_variables
        fi

        # If SUDO_SCRIPT_FD is set, then close it
        if [ -n "${SUDO_SCRIPT_FD:-}" ]; then
            exec {SUDO_SCRIPT_FD}<&-
            SUDO_SCRIPT_FD=""
        fi


    else
        sudo_log_errors "COMMAND_TYPE '$COMMAND_TYPE' not handled while running sudo command in 'sudo_run'"
        return 1
    fi

    # If SUDO_DRY_RUN is not enabled
    if [[ "$SUDO_DRY_RUN" != "1" ]]; then
        sudo_log 3 $'\n'"SUDO_EXIT_CODE='$SUDO_EXIT_CODE'"
    fi

    # If sudo is being run in an interactive shell, then reset terminal
    if [[ $- == *i* ]]; then
        stty sane &>/dev/null
    fi

    return $SUDO_EXIT_CODE

}

##
# `sudo_run_pre_exit_commands` `<exit_code>`
##
sudo_run_pre_exit_commands() {

    local return_value

    local exit_code="$1"

    # If HOLD_AFTER_SUDO is enabled
    if [[ "$HOLD_AFTER_SUDO" == "1" ]]; then
        # If HOLD_ONLY_ON_FAILURE is not enabled or (HOLD_ONLY_ON_FAILURE is enabled and exit_code does not equal 0)
        if [[ "$HOLD_ONLY_ON_FAILURE" != "1" ]] || { [[ "$HOLD_ONLY_ON_FAILURE" == "1" ]] && [[ "$exit_code" != "0" ]]; }; then
            # If stdin and stdout are available
            if [ -t 0 ] && [ -t 1 ]; then
                # If HOLD_STRING_AFTER_SUDO is set
                if [ -n "$HOLD_STRING_AFTER_SUDO" ]; then
                    local valid_alphanumeric_and_punct_string_regex='^[[:alnum:][:punct:]]+$'

                    if [[ "$HOLD_STRING_AFTER_SUDO" =~ $valid_alphanumeric_and_punct_string_regex ]]; then
                        # Read from stdin until HOLD_STRING_AFTER_SUDO is correctly entered
                        # read should never timeout because of TMOUT=0
                        local exit_while=0
                        while [[ $exit_while != "1" ]]; do
                            TMOUT=0 read -p "Enter '$HOLD_STRING_AFTER_SUDO' to exit:"$'\n' input
                            if [ $? -ne 0 ] || [[ "$input" == "$HOLD_STRING_AFTER_SUDO" ]]; then
                                exit_while=1
                            fi
                        done
                    else
                        sudo_log_errors "HOLD_STRING_AFTER_SUDO '$HOLD_STRING_AFTER_SUDO' is invalid. It can only contain alphanumeric and punctuation characters"
                        return 1
                    fi

                # Else if only '--hold' was passed
                else
                    # Read any character from stdin in silent mode
                    # read should never timeout because of TMOUT=0
                    TMOUT=0 read -s -n 1
                fi
            fi
        fi
    fi

    # If SLEEP_AFTER_SUDO is enabled
    if [[ "$SLEEP_AFTER_SUDO" == "1" ]]; then
        # If SLEEP_ONLY_ON_FAILURE is not enabled or (SLEEP_ONLY_ON_FAILURE is enabled and exit_code does not equal 0)
        if [[ "$SLEEP_ONLY_ON_FAILURE" != "1" ]] || { [[ "$SLEEP_ONLY_ON_FAILURE" == "1" ]] && [[ "$exit_code" != "0" ]]; }; then
            local valid_floating_point_number_regex='^[0-9]+(\.[0-9]+)?$'

            if [[ "$SLEEP_TIME_AFTER_SUDO" =~ $valid_floating_point_number_regex ]]; then
                # Sleep for SLEEP_TIME_AFTER_SUDO seconds
                sleep "$SLEEP_TIME_AFTER_SUDO"
            else
                sudo_log_errors "SLEEP_TIME_AFTER_SUDO '$SLEEP_TIME_AFTER_SUDO' is not a valid floating point number"
                return 1
            fi
        fi
    fi

    return 0

}

sudo_set_su_variables() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_su_variables"

    SU=""
    SU_BIN_PATH=""
    SU_INTERACTIVE_OPTION_SUPPORTED="0"

    local -a su_search_paths=()

    # Check "`su` search paths" in README for more info.
    # If SUDO_SU_PATH is not a valid absolute path
    if [[ ! "$SUDO_SU_PATH" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        su_search_paths+=("/system/bin/su" "/debug_ramdisk/su" "/system/xbin/su" "/sbin/su" "/sbin/bin/su" "/system/sbin/su" "/su/xbin/su" "/su/bin/su" "/magisk/.core/bin/su")
    else
        su_search_paths+=("$SUDO_SU_PATH")
    fi

    local su
    local su_found=0
    local su_help=""

    for su in "${su_search_paths[@]}"; do
        if [ -x "$su" ]; then
            sudo_log 3 "A su binary found at '$su'"
            su_found=1

            sudo_unset_pre_su_variables
            # Redirect stderr to stdout since some su variants like
            # Android debug build su at `/system/xbin/su` prints helps on stderr.
            su_help="$($su --help 2>&1 < /dev/null)"
            sudo_set_post_su_variables

            # If '-c' option is not supported, then continue searching
            if [[ "$su_help" != *"-c,"* ]] && [[ "$su_help" != *"-c "* ]]; then
                sudo_log 3 "The su binary found does not support '-c' option, continuing search"
                continue
            # If '--shell' option is not supported, then continue searching
            elif [[ "$su_help" != *"--shell"* ]]; then
                sudo_log 3 "The su binary found does not support '--shell' option, continuing search"
                continue
            # If '--preserve-environment' option is not supported, then continue searching
            elif [[ "$su_help" != *"--preserve-environment"* ]]; then
                sudo_log 3 "The su binary found does not support '--preserve-environment' option, continuing search"
                continue
            # If '--mount-master' option is not supported, then continue searching
            elif [[ "$su_help" != *"--mount-master"* ]]; then
                sudo_log 3 "The su binary found does not support '--mount-master' option, continuing search"
                continue
            # Else use the su
            else
                SU="$su"

                SU_BIN_PATH_BASENAME="${SU##*/}" # Strip longest match of */ from start
                SU_BIN_PATH="${SU:0:${#SU} - ${#SU_BIN_PATH_BASENAME}}" # Substring from 0 to position of basename
                case "$SU_BIN_PATH" in *[!/]*/) SU_BIN_PATH="${SU_BIN_PATH%"${SU_BIN_PATH##*[!/]}"}";; *[/]) SU_BIN_PATH="/";; esac # Remove trailing slashes if not root

                # If '--interactive' option is supported.
                # - https://github.com/topjohnwu/Magisk/commit/4864c1112
                if [[ "$su_help" == *"--interactive"* ]]; then
                    SU_INTERACTIVE_OPTION_SUPPORTED=1
                fi

                break
            fi

            sudo_log 3 ""
        fi
    done

    # If SU is not set
    if [ -z "$SU" ]; then
        # If su_found is not set to "1"
        if [[ "$su_found" != "1" ]]; then
            sudo_log_errors "No 'su' binary found"
        else
            sudo_log_errors "No 'su' binary found that supports the '-c', '--shell', '--preserve-environment' and '--mount-master' options"
        fi

        sudo_log_errors "SU_SEARCH_PATHS: ${su_search_paths[*]}"
        sudo_log_errors "sudo requires a 'su' binary that supports the '-c', '--shell', '--preserve-environment' and '--mount-master' options"
        return 1
    fi

    sudo_log 3 "SU='$SU'"
    sudo_log 3 "SU_BIN_PATH='$SU_BIN_PATH'"
    sudo_log 3 "SU_INTERACTIVE_OPTION_SUPPORTED='$SU_INTERACTIVE_OPTION_SUPPORTED'"

    return 0

}
##
# Set the su command that will be used to set up the sudo environment.
##
sudo_set_su_env_command() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_su_env_command"

    # Set SU_ENV_COMMAND_VARIABLES_TO_EXPORT
    sudo_set_su_env_command_variables_to_export || return $?

    SU_ENV_COMMAND="$SU"

    # If ROOTFS_PARTITION_MM_DEPENDENT_PATHS or SYSTEM_PARTITION_MM_DEPENDENT_PATHS is set
    if [ -n "$ROOTFS_PARTITION_MM_DEPENDENT_PATHS" ] || [ -n "$SYSTEM_PARTITION_MM_DEPENDENT_PATHS" ]; then
        # If SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS does not start with the '--mount-master' or '-mm' command option, then
        # add the '--mount-master' option to SU_ENV_COMMAND at the start as required by su
        if [[ ! "${SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS[*]}" =~ $VALID_SU_MOUNT_MASTER_OPTION_PREFIXED_STRING  ]]; then
            SU_ENV_COMMAND+=" --mount-master"
        fi
    fi

    # If SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS is set, then add the options to SU_ENV_COMMAND
    if [ ${#SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS[@]} -ne 0 ]; then
        printf -v "SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS_STRING" "%q " "${SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS[@]}"
        SU_ENV_COMMAND+=" $SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS_STRING"
        SU_ENV_COMMAND="${SU_ENV_COMMAND% }" # Remove trailing space
    fi

    # Explicitly pass `--interactive` option so that `su` allocates a tty with `-c`.
    # - https://github.com/topjohnwu/Magisk/pull/8927
    # - https://github.com/topjohnwu/Magisk/commit/9ddeab03
    # - https://github.com/topjohnwu/Magisk/commit/4864c1112
    if [[ "$SU_INTERACTIVE_OPTION_SUPPORTED" == "1" ]]; then
        SU_ENV_COMMAND+=" --interactive"
    fi

    # We rely on termux to set up most of the environment since it will be dependent on android os and device,
    # hence '--preserve-environment' is required
    # We also source the sudo script in some SU_ENV_COMMAND commands to define its functions
    # so that only the parent function is called within a new su shell instead of
    # calling a new su shell for every root command that needs to be run inside
    # the child functions
    # This has drastic performance improvements in some cases where multiple root
    # commands need to be run since creating a new su shell for each command has too
    # much overhead.
    SU_ENV_COMMAND+=" --preserve-environment --shell $BASH_SHELL_PATH -c $SU_ENV_COMMAND_VARIABLES_TO_EXPORT "

    sudo_log 3 "SU_ENV_COMMAND=\`$SU_ENV_COMMAND\`"

    return 0

}

##
# Set the su command that will be used to run the sudo COMMAND_TYPE command.
##
sudo_set_su_run_command() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_su_run_command"

    SU_RUN_COMMAND="$SU"

    # If ROOTFS_PARTITION_MM_DEPENDENT_PATHS or SYSTEM_PARTITION_MM_DEPENDENT_PATHS is set
    if [ -n "$ROOTFS_PARTITION_MM_DEPENDENT_PATHS" ] || [ -n "$SYSTEM_PARTITION_MM_DEPENDENT_PATHS" ]; then
        # If SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS does not start with the '--mount-master' or '-mm' command option, then
        # add the '--mount-master' option to SU_RUN_COMMAND at the start as required by su
        if [[ ! "${SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS[*]}" =~ $VALID_SU_MOUNT_MASTER_OPTION_PREFIXED_STRING  ]]; then
            SU_RUN_COMMAND+=" --mount-master"
        fi
    fi

    # If SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS is set, then add the options to SU_RUN_COMMAND
    if [ ${#SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS[@]} -ne 0 ]; then
        printf -v "SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS_STRING" "%q " "${SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS[@]}"
        SU_RUN_COMMAND+=" $SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS_STRING"
        SU_RUN_COMMAND="${SU_RUN_COMMAND% }" # Remove trailing space
    fi

    # Explicitly pass `--interactive` option so that `su` allocates a tty with `-c`.
    # - https://github.com/topjohnwu/Magisk/pull/8927
    # - https://github.com/topjohnwu/Magisk/commit/9ddeab03
    # - https://github.com/topjohnwu/Magisk/commit/4864c1112
    if [[ "$SU_INTERACTIVE_OPTION_SUPPORTED" == "1" ]]; then
        SU_RUN_COMMAND+=" --interactive"
    fi

    # If DISABLE_PRESERVE_ENVIRONMENT_FOR_SU is not enabled, then use the option
    if [[ "$DISABLE_PRESERVE_ENVIRONMENT_FOR_SU" != "1" ]]; then
        SU_RUN_COMMAND+=" --preserve-environment"
    fi

    SU_RUN_COMMAND+=" --shell $BASH_SHELL_PATH -c"

    sudo_log 3 "SU_RUN_COMMAND=\`$SU_RUN_COMMAND\`"

    return 0

}

sudo_set_pre_required_variables() {

    local return_value

    # Find android sdk/os version
    # Termux app exports ANDROID__BUILD_VERSION_SDK for `>= v0.119.0`
    if [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $VALID_NUMBER_REGEX ]]; then
        ANDROID__BUILD_VERSION_SDK="$(unset LD_LIBRARY_PATH; unset LD_PRELOAD; getprop "ro.build.version.sdk")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $VALID_NUMBER_REGEX ]]; then
            sudo_log_errors "Failure while finding 'ro.build.version.sdk' property"
            sudo_log_errors "ANDROID__BUILD_VERSION_SDK='$ANDROID__BUILD_VERSION_SDK'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    fi

    sudo_log 3 "ANDROID__BUILD_VERSION_SDK='$ANDROID__BUILD_VERSION_SDK'"



    # Set LD_LIBRARY_PATH for all external commands that may be run
    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        # Set only termux library path
        LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"
    else
        # Do not set termux or android library paths
        LD_LIBRARY_PATH=""
    fi

    SUDO_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"

    sudo_log 3 "LD_LIBRARY_PATH='$LD_LIBRARY_PATH'"

    return 0

}

sudo_set_required_variables() {

    local return_value

    # Do not modify unless you known what you are doing

    sudo_log_literal 3 "\nRunning sudo_set_required_variables"

    # Set LD_PRELOAD
    export LD_PRELOAD="$TERMUX_LD_PRELOAD"

    SUDO_LD_PRELOAD="$LD_PRELOAD"

    local remove_duplicates_in_path_variable=0
    local remove_duplicates_in_ld_library_path_variable=0

    # Store PATH and LD_LIBRARY_PATH
    OLD_PATH="$PATH"
    OLD_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"


    # Set PATH
    PATH="$TERMUX_BIN:$TERMUX_BIN_APPLETS:$SYS_XBIN:$SYS_BIN"

    sudo_log 3 "PATH='$PATH'"


    # Set current working directory
    CURRENT_WORKING_DIR="$PWD"
    # Do not needlessly create a subshell
    if [[ ! "$CURRENT_WORKING_DIR" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]]; then
        # We use `-L` logical mode as its default bash shell behaviour for `pwd` builtin,
        # unlike `pwd` external command, which uses `-P` physical mode by default.
        # - https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-pwd
        # - https://github.com/bminor/bash/blob/bash-5.2/builtins/cd.def#L472
        # - https://man7.org/linux/man-pages/man1/pwd.1.html
        CURRENT_WORKING_DIR="$(pwd -L)"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$CURRENT_WORKING_DIR" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]]; then
            sudo_log_errors "Failure while finding current working directory"
            sudo_log_errors "CURRENT_WORKING_DIR='$CURRENT_WORKING_DIR'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    fi

    sudo_log 3 "CURRENT_WORKING_DIR='$CURRENT_WORKING_DIR'"



    # Set path priority variables to use depending on android or termux priority
    sudo_set_path_priority_variables "$SET_SECONDARY_PATHS"



    # Set variables for PATH_TO_EXPORT
    if [[ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]]; then
        # Set termux followed by android paths to give termux paths priority for `-t` flag
        TERMUX_PRIORITY_PATH="$TERMUX_PATH:$ANDROID_PATH"

        # Set android followed by termux paths to give android paths priority for `-a` flag
        ANDROID_PRIORITY_PATH="$ANDROID_PATH:$TERMUX_PATH"
    else
        # Set only termux paths for `-T` and `-TT` flag
        # No need to add SU_BIN_PATH as termux su wrapper in TERMUX_BIN would override it
        TERMUX_PRIORITY_PATH="$TERMUX_PATH"

        # Set only android paths for `-A` and `-AA` flag
        ANDROID_PRIORITY_PATH="$ANDROID_PATH"
    fi


    # If SUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE is enabled and OLD_PATH is not empty, then append it to PATH variables
    if [[ "$SUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE" == "1" ]] && [ -n "$OLD_PATH" ]; then
        TERMUX_PRIORITY_PATH+=":$OLD_PATH"
        ANDROID_PRIORITY_PATH+=":$OLD_PATH"
        remove_duplicates_in_path_variable=1
    fi

    # If SUDO_ADDITIONAL_PATHS_TO_EXPORT is not empty, then append it to PATH variables
    if [ -n "$SUDO_ADDITIONAL_PATHS_TO_EXPORT" ]; then
        TERMUX_PRIORITY_PATH+=":$SUDO_ADDITIONAL_PATHS_TO_EXPORT"
        ANDROID_PRIORITY_PATH+=":$SUDO_ADDITIONAL_PATHS_TO_EXPORT"
        remove_duplicates_in_path_variable=1
    fi


    # Remove_duplicates_in_path_variable is only enabled if custom paths are added to the PATH variables
    # This will reduce execution time since an external call to awk with a subshell will be made
    # Default paths set must not have any duplicates

    # Remove duplicates from TERMUX_PRIORITY_PATH and check if it is valid and can be used as the PATH variable
    sudo_parse_and_validate_path_variable "TERMUX_PRIORITY_PATH" "TERMUX_PRIORITY_PATH" "$TERMUX_PRIORITY_PATH" "$remove_duplicates_in_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to parse and validate 'TERMUX_PRIORITY_PATH'"
        return $return_value
    fi

    # Remove duplicates from ANDROID_PRIORITY_PATH and check if it is valid and can be used as the PATH variable
    sudo_parse_and_validate_path_variable "ANDROID_PRIORITY_PATH" "ANDROID_PRIORITY_PATH" "$ANDROID_PRIORITY_PATH" "$remove_duplicates_in_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to parse and validate 'ANDROID_PRIORITY_PATH'"
        return $return_value
    fi


    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        # Set only termux library path for all `-t`, `-T` and `-TT` flags
        TERMUX_PRIORITY_LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"

        # Set only termux library path for `-a` flag but not for `-A` and `-AA` flags
        if [[ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]]; then
            ANDROID_PRIORITY_LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"
        else
            ANDROID_PRIORITY_LD_LIBRARY_PATH=""
        fi
    else
        # Do not set termux or android library paths for any flags
        TERMUX_PRIORITY_LD_LIBRARY_PATH=""
        ANDROID_PRIORITY_LD_LIBRARY_PATH=""
    fi


    # If SUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE is enabled and OLD_LD_LIBRARY_PATH is not empty, then append it to LD_LIBRARY_PATH variables
    if [[ "$SUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE" == "1" ]] && [ -n "$OLD_LD_LIBRARY_PATH" ]; then
        TERMUX_PRIORITY_LD_LIBRARY_PATH+=":$OLD_LD_LIBRARY_PATH"
        ANDROID_PRIORITY_LD_LIBRARY_PATH+=":$OLD_LD_LIBRARY_PATH"
        remove_duplicates_in_ld_library_path_variable=1
    fi

    # If SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT is not empty, then append it to LD_LIBRARY_PATH variables
    if [ -n "$SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT" ]; then
        TERMUX_PRIORITY_LD_LIBRARY_PATH+=":$SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT"
        ANDROID_PRIORITY_LD_LIBRARY_PATH+=":$SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT"
        remove_duplicates_in_ld_library_path_variable=1
    fi


    # Remove_duplicates_in_path_variable is only enabled if custom paths are added to the LD_LIBRARY_PATH variables
    # This will reduce execution time since an external call to awk with a subshell will be made
    # Default paths set must not have any duplicates

    # Remove duplicates from TERMUX_PRIORITY_LD_LIBRARY_PATH and check if it is valid and can be used as the LD_LIBRARY_PATH variable
    sudo_parse_and_validate_path_variable "TERMUX_PRIORITY_LD_LIBRARY_PATH" "TERMUX_PRIORITY_LD_LIBRARY_PATH" "$TERMUX_PRIORITY_LD_LIBRARY_PATH" "$remove_duplicates_in_ld_library_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to parse and validate 'TERMUX_PRIORITY_LD_LIBRARY_PATH'"
        return $return_value
    fi

    # Remove duplicates from ANDROID_PRIORITY_LD_LIBRARY_PATH and check if it is valid and can be used as the LD_LIBRARY_PATH variable
    sudo_parse_and_validate_path_variable "ANDROID_PRIORITY_LD_LIBRARY_PATH" "ANDROID_PRIORITY_LD_LIBRARY_PATH" "$ANDROID_PRIORITY_LD_LIBRARY_PATH" "$remove_duplicates_in_ld_library_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to parse and validate 'ANDROID_PRIORITY_LD_LIBRARY_PATH'"
        return $return_value
    fi



    # Set TERMUX_PRIORITY_LD_PRELOAD_COMMAND to set LD_PRELOAD to libtermux-exec.so
    TERMUX_PRIORITY_LD_PRELOAD_COMMAND="export LD_PRELOAD='${LD_PRELOAD//\'/\'\\\'\'}';"

    # Set ANDROID_PRIORITY_LD_PRELOAD_COMMAND to unset LD_PRELOAD
    ANDROID_PRIORITY_LD_PRELOAD_COMMAND="unset LD_PRELOAD;"



    # Set SUDO_SHELL_HOME
    sudo_trim_trailing_newlines "SUDO_SHELL_HOME" "$SUDO_SHELL_HOME"

    # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in SUDO_SHELL_HOME
    # Canonicalize_path is only enabled if a custom path was passed for SUDO_SHELL_HOME by the user
    # This will reduce execution time since an external call to readlink with a subshell will be made
    sudo_expand_termux_path "SUDO_SHELL_HOME" "SUDO_SHELL_HOME" "$SUDO_SHELL_HOME" "$TERMUX_PREFIX" "$TERMUX_HOME" "$CUSTOM_SUDO_SHELL_HOME_SET"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to expand SUDO_SHELL_HOME '$SUDO_SHELL_HOME'"
        return $return_value
    fi

    # If SUDO_SHELL_HOME is not a valid absolute path
    if [[ ! "$SUDO_SHELL_HOME" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "The SUDO_SHELL_HOME '$SUDO_SHELL_HOME' is not a valid absolute path"
        return 1
    fi

    sudo_log 3 "SUDO_SHELL_HOME='$SUDO_SHELL_HOME'"

    # Find the parent directory of the SUDO_SHELL_HOME
    SUDO_SHELL_HOME_BASENAME="${SUDO_SHELL_HOME##*/}" # Strip longest match of */ from start
    SUDO_SHELL_HOME_PARENT_DIR="${SUDO_SHELL_HOME:0:${#SUDO_SHELL_HOME} - ${#SUDO_SHELL_HOME_BASENAME}}" # Substring from 0 to position of basename
    case "$SUDO_SHELL_HOME_PARENT_DIR" in *[!/]*/) SUDO_SHELL_HOME_PARENT_DIR="${SUDO_SHELL_HOME_PARENT_DIR%"${SUDO_SHELL_HOME_PARENT_DIR##*[!/]}"}";; *[/]) SUDO_SHELL_HOME_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    sudo_log 3 "SUDO_SHELL_HOME_PARENT_DIR='$SUDO_SHELL_HOME_PARENT_DIR'"


    # Use SUDO_SHELL_HOME as SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY
    SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY="$SUDO_SHELL_HOME"



    # If SUDO_POST_SHELL_HOME is set
    if [ -n "$SUDO_POST_SHELL_HOME" ]; then
        # Set SUDO_POST_SHELL_HOME
        sudo_trim_trailing_newlines "SUDO_POST_SHELL_HOME" "$SUDO_POST_SHELL_HOME"

        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in SUDO_POST_SHELL_HOME
        # Canonicalize_path is only enabled if a custom path was passed for SUDO_POST_SHELL_HOME by the user
        # This will reduce execution time since an external call to readlink with a subshell will be made
        sudo_expand_termux_path "SUDO_POST_SHELL_HOME" "SUDO_POST_SHELL_HOME" "$SUDO_POST_SHELL_HOME" "$TERMUX_PREFIX" "$TERMUX_HOME" "$CUSTOM_SUDO_POST_SHELL_HOME_SET"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to expand 'SUDO_POST_SHELL_HOME'"
            return $return_value
        fi

        # If SUDO_POST_SHELL_HOME is not a valid absolute path
        if [[ ! "$SUDO_POST_SHELL_HOME" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            sudo_log_errors "The SUDO_POST_SHELL_HOME '$SUDO_POST_SHELL_HOME' is not a valid absolute path"
            return 1
        fi

        sudo_log 3 "SUDO_POST_SHELL_HOME='$SUDO_POST_SHELL_HOME'"

        # Find the parent directory of the SUDO_POST_SHELL_HOME
        SUDO_POST_SHELL_HOME_BASENAME="${SUDO_POST_SHELL_HOME##*/}" # Strip longest match of */ from start
        SUDO_POST_SHELL_HOME_PARENT_DIR="${SUDO_POST_SHELL_HOME:0:${#SUDO_POST_SHELL_HOME} - ${#SUDO_POST_SHELL_HOME_BASENAME}}" # Substring from 0 to position of basename
        case "$SUDO_POST_SHELL_HOME_PARENT_DIR" in *[!/]*/) SUDO_POST_SHELL_HOME_PARENT_DIR="${SUDO_POST_SHELL_HOME_PARENT_DIR%"${SUDO_POST_SHELL_HOME_PARENT_DIR##*[!/]}"}";; *[/]) SUDO_POST_SHELL_HOME_PARENT_DIR="/";; esac # Remove trailing slashes if not root

        sudo_log 3 "SUDO_POST_SHELL_HOME_PARENT_DIR='$SUDO_POST_SHELL_HOME_PARENT_DIR'"
    fi



    # If SUDO_SHELL_WORKING_DIR is set
    if [ -n "$SUDO_SHELL_WORKING_DIR" ]; then
        # Set SUDO_SHELL_WORKING_DIR
        sudo_set_sudo_shell_working_dir || return $?
    fi



    # Create TMPDIR if missing
    sudo_setup_termux_tmp_dir || return $?



    # Set ROOTFS_PARTITION_*_DEPENDENT_PATHS and SYSTEM_PARTITION_*_DEPENDENT_PATHS
    # ROOTFS_PARTITION_MM_DEPENDENT_PATHS and SYSTEM_PARTITION_MM_DEPENDENT_PATHS are
    # required by sudo_set_su_env_command and sudo_set_su_run_command functions to
    # add '--mount-master option' to SU_ENV_COMMAND and SU_RUN_COMMAND if required.
    # ROOTFS_PARTITION_RW_DEPENDENT_PATHS and SYSTEM_PARTITION_RW_DEPENDENT_PATHS are
    # required by the sudo_remount_partitions_for_sudo_shell_homes function to
    # remount rootfs `/` or system `/system` partition.
    # Using parent directories for rootfs checks since some directories in root like /mnt may
    # require rootfs to be mounted as rw to be writeable
    ROOTFS_PARTITION_RW_DEPENDENT_PATHS=""
    SYSTEM_PARTITION_RW_DEPENDENT_PATHS=""


    # The SUDO_SHELL_HOME and SUDO_POST_SHELL_HOME must be rw, and hence
    # always added to *_PARTITION_RW_DEPENDENT_PATHS.

    # If SUDO_SHELL_HOME is in system "/system" partition
    if [[ "$SUDO_SHELL_HOME" =~ $VALID_PATH_IN_SYSTEM_PARTITION_REGEX ]]; then
        SYSTEM_PARTITION_RW_DEPENDENT_PATHS+=" SUDO_SHELL_HOME '$SUDO_SHELL_HOME'"
    # If SUDO_SHELL_HOME_PARENT_DIR is in rootfs "/" partition
    elif [[ "$SUDO_SHELL_HOME_PARENT_DIR" =~ $VALID_PATH_IN_ROOTFS_PARTITION_REGEX ]]; then
        ROOTFS_PARTITION_RW_DEPENDENT_PATHS+=" SUDO_SHELL_HOME '$SUDO_SHELL_HOME'"
    fi

    # If SUDO_POST_SHELL_HOME is in system "/system" partition
    if [[ "$SUDO_POST_SHELL_HOME" =~ $VALID_PATH_IN_SYSTEM_PARTITION_REGEX ]]; then
        SYSTEM_PARTITION_RW_DEPENDENT_PATHS+=" SUDO_POST_SHELL_HOME '$SUDO_POST_SHELL_HOME'"
    # If SUDO_POST_SHELL_HOME_PARENT_DIR is in rootfs "/" partition
    elif [[ "$SUDO_POST_SHELL_HOME_PARENT_DIR" =~ $VALID_PATH_IN_ROOTFS_PARTITION_REGEX ]]; then
        ROOTFS_PARTITION_RW_DEPENDENT_PATHS+=" SUDO_POST_SHELL_HOME '$SUDO_POST_SHELL_HOME'"
    fi

    ROOTFS_PARTITION_MM_DEPENDENT_PATHS="$ROOTFS_PARTITION_RW_DEPENDENT_PATHS"
    SYSTEM_PARTITION_MM_DEPENDENT_PATHS="$SYSTEM_PARTITION_RW_DEPENDENT_PATHS"


    # The SUDO_SHELL_WORKING_DIR normally only needs to be readable,
    # but if it does not exist, then its parent partition must be rw.
    # Since rw remount is only possible on android `< 10`, its only added
    # to *_PARTITION_RW_DEPENDENT_PATHS for lower versions and if it
    # does not already exist to allow using an already existing directory
    # like `/` or `/system` on android `>= 10`.
    # If passing a non-existent directory on android `>= 10`, then
    # `mkdir` called by sudo_setup_sudo_shell_working_dir will error
    # out with `cannot create directory '/path': Read-only file system`
    local sudo_shell_working_dir_exists=0
    [ -d "$SUDO_SHELL_WORKING_DIR" ] && sudo_shell_working_dir_exists=1

    # If SUDO_SHELL_WORKING_DIR is in system "/system" partition
    if [[ "$SUDO_SHELL_WORKING_DIR" =~ $VALID_PATH_IN_SYSTEM_PARTITION_REGEX ]]; then
        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 29 ] && [ "$sudo_shell_working_dir_exists" != "1" ]; then
            SYSTEM_PARTITION_RW_DEPENDENT_PATHS+=" SUDO_SHELL_WORKING_DIR '$SUDO_SHELL_WORKING_DIR'"
        fi

        SYSTEM_PARTITION_MM_DEPENDENT_PATHS+=" SUDO_SHELL_WORKING_DIR '$SUDO_SHELL_WORKING_DIR'"
    # If SUDO_SHELL_WORKING_DIR_PARENT_DIR is under rootfs "/" partition
    elif [ "$SUDO_SHELL_WORKING_DIR" != "/" ] && [[ "$SUDO_SHELL_WORKING_DIR_PARENT_DIR" =~ $VALID_PATH_IN_ROOTFS_PARTITION_REGEX ]]; then
        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 29 ] && [ "$sudo_shell_working_dir_exists" != "1" ]; then
            ROOTFS_PARTITION_RW_DEPENDENT_PATHS+=" SUDO_SHELL_WORKING_DIR '$SUDO_SHELL_WORKING_DIR'"
        fi

        ROOTFS_PARTITION_MM_DEPENDENT_PATHS+=" SUDO_SHELL_WORKING_DIR '$SUDO_SHELL_WORKING_DIR'"
    fi

    # If ROOTFS_PARTITION_RW_DEPENDENT_PATHS or SYSTEM_PARTITION_RW_DEPENDENT_PATHS is set
    if [ -n "$ROOTFS_PARTITION_RW_DEPENDENT_PATHS" ] || [ -n "$SYSTEM_PARTITION_RW_DEPENDENT_PATHS" ]; then
        # If android `>= 10`
        if [ "$ANDROID__BUILD_VERSION_SDK" -ge 29 ]; then
            [ -n "$ROOTFS_PARTITION_RW_DEPENDENT_PATHS" ] && sudo_log_errors "The rootfs '/' partition cannot be mounted as rw to be used for$ROOTFS_PARTITION_RW_DEPENDENT_PATHS since in android >= 10 the rootfs partition is likely a read-only system-as-root SAR partition"
            [ -n "$SYSTEM_PARTITION_RW_DEPENDENT_PATHS" ] && sudo_log_errors "The system '/system' partition cannot be mounted as rw to be used for$SYSTEM_PARTITION_RW_DEPENDENT_PATHS since in android >= 10 the system partition is an ext4 dedup filesystem"
            return 1
        fi

        if [ -n "$SYSTEM_PARTITION_RW_DEPENDENT_PATHS" ] && [[ "$(cat /proc/self/mounts)" == *"/.magisk/mirror/system"* ]]; then
             sudo_log_errors "The system '/system' partition cannot be mounted as rw to be used for$SYSTEM_PARTITION_RW_DEPENDENT_PATHS since magisk system mirror is a read-only partition"
            return 1
        fi
    fi

    return 0

}

##
# Set termux and android path priority variables that should be used
# depending on required priority.
#
#
# `sudo_set_path_priority_variables` `<set_secondary_paths>`
sudo_set_path_priority_variables() {

    local set_secondary_paths="$1"

    # Set TERMUX_PATH
    if [[ "$set_secondary_paths" == "1" ]]; then
        TERMUX_PATH="$TERMUX_BIN:$TERMUX_BIN_APPLETS"
    else
        TERMUX_PATH="$TERMUX_BIN"
    fi


    # Set ANDROID_PATH
    if [[ "$set_secondary_paths" == "1" ]]; then
        # If android >= 11
        if [ "$ANDROID__BUILD_VERSION_SDK" -ge 30 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-11.0.0_r1:bionic/libc/include/paths.h;l=50
            # - https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/include/paths.h;l=50
            ANDROID_PATH="/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"
        # If android >= 10
        elif [ "$ANDROID__BUILD_VERSION_SDK" -ge 29 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-10.0.0_r1:bionic/libc/include/paths.h;l=50
            ANDROID_PATH="/sbin:/system/sbin:/product/bin:/apex/com.android.runtime/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
        # If android >= 9
        elif [ "$ANDROID__BUILD_VERSION_SDK" -ge 28 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-9.0.0_r1:bionic/libc/include/paths.h;l=41
            ANDROID_PATH="/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
        # If android >= 8
        elif [ "$ANDROID__BUILD_VERSION_SDK" -ge 26 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-8.0.0_r1:bionic/libc/include/paths.h;l=39
            ANDROID_PATH="/sbin:/system/sbin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin"
        # If android < 8   
        # - https://cs.android.com/android/platform/superproject/+/android-7.0.0_r1:bionic/libc/include/paths.h;l=37    
        else
            ANDROID_PATH="/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin"
        fi

        # If SU_BIN_PATH is not empty and if it does not already exist in ANDROID_PATH, then append it to ANDROID_PATH
        if [ -n "$SU_BIN_PATH" ] && [[ "$SU_BIN_PATH" != *:* ]] && [[ ":$ANDROID_PATH:" != *":$SU_BIN_PATH:"* ]]; then
            ANDROID_PATH+=":$SU_BIN_PATH"
        fi
    else
        ANDROID_PATH="$SYS_BIN"
    fi

    return 0

}

##
# Function that should be called before running su commands.
# This will unset variable so that some su binaries like the ones provided by magisk run successfully.
#
# `sudo_unset_pre_su_variables`
##
sudo_unset_pre_su_variables() {

    unset LD_PRELOAD
    if [ "$ANDROID__BUILD_VERSION_SDK" -ge 24 ]; then
        unset LD_LIBRARY_PATH
    fi

    return 0

}

##
# Function that should be called after running su commands.
# This will reset variable previously unset by sudo_unset_pre_su_variables so that sudo script commands run successfully.
#
# `sudo_set_post_su_variables`
##
sudo_set_post_su_variables() {

    LD_PRELOAD="$SUDO_LD_PRELOAD"
    LD_LIBRARY_PATH="$SUDO_LD_LIBRARY_PATH"

    return 0

}

##
# Set variables to export with priority to termux or android bin and library paths.
#
# `priority` must be one of `termux` or `android`.
#
# `sudo_set_priority_dependent_variables` `<priority>`
##
sudo_set_priority_dependent_variables() {

    local return_value

    # If argument count is not 1
    if [ $# -ne 1 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_priority_dependent_variables'"
        return 1
    fi

    local priority="$1"

    if [[ "$priority" != "termux" ]] && [[ "$priority" != "android" ]]; then
        sudo_log_errors "priority '$priority' passed to 'sudo_set_priority_dependent_variables' does not equal 'termux' or 'android'"
        return 1
    fi

    # If priority to the previous call to this function was the same, then just return
    if [[ "$priority" == "$previous_priority_dependent_variables_priortiy" ]]; then
        return 0
    fi

    sudo_log_literal 3 "\nRunning sudo_set_priority_dependent_variables with priority '$priority'"

    # Set PATH_TO_EXPORT
    # If priority equals "termux" then PATH_TO_EXPORT should be set to TERMUX_PRIORITY_PATH
    if [[ "$priority" == "termux" ]]; then
        PATH_TO_EXPORT="$TERMUX_PRIORITY_PATH"
    # If priority equals "android" then PATH_TO_EXPORT should be set to ANDROID_PRIORITY_PATH
    else
        PATH_TO_EXPORT="$ANDROID_PRIORITY_PATH"
    fi

    sudo_log 3 "PATH_TO_EXPORT='$PATH_TO_EXPORT'"


    # If priority equals "termux" then LD_LIBRARY_PATH_TO_EXPORT should be set to TERMUX_PRIORITY_LD_LIBRARY_PATH
    if [[ "$priority" == "termux" ]]; then
        LD_LIBRARY_PATH_TO_EXPORT="$TERMUX_PRIORITY_LD_LIBRARY_PATH"
    # If priority equals "android" then LD_LIBRARY_PATH_TO_EXPORT should be set to ANDROID_PRIORITY_LD_LIBRARY_PATH
    else
        LD_LIBRARY_PATH_TO_EXPORT="$ANDROID_PRIORITY_LD_LIBRARY_PATH"
    fi

    sudo_log 3 "LD_LIBRARY_PATH_TO_EXPORT='$LD_LIBRARY_PATH_TO_EXPORT'"


    # If priority equals "termux" then LD_PRELOAD_COMMAND should be set to TERMUX_PRIORITY_LD_PRELOAD_COMMAND
    if [[ "$priority" == "termux" ]]; then
        LD_PRELOAD_COMMAND="$TERMUX_PRIORITY_LD_PRELOAD_COMMAND"
    # If priority equals "android" then LD_PRELOAD_COMMAND should be set to ANDROID_PRIORITY_LD_PRELOAD_COMMAND
    else
        LD_PRELOAD_COMMAND="$ANDROID_PRIORITY_LD_PRELOAD_COMMAND"
    fi

    sudo_log 3 "LD_PRELOAD_COMMAND='$LD_PRELOAD_COMMAND'"


    previous_priority_dependent_variables_priortiy="$priority"

    return 0

}

##
# The function is used to export variables so that they can be used from within the SU_ENV_COMMAND su bash shell
# The variables must be unexported after the sudo environment has been setup up
# And only the COMMAND_TYPE SU_RUN_COMMAND su needs to be run
# The COMMAND_TYPE su shell should not have the variables of the sudo script in its environment
#
# `command` must be one of `export` or `unexport`.
#
# `sudo_export_or_unexport_shared_variables_for_su` `<command>`
##
sudo_export_or_unexport_shared_variables_for_su() {

    local return_value

    # If argument count is not 1
    if [ $# -ne 1 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_export_or_unexport_shared_variables_for_su'"
        return 1
    fi

    local command="$1"

    if [[ "$command" != "export" ]] && [[ "$command" != "unexport" ]]; then
        sudo_log_errors "command '$command' passed to 'sudo_export_or_unexport_shared_variables_for_su' does not equal 'export' or 'unexport'"
        return 1
    fi

    # If command equals "unexport"
    if [[ "$command" == "unexport" ]]; then
        command="export -n"
    fi

    $command SUDO_LOG_LEVEL

    if [ -n "$sudo_start_time" ]; then
        $command sudo_start_time
    fi

    return 0

}

sudo_set_su_env_command_variables_to_export() {

    local return_value

    # Set SU_ENV_COMMAND_VARIABLES_TO_EXPORT
    SU_ENV_COMMAND_VARIABLES_TO_EXPORT="export PATH='${PATH_TO_EXPORT//\'/\'\\\'\'}'; export LD_LIBRARY_PATH='${LD_LIBRARY_PATH_TO_EXPORT//\'/\'\\\'\'}'; export HOME='${SUDO_SHELL_HOME//\'/\'\\\'\'}'; export LANG='${LANG//\'/\'\\\'\'}'; $LD_PRELOAD_COMMAND"

    return 0

}

sudo_add_export_or_unset_var_command() {

    local var_to_update="$1"
    local var_to_export="$2"
    local var_value="$3"

    if [ -n "$var_value" ]; then
        printf -v "$var_to_update" "%s" "${!var_to_update}export $var_to_export='${var_value//\'/\'\\\'\'}';"$'\n'
    else
        # Do not export empty variable as it will appear in environ
        # And unset it if it already exists
        printf -v "$var_to_update" "%s" "${!var_to_update}unset $var_to_export;"$'\n'
    fi

}

sudo_set_pre_sudo_shell_commands_to_run() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_pre_sudo_shell_commands_to_run"

    local priority

    # Set PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to required bin and library paths

    # If COMMAND_TYPE equals "su"
    if [[ "$COMMAND_TYPE" == "su" ]]; then
        priority="termux"
        sudo_log 3 "Setting PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to 'termux' bin and library paths for COMMAND_TYPE 'su'"

    # If COMMAND_TYPE equals "asu"
    elif [[ "$COMMAND_TYPE" == "asu" ]]; then
        priority="android"
        sudo_log 3 "Setting PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to 'android' bin and library paths for COMMAND_TYPE 'asu'"

    # If COMMAND_TYPE equals "path"
    elif [[ "$COMMAND_TYPE" == "path" ]]; then
        # If PATH_PRIORITY is android or termux
        if [[ "$PATH_PRIORITY" == "android" ]] || [[ "$PATH_PRIORITY" == "termux" ]]; then
            priority="$PATH_PRIORITY"
            sudo_log 3 "Setting PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to '$priority' bin and library paths for COMMAND_TYPE 'path' since PATH_PRIORITY is '$PATH_PRIORITY'"
        # If PATH_PRIORITY is default
        else
            # If SUDO_CANONICAL_PATH_COMMAND is under termux rootfs
            if [[ "$SUDO_CANONICAL_PATH_COMMAND" == "$TERMUX_ROOTFS"/* ]]; then
                priority="termux"
                sudo_log 3 "Setting PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to 'termux' bin and library paths for COMMAND_TYPE 'path' since SUDO_PATH_COMMAND is under termux rootfs"
            else
                priority="android"
                sudo_log 3 "Setting PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to 'android' bin and library paths for COMMAND_TYPE 'path' since SUDO_PATH_COMMAND is not under termux rootfs"
            fi
        fi

    # If COMMAND_TYPE equals "script"
    else
        # If PATH_PRIORITY is android
        if [[ "$PATH_PRIORITY" == "android" ]]; then
            priority="android"
        # If PATH_PRIORITY is default or termux    
        else
            priority="termux"
        fi
        sudo_log 3 "Setting PRE_SUDO_SHELL_COMMANDS_TO_RUN with priority to '$priority' bin and library paths for COMMAND_TYPE 'script' since PATH_PRIORITY is '$PATH_PRIORITY'"
    fi

    # Set priority_dependent_variables with new priority if needed
    sudo_set_priority_dependent_variables "$priority" || return $?

    # Set PRE_SUDO_SHELL_COMMANDS_TO_RUN
    # Set variables that need to be exported when running the sudo shell
    PRE_SUDO_SHELL_COMMANDS_TO_RUN=""

    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export PATH='${PATH_TO_EXPORT//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export SUDO__TERMUX_PRIORITY_PATH='${TERMUX_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export SUDO__ANDROID_PRIORITY_PATH='${ANDROID_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'

    sudo_add_export_or_unset_var_command "PRE_SUDO_SHELL_COMMANDS_TO_RUN" "LD_LIBRARY_PATH" "$LD_LIBRARY_PATH_TO_EXPORT" || return $?
    sudo_add_export_or_unset_var_command "PRE_SUDO_SHELL_COMMANDS_TO_RUN" "SUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH" "$TERMUX_PRIORITY_LD_LIBRARY_PATH" || return $?
    sudo_add_export_or_unset_var_command "PRE_SUDO_SHELL_COMMANDS_TO_RUN" "SUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH" "$ANDROID_PRIORITY_LD_LIBRARY_PATH" || return $?
 
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}ROOTFS='${TERMUX_ROOTFS//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}HOME='${TERMUX_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'
    # If `$PREFIX` already exported when running `sudo`, only then export it
    [[ ! "$PREFIX" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]] && \
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'

    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export TMPDIR='${TMPDIR//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export HOME='${SUDO_SHELL_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export TERM='${TERM//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export LANG='${LANG//\'/\'\\\'\'}';"$'\n'

    # If COMMAND_TYPE equals "script" and DISABLE_STDIN_FOR_CORE_SCRIPT is enabled
    if [[ "$COMMAND_TYPE" == "script" ]] && [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]]; then
        # Unset PS1 so that scripts run by script shells can check that interactive shell is not available
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="unset PS1;"$'\n'
    else
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export PS1='${SUDO_SHELL_PS1//\'/\'\\\'\'}';"$'\n'
    fi

    # If LD_PRELOAD_COMMAND is not empty, then append it to PRE_SUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$LD_PRELOAD_COMMAND" ]; then
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="$LD_PRELOAD_COMMAND"$'\n'
    fi
    PRE_SUDO_SHELL_COMMANDS_TO_RUN+="export SUDO__TERMUX_LD_PRELOAD='${TERMUX_LD_PRELOAD//\'/\'\\\'\'}';"$'\n'

    # If SUDO_SHELL_RCFILE_COMMANDS is not empty, then append it to PRE_SUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$SUDO_SHELL_RCFILE_COMMANDS" ]; then
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="$SUDO_SHELL_RCFILE_COMMANDS"$'\n'
    fi

    # If SUDO_SHELL_HISTFILE_COMMANDS is not empty, then append it to PRE_SUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$SUDO_SHELL_HISTFILE_COMMANDS" ]; then
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="$SUDO_SHELL_HISTFILE_COMMANDS"$'\n'
    fi

    # If SET_SUDO_SHELL_TERMINAL_TITLE is enabled and stdout is available, then add command to set terminal title to PRE_SUDO_SHELL_COMMANDS_TO_RUN
    if [[ "$SET_SUDO_SHELL_TERMINAL_TITLE" == "1" ]] && [ -t 1 ]; then
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+='echo -ne "\e]0;'"$SUDO_SHELL_TERMINAL_TITLE"'\a";'$'\n'
    fi

    # If SUDO_SHELL_WORKING_DIR is set, then append cd command to PRE_SUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$SUDO_SHELL_WORKING_DIR" ]; then
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="cd -- '${SUDO_SHELL_WORKING_DIR//\'/\'\\\'\'}';"$'\n'
    # Otherwise append current working directory in case su changes it
    else
        PRE_SUDO_SHELL_COMMANDS_TO_RUN+="cd -- '${CURRENT_WORKING_DIR//\'/\'\\\'\'}';"$'\n'
    fi

    # If COMMAND_TYPE equals "su", "asu" or "path"
    if [[ "$COMMAND_TYPE" == "su" ]] || [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "path" ]]; then
        # If ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN is not empty, then append it to PRE_SUDO_SHELL_COMMANDS_TO_RUN
        if [ -n "$ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN" ]; then
            PRE_SUDO_SHELL_COMMANDS_TO_RUN+="$ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN"$'\n\n'
        fi
    fi

    #sudo_log 3 $'\n'"PRE_SUDO_SHELL_COMMANDS_TO_RUN='$PRE_SUDO_SHELL_COMMANDS_TO_RUN'"

    return 0

}

sudo_set_pre_sudo_post_shell_commands_to_run() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_pre_sudo_post_shell_commands_to_run"

    # Set PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN with priority to termux paths
    sudo_log_literal 3 "\nSetting PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN with priority to termux paths"
    local priority="termux"

    # Set priority_dependent_variables with new priority if needed
    sudo_set_priority_dependent_variables "$priority" || return $?

    # Set PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN
    # Set variables that need to be exported when running the sudo post shell
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN=""

    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export PATH='${PATH_TO_EXPORT//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export SUDO__TERMUX_PRIORITY_PATH='${TERMUX_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export SUDO__ANDROID_PRIORITY_PATH='${ANDROID_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'

    sudo_add_export_or_unset_var_command "PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN" "LD_LIBRARY_PATH" "$LD_LIBRARY_PATH_TO_EXPORT" || return $?
    sudo_add_export_or_unset_var_command "PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN" "SUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH" "$TERMUX_PRIORITY_LD_LIBRARY_PATH" || return $?
    sudo_add_export_or_unset_var_command "PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN" "SUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH" "$ANDROID_PRIORITY_LD_LIBRARY_PATH" || return $?

    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}ROOTFS='${TERMUX_ROOTFS//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}HOME='${TERMUX_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'
    # If `$PREFIX` already exported when running `sudo`, only then export it
    [[ ! "$PREFIX" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]] && \
        PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'

    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export TMPDIR='${TMPDIR//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export HOME='${SUDO_POST_SHELL_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export TERM='${TERM//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export LANG='${LANG//\'/\'\\\'\'}';"$'\n'
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export PS1='${SUDO_POST_SHELL_PS1//\'/\'\\\'\'}';"$'\n'

    # If LD_PRELOAD_COMMAND is not empty, then append it to PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN
    if [ -n "$LD_PRELOAD_COMMAND" ]; then
        PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="$LD_PRELOAD_COMMAND"$'\n'
    fi
    PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="export SUDO__TERMUX_LD_PRELOAD='${TERMUX_LD_PRELOAD//\'/\'\\\'\'}';"$'\n'

    # If SUDO_POST_SHELL_RCFILE_COMMANDS is not empty, then append it to PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN
    if [ -n "$SUDO_POST_SHELL_RCFILE_COMMANDS" ]; then
        PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="$SUDO_POST_SHELL_RCFILE_COMMANDS"$'\n'
    fi

    # If SUDO_POST_SHELL_HISTFILE_COMMANDS is not empty, then append it to PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN
    if [ -n "$SUDO_POST_SHELL_HISTFILE_COMMANDS" ]; then
        PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN+="$SUDO_POST_SHELL_HISTFILE_COMMANDS"$'\n'
    fi

    #sudo_log 3 $'\n'"PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN='$PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN'"

    return 0

}

sudo_set_sudo_command_path() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_command_path"

    SUDO_PATH_COMMAND="${SUDO_COMMAND[0]}"

    sudo_log 2 "SUDO_PATH_COMMAND='$SUDO_PATH_COMMAND'"

    # If SUDO_PATH_COMMAND is empty
    if [ -z "$SUDO_PATH_COMMAND" ]; then
        sudo_log_errors "The sudo command path '$SUDO_PATH_COMMAND' is empty"
        return 1
    fi

    # If PATH_PRIORITY is android
    if [[ "$PATH_PRIORITY" == "android" ]]; then
        # Set priority_dependent_variables to android for PATH_TO_EXPORT used by the sudo_find_absolute_path_for_executable_and_validate function
        # We do this now and later in the sudo_set_pre_sudo_shell_commands_to_run function as well once the final SUDO_PATH_COMMAND has been set
        sudo_set_priority_dependent_variables "android" || return $?
    fi

    # Find the absolute path for SUDO_PATH_COMMAND that should be used and validate it
    # SUDO_PATH_COMMAND is either considered an absolute path, otherwise searched for in current working directory or in all the paths in $PATH_TO_EXPORT variable
    # If USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION is enabled
    if [[ "$USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION" == "1" ]]; then
        sudo_unset_pre_su_variables
        SUDO_ABSOLUTE_PATH_COMMAND="$($SU_ENV_COMMAND "source '${SUDO_SCRIPT_PATH//\'/\'\\\'\'}' || exit \$?; \
ANDROID__BUILD_VERSION_SDK='${ANDROID__BUILD_VERSION_SDK//\'/\'\\\'\'}'; \
CURRENT_WORKING_DIR='${CURRENT_WORKING_DIR//\'/\'\\\'\'}'; \
sudo_find_absolute_path_for_executable_and_validate \"SUDO_ABSOLUTE_PATH_COMMAND\" \"SUDO_PATH_COMMAND\" '${SUDO_PATH_COMMAND//\'/\'\\\'\'}' '${PATH_TO_EXPORT//\'/\'\\\'\'}' \"$TERMUX_PREFIX\" \"$TERMUX_HOME\" 1" 2>&1 < /dev/null)"
        return_value=$?
        sudo_set_post_su_variables
        if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
            [ -n "$SUDO_ABSOLUTE_PATH_COMMAND" ] && echo "$SUDO_ABSOLUTE_PATH_COMMAND" 1>&2
        fi
    else
        sudo_find_absolute_path_for_executable_and_validate "SUDO_ABSOLUTE_PATH_COMMAND" "SUDO_PATH_COMMAND" "$SUDO_PATH_COMMAND" "$PATH_TO_EXPORT" "$TERMUX_PREFIX" "$TERMUX_HOME" 0
        return_value=$?
    fi
    if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
        sudo_log_errors "Failure while running 'sudo_find_absolute_path_for_executable_and_validate'"
        return $return_value
    elif [ $return_value -eq 112 ]; then
        sudo_log_errors "Command '$SUDO_PATH_COMMAND' not found"
        sudo_log_errors "Check your spelling and try again"
        return 1
    fi

    SUDO_PATH_COMMAND="$SUDO_ABSOLUTE_PATH_COMMAND"

    sudo_log 2 "SUDO_ABSOLUTE_PATH_COMMAND='$SUDO_ABSOLUTE_PATH_COMMAND'"

    # If SUDO_PATH_COMMAND is not a valid absolute path
    if [[ ! "$SUDO_PATH_COMMAND" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "The SUDO_PATH_COMMAND '$SUDO_PATH_COMMAND' is not a valid absolute path"
        return 1
    fi


    # If PATH_PRIORITY is default
    if [[ "$PATH_PRIORITY" != "android" ]] && [[ "$PATH_PRIORITY" != "termux" ]]; then
        # Find canonical path to be used for setting priority in sudo_set_pre_sudo_shell_commands_to_run
        SUDO_CANONICAL_PATH_COMMAND="$(readlink -m -- "$SUDO_ABSOLUTE_PATH_COMMAND")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$SUDO_CANONICAL_PATH_COMMAND" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            sudo_log_errors "Failure while finding canonical path to sudo path commmand"
            sudo_log_errors "SUDO_CANONICAL_PATH_COMMAND='$SUDO_CANONICAL_PATH_COMMAND'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi

        if [[ "$SUDO_CANONICAL_PATH_COMMAND" != "$SUDO_ABSOLUTE_PATH_COMMAND" ]]; then
            sudo_log 2 "SUDO_CANONICAL_PATH_COMMAND='$SUDO_CANONICAL_PATH_COMMAND'"
        fi
    fi

    return 0

}

sudo_set_sudo_path_command() {

    local return_value

    sudo_log_literal 3 "\n\n\nRunning sudo_set_sudo_path_command"

    # If SUDO_COMMAND is not set
    if [ ${#SUDO_COMMAND[@]} -eq 0 ]; then
        sudo_log_errors "SUDO_COMMAND is not set while running 'sudo_set_sudo_path_command'"
        return 1
    fi

    sudo_log 3 "SUDO_COMMAND_ARRAY_COUNT='${#SUDO_COMMAND[@]}'"

    sudo_log 3 $'\n'"SUDO_PATH_COMMAND=\`$SUDO_PATH_COMMAND\`"

    SUDO_PATH_COMMAND_TO_RUN=""

    # If "su" binary is being run, then unset LD_PRELOAD and LD_LIBRARY_PATH
    # If only "su" was passed without the '-a' option and current directory
    # did not have the "su" binary, then the wrapper script by termux at
    # $PREFIX/bin/su would ideally have been chosen by
    # the sudo_set_sudo_command_path function as SUDO_PATH_COMMAND, in
    # which case the wrapper script would ideally also automatically
    # unset the variables
    if [[ "$SUDO_PATH_COMMAND" == *"/su" ]]; then
        SUDO_PATH_COMMAND_TO_RUN="unset LD_PRELOAD; unset LD_LIBRARY_PATH; "
    fi

    # If SUDO_COMMAND argument size is 1, then only a path was passed to be executed
    if [ ${#SUDO_COMMAND[@]} -eq 1 ]; then

        SUDO_PATH_COMMAND_TO_RUN+="'${SUDO_PATH_COMMAND//\'/\'\\\'\'}'"
    # Else path was passed as $1, followed by arguments that should be passed to the path
    else
        SUDO_COMMAND=("${SUDO_COMMAND[@]:1}") # Remove first element since its the unparsed SUDO_PATH_COMMAND

        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
        if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
            sudo_log 3 "Processing SUDO_PATH_COMMAND_ARGS array as per RUN_COMMAND intent rules"
        fi

        for i in "${!SUDO_COMMAND[@]}"; do
            # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
            if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                # Replace any COMMA_ALTERNATIVE characters with normal commas `,` that exist in {SUDO_COMMAND[$i]}
                if [[ "${SUDO_COMMAND[$i]}" == *"$COMMA_ALTERNATIVE"* ]]; then
                    sudo_log 3 "COMMA_ALTERNATIVE found in SUDO_PATH_COMMAND_ARG $((i+1))"
                    sudo_replace_comma_alternative_chars_with_commas_in_string "SUDO_COMMAND[$i]" "${SUDO_COMMAND[$i]}"
                fi
            fi

            # If DISABLE_ARGUMENTS_LOGGING is not enabled
            if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
                sudo_log 3 "SUDO_PATH_COMMAND_ARG $((i+1))=\`${SUDO_COMMAND[$i]}\`"$'\n'
            fi
        done

        printf -v "SUDO_PATH_COMMAND_ARGS" "%q " "${SUDO_COMMAND[@]}"
        SUDO_PATH_COMMAND_ARGS="${SUDO_PATH_COMMAND_ARGS% }" # Remove trailing space

        SUDO_PATH_COMMAND_ARGS_LENGTH="${#SUDO_PATH_COMMAND_ARGS}"
        sudo_log 3 "SUDO_PATH_COMMAND_ARGS_LENGTH='$SUDO_PATH_COMMAND_ARGS_LENGTH'"


        # The `path` would not contribute much to crossing ARG_MAX since its only a path to a file, unless the path is too long
        # The ARG_MAX would be a concern only when arguments to `path` are passed via process substitution to the sudo script
        # and not as a direct argument since in that case ARG_MAX would have crossed at the point instead
        # If SUDO_PATH_COMMAND_ARGS_LENGTH is greater than SUDO_ARG_MAX_SAFE_LIMIT
        if [[ "$SUDO_PATH_COMMAND_ARGS_LENGTH" -gt "$SUDO_ARG_MAX_SAFE_LIMIT" ]]; then
            sudo_log 2 "Warning! The SUDO_PATH_COMMAND_ARGS_LENGTH '$SUDO_PATH_COMMAND_ARGS_LENGTH' is greater than $((SUDO_ARG_MAX_SAFE_LIMIT / 1024))KB. This may cause an 'Argument list too long' exception."
        fi

        # Pass SUDO_PATH_COMMAND_ARGS to SUDO_PATH_COMMAND
        SUDO_PATH_COMMAND_TO_RUN+="'${SUDO_PATH_COMMAND//\'/\'\\\'\'}' $SUDO_PATH_COMMAND_ARGS"
    fi

    # `SUDO_PATH_COMMAND_TO_RUN` and `SUDO_SCRIPT_COMMAND_TO_RUN` needs
    # to be passed to the `bash` shell inside `su` by the `sudo_run` function.
    # We pass the `SUDO_PATH_COMMAND_TO_RUN` to bash instead of directly
    # passing commands to `su -c` because `LD_PRELOAD` does not work
    # in the later case and scripts that are using `#!/usr/bin/*`
    # shebang instead of Termux shebang fail.
    # Check https://github.com/agnostic-apollo/sudo/blob/master/site/pages/en/projects/docs/developer/guides/su-sub-process-communication/index.md
    # for more info on why `fd` with process substitution is used.
    sudo_get_unsed_file_descriptor_and_path SUDO_PATH_FD SUDO_PATH_FD_PATH "to write SUDO_PATH_COMMAND_TO_RUN" || return $?

    # Use printf to write to SUDO_PATH_FD
    sudo_log_literal 3 "Writing SUDO_PATH_COMMAND_TO_RUN to SUDO_PATH_FD_PATH '$SUDO_PATH_FD_PATH'"
    eval "exec $SUDO_PATH_FD<" <(printf "%s" "$SUDO_PATH_COMMAND_TO_RUN")
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while writing SUDO_PATH_COMMAND_TO_RUN to SUDO_PATH_FD '$SUDO_PATH_FD'"
        return $return_value
    fi

    return 0

}

sudo_set_sudo_script_command() {

    local return_value

    sudo_log_literal 3 "\n\n\nRunning sudo_set_sudo_script_command"

    SUDO_SCRIPT_COMMAND_TO_RUN=$'\n'

    # Append PRE_SUDO_SHELL_COMMANDS_TO_RUN to SUDO_SCRIPT_COMMAND_TO_RUN
    SUDO_SCRIPT_COMMAND_TO_RUN+="$PRE_SUDO_SHELL_COMMANDS_TO_RUN"$'\n\n'

    # If ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN is not empty, then append it to SUDO_SCRIPT_COMMAND_TO_RUN
    if [ -n "$ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN" ]; then
        SUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN"$'\n\n'
    fi

    sudo_log 3 "SUDO_COMMAND_ARRAY_COUNT='${#SUDO_COMMAND[@]}'"

    # If SUDO_CORE_SCRIPT or arguments are passed and SUDO_CORE_SCRIPT is not empty
    # The SUDO_CORE_SCRIPT can optionally not be passed or passed as an empty string so that other "features"
    # of the "script" COMMAND_TYPE can still be used
    if [ ${#SUDO_COMMAND[@]} -ne 0 ] && [ -n "${SUDO_COMMAND[0]}" ]; then

        sudo_log 3 ""

        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
        if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
            sudo_log 3 "Processing SUDO_CORE_SCRIPT and SUDO_CORE_SCRIPT_COMMAND_ARGS array as per RUN_COMMAND intent rules"
        fi

        for i in "${!SUDO_COMMAND[@]}"; do
            # If its the SUDO_CORE_SCRIPT argument and DECODE_CORE_SCRIPT_CONTENT or CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE is enabled
            if [ "$i" -eq 0 ] && { [[ "$DECODE_CORE_SCRIPT_CONTENT" == "1" ]] ||  [[ "$CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE" == "1" ]]; }; then
                # The SUDO_COMMAND[1] contains encoded data or a path to a file so no need to process it
                continue
            fi

            # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
            if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                # Replace any COMMA_ALTERNATIVE characters with normal commas `,` that exist in {SUDO_COMMAND[$i]}
                if [[ "${SUDO_COMMAND[$i]}" == *"$COMMA_ALTERNATIVE"* ]]; then
                    # If its the SUDO_CORE_SCRIPT argument
                    if [ "$i" -eq 0 ]; then
                        sudo_log 3 "COMMA_ALTERNATIVE found in SUDO_CORE_SCRIPT"
                    else
                        sudo_log 3 "COMMA_ALTERNATIVE found in SUDO_CORE_SCRIPT_COMMAND_ARG $((i+1))"
                    fi
                    sudo_replace_comma_alternative_chars_with_commas_in_string "SUDO_COMMAND[$i]" "${SUDO_COMMAND[$i]}"
                fi
            fi

            # If DISABLE_ARGUMENTS_LOGGING is not enabled
            if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
                # If its the SUDO_CORE_SCRIPT argument
                if [ "$i" -eq 0 ]; then
                    sudo_log 3 "SUDO_CORE_SCRIPT=\`${SUDO_COMMAND[$i]}\`"$'\n'
                # Else SUDO_CORE_SCRIPT was passed as $1, followed by arguments that should be passed to the script
                else
                    sudo_log 3 "SUDO_CORE_SCRIPT_COMMAND_ARG $((i+1))=\`${SUDO_COMMAND[$i]}\`"$'\n'
                fi
            fi
        done

        # Set the first argument as SUDO_CORE_SCRIPT
        SUDO_CORE_SCRIPT="${SUDO_COMMAND[0]}"

        # If SUDO_CORE_SCRIPT_TEMP_FILENAME is empty, then use default
        if [ -z "$SUDO_CORE_SCRIPT_TEMP_FILENAME" ]; then
            SUDO_CORE_SCRIPT_TEMP_FILENAME="sudo_script__core_script"
        else
            # Else if user passed the filename with --script-name' option, then
            # strip longest match of */ from start, to remove any directory path passed and keep only the basename
            SUDO_CORE_SCRIPT_TEMP_FILENAME="${SUDO_CORE_SCRIPT_TEMP_FILENAME##*/}"
            # If empty, then use default
            SUDO_CORE_SCRIPT_TEMP_FILENAME="${SUDO_CORE_SCRIPT_TEMP_FILENAME:-sudo_script__core_script}"
        fi

        # Start a new SUDO_SHELL script shell and pass SUDO_CORE_SCRIPT to it
        # The SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL will contain the SUDO_CORE_SCRIPT argument that will be passed to the SUDO_SHELL
        # The way the SUDO_CORE_SCRIPT argument will be passed will depend on script shell capabilities and the options set
        # sudo_set_script_argument_for_script_shell shell_basename heredoc_word heredoc_word_quote script_is_path_to_script_file force_use_temp_script_file decode_script_content script_file_label script_file_name script_file_path/script_content
        sudo_set_script_argument_for_script_shell "$SUDO_SHELL_BASENAME" "SUDO_SCRIPT__CORE_SCRIPT_EOF" "'" "$CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE" "$FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT" "$DECODE_CORE_SCRIPT_CONTENT" "SUDO_CORE_SCRIPT" "$SUDO_CORE_SCRIPT_TEMP_FILENAME" "$SUDO_CORE_SCRIPT"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to create SUDO_CORE_SCRIPT argument commands to pass them to SUDO_SHELL '$SUDO_SHELL'"
            return $return_value
        fi

        # Pass the SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL set by sudo_set_script_argument_for_script_shell to SUDO_SHELL
        printf -v "SUDO_SHELL_COMMAND_STRING" "$SUDO_SHELL_COMMAND_PRINT_FORMAT" "${SUDO_SHELL_COMMAND[@]}"
        SUDO_CORE_SCRIPT_COMMAND_TO_RUN="$SUDO_SHELL_COMMAND_STRING$SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL"

        # If arguments need to be passed to SUDO_CORE_SCRIPT
        if [ ${#SUDO_COMMAND[@]} -gt 1 ]; then
            SUDO_COMMAND=("${SUDO_COMMAND[@]:1}") # Remove first element since its the script

            printf -v "SUDO_CORE_SCRIPT_COMMAND_ARGS" "%q " "${SUDO_COMMAND[@]}"
            SUDO_CORE_SCRIPT_COMMAND_ARGS="${SUDO_CORE_SCRIPT_COMMAND_ARGS% }" # Remove trailing space

            SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH="${#SUDO_CORE_SCRIPT_COMMAND_ARGS}"
            sudo_log 3 "SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH='$SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH'"

            # The `core_script` would not contribute much to crossing ARG_MAX since its either passed with process substitution or
            # as a path to a file storing it, unless the path is too long
            # The ARG_MAX would be a concern only when arguments to `core_script` are passed via process substitution to the sudo script
            # and not as a direct argument since in that case ARG_MAX would have crossed at the point instead
            # If SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH is greater than SUDO_ARG_MAX_SAFE_LIMIT
            if [[ "$SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH" -gt "$SUDO_ARG_MAX_SAFE_LIMIT" ]]; then
                sudo_log 2 "Warning! The SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH '$SUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH' is greater than $((SUDO_ARG_MAX_SAFE_LIMIT / 1024))KB. This may cause an 'Argument list too long' exception."
            fi

            # Pass the arguments to the SUDO_SHELL after the SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL
            SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=" $SUDO_CORE_SCRIPT_COMMAND_ARGS"
        fi

        # If SUDO_CORE_SCRIPT_REDIRECT_MODE or SUDO_SHELL_STDIN_STRING is set or
        # DISABLE_STDIN_FOR_CORE_SCRIPT or RUN_CORE_SCRIPT_IN_BACKGROUND is enabled
        if [ -n "$SUDO_CORE_SCRIPT_REDIRECT_MODE" ] || \
            [ -n "$SUDO_SHELL_STDIN_STRING" ] || \
                [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]] || \
                    [[ "$RUN_CORE_SCRIPT_IN_BACKGROUND" == "1" ]]; then
            # Surround SUDO_CORE_SCRIPT_COMMAND_TO_RUN with command grouping
            SUDO_CORE_SCRIPT_COMMAND_TO_RUN="{"$'\n\n'"$SUDO_CORE_SCRIPT_COMMAND_TO_RUN"$'\n\n''}'

            # If SUDO_CORE_SCRIPT_REDIRECT_MODE is set
            if [ -n "$SUDO_CORE_SCRIPT_REDIRECT_MODE" ]; then

                # If SUDO_CORE_SCRIPT_REDIRECT_MODE equal "0", then redirect stderr to stdout
                if [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "0" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 2>&1'

                # Elif SUDO_CORE_SCRIPT_REDIRECT_MODE equal "1", then redirect stdout to stderr
                elif [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "1" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 1>&2'

                # Elif SUDO_CORE_SCRIPT_REDIRECT_MODE equal "2", then redirect stdout to /dev/null
                elif [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "2" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 1>/dev/null'

                # Elif SUDO_CORE_SCRIPT_REDIRECT_MODE equal "3", then redirect stderr to /dev/null
                elif [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "3" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 2>/dev/null'

                # Elif SUDO_CORE_SCRIPT_REDIRECT_MODE equal "4", then redirect both stdout and stderr to /dev/null
                elif [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "4" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' &>/dev/null'

                # Elif SUDO_CORE_SCRIPT_REDIRECT_MODE equal "5", then redirect stderr to stdout and redirect stdout to stderr
                elif [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "5" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 3>&2 2>&1 1>&3'

                # Elif SUDO_CORE_SCRIPT_REDIRECT_MODE equal "6", then redirect stderr to stdout and redirect stdout to /dev/null
                elif [[ "$SUDO_CORE_SCRIPT_REDIRECT_MODE" == "6" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 2>&1 1>/dev/null'

                # Else append SUDO_CORE_SCRIPT_REDIRECT_MODE to SUDO_CORE_SCRIPT_COMMAND_TO_RUN
                else
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=" $SUDO_CORE_SCRIPT_REDIRECT_MODE"

                fi
            fi

            # If SUDO_SHELL_STDIN_STRING is set
            if [ -n "$SUDO_SHELL_STDIN_STRING" ]; then
                # If SUDO_SHELL_BASENAME is in SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
                if [[ " $SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $SUDO_SHELL_BASENAME "* ]]; then
                    # Pass SUDO_SHELL_STDIN_STRING as stdin with a herestring to SUDO_SHELL
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' <<<'"'${SUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"
                else
                    # Pass SUDO_SHELL_STDIN_STRING as stdin with process substitution to SUDO_SHELL
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' < <(printf "%s" '"'${SUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"')'
                fi
            else
                # If DISABLE_STDIN_FOR_CORE_SCRIPT is enabled, then redirect stdin to /dev/null
                if [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]]; then
                    SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' < /dev/null'
                fi
            fi

            # If RUN_CORE_SCRIPT_IN_BACKGROUND is enabled, then start SUDO_CORE_SCRIPT in background
            if [[ "$RUN_CORE_SCRIPT_IN_BACKGROUND" == "1" ]]; then
                SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' &'
                SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n''export SUDO_SCRIPT__CORE_SCRIPT_PID=$!;'
                SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n''export SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE=0;'
            fi

            SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n\n'
        fi

        # If RUN_CORE_SCRIPT_IN_BACKGROUND is not enabled
        if [[ "$RUN_CORE_SCRIPT_IN_BACKGROUND" != "1" ]]; then
            SUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n''export SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE=$?;'$'\n\n'

            # If EXIT_EARLY_IF_CORE_SCRIPT_FAILS is enabled, then exit if SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE does not equal 0
            if [[ "$EXIT_EARLY_IF_CORE_SCRIPT_FAILS" == "1" ]]; then
                SUDO_CORE_SCRIPT_COMMAND_TO_RUN+='[ $SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE -ne 0 ] && exit $SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE'$'\n\n'
            fi
        fi

        # Append SUDO_CORE_SCRIPT_COMMAND_TO_RUN to SUDO_SCRIPT_COMMAND_TO_RUN
        SUDO_SCRIPT_COMMAND_TO_RUN+="$SUDO_CORE_SCRIPT_COMMAND_TO_RUN"

    else
        # Append dummy SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE to SUDO_SCRIPT_COMMAND_TO_RUN
        SUDO_SCRIPT_COMMAND_TO_RUN+='export SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE=0;'$'\n\n'
    fi

    # If ADDITIONAL_SUDO_SHELL_POST_COMMANDS_TO_RUN is not empty, then append it to SUDO_SCRIPT_COMMAND_TO_RUN
    if [ -n "$ADDITIONAL_SUDO_SHELL_POST_COMMANDS_TO_RUN" ]; then
        SUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_SUDO_SHELL_POST_COMMANDS_TO_RUN"$'\n\n'
    fi

    # If GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT is enabled, then simulate double back button press to go to the last activity, first to close keyboard and second to close terminal session
    if [[ "$GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        SUDO_SCRIPT_COMMAND_TO_RUN+='$(export PATH="$ANDROID_PRIORITY_PATH"; export LD_LIBRARY_PATH="$ANDROID_PRIORITY_LD_LIBRARY_PATH"; unset LD_PRELOAD; input keyevent KEYCODE_BACK; input keyevent KEYCODE_BACK;);'$'\n\n'
    # If GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT is enabled, then simulate home button press to go to the launcher activity
    elif [[ "$GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        SUDO_SCRIPT_COMMAND_TO_RUN+='$(export PATH="$ANDROID_PRIORITY_PATH"; export LD_LIBRARY_PATH="$ANDROID_PRIORITY_LD_LIBRARY_PATH"; unset LD_PRELOAD; am start --user 0 -a android.intent.action.MAIN -c android.intent.category.HOME &>/dev/null;);'$'\n\n'
    fi

    # If CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled, then add clear command
    if [[ "$CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        SUDO_SCRIPT_COMMAND_TO_RUN+="clear"$'\n'
    fi

    # If RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled, start a new interactive post shell
    # We do not check if stdout and stdin are available since sudo could be piped or redirected and may not be connected to a tty
    # The -t 0 and -t 1 checks fail if sudo is run in a simple subshell in android 10 but not on 7
    if [[ "$RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        # Append PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN
        SUDO_SCRIPT_COMMAND_TO_RUN+="$PRE_SUDO_POST_SHELL_COMMANDS_TO_RUN"$'\n'

        # If ADDITIONAL_SUDO_POST_SHELL_PRE_COMMANDS_TO_RUN is not empty, then append it to SUDO_SCRIPT_COMMAND_TO_RUN
        if [ -n "$ADDITIONAL_SUDO_POST_SHELL_PRE_COMMANDS_TO_RUN" ]; then
            SUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_SUDO_POST_SHELL_PRE_COMMANDS_TO_RUN"$'\n'
        fi

        printf -v "SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING" "$SUDO_POST_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT" "${SUDO_POST_SHELL_INTERACTIVE_COMMAND[@]}"
        SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING="${SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING% }" # Remove trailing space

        # If SUDO_POST_SHELL_STDIN_STRING is set
        if [ -n "$SUDO_POST_SHELL_STDIN_STRING" ]; then
            # Surround SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING with command grouping
            SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING="{"$'\n\n'"$SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING"$'\n\n''}'

            # If SUDO_POST_SHELL_BASENAME is in SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
            if [[ " $SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $SUDO_POST_SHELL_BASENAME "* ]]; then
                # Pass SUDO_POST_SHELL_STDIN_STRING as stdin with a herestring to SUDO_POST_SHELL
                SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING+=' <<<'"'${SUDO_POST_SHELL_STDIN_STRING//\'/\'\\\'\'}'"
            else
                # Pass SUDO_POST_SHELL_STDIN_STRING as stdin with process substitution to SUDO_POST_SHELL
                SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING+=' < <(printf "%s" '"'${SUDO_POST_SHELL_STDIN_STRING//\'/\'\\\'\'}'"')'
            fi
        fi

        SUDO_SCRIPT_COMMAND_TO_RUN+="$SUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING"$'\n'

        # If ADDITIONAL_SUDO_POST_SHELL_POST_COMMANDS_TO_RUN is not empty, then append it to SUDO_SCRIPT_COMMAND_TO_RUN
        if [ -n "$ADDITIONAL_SUDO_POST_SHELL_POST_COMMANDS_TO_RUN" ]; then
            SUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_SUDO_POST_SHELL_POST_COMMANDS_TO_RUN"$'\n'
        fi
    else
        # Exit with exit code of SUDO_CORE_SCRIPT
        SUDO_SCRIPT_COMMAND_TO_RUN+='exit $SUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE'$'\n'
    fi



    # Set SUDO_SCRIPT_COMMAND_TRAPS and SUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION
    sudo_create_script_command_traps
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to create traps commands for SUDO_TEMP_DIRECTORY '$SUDO_TEMP_DIRECTORY'"
        return $return_value
    fi

    # If SUDO_SCRIPT_COMMAND_TRAPS is set
    if [ -n "$SUDO_SCRIPT_COMMAND_TRAPS" ]; then
        # If a script shell that doesn't support process substitution is being used or '-f' is passed, then
        # sudo_set_script_argument_for_script_shell_for_sudo will store temp core_script file at SUDO_CORE_SCRIPT_TEMP_FILENAME in SUDO_TEMP_DIRECTORY
        # Add traps at start of SUDO_SCRIPT_COMMAND_TO_RUN to remove the SUDO_TEMP_DIRECTORY when the script exits
        SUDO_SCRIPT_COMMAND_TO_RUN=$'\n'"$SUDO_SCRIPT_COMMAND_TRAPS"$'\n'"$SUDO_SCRIPT_COMMAND_TO_RUN"
    fi



    # `SUDO_SCRIPT_COMMAND_TO_RUN` cannot be passed to the `bash` inside `su` using process substitution.
    # Check https://github.com/agnostic-apollo/sudo/blob/master/site/pages/en/projects/docs/developer/guides/su-sub-process-communication/index.md
    # for more info on why `fd` with process substitution is used.
    sudo_get_unsed_file_descriptor_and_path SUDO_SCRIPT_FD SUDO_SCRIPT_FD_PATH "to write SUDO_SCRIPT_COMMAND_TO_RUN" || return $?

    # Use printf to write to SUDO_SCRIPT_FD
    sudo_log_literal 3 "\nWriting SUDO_SCRIPT_COMMAND_TO_RUN to SUDO_SCRIPT_FD_PATH '$SUDO_SCRIPT_FD_PATH'"
    eval "exec $SUDO_SCRIPT_FD<" <(printf "%s" "$SUDO_SCRIPT_COMMAND_TO_RUN")
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while writing SUDO_SCRIPT_COMMAND_TO_RUN to SUDO_SCRIPT_FD '$SUDO_SCRIPT_FD'"
        return $return_value
    fi

    return 0

}

sudo_check_if_setting_up_sudo_temp_directory_is_required() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_check_if_setting_up_sudo_temp_directory_is_required"

    # If SUDO_SHELL_BASENAME is in SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
    # or force_use_temp_script_file is enabled
    # then the script file will need to be stored in a temp script file in SUDO_TEMP_DIRECTORY
    # This logic must be same as that in sudo_set_script_argument_for_script_shell function
    # so that SUDO_TEMP_DIRECTORY has already been created if needed
    # and the script_file path can be set correctly and be passed to the script shell
    # Its not directly created in the other function to reduce a call to the su shell
    if [[ " $SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $SUDO_SHELL_BASENAME "* ]] || [[ "$FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT" == "1" ]]; then
        # Enable SETUP_SUDO_TEMP_DIRECTORY
        sudo_log 3 "SETUP_SUDO_TEMP_DIRECTORY enabled"
        SETUP_SUDO_TEMP_DIRECTORY=1
    fi

    return 0

}

##
# `sudo_set_script_argument_for_script_shell` `<shell_basename>` `<heredoc_word>` `<heredoc_word_quote>` `<script_is_path_to_script_file>` `<force_use_temp_script_file>` `<decode_script_content>` `<script_file_label>` `<script_file_name>` `<script_file_path>`/script_content
##
sudo_set_script_argument_for_script_shell() {

    local return_value

    # If argument count is not 9
    if [ $# -ne 9 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_script_argument_for_script_shell'"
        return 1
    fi

    local shell_basename="$1"
    local heredoc_word="$2"
    local heredoc_word_quote="$3"
    local script_is_path_to_script_file="$4"
    local force_use_temp_script_file="$5"
    local decode_script_content="$6"
    local script_file_label="$7"
    local script_file_name="$8"

    # If shell_basename is not in any of the SUDO_SUPPORTED_SCRIPT_SHELLS, then exit with error
    if [[ "$shell_basename" == *' '* ]] || [[ " $SUDO_SUPPORTED_SCRIPT_SHELLS " != *" $shell_basename "* ]]; then
        sudo_log_errors "The shell_basename '$shell_basename' while running 'sudo_set_script_argument_for_script_shell' is not supported. It must be one of '$SUDO_SUPPORTED_SCRIPT_SHELLS'"
        return 1
    fi

    SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL=""

    # If script_is_path_to_script_file is enabled, then just pass script_file_path as the argument to the script shell
    if [[ "$script_is_path_to_script_file" == "1" ]]; then
        local script_file_path="$9"

        sudo_log 3 "$script_file_label will be passed to the script shell as a path to a file"

        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in script_file_path
        sudo_expand_termux_path "script_file_path" "$script_file_label" "$script_file_path" "$TERMUX_PREFIX" "$TERMUX_HOME" 3
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to expand $script_file_label '$script_file_path'"
            return $return_value
        fi

        # If script_file_path is not a valid absolute path
        if [[ ! "$script_file_path" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            sudo_log_errors "The $script_file_label '$script_file_path' is not a valid absolute path"
            return 1
        fi

        sudo_log 3 "script_file_path='$script_file_path'"
        printf -v "script_file_path_string" "%q" "$script_file_path"
        SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL="$script_file_path_string"

    else
        local script_content="$9"

        # If shell is in SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT (dash, sh, node, php)
        # or force_use_temp_script_file is enabled, then
        # store the script in a temp script file in SUDO_TEMP_DIRECTORY and pass that as argument to the script shell
        if [[ " $SUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $shell_basename "* ]] || [[ "$force_use_temp_script_file" == "1" ]]; then
            local log_content=1

            # If DISABLE_ARGUMENTS_LOGGING is enabled
            if [[ "$DISABLE_ARGUMENTS_LOGGING" == "1" ]]; then
                log_content=0
            fi

            sudo_log 3 "$script_file_label will be passed to the script shell after being store in a temp file"

            # If SUDO_TEMP_DIRECTORY is not a valid absolute path
            if [[ ! "$SUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
                sudo_log_errors "The SUDO_TEMP_DIRECTORY '$SUDO_TEMP_DIRECTORY' is not a valid absolute path, required by 'sudo_set_script_argument_for_script_shell'"
                return 1
            fi

            script_file="$SUDO_TEMP_DIRECTORY/$script_file_name"

            sudo_log 3 "$script_file_label temp file='$script_file'"

            # sudo_create_sudo_temp_file label path log_content decode_content content
            sudo_create_sudo_temp_file "$script_file_label" "$script_file" "$log_content" "$decode_script_content" "$script_content"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failure while running 'sudo_create_sudo_temp_file'"
                return $return_value
            fi

            printf -v "script_file_string" "%q" "$script_file"
            SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL="$script_file_string"

        # If shell is bash, zsh, fish, ksh, python python2, ruby, perl, lua5.2, lua5.3, lua5.4,
        # use process substitution with printf to pass script_content to the script shell.
        # Heredoc is not used since that will create a temp file in TMPDIR which is slower and less secure.
        # Note that ARG_MAX will not cross because of passing the script_content as an argument to printf
        # since printf is a shell built-in and exec is not done. It will however cross if an external call were to
        # be made to printf with `$PREFIX/bin/print`. The ARG_MAX would be a concern only when `core_script`
        # is passed via process substitution to the sudo script and not as a direct argument since in that
        # case ARG_MAX would have crossed at the point instead.
        elif [[ " bash zsh fish ksh python python2 ruby perl lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then

            sudo_log 3 "$script_file_label will be passed to the script shell using process substitution with printf command"

            SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL='<(printf "%s" '"'${script_content//\'/\'\\\'\'}
'"')'

            #sudo_log 3 "$script_file_label will be passed to the script shell using process substitution with a cat heredoc"

#           SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL='<(cat <<'"$heredoc_word_quote$heredoc_word$heredoc_word_quote"'
#'"$script_content"'
#
#'"$heredoc_word"'
#)'


        else
            sudo_log_errors "shell_basename '$shell_basename' not handled while running 'sudo_set_script_argument_for_script_shell'"
            return 1
        fi
    fi

    return 0

}

##
# `sudo_create_sudo_temp_file` `<label>` `<path>` `<log_content>` `<decode_content>` `<content>`
##
sudo_create_sudo_temp_file() {

    local return_value
    local su_output

    # If argument count is not 5
    if [ $# -ne 5 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_create_sudo_temp_file'"
        return 1
    fi

    local label="$1"
    local path="$2"
    local log_content="$3"
    local decode_content="$4"
    local content="$5"

    # If path is not a valid absolute path
    if [[ ! "$path" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "The '$label' file at path '$path' is not an absolute path"
        return 2
    fi

    local TEMP_FILE_FD
    local TEMP_FILE_FD_PATH

    # `content` cannot be passed to the `bash` inside `su` using process substitution.
    # Check https://github.com/agnostic-apollo/sudo/blob/master/site/pages/en/projects/docs/developer/guides/su-sub-process-communication/index.md
    # for more info on why `fd` with process substitution is used.
    sudo_get_unsed_file_descriptor_and_path TEMP_FILE_FD TEMP_FILE_FD_PATH "to write decoded $label" || return $?

    # Write the contents to TEMP_FILE_FD_PATH
    # Decode first if required
    # Decoding of binary data needs to be done on the fly since
    # binary data cannot be stored in a variable to be passed using herestring
    # and nor can a heredoc be used to pass binary data
    # Process substitution is not possible for passing data to su due to /proc/self/fd issues,
    # hence a fd is opened and used instead
    # a herestring or heredoc could have been used for passing text only data
    # but those will create a temp file in TMPDIR which is slower and less secure
    sudo_log 3 "Writing $label to TEMP_FILE_FD '$TEMP_FILE_FD'"
    if [[ "$decode_content" == "1" ]]; then
        eval "exec $TEMP_FILE_FD<" <(printf '%s' "$content" | base64 -d)
    else
        eval "exec $TEMP_FILE_FD<" <(printf '%s' "$content")
    fi
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while writing $label to TEMP_FILE_FD '$TEMP_FILE_FD'"
    else
        # Use cat to read contents from fd at TEMP_FILE_FD_PATH
        # and redirect stdout to file at path to write to it
        sudo_log 3 "Creating $label file at '$path'"
        sudo_unset_pre_su_variables
        su_output=$($SU_ENV_COMMAND "cat \"$TEMP_FILE_FD_PATH\" > '${path//\'/\'\\\'\'}'" 2>&1 < /dev/null)
        return_value=$?
        sudo_set_post_su_variables
        { [ $return_value -ne 0 ] && [ -n "$su_output" ]; } && sudo_log_errors "$su_output"
    fi

    # If TEMP_FILE_FD is set, then close it
    if [ -n "$TEMP_FILE_FD" ]; then
        exec {TEMP_FILE_FD}<&-
        TEMP_FILE_FD=""
    fi

    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while creating $label file at '$path'"
        return $return_value
    fi

    # Read file at path again and log its content but only if binary data is not stored in it
    if [[ "$SUDO_LOG_LEVEL" -ge 2 ]] && [[ "$log_content" == "1" ]]  && [[ "$decode_content" != "1" ]]; then
        local file_contents=""
        sudo_unset_pre_su_variables
        file_contents=$($SU_ENV_COMMAND "cat '${path//\'/\'\\\'\'}'" 2>&1 < /dev/null)
        return_value=$?
        sudo_set_post_su_variables
        if [ $return_value -ne 0 ]; then
            [ -n "$file_contents" ] && echo "$file_contents" 1>&2
            sudo_log_errors "Failure while reading $label file at '$path'"
            return $return_value
        fi
        sudo_log 2 $'\n'"${label}_CONTENTS=\`$file_contents\`"
    fi

    return 0

}

sudo_set_sudo_shell() {

    local return_value
    local su_output

    sudo_log_literal 3 "\nRunning sudo_set_sudo_shell"

    # If on Android `< 7`, and running `asu`/`script` commands with
    # `-A` or `-AA` flags, then default to Android system shell, as
    # Termux shells will have linker errors as `LD_LIBRARY_PATH` will
    # not be set, so only use/allow `/system/bin/sh` shell.

    # If SUDO_SHELL is set
    if [ -n "$SUDO_SHELL" ]; then
        sudo_trim_trailing_newlines "SUDO_SHELL" "$SUDO_SHELL"

        # Validate the SUDO_SHELL
        # If USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION is enabled
        if [[ "$USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION" == "1" ]]; then
            sudo_unset_pre_su_variables
            SUDO_SHELL="$($SU_ENV_COMMAND "source '${SUDO_SCRIPT_PATH//\'/\'\\\'\'}' || exit \$?; \
sudo_validate_shell \"SUDO_SHELL\" '${SUDO_SHELL//\'/\'\\\'\'}' '${SUDO_SUPPORTED_SHELLS//\'/\'\\\'\'}' \"$TERMUX_PREFIX\" \"$TERMUX_BIN\" \"$TERMUX_HOME\"" 2>&1 < /dev/null)"
            return_value=$?
            sudo_set_post_su_variables
            { [ $return_value -ne 0 ] && [ -n "$SUDO_SHELL" ]; } && sudo_log_errors "$SUDO_SHELL"
        else
            SUDO_SHELL="$(sudo_validate_shell "SUDO_SHELL" "$SUDO_SHELL" "$SUDO_SUPPORTED_SHELLS" "$TERMUX_PREFIX" "$TERMUX_BIN" "$TERMUX_HOME")"
            return_value=$?
        fi
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to validate 'SUDO_SHELL'"
            return $return_value
        fi

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]] && \
                [[ "$SUDO_SHELL" != "/system/bin/sh" ]]; then
            sudo_log_errors "The 'SUDO_SHELL' must be '/system/bin/sh' if running '$COMMAND_TYPE' command on Android '< 7'"
            return 1
        fi
    else
        # Default to bash as SUDO_SHELL
        SUDO_SHELL="$BASH_SHELL_PATH"

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]]; then
            SUDO_SHELL="/system/bin/sh"
        fi
    fi

    # If SUDO_SHELL is not a valid absolute path
    if [[ ! "$SUDO_SHELL" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "The SUDO_SHELL '$SUDO_SHELL' is not a valid absolute path"
        return 1
    fi

    sudo_log 2 "SUDO_SHELL='$SUDO_SHELL'"

    # Find the basename and parent directory of the SUDO_SHELL
    SUDO_SHELL_BASENAME="${SUDO_SHELL##*/}" # Strip longest match of */ from start
    SUDO_SHELL_PARENT_DIR="${SUDO_SHELL:0:${#SUDO_SHELL} - ${#SUDO_SHELL_BASENAME}}" # Substring from 0 to position of basename
    case "$SUDO_SHELL_PARENT_DIR" in *[!/]*/) SUDO_SHELL_PARENT_DIR="${SUDO_SHELL_PARENT_DIR%"${SUDO_SHELL_PARENT_DIR##*[!/]}"}";; *[/]) SUDO_SHELL_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    sudo_log 3 "SUDO_SHELL_BASENAME='$SUDO_SHELL_BASENAME'"
    sudo_log 3 "SUDO_SHELL_PARENT_DIR='$SUDO_SHELL_PARENT_DIR'"

    # If SUDO_SHELL is not in any of the SUDO_SUPPORTED_SHELLS, then exit with error
    # The basename of the shell file could be faked but the actual shell inside the file is not checked
    if [[ "$SUDO_SHELL_BASENAME" == *' '* ]] || [[ " $SUDO_SUPPORTED_SHELLS " != *" $SUDO_SHELL_BASENAME "* ]]; then
        sudo_log_errors "The SUDO_SHELL '$SUDO_SHELL' is not supported. It must be one of '$SUDO_SUPPORTED_SHELLS'"
        return 1
    fi

    return 0

}

sudo_set_sudo_post_shell() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_post_shell"

    # If on Android `< 7`, and running `asu`/`script` commands with
    # `-A` or `-AA` flags, then default to Android system shell, as
    # Termux shells will have linker errors as `LD_LIBRARY_PATH` will
    # not be set, so only use/allow `/system/bin/sh` shell.

    # If SUDO_POST_SHELL is set
    if [ -n "$SUDO_POST_SHELL" ]; then
        sudo_trim_trailing_newlines "SUDO_POST_SHELL" "$SUDO_POST_SHELL"

        # Validate the SUDO_POST_SHELL
        # If USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION is enabled
        if [[ "$USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION" == "1" ]]; then
            sudo_unset_pre_su_variables
            SUDO_POST_SHELL="$($SU_ENV_COMMAND "source '${SUDO_SCRIPT_PATH//\'/\'\\\'\'}' || exit \$?; \
sudo_validate_shell \"SUDO_POST_SHELL\" '${SUDO_POST_SHELL//\'/\'\\\'\'}' '${SUDO_SUPPORTED_POST_SHELLS//\'/\'\\\'\'}' \"$TERMUX_PREFIX\" \"$TERMUX_BIN\" \"$TERMUX_HOME\"" 2>&1 < /dev/null)"
            return_value=$?
            sudo_set_post_su_variables
            { [ $return_value -ne 0 ] && [ -n "$SUDO_POST_SHELL" ]; } && sudo_log_errors "$SUDO_POST_SHELL"
        else
            SUDO_POST_SHELL="$(sudo_validate_shell "SUDO_POST_SHELL" "$SUDO_POST_SHELL" "$SUDO_SUPPORTED_POST_SHELLS" "$TERMUX_PREFIX" "$TERMUX_BIN" "$TERMUX_HOME")"
            return_value=$?
        fi
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to validate 'SUDO_POST_SHELL'"
            return $return_value
        fi

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]] && \
                [[ "$SUDO_POST_SHELL" != "/system/bin/sh" ]]; then
            sudo_log_errors "The 'SUDO_POST_SHELL' must be '/system/bin/sh' if running '$COMMAND_TYPE' command on Android '< 7'"
            return 1
        fi
    else
        # Default to bash as SUDO_POST_SHELL
        SUDO_POST_SHELL="$BASH_SHELL_PATH"

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]]; then
            SUDO_POST_SHELL="/system/bin/sh"
        fi
    fi

    # If SUDO_POST_SHELL is not a valid absolute path
    if [[ ! "$SUDO_POST_SHELL" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "The SUDO_POST_SHELL '$SUDO_POST_SHELL' is not a valid absolute path"
        return 1
    fi

    sudo_log 2 "SUDO_POST_SHELL='$SUDO_POST_SHELL'"

    # Find the basename and parent directory of the SUDO_POST_SHELL
    SUDO_POST_SHELL_BASENAME="${SUDO_POST_SHELL##*/}" # Strip longest match of */ from start
    SUDO_POST_SHELL_PARENT_DIR="${SUDO_POST_SHELL:0:${#SUDO_POST_SHELL} - ${#SUDO_POST_SHELL_BASENAME}}" # Substring from 0 to position of basename
    case "$SUDO_POST_SHELL_PARENT_DIR" in *[!/]*/) SUDO_POST_SHELL_PARENT_DIR="${SUDO_POST_SHELL_PARENT_DIR%"${SUDO_POST_SHELL_PARENT_DIR##*[!/]}"}";; *[/]) SUDO_POST_SHELL_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    sudo_log 3 "SUDO_POST_SHELL_BASENAME='$SUDO_POST_SHELL_BASENAME'"
    sudo_log 3 "SUDO_POST_SHELL_PARENT_DIR='$SUDO_POST_SHELL_PARENT_DIR'"

    # If SUDO_POST_SHELL is not in any of the SUDO_SUPPORTED_SHELLS, then exit with error
    # The basename of the shell file could be faked but the actual shell inside the file is not checked
    if [[ "$SUDO_POST_SHELL_BASENAME" == *' '* ]] || [[ " $SUDO_SUPPORTED_POST_SHELLS " != *" $SUDO_POST_SHELL_BASENAME "* ]]; then
        sudo_log_errors "The SUDO_POST_SHELL '$SUDO_POST_SHELL' is not supported. It must be one of '$SUDO_SUPPORTED_POST_SHELLS'"
        return 1
    fi

    return 0

}

##
# `sudo_validate_shell` `<shell_label>` `<user_shell>` `<supported_shells>` `<termux_prefix>` `<termux_bin>` `<termux_home>`
##
sudo_validate_shell() {

    local return_value

    # If argument count is not 6
    if [ $# -ne 6 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_validate_shell'"
        return 1
    fi

    local shell_label="$1"
    local user_shell="$2"
    local supported_shells="$3"
    local termux_prefix="$4"
    local termux_bin="$5"
    local termux_home="$6"

    local shell

    # If user_shell is set to a shell in supported_shells, then set user_shell to "$termux_bin/$user_shell"
    if [[ "$user_shell" != *'/'* ]]; then
        if [[ "$user_shell" != *' '* ]] && [[ " $supported_shells " == *" $user_shell "* ]]; then
            shell="$termux_bin/$user_shell"
        else
            sudo_log_errors "The $shell_label '$user_shell' is not supported. It must be one of '$supported_shells'"
            return 1
        fi
    else
        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in user_shell
        sudo_expand_termux_path "user_shell" "$shell_label" "$user_shell" "$termux_prefix" "$termux_home" 3
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to expand $shell_label '$user_shell'"
            return $return_value
        fi

        shell="$user_shell"
    fi

    # sudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
    sudo_run_file_type_tests_on_path "$shell_label" "$shell" 1 1 1 "frx" || return $?

    # Echo shell to stdout
    echo "$shell"

}

sudo_set_sudo_shell_rcfile() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_shell_rcfile"

    # Set rcfile variables
    sudo_set_shell_rcfile "SUDO_SHELL" "$SUDO_SHELL_BASENAME" "$SUDO_SHELL_HOME"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_set_rcfile_functions' for SUDO_SHELL '$SUDO_SHELL'"
        return $return_value
    fi

    SUDO_SHELL_RCFILE="$SHELL_RCFILE"
    SUDO_SHELL_RCFILE_PARENT_DIR="$SHELL_RCFILE_PARENT_DIR"
    SUDO_SHELL_RCFILE_COMMANDS="$SHELL_RCFILE_COMMANDS"
    SUDO_SHELL_RCFILE_VALUE="$SHELL_RCFILE_VALUE"
    SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    sudo_log 3 "SUDO_SHELL_RCFILE='$SUDO_SHELL_RCFILE'"
    sudo_log 3 "SUDO_SHELL_RCFILE_PARENT_DIR='$SUDO_SHELL_RCFILE_PARENT_DIR'"
    sudo_log 3 "SUDO_SHELL_RCFILE_COMMANDS='$SUDO_SHELL_RCFILE_COMMANDS'"
    sudo_log 3 "SUDO_SHELL_RCFILE_VALUE=\`$SUDO_SHELL_RCFILE_VALUE\`"

    return 0

}

sudo_set_sudo_post_shell_rcfile() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_post_shell_rcfile"

    # Set rcfile variables
    sudo_set_shell_rcfile "SUDO_POST_SHELL" "$SUDO_POST_SHELL_BASENAME" "$SUDO_POST_SHELL_HOME"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_set_rcfile_functions' for SUDO_POST_SHELL '$SUDO_POST_SHELL'"
        return $return_value
    fi

    SUDO_POST_SHELL_RCFILE="$SHELL_RCFILE"
    SUDO_POST_SHELL_RCFILE_PARENT_DIR="$SHELL_RCFILE_PARENT_DIR"
    SUDO_POST_SHELL_RCFILE_COMMANDS="$SHELL_RCFILE_COMMANDS"
    SUDO_POST_SHELL_RCFILE_VALUE="$SHELL_RCFILE_VALUE"
    SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    sudo_log 3 "SUDO_POST_SHELL_RCFILE='$SUDO_POST_SHELL_RCFILE'"
    sudo_log 3 "SUDO_POST_SHELL_RCFILE_PARENT_DIR='$SUDO_POST_SHELL_RCFILE_PARENT_DIR'"
    sudo_log 3 "SUDO_POST_SHELL_RCFILE_COMMANDS='$SUDO_POST_SHELL_RCFILE_COMMANDS'"
    sudo_log 3 "SUDO_POST_SHELL_RCFILE_VALUE=\`$SUDO_POST_SHELL_RCFILE_VALUE\`"

    return 0

}

##
# `sudo_set_shell_rcfile` `<shell_basename>` `<shell_home>`
##
sudo_set_shell_rcfile() {

    local return_value

    # If argument count is not 3
    if [ $# -ne 3 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_shell_rcfile'"
        return 1
    fi

    local shell_label="$1"
    local shell_basename="$2"
    local shell_home="$3"

    # RCFILE are usually unique for different shells
    # If shell_home equals TERMUX_HOME and shell has no --rc param or
    # environment variable, then termux shells and sudo shells will
    # have to share rc files.

    # Was going to add support for tcsh but decided not to after reading the following and having a chuckle
    # - https://web.fe.up.pt/~jmcruz/etc/unix/sh-vs-csh.html

    SHELL_RCFILE=""
    SHELL_RCFILE_PARENT_DIR=""
    SHELL_RCFILE_COMMANDS=""
    SHELL_RCFILE_VALUE=""
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()

    # If shell is zsh
    if [[ "$shell_basename" == "zsh" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and sudo shell rc files are shared
        # since only the parent dir of ".zshrc" file can be defined in ZDOTDIR
        SHELL_RCFILE="$shell_home/.zshrc"
        SHELL_RCFILE_COMMANDS="export ZDOTDIR='${shell_home//\'/\'\\\'\'}';"

    # If shell is fish
    elif [[ "$shell_basename" == "fish" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and sudo shell rc files are shared since "config.fish" is always loaded
        # XDG_RUNTIME_DIR is exported and is inside shell_home because otherwise fish shell creates
        # the "$TMPDIR/fish.root" directory with root ownership
        SHELL_RCFILE="$shell_home/.config/fish/config.fish"
        SHELL_RCFILE_COMMANDS="export XDG_CONFIG_HOME='${shell_home//\'/\'\\\'\'}/.config';"
        SHELL_RCFILE_COMMANDS+=$'\n'"export XDG_CACHE_HOME='${shell_home//\'/\'\\\'\'}/.cache';"
        SHELL_RCFILE_COMMANDS+=$'\n'"export XDG_DATA_HOME='${shell_home//\'/\'\\\'\'}/.local/share';"
        SHELL_RCFILE_COMMANDS+=$'\n'"export XDG_RUNTIME_DIR='${shell_home//\'/\'\\\'\'}/.cache/tmp';"
        SHELL_RCFILE_COMMANDS+=$'\n'"[ ! -d \"\$XDG_CONFIG_HOME\" ] && mkdir -p \"\$XDG_CONFIG_HOME\";"
        SHELL_RCFILE_COMMANDS+=$'\n'"[ ! -d \"\$XDG_DATA_HOME\" ] && mkdir -p \"\$XDG_DATA_HOME\";"
        SHELL_RCFILE_COMMANDS+=$'\n'"[ ! -d \"\$XDG_RUNTIME_DIR\" ] && mkdir -p \"\$XDG_RUNTIME_DIR\";"

    # If shell is ruby
    elif [[ "$shell_basename" == "ruby" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and sudo shell rc files are shared since "~/.irbrc" is always loaded
        SHELL_RCFILE="$shell_home/.irbrc"

    # If shell is pry
    elif [[ "$shell_basename" == "pry" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and sudo shell rc files are shared since "~/.pryrc" is always loaded
        SHELL_RCFILE="$shell_home/.pryrc"

    # If shell is bash, dash, sh, ksh, php, python
    elif [[ " bash dash sh ksh python php python2 " == *" $shell_basename "* ]]; then
        # If shell_home equals TERMUX_HOME, then set the RCFILE with "sudo_" appended to it
        # so that termux shell and sudo shell rc files are not shared since --rc params or
        # environment variables can be used to define the path to the rc file
        local shell_rcfile_subname
        if [[ "$shell_home" == "$TERMUX_HOME" ]]; then
            shell_rcfile_subname="sudo_${shell_basename}"
        else
            shell_rcfile_subname="${shell_basename}"
        fi

        # If shell is bash
        if [[ "$shell_basename" == "bash" ]]; then
            # Use the --rcfile param to pass the path to rcfile
            SHELL_RCFILE="$shell_home/.${shell_rcfile_subname}rc"
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("--rcfile" "$SHELL_RCFILE")

        # If shell is python, python2
        elif [[ " python python2 " == *" $shell_basename "* ]]; then
            # Use the PYTHONSTARTUP environment variable to pass the path to rcfile
            SHELL_RCFILE="$shell_home/.${shell_rcfile_subname}rc"
            SHELL_RCFILE_COMMANDS="export PYTHONSTARTUP='${SHELL_RCFILE//\'/\'\\\'\'}';"

        # If shell is php
        elif [[ "$shell_basename" == "php" ]]; then
            # Use the -c param to pass the path to ini file
            SHELL_RCFILE="$shell_home/${shell_rcfile_subname}.ini"
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("-c" "$SHELL_RCFILE")

        # If shell is dash, sh, ksh
        else
            # Use the PYTHONSTARTUP environment variable to pass the path to rcfile
            SHELL_RCFILE="$shell_home/.${shell_rcfile_subname}rc"
            SHELL_RCFILE_COMMANDS="export ENV='${SHELL_RCFILE//\'/\'\\\'\'}';"
        fi

    # If shell is node, perl, lua5.2, lua5.3, lua5.4
    elif [[ " node perl lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then
        # The shell does not have a rc file or does not use it
        sudo_log 3 "The '$shell_basename' shell does not have a rc file or does not use it"
    else
        sudo_log_errors "shell_basename '$shell_basename' not handled while running 'sudo_set_shell_rcfile'"
        return 1
    fi


    # If SHELL_RCFILE is set
    if [ -n "$SHELL_RCFILE" ]; then

        # If SHELL_RCFILE is not a valid absolute path
        if [[ ! "$SHELL_RCFILE" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            sudo_log_errors "The ${shell_label}_RCFILE '$SHELL_RCFILE' is not a valid absolute path"
            return 1
        fi

        # If SHELL_RCFILE_COMMANDS is set
        if [ -n "$SHELL_RCFILE_COMMANDS" ]; then
            SHELL_RCFILE_COMMANDS+=$'\n'
        fi

        SHELL_RCFILE_COMMANDS+="export RCFILE='${SHELL_RCFILE//\'/\'\\\'\'}';"


        # Find the parent directory of the SHELL_RCFILE
        SHELL_RCFILE_BASENAME="${SHELL_RCFILE##*/}" # Strip longest match of */ from start
        SHELL_RCFILE_PARENT_DIR="${SHELL_RCFILE:0:${#SHELL_RCFILE} - ${#SHELL_RCFILE_BASENAME}}" # Substring from 0 to position of basename
        case "$SHELL_RCFILE_PARENT_DIR" in *[!/]*/) SHELL_RCFILE_PARENT_DIR="${SHELL_RCFILE_PARENT_DIR%"${SHELL_RCFILE_PARENT_DIR##*[!/]}"}";; *[/]) SHELL_RCFILE_PARENT_DIR="/";; esac # Remove trailing slashes if not root

        # Set SHELL_RCFILE_VALUE to be set in SHELL_RCFILE
        SHELL_RCFILE_VALUE=""

        # If shell is bash, zsh, dash, sh, fish or ksh
        if [[ " bash zsh dash sh fish ksh " == *" $shell_basename "* ]]; then
            # Not defining any variables since they are dynamically defined by "sudo" command
            # Overriding may create problems in the future as well if dynamically defined variable values change
            # PATH, LD_LIBRARY_PATH and PS1 must never be overridden in rcfile, otherwise "sudo" commands will not work properly,
            # especially the "sudo asu" and "sudo <command>" commands

            # Define any required functions to add to SHELL_RCFILE_VALUE in RCFILE_FUNCTIONS
            sudo_set_rcfile_functions "$shell_basename" || return $?

            # If RCFILE_FUNCTIONS is not empty, then append it to SHELL_RCFILE_VALUE
            if [ -n "$RCFILE_FUNCTIONS" ]; then
                SHELL_RCFILE_VALUE+="$RCFILE_FUNCTIONS"$'\n'
            fi
        fi
    fi

    return 0

}

##
# `sudo_set_rcfile_functions`
##
sudo_set_rcfile_functions() {

    local return_value

    # If argument count is not 1
    if [ $# -ne 1 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_rcfile_functions'"
        return 1
    fi

    local shell_basename="$1"

    RCFILE_FUNCTIONS=""

    # If shell is fish
    if [[ "$shell_basename" == "fish" ]]; then

        local fish_quiet_option=" -q"
        # If on Android `< 7`
        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
            fish_quiet_option=""
        fi

        # Define export helper function for fish shell that allows export command in bash to be used
        # shellcheck disable=SC2016
        FISH_SHELL_EXPORT_FUNCTION='
function export
    if [ $argv ]
        set var (echo $argv | cut -f1 -d=)
        set val (echo $argv | cut -f2 -d=)
        set -g -x $var $val
    end
end

'"funcsave$fish_quiet_option export
"

        # Define unset helper function for fish shell that allows export command in bash to be used
        # shellcheck disable=SC2016
        FISH_SHELL_UNSET_FUNCTION='
function unset
    set --erase $argv
end

'"funcsave$fish_quiet_option unset
"

    # Define tpath helper function for fish shell that sets priority to termux paths
    # shellcheck disable=SC2016
    FISH_SHELL_TPATH_FUNCTION='
function tpath
    export PATH="$SUDO__TERMUX_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$SUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH";
    export LD_PRELOAD="$SUDO__TERMUX_LD_PRELOAD";
end
'

    # Define apath helper function for fish shell that sets priority to android paths
    # shellcheck disable=SC2016
    FISH_SHELL_APATH_FUNCTION='
function apath
    export PATH="$SUDO__ANDROID_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$SUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH";
    '"$ANDROID_PRIORITY_LD_PRELOAD_COMMAND"'
end
'

        RCFILE_FUNCTIONS="$FISH_SHELL_EXPORT_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$FISH_SHELL_UNSET_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$FISH_SHELL_TPATH_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$FISH_SHELL_APATH_FUNCTION"





    # If shell is bash, zsh, dash, sh or ksh
    elif [[ " bash zsh dash sh ksh " == *" $shell_basename "* ]]; then

        # Define tpath helper function for bash, zsh, sh, etc shells that sets priority to termux paths
        # shellcheck disable=SC2016
        GENERAL_SHELL_TPATH_FUNCTION='
tpath() {
    export PATH="$SUDO__TERMUX_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$SUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH";
    export LD_PRELOAD="$SUDO__TERMUX_LD_PRELOAD";
}
'


        # Define apath helper function for bash, zsh, sh, etc shells that sets priority to android paths
        # shellcheck disable=SC2016
        GENERAL_SHELL_APATH_FUNCTION='
apath() {
    export PATH="$SUDO__ANDROID_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$SUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH";
    '"$ANDROID_PRIORITY_LD_PRELOAD_COMMAND"'
}
'


        RCFILE_FUNCTIONS="$GENERAL_SHELL_TPATH_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$GENERAL_SHELL_APATH_FUNCTION"

    fi

    return 0

}

sudo_set_sudo_shell_histfile() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_shell_histfile"

    # Set histfile variables
    sudo_set_shell_histfile "SUDO_SHELL" "$SUDO_SHELL_BASENAME" "$SUDO_SHELL_HOME" "$SUDO_SHELLS_HISTORY_ENABLED"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_set_shell_histfile' for SUDO_SHELL '$SUDO_SHELL'"
        return $return_value
    fi

    SUDO_SHELL_HISTFILE="$SHELL_HISTFILE"
    SUDO_SHELL_HISTFILE_PARENT_DIR="$SHELL_HISTFILE_PARENT_DIR"
    SUDO_SHELL_HISTFILE_COMMANDS="$SHELL_HISTFILE_COMMANDS"
    SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    sudo_log 3 "SUDO_SHELL_HISTFILE='$SUDO_SHELL_HISTFILE'"
    sudo_log 3 "SUDO_SHELL_HISTFILE_PARENT_DIR='$SUDO_SHELL_HISTFILE_PARENT_DIR'"
    sudo_log 3 "SUDO_SHELL_HISTFILE_COMMANDS='$SUDO_SHELL_HISTFILE_COMMANDS'"

    return 0

}

sudo_set_sudo_post_shell_histfile() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_post_shell_histfile"

    # Set histfile variables
    sudo_set_shell_histfile "SUDO_POST_SHELL" "$SUDO_POST_SHELL_BASENAME" "$SUDO_POST_SHELL_HOME" "$SUDO_SHELLS_HISTORY_ENABLED"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_set_shell_histfile' for SUDO_POST_SHELL '$SUDO_POST_SHELL'"
        return $return_value
    fi

    SUDO_POST_SHELL_HISTFILE="$SHELL_HISTFILE"
    SUDO_POST_SHELL_HISTFILE_PARENT_DIR="$SHELL_HISTFILE_PARENT_DIR"
    SUDO_POST_SHELL_HISTFILE_COMMANDS="$SHELL_HISTFILE_COMMANDS"
    SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    sudo_log 3 "SUDO_POST_SHELL_HISTFILE='$SUDO_POST_SHELL_HISTFILE'"
    sudo_log 3 "SUDO_POST_SHELL_HISTFILE_PARENT_DIR='$SUDO_POST_SHELL_HISTFILE_PARENT_DIR'"
    sudo_log 3 "SUDO_POST_SHELL_HISTFILE_COMMANDS='$SUDO_POST_SHELL_HISTFILE_COMMANDS'"

    return 0

}

##
# `sudo_set_shell_histfile` `<shell_label>` `<shell_basename>` `<shell_home>` `<shell_history_enabled>`
##
sudo_set_shell_histfile() {

    local return_value

    # If argument count is not 4
    if [ $# -ne 4 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_shell_histfile'"
        return 1
    fi

    local shell_label="$1"
    local shell_basename="$2"
    local shell_home="$3"
    local shell_history_enabled="$4"

    SHELL_HISTFILE=""
    SHELL_HISTFILE_PARENT_DIR=""
    SHELL_HISTFILE_COMMANDS=""
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()

    # If shell_history_enabled is enabled
    if [[ "$shell_history_enabled" == "1" ]]; then

        # History files are usually unique for different shells
        # If shell_home equals TERMUX_HOME, then termux shells and sudo
        # shells will have to share history files if the shell does
        # not support HISTFILE variable

        # If shell is fish
        if [[ "$shell_basename" == "fish" ]]; then
            local histfile_session_id

            # If shell_home and TERMUX_HOME are same, then set the HISTFILE with "sudo_"
            # appended to it to keep sudo shells command history separate from termux shells
            if [[ "$shell_home" == "$TERMUX_HOME" ]]; then
                histfile_session_id="sudo_fish"
            else
                histfile_session_id="fish"
            fi

            # fish uses the variable fish_history to store the session id for the history file
            # The history file ends up being "${fish_history}_history"
            SHELL_HISTFILE="$shell_home/.local/share/fish/${histfile_session_id}_history"
            SHELL_HISTFILE_COMMANDS="export fish_history='$histfile_session_id';"

        # If shell is python
        elif [[ "$shell_basename" == "python" ]]; then
            # python uses "~/.python_history" file to store history by default
            # History feature was introduced in 3.4
            SHELL_HISTFILE="$shell_home/.python_history"

        # If shell is ruby
        elif [[ "$shell_basename" == "ruby" ]]; then
            # irb uses "~/.irb_history" file to store history by default
            # If rvm is used, then its "~/.irb-history"
            # There are no params or environment variables that can be used to set history settings
            # History settings can be changed by defining following config options in "~/.irbrc" file
            # IRB.conf[:HISTORY_FILE] = "~/.irb_history"
            # IRB.conf[:SAVE_HISTORY] = 1000
            SHELL_HISTFILE="$shell_home/.irb_history"

        # If shell is pry
        elif [[ "$shell_basename" == "pry" ]]; then
            # pry uses "~/.pry_history" file to store history by default
            # There are no params or environment variables that can be used to set history settings
            # History settings can be changed by defining following config options in "~/.pryrc" file
            # Pry.config.history_file = "~/.pry_history"
            # Pry.config.history_load = true
            # Pry.config.history_save = true
            SHELL_HISTFILE="$shell_home/.pry_history"

        # If shell is php
        elif [[ "$shell_basename" == "php" ]]; then
            # php uses "~/.php_history" file to store history by default
            SHELL_HISTFILE="$shell_home/.php_history"

        # If shell is bash, zsh, dash, sh, ksh, node, perl
        elif [[ " bash zsh dash sh ksh node perl " == *" $shell_basename "* ]]; then
            # If shell_home and TERMUX_HOME are same, then set the HISTFILE with "sudo_"
            # appended to it to keep sudo shells command history separate from termux shells
            local shell_histfile_subname
            if [[ "$shell_home" == "$TERMUX_HOME" ]]; then
                shell_histfile_subname="sudo_${shell_basename}"
            else
                shell_histfile_subname="${shell_basename}"
            fi

            # If shell is bash
            if [[ "$shell_basename" == "bash" ]]; then
                # bash uses HISTFILE environment variable for history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SHELL_HISTFILE_COMMANDS="export HISTSIZE=1000;"
                SHELL_HISTFILE_COMMANDS+=$'\n'"export HISTFILESIZE=1000;"
            # If shell is zsh
            elif [[ "$shell_basename" == "zsh" ]]; then
                # zsh uses HISTFILE environment variable for history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SHELL_HISTFILE_COMMANDS="export HISTSIZE=1000;"
                SHELL_HISTFILE_COMMANDS+=$'\n'"export SAVEHIST=1000;"

            # If shell is node
            elif [[ "$shell_basename" == "node" ]]; then
                # node uses NODE_REPL_HISTORY to define path for history file
                # and NODE_REPL_HISTORY_SIZE for size of history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SHELL_HISTFILE_COMMANDS="export NODE_REPL_HISTORY='${SHELL_HISTFILE//\'/\'\\\'\'}';"
                SHELL_HISTFILE_COMMANDS+=$'\n'"export NODE_REPL_HISTORY_SIZE=1000;"

            # If shell is perl
            elif [[ "$shell_basename" == "perl" ]]; then
                # Use rlwrap "--history-filename" and "--histsize" params to set history settings
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS+=("--history-filename" "$SHELL_HISTFILE" "--histsize" "1000")

            # If shell is dash sh ksh
            else
                # The shells use HISTFILE environment variable for history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
            fi

        # If shell is python2, lua5.2, lua5.3, lua5.4
        elif [[ " python2 lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then
            # The shell does not have a history file or does not use it
            sudo_log 3 "The '$shell_basename' shell does not have a history file or does not use it"

        else
            sudo_log_errors "shell_basename '$shell_basename' not handled while running 'sudo_set_shell_histfile'"
            return 1
        fi


        # If SHELL_HISTFILE is set
        if [ -n "$SHELL_HISTFILE" ]; then
            # If SHELL_HISTFILE is not a valid absolute path
            if [[ ! "$SHELL_HISTFILE" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
                sudo_log_errors "The ${shell_label}_HISTFILE '$SHELL_HISTFILE' is not a valid absolute path"
                return 1
            fi

            # If SHELL_HISTFILE_COMMANDS is set
            if [ -n "$SHELL_HISTFILE_COMMANDS" ]; then
                SHELL_HISTFILE_COMMANDS+=$'\n'
            fi

            SHELL_HISTFILE_COMMANDS+="export HISTFILE='${SHELL_HISTFILE//\'/\'\\\'\'}';"

            # Find the parent directory of the SHELL_HISTFILE
            SHELL_HISTFILE_BASENAME="${SHELL_HISTFILE##*/}" # Strip longest match of */ from start
            SHELL_HISTFILE_PARENT_DIR="${SHELL_HISTFILE:0:${#SHELL_HISTFILE} - ${#SHELL_HISTFILE_BASENAME}}" # Substring from 0 to position of basename
            case "$SHELL_HISTFILE_PARENT_DIR" in *[!/]*/) SHELL_HISTFILE_PARENT_DIR="${SHELL_HISTFILE_PARENT_DIR%"${SHELL_HISTFILE_PARENT_DIR##*[!/]}"}";; *[/]) SHELL_HISTFILE_PARENT_DIR="/";; esac # Remove trailing slashes if not root
        fi

    else
        # If shell is fish
        if [[ "$shell_basename" == "fish" ]]; then
            # fish uses '--private' flag to disable history
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("--private")

        # If shell is python
        elif [[ "$shell_basename" == "python" ]]; then
            # Disable the "readline.write_history_file" function that writes history to file
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("-c" 'import readline; readline.write_history_file = lambda *args: None')

        # If shell is pry
        elif [[ "$shell_basename" == "pry" ]]; then
            # Use the "Pry.config.history_save" config to disable history saving
            # The "--no-history" flag to disable history loading is raising an exception in pry-0.13.1
            # Using the "Pry.config.history_load" config option with "-e" to disable history loading
            # does not work, since its already loaded by the time its run
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("-e" 'Pry.config.history_save = false;')

        # If shell is node
        elif [[ "$shell_basename" == "node" ]]; then
            # node uses NODE_REPL_HISTORY to define path for history file
            # Unsetting it disables history
            SHELL_HISTFILE_COMMANDS="export NODE_REPL_HISTORY='';"

        # If shell is perl
        elif [[ "$shell_basename" == "perl" ]]; then
            # Use rlwrap "--history-filename" to set history settings
            SUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS+=("--history-filename" "/dev/null")

        # If shell is bash, zsh, dash, sh, ksh
        elif [[ " bash zsh dash sh ksh " == *" $shell_basename "* ]]; then
            #If shell is bash
            #if [[ "$shell_basename" == "bash" ]]; then
                # bash uses 'history' shopt_option to control history, so unset it with a command option
                # For some reason this does not work since bash shell automatically enables history by default for interactive shells
                # Can be confirmed by running "shopt -o" in a new interactive shell
                #SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("+o" "history")
            #fi

            # Unsetting HISTFILE does not work for all shells like bash since it sets the default value if HISTFILE is not set
            # HISTFILE may still be overridden in a startup or a rc file
            SHELL_HISTFILE_COMMANDS="export HISTFILE='/dev/null';"

        # If shell is ruby, lua5.2, lua5.3, lua5.4, php, python2
        elif [[ " ruby lua5.2 lua5.3 lua5.4 php python2 " == *" $shell_basename "* ]]; then
            # The shell does not have a history file or does not use it or cannot be disabled using any params or environment variables
            sudo_log 3 "The '$shell_basename' shell does not have a history file or does not use it or cannot be disabled using any params or environment variables"

        else
            sudo_log_errors "shell_basename '$shell_basename' not handled while running 'sudo_set_shell_histfile'"
            return 1
        fi
    fi

    return 0

}

sudo_set_sudo_shell_command() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_shell_command"

    SHELL_ADDITIONAL_COMMAND_OPTIONS=("${SUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # Set shell command variables
    sudo_set_shell_command "SUDO_SHELL" "$SUDO_SHELL" "$SUDO_SHELL_BASENAME" "$SUDO_SHELL_PARENT_DIR" "$interactive_sudo_shell_required"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_set_shell_command' for SUDO_SHELL '$SUDO_SHELL'"
        return $return_value
    fi

    SUDO_SHELL_COMMAND=("${SHELL_COMMAND[@]}")
    SUDO_SHELL_INTERACTIVE_COMMAND=("${SHELL_INTERACTIVE_COMMAND[@]}")
    SUDO_SHELL_COMMAND_PRINT_FORMAT="$SHELL_COMMAND_PRINT_FORMAT"
    SUDO_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="$SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT"


    sudo_log 3 "SUDO_SHELL_COMMAND='${SUDO_SHELL_COMMAND[*]}'"
    sudo_log 3 "SUDO_SHELL_INTERACTIVE_COMMAND='${SUDO_SHELL_INTERACTIVE_COMMAND[*]}'"

    return 0

}

sudo_set_sudo_post_shell_command() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_post_shell_command"

    SHELL_ADDITIONAL_COMMAND_OPTIONS=()
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # Set shell command variables
    sudo_set_shell_command "SUDO_POST_SHELL" "$SUDO_POST_SHELL" "$SUDO_POST_SHELL_BASENAME" "$SUDO_POST_SHELL_PARENT_DIR" 1
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_set_shell_command' for SUDO_POST_SHELL '$SUDO_POST_SHELL'"
        return $return_value
    fi

    SUDO_POST_SHELL_INTERACTIVE_COMMAND=("${SHELL_INTERACTIVE_COMMAND[@]}")
    SUDO_POST_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="$SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT"

    sudo_log 3 "SUDO_POST_SHELL_INTERACTIVE_COMMAND='${SUDO_POST_SHELL_INTERACTIVE_COMMAND[*]}'"

    return 0

}

##
# `sudo_set_shell_command` `<shell_label>` `<shell>` `<shell_basename>` `<shell_parent_dir>` `<interactive_shell_required>`
##
sudo_set_shell_command() {

    local return_value

    # If argument count is not 5
    if [ $# -ne 5 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_shell_command'"
        return 1
    fi

    local shell_label="$1"
    local shell="$2"
    local shell_basename="$3"
    local shell_parent_dir="$4"
    local interactive_shell_required="$5"

    local shell_dependency_label=""
    local shell_dependency=""
    local shell_interactive_dependency_label=""
    local shell_interactive_dependency=""

    SHELL_COMMAND_PRINT_FORMAT="%q "
    SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="%q "

    # If shell is bash
    if [[ "$shell_basename" == "bash" ]]; then
        SHELL_COMMAND=("$shell" "--noprofile" "--norc" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-i")

    # If shell is zsh
    elif [[ "$shell_basename" == "zsh" ]]; then
        SHELL_COMMAND=("$shell" "--no-rcs" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-i")

    # If shell is python, python2
    elif [[ " python python2 " == *" $shell_basename "* ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "-i" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # If shell is ruby
    elif [[ "$shell_basename" == "ruby" ]]; then
        # The ruby interactive shell is named irb
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell_parent_dir/irb" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

        shell_interactive_dependency_label="irb"
        shell_interactive_dependency="$TERMUX_BIN/irb"

    # If shell is pry
    elif [[ "$shell_basename" == "pry" ]]; then
        # pry does not support passing scripts, ruby must be used instead
        SHELL_COMMAND=()
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # If shell is perl
    elif [[ "$shell_basename" == "perl" ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")

        # The perl interactive shell is started with rlwrap
        # rlwrap -A -pgreen -S "perl> " perl -wnE 'say eval()//$@'
        local shell_interactive_command_string;
        printf -v "shell_interactive_command_string" "%q " \
            "$TERMUX_BIN/rlwrap" "-A" "-pgreen" "-S" "perl> " "${SUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS[@]}" \
                "$shell_parent_dir/perl" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-wnE" 'say eval()//$@'
        SHELL_INTERACTIVE_COMMAND=("$shell_interactive_command_string")
        SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="%s"

        shell_interactive_dependency_label="rlwrap"
        shell_interactive_dependency="$TERMUX_BIN/rlwrap"

    # If shell is php
    elif [[ "$shell_basename" == "php" ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-a")

    # If shell is dash, sh, ksh, fish, node, lua5.2, lua5.3, lua5.4
        elif [[ " dash sh ksh fish node lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-i")
    else
        sudo_log_errors "shell_basename '$shell_basename' not handled while running 'sudo_set_shell_command'"
        return 1
    fi

    # If interactive_shell_required is not enabled
    if [[ "$interactive_shell_required" != "1" ]]; then
        # If shell_dependency is set
        if [ -n "$shell_dependency" ]; then
            # If USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION is enabled
            if [[ "$USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION" == "1" ]]; then
                sudo_unset_pre_su_variables
                SUDO_POST_SHELL="$($SU_ENV_COMMAND "source '${SUDO_SCRIPT_PATH//\'/\'\\\'\'}' || exit \$?; sudo_run_file_type_tests_on_path \"$shell_dependency_label\" '${shell_dependency//\'/\'\\\'\'}' 1 1 1 \"frx\"" 2>&1 < /dev/null)"
                return_value=$?
                sudo_set_post_su_variables
                { [ $return_value -ne 0 ] && [ -n "$SUDO_POST_SHELL" ]; } && sudo_log_errors "$SUDO_POST_SHELL"
            else
                sudo_run_file_type_tests_on_path "$shell_dependency_label" "$shell_dependency" 1 1 1 "frx"
                return_value=$?
            fi
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "'$shell_dependency_label' is required to run non-interactive '$shell_basename' shell"
                return $return_value
            fi
        fi
    else
        # If shell_interactive_dependency is set
        if [ -n "$shell_interactive_dependency" ]; then
            # If USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION is enabled
            if [[ "$USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION" == "1" ]]; then
                sudo_unset_pre_su_variables
                SUDO_POST_SHELL="$($SU_ENV_COMMAND "source '${SUDO_SCRIPT_PATH//\'/\'\\\'\'}' || exit \$?; sudo_run_file_type_tests_on_path \"$shell_interactive_dependency_label\" '${shell_interactive_dependency//\'/\'\\\'\'}' 1 1 1 \"frx\"" 2>&1 < /dev/null)"
                return_value=$?
                sudo_set_post_su_variables
                { [ $return_value -ne 0 ] && [ -n "$SUDO_POST_SHELL" ]; } && sudo_log_errors "$SUDO_POST_SHELL"
            else
                sudo_run_file_type_tests_on_path "$shell_interactive_dependency_label" "$shell_interactive_dependency" 1 1 1 "frx"
                return_value=$?
            fi
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "'$shell_interactive_dependency_label' is required to run interactive '$shell_basename' shell"
                return $return_value
            fi
        fi
    fi

    return 0

}

sudo_setup_sudo_shell_home_and_working_environment_wrapper() {

    local return_value
    local su_output

    sudo_log_literal 3 "\n\n\nRunning sudo_setup_sudo_shell_home_and_working_environment_wrapper stage 1"

    SETUP_SUDO_TEMP_DIRECTORY=0

    # If COMMAND_TYPE equals "script" and
    if [[ "$COMMAND_TYPE" == "script" ]]; then
        # Enable SETUP_SUDO_TEMP_DIRECTORY if required
        sudo_check_if_setting_up_sudo_temp_directory_is_required || return $?

        # If SETUP_SUDO_TEMP_DIRECTORY is enabled
        if [[ "$SETUP_SUDO_TEMP_DIRECTORY" == "1" ]]; then
            # Find an unused fd that is passed to su which the function sudo_setup_sudo_temp_directory will use to write the SUDO_TEMP_DIRECTORY value
            # which is later read after su returns
            # stdout cannot be used to return SUDO_TEMP_DIRECTORY from su using a subshell due to logging and possibly other output to stdout
            sudo_su_sub_process__receive_comm__start || return $?
        fi
    fi

    # If SETUP_SUDO_TEMP_DIRECTORY is not enabled and SUDO_DRY_RUN is enabled,
    # then just return since no need to create homes, rc files, history files, work dir and temp dir
    if [[ "$SETUP_SUDO_TEMP_DIRECTORY" != "1" ]] && [[ "$SUDO_DRY_RUN" == "1" ]]; then
        return 0
    fi



    # Remount android rootfs "/" partition and/or system "/system" partition as rw if
    # they need to be used for SUDO_SHELL_HOME, SUDO_POST_SHELL_HOME or SUDO_SHELL_WORKING_DIR
    sudo_remount_partitions_for_sudo_shell_homes "rw" || return $?



    local -a SU_ENV_COMMAND_ADDITIONAL_VARIABLES_TO_EXPORT_ARRAY=(
        ANDROID__BUILD_VERSION_SDK

        SUDO_SHELL_HOME_PARENT_DIR
        SUDO_SHELL_HOME

        SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES
        SUDO_SHELL_RCFILE_PARENT_DIR
        SUDO_SHELL_RCFILE
        SUDO_SHELL_RCFILE_VALUE

        SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES
        SUDO_SHELL_HISTFILE_PARENT_DIR
        SUDO_SHELL_HISTFILE

        SUDO_POST_SHELL_HOME_PARENT_DIR
        SUDO_POST_SHELL_HOME

        SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES
        SUDO_POST_SHELL_RCFILE_PARENT_DIR
        SUDO_POST_SHELL_RCFILE
        SUDO_POST_SHELL_RCFILE_VALUE

        SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES
        SUDO_POST_SHELL_HISTFILE_PARENT_DIR
        SUDO_POST_SHELL_HISTFILE

        SUDO_SHELL_WORKING_DIR

        REMOVE_PREVIOUS_SUDO_TEMP_FILES
        SETUP_SUDO_TEMP_DIRECTORY
        SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY
        SUDO_TEMP_DIRECTORY_PREFIX
        SUDO_TEMP_DIRECTORY

        TERMUX_ROOTFS
        TERMUX_PREFIX
        TERMUX_HOME

        SUDO_DRY_RUN
    )

    local var

    # Export additional variables that are required by su that were not exported by sudo_export_or_unexport_shared_variables_for_su
    for var in "${SU_ENV_COMMAND_ADDITIONAL_VARIABLES_TO_EXPORT_ARRAY[@]}"; do
        export "${var}"
    done



    sudo_log_literal 3 "\nRunning sudo_setup_sudo_shell_home_and_working_environment"

    # Run sudo_setup_sudo_shell_home_and_working_environment that sets up the sudo environment
    sudo_unset_pre_su_variables
    su_output=$($SU_ENV_COMMAND "source '${SUDO_SCRIPT_PATH//\'/\'\\\'\'}' || exit \$?; sudo_setup_sudo_shell_home_and_working_environment;" 2>&1 < /dev/null)
    return_value=$?
    sudo_set_post_su_variables
    [ -n "$su_output" ] && echo "$su_output"
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_setup_sudo_shell_home_and_working_environment'"
        return $return_value
    fi



    # Remove export property from additional variables exported earlier
    for var in "${SU_ENV_COMMAND_ADDITIONAL_VARIABLES_TO_EXPORT_ARRAY[@]}"; do
        export -n "${var}"
    done




    sudo_log_literal 3 "\nRunning sudo_setup_sudo_shell_home_and_working_environment_wrapper stage 2"

    # If SETUP_SUDO_TEMP_DIRECTORY is enabled
    if [[ "$SETUP_SUDO_TEMP_DIRECTORY" == "1" ]]; then
        sudo_su_sub_process__receive_comm__stop || return $?

        # If SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH does not exist
        if [ ! -e "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH" ]; then
            sudo_log_errors "The SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH '$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH' does not exist that needs to be used to read SUDO_TEMP_DIRECTORY"
            return 1
        fi

        # Read the value of SUDO_TEMP_DIRECTORY from SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH which the sudo_setup_sudo_temp_directory function would have written while running su
        SUDO_TEMP_DIRECTORY="$(cat "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH")"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failure to read SUDO_TEMP_DIRECTORY from SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH '$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH'"
            return $return_value
        fi

        # If SUDO_TEMP_DIRECTORY is not a valid absolute path
        if [[ ! "$SUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            sudo_log_errors "The SUDO_TEMP_DIRECTORY '$SUDO_TEMP_DIRECTORY' is not a valid absolute path"
            return 1
        fi

        sudo_log 3 "SUDO_TEMP_DIRECTORY='$SUDO_TEMP_DIRECTORY'"

        sudo_su_sub_process__receive_comm__cleanup || return $?
    fi

    return 0

}

sudo_setup_sudo_shell_home_and_working_environment() {

    local return_value

    sudo_log_literal 3 "Started sudo_setup_sudo_shell_home_and_working_environment"

    # sudo_setup_shell_home shell_label shell_home_parent_dir shell_home shell_automatically_create_rc_file shell_rcfile_parent_dir shell_rcfile shell_rcfile_value  shell_histfile_parent_dir shell_histfile
    sudo_setup_shell_home "SUDO_SHELL" "$SUDO_SHELL_HOME_PARENT_DIR" "$SUDO_SHELL_HOME" "$SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES" "$SUDO_SHELL_RCFILE_PARENT_DIR" "$SUDO_SHELL_RCFILE" "$SUDO_SHELL_RCFILE_VALUE" "$SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES" "$SUDO_SHELL_HISTFILE_PARENT_DIR" "$SUDO_SHELL_HISTFILE"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
        sudo_log_errors "Failed to setup SUDO_SHELL_HOME"
        return $return_value
    fi

    # If SUDO_DRY_RUN is not enabled, only then run it
    # If it is enabled, then we must be running this function because SETUP_SUDO_TEMP_DIRECTORY was enabled
    # in which case no need to create post shell home and work dir
    if [[ "$SUDO_DRY_RUN" != "1" ]]; then

        # If SUDO_POST_SHELL_HOME is set
        if [ -n "$SUDO_POST_SHELL_HOME" ]; then
            # If SUDO_SHELL and SUDO_POST_SHELL home, rcfile or histfiles are different
            if [[ "$SUDO_POST_SHELL_HOME" != "$SUDO_SHELL_HOME" ]] || \
                    [[ "$SUDO_POST_SHELL_RCFILE" != "$SUDO_SHELL_RCFILE" ]] || \
                        [[ "$SUDO_POST_SHELL_HISTFILE" != "$SUDO_SHELL_HISTFILE" ]]; then
                # sudo_setup_shell_home shell_label shell_home_parent_dir shell_home shell_automatically_create_rc_file shell_rcfile_parent_dir shell_rcfile shell_rcfile_value shell_histfile_parent_dir  shell_histfile
                sudo_setup_shell_home "SUDO_POST_SHELL"  "$SUDO_POST_SHELL_HOME_PARENT_DIR" "$SUDO_POST_SHELL_HOME" "$SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES" "$SUDO_POST_SHELL_RCFILE_PARENT_DIR" "$SUDO_POST_SHELL_RCFILE" "$SUDO_POST_SHELL_RCFILE_VALUE" "$SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES" "$SUDO_POST_SHELL_HISTFILE_PARENT_DIR" "$SUDO_POST_SHELL_HISTFILE"
                return_value=$?
                if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
                    sudo_log_errors "Failed to setup SUDO_POST_SHELL_HOME"
                    return $return_value
                fi
            fi
        fi

        # If SUDO_SHELL_WORKING_DIR is set and does not equal rootfs
        if [ -n "$SUDO_SHELL_WORKING_DIR" ] && [ "$SUDO_SHELL_WORKING_DIR" != "/" ]; then
            # Create SUDO_SHELL_WORKING_DIR if missing
            sudo_setup_sudo_shell_working_dir || return $?
        fi
    fi

    # Setup SUDO_TEMP_DIRECTORY
    sudo_setup_sudo_temp_directory
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_setup_sudo_temp_directory'"
        return $return_value
    fi

    return 0

}

##
# `sudo_setup_shell_home` `<shell_label>` `<shell_home_parent_dir>` `<shell_home>` `<shell_automatically_create_rc_file>` `<shell_rcfile_parent_dir>` `<shell_rcfile>` `<shell_rcfile_value>`  `<shell_histfile_parent_dir>` `<shell_histfile>`
##
sudo_setup_shell_home() {

    local return_value

    # If argument count is not 10
    if [ $# -ne 10 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_setup_shell_home'"
        return 1
    fi

    local shell_label="$1"
    local shell_home_parent_dir="$2"
    local shell_home="$3"
    local shell_automatically_create_rc_file="$4"
    local shell_rcfile_parent_dir="$5"
    local shell_rcfile="$6"
    local shell_rcfile_value="$7"
    local shell_automatically_create_history_file="$8"
    local shell_histfile_parent_dir="$9"
    local shell_histfile="${10}"

    local create_shell_home_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_home
    local shell_home_ownership
    local shell_home_permission
    local shell_home_file_type_tests

    local create_shell_rcfile_parent_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir
    local shell_rcfile_parent_dir_ownership
    local shell_rcfile_parent_dir_permission
    local shell_rcfile_parent_dir_file_type_tests

    local create_shell_rcfile_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile
    local shell_rcfile_ownership
    local shell_rcfile_permission
    local shell_rcfile_file_type_tests

    local create_shell_histfile_parent_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir
    local shell_histfile_parent_dir_ownership
    local shell_histfile_parent_dir_permission
    local shell_histfile_parent_dir_file_type_tests

    local create_shell_histfile_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_histfile
    local shell_histfile_ownership
    local shell_histfile_permission
    local shell_histfile_file_type_tests

    local validation_result

    sudo_log_literal 3 "\nRunning sudo_setup_shell_home for $shell_label"



    create_shell_home_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_shell_home=1
    shell_home_permission="700"
    shell_home_file_type_tests="rwx"

    # Validate if shell_home is a whitelisted path under TERMUX_ROOTFS
    sudo_validate_path_is_a_whitelisted_path_under_termux_rootfs "${shell_label}_HOME" "$shell_home"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 2 ] &&  [ $return_value -ne 3 ]; then
        return $return_value
    fi

    validation_result=$return_value

    # If shell_home is a whitelisted path under TERMUX_ROOTFS
    if [ $validation_result -eq 0 ]; then
        # If shell_home and TERMUX_HOME are same, then root ownership
        # must not be set to it otherwise termux app non-root shell will not work
        if [[ "$shell_home" == "$TERMUX_HOME" ]]; then
            shell_home_ownership="--reference=\"$TERMUX_ROOTFS\""
        else
            shell_home_ownership="root:root"
        fi
    # If shell_home is a blacklisted path under TERMUX_ROOTFS
    elif [ $validation_result -eq 2 ]; then
        sudo_log_errors "The '$shell_home' cannot be used as ${shell_label}_HOME"
        return 1
    # If shell_home is not under TERMUX_ROOTFS
    else
        shell_home_ownership="--reference='${shell_home_parent_dir//\'/\'\\\'\'}'"
    fi



    # If shell_automatically_create_rc_file is not enabled or SUDO_DRY_RUN is enabled, then unset shell_rcfile
    if [[ "$shell_automatically_create_rc_file" != "1" ]] || [[ "$SUDO_DRY_RUN" == "1" ]]; then
        shell_rcfile=""
    fi

    # If shell_rcfile is set
    if [ -n "$shell_rcfile" ]; then
        # If shell_rcfile_parent_dir is not the same as shell_home or one of subdirectories,
        # otherwise remounting rootfs and system partition would become too complicated
        if [[ "$shell_rcfile_parent_dir" != "$shell_home" ]] && [[ "$shell_rcfile_parent_dir" != "$shell_home"/* ]]; then
            sudo_log_errors "The ${shell_label}_RCFILE_PARENT_DIR '$shell_rcfile_parent_dir' must be same as ${shell_label}_HOME '$shell_home' or be one of its subdirectories"
            return 1
        fi

        create_shell_rcfile_parent_dir_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir=1
        shell_rcfile_parent_dir_permission="700"
        shell_rcfile_parent_dir_file_type_tests="rwx"

        create_shell_rcfile_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_rcfile=1
        shell_rcfile_permission="600"
        shell_rcfile_file_type_tests="rw"

        # Validate if shell_rcfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        sudo_validate_path_is_a_whitelisted_path_under_termux_rootfs "${shell_label}_RCFILE_PARENT_DIR" "$shell_rcfile_parent_dir"
            return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 2 ] &&  [ $return_value -ne 3 ]; then
            return $return_value
        fi

        validation_result=$return_value

        # If shell_rcfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        if [ $validation_result -eq 0 ]; then
            # If shell_rcfile_parent_dir and TERMUX_HOME are same, then root ownership
            # must not be set to it otherwise termux app non-root shell will not work
            if [[ "$shell_rcfile_parent_dir" == "$TERMUX_HOME" ]]; then
                shell_rcfile_parent_dir_ownership="--reference=\"$TERMUX_ROOTFS\""
                shell_rcfile_ownership="--reference=\"$TERMUX_ROOTFS\""
            else
                shell_rcfile_parent_dir_ownership="root:root"
                shell_rcfile_ownership="root:root"
            fi
        # If shell_rcfile_parent_dir is a blacklisted path under TERMUX_ROOTFS
        elif [ $validation_result -eq 2 ]; then
            sudo_log_errors "The '$shell_rcfile_parent_dir' cannot be used as ${shell_label}_RCFILE_PARENT_DIR"
            return 1
        # If shell_rcfile_parent_dir is not under TERMUX_ROOTFS
        else
            # If shell_rcfile_parent_dir and shell_home are same
            if [[ "$shell_rcfile_parent_dir" == "$shell_home" ]]; then
                shell_rcfile_parent_dir_ownership="--reference='${shell_home_parent_dir//\'/\'\\\'\'}'"
                shell_rcfile_ownership="--reference='${shell_home_parent_dir//\'/\'\\\'\'}'"
            else

                # Find the parent directory of the shell_rcfile_parent_dir
                shell_rcfile_parent_dir_basename="${shell_rcfile_parent_dir##*/}" # Strip longest match of */ from start
                shell_rcfile_parent_dir_parent_dir="${shell_rcfile_parent_dir:0:${#shell_rcfile_parent_dir} - ${#shell_rcfile_parent_dir_basename}}" # Substring from 0 to position of basename
                case "$shell_rcfile_parent_dir_parent_dir" in *[!/]*/) shell_rcfile_parent_dir_parent_dir="${shell_rcfile_parent_dir_parent_dir%"${shell_rcfile_parent_dir_parent_dir##*[!/]}"}";; *[/]) shell_rcfile_parent_dir_parent_dir="/";; esac # Remove trailing slashes if not root

                shell_rcfile_parent_dir_ownership="--reference='${shell_rcfile_parent_dir_parent_dir//\'/\'\\\'\'}'"
                shell_rcfile_ownership="--reference='${shell_rcfile_parent_dir//\'/\'\\\'\'}'"
            fi
        fi
    fi



    # If shell_automatically_create_history_files is not enabled or SUDO_DRY_RUN is enabled, then unset shell_histfile
    if [[ "$shell_automatically_create_history_file" != "1" ]] || [[ "$SUDO_DRY_RUN" == "1" ]]; then
        shell_histfile=""
    fi

    # If shell_histfile is set
    if [ -n "$shell_histfile" ]; then

        # If shell_histfile_parent_dir is not the same as shell_home or one of subdirectories,
        # otherwise remounting rootfs and system partition would become too complicated
        if [[ "$shell_histfile_parent_dir" != "$shell_home" ]] && [[ "$shell_histfile_parent_dir" != "$shell_home"/* ]]; then
            sudo_log_errors "The ${shell_label}_HISTFILE_PARENT_DIR '$shell_histfile_parent_dir' must be same as ${shell_label}_HOME '$shell_home' or be one of its subdirectories"
            return 1
        fi

        create_shell_histfile_parent_dir_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir=1
        shell_histfile_parent_dir_permission="700"
        shell_histfile_parent_dir_file_type_tests="rwx"

        create_shell_histfile_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_histfile=1
        shell_histfile_permission="600"
        shell_histfile_file_type_tests="rw"

        # Validate if shell_histfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        sudo_validate_path_is_a_whitelisted_path_under_termux_rootfs "${shell_label}_HISTFILE_PARENT_DIR" "$shell_histfile_parent_dir"
        return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 2 ] &&  [ $return_value -ne 3 ]; then
            return $return_value
        fi

        validation_result=$return_value

        # If shell_histfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        if [ $validation_result -eq 0 ]; then
            # If shell_histfile_parent_dir and TERMUX_HOME are same, then root ownership
            # must not be set to it otherwise termux app non-root shell will not work
            if [[ "$shell_histfile_parent_dir" == "$TERMUX_HOME" ]]; then
                shell_histfile_parent_dir_ownership="--reference=\"$TERMUX_ROOTFS\""
                shell_histfile_ownership="--reference=\"$TERMUX_ROOTFS\""
            else
                shell_histfile_parent_dir_ownership="root:root"
                shell_histfile_ownership="root:root"
            fi
        # If shell_histfile_parent_dir is a blacklisted path under TERMUX_ROOTFS
        elif [ $validation_result -eq 2 ]; then
            sudo_log_errors "The '$shell_histfile_parent_dir' cannot be used as ${shell_label}_HISTFILE_PARENT_DIR"
            return 1
        # If shell_histfile_parent_dir is not under TERMUX_ROOTFS
        else
            # If shell_histfile_parent_dir and shell_home are same
            if [[ "$shell_histfile_parent_dir" == "$shell_home" ]]; then
                shell_histfile_parent_dir_ownership="--reference='${shell_home_parent_dir//\'/\'\\\'\'}'"
                shell_histfile_ownership="--reference='${shell_home_parent_dir//\'/\'\\\'\'}'"
            else
                # Find the parent directory of the shell_histfile_parent_dir
                shell_histfile_parent_dir_basename="${shell_histfile_parent_dir##*/}" # Strip longest match of */ from start
                shell_histfile_parent_dir_parent_dir="${shell_histfile_parent_dir:0:${#shell_histfile_parent_dir} - ${#shell_histfile_parent_dir_basename}}" # Substring from 0 to position of basename
                case "$shell_histfile_parent_dir_parent_dir" in *[!/]*/) shell_histfile_parent_dir_parent_dir="${shell_histfile_parent_dir_parent_dir%"${shell_histfile_parent_dir_parent_dir##*[!/]}"}";; *[/]) shell_histfile_parent_dir_parent_dir="/";; esac # Remove trailing slashes if not root

                shell_histfile_parent_dir_ownership="--reference='${shell_histfile_parent_dir_parent_dir//\'/\'\\\'\'}'"
                shell_histfile_ownership="--reference='${shell_histfile_parent_dir//\'/\'\\\'\'}'"
            fi
        fi
    fi



    sudo_create_shell_home "$shell_label" \
        "$shell_home" "$create_shell_home_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_home" "$shell_home_ownership" "$shell_home_permission" "$shell_home_file_type_tests" \
        "$shell_rcfile_parent_dir" "$create_shell_rcfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir" "$shell_rcfile_parent_dir_ownership" "$shell_rcfile_parent_dir_permission" "$shell_rcfile_parent_dir_file_type_tests" \
        "$shell_rcfile" "$create_shell_rcfile_if_it_does_not_exist" "$shell_rcfile_value" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile" "$shell_rcfile_ownership" "$shell_rcfile_permission" "$shell_rcfile_file_type_tests" \
        "$shell_histfile_parent_dir" "$create_shell_histfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir" "$shell_histfile_parent_dir_ownership" "$shell_histfile_parent_dir_permission" "$shell_histfile_parent_dir_file_type_tests" \
        "$shell_histfile" "$create_shell_histfile_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_histfile" "$shell_histfile_ownership" "$shell_histfile_permission" "$shell_histfile_file_type_tests"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while running 'sudo_create_shell_home'"
        return $return_value
    fi

    return 0

}

##
# `sudo_create_shell_home` `<shell_label>` \
#     `<shell_home>` `<create_shell_home_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_home>` `<shell_home_ownership>` `<shell_home_permission>` `<shell_home_file_type_tests>` \
#     `<shell_rcfile_parent_dir>` `<create_shell_rcfile_parent_dir_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir>` `<shell_rcfile_parent_dir_ownership>` `<shell_rcfile_parent_dir_permission>` `<shell_rcfile_parent_dir_file_type_tests>` \
#     `<shell_rcfile>` `<create_shell_rcfile_if_it_does_not_exist>` `<shell_rcfile_value>` `<only_set_perms_and_ownership_on_creation_of_shell_rcfile>` `<shell_rcfile_ownership>` `<shell_rcfile_permission>` `<shell_rcfile_file_type_tests>` \
#     `<shell_histfile_parent_dir>` `<create_shell_histfile_parent_dir_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir>` `<shell_histfile_parent_dir_ownership>` `<shell_histfile_parent_dir_permission>` `<shell_histfile_parent_dir_file_type_tests>` \
#     `<shell_histfile>` `<create_shell_histfile_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_histfile>` `<shell_histfile_ownership>` `<shell_histfile_permission>` `<shell_histfile_file_type_tests>`
##
sudo_create_shell_home() {

    local return_value

    # If argument count is not 32
    if [ $# -ne 32 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_create_shell_home'"
        return 1
    fi

    local shell_label="$1"

    local shell_home="$2"
    local create_shell_home_if_it_does_not_exist="$3"
    local only_set_perms_and_ownership_on_creation_of_shell_home="$4"
    local shell_home_ownership="$5"
    local shell_home_permission="$6"
    local shell_home_file_type_tests="$7"


    local shell_rcfile_parent_dir="$8"
    local create_shell_rcfile_parent_dir_if_it_does_not_exist="$9"
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir="${10}"
    local shell_rcfile_parent_dir_ownership="${11}"
    local shell_rcfile_parent_dir_permission="${12}"
    local shell_rcfile_parent_dir_file_type_tests="${13}"


    local shell_rcfile="${14}"
    local create_shell_rcfile_if_it_does_not_exist="${15}"
    local shell_rcfile_value="${16}"
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile="${17}"
    local shell_rcfile_ownership="${18}"
    local shell_rcfile_permission="${19}"
    local shell_rcfile_file_type_tests="${20}"


    local shell_histfile_parent_dir="${21}"
    local create_shell_histfile_parent_dir_if_it_does_not_exist="${22}"
    local only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir="${23}"
    local shell_histfile_parent_dir_ownership="${24}"
    local shell_histfile_parent_dir_permission="${25}"
    local shell_histfile_parent_dir_file_type_tests="${26}"

    local shell_histfile="${27}"
    local create_shell_histfile_if_it_does_not_exist="${28}"
    local only_set_perms_and_ownership_on_creation_of_shell_histfile="${29}"
    local shell_histfile_ownership="${30}"
    local shell_histfile_permission="${31}"
    local shell_histfile_file_type_tests="${32}"



    # Create shell_home if missing and set ownership and permissions
    # sudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    sudo_create_modify_validate_directory "${shell_label}_HOME" "$shell_home" 1 "$create_shell_home_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_home" "$shell_home_ownership" "$shell_home_permission" - - - - "$shell_home_file_type_tests" || return $?



    # If shell_rcfile is set
    if [ -n "$shell_rcfile" ]; then
        # If shell_home and shell_rcfile_parent_dir are not same
        if [[ "$shell_home" != "$shell_rcfile_parent_dir" ]]; then
            # Create shell_rcfile_parent_dir if missing and set ownership and permissions
            # sudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
            sudo_create_modify_validate_directory "${shell_label}_RCFILE_PARENT_DIR" "$shell_rcfile_parent_dir" 1 "$create_shell_rcfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir" "$shell_rcfile_parent_dir_ownership" "$shell_rcfile_parent_dir_permission" - - - - "$shell_rcfile_parent_dir_file_type_tests" || return $?
        fi

        # Create shell_rcfile if missing and set ownership and permissions
        # sudo_create_modify_validate_file file_path_label file_path check_if_absolute_path create_file_if_it_does_not_exist file_creation_command_options file_content only_set_perms_and_ownership_on_creation file_chown_command_options file_chmod_command_options file_type_tests
        sudo_create_modify_validate_file "${shell_label}_RCFILE" "$shell_rcfile" 1 "$create_shell_rcfile_if_it_does_not_exist" "%s" "$shell_rcfile_value" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile" "$shell_rcfile_ownership" "$shell_rcfile_permission" "$shell_rcfile_file_type_tests" || return $?
    fi



    # If shell_histfile is set
    if [ -n "$shell_histfile" ]; then
        # If shell_home and shell_histfile_parent_dir are not same
        # and shell_rcfile_parent_dir shell_histfile_parent_dir are not same
        if [[ "$shell_home" != "$shell_histfile_parent_dir" ]] && [[ "$shell_rcfile_parent_dir" != "$shell_histfile_parent_dir" ]]; then
            # Create shell_histfile_parent_dir if missing and set ownership and permissions
            # sudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
            sudo_create_modify_validate_directory "${shell_label}_HISTFILE_PARENT_DIR" "$shell_histfile_parent_dir" 1 "$create_shell_histfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir" "$shell_histfile_parent_dir_ownership" "$shell_histfile_parent_dir_permission" - - - - "$shell_histfile_parent_dir_file_type_tests" || return $?
        fi

        # Create shell_histfile if missing and set ownership and permissions
        # sudo_create_modify_validate_file file_path_label file_path check_if_absolute_path create_file_if_it_does_not_exist file_creation_command_options file_content only_set_perms_and_ownership_on_creation file_chown_command_options file_chmod_command_options file_type_tests
        sudo_create_modify_validate_file "${shell_label}_HISTFILE" "$shell_histfile" 1 "$create_shell_histfile_if_it_does_not_exist" "%s" "" "$only_set_perms_and_ownership_on_creation_of_shell_histfile" "$shell_histfile_ownership" "$shell_histfile_permission" "$shell_histfile_file_type_tests" || return $?
    fi

    return 0

}

sudo_setup_termux_tmp_dir() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_setup_termux_tmp_dir"

    local create_termux_tmp_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_termux_tmp_dir
    local termux_tmp_dir_permission
    local termux_tmp_dir_ownership
    local termux_tmp_dir_file_type_tests

    create_termux_tmp_dir_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_termux_tmp_dir=1
    termux_tmp_dir_ownership="--reference='$TERMUX_PREFIX'"
    termux_tmp_dir_permission="700"
    termux_tmp_dir_file_type_tests="drwx"


    # Create TMPDIR if missing
    # sudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    sudo_create_modify_validate_directory "TMPDIR" "$TMPDIR" 1 "$create_termux_tmp_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_termux_tmp_dir" "$termux_tmp_dir_ownership" "$termux_tmp_dir_permission" - - - - "$termux_tmp_dir_file_type_tests" || return $?

    return 0

}

sudo_set_sudo_shell_working_dir() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_set_sudo_shell_working_dir"

    if [ "$SUDO_SHELL_WORKING_DIR" != "/" ]; then
        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in SUDO_SHELL_WORKING_DIR
        sudo_expand_termux_path "SUDO_SHELL_WORKING_DIR" "SUDO_SHELL_WORKING_DIR" "$SUDO_SHELL_WORKING_DIR" "$TERMUX_PREFIX" "$TERMUX_HOME" 1
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to expand SUDO_SHELL_WORKING_DIR '$SUDO_SHELL_WORKING_DIR'"
            return $return_value
        fi
    fi

    # If SUDO_SHELL_WORKING_DIR is not a valid absolute path
    if [[ ! "$SUDO_SHELL_WORKING_DIR" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]]; then
        sudo_log_errors "The SUDO_SHELL_WORKING_DIR '$SUDO_SHELL_WORKING_DIR' is not a valid absolute path"
        return 1
    fi

    sudo_log 2 "SUDO_SHELL_WORKING_DIR='$SUDO_SHELL_WORKING_DIR'"

    # Find the parent directory of the SUDO_SHELL_WORKING_DIR
    SUDO_SHELL_WORKING_DIR_BASENAME="${SUDO_SHELL_WORKING_DIR##*/}" # Strip longest match of */ from start
    SUDO_SHELL_WORKING_DIR_PARENT_DIR="${SUDO_SHELL_WORKING_DIR:0:${#SUDO_SHELL_WORKING_DIR} - ${#SUDO_SHELL_WORKING_DIR_BASENAME}}" # Substring from 0 to position of basename
    case "$SUDO_SHELL_WORKING_DIR_PARENT_DIR" in *[!/]*/) SUDO_SHELL_WORKING_DIR_PARENT_DIR="${SUDO_SHELL_WORKING_DIR_PARENT_DIR%"${SUDO_SHELL_WORKING_DIR_PARENT_DIR##*[!/]}"}";; *[/]) SUDO_SHELL_WORKING_DIR_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    sudo_log 3 "SUDO_SHELL_WORKING_DIR_PARENT_DIR='$SUDO_SHELL_WORKING_DIR_PARENT_DIR'"

    return 0

}

sudo_setup_sudo_shell_working_dir() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_setup_sudo_shell_working_dir"

    local create_shell_working_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_working_dir
    local shell_working_dir_permission
    local shell_working_dir_ownership
    local shell_working_dir_file_type_tests

    create_shell_working_dir_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_shell_working_dir=1
    shell_working_dir_permission="700"

    # Find the parent directory of the SUDO_SHELL_WORKING_DIR
    SUDO_SHELL_WORKING_DIR_BASENAME="${SUDO_SHELL_WORKING_DIR##*/}" # Strip longest match of */ from start
    SUDO_SHELL_WORKING_DIR_PARENT_DIR="${SUDO_SHELL_WORKING_DIR:0:${#SUDO_SHELL_WORKING_DIR} - ${#SUDO_SHELL_WORKING_DIR_BASENAME}}" # Substring from 0 to position of basename
    case "$SUDO_SHELL_WORKING_DIR_PARENT_DIR" in *[!/]*/) SUDO_SHELL_WORKING_DIR_PARENT_DIR="${SUDO_SHELL_WORKING_DIR_PARENT_DIR%"${SUDO_SHELL_WORKING_DIR_PARENT_DIR##*[!/]}"}";; *[/]) SUDO_SHELL_WORKING_DIR_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    shell_working_dir_ownership="--reference='${SUDO_SHELL_WORKING_DIR_PARENT_DIR//\'/\'\\\'\'}'"


    # If SUDO_SHELL_WORKING_DIR is the same as TERMUX_ROOTFS or is under it
    if [[ "$SUDO_SHELL_WORKING_DIR" == "$TERMUX_ROOTFS" ]] || [[ "$SUDO_SHELL_WORKING_DIR" == "$TERMUX_ROOTFS"/* ]]; then
        shell_working_dir_file_type_tests="drwx"
    # It might not be possible for the directory to be writable or executable in other paths like in storage or rootfs/system partition
    else
        shell_working_dir_file_type_tests="dr"
    fi


    # Create SUDO_SHELL_WORKING_DIR if missing
    # sudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    sudo_create_modify_validate_directory "SUDO_SHELL_WORKING_DIR" "$SUDO_SHELL_WORKING_DIR" 1 "$create_shell_working_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_working_dir" "$shell_working_dir_ownership" "$shell_working_dir_permission" - - - - "$shell_working_dir_file_type_tests" || return $?

    return 0

}

sudo_setup_sudo_temp_directory() {

    local return_value

    local valid_absolute_path_regex='^(/[^/]+)+$'

    # If REMOVE_PREVIOUS_SUDO_TEMP_FILES is enabled
    if [[ "$REMOVE_PREVIOUS_SUDO_TEMP_FILES" == "1" ]]; then
        # If SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY is set to an absolute path and SUDO_TEMP_DIRECTORY_PREFIX is not empty
        if [[ "$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" =~ $valid_absolute_path_regex ]] && [ -n "$SUDO_TEMP_DIRECTORY_PREFIX" ]; then
            # Remove all directories with the prefix SUDO_TEMP_DIRECTORY_PREFIX
            sudo_log_literal 3 "\nRemove all directories with the prefix '$SUDO_TEMP_DIRECTORY_PREFIX' in SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY'"
            find "$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" -maxdepth 1 -type d -name "$SUDO_TEMP_DIRECTORY_PREFIX*" -exec rm -rf "{}" \;
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failure while removing all directories with the prefix '$SUDO_TEMP_DIRECTORY_PREFIX' in SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY'"
                return $return_value
            fi
        fi
    fi

    # If SETUP_SUDO_TEMP_DIRECTORY is not enabled, then just return
    if [[ "$SETUP_SUDO_TEMP_DIRECTORY" != "1" ]]; then
        return 0
    fi

    sudo_log_literal 3 "\nRunning sudo_setup_sudo_temp_directory"

    # If SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY is not a valid absolute path
    if [[ ! "$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" =~ $valid_absolute_path_regex ]]; then
        sudo_log_errors "The SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY' is not a valid absolute path"
        return 1
    fi

    # If SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH is not a valid absolute path
    if [[ ! "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH" =~ $valid_absolute_path_regex ]]; then
        sudo_log_errors "The SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH '$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH' is not a valid absolute path"
        return 1
    fi

    # Create a temp directory in SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY to store temp scripts used by the sudo script
    # SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY by default would be same as SUDO_SHELL_HOME
    # TMPDIR is not used since termux will not be able to remove PREFIX or TMPDIR if the
    # directory is not removed automatically at the end of sudo execution and left there.
    # The parent directory of the scripts must also have root ownership for security reasons,
    # hence a directory is created to store script files since SUDO_SHELL_HOME itself may not have root ownership,
    # specially if its the same as TERMUX_HOME
    # Moreover if '--script-name' is passed, then there may be conflicts between executions since
    # temp files will likely share the same parent directory and have the same name
    # this will allow each execution of the script to have a separate directory for itself with a random suffix.
    # Scripts will also have an empty directory to use that will be unique for them, which will be removed after execution
    SUDO_TEMP_DIRECTORY="$(mktemp -d --tmpdir="$SUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" "$SUDO_TEMP_DIRECTORY_PREFIX.XXXXXX")"
    return_value=$?
    if [ $return_value -ne 0 ] || [[ ! "$SUDO_TEMP_DIRECTORY" =~ $valid_absolute_path_regex ]]; then
        sudo_log_errors "Failure while running mktemp to create SUDO_TEMP_DIRECTORY"
        sudo_log_errors "SUDO_TEMP_DIRECTORY='$SUDO_TEMP_DIRECTORY'"
        if [ $return_value -eq 0 ]; then
            return_value=1
        fi
        return $return_value
    fi

    # Write the value of SUDO_TEMP_DIRECTORY to SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD
    printf "%s" "$SUDO_TEMP_DIRECTORY" > "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while writing SUDO_TEMP_DIRECTORY to SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH '$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH'"
        return $return_value
    fi

    return 0

}

set_sudo_traps() {

    local trap_function="${1:-}"

    if [[ ! "$trap_function" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
        sudo_log_errors "The trap_function '$trap_function' argument passed to \
'set_sudo_traps' is not a valid function name."
        return 64 # EX__USAGE
    fi

    # shellcheck disable=SC2064
    trap "$trap_function" EXIT
    # shellcheck disable=SC2064
    trap "$trap_function TERM" TERM
    # shellcheck disable=SC2064
    trap "$trap_function INT" INT
    # shellcheck disable=SC2064
    trap "$trap_function HUP" HUP
    # shellcheck disable=SC2064
    trap "$trap_function QUIT" QUIT

    return 0

}

sudo_trap() {

    # The sudo_trap will do the following:
    # Store the original trap signal in $sudo_exit_code.
    # Remove the EXIT trap so its not called again.
    # Remove temp_directory if set if sudo command failed.
    # Remount rootfs and system partitions back to ro if needed.
    # If a signal argument was passed, then remove its trap and
    # then exit with the original trap signal exit code
    # so that parent processes can be notified if necessary.

    local sudo_exit_code=$?
    trap - EXIT

    [ $sudo_exit_code -ne 0 ] && sudo_remove_sudo_temp_directory
    [ $sudo_exit_code -ne 0 ] && sudo_close_command_fds
    [ $sudo_exit_code -ne 0 ] && sudo_su_sub_process__receive_comm__stop
    [ $sudo_exit_code -ne 0 ] && sudo_su_sub_process__receive_comm__cleanup
    sudo_remount_partitions_for_sudo_shell_homes "ro"

    [ -n "${1:-}" ] && trap - "$1"
    exit $sudo_exit_code

}

sudo_remove_sudo_temp_directory() {

    local return_value

    local su_output

    # If SUDO_TEMP_DIRECTORY is a valid absolute path and SU_ENV_COMMAND is set and
    # DO_NOT_DELETE_SUDO_TEMP_DIRECTORY_ON_EXIT is not enabled and
    # Sudo command failed
    if [[ "$SUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]] && \
        [ -n "$SU_ENV_COMMAND" ] && \
            [[ "$DO_NOT_DELETE_SUDO_TEMP_DIRECTORY_ON_EXIT" != "1" ]]; then
        # Remove SUDO_TEMP_DIRECTORY in case it wasn't already removed
        sudo_log_literal 3 "\nRemoving SUDO_TEMP_DIRECTORY in case it wasn't already removed"
        sudo_unset_pre_su_variables
        su_output=$($SU_ENV_COMMAND "rm -rf '${SUDO_TEMP_DIRECTORY//\'/\'\\\'\'}'" 2>&1 < /dev/null)
        return_value=$?
        sudo_set_post_su_variables
        { [ $return_value -ne 0 ] && [ -n "$su_output" ]; } && sudo_log_errors "$su_output"
        SUDO_TEMP_DIRECTORY=""
    fi

}

sudo_close_command_fds() {

    if [ -n "${SUDO_PATH_FD:-}" ]; then
        exec {SUDO_PATH_FD}<&-
        SUDO_PATH_FD=""
    fi

    if [ -n "${SUDO_SCRIPT_FD:-}" ]; then
        exec {SUDO_SCRIPT_FD}<&-
        SUDO_SCRIPT_FD=""
    fi

    if [ -n "${TEMP_FILE_FD:-}" ]; then
        exec {TEMP_FILE_FD}<&-
        TEMP_FILE_FD=""
    fi

}

sudo_create_script_command_traps() {

    local return_value

    sudo_log_literal 3 "\nRunning sudo_create_script_command_traps"

    # The sudo_script__trap will do the following:
    # Store the original trap signal in $sudo_script__exit_code.
    # Call the sudo_script__custom_trap function.
    # If it exits with 0, then continue normally.
    # If it exits with 125 'ECANCELED', then do not continue and just return
    # If it exits with any other exit code, store it so that we exit
    # with that instead of the original trap signal.
    # Remove the EXIT trap so its not called again.
    # Remove temp_directory if set.
    # If a signal argument was passed, then remove its trap.
    # Send the original trap signal to all the children of the pid
    # and exit with the original trap signal exit code or that of the
    # sudo_script__custom_trap function so that parent processes can be
    # notified if necessary.

    SUDO_SCRIPT_COMMAND_TRAPS=""

    # If SUDO_TEMP_DIRECTORY is a valid absolute path and DO_NOT_DELETE_SUDO_TEMP_DIRECTORY_ON_EXIT is not enabled
    if [[ "$SUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]] && [[ "$DO_NOT_DELETE_SUDO_TEMP_DIRECTORY_ON_EXIT" != "1" ]]; then
        # Append the function to SUDO_SCRIPT_COMMAND_TRAPS to remove SUDO_TEMP_DIRECTORY
        # This may specially be necessary if '-E' is passed
        SUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION="sudo_script__remove_temp_directory"

        SUDO_SCRIPT_COMMAND_TRAPS+='
export SUDO_SCRIPT__TEMP_DIR='"'${SUDO_TEMP_DIRECTORY//\'/\'\\\'\'}'"'

'"$SUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION"'() {
    rm -rf '"'${SUDO_TEMP_DIRECTORY//\'/\'\\\'\'}'"'
}
'
    else
        SUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION=""
    fi

    # FIXME: Use alternate for `pgrep` as it will not be available on
    # Android `< 6` if PATH is set to `/system/bin`. Termux does
    # provide it with `procps` package under `$TERMUX_PREFIX/bin`.
    # shellcheck disable=SC2016
    local sudo_script__killtree_command='sudo_script__killtree "${1:-}" $$'
    # If on Android `< 6`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 23 ]; then
        sudo_script__killtree_command='command -v "pgrep" 1>/dev/null 2>&1 && '"$sudo_script__killtree_command"
    fi

    # shellcheck disable=SC2016
    SUDO_SCRIPT_COMMAND_TRAPS+='
sudo_script__custom_trap() { :; }

sudo_script__killtree() {
    local signal="$1"; local pid="$2"; local cpid
    for cpid in $(pgrep -P "$pid"); do sudo_script__killtree "$signal" "$cpid"; done
    [ "$pid" != "$$" ] && kill "-${signal:-15}" "$pid" 2>/dev/null
}

sudo_script__trap() {
    local sudo_script__exit_code=$?
    local return_value=0; sudo_script__custom_trap "$@" || return_value=$?
    [ $return_value -eq 125 ] && return 0
    [ $return_value -ne 0 ] && sudo_script__exit_code=$return_value
    trap - EXIT '"${SUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION:+$'\n'    $SUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION}"'
    [ -n "${1:-}" ] && trap - "$1"
    '"$sudo_script__killtree_command"'; exit $sudo_script__exit_code
}
'"
trap 'sudo_script__trap' EXIT
trap 'sudo_script__trap TERM' TERM
trap 'sudo_script__trap INT' INT
trap 'sudo_script__trap HUP' HUP
trap 'sudo_script__trap QUIT' QUIT
"
    return 0

}

##
# Check https://github.com/agnostic-apollo/sudo/blob/master/site/pages/en/projects/docs/developer/guides/su-sub-process-communication/index.md
# for more info on why `fd` with process substitution is used.
##
sudo_su_sub_process__receive_comm__start() {

    local return_value

    sudo_log 4 "Starting su sub processs receive communication"

    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD=""
    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH=""
    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID=""
    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID=""

    # Export for `su --preserve-environment` process.
    export SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH

    # Find an unused fd that can be used for communication with a `su` sub process,
    # in case stdout cannot be used due to logging and possibly other output to stdout.
    # Store the fd to close it when `sudo_su_sub_process__receive_comm__cleanup()`
    # is called, either after receive data has been read, or in `sudo_trap`
    # in case `sudo` exits early due to errors or kill signals.
    sudo_get_unsed_file_descriptor_and_path SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD \
        SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH "for su sub processs receive communication" || return $?

    sudo_log 4 "SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH='$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH'"

    # Start a process with process substitution and attach its stdout to `SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD`.
    eval "exec $SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD<" <(
        sudo_su_subprocess_trap() {
            local sudo_exit_code=$?
            trap - EXIT

            sudo_log 5 echo sudo_su_subprocess_trap 1>&2
            if [ -n "${SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID:-}" ]; then
                sudo_log 4 "Killing su sub processs receive communication relay process background process with pid $SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID" 1>&2
                kill "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID"
                SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID=""
            fi

            [ -n "${1:-}" ] && trap - "$1"
            exit $sudo_exit_code

        }

        # Start a sleep process in background and wait on it to keep
        # the current process substitution process alive until it is
        # killed manually after `su` process ends and communication is
        # no longer required by calling `sudo_su_sub_process__receive_comm__stop()`.
        # Setup a trap to also kill the background sleep process when
        # current process substitution process is sent a kill signal.
        set_sudo_traps "sudo_su_subprocess_trap" || exit $?
        sleep infinity &
        # Store the pid of the background sleep process for wait and trap.
        SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID="$!"
        sudo_log 4 "SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID=$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID (ppid=$BASHPID)" 1>&2
        wait "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID"
    )
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while opening SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD '$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD' for su sub processs receive communication"
        return $return_value
    fi
    # Store the pid of the process substitution process to kill it later
    # when `sudo_su_sub_process__receive_comm__stop` is called.
    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID="$!"
    sudo_log 4 "SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID=$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID (ppid=$$)"

}

sudo_su_sub_process__receive_comm__stop() {

    local return_value

    local output

    if [ -n "${SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID:-}" ]; then
        # Kill the process substitution process.
        sudo_log 4 "Killing su sub processs receive communication relay process with pid $SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID"

        output="$(kill "$SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID" 2>&1)"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log 4 "$output" 1>&2
            sudo_log 4 "Failure while killing su sub processs receive communication relay process with pid $SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID" 1>&2
        fi
        SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__PID=""
    fi

    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__RELAY_PROCESS__BG_PID=""

}

sudo_su_sub_process__receive_comm__cleanup() {

    local return_value

    # If SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD is set, then close it.
    if [ -n "${SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD:-}" ]; then
        exec {SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD}<&-
        SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD=""
    fi

    SUDO_SU_SUB_PROCESS__RECEIVE_COMM__FD_PATH=""

}

##
# `sudo_run_file_type_tests_on_path` `<label>` `<path>` `<log_file_tests_failure_errors>` `<show_stat_output_on_file_tests_failure>` `<check_if_absolute_path>` `<file_type_tests>`
##
sudo_run_file_type_tests_on_path() {

    local return_value

    # If argument count is not 6
    if [ $# -ne 6 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_run_file_type_tests_on_path'"
        return 1
    fi

    local label="$1"
    local path="$2"
    local log_file_tests_failure_errors="$3"
    local show_stat_output_on_file_tests_failure="$4"
    local check_if_absolute_path="$5"
    local file_type_tests="$6"

    # If file_type_tests is invalid
    if [[ ! "$file_type_tests" =~ ^[bcdefgGkhLOprSsuwx]+$ ]]; then
        sudo_log_errors "file_type_tests '$file_type_tests' passed to 'sudo_run_file_type_tests_on_path' is not valid"
        return 1
    fi

    # If check_if_absolute_path is enabled and path is not a valid absolute path
    local valid_rootfs_or_absolute_path_regex='^((/)|((/[^/]+)+))$'
    if [[ "$check_if_absolute_path" == "1" ]] && [[ ! "$path" =~ $valid_rootfs_or_absolute_path_regex ]]; then
        sudo_log_errors "The '$label' file '$path' is not an absolute path"
        return 2
    fi

    local command=""

    for (( i=0; i<${#file_type_tests}; i++ )); do
        file_type_test="${file_type_tests:$i:1}"

        [[ -n "$command" ]] && command+=" && "
        command+="test -$file_type_test '${path//\'/\'\\\'\'}'" # Replace any single quotes `'` with `'\''` to maintain quoting and prevent arbitrary command execution with eval
    done

    # If command is empty
    if [[ -z "$command" ]]; then
        return 0
    fi

    # Run all tests
    # 0 means success, 1 means failure, other exit codes mean some other error
    eval "$command"
    return_value=$?
    if [ $return_value -eq 0 ]; then
        return 0
    fi

    if [ $return_value -ne 1 ] || \
        { [ $return_value -eq 1 ] && [[ "$log_file_tests_failure_errors" == "1" ]]; }; then
        local file_type_tests_label=""

        declare -A file_type_tests_labels=(
            ["b"]="[block special device]"
            ["c"]="[character special device]"
            ["d"]="[directory]"
            ["e"]="[exists]"
            ["f"]="[regular file]"
            ["g"]="[set-group-id bit set]"
            ["G"]="[owned by the current effective group id]"
            ["k"]="[sticky bit set]"
            ["h"]="[symbolic link]"
            ["L"]="[symbolic link]"
            ["O"]="[owned by the current effective user id]"
            ["p"]="[pipe]"
            ["r"]="[readable]"
            ["S"]="[socket]"
            ["s"]="[size greater than zero]"
            ["u"]="[set-user-id bit set]"
            ["w"]="[writable]"
            ["x"]="[executable]"
        )

        for (( i=0; i<${#file_type_tests}; i++ )); do
            file_type_test="${file_type_tests:$i:1}"

            [[ -n "$file_type_tests_label" ]] && file_type_tests_label+=", "
            file_type_tests_label+="${file_type_tests_labels[$file_type_test]}"
        done
    fi

    if [ $return_value -ne 1 ]; then
        sudo_log_errors "Failed to run the following test types on the file '$label' at path '$path': $file_type_tests_label"
    else
        if [[ "$log_file_tests_failure_errors" == "1" ]]; then
            sudo_log_errors "The '$label' file at path '$path' failed one or more of the following test types: $file_type_tests_label"
            if [[ "$show_stat_output_on_file_tests_failure" == "1" ]]; then
                current_user_id="$(id -u 2>/dev/null)"
                current_user_name="$(id -un 2>/dev/null)"
                stat_output="$(stat --format="file type: %F"$'\n'"access: %A (%a)"$'\n'"owner: %U (%u)"$'\n'"group: %G (%g)"$'\n'"selinux context: %C"$'\n'"size: %s" "$path" 2>/dev/null)"
                # If stat_output is not empty
                if [[ -n "$stat_output" ]]; then
                    sudo_log_errors "current user: $current_user_name ($current_user_id)"$'\n'"$stat_output"
                fi
            fi
        fi
    fi

    return $return_value

}

##
# `sudo_create_modify_validate_directory` `<directory_path_label>` `<directory_path>` `<check_if_absolute_path>` `<create_directory_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation>` `<directory_chown_command_options>` `<directory_chmod_command_options>` `<sub_directories_chown_command_options>` `<sub_directories_chmod_command_options>` `<sub_files_chown_command_options>` `<sub_files_chmod_command_options>` `<file_type_tests>`
##
sudo_create_modify_validate_directory() {

    local return_value

    # If argument count is not 12
    if [ $# -ne 12 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_create_modify_validate_directory'"
        return 1
    fi

    #sudo_log_literal 3 "\nRunning sudo_create_modify_validate_directory"

    local directory_path_label="$1"
    local directory_path="$2"
    local check_if_absolute_path="$3"
    local create_directory_if_it_does_not_exist="$4"
    local only_set_perms_and_ownership_on_creation="$5"
    local directory_chown_command_options="$6"
    local directory_chmod_command_options="$7"
    local sub_directories_chown_command_options="$8"
    local sub_directories_chmod_command_options="$9"
    local sub_files_chown_command_options="${10}"
    local sub_files_chmod_command_options="${11}"
    local file_type_tests="${12}"

    local directory_created=0

    # If create_directory_if_it_does_not_exist is not set to 0 or 1
    if [[ "$create_directory_if_it_does_not_exist" != "0" ]] && [[ "$create_directory_if_it_does_not_exist" != "1" ]]; then
        sudo_log_errors "create_directory_if_it_does_not_exist '$create_directory_if_it_does_not_exist' passed to 'sudo_create_modify_validate_directory' is not equal to '0' or '1'"
        return 1
    fi

    # If only_set_perms_and_ownership_on_creation is not set to 0 or 1
    if [[ "$only_set_perms_and_ownership_on_creation" != "0" ]] && [[ "$only_set_perms_and_ownership_on_creation" != "1" ]]; then
        sudo_log_errors "only_set_perms_and_ownership_on_creation '$only_set_perms_and_ownership_on_creation' passed to 'sudo_create_modify_validate_directory' is not equal to '0' or '1'"
        return 1
    fi

    # If check_if_absolute_path is enabled and directory_path is not a valid absolute path
    local valid_rootfs_or_absolute_path_regex='^((/)|((/[^/]+)+))$'
    if [[ "$check_if_absolute_path" == "1" ]] && [[ ! "$directory_path" =~ $valid_rootfs_or_absolute_path_regex ]]; then
        sudo_log_errors "The '$directory_path_label' directory '$directory_path' is not an absolute path"
        return 2
    fi

    # Check if a non-directory file exists at directory path
    if [ -e "$directory_path" ] && [ ! -d "$directory_path" ]; then
        sudo_log_errors "A non-directory file exists at $directory_path_label '$directory_path'"
        return 1
    fi

    # If directory does not exist
    if [ ! -d "$directory_path" ]; then
        # If create_directory_if_it_does_not_exist is enabled, then create directory
        if [[ "$create_directory_if_it_does_not_exist" == "1" ]]; then
            sudo_log 3 "Creating $directory_path_label directory at '$directory_path'"

            mkdir -p "$directory_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to create $directory_path_label directory at '$directory_path'"
                return $return_value
            fi

            if [ ! -d "$directory_path" ]; then
                sudo_log_errors "Failed to find $directory_path_label directory at '$directory_path' after creation"
                return 1
            fi

            directory_created=1
        else
            sudo_log_errors "Failed to find $directory_path_label directory at '$directory_path'"
            return 1
        fi
    else
        if [[ "$create_directory_if_it_does_not_exist" == "1" ]]; then
            sudo_log 3 "The $directory_path_label directory already exists at '$directory_path'"
        else
            sudo_log 3 "The $directory_path_label directory exists at '$directory_path'"
        fi
    fi

    # If only_set_perms_and_ownership_on_creation is enabled and directory was not created
    if  [[ "$only_set_perms_and_ownership_on_creation" == "1" ]] && [[ "$directory_created" == "0" ]]; then
        sudo_log 3 "Skipping setting ownership and permission for $directory_path_label directory since it was not created"
    else

        # Set directory ownership
        if [[ "$directory_chown_command_options" != "-" ]]; then
            local -a directory_chown_command_options_array=()
            sudo_set_shell_command_args_array directory_chown_command_options_array \
                "directory_chown_command_options" "$directory_chown_command_options" || return $?

            sudo_log 3 "Setting '${directory_chown_command_options_array[*]}' ownership to $directory_path_label directory at '$directory_path' directory"
            chown "${directory_chown_command_options_array[@]}" "$directory_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set ownership of $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set directory permissions
        if [[ "$directory_chmod_command_options" != "-" ]]; then
            local -a directory_chmod_command_options_array=()
            sudo_set_shell_command_args_array directory_chmod_command_options_array \
                "directory_chmod_command_options" "$directory_chmod_command_options" || return $?

            sudo_log 3 "Setting '${directory_chmod_command_options_array[*]}' permissions to $directory_path_label directory at '$directory_path' directory"
            chmod "${directory_chmod_command_options_array[@]}" "$directory_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set permissions of $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subdirectories ownership
        if [[ "$sub_directories_chown_command_options" != "-" ]]; then
            local -a sub_directories_chown_command_options_array=()
            sudo_set_shell_command_args_array sub_directories_chown_command_options_array \
                "sub_directories_chown_command_options" "$sub_directories_chown_command_options" || return $?

            sudo_log 3 "Setting '${sub_directories_chown_command_options_array[*]}' ownership to $directory_path_label directory at '$directory_path' subdirectories"
            (sudo_trim_env_for_xargs && find "$directory_path" -type d -print0 | xargs -0 -r -- chown "${sub_directories_chown_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set ownership of subdirectories in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subdirectories permissions
        if [[ "$sub_directories_chmod_command_options" != "-" ]]; then
            local -a sub_directories_chmod_command_options_array=()
            sudo_set_shell_command_args_array sub_directories_chmod_command_options_array \
                "sub_directories_chmod_command_options" "$sub_directories_chmod_command_options" || return $?

            sudo_log 3 "Setting '${sub_directories_chmod_command_options_array[*]}' permissions to $directory_path_label directory at '$directory_path' subdirectories"
            (sudo_trim_env_for_xargs && find "$directory_path" -type d -print0 | xargs -0 -r -- chmod "${sub_directories_chmod_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set permissions of subdirectories in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subfiles ownership
        if [[ "$sub_files_chown_command_options" != "-" ]]; then
            local -a sub_files_chown_command_options_array=()
            sudo_set_shell_command_args_array sub_files_chown_command_options_array \
                "sub_files_chown_command_options" "$sub_files_chown_command_options" || return $?

            sudo_log 3 "Setting '${sub_files_chown_command_options_array[*]}' ownership to $directory_path_label directory at '$directory_path' subfiles"
            (sudo_trim_env_for_xargs && find "$directory_path" -type f -print0 | xargs -0 -r -- chown "${sub_files_chown_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set ownership of subfiles in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subfiles permissions
        if [[ "$sub_files_chmod_command_options" != "-" ]]; then
            local -a sub_files_chmod_command_options_array=()
            sudo_set_shell_command_args_array sub_files_chmod_command_options_array \
                "sub_files_chmod_command_options" "$sub_files_chmod_command_options" || return $?

            sudo_log 3 "Setting '${sub_files_chmod_command_options_array[*]}' permissions to $directory_path_label directory at '$directory_path' subfiles"
            (sudo_trim_env_for_xargs && find "$directory_path" -type f -print0 | xargs -0 -r -- chmod "${sub_files_chmod_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set permissions of subfiles in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi
    fi


    # Run file type tests with test command
    if [[ "$file_type_tests" != "-" ]]; then
        # sudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
        sudo_run_file_type_tests_on_path "$directory_path_label" "$directory_path" 1 1 0 "$file_type_tests" || return $?
    fi


    return 0

}

##
# `sudo_create_modify_validate_file` `<file_path_label>` `<file_path>` `<check_if_absolute_path>` `<create_file_if_it_does_not_exist>` `<file_creation_command_options>` `<file_content>` `<only_set_perms_and_ownership_on_creation>` `<file_chown_command_options>` `<file_chmod_command_options>` `<file_type_tests>`
##
sudo_create_modify_validate_file() {

    local return_value

    # If argument count is not 10
    if [ $# -ne 10 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_create_modify_validate_file'"
        return 1
    fi

    #sudo_log_literal 3 "\nRunning sudo_create_modify_validate_file"

    local file_path_label="$1"
    local file_path="$2"
    local check_if_absolute_path="$3"
    local create_file_if_it_does_not_exist="$4"
    local file_creation_command_options="$5"
    local file_content="$6"
    local only_set_perms_and_ownership_on_creation="$7"
    local file_chown_command_options="$8"
    local file_chmod_command_options="$9"
    local file_type_tests="${10}"

    local file_created=0

    # If create_file_if_it_does_not_exist is not set to 0 or 1
    if [[ "$create_file_if_it_does_not_exist" != "0" ]] && [[ "$create_file_if_it_does_not_exist" != "1" ]]; then
        sudo_log_errors "create_file_if_it_does_not_exist '$create_file_if_it_does_not_exist' passed to 'sudo_create_modify_validate_file' is not equal to '0' or '1'"
        return 1
    fi

    # If only_set_perms_and_ownership_on_creation is not set to 0 or 1
    if [[ "$only_set_perms_and_ownership_on_creation" != "0" ]] && [[ "$only_set_perms_and_ownership_on_creation" != "1" ]]; then
        sudo_log_errors "only_set_perms_and_ownership_on_creation '$only_set_perms_and_ownership_on_creation' passed to 'sudo_create_modify_validate_file' is not equal to '0' or '1'"
        return 1
    fi

    # If check_if_absolute_path is enabled and file_path is not a valid absolute path
    local valid_absolute_path_regex='^(/[^/]+)+$'
    if [[ "$check_if_absolute_path" == "1" ]] && [[ ! "$file_path" =~ $valid_absolute_path_regex ]]; then
        sudo_log_errors "The '$file_path_label' file '$file_path' is not an absolute path"
        return 2
    fi

    # Check if a non-file file exists at file path
    if [ -e "$file_path" ] && [ ! -f "$file_path" ]; then
        sudo_log_errors "A non-regular file exists at $file_path_label '$file_path'"
        return 1
    fi

    # If file does not exist
    if [ ! -f "$file_path" ]; then
        # If create_file_if_it_does_not_exist is enabled, then create file
        if [[ "$create_file_if_it_does_not_exist" == "1" ]]; then
            sudo_log 3 "Creating $file_path_label '$file_path' file"

            local -a file_creation_command_options_array
            if [[ "$file_creation_command_options" != "-" ]]; then
                local -a file_creation_command_options_array=()
                sudo_set_shell_command_args_array file_creation_command_options_array \
                    "file_creation_command_options" "$file_creation_command_options" || return $?
            fi

            # If file_creation_options is set, then pass it to printf
            if [ ${#file_creation_command_options_array[@]} -ne 0 ]; then
                printf "${file_creation_command_options_array[@]}" "$file_content" > "$file_path"
            else
                printf "$file_content" > "$file_path"
            fi
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to create $file_path_label file at '$file_path'"
                return $return_value
            fi

            if [ ! -f "$file_path" ]; then
                sudo_log_errors "Failed to find $file_path_label file at '$file_path' after creation"
                return 1
            fi

            file_created=1
        else
            sudo_log_errors "Failed to find $file_path_label file at '$file_path'"
            return 1
        fi
    else
        if [[ "$create_file_if_it_does_not_exist" == "1" ]]; then
            sudo_log 3 "The $file_path_label file already exists at '$file_path'"
        else
            sudo_log 3 "The $file_path_label file exists at '$file_path'"
        fi
    fi

    # If only_set_perms_and_ownership_on_creation is enabled and file was not created
    if  [[ "$only_set_perms_and_ownership_on_creation" == "1" ]] && [[ "$file_created" == "0" ]]; then
        sudo_log 3 "Skipping setting ownership and permission for $file_path_label file since it was not created"
    else
        # Set file ownership
        if [[ "$file_chown_command_options" != "-" ]]; then
            local -a file_chown_command_options_array=()
            sudo_set_shell_command_args_array file_chown_command_options_array \
                "file_chown_command_options" "$file_chown_command_options" || return $?

            sudo_log 3 "Setting '${file_chown_command_options_array[*]}' ownership to $file_path_label '$file_path' file"
            chown "${file_chown_command_options_array[@]}" "$file_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set ownership of $file_path_label file at '$file_path'"
                return $return_value
            fi
        fi

        # Set file permissions
        if [[ "$file_chmod_command_options" != "-" ]]; then
            local -a file_chown_command_options_array=()
            sudo_set_shell_command_args_array file_chmod_command_options_array \
                "file_chmod_command_options" "$file_chmod_command_options" || return $?

            sudo_log 3 "Setting '${file_chmod_command_options_array[*]}' permissions to $file_path_label '$file_path' file"
            chmod "${file_chmod_command_options_array[@]}" "$file_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                sudo_log_errors "Failed to set permissions of $file_path_label file at '$file_path'"
                return $return_value
            fi
        fi
    fi


    # Run file type tests with test command
    if [[ "$file_type_tests" != "-" ]]; then
        # sudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
        sudo_run_file_type_tests_on_path "$file_path_label" "$file_path" 1 1 0 "$file_type_tests" || return $?
    fi


    return 0

}

##
# `sudo_expand_termux_path` `<variable_name>` `<label>` `<path>` `<termux_prefix>` `<termux_home>` `<canonicalize_path>`
##
sudo_expand_termux_path() {

    local return_value

    # If argument count is not 6
    if [ $# -ne 6 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_expand_termux_path'"
        return 1
    fi

    local variable_name="$1"
    local label="$2"
    local path_to_expand="$3"
    local termux_prefix="$4"
    local termux_home="$5"
    local canonicalize_path="$6"

    local absolute_path_to_expand
    local valid_absolute_path_regex='^(/[^/]+)+$'

    [[ "$path_to_expand" == "\$PREFIX/" ]] && path_to_expand="$termux_prefix" # Replace '$PREFIX/' with "$termux_prefix"
    [[ "$path_to_expand" == "~/" ]] && path_to_expand="$termux_home" # Replace '~/' with "$termux_home"

    path_to_expand="${path_to_expand/#\$PREFIX\//$termux_prefix\/}" # Replace '$PREFIX/*' with "$termux_prefix/*"
    path_to_expand="${path_to_expand/#~\//$termux_home\/}" # Replace '~/*' with "$termux_home/*"

    # If canonicalize_path equals "1" or (canonicalize_path equals "2" and path_to_expand is not a symlink
    if [[ "$canonicalize_path" == "1" ]] || { [[ "$canonicalize_path" == "2" ]] && [ ! -L "$path_to_expand" ]; }; then
        absolute_path_to_expand="$path_to_expand"
        path_to_expand="$(readlink -m -- "$path_to_expand")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$path_to_expand" =~ $valid_absolute_path_regex ]]; then
            sudo_log_errors "Failure while finding canonical path for path_to_expand '$absolute_path_to_expand'"
            sudo_log_errors "canonical_path_to_expand = '$path_to_expand'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    elif [[ "$canonicalize_path" == "3" ]]; then
        # If path is relative to current working directory starting with `./` or `../`
        if [[ "${path_to_expand:0:2}" == "./" ]] || [[ "${path_to_expand:0:3}" == "../" ]]; then
            # Prepend current working directory
            if [[ "$CURRENT_WORKING_DIR" != "/" ]]; then
                path_to_expand="$CURRENT_WORKING_DIR/$path_to_expand"
            else
                path_to_expand="/$path_to_expand"
            fi
        fi

        # Replace duplicate path separators `//` with single `/`
        path_to_expand="${path_to_expand//\/\///}"
    fi

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If variable_name does not equal "path_to_expand" and is valid bash variable_name
    if [[ "$variable_name" != "path_to_expand" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name to path_to_expand
        printf -v "$variable_name" "%s" "$path_to_expand"
    else
        sudo_log_errors "variable_name '$1' passed to 'sudo_expand_termux_path' equals 'path_to_expand' or is not a valid bash variable name"
        return 1
    fi

}

##
# - The path will be first expanded by `sudo_expand_termux_path`. If the path is relative to current directory starting with `./` or `../`,
#   then it is prefixed with CURRENT_WORKING_DIR due to passing `canonicalize_path=3`.
# - If an absolute path is returned by `sudo_expand_termux_path`, then it checked to see if it is for an executable file,
#   otherwise executable is searched in all the paths in `paths_to_check_for_executable` list (ideally `$PATH` variable).
# - If an executable is found, then that is returned, otherwise function fails with 112.
#
# `sudo_find_absolute_path_for_executable_and_validate` `<variable_name>` `<label>` `<path>` `<paths_to_check_for_executable>` `<termux_prefix>` `<termux_home>` `<output_path_to_stdout>`
##
sudo_find_absolute_path_for_executable_and_validate() {

    local return_value

    # If argument count is not 7
    if [ $# -ne 7 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_find_absolute_path_for_executable_and_validate'"
        return 1
    fi

    local variable_name="$1"
    local label="$2"
    local path="$3"
    local paths_to_check_for_executable="$4"
    local termux_prefix="$5"
    local termux_home="$6"
    local output_path_to_stdout="$7"

    local executable_found=0
    local absolute_path
    local expanded_path
    local valid_absolute_path_regex='^(/[^/]+)+$'

    # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in path
    sudo_expand_termux_path "expanded_path" "${label}_PATH" "$path" "$termux_prefix" "$termux_home" 3
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to expand ${label}_PATH '$path'"
        return $return_value
    fi

    [[ "$output_path_to_stdout" == "1" ]] || sudo_log 3 "${label}_EXPANDED_PATH='$expanded_path'"

    if [[ "$expanded_path" =~ $valid_absolute_path_regex ]]; then
        absolute_path="$expanded_path"
        test -f "$absolute_path" && test -r "$absolute_path" && test -x "$absolute_path"
        return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
            sudo_log_errors "Failed to run the following test types on the file '${label}_PATH' at path '$absolute_path': [regular file], [readable], [executable]"
            return $return_value
        elif [ $return_value -eq 0 ]; then
            [[ "$output_path_to_stdout" == "1" ]] || sudo_log 3 "Executable found at '$absolute_path'"
            executable_found=1
        fi
    fi

    # If executable still not found and original path was just a basename, then check if path exists in PATH_TO_EXPORT
    local valid_absolute_path_regex='^(/[^/]+)+$'
    if [[ "$executable_found" == "0" ]] && [[ "$path" != *'/'* ]]; then
        # Check if paths_to_check_for_executable is valid
        local invalid_value_for_path_variable_regex='^:|:$|.*::.*|.*'$'\n''.*'
        if [[ "$paths_to_check_for_executable" =~ $invalid_value_for_path_variable_regex ]]; then
            sudo_log_errors "PATHS_TO_CHECK_FOR_EXECUTABLE '$paths_to_check_for_executable' is invalid, it cannot start or end with a colon, contain two consecutive colons ':' or contain newline characters"
            return 1
        fi

        [[ "$output_path_to_stdout" == "1" ]] || sudo_log 3 "Checking for '$path' executable at following paths: '$paths_to_check_for_executable'"

        # Check if path is a binary or any executable in paths_to_check_for_executable
        for path_to_check_for_executable in ${paths_to_check_for_executable//:/ }; do
            absolute_path="$path_to_check_for_executable/$path"
            [[ "$output_path_to_stdout" == "1" ]] || sudo_log 3 "'$absolute_path'"

            test -f "$absolute_path" && test -r "$absolute_path" && test -x "$absolute_path"
            return_value=$?
            if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
                sudo_log_errors "Failed to run the following test types on the file '${label}_PATH' at path '$absolute_path': [regular file], [readable], [executable]"
                return $return_value
            elif [ $return_value -eq 0 ]; then
                [[ "$output_path_to_stdout" == "1" ]] || sudo_log 3 "Executable found at '$absolute_path'"
                executable_found=1
                break
            fi
        done
    fi

    # If executable is not found, then exit with error, since this is the final path
    if [[ "$executable_found" != "1" ]]; then
        return 112
    fi

    # If output_path_to_stdout is enabled, then create file
    if [[ "$output_path_to_stdout" == "1" ]]; then
        # Echo absolute_path to stdout
        echo "$absolute_path"
    else
        local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

        # If variable_name does not equal "absolute_path" and is valid bash variable_name
        if [[ "$variable_name" != "absolute_path" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
            # Set variable_name to absolute_path
            printf -v "$variable_name" "%s" "$absolute_path"
        else
            sudo_log_errors "variable_name '$1' passed to 'sudo_find_absolute_path_for_executable_and_validate' equals 'absolute_path' or is not a valid bash variable name"
            return 1
        fi
    fi

}

##
# Validate if path is under TERMUX_ROOTFS and is not backlisted.
#
# `sudo_validate_path_is_a_whitelisted_path_under_termux_rootfs` `<label>` `<path>`
##
sudo_validate_path_is_a_whitelisted_path_under_termux_rootfs() {

    local return_value

    # If argument count is not 2
    if [ $# -ne 2 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_validate_path_is_a_whitelisted_path_under_termux_rootfs'"
        return 1
    fi

    local label="$1"
    local path="$2"

    local termux_rootfs_escaped
    local termux_home_escaped
    local termux_prefix_escaped

    # Android app package names can only contain `[a-zA-Z0-9_]` characters
    # with a dot `.` between segments and each segment must start with
    # an alphabet. (`^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$`).
    # So only a dot `.` character in termux paths would need to be escaped in a regex.
    # - https://developer.android.com/build/configure-app-module#set-application-id
    # - https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:frameworks/base/core/java/android/content/pm/parsing/ApkLiteParseUtils.java;l=671-676
    # - https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:frameworks/base/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java;l=63

    termux_rootfs_escaped="${TERMUX_ROOTFS//./\\.}" # Replace `.` with `\.`
    termux_rootfs_escaped="${termux_rootfs_escaped////[\\\/]+}" # Replace `/` with `[\/]+`

    termux_home_escaped="${TERMUX_HOME//./\\.}" # Replace `.` with `\.`
    termux_home_escaped="${termux_home_escaped////[\\\/]+}" # Replace `/` with `[\/]+`

    termux_prefix_escaped="${TERMUX_PREFIX//./\\.}" # Replace `.` with `\.`
    termux_prefix_escaped="${termux_prefix_escaped////[\\\/]+}" # Replace `/` with `[\/]+`

    local valid_path_under_termux_rootfs_regex='^'"$termux_rootfs_escaped"'[\/]+.+'
    local blacklisted_path_in_termux_rootfs_regex='^(('"$termux_home_escaped"'[\/]+\.(cache|config|local|termux))|('"$termux_prefix_escaped"')|('"$termux_prefix_escaped"'[\/]+.*))([\/]+)?$'

    # If path same as TERMUX_ROOTFS
    if [[ "$path" == "$TERMUX_ROOTFS" ]]; then
        sudo_log 3 "$label '$path' is the same as TERMUX_ROOTFS"
        return 2
    # If path is set to an absolute path under TERMUX_ROOTFS
    elif [[ "$path" =~ $valid_path_under_termux_rootfs_regex ]]; then
        # If path is set to a blacklist path under TERMUX_ROOTFS
        if [[ "$path" =~ $blacklisted_path_in_termux_rootfs_regex ]]; then
            sudo_log 3 "$label '$path' matches one of following blacklisted paths:"
            sudo_log 3 "'$TERMUX_HOME/.{cache,config,local,termux}', '$TERMUX_PREFIX/*'"
            return 2
        else
            return 0
        fi
    else
        return 3
    fi

}

##
# `sudo_parse_and_validate_path_variable` `<variable_name>` `<label>` `<path>` `<remove_duplicates>`
##
sudo_parse_and_validate_path_variable() {

    local return_value

    # If argument count is not 4
    if [ $# -ne 4 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_parse_and_validate_path_variable'"
        return 1
    fi

    local variable_name="$1"
    local label="$2"
    local path_to_parse="$3"
    local remove_duplicates="$4"

    # If remove_duplicates is enabled
    if [[ "$remove_duplicates" == "1" ]]; then
        # Remove duplicates from path_to_parse
        path_to_parse="$(printf "%s" "$path_to_parse" | awk -v RS=: -v ORS= '!a[$0]++ {if (NR>1) printf(":"); printf("%s", $0) }' )"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            sudo_log_errors "Failed to remove duplicates from $label '$path_to_parse'"
            return $return_value
        fi
    fi

    # Check if path_to_parse is valid
    local invalid_value_for_path_variable_regex='^:|:$|.*::.*|.*'$'\n''.*'
    if [[ "$path_to_parse" =~ $invalid_value_for_path_variable_regex ]]; then
        sudo_log_errors "$label '$path_to_parse' is invalid, it cannot start or end with a colon, contain two consecutive colons ':' or contain newline characters"
        return 1
    fi

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If variable_name does not equal "path_to_parse" and is valid bash variable_name
    if [[ "$variable_name" != "path_to_parse" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name to path
        printf -v "$variable_name" "%s" "$path_to_parse"
    else
        sudo_log_errors "variable_name '$1' passed to 'sudo_parse_and_validate_path_variable' equals 'path_to_parse' or is not a valid bash variable name"
        return 1
    fi

}

##
# Remount partitions for sudo shell home.
#
# `remount_mode` must be `ro` or `rw`.
#
# `sudo_remount_partitions_for_sudo_shell_homes` `<remount_mode>`
##
sudo_remount_partitions_for_sudo_shell_homes() {

    local return_value

    # If SUDO_DRY_RUN is enabled, then just return
    if [[ "$SUDO_DRY_RUN" == "1" ]]; then
        return 0
    fi

    # If remount_mode equals "ro" and DO_NOT_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO is enabled, then just return
    if [[ "$remount_mode" == "ro" ]] && [[ "$DO_NOT_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO" == "1" ]]; then
        return 0
    fi

    sudo_log_literal 3 "\nRunning sudo_remount_partitions_for_sudo_shell_homes"

    # If argument count is not 1
    if [ $# -ne 1 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_remount_partitions_for_sudo_shell_homes'"
        return 1
    fi

    local remount_mode="$1"
    if [[ "$remount_mode" != "ro" ]] && [[ "$remount_mode" != "rw" ]]; then
        sudo_log_errors "remount_mode '$remount_mode' passed to 'sudo_remount_partitions_for_sudo_shell_homes' does not equal 'ro' or 'rw'"
        return 1
    fi

    # If ROOTFS_PARTITION_RW_DEPENDENT_PATHS is set
    if [ -n "$ROOTFS_PARTITION_RW_DEPENDENT_PATHS" ]; then
        # If remount_mode equals "rw"
        if [[ "$remount_mode" == "rw" ]]; then
            # Remount android rootfs partition as rw
            sudo_log 3 "Remounting rootfs '/' partition as rw to be used for$ROOTFS_PARTITION_RW_DEPENDENT_PATHS"
            sudo_remount_partition "rootfs" "rw" 0
            return_value=$?
            if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
                sudo_log_errors "Failed to mount rootfs '/' partition as rw to be used for$ROOTFS_PARTITION_RW_DEPENDENT_PATHS"
                return $return_value
            fi

            rootfs_partition_remounted=1
        # If remount_mode equals "ro"
        elif [[ "$remount_mode" == "ro" ]]; then
            # If rootfs_partition_remounted is enabled
            if [[ "$rootfs_partition_remounted" == "1" ]]; then
                # Mount rootfs partition back as as ro
                # If rootfs partition was not mounted as ro before running sudo command it will not be remounted to ro
                # unless FORCE_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO is enabled
                sudo_remount_partition "rootfs" "ro" "$FORCE_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO"
                rootfs_partition_remounted=0
            fi
        fi
    fi


    # If SYSTEM_PARTITION_RW_DEPENDENT_PATHS is set
    if [ -n "$SYSTEM_PARTITION_RW_DEPENDENT_PATHS" ]; then
        # If remount_mode equals "rw"
        if [[ "$remount_mode" == "rw" ]]; then
            # Remount android system partition as rw
            sudo_log 3 "Remounting system '/system' partition as rw to be used for$SYSTEM_PARTITION_RW_DEPENDENT_PATHS"
            sudo_remount_partition "system" "rw" 0
            return_value=$?
            if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
                sudo_log_errors "Failed to mount system '/system' partition as rw to be used for$SYSTEM_PARTITION_RW_DEPENDENT_PATHS"
                return $return_value
            fi

            system_partition_remounted=1
        # If remount_mode equals "ro"
        elif [[ "$remount_mode" == "ro" ]]; then
            # If system_partition_remounted is enabled
            if [[ "$system_partition_remounted" == "1" ]]; then
                # Mount system partition back as as ro
                # If system partition was not mounted as ro before running sudo command it will not be remounted to ro
                # unless FORCE_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO is enabled
                sudo_remount_partition "system" "ro" "$FORCE_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO"
                system_partition_remounted=0
            fi
        fi
    fi

    return 0

}


##
# `sudo_get_unsed_file_descriptor_and_path` `<fd_output_variable_name>` \
#     `<fd_path_output_variable_name>` `<label>`
##
sudo_get_unsed_file_descriptor_and_path() {

    local return_value

    local fd_output_variable_name="${1:-}"
    local fd_path_output_variable_name="${2:-}"
    local label="${3:-}"

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If `fd_path_output_variable_name` does not equal "__fd" and is valid bash variable_name.
    if [[ ! "$fd_path_output_variable_name" =~ $valid_bash_variable_name_regex ]]; then
        sudo_log_errors "The fd_output_variable_name '$1' passed to 'sudo_get_unsed_file_descriptor_and_path' is not a valid bash variable name"
        return 1
    fi

    return_value=0
    sudo_get_unsed_file_descriptor "$fd_output_variable_name" || return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failure while getting an unused file descriptor for $label"
        return $return_value
    fi

    local __fd="${!fd_output_variable_name}" || return $?

    if [[ ! "$__fd" =~ ^[0-9]+$ ]]; then
        sudo_log_errors "The unused file descriptor${label:+" ${label:-}"} is not a valid number"
        sudo_log_errors "$fd_output_variable_name='$__fd'"
        return 1
    fi

    # Android fd directory is `/proc/self/fd`.
    # Use `$BASHPID` instead of self so that `su` process can access it.
    # Do not use `$$` as it may be invalid if running in a sub shell.
    printf -v "$fd_path_output_variable_name" "%s" "/proc/$BASHPID/fd/$__fd"

}

##
# `sudo_get_unsed_file_descriptor` `<fd_output_variable_name>`
##
sudo_get_unsed_file_descriptor() {

    local return_value

    local fd_output_variable_name="${1:-}"

    local __fd=2

    # ulimit -n returns per-process max file descriptors that can be opened,
    # but not using it to reduce external call.
    # Instead using the default 256 set by most systems for compatibility.
    # Real limit is likely to be higher like 1024, depending on android kernel version.
    # local max=$(ulimit -n || echo 256)
    local max=256

    # Iterate over all fds and find one for which dupe fails and use that.
    while ((++__fd < max)); do
       ! true <&"$__fd" && break
    done 2>/dev/null
    return_value=$?
    if [ $return_value -ne 0 ]; then
        sudo_log_errors "Failed to find an unused descriptor between 2-$max. last __fd: '$__fd'"
        return $return_value
    fi

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If `fd_output_variable_name` does not equal "__fd" and is valid bash variable_name.
    if [[ "$fd_output_variable_name" != "__fd" ]] && [[ "$fd_output_variable_name" =~ $valid_bash_variable_name_regex ]]; then
        printf -v "$fd_output_variable_name" "%s" "$__fd"
    else
        sudo_log_errors "The fd_output_variable_name '$1' passed to 'sudo_get_unsed_file_descriptor' equals '__fd' or is not a valid bash variable name"
        return 1
    fi

}

##
# Remount partitions for sudo shell home.
#
# `remount_partition` must be `rootfs` or `system`.
# `remount_mode` must be `ro` or `rw`.
# `force_remount` must be `0` or `1`.
#
# `sudo_remount_partition` `<remount_partition>` `<remount_mode>` `<force_remount>`
##
sudo_remount_partition() {

    local return_value

    # If argument count is not 3
    if [ $# -ne 3 ]; then
        sudo_log_errors "Invalid argument count to 'remount_android_rootfs_for_cldia'"
        return 1
    fi

    local remount_partition="$1"
    if [[ "$remount_partition" != "rootfs" ]] && [[ "$remount_partition" != "system" ]]; then
        sudo_log_errors "remount_partition '$remount_partition' passed to 'sudo_remount_partition' does not equal 'rootfs' or 'system'"
        return 1
    fi

    local remount_mode="$2"
    if [[ "$remount_mode" != "ro" ]] && [[ "$remount_mode" != "rw" ]]; then
        sudo_log_errors "remount_mode '$remount_mode' passed to 'sudo_remount_partition' does not equal 'ro' or 'rw'"
        return 1
    fi

    local force_remount="$3"
    if [[ "$force_remount" != "0" ]] && [[ "$force_remount" != "1" ]]; then
        sudo_log_errors "remount_mode '$remount_mode' passed to 'sudo_remount_partition' does not equal '0' or '1'"
        return 1
    fi

    local remount_partition_mount_point
    local current_mount_mode_command_output
    local current_mount_mode
    local remount_partition_previous_state_ro
    local remount_partition_previous_state_ro_variable_name
    local mountBinaryPath
    local remount_command_output

    # Search for mount executable
    for f in "$SYS_XBIN" "$SYS_BIN"; do
        test -x "$f/mount"
        return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
            sudo_log_errors "test command for '$f/mount' failed"
            return $return_value
        fi

        # If mount executable exists at "$f/mount"
        if [ $return_value -eq 0 ]; then
            mountBinaryPath="$f/mount"
            break
        fi
    done

    # If mount executable not found
    if [ -z "$mountBinaryPath" ]; then
        sudo_log_errors "\nCannot find mount executable"
        return 1
    fi

    # If remount_partition equals "rootfs"
    if [[ "$remount_partition" == "rootfs" ]]; then
        remount_partition_mount_point="/"
    # If remount_partition equals "system"
    elif [[ "$remount_partition" == "system" ]]; then
        remount_partition_mount_point="/system"
    else
        sudo_log_errors "remount_partition '$remount_partition' not handled"
        return 1
    fi

    # Find entry of the mount point in /proc/mounts
    # There is an additional "^[^ ]+ " before the path so that only mount points are matched and not the mount sources
    # There is an additional " " after the path so that grep does not match mounts on subdirectories of the mount point
    # or any enteries in the same directory as the mount point with the same basename but with one or more characters at the end
    remount_partition_mount_entry="$(grep -m 1 -E "^[^ ]+ $remount_partition_mount_point " /proc/mounts)"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
        sudo_log_errors "$remount_partition_mount_entry"
        sudo_log_errors "Failed to run grep to get remount_partition_mount_entry from /proc/mounts"
        return $return_value
    fi
    sudo_log 3 "remount_partition_mount_entry='$remount_partition_mount_entry'"

    # If remount_partition_mount_entry is empty, then mount_point is not mounted
    if [[ -z "$remount_partition_mount_entry" ]]; then
        sudo_log 3 "No mount entries found for '$remount_partition_mount_point' in /proc/mounts"
        sudo_log 3 "'$remount_partition_mount_point' is not mounted"
        return 112
    fi

    # Check if remount_partition_mount_point is currently mounted as the same mount_mode as remount_mode or not
    current_mount_mode_command_output="$(echo "$remount_partition_mount_entry" | grep -E "^[^ ]+ $remount_partition_mount_point [^ ]+ ro,")"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
        sudo_log_errors "$current_mount_mode_command_output"
        sudo_log_errors "Failed to find if $remount_partition_mount_point is mounted as $remount_mode"
        return $return_value
    # If current_mount_mode equals "ro"
    elif [ $return_value -eq 0 ]; then
        current_mount_mode="ro"
    # If current_mount_mode equals "rw"
    else
        current_mount_mode="rw"
    fi

    remount_partition_previous_state_ro_variable_name="${remount_partition^^}_PREVIOUS_STATE_RO"

    # If remount_mode equals "rw"
    if [[ "$remount_mode" == "rw" ]]; then
        # Set previous remount state of remount_partition to be used later
        # Note that $remount_partition will be evaluated to the value in the variable like "rootfs" or "system"
        sudo_log 3 "Setting $remount_partition_previous_state_ro_variable_name to $return_value"
        eval $remount_partition_previous_state_ro_variable_name=$return_value
    fi

    # If remount_mode is equal to current_mount_mode
    if [[ "$remount_mode" == "$current_mount_mode" ]]; then
        sudo_log 3 "'$remount_partition_mount_point' is already mounted as $remount_mode"

        # If force_remount is not enabled, then exit
        if [[ $force_remount != "1" ]]; then
            return 0
        else
            sudo_log 3 "Force remounting '$remount_partition_mount_point' as $remount_mode"
        fi
    else
        sudo_log 3 "'$remount_partition_mount_point' is mounted as $current_mount_mode"
    fi

    # If remount_mode equals "ro"
    if [[ "$remount_mode" == "ro" ]]; then
        # Find previous remount state of remount_partition
        # Note that $remount_partition will be evaluated to the value in the variable like "rootfs" or "system"
        eval remount_partition_previous_state_ro="\$$remount_partition_previous_state_ro_variable_name"

        # If rootfs was previously mounted as rw and force_remount is not set to 1
        # remount_partition_previous_state_ro will be 0 if it was ro, 1 if it was rw
        if [[ "$remount_partition_previous_state_ro" == "1" ]] && [[ $force_remount -ne 1 ]]; then
            sudo_log 3 "Skipping remount '$remount_partition_mount_point' as ro since it was previously mounted as rw"
            return 0
        fi
    fi

    # If SU or SU_ENV_COMMAND is not set
    # This function is sourced and called by the sudo_tests script in which case sudo_main is not called to set SU and SU_ENV_COMMAND
    if [ -z "$SU" ] || [ -z "$SU_ENV_COMMAND" ]; then
        # Set SU and SU_BIN_PATH
        sudo_set_su_variables || return $?

        # Set SU_ENV_COMMAND
        sudo_set_su_env_command || return $?
    fi

    # Remount remount_partition_mount_point as remount_mode in global namespace
    sudo_log 3 $'\n'"Remounting $remount_partition_mount_point as $remount_mode"

    sudo_unset_pre_su_variables
    remount_command_output="$($SU_ENV_COMMAND "\"$mountBinaryPath\" -o \"$remount_mode,remount\" \"$remount_partition_mount_point\"" 2>&1 < /dev/null)"
    return_value=$?
    sudo_set_post_su_variables
    # If mount_point is busy error received, then just ignore
    if [ $return_value -eq 32 ] && [[ "$remount_mode" == "ro" ]] && [[ "$remount_command_output" == *"$remount_partition_mount_point is busy"* ]]; then
        sudo_log 3 "Failed to remount $remount_partition_mount_point as $remount_mode, since its busy"
        sudo_log 3 "Ignoring error and force setting result_code to '0'"
        return 0
    # Else if non zero exit code received or output is set, then exit with error
    # in some cases exit code is 0, even though mount actually fails like if partition is read only
    elif [ $return_value -ne 0 ] || [ -n "$remount_command_output" ]; then
        sudo_log_errors "$remount_command_output"
        sudo_log_errors "Failed to remount $remount_partition_mount_point as $remount_mode"
        if [ $return_value -eq 0 ]; then
            return_value=1
        fi
    else
        sudo_log 3 "Remount $remount_partition_mount_point as $remount_mode successful"
    fi

    return $return_value

}



##
# Get/Set/Unset variable names and values for `TERMUX*__` and other
# scoped environment variables exported by different Termux runtime
# components, with support for fallback values and validation of
# values.
#
# The `extended_validator` logic is based on `libalteran-sh`
# `bash___shell__validate_variable_with_extended_validator()` function.
#
# **See Also:**
# - https://github.com/termux/termux-core-package/blob/master/site/pages/en/projects/docs/usage/utils/termux-scoped-env-variable.md
# - https://github.com/termux/termux-core-package/blob/master/src/scripts/termux-scoped-env-variable.bash.in
# - https://github.com/termux/termux-packages/blob/master/packages/termux-core/src/scripts/termux_core__bash__termux_scoped_env_variable
#
#
# `termux_core__bash__termux_scoped_env_variable` `get-name` \
#     `<output_mode>` \
#     `<scoped_var_scope_mode>` `<scoped_var_sub_name>`
# `termux_core__bash__termux_scoped_env_variable` `get-value` \
#     `<output_mode>` \
#     `<scoped_var_scope_mode>` `<scoped_var_sub_name>` \
#     `<extended_validator>` [`<default_values...>`]
##
termux_core__bash__termux_scoped_env_variable() {

    local return_value

    local command_type="${1:-}"
    local command_action="${command_type%%-*}"
    [ $# -gt 0 ] && shift 1

    if [ "$command_type" = "get-name" ]; then
        local output_mode="${1:-}"
        local scoped_var_scope_mode="${2:-}"
        local scoped_var_sub_name="${3:-}"

        if [ $# -ne 3 ]; then
            echo "Invalid argument count $# for the 'get-name' command. \
The 'termux_core__bash__termux_scoped_env_variable' function expects 3 arguments." 1>&2
            printf 'Arguments: %s\n' "$*" 1>&2
            return 64 # EX__USAGE
        fi
    elif [ "$command_type" = "get-value" ]; then
        local output_mode="${1:-}"
        local scoped_var_scope_mode="${2:-}"
        local scoped_var_sub_name="${3:-}"
        local extended_validator="${4:-}"

        local validator_arg
        local validator_mode

        if [ $# -lt 4 ]; then
            echo "Invalid argument count $# for the 'get-value' command. \
The 'termux_core__bash__termux_scoped_env_variable' function expects minimum 4 arguments." 1>&2
            printf 'Arguments: %s\n' "$*" 1>&2
            return 64 # EX__USAGE
        fi

        # Remove args before `default_values` to be used in `var_value_cur` for loop below.
        shift 4

        case "$extended_validator" in
            '?'|'*')
                validator_arg=""
                validator_mode="$extended_validator"
                ;;
            'r+='?*|'r-='?*)
                validator_arg="${extended_validator:3}" # 3:end
                validator_mode="${extended_validator:0:3}" # 0:3
                ;;
            *)
                echo "The extended_validator '$extended_validator' \
argument passed to 'termux_core__bash__termux_scoped_env_variable' is not valid. \
It must either be equal to \`?\` or \`*\`, or a regex that starts with \`r+=\` or \`r-=\`." 1>&2
                return 64 # EX__USAGE
                ;;
        esac
    else
        echo "The command '$command_type' passed to 'termux_core__bash__termux_scoped_env_variable' is not valid." 1>&2
        return 64 # EX__USAGE
    fi

    local i
    local is_value_valid
    local scoped_var_root_scope_name=""
    local scoped_var_scope_name=""
    local scoped_var_sub_scope_name=""
    local scoped_var_name=""
    local scoped_var_set=""
    local scoped_var_value_invalid_error_suffix=""
    local var_value_cur

    # A valid environment variable name (like `TERMUX__VAR`) or a bash array variable (like `TERMUX__ARRAY[0]`).
    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'


    if [ "$command_action" = "get" ]; then
        if [ "$output_mode" != ">" ] && [ "$output_mode" != "-" ]; then
            # If `output_mode` is not a valid environment variable name.
            if [[ ! "$output_mode" =~ $valid_bash_variable_name_regex ]]; then
                echo "The output_mode '$output_mode' argument passed to \
'termux_core__bash__termux_scoped_env_variable' is not a valid environment variable name, or equal to \`>\` or \`-\`." 1>&2
                return 64 # EX__USAGE
            fi
        fi
    fi


    case "$scoped_var_scope_mode" in
        s=?*) scoped_var_scope_name="${scoped_var_scope_mode:2}";; # 2:end
        ss=?*) scoped_var_sub_scope_name="${scoped_var_scope_mode:3}";; # 3:end
        '') ;;
        *)
            echo "The scoped_var_scope_mode '$scoped_var_scope_mode' \
argument for the variable to $command_action passed to \
'termux_core__bash__termux_scoped_env_variable' is not valid. \
It must either be a supported component name starting with \`cn=\`, \
or an environment variable scope starting with \`s=\` or \`ss=\`." 1>&2
            return 64 # EX__USAGE
            ;;
    esac


    if [ -n "$scoped_var_scope_mode" ]; then
        if [ -n "$scoped_var_scope_name" ]; then
            # Generate the full name for the variable under the provided root and sub scope.
            scoped_var_name="${scoped_var_scope_name}${scoped_var_sub_name}"
        else
            # Generate the full name for the variable under the Termux root scope and provided sub scope.
            # If `TERMUX_ENV__S_ROOT` environment variable set.
            # shellcheck disable=SC2050
            if [ -n "${TERMUX_ENV__S_ROOT:-}" ]; then
                scoped_var_root_scope_name="$TERMUX_ENV__S_ROOT"
                if [[ ! "$scoped_var_root_scope_name" =~ $valid_bash_variable_name_regex ]]; then
                    echo "The TERMUX_ENV__S_ROOT environment variable value '$scoped_var_root_scope_name' \
while running 'termux_core__sh__termux_scoped_env_variable' is not a valid environment variable name." 1>&2
                    return 1
                fi
            # If `TERMUX_ENV__S_ROOT` placeholder got replaced during build time.
            elif [ "TERMUX_" != @"TERMUX_ENV__S_ROOT"@ ]; then
                scoped_var_root_scope_name="TERMUX_"
                if [[ ! "$scoped_var_root_scope_name" =~ $valid_bash_variable_name_regex ]]; then
                    echo "The TERMUX_ENV__S_ROOT build value '$scoped_var_root_scope_name' \
while running 'termux_core__sh__termux_scoped_env_variable' is not a valid environment variable name." 1>&2
                    return 1
                fi
            else
                scoped_var_root_scope_name="TERMUX_"
            fi

            scoped_var_name="${scoped_var_root_scope_name}${scoped_var_sub_scope_name}${scoped_var_sub_name}"
        fi

        if [[ ! "$scoped_var_name" =~ $valid_bash_variable_name_regex ]]; then
            echo "The name of the variable to $command_action '$scoped_var_name' generated in \
'termux_core__bash__termux_scoped_env_variable' is not a valid environment variable name." 1>&2
            return 64 # EX__USAGE
        fi


        # If command type equals `get-name`, then return the variable name and exit.
        if [ "$command_type" = "get-name" ]; then
            #echo "scoped_var_name=$scoped_var_name"
            if [ "$output_mode" = ">" ]; then
                printf "%s" "$scoped_var_name"
                return $?
            elif [ "$output_mode" != "-" ]; then
                printf -v "$output_mode" "%s" "$scoped_var_name"
                #eval "echo $output_mode=\"\${${output_mode}}\"" # Surround `${output_mode}` with `${}` in case its a base array variable name
                return $?
            else
                return 0
            fi
        fi
    else
        if [ "$command_type" = "get-name" ]; then
            echo "The scoped_var_scope_mode argument for the variable \
to $command_action passed for the '$command_type' command to \
'termux_core__bash__termux_scoped_env_variable' is not set." 1>&2
            return 64 # EX__USAGE
        fi
    fi


    # If command type equals `get-value`, then find the first valid in variable name/values passed.
    if [ "$command_type" = "get-value" ]; then
        # Loop on [`<expanded_scoped_var_name>` `<default_values>`] to
        # find the first valid value.
        i=0
        for var_value_cur in "$scoped_var_name" "$@"; do
            var_value_cur="${var_value_cur:-}"

            # If first loop, then expand the `scoped_var_name` to its value.
            if [ "$i" = 0 ] && [ -n "$scoped_var_name" ]; then
                # If mode is `*`, expand variable if it is set, or defined
                # but empty. Else if its not defined, then ignore it.
                if [ "$validator_mode" = "*" ]; then
                    eval '[ -n "${'"$scoped_var_name"'+x}" ] && scoped_var_set=1 || scoped_var_set=0'
                    if [ "$scoped_var_set" = "1" ]; then
                        var_value_cur="${!scoped_var_name:-}"
                    else
                        i=$((i + 1)); continue;
                    fi
                else
                    var_value_cur="${!scoped_var_name:-}"
                fi
            fi

            is_value_valid=0
            if [ "$validator_mode" = "r+=" ]; then
                if [[ "$var_value_cur" =~ $validator_arg ]]; then
                    is_value_valid=1
                fi
            elif [ "$validator_mode" = "r-=" ]; then
                if [[ ! "$var_value_cur" =~ $validator_arg ]]; then
                    is_value_valid=1
                fi
            else
                # If mode is `?` or `*`, and value is set,
                # or mode is `*` and value is not set.
                if [ -n "$var_value_cur" ] || [ "$validator_mode" = "*" ]; then
                    is_value_valid=1
                # Else if mode is `?`, and value is not set.
                else
                    is_value_valid=0
                fi
            fi

            if [ "$is_value_valid" = "1" ]; then
                #echo "var_value_cur=$var_value_cur"
                if [ "$output_mode" = ">" ]; then
                    printf "%s" "$var_value_cur"
                    return $?
                elif [ "$output_mode" != "-" ]; then
                    printf -v "$output_mode" "%s" "$var_value_cur"
                    #eval "echo $output_mode=\"\${${output_mode}}\"" # Surround `${output_mode}` with `${}` in case its a base array variable name
                    return $?
                else
                    return 0
                fi
            fi

            i=$((i + 1))
        done


        # If a valid value not found.

        if [ -n "$scoped_var_name" ]; then
            scoped_var_value_invalid_error_suffix=" that is read from the '\$$scoped_var_name' variable"
        fi
        if [ "$output_mode" != ">" ] && [ "$output_mode" != "-" ]; then
            # Set output variable in `output_mode` to an empty string
            # since it may already be set, as callers may try to use that
            # wrong value without checking the exit code.
            # We unset after reading the values, otherwise if
            # `scoped_var_name` is equal to output variable in
            # `output_mode`, then `scoped_var_name` would get unset before
            # its read.
            printf -v "$output_mode" "%s" "" || return $?

            echo "Failed to find a valid value to set to the '\$$output_mode' \
variable${scoped_var_value_invalid_error_suffix}." 1>&2
        else
            echo "Failed to find a valid value${scoped_var_value_invalid_error_suffix}." 1>&2
        fi
        return 81 # C_EX__NOT_FOUND
    fi

}

##
# Set a bash indexed array (`declared -a`) to shell command arguments
# defined as a string by splitting the string as normally done by the
# shell.
#
# This function is based on `libalteran-sh`
# `bash___shell__set_shell_command_args_array()`
# function, check it for more info and comments.
#
#
# `sudo_set_shell_command_args_array` \
#     `<command_args_array_variable_name>` \
#     `<command_args_label>` `<command_args_string>`
##
sudo_set_shell_command_args_array() {

    local return_value

    if [ $# -ne 3 ]; then
        sudo_log_errors "Invalid argument count to 'sudo_set_shell_command_args_array'"
        return 1
    fi

    local command_args_array_variable_name="$1"
    local command_args_label="$2"
    local command_args_string="$3"

    local command_arg
    local command_args_string_contains_shell_special_chars="false"
    local command_args_string_contains_space="false"
    local newline=$'\n'
    local space_containing_string_regex='[[:space:]]+'
    local shell_special_chars_containing_string_regex='[]["'\''*?!\]+'
    local xargs_command_output

    local -n  command_args_array="$command_args_array_variable_name" || return $?
    command_args_array=()


    if [[ -z "$command_args_string" ]]; then
        # Unset `nameref` to `command_args_array_variable_name`.
        unset -n  command_args_array || return $?
        return 0
    fi

    if [[ "$command_args_string" == *$'\n'* ]]; then
        sudo_log_errors "The $command_args_label value to be \
converted to a command array cannot contain a newline '\n' character:"
        sudo_log_errors "\`\`\`"
        sudo_log_errors "$command_args_string"
        sudo_log_errors "\`\`\`"
        return 64 # EX__USAGE
    fi


    if [[ "$command_args_string" =~ $shell_special_chars_containing_string_regex ]]; then
        command_args_string_contains_shell_special_chars="true"
    fi
    if [[ "$command_args_string" =~ $space_containing_string_regex ]]; then
        command_args_string_contains_space="true"
    fi

    if [[ "$command_args_string_contains_shell_special_chars" == "true" ]] || \
            [[ "$command_args_string_contains_space" == "true" ]]; then

        # Use `xargs` if command args string contains whitespaces or
        # shell special characters.
        if [[ "$command_args_string_contains_shell_special_chars" == "true" ]]; then
            if [[ -z "$SUDO_XARGS_PATH" ]]; then
                return_value=0
                SUDO_XARGS_PATH="$(command -v "xargs")" || return_value=$?
                if [ $return_value -ne 0 ]; then
                    sudo_log_errors "Failed to find 'xargs' for converting $command_args_label value to a command array."
                    return $return_value
                fi
            fi

            # Android `toybox` provided `xargs` does not parse arguments
            # properly and single and double quotes around arguments
            # remain, nor do backslash escapes work.
            # Termux `findutils` package supplied `xargs` does not
            # have such issues, so we ignore the check for it.
            # `/system/bin/xargs` may get called if current shell has
            # `/system/bin` in `$PATH` instead of or before Termux bin path.
            if [[ "$SUDO_XARGS_PATH" != "$TERMUX_BIN/xargs" ]]; then
                # The logic to check if `xargs` parsing is valid is based
                # on `libalteran-sh` `bash___shell__set_is_xargs_command_args_parsing_valid()`
                # function, check it for more info and comments.
                return_value=0
                xargs_command_output="$(sudo_trim_env_for_xargs && \
                    printf "%s" "'' 'arg' '' 'arg with space' 'arg surround by single quote' \"arg surround by double quote\" 'arg with '\'' single quote' 'arg with \" double quote' 'arg with \" double quote surround by single quote' \"arg with ' single quote surround by double quote\" arg\ with\ escaped\ space 'arg with backslash \\ and forward slash / surround by single quote' \"arg with backslash \\ and forward slash / surround by double quote\" \\/ \\\\ ''" | \
                    xargs -r -n1 -- printf "%s\n" && echo -n x)" || return_value=$?
                if [ $return_value -ne 0 ]; then
                    sudo_log_errors "Failed to check if xargs command args parsing is valid."
                    sudo_log_errors "xargs_command_output=\`$xargs_command_output\`"
                    return $return_value
                fi

                if [[ "${xargs_command_output%x}" != "${newline}arg${newline}${newline}arg with space${newline}arg surround by single quote${newline}arg surround by double quote${newline}arg with ' single quote${newline}arg with \" double quote${newline}arg with \" double quote surround by single quote${newline}arg with ' single quote surround by double quote${newline}arg with escaped space${newline}arg with backslash \ and forward slash / surround by single quote${newline}arg with backslash \\ and forward slash / surround by double quote${newline}/${newline}\\${newline}" ]]; then
                    sudo_log_errors "The $command_args_label value cannot be \
converted to a command array in current execution environment as it contains \
shell special characters and 'xargs' command args parsing is not valid:"
                    sudo_log_errors "\`\`\`"
                    sudo_log_errors "$command_args_string"
                    sudo_log_errors "\`\`\`"
                    sudo_log_errors "xargs path: \`$(command -v "xargs" || true)\`"
                    sudo_log_errors "xargs version: \`$({ xargs --version 2>/dev/null || true; } | head -n 1)\`"
                    return 1
                fi
            fi

            command_arg="READ_ERROR"
            return_value=0
            while IFS= read -r command_arg; return_value=$?; [[ $return_value -eq 0 ]]; do
                command_args_array+=("$command_arg")
            done < <({ sudo_trim_env_for_xargs && \
                printf "%s\n" "$command_args_string" | \
                xargs -r -n1 -- printf "%s\n"; } || echo -n "CMD_ERROR")
            if [[ -n "${command_arg:-}" ]] || [ $return_value -ne 1 ]; then
                sudo_log_errors "Failed to create command array for \
command arguments string \`$command_args_string\`."
                [[ -n "${command_arg:-}" ]] && sudo_log_errors "Error type: '$command_arg'"
                if [[ -n ${!:-} ]]; then
                    wait "$!" || true
                fi
                return 1
            fi
        else
            # Avoid creating subshell and external call to xargs if
            # command args string contains whitespaces but does not
            # contain shell special characters and rely on whitespace
            # splitting of arguments.
            local old_ifs="$IFS"
            IFS=$' \t\n'
            # shellcheck disable=SC2206
            command_args_array=( $command_args_string )
            IFS="$old_ifs"
        fi
    else
        # Avoid creating subshell and external call to xargs if
        # command args string does not contain whitespaces or shell
        # special characters.
        command_args_array=( "$command_args_string" )
    fi

    # Unset `nameref` to `command_args_array_variable_name`.
    unset -n  command_args_array || return $?

    return 0

}

##
# Trim exported environment variables before running `xargs` to
# prevent `environment is too large for exec` error on Android `< 6`.
#
# On Android `5`, `getconf ARG_MAX` equals `4096` and `xargs` always
# fails to run.
#
# Only `PATH`, `$LD_LIBRARY_PATH` and `$LD_PRELOAD` variables are kept,
# and all other variables are unset.
#
# - https://www.gnu.org/software/findutils/manual/html_node/find_html/Error-Messages-From-xargs.html
##
sudo_trim_env_for_xargs() {

    # If on Android `< 6`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 23 ]; then
        local env_variables
        env_variables="$(compgen -e | grep -v -E "^PATH|LD_LIBRARY_PATH|LD_PRELOAD$")" || return $?
        if [ -n "$env_variables" ]; then
            # shellcheck disable=SC2086
            unset $env_variables
        fi
    fi

}



##
# `sudo_replace_comma_alternative_chars_with_commas_in_string` `<string>`
##
sudo_replace_comma_alternative_chars_with_commas_in_string() {

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If $1 is valid bash variable_name
    if [[ "$1" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name stored in $1 to variable_value in $2 after replacing all COMMA_ALTERNATIVE characters with a comma ',' in $2
        printf -v "$1" "%s" "${2//$COMMA_ALTERNATIVE/,}"
    else
        sudo_log_errors "variable_name '$1' passed to 'sudo_replace_comma_alternative_chars_with_commas_in_string' is not a valid bash variable name"
    fi

}

##
# `sudo_trim_trailing_newlines` `<variable_name>` `<variable_value>`
##
sudo_trim_trailing_newlines() {

    local extglob_was_unset=1
    shopt extglob >/dev/null && extglob_was_unset=0 # Check if 'extglob' is currently set
    (( extglob_was_unset )) && shopt -s extglob # Set 'extglob', if currently unset

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If $1 is valid bash variable_name
    if [[ "$1" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name stored in $1 to variable_value in $2 without trailing newline and carriage return characters
        printf -v "$1" "%s" "${2%%*([$'\r\n'])}"
    else
        sudo_log_errors "variable_name '$1' passed to 'sudo_trim_trailing_newlines' is not a valid bash variable name"
    fi

    (( extglob_was_unset )) && shopt -u extglob # Unset 'extglob', if previously unset

}

##
# `sudo_process_script_arguments` [`<argument...>`]
##
sudo_process_script_arguments() {

    local opt; local opt_arg; local OPTARG=""; local OPTIND=1;

    # Parse options to main command
    while getopts ":hqvaAbBcdDeEfFHilLnNoOpPrRsStT-:" opt; do
        case "${opt}" in
            -)
                case "${OPTARG}" in *?=*) opt_arg="${OPTARG#*=}";; *) opt_arg="";; esac
                case "${OPTARG}" in
                    help-extra)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        sudo_show_help_extra || return $?
                        SUDO_NOOP_COMMAND=1; return 0
                        ;;
                    help-extra=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    help)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        sudo_show_help || return $?
                        SUDO_NOOP_COMMAND=1; return 0
                        ;;
                    help=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    quiet)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SUDO_LOG_LEVEL=0
                        ;;
                    quiet=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    version)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        echo "sudo version=$SUDO__VERSION org=agnostic-apollo project=sudo"
                        SUDO_NOOP_COMMAND=1; return 0
                        ;;
                    version=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    comma-alternative=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        COMMA_ALTERNATIVE="$opt_arg"
                        ;;
                    comma-alternative | comma-alternative=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    dry-run)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SUDO_DRY_RUN=1
                        ;;
                    dry-run=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    export-paths=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        sudo_trim_trailing_newlines "SUDO_ADDITIONAL_PATHS_TO_EXPORT" "$opt_arg"
                        ;;
                    export-paths | export-paths=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    export-ld-lib-paths=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        sudo_trim_trailing_newlines "SUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT" "$opt_arg"
                        ;;
                    export-ld-lib-paths | export-ld-lib-paths=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    force-remount-ro)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        FORCE_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO=1
                        ;;
                    force-remount-ro=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    hold)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        HOLD_STRING_AFTER_SUDO=""
                        HOLD_AFTER_SUDO=1
                        ;;
                    hold=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "HOLD_STRING_AFTER_SUDO" "$val"
                        HOLD_AFTER_SUDO=1
                        ;;
                    hold=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    hold-if-fail)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        HOLD_ONLY_ON_FAILURE=1
                        ;;
                    hold-if-fail=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    list-interactive-shells)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        echo "$SUDO_SUPPORTED_INTERACTIVE_SHELLS"
                        SUDO_NOOP_COMMAND=1; return 0
                        ;;
                    list-interactive-shells=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    list-script-shells)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        echo "$SUDO_SUPPORTED_SCRIPT_SHELLS"
                        SUDO_NOOP_COMMAND=1; return 0
                        ;;
                    list-script-shells=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    no-create-hist)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES=0
                        ;;
                    no-create-hist=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    no-create-rc)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES=0
                        ;;
                    no-create-rc=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    no-hist)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SUDO_SHELLS_HISTORY_ENABLED=0
                        ;;
                    no-hist=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    no-log-args)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        DISABLE_ARGUMENTS_LOGGING=1
                        ;;
                    no-log-args=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    no-remount-ro)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        DO_NOT_REMOUNT_PARTITIONS_BACK_TO_RO_AFTER_SUDO=1
                        ;;
                    no-remount-ro=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    keep-temp)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        DO_NOT_DELETE_SUDO_TEMP_DIRECTORY_ON_EXIT=1
                        ;;
                    keep-temp=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    post-shell=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        sudo_trim_trailing_newlines "SUDO_POST_SHELL" "$opt_arg"
                        ;;
                    post-shell | post-shell=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    post-shell-home=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "SUDO_POST_SHELL_HOME" "$val"
                        CUSTOM_SUDO_POST_SHELL_HOME_SET=1
                        ;;
                    post-shell-home | post-shell-home=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    post-shell-options=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_set_shell_command_args_array SUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS \
                            "'--post-shell-options' arg option" "$val" || return $?
                        ;;
                    post-shell-options | post-shell-options=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    post-shell-post-commands=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_SUDO_POST_SHELL_POST_COMMANDS_TO_RUN="$val"
                        ;;
                    post-shell-post-commands | post-shell-post-commands=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    post-shell-pre-commands=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_SUDO_POST_SHELL_PRE_COMMANDS_TO_RUN="$val"
                        ;;
                    post-shell-pre-commands | post-shell-pre-commands=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    post-shell-stdin-string=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        SUDO_POST_SHELL_STDIN_STRING="$val"
                        ;;
                    post-shell-stdin-string | post-shell-stdin-string=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    remove-prev-temp)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        REMOVE_PREVIOUS_SUDO_TEMP_FILES=1
                        ;;
                    remove-prev-temp=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    script-decode)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=1
                        DECODE_CORE_SCRIPT_CONTENT=1
                        ;;
                    script-decode=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    script-name=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "SUDO_CORE_SCRIPT_TEMP_FILENAME" "$val"
                        ;;
                    script-name | script-name=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    script-redirect=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "SUDO_CORE_SCRIPT_REDIRECT_MODE" "$val"
                        ;;
                    script-redirect | script-redirect=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    shell=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        sudo_trim_trailing_newlines "SUDO_SHELL" "$opt_arg"
                        ;;
                    shell | shell=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    shell-home=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "SUDO_SHELL_HOME" "$val"
                        CUSTOM_SUDO_SHELL_HOME_SET=1
                        ;;
                    shell-home | shell-home=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    shell-options=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_set_shell_command_args_array SUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS \
                            "'--shell-options' arg option" "$val" || return $?
                        ;;
                    shell-options | shell-options=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    shell-post-commands=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_SUDO_SHELL_POST_COMMANDS_TO_RUN="$val"
                        ;;
                    shell-post-commands | shell-post-commands=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    shell-pre-commands=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_SUDO_SHELL_PRE_COMMANDS_TO_RUN="$val"
                        ;;
                    shell-pre-commands | shell-pre-commands=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    shell-stdin-string=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        SUDO_SHELL_STDIN_STRING="$val"
                        ;;
                    shell-stdin-string | shell-stdin-string=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    sleep=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        sudo_trim_trailing_newlines "SLEEP_TIME_AFTER_SUDO" "$opt_arg"
                        SLEEP_AFTER_SUDO=1
                        ;;
                    sleep | sleep=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    sleep-if-fail)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SLEEP_ONLY_ON_FAILURE=1
                        ;;
                    sleep-if-fail=*)
                        sudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        sudo_exit_on_args_error || return $?
                        ;;
                    su-env-options=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_set_shell_command_args_array SUDO_SU_ENV_ADDITIONAL_COMMAND_OPTIONS \
                            "'--su-env-options' arg option" "$val" || return $?
                        ;;
                    su-env-options | su-env-options=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    su-path=?*)
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        sudo_trim_trailing_newlines "SUDO_SU_PATH" "$opt_arg"
                        ;;
                    su-path | su-path=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    su-run-options=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_set_shell_command_args_array SUDO_SU_RUN_ADDITIONAL_COMMAND_OPTIONS \
                            "'--su-run-options' arg option" "$val" || return $?
                        ;;
                    su-run-options | su-run-options=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    title=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "SUDO_SHELL_TERMINAL_TITLE" "$val"
                        SET_SUDO_SHELL_TERMINAL_TITLE=1
                        ;;
                    title | title=)
                        SUDO_SHELL_TERMINAL_TITLE=""
                        SET_SUDO_SHELL_TERMINAL_TITLE=1
                        ;;
                    work-dir=?*)
                        val="$opt_arg"
                        sudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            sudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        sudo_trim_trailing_newlines "SUDO_SHELL_WORKING_DIR" "$val"
                        ;;
                    work-dir | work-dir=)
                        sudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                    '')
                        sudo_log_args "Parsing option: '--'"
                        break # End of options `--`.
                        ;;
                    *)
                        sudo_log_arg_errors "Unknown option: '--${OPTARG:-}'."
                        sudo_exit_on_args_error || return $?
                        ;;
                esac
                ;;
            h)
                sudo_log_args "Parsing option: '-${opt}'"
                sudo_show_help || return $?
                SUDO_NOOP_COMMAND=1; return 0
                ;;
            q)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_LOG_LEVEL=0
                ;;
            v)
                sudo_log_args "Parsing option: '-${opt}'"
                if [ "$SUDO_LOG_LEVEL" -lt "$SUDO_MAX_LOG_LEVEL" ]; then
                    SUDO_LOG_LEVEL=$((SUDO_LOG_LEVEL+1));
                else
                    sudo_log_arg_errors "Invalid option, max log level is $SUDO_MAX_LOG_LEVEL"
                    sudo_exit_on_args_error || return $?
                fi
                ;;
            a)
                sudo_log_args "Parsing option: '-${opt}'"
                A_FLAG_PASSED=1
                PATH_PRIORITY="android"
                ;;
            A)
                sudo_log_args "Parsing option: '-${opt}'"
                A_FLAG_PASSED=1
                PATH_PRIORITY="android"

                if [ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]; then
                    # If first '-A' option passed
                    SET_SECONDARY_PATHS=0
                else
                    # If '-AA' passed
                    SET_SECONDARY_PATHS=1
                fi
                SET_SECONDARY_PRIORITY_PATHS=0
                ;;
            b)
                sudo_log_args "Parsing option: '-${opt}'"
                GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            B)
                sudo_log_args "Parsing option: '-${opt}'"
                RUN_CORE_SCRIPT_IN_BACKGROUND=1
                ;;
            c)
                sudo_log_args "Parsing option: '-${opt}'"
                CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            d)
                sudo_log_args "Parsing option: '-${opt}'"
                DISABLE_STDIN_FOR_CORE_SCRIPT=1
                ;;
            D)
                sudo_log_args "Parsing option: '-${opt}'"
                DISABLE_PRESERVE_ENVIRONMENT_FOR_SU=1
                ;;
            e)
                sudo_log_args "Parsing option: '-${opt}'"
                EXIT_EARLY_IF_CORE_SCRIPT_FAILS=1
                ;;
            E)
                sudo_log_args "Parsing option: '-${opt}'"
                EXEC_SUDO_SHELL=1
                ;;
            f)
                sudo_log_args "Parsing option: '-${opt}'"
                FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=1
                ;;
            F)
                sudo_log_args "Parsing option: '-${opt}'"
                CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE=1
                ;;
            H)
                sudo_log_args "Parsing option: '-${opt}'"
                SAME_SUDO_POST_SHELL_HOME_AS_SUDO_SHELL_HOME=1
                ;;
            i)
                sudo_log_args "Parsing option: '-${opt}'"
                RUN_INTERACTIVE_POST_SUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            l)
                sudo_log_args "Parsing option: '-${opt}'"
                GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            L)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE=1
                ;;
            n)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_CORE_SCRIPT_REDIRECT_MODE=3
                ;;
            N)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_CORE_SCRIPT_REDIRECT_MODE=4
                ;;
            o)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_CORE_SCRIPT_REDIRECT_MODE=0
                ;;
            O)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_CORE_SCRIPT_REDIRECT_MODE=1
                ;;
            p)
                sudo_log_args "Parsing option: '-${opt}'"
                COMMAND_TYPE="path"
                COMMAND_TYPE_PATH_FORCED=1
                ;;
            P)
                sudo_log_args "Parsing option: '-${opt}'"
                SUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE=1
                ;;
            r)
                sudo_log_args "Parsing option: '-${opt}'"
                PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES=1
                ;;
            R)
                sudo_log_args "Parsing option: '-${opt}'"
                USE_ROOT_FOR_PATH_SEARCH_AND_VALIDATION=1
                ;;
            s)
                sudo_log_args "Parsing option: '-${opt}'"
                COMMAND_TYPE="script"
                ;;
            S)
                sudo_log_args "Parsing option: '-${opt}'"
                SAME_SUDO_POST_SHELL_AS_SUDO_SHELL=1
                ;;
            t)
                sudo_log_args "Parsing option: '-${opt}'"
                T_FLAG_PASSED=1
                PATH_PRIORITY="termux"
                ;;
            T)
                sudo_log_args "Parsing option: '-${opt}'"
                T_FLAG_PASSED=1
                PATH_PRIORITY="termux"

                if [ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]; then
                    # If first '-T' option passed
                    SET_SECONDARY_PATHS=0
                else
                    # If '-TT' passed
                    SET_SECONDARY_PATHS=1
                fi
                SET_SECONDARY_PRIORITY_PATHS=0
                ;;
            :)
                sudo_log_arg_errors "No argument passed for arg option '-$OPTARG'."
                sudo_exit_on_args_error || return $?
                ;;
            \?)
                sudo_log_arg_errors "Unknown option${OPTARG:+": '-${OPTARG:-}'"}."
                sudo_exit_on_args_error || return $?
                ;;
        esac
    done
    shift $((OPTIND - 1)) # Remove already processed arguments from arguments array

    # If arguments received
    if [ $# -ne 0 ]; then
        # If (COMMAND_TYPE_PATH_FORCED is not enabled and $1 equals "su" or "asu"
        if [[ "$COMMAND_TYPE_PATH_FORCED" != "1" ]] && { [[ "$1" == "su" ]] || [[ "$1" == "asu" ]]; }; then
            COMMAND_TYPE="$1"
            shift # Remove $1 from the arguments array

            # If more arguments are given
            if [ $# -ne 0 ]; then
                sudo_log_arg_errors "Unknown arguments to '$COMMAND_TYPE': '$*'"
                sudo_exit_on_args_error || return $?
            fi

            if [[ "$COMMAND_TYPE" == "su" ]] && [[ "$A_FLAG_PASSED" == "1" ]]; then
                sudo_log_arg_errors "Cannot pass '-a|-A' flags to 'su' command, use '-t|-T' flags instead"
                sudo_exit_on_args_error || return $?
            fi

            if [[ "$COMMAND_TYPE" == "asu" ]] && [[ "$T_FLAG_PASSED" == "1" ]]; then
                sudo_log_arg_errors "Cannot pass '-t|-T' flags to 'asu' command, use '-a|-A' flags instead"
                sudo_exit_on_args_error || return $?
            fi

        # If COMMAND_TYPE equals "path" or "script"
        elif [[ "$COMMAND_TYPE" == "path" ]] || [[ "$COMMAND_TYPE" == "script" ]]; then
            # Set rest of the arguments to the sudo script as SUDO_COMMAND
            SUDO_COMMAND=()
            local return_value
            local read_argument_from_fd
            local fd_number
            local i=1
            for arg in "$@"; do
                read_argument_from_fd=0

                # If process substitution was used to pass path to an fd file as argument that contains the actual argument value
                # and the fd is not of stdin, stdout or stderr
                if [[ "$arg" =~ ^/proc/self/fd/[0-9]+$ ]] && [[ ! "$arg" =~ ^/proc/self/fd/(0|1|2)$ ]]; then
                    fd_number="${arg##*/}"
                    # If fd is readable, then
                    if read -t 0 -u "$fd_number" 2>/dev/null; then
                        # Enable read_argument_from_fd
                        read_argument_from_fd=1

                        # If COMMAND_TYPE equals "script" and its the first argument
                        if [[ "$COMMAND_TYPE" == "script" ]] && [ $i -eq 1 ]; then
                            # Disable read_argument_from_fd since we are reading it here with cat
                            # fd can't be read again, seeking backwards is not possible
                            read_argument_from_fd=0

                            # Read core_script from fd in encoded form since it may contain non UTF-8 or binary data
                            encoded_arg="$(cat "$arg" | base64)"
                            return_value=$?
                            if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
                                sudo_log_arg_errors "Failure while encoding core_script received as argument"
                                return $return_value
                            fi

                            # Check if core_script contains non UTF-8 or binary data
                            # Decode data first before passing to grep
                            printf '%s' "$encoded_arg" | base64 -d | grep -axvq '.*'
                            return_value=$?
                            if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
                                sudo_log_arg_errors "Failure while checking if core_script contains non UTF-8 or binary data"
                                return $return_value
                            # If found
                            elif [ $return_value -eq 0 ]; then
                                # Enable use of temp script file for core_script and enable decoding
                                FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=1
                                DECODE_CORE_SCRIPT_CONTENT=1

                                # Set encoded data to arg
                                arg="$encoded_arg"
                            # If not found
                            else
                                # Set decoded data to arg
                                arg="$(printf '%s' "$encoded_arg" | base64 -d)"
                            fi
                        fi
                    fi
                fi

                # If read_argument_from_fd is enabled
                if [[ "$read_argument_from_fd" == "1" ]]; then
                    # Use the fd file content as argument value
                    SUDO_COMMAND+=( "$(<"$arg")" )
                else
                    # Directly use the argument value
                    SUDO_COMMAND+=("$arg")
                fi

                i=$((i + 1))
            done
            shift $# # Remove all remaining arguments from arguments array
        fi

    # Else show help
    else
        if [[ "$COMMAND_TYPE" == "script" ]]; then
            SUDO_COMMAND=()
        else
            sudo_show_help
            SUDO_NOOP_COMMAND=1; return 0
        fi
    fi

}

sudo_show_help() {

    cat <<'SUDO_HELP_EOF' | \
        sed \
            -e "s%[@]TERMUX__LNAME[@]%${TERMUX__LNAME}%g" \
            -e "s%[@]TERMUX_APP__NAME[@]%${TERMUX_APP__NAME}%g"
sudo stands for 'superuser do'.
It is a wrapper script to execute commands as the 'root (superuser)'
user in the Termux app, like to drop to an interactive
shell for any of the supported shells, or to execute shell script
files or their text passed as an argument.


Usage:
  sudo [command_options] su
  sudo [command_options] asu
  sudo [command_options] [-p] <command> [command_args]
  sudo [command_options] -s <core_script> [core_script_args]


Available command_options:
  [ -h | --help ]    Display this help screen.
  [ --help-extra ]   Display more help about how sudo command works.
  [ -q | --quiet ]   Set log level to 'OFF'.
  [ -v | -vv ]       Set log level to 'DEBUG', 'VERBOSE'.
  [ --version ]      Display version.
  [ -a ]             Set priority to android paths for 'path' and
                     'script' command types. The '$PATH' variable will
                     contain all android bin paths followed all termux
                     bin paths. The '$LD_PRELOAD' variable will not be
                     set.
  [ -A ]             Set priority to android paths for 'asu', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain only '/system/bin' path. The
                     '$LD_PRELOAD' variable will not be set.
  [ -AA ]            Set priority to android paths for 'asu', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain all android bin paths. The
                     '$LD_PRELOAD' variable will not be set.
  [ -b ]             Go back to last activity after running core_script.
  [ -B ]             Run core_script in background.
  [ -c ]             Clear shell after running core_script.
  [ -d ]             Disable stdin for core_script.
  [ -D ]             Disable preserve environment for su.
  [ -e ]             Exit early if core_script fails.
  [ -E ]             Exec interactive shell or the path command.
  [ -f ]             Force use temp script file for core_script.
  [ -F ]             Consider core_script to be a path to script file
                     instead of script text.
  [ -H ]             Same sudo post shell home as sudo shell home.
  [ -i ]             Run interactive sudo post shell after running
                     core_script.
  [ -l ]             Go to launcher activtiy after running core_script
  [ -L ]             Export all existing paths in '$LD_LIBRARY_PATH'
                     variable.
  [ -n ]             Redirect stderr to /dev/null for core_script.
  [ -N ]             Redirect stdout and stderr to /dev/null for
                     core_script.
  [ -o ]             Redirect stderr to stdout for core_script.
  [ -O ]             Redirect stdout to stderr for core_script.
  [ -p ]             Set 'path' as command type [default].
  [ -P ]             Export all existing paths in '$PATH' variable.
  [ -r ]             Parse commands as per RUN_COMMAND intent rules.
  [ -R ]             Use root for searching and validating paths.
  [ -s ]             Set 'script' as command type.
  [ -S ]             Same sudo post shell as sudo shell.
  [ -t ]             Set priority to termux paths for 'path' and
                     'script' command types. The '$PATH' variable will
                     contain all termux bin paths followed all android
                     bin paths. The '$LD_PRELOAD' variable will
                     contain '$TERMUX__PREFIX/lib/libtermux-exec.so'.
  [ -T ]             Set priority to termux paths for 'su', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain only '$TERMUX__PREFIX/bin' path.
                     The '$LD_PRELOAD' variable will contain
                     '$TERMUX__PREFIX/lib/libtermux-exec.so'.
  [ -TT ]            Set priority to termux paths for 'su', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain all termux bin paths. The
                     '$LD_PRELOAD' variable will contain
                     '$TERMUX__PREFIX/lib/libtermux-exec.so'.
  [ --comma-alternative=<alternative> ]
                     Comma alternative character to be used for
                     the '-r' option instead of the default.
  [ --dry-run ]
                     Do not execute sudo commands.
  [ --export-paths=<paths> ]
                     Additional paths to export in '$PATH' variable,
                     separated with colons ':'.
  [ --export-ld-lib-paths=<paths> ]
                     Additional paths to export in '$LD_LIBRARY_PATH'
                     variable, separated with colons ':'.
  [ --force-remount-ro ]
                     Force remount rootfs and system partitions back
                     to ro after sudo commands.
  [ --hold[=<string>] ]
                     Hold sudo from exiting until string is entered,
                     defaults to any character if string is not passed.
  [ --hold-if-fail ]
                     If '--hold' option is passed, then only hold if
                     exit code of sudo does not equal '0'.
  [ --list-interactive-shells ]
                     Display list of supported interactive shells.
  [ --list-script-shells ]
                     Display list of supported script shells.
  [ --no-create-rc ]
                     Do not create rc files automatically.
  [ --no-create-hist ]
                     Do not create history files automatically.
  [ --no-hist ]
                     Do not save history for sudo shell and sudo post
                     shell.
  [ --no-log-args ]
                     Do not log arguments and core_script content
                     when log level is '>= DEBUG'.
  [ --no-remount-ro ]
                     Do not remount rootfs and system partitions back
                     to ro after sudo commands.
  [ --keep-temp ]
                     Do not delete sudo temp directory on exit.
  [ --post-shell=<shell> ]
                     Name or absolute path for sudo post shell.
  [ --post-shell-home=<path> ]
                     Absolute path for sudo post shell home.
  [ --post-shell-options=<options> ]
                     Additional options to pass to sudo post shell.
  [ --post-shell-post-commands=<commands> ]
                     Bash commands to run after sudo post shell.
  [ --post-shell-pre-commands=<commands> ]
                     Bash commands to run before sudo post shell.
  [ --post-shell-stdin-string=<string> ]
                     String to pass as stdin to sudo post shell.
  [ --remove-prev-temp ]
                     Remove temp files and directories created on
                     previous runs of sudo command.
  [ --script-decode ]
                     Consider the core_script as base64
                     encoded that should be decoded before execution.
  [ --script-name=<name> ]
                     Filename to use for the core_script temp file
                     created in '.sudo.temp.XXXXXX' directory instead
                     of 'sudo_script__core_script'.
  [ --script-redirect=<mode/string> ]
                     Core_script redirect mode for stdout and stderr.
  [ --shell=<shell> ]
                     Name or absolute path for sudo shell.
  [ --shell-home=<path> ]
                     Absolute path for sudo shell home.
  [ --shell-options=<options> ]
                     Additional options to pass to sudo shell.
  [ --shell-post-commands=<commands> ]
                     Bash commands to run after sudo shell for script
                     command type.
  [ --shell-pre-commands=<commands> ]
                     Bash commands to run before sudo shell.
  [ --shell-stdin-string=<string> ]
                     String to pass as stdin to sudo shell for script
                     command type.
  [ --sleep=<seconds> ]
                     Sleep for x seconds before exiting sudo.
  [ --sleep-if-fail ]
                     If '--sleep' option is passed, then only sleep if
                     exit code of sudo does not equal '0'.
  [ --su-env-options=<options> ]
                     Additional options to pass to su that sets up the
                     sudo environment.
  [ --su-path=<path> ]
                     Absolute path for su binary to use instead of
                     searching for it in default search paths.
  [ --su-run-options=<options> ]
                     Additional options to pass to su that runs the
                     final sudo command_type command.
  [ --title=<title> ]
                     Title for sudo shell terminal.
  [ --work-dir=<path> ]
                     Absolute path for working directory.


Set log level to '>= DEBUG' to get more info when running sudo command.

Pass '--dry-run' option with log level '>= DEBUG' to see the commands
that will be run without actually executing them.

Visit https://github.com/agnostic-apollo/sudo for more help on how
sudo command works.
SUDO_HELP_EOF

echo $'\n'"Supported interactive shells: \`$SUDO_SUPPORTED_INTERACTIVE_SHELLS\`"
echo $'\n'"Supported script shells: \`$SUDO_SUPPORTED_SCRIPT_SHELLS\`"

}

sudo_show_help_extra() {

    sudo_show_help

    cat <<'SUDO_HELP_EOF' | \
        sed \
            -e "s%[@]TERMUX__LNAME[@]%${TERMUX__LNAME}%g" \
            -e "s%[@]TERMUX_APP__NAME[@]%${TERMUX_APP__NAME}%g"


The 'su' command type drops to an interactive shell as the
'root (superuser)' user for any of the supported interactive shells.
To drop to a root 'bash' shell, just run 'sudo su'. The priority will
be set to termux bin and library paths in '$PATH' and
'$LD_LIBRARY_PATH' variables.
Use the '--shell' option to set the interactive shell to use.


The 'asu' command type is the same as 'su' command type but
instead the priority will be set to android bin and library paths in
'$PATH' and '$LD_LIBRARY_PATH' variables.
Use the '--shell' option to set the interactive shell to use. Only
'/system/bin/sh' shell is allowed on Android '< 7' with '-A' and '-AA'
flags.


The 'path' command type runs a single command as the 'root (superuser)'
user. You can use it just by running 'sudo <command> [command_args]'
where 'command' is the executable you want to run and 'command_args'
are any optional arguments to it. The 'command' will be run within a
'bash' shell.
The 'command' must be an 'absolute' path to an executable, or
'relative' path from the current working directory to an executable
starting starting with './' or '../' (like './script.sh') or the
executable 'basename' in a directory listed in the final '$PATH'
variable that is to be exported by the 'sudo' command depending on
priority set.
The priority is set based on '-a|-A|-AA' or '-t|-T|-TT' flags, and
if flags are not passed, then the priority for bin paths in '$PATH'
variable is given to termux paths followed by android paths if
executable canonical path is under '$TERMUX__ROOTFS' directory,
otherwise to android paths followed by termux paths.
To call the 'su' binary, run the 'sudo -p su [user]' command.


The 'script' command type takes any script text or path to a script
file for any of the supported script shells referred as 'sudo shell',
and executes the script with any optional arguments with the desired
script shell. This can be done by running the
'sudo -s <core_script> [core_script_args]' command.
The 'core_script' will be considered a 'bash' script by default.
The 'core_script' will be passed to the desired shell using
process substitution or after storing the 'core_script' in a temp file
in a temp directory in 'sudo shell' home
'$HOME/.sudo.temp.XXXXXX/sudo_script__core_script' and passing the path to
the desired shell, where 'XXXXXX' is a randomly generated string.
The method is automatically chosen based on the script shell
capabilities. The '-f' option can be used to force the usage of a
script file. The '-F' option can passed so that the 'core_script'
is considered as a path to script file that should be passed to
'sudo shell' directly instead of considering it as a script text.
Use the '--shell' option to set the script shell to use.
Use the '--post-shell' option to set the interactive shell to use if
'-i' option is passed. Only '/system/bin/sh' shell is allowed on
Android '< 7' with '-A' and '-AA' flags.
The priority is given to termux paths unless '-a|-A|-AA' or
'-t|-T|-TT' flags are passed.


Run "exit" command of your shell to exit interactive shells and return
to the termux shell.
SUDO_HELP_EOF

}

sudo_exit_on_args_error() {

    echo ""
    sudo_show_help || return $?
    sudo_run_pre_exit_commands 1 || return $?
    return 64 # EX__USAGE

}



# If script is sourced, return with success, otherwise call main function.
# - https://stackoverflow.com/a/28776166/14686958
# - https://stackoverflow.com/a/29835459/14686958
if (return 0 2>/dev/null); then
    return 0 # EX__SUCCESS
else
    sudo_main "$@"
    exit $?
fi
