Last active
May 13, 2025 14:36
-
-
Save cyberofficial/ff3ba83361f1a0f12b954f0706028a2c to your computer and use it in GitHub Desktop.
ProotSetUp.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠ | |
# Make sure to back up your proot system before using. | |
# proot-distro backup debian --output "yourfilename.tar" | |
# Always recommend to back up your files first. | |
# ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠ | |
# If you are just starting up with Termux and want to set up a VNC server with LXDE desktop environment, run the following commands: | |
# * Install Termux from F-Droid or Play Store (F-Droid is recommended) | |
# F-Droid: https://f-droid.org/en/packages/com.termux/ | |
# * Install proot-distro from Termux's package manager | |
# - You can do this by running: | |
# pkg install proot-distro | |
# (it's recommended to update your Termux packages first by running pkg update && pkg upgrade) | |
# * Install Debian using proot-distro | |
# - You can do this by running: | |
# proot-distro install debian | |
# * Log into the Debian proot environment | |
# - You can do this by running: | |
# proot-distro login debian | |
# After that, you can run the script below to set up a VNC server with LXDE desktop environment via curl or wget, just make sure to run it as root inside the proot environment. | |
# You can run this by doing: | |
# bash <(curl -fsSL https://gist.githubusercontent.com/cyberofficial/ff3ba83361f1a0f12b954f0706028a2c/raw/ProotSetUpVnc.sh) | |
# -or- | |
# bash <(wget -qO- https://gist.githubusercontent.com/cyberofficial/ff3ba83361f1a0f12b954f0706028a2c/raw/ProotSetUpVnc.sh) | |
# This requires Termux + Proot-Distro + Debian | |
# If you encounter issues, please let me know or by commenting. | |
# The Script will auto setup most things | |
# This script sets up a lightweight LXDE desktop and TightVNC server | |
# for a NON-ROOT user inside a Termux proot Debian environment. | |
# It manages user creation, sudo installation/config, configuration, | |
# and provides options for reinstallation, purification, and reconfiguration. | |
# It uses a config file (/root/vnc_setup_config) to track the user and VNC display. | |
# Exit immediately if a command exits with a non-zero status. | |
set -e | |
# --- Configuration --- | |
DESKTOP_ENV="lxde" # Lightweight desktop environment to install | |
VNC_SERVER="tightvncserver" # VNC server package | |
RESOLUTION="1920x1080" # Desired VNC resolution | |
# DISPLAY_NUM and VNC_PORT are now determined dynamically and stored in config | |
START_SCRIPT="start-vnc.sh" # Name of the VNC start script | |
STOP_SCRIPT="stop-vnc.sh" # Name of the VNC stop script | |
USER_CONFIG_FILE="/root/vnc_setup_config" # File to store the desktop username and VNC display | |
CREATED_USERNAME_VAR="VNC_DESKTOP_USER" # Variable name for the username in config file | |
CREATED_DISPLAY_VAR="VNC_DISPLAY_NUM" # Variable name for the display number in config file | |
# PACKAGES_TO_INSTALL lists packages specific to the desktop/VNC setup, NOT core utilities like sudo | |
# sudo is installed explicitly in install_packages | |
PACKAGES_TO_INSTALL="$DESKTOP_ENV $VNC_SERVER lxterminal xterm" | |
# Retry parameters for apt operations | |
MAX_APT_RETRIES=5 | |
APT_RETRY_DELAY=15 # seconds | |
echo "--- LXDE Desktop and TightVNC Setup Script for Termux Proot Debian ---" | |
# --- Check Environment --- | |
if [ "$(whoami)" != "root" ]; then | |
echo "Error: This script must be run as root inside the proot environment." | |
echo "Please log into Debian as root using 'proot-distro login debian' and run the script." | |
exit 1 | |
fi | |
# Check if apt is available | |
if ! command -v apt &> /dev/null; then | |
echo "Error: 'apt' command not found. Are you sure you are running this inside the Debian proot environment?" | |
exit 1 | |
fi | |
# --- Global Variables (populated by detection/actions) --- | |
VNC_DESKTOP_USER="" # Will store the username from config or newly created | |
VNC_DISPLAY_NUM="" # Will store the VNC display number from config or newly assigned | |
CONFIG_USER_EXISTS=false # Does the user mentioned in the config file actually exist? | |
CONFIG_FILE_EXISTS=false # Does the config file itself exist? | |
# --- Functions --- | |
# Helper function for retrying commands, specifically designed for apt | |
retry_apt_command() { | |
local cmd=("$@") | |
local attempt=1 | |
local success=0 | |
while [ "$attempt" -le "$MAX_APT_RETRIES" ]; do | |
echo "Attempt $attempt/$MAX_APT_RETRIES: Running apt command '${cmd[*]}'..." | |
# Run command with -qq to suppress some output during retries unless it fails | |
# Using set +e temporarily so the retry logic can handle failures | |
set +e | |
# Redirect stderr of the apt command to stdout for easier logging in the loop | |
if "${cmd[@]}" 2>&1; then | |
success=1 | |
set -e # Restore set -e | |
break | |
else | |
set -e # Restore set -e before printing error and sleeping | |
echo "Apt command failed (exit code $?). Retrying in $APT_RETRY_DELAY seconds..." >&2 # Print to stderr | |
if [ "$attempt" -lt "$MAX_APT_RETRIES" ]; then | |
sleep "$APT_RETRY_DELAY" | |
attempt=$((attempt + 1)) | |
# Clear potential locks before retrying apt command | |
cleanup_apt_locks | |
else | |
# Last attempt failed | |
break | |
fi | |
fi | |
done | |
if [ "$success" -eq 0 ]; then | |
echo "Apt command failed after $MAX_APT_RETRIES attempts: '${cmd[*]}'" >&2 | |
return 1 # Indicate failure | |
fi | |
return 0 # Indicate success | |
} | |
# Function to clean up apt lock files | |
cleanup_apt_locks() { | |
# This function is called within retry_apt_command, avoid infinite recursion | |
# by checking for already running cleanup messages. | |
if [[ "$BASH_COMMAND" == *cleanup_apt_locks* && "$BASH_LINENO" -ne "${BASH_LINENO[0]}" ]]; then | |
# We are already inside a cleanup_apt_locks call deeper in the stack | |
return 0 | |
fi | |
# Add a check to avoid printing "Checking for and removing..." repeatedly during retries | |
# unless it's the first call in a sequence. | |
if [ "$APT_CLEANUP_RUNNING" != "true" ]; then | |
echo "Checking for and removing potentially stale apt lock files..." | |
export APT_CLEANUP_RUNNING="true" # Set a flag | |
# List of common apt lock files and directories | |
LOCK_PATHS=( | |
"/var/lib/dpkg/lock" | |
"/var/lib/apt/lists/lock" | |
"/var/cache/apt/archives/lock" | |
"/var/lib/dpkg/lock-frontend" | |
"/var/lib/apt/lists/lock-frontend" | |
) | |
for lock_path in "${LOCK_PATHS[@]}"; do | |
if [ -e "$lock_path" ]; then # -e checks for existence of file or directory | |
echo " Removing lock: $lock_path" | |
rm -rf "$lock_path" || echo "Warning: Could not remove $lock_path" | |
fi | |
done | |
echo "Apt lock cleanup complete." | |
unset APT_CLEANUP_RUNNING # Unset the flag | |
fi | |
# Avoid extra blank line if called mid-retry | |
# echo "" | |
} | |
# Function to stop the VNC server for a given user and display | |
# Note: This function stops a *specific* display. The user's stop script handles 'all'. | |
stop_vnc_server() { | |
local user_to_stop="$1" # User whose VNC server should be stopped | |
local display_to_stop="$2" # Specific display number (e.g., :1) | |
if [ -z "$user_to_stop" ] || [ -z "$display_to_stop" ]; then | |
echo "Cannot stop VNC server: User or display not specified." | |
return 1 | |
fi | |
if ! id -u "$user_to_stop" > /dev/null 2>&1; then | |
echo "Cannot stop VNC server: User '$user_to_stop' does not exist." | |
return 1 | |
fi | |
echo "Attempting to stop VNC server for user '$user_to_stop' on display $display_to_stop..." | |
# Find the PID of the VNC server process for the specific user and display | |
# Use pgrep on the actual command name, not the argument string, for reliability | |
VNC_PID=$(pgrep -u "$user_to_stop" -f "Xtightvnc .* $display_to_stop") | |
# Remove lock files and X11 unix sockets for this display (in /tmp only) | |
local display_num_only="${display_to_stop#:}" | |
local lock_file="/tmp/.X${display_num_only}-lock" | |
local unix_socket="/tmp/.X11-unix/X${display_num_only}" | |
if [ -f "$lock_file" ]; then | |
echo "Removing lock file: $lock_file" | |
rm -f "$lock_file" | |
fi | |
if [ -e "$unix_socket" ]; then | |
echo "Removing X11 unix socket: $unix_socket" | |
rm -f "$unix_socket" | |
fi | |
if [ -n "$VNC_PID" ]; then | |
echo "Found VNC server process (PID: $VNC_PID). Sending kill signal via vncserver command..." | |
set +e | |
if runuser -l "$user_to_stop" -c "export HOME='$user_home' && vncserver -kill $display_to_stop"; then | |
echo "VNC server stop command successful." | |
sleep 3 | |
if pgrep -P "$VNC_PID" > /dev/null || ps -p "$VNC_PID" > /dev/null; then | |
echo "Warning: VNC server process $VNC_PID might still be running after stop command. Attempting direct kill..." | |
kill "$VNC_PID" || true | |
sleep 2 | |
if pgrep -P "$VNC_PID" > /dev/null || ps -p "$VNC_PID" > /dev/null; then | |
echo "Warning: VNC server process $VNC_PID might *still* be running after kill signal. Manual intervention may be needed." | |
fi | |
fi | |
else | |
echo "Warning: Failed to stop VNC server using 'vncserver -kill' as user. Attempting direct kill of PID $VNC_PID..." | |
kill "$VNC_PID" || true | |
sleep 2 | |
if pgrep -P "$VNC_PID" > /dev/null || ps -p "$VNC_PID" > /dev/null; then | |
echo "Warning: VNC server process $VNC_PID might still be running after kill signal. Attempting kill -9..." | |
kill -9 "$VNC_PID" || true | |
fi | |
fi | |
set -e | |
else | |
echo "No VNC server found running for user '$user_to_stop' on display $display_to_stop." | |
fi | |
} | |
# Function to find the next available VNC display number for a user | |
find_available_display() { | |
local user_to_check="$1" | |
if [ -z "$user_to_check" ]; then | |
echo "Error: Cannot find available display: No user specified." | |
return 1 | |
fi | |
if ! id -u "$user_to_check" > /dev/null 2>&1; then | |
echo "Error: Cannot find available display: User '$user_to_check' does not exist." | |
return 1 | |
fi | |
local display=1 | |
local max_display_check=100 # Prevent infinite loop | |
echo "Searching for available VNC display for user '$user_to_check'..." | |
while [ "$display" -le "$max_display_check" ]; do | |
# Check if a VNC server process is running for this user on this display | |
if ! pgrep -u "$user_to_check" -f "Xtightvnc :$display" > /dev/null; then | |
# Display is available | |
echo "Found available display: :$display" | |
VNC_DISPLAY_NUM=":$display" # Set global variable | |
return 0 # Success | |
fi | |
((display++)) | |
done | |
echo "Error: Could not find an available VNC display up to :$max_display_check for user '$user_to_check'." | |
return 1 # Failure | |
} | |
# Function to remove user-specific VNC configuration and scripts | |
cleanup_user_vnc_config() { | |
local user_to_clean="$1" | |
if [ -z "$user_to_clean" ]; then | |
echo "Cannot cleanup user VNC config: No user specified." | |
return 1 | |
fi | |
if ! id -u "$user_to_clean" > /dev/null 2>&1; then | |
echo "Cannot cleanup user VNC config: User '$user_to_clean' does not exist. Skipping config cleanup." | |
return 0 | |
fi | |
local user_home="$(eval echo ~$user_to_clean)" # Get the actual user home dir | |
if [ ! -d "$user_home" ]; then | |
echo "Cannot cleanup user VNC config: Home directory for user '$user_to_clean' not found ($user_home). Skipping config cleanup." | |
return 1 | |
fi | |
local vnc_user_dir="$user_home/.vnc" | |
local user_start_script="$user_home/$START_SCRIPT" | |
local user_stop_script="$user_home/$STOP_SCRIPT" | |
echo "Cleaning up VNC configuration and scripts for user '$user_to_clean' in '$user_home'..." | |
# Remove .vnc directory | |
if [ -d "$vnc_user_dir" ]; then | |
echo "Removing VNC configuration directory: $vnc_user_dir" | |
rm -rf "$vnc_user_dir" | |
fi | |
# Remove start/stop scripts | |
if [ -f "$user_start_script" ]; then | |
echo "Removing start script: $user_start_script" | |
rm -f "$user_start_script" | |
fi | |
if [ -f "$user_stop_script" ]; then | |
echo "Removing stop script: $user_stop_script" | |
rm -f "$user_stop_script" | |
fi | |
echo "User VNC configuration and scripts cleanup complete." | |
} | |
# Function to remove installed packages (specific to desktop/VNC, not core) | |
remove_packages() { | |
echo "Removing desktop/VNC packages: $PACKAGES_TO_INSTALL" | |
# Use --purge to also remove configuration files | |
# Attempt removal of packages listed in PACKAGES_TO_INSTALL, ignore failure if they aren't installed | |
# Use retry logic for the remove command | |
if retry_apt_command apt remove --purge -y $PACKAGES_TO_INSTALL; then | |
echo "Desktop/VNC Package removal complete." | |
else | |
echo "Warning: Failed to remove all desktop/VNC packages after retries." | |
# Don't exit, let the script continue cleanup if possible | |
fi | |
# Autoremove might also have transient issues, add retry | |
if retry_apt_command apt autoremove -y; then | |
echo "Autoremove complete." | |
else | |
echo "Warning: Failed to complete autoremove after retries." | |
fi | |
} | |
# Function to update package lists and install necessary packages | |
install_packages() { | |
echo "--- Preparing for Package Operations ---" | |
# cleanup_apt_locks is called within retry_apt_command | |
echo "Updating package lists..." | |
# Use retry logic for the update command | |
if ! retry_apt_command apt update; then | |
echo "Error: Failed to update apt lists after retries. Cannot proceed with installation." | |
exit 1 | |
fi | |
# Explicitly install sudo if not present - it's a core utility for the user | |
echo "Ensuring sudo is installed..." | |
# Use retry logic for sudo install | |
if ! retry_apt_command apt install -y sudo --fix-missing; then | |
echo "Error: Failed to install sudo after retries. Cannot proceed." | |
exit 1 | |
fi | |
# Ensure sudoers configuration allows the sudo group | |
ensure_sudo_config | |
echo "Installing required desktop/VNC packages: $PACKAGES_TO_INSTALL" | |
# Use retry logic for desktop/VNC install | |
# Use --fix-missing to try and recover from interrupted downloads | |
if ! retry_apt_command apt install -y --fix-missing $PACKAGES_TO_INSTALL; then | |
echo "Error: Failed to install desktop/VNC packages after retries. Cannot proceed." | |
exit 1 | |
fi | |
echo "Package installation complete." | |
} | |
# Function to ensure the sudo group has permissions in sudoers config | |
ensure_sudo_config() { | |
echo "Ensuring sudo group has necessary permissions..." | |
local sudoers_file="/etc/sudoers" | |
local sudoers_d_dir="/etc/sudoers.d" | |
local custom_config_file="$sudoers_d_dir/99-custom-sudoers" | |
local sudo_rule="%sudo ALL=(ALL:ALL) ALL" | |
local include_rule="#includedir /etc/sudoers.d" # Common way to include the directory | |
# --- Step 1: Ensure the custom sudoers file for %sudo group exists and is correct --- | |
if [ ! -f "$custom_config_file" ] || ! grep -q "^$sudo_rule$" "$custom_config_file"; then | |
echo "Creating/Updating custom sudoers file '$custom_config_file' for '%sudo' group..." | |
# Ensure the directory exists | |
mkdir -p "$sudoers_d_dir" | |
# Create the custom config file | |
echo "$sudo_rule" > "$custom_config_file" | |
# Set correct permissions (0440 is recommended for sudoers files) | |
chmod 0440 "$custom_config_file" | |
chown root:root "$custom_config_file" | |
echo "Created '$custom_config_file'." | |
else | |
echo "Custom sudoers file '$custom_config_file' for '%sudo' group already exists and is correct." | |
fi | |
# --- Step 2: Ensure /etc/sudoers includes the sudoers.d directory --- | |
# Check if any line exists that includes 'sudoers.d' (commented or uncommented) | |
# Use -E for extended regex, more portable than -P | |
if grep -qE '^#includedir /etc/sudoers.d' "$sudoers_file" 2>/dev/null; then | |
echo "'sudoers.d' include directive already present in '$sudoers_file'." | |
else | |
# If no such line is found, append the recommended include directive | |
echo "Adding '$sudoers_d_dir' include directive to '$sudoers_file'." | |
if [ -w "$sudoers_file" ]; then | |
echo "$include_rule" >> "$sudoers_file" | |
echo "" >> "$sudoers_file" | |
echo "Added include directive to '$sudoers_file'." | |
else | |
echo "Error: '$sudoers_file' is not writable by root. Cannot add include directive." | |
echo "Manual intervention is required: Add the line '$include_rule' to '$sudoers_file'." | |
return 1 | |
fi | |
fi | |
echo "Sudo configuration check/fix complete." | |
echo "Note: For sudo permission changes to take full effect, you might need to log out and log back in as the user." | |
} | |
# Function to create the normal user and set their login password | |
create_normal_user() { | |
local username="" | |
echo "" | |
echo "--- Creating Non-Root Desktop User ---" | |
while true; do | |
read -p "Enter the desired username for the desktop environment: " username | |
if [ -z "$username" ]; then | |
echo "Username cannot be empty." | |
elif [[ ! "$username" =~ ^[a-z_][a-z0-9_-]*$ ]]; then | |
echo "Invalid username. Must start with a lowercase letter or underscore, followed by lowercase letters, numbers, underscores, or hyphens." | |
echo "Examples: user, myuser, dev_user" | |
elif id -u "$username" > /dev/null 2>&1; then | |
echo "Error: User '$username' already exists. Please choose a different username." | |
else | |
break # Valid and non-existent username entered | |
fi | |
done | |
echo "Creating user '$username'..." | |
# Ensure sudo group exists | |
if ! getent group sudo >/dev/null; then | |
echo "'sudo' group does not exist. Creating it..." | |
groupadd sudo | |
fi | |
# Create user and add to sudo group immediately | |
if adduser --disabled-password --gecos "" "$username"; then | |
echo "User '$username' created." | |
echo "Adding user '$username' to the 'sudo' group..." | |
usermod -aG sudo "$username" | |
echo "User '$username' added to sudo group." | |
else | |
echo "Error: Failed to create user '$username'. Aborting." | |
exit 1 | |
fi | |
echo "Setting login password for user '$username'..." | |
echo "Please enter and verify the login password for user '$username':" | |
passwd "$username" | |
echo "Login password set for user '$username' (or attempted)." | |
echo "" | |
echo "IMPORTANT: To ensure sudo works immediately, please log out and log back in as '$username', or run: exec su - $username" | |
echo "This will refresh group membership and allow sudo to work without needing 'newgrp sudo'." | |
# Store the created username in the config file - display number added later | |
# Overwrite the file as this is fresh creation | |
echo "$CREATED_USERNAME_VAR=$username" > "$USER_CONFIG_FILE" | |
VNC_DESKTOP_USER="$username" # Set global variable | |
CONFIG_USER_EXISTS=true # User was just created | |
CONFIG_FILE_EXISTS=true # Config file was just created | |
echo "Setting login password for user '$username'..." | |
# Prompt and set the login password for the new user | |
# Use expected prompts to feed password | |
# Read password *before* piping to passwd to handle interaction correctly | |
echo "Please enter and verify the login password for user '$username':" | |
passwd "$username" | |
# Check passwd exit status? passwd can fail, but usually prompts on tty | |
# For piped input, success/failure is less obvious. Assume success if no pipe error. | |
echo "Login password set for user '$username' (or attempted)." | |
# Store the created username in the config file - display number added later | |
# Overwrite the file as this is fresh creation | |
echo "$CREATED_USERNAME_VAR=$username" > "$USER_CONFIG_FILE" | |
VNC_DESKTOP_USER="$username" # Set global variable | |
CONFIG_USER_EXISTS=true # User was just created | |
CONFIG_FILE_EXISTS=true # Config file was just created | |
echo "Configuration updated to use user '$VNC_DESKTOP_USER'." | |
} | |
# Function to prompt whether to create a user | |
prompt_create_user() { | |
# Only prompt if VNC_DESKTOP_USER is not already set globally (e.g., from config file) | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "" | |
echo "A dedicated non-root user is recommended for the desktop environment." | |
echo "If you skip creating a user now, the VNC desktop setup will be incomplete." | |
read -p "Do you want to create the primary desktop user account now? (y/N): " -n 1 -r | |
echo "" # Move to a new line | |
if [[ "$REPLY" =~ ^[Yy]$ ]]; then | |
# Call the actual user creation function | |
create_normal_user | |
else | |
echo "Skipping user creation." | |
# VNC_DESKTOP_USER remains unset or keeps old value, CONFIG_USER_EXISTS is false | |
# Ensure config file is removed if user was not created but maybe a stale one existed | |
if [ -f "$USER_CONFIG_FILE" ]; then | |
echo "Removing user config file as user creation was skipped: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" || true | |
CONFIG_FILE_EXISTS=false | |
VNC_DESKTOP_USER="" # Clear global | |
VNC_DISPLAY_NUM="" # Clear global | |
fi | |
return 1 # Indicate failure (user not created) | |
fi | |
else | |
echo "Using existing configured user '$VNC_DESKTOP_USER'." | |
# If we reach here, the user exists and is configured, so we succeed | |
return 0 | |
fi | |
} | |
# Function to set the VNC password for the target user | |
set_vnc_password() { | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Cannot set VNC password. No valid desktop user is configured." | |
return 1 | |
fi | |
local user_to_configure="$VNC_DESKTOP_USER" | |
local user_home="$(eval echo ~$user_to_configure)" | |
local vnc_user_dir="$user_home/.vnc" | |
echo "" | |
echo "--- Setting VNC Password for user '$user_to_configure' ---" | |
echo "You will be prompted to set a VNC password for this user." | |
echo "This password is required to connect from a VNC client." | |
echo "You might be asked for a 'view-only' password; just press Enter if you don't want one." | |
# Need to do interactive password setting via runuser | |
# The 'vncpasswd' command needs a TTY for interactive prompts | |
# 'runuser -l user -c command' usually provides a pseudo-tty | |
# Ensure the user's .vnc directory exists before running vncpasswd as the user | |
mkdir -p "$vnc_user_dir" | |
chown "$user_to_configure":"$user_to_configure" "$vnc_user_dir" | |
if runuser -l "$user_to_configure" -c "export HOME='$user_home' && vncpasswd"; then | |
echo "VNC password set for user '$user_to_configure'." | |
else | |
echo "Error setting VNC password for user '$user_to_configure'." | |
return 1 | |
fi | |
} | |
# Function to configure the xstartup file for the target user | |
configure_xstartup() { | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Cannot configure xstartup. No valid desktop user is configured." | |
return 1 | |
fi | |
local user_to_configure="$VNC_DESKTOP_USER" | |
local user_home="$(eval echo ~$user_to_configure)" | |
local vnc_user_dir="$user_home/.vnc" | |
local xstartup_file="$vnc_user_dir/xstartup" | |
echo "Configuring VNC xstartup file for user '$user_to_configure': $xstartup_file" | |
# Create the user's .vnc directory if it doesn't exist | |
mkdir -p "$vnc_user_dir" | |
chown "$user_to_configure":"$user_to_configure" "$vnc_user_dir" | |
# Backup existing xstartup if it exists | |
if [ -f "$xstartup_file" ]; then | |
echo "Backing up existing $xstartup_file to ${xstartup_file}.bak" | |
mv "$xstartup_file" "${xstartup_file}.bak" | |
fi | |
# Create the new xstartup file to launch LXDE | |
# IMPORTANT: This file is written by root but will be EXECUTED by vncserver as the target user | |
# Removed the problematic 'exec newgrp sudo' line | |
cat << EOF > "$xstartup_file" | |
#!/bin/sh | |
# Start the desktop environment | |
# Ensure paths are correct, especially for Termux proot | |
unset SESSION_MANAGER | |
unset DBUS_SESSION_BUS_ADDRESS | |
# Use startlxde - this should be in the user's PATH after installing lxde | |
startlxde & | |
# Add any other commands you want to run on session start here | |
# Example: Start a terminal | |
# lxterminal & | |
# NOTE: This script is executed by the vncserver command running as the user. | |
# Make sure the command that starts your desktop environment (like startlxde) | |
# runs in the background by ending with '&'). | |
# Standard X startup stuff | |
# Check for global xstartup but it's unlikely to exist/be relevant in proot | |
[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup | |
# Load user Xresources if they exist | |
[ -x \$HOME/.Xresources ] && xrdb \$HOME/.Xresources | |
# Ensure the user owns the file after root creates it | |
# This is done outside the EOF block by the root script | |
EOF | |
# Make xstartup executable | |
chmod +x "$xstartup_file" | |
# Ensure the user owns the file and directory | |
chown "$user_to_configure":"$user_to_configure" "$xstartup_file" | |
echo "xstartup file configured for user '$user_to_configure'." | |
echo "Removed problematic 'exec newgrp sudo' from xstartup." | |
} | |
# Function to create the start and stop scripts in the user's home | |
# These scripts will source the config file to get the display number | |
create_user_scripts() { | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Cannot create user scripts. No valid desktop user is configured." | |
return 1 | |
fi | |
if [ -z "$VNC_DISPLAY_NUM" ]; then | |
echo "Error: Cannot create user scripts. VNC display number is not set." | |
return 1 | |
fi | |
local user_to_configure="$VNC_DESKTOP_USER" | |
local user_home="$(eval echo ~$user_to_configure)" | |
local user_start_script="$user_home/$START_SCRIPT" | |
local user_stop_script="$user_home/$STOP_SCRIPT" | |
local current_vnc_port=$((5900 + ${VNC_DISPLAY_NUM#:*})) | |
echo "" | |
echo "Creating start script: $user_start_script for user '$user_to_configure' (Display $VNC_DISPLAY_NUM, Port $current_vnc_port)" | |
# Updated start script: try to kill, remove lock, then start VNC server, and clean up /tmp as well | |
cat << 'EOF' > "$user_start_script" | |
#!/bin/bash | |
# Script to start the TightVNC server for LXDE desktop | |
USER_CONFIG_FILE="/root/vnc_setup_config" | |
if [ -f "$USER_CONFIG_FILE" ]; then | |
eval "$(grep "^VNC_DESKTOP_USER=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
eval "$(grep "^VNC_DISPLAY_NUM=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
else | |
echo "Error: Configuration file not found at $USER_CONFIG_FILE." | |
exit 1 | |
fi | |
export HOME="$(eval echo ~$VNC_DESKTOP_USER)" | |
echo "Select VNC resolution:" | |
echo " 1) 480p (854x480)" | |
echo " 2) 720p (1280x720)" | |
echo " 3) 1080p (1920x1080)" | |
echo " 4) Z Fold Landscape (2208x1768)" | |
echo " 5) Z Fold Portrait (1768x2208)" | |
echo " 6) Custom" | |
read -p "Enter choice [1-6]: " res_choice | |
case "$res_choice" in | |
1) RESOLUTION="854x480" ;; | |
2) RESOLUTION="1280x720" ;; | |
3) RESOLUTION="1920x1080" ;; | |
4) RESOLUTION="2208x1768" ;; | |
5) RESOLUTION="1768x2208" ;; | |
6) | |
read -p "Enter custom resolution (e.g. 1600x900): " RESOLUTION | |
;; | |
*) | |
echo "Invalid choice, defaulting to 1920x1080" | |
RESOLUTION="1920x1080" | |
;; | |
esac | |
DEFAULT_DISPLAY="${VNC_DISPLAY_NUM:-:1}" | |
read -p "Enter VNC display number to use (e.g. :1), or press Enter for [$DEFAULT_DISPLAY]: " DISPLAY_NUM_RAW | |
DISPLAY_NUM="${DISPLAY_NUM_RAW:-$DEFAULT_DISPLAY}" | |
# Ensure display number starts with colon | |
if [[ ! "$DISPLAY_NUM" =~ ^: ]]; then | |
DISPLAY_NUM=":$DISPLAY_NUM" | |
fi | |
VNC_PORT=$((5900 + ${DISPLAY_NUM#:*})) | |
LOCK_FILE="$HOME/.X${DISPLAY_NUM#:}-lock" | |
GLOBAL_LOCK="/.X${DISPLAY_NUM#:}-lock" | |
TMP_LOCK="/tmp/.X${DISPLAY_NUM#:}-lock" | |
# Try to kill any running VNC server on this display | |
echo "Attempting to kill any existing VNC server on display $DISPLAY_NUM..." | |
vncserver -kill "$DISPLAY_NUM" 2>/dev/null || true | |
# Remove lock file if it still exists (in /tmp only) | |
if [ -f "$TMP_LOCK" ]; then | |
echo "Removing stale lock file: $TMP_LOCK" | |
rm -f "$TMP_LOCK" | |
fi | |
# Remove X11 unix socket if present (for this display) in /tmp only | |
if [ -d "/tmp/.X11-unix" ]; then | |
echo "Removing X11 unix socket for display $DISPLAY_NUM from /tmp/.X11-unix" | |
rm -f "/tmp/.X11-unix/X${DISPLAY_NUM#:}" 2>/dev/null || true | |
fi | |
echo "Starting VNC server on display $DISPLAY_NUM ($RESOLUTION) for user $(whoami)..." | |
echo "Connect your VNC client to <your_phone_ip>:$VNC_PORT" | |
if pgrep -u "$(whoami)" -f "Xtightvnc ${DISPLAY_NUM#:}" > /dev/null; then | |
echo "VNC server is already running on display $DISPLAY_NUM for $(whoami)." | |
else | |
vncserver -geometry "$RESOLUTION" "$DISPLAY_NUM" & | |
# Use correct log file name: $HOME/.vnc/$(hostname)${DISPLAY_NUM}.log | |
echo "VNC server start command issued. Check \$HOME/.vnc/$(hostname)${DISPLAY_NUM}.log for startup status." | |
echo "Remember to stop the server when done using the 'stop-vnc.sh' script." | |
fi | |
EOF | |
chmod +x "$user_start_script" | |
chown "$user_to_configure":"$user_to_configure" "$user_start_script" | |
echo "Start script created: $user_start_script" | |
echo "" | |
echo "Creating stop script: $user_stop_script for user '$user_to_configure' (Display $VNC_DISPLAY_NUM)" | |
# Improved stop script: kills vncserver, removes lock, removes unix socket (including /tmp), and kills stuck Xtightvnc if needed | |
cat << 'EOF' > "$user_stop_script" | |
#!/bin/bash | |
# Script to stop the TightVNC server for the current user | |
USER_CONFIG_FILE="/root/vnc_setup_config" | |
if [ -f "$USER_CONFIG_FILE" ]; then | |
eval "$(grep "^VNC_DESKTOP_USER=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
else | |
echo "Error: Configuration file not found at $USER_CONFIG_FILE." | |
exit 1 | |
fi | |
export HOME="$(eval echo ~$VNC_DESKTOP_USER)" | |
read -p "Enter the display number to stop (just the number, e.g. 1): " DISPLAY_NUM | |
if [[ ! "$DISPLAY_NUM" =~ ^[0-9]+$ ]]; then | |
echo "Invalid display number." | |
exit 1 | |
fi | |
DISPLAY=":$DISPLAY_NUM" | |
LOCK_FILE="$HOME/.X${DISPLAY_NUM}-lock" | |
GLOBAL_LOCK="/.X${DISPLAY_NUM}-lock" | |
TMP_LOCK="/tmp/.X${DISPLAY_NUM}-lock" | |
UNIX_SOCKET="/.X11-unix/X${DISPLAY_NUM}" | |
TMP_UNIX_SOCKET="/tmp/.X11-unix/X${DISPLAY_NUM}" | |
echo "Stopping VNC server on display $DISPLAY..." | |
if vncserver -kill "$DISPLAY"; then | |
echo "TightVNC server on display $DISPLAY stopped successfully." | |
else | |
echo "Could not stop TightVNC server on display $DISPLAY with vncserver -kill." | |
fi | |
# Remove lock file in /tmp only | |
if [ -f "$TMP_LOCK" ]; then | |
echo "Removing lock file: $TMP_LOCK" | |
rm -f "$TMP_LOCK" | |
fi | |
# Remove X11 unix socket in /tmp only | |
if [ -e "$TMP_UNIX_SOCKET" ]; then | |
echo "Removing X11 unix socket: $TMP_UNIX_SOCKET" | |
rm -f "$TMP_UNIX_SOCKET" | |
fi | |
# Kill any remaining Xtightvnc process for this display | |
VNC_PID=$(pgrep -u "$(whoami)" -f "Xtightvnc .* $DISPLAY") | |
if [ -n "$VNC_PID" ]; then | |
echo "Killing remaining Xtightvnc process ID $VNC_PID" | |
kill -9 "$VNC_PID" || true | |
fi | |
echo "VNC stop script complete for display $DISPLAY." | |
EOF | |
chmod +x "$user_stop_script" | |
chown "$user_to_configure":"$user_to_configure" "$user_stop_script" | |
echo "Stop script created: $user_stop_script" | |
} | |
# Function to create a script that wipes all X lock files (for all users) | |
create_wipe_x_locks_script() { | |
# Try to use the directory of the main script, fallback to /root if not writable or if running in a pipe | |
local script_dir | |
if [ -n "${BASH_SOURCE[0]}" ] && [ "${BASH_SOURCE[0]}" != "" ] && [ "${BASH_SOURCE[0]}" != "bash" ] && [ -d "$(dirname "${BASH_SOURCE[0]}")" ]; then | |
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
else | |
script_dir="/root" | |
fi | |
# If not writable, fallback to /root | |
if [ ! -w "$script_dir" ]; then | |
script_dir="/root" | |
fi | |
local wipe_script="$script_dir/wipe-x-locks.sh" | |
echo "Creating wipe-x-locks.sh in $script_dir" | |
cat << 'EOS' > "$wipe_script" | |
#!/bin/bash | |
# Remove all .X*-lock files, X11 unix sockets, and orphaned Xtightvnc processes | |
echo "Removing all /tmp/.X11-unix/* and /tmp/.X*-lock files (root required)..." | |
rm -rf /tmp/.X11-unix/* 2>/dev/null || true | |
rm -rf /tmp/.X*-lock 2>/dev/null || true | |
echo "Searching and removing all .X*-lock files in common locations..." | |
find / /tmp /home "$HOME" /root -maxdepth 2 -type f -name '.X*-lock' 2>/dev/null -exec rm -f {} \; | |
find / -maxdepth 1 -type f -name '.X*-lock' 2>/dev/null -exec rm -f {} \; | |
echo "Checking for orphaned Xtightvnc processes..." | |
ps aux | grep Xtightvnc | grep -v grep | |
read -p 'Do you want to kill all Xtightvnc processes? (y/N): ' killvnc | |
if [[ "$killvnc" =~ ^[Yy]$ ]]; then | |
pkill -9 Xtightvnc && echo "All Xtightvnc processes killed." | |
else | |
echo "Skipped killing Xtightvnc processes." | |
fi | |
echo "Done. All .X*-lock files and X11 unix sockets removed (if permissions allowed)." | |
EOS | |
chmod +x "$wipe_script" | |
echo "wipe-x-locks.sh created at $wipe_script" | |
} | |
# Function to remove the desktop user | |
remove_user() { | |
local user_to_remove="$1" | |
if [ -z "$user_to_remove" ]; then | |
echo "Cannot remove user: No user specified." | |
return 1 | |
fi | |
if ! id -u "$user_to_remove" > /dev/null 2>&2; then # Check ID, send errors to /dev/null | |
echo "User '$user_to_remove' does not exist. Skipping user removal." | |
# Even if user is gone, clean up the config file referencing them | |
if [ -f "$USER_CONFIG_FILE" ]; then | |
echo "Removing user config file: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" | |
CONFIG_FILE_EXISTS=false | |
fi | |
VNC_DESKTOP_USER="" # Clear global variable | |
VNC_DISPLAY_NUM="" # Clear global | |
CONFIG_USER_EXISTS=false | |
return 0 | |
fi | |
echo "" | |
echo "--- Removing User '$user_to_remove' ---" | |
echo "Warning: This will delete the user account and their home directory ('$(eval echo ~$user_to_remove)')." | |
read -p "Are you sure you want to remove the user '$user_to_remove' and their home directory? (y/N): " -n 1 -r | |
echo "" # Move to a new line | |
if [[ "$REPLY" =~ ^[Yy]$ ]]; then | |
echo "Removing user '$user_to_remove' and their home directory..." | |
# Stop their processes first if possible using the determined display number | |
# Need to ensure VNC_DISPLAY_NUM is set correctly before calling stop_vnc_server | |
local display_num_to_stop="$VNC_DISPLAY_NUM" # Use current global if available | |
if [ -z "$display_num_to_stop" ] && [ -f "$USER_CONFIG_FILE" ]; then | |
# If global isn't set, try sourcing just the display variable from the file *before* removing the user/file | |
# Use eval to source to set the variable in the current shell | |
eval "$(grep "^$CREATED_DISPLAY_VAR=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
display_num_to_stop="$VNC_DISPLAY_NUM" # VNC_DISPLAY_NUM might now be set | |
fi | |
# Attempt to stop the specific server if a display was found | |
if [ -n "$display_num_to_stop" ]; then | |
stop_vnc_server "$user_to_remove" "$display_num_to_stop" || true # Attempt stop but continue | |
else | |
echo "Warning: Could not determine specific VNC display for user '$user_to_remove'. Cannot attempt graceful stop." | |
echo "Attempting to kill all processes for user '$user_to_remove' before removal..." | |
# Aggressive kill for the user's processes if graceful stop isn't possible | |
pkill -u "$user_to_remove" || true | |
sleep 2 # Give processes a moment to die | |
fi | |
# Use deluser --remove-home to remove user and their home directory | |
# Removed --force as it's not supported | |
if deluser --remove-home "$user_to_remove"; then | |
echo "User '$user_to_remove' removed successfully." | |
# Remove the config file | |
if [ -f "$USER_CONFIG_FILE" ]; then | |
echo "Removing user config file: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" | |
CONFIG_FILE_EXISTS=false | |
fi | |
VNC_DESKTOP_USER="" # Clear global variable | |
VNC_DISPLAY_NUM="" # Clear global | |
CONFIG_USER_EXISTS=false | |
else | |
# Modified error message as --force is removed | |
echo "Error: Failed to remove user '$user_to_remove' using 'deluser --remove-home'." | |
echo "Manual cleanup may be required (e.g. 'deluser --remove-home $user_to_remove' or check processes owned by their UID)." | |
return 1 # Indicate failure | |
fi | |
else | |
echo "User removal aborted." | |
return 1 # Indicate user was NOT removed | |
fi | |
} | |
# Function to prompt whether to remove the detected user | |
prompt_remove_user() { | |
# Only prompt if a user was detected in the config file and still exists | |
if [ -n "$VNC_DESKTOP_USER" ] && [ "$CONFIG_USER_EXISTS" = true ]; then | |
echo "" | |
echo "An existing desktop user '$VNC_DESKTOP_USER' was detected." | |
read -p "Do you want to remove this user account and their home directory as part of the cleanup? (y/N): " -n 1 -r | |
echo "" # Move to a new line | |
if [[ "$REPLY" =~ ^[Yy]$ ]]; then | |
remove_user "$VNC_DESKTOP_USER" # This function updates globals and removes config file | |
else | |
echo "Keeping user '$VNC_DESKTOP_USER'." | |
# User is kept, but config/packages are being handled by the calling function flow | |
fi | |
else | |
echo "No existing valid user detected to remove." | |
fi | |
} | |
# Function to fix permissions for the user's VNC files and scripts | |
fix_user_vnc_permissions() { | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Cannot fix permissions. No valid desktop user is configured." | |
return 1 | |
fi | |
local user_to_fix="$VNC_DESKTOP_USER" | |
local user_home="$(eval echo ~$user_to_fix)" | |
local vnc_user_dir="$user_home/.vnc" | |
local xstartup_file="$vnc_user_dir/xstartup" | |
local passwd_file="$vnc_user_dir/passwd" | |
local user_start_script="$user_home/$START_SCRIPT" | |
local user_stop_script="$user_home/$STOP_SCRIPT" | |
echo "Fixing permissions for VNC files and scripts for user '$user_to_fix' in '$user_home'..." | |
# Fix ownership | |
# Use find for recursive chown, more robust | |
if [ -d "$vnc_user_dir" ]; then find "$vnc_user_dir" -exec chown "$user_to_fix":"$user_to_fix" {} \; || echo "Warning: Failed to change ownership in $vnc_user_dir"; fi | |
if [ -f "$user_start_script" ]; then chown "$user_to_fix":"$user_to_fix" "$user_start_script" || echo "Warning: Failed to change ownership of $user_start_script"; fi | |
if [ -f "$user_stop_script" ]; then chown "$user_to_fix":"$user_to_fix" "$user_stop_script" || echo "Warning: Failed to change ownership of $user_stop_script"; fi | |
# Fix directory and file permissions | |
if [ -d "$vnc_user_dir" ]; then chmod 700 "$vnc_user_dir" || echo "Warning: Failed to set permissions on $vnc_user_dir"; fi # .vnc should only be accessible by the user | |
# Fix permissions on specific files within .vnc explicitly | |
if [ -f "$xstartup_file" ]; then chmod 700 "$xstartup_file" || echo "Warning: Failed to set execute permission on $xstartup_file"; fi # xstartup needs execute | |
if [ -f "$passwd_file" ]; then chmod 600 "$passwd_file" || echo "Warning: Failed to set 600 permission on $passwd_file"; fi # passwd should be private | |
if [ -f "$user_start_script" ]; then chmod 700 "$user_start_script" || echo "Warning: Failed to set execute permission on $user_start_script"; fi # start script needs execute | |
if [ -f "$user_stop_script" ]; then chmod 700 "$user_stop_script" || echo "Warning: Failed to set execute permission on $user_stop_script"; fi # stop script needs execute | |
echo "Permission fixing complete." | |
} | |
# Function to add the 'newgrp sudo' hint to the user's bashrc | |
add_bashrc_sudo_hint() { | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Cannot add bashrc hint. No valid desktop user is configured." | |
return 1 | |
fi | |
local user_to_configure="$VNC_DESKTOP_USER" | |
local user_home="$(eval echo ~$user_to_configure)" | |
local bashrc_file="$user_home/.bashrc" | |
local clean_marker="# --- ProotSetUpVnc.sh login message ---" | |
if [ ! -f "$bashrc_file" ]; then | |
echo "Warning: User '$user_to_configure' does not have a ~/.bashrc file. Cannot add login message." | |
return 1 | |
fi | |
# Remove any previous block from this script and other known legacy login message blocks | |
sed -i "/$clean_marker/,/$clean_marker/d" "$bashrc_file" | |
# Remove legacy/old login message blocks (e.g. Welcome back! and newgrp sudo hints) | |
sed -i '/^echo ".*Welcome back!"$/,/^This might start a new sub-shell where sudo works correctly\./d' "$bashrc_file" | |
sed -i '/^If you need to use.*newgrp sudo/,/^This might start a new sub-shell where sudo works correctly\./d' "$bashrc_file" | |
sed -i '/^If you have sudo issues, log out and log back in to refresh group membership\./d' "$bashrc_file" | |
sed -i '/^If VNC fails to start or stop, run: sudo rm -rf \/.\*; sudo rm -rf \/.\*-lock/d' "$bashrc_file" | |
sed -i '/^If VNC fails to start or stop, run: sudo rm -rf \/\*; sudo rm -rf \*-lock/d' "$bashrc_file" | |
sed -i '/^To activate sudo group membership, you may need to run/d' "$bashrc_file" | |
cat <<'EOMSG' >> "$bashrc_file" | |
$clean_marker | |
echo "" | |
echo "Welcome back!" | |
echo "" | |
echo "Sudo tips:" | |
echo "- If you have sudo issues, log out and log back in to refresh group membership." | |
echo "- If 'sudo' says you're not in the sudoers file, but 'id' or 'groups' shows you are in 'sudo', run: newgrp sudo" | |
echo "" | |
echo "VNC tips:" | |
echo "- If VNC fails to start or stop, try cleaning X locks:" | |
echo " Normal: rm -rf /tmp/.X11-unix/*; rm -rf /tmp/.X*-lock" | |
echo " Sudo: sudo rm -rf /tmp/.X11-unix/*; sudo rm -rf /tmp/.X*-lock" | |
echo "" | |
echo "Enjoy your session!" | |
$clean_marker | |
EOMSG | |
chown "$user_to_configure":"$user_to_configure" "$bashrc_file" | |
echo "Clean login message added to '$bashrc_file'." | |
} | |
# Function to configure VNC for the user (sets password, xstartup, creates scripts) | |
# Assumes user exists and VNC_DESKTOP_USER and CONFIG_USER_EXISTS are set | |
configure_vnc_user_setup() { | |
if [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Cannot configure VNC setup. No valid desktop user is configured." | |
return 1 | |
fi | |
# Need to find an available display *before* configuring and creating scripts | |
find_available_display "$VNC_DESKTOP_USER" | |
if [ -z "$VNC_DISPLAY_NUM" ]; then | |
echo "Error: Aborting VNC setup as no available display was found." | |
return 1 | |
fi | |
# Save the user and display number to the config file | |
# Overwrite the file to ensure it's clean | |
echo "$CREATED_USERNAME_VAR=$VNC_DESKTOP_USER" > "$USER_CONFIG_FILE" | |
echo "$CREATED_DISPLAY_VAR=$VNC_DISPLAY_NUM" >> "$USER_CONFIG_FILE" | |
CONFIG_FILE_EXISTS=true # Mark config file as existing | |
echo "Updated config file '$USER_CONFIG_FILE' with user and display ($VNC_DESKTOP_USER, $VNC_DISPLAY_NUM)." | |
local current_vnc_port=$((5900 + ${VNC_DISPLAY_NUM#:*})) | |
echo "Configuring VNC for user '$VNC_DESKTOP_USER' on display $VNC_DISPLAY_NUM (Port $current_vnc_port)..." | |
# Now proceed with setting password, creating xstartup and scripts using $VNC_DESKTOP_USER and $VNC_DISPLAY_NUM | |
set_vnc_password | |
configure_xstartup # This template no longer includes 'exec newgrp sudo' | |
create_user_scripts # These scripts will read the display number from the config file | |
fix_user_vnc_permissions "$VNC_DESKTOP_USER" # Ensure correct permissions after creation | |
add_bashrc_sudo_hint # Add the sudo hint to the user's bashrc | |
echo "VNC setup configuration complete for user '$VNC_DESKTOP_USER'." | |
} | |
# --- Prerequisite Check --- | |
check_prerequisites() { | |
# Only check for sudo package | |
if ! dpkg -s sudo &>/dev/null; then | |
echo "==============================================================" | |
echo " Prerequisite Check: Missing required package: sudo" | |
echo "==============================================================" | |
read -p "Would you like to install 'sudo' now? (y/N): " -n 1 -r | |
echo "" | |
if [[ "$REPLY" =~ ^[Yy]$ ]]; then | |
echo "Updating package lists and installing sudo..." | |
apt update && apt install -y sudo | |
if ! dpkg -s sudo &>/dev/null; then | |
echo "Error: Failed to install sudo. Please install it manually." | |
exit 1 | |
fi | |
echo "'sudo' installed successfully." | |
else | |
echo "Please install 'sudo' before running this script." | |
echo "Example: apt update && apt install -y sudo" | |
exit 1 | |
fi | |
fi | |
} | |
# --- Main Logic --- | |
check_prerequisites | |
# Fancy welcome screen for initial install | |
show_initial_welcome() { | |
clear | |
echo "==============================================================" | |
echo " Welcome to the LXDE Desktop + TightVNC Setup " | |
echo "==============================================================" | |
echo "" | |
echo "This script will:" | |
echo " - Install a lightweight LXDE desktop environment" | |
echo " - Install and configure TightVNC server" | |
echo " - Create a non-root user for desktop access" | |
echo " - Set up start/stop scripts for VNC" | |
echo " - Add helpful login messages and tips" | |
echo "" | |
echo "Requirements:" | |
echo " - Termux + proot-distro + Debian" | |
echo " - Run as root inside your proot environment" | |
echo "" | |
echo "Proceeding will make changes to your Debian proot installation." | |
echo "" | |
read -p "Do you wish to continue? (y/N): " -n 1 -r | |
echo "" | |
if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then | |
echo "Aborted by user." | |
exit 0 | |
fi | |
clear | |
} | |
# Always clean apt locks at the beginning | |
# This is also called by retry_apt_command, but calling it once upfront is good practice | |
cleanup_apt_locks | |
# --- Detection --- | |
# Check for existing setup primarily by looking for the config file | |
if [ -f "$USER_CONFIG_FILE" ]; then | |
CONFIG_FILE_EXISTS=true | |
# Source the config file to get VNC_DESKTOP_USER and VNC_DISPLAY_NUM | |
# Adding check before source in case file exists but is empty/malformed | |
if [ -s "$USER_CONFIG_FILE" ]; then # -s checks if file exists and is not empty | |
# Use eval to source the required variables from the file | |
# Use || true in case a variable is missing, so it doesn't stop sourcing the other | |
eval "$(grep "^$CREATED_USERNAME_VAR=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
eval "$(grep "^$CREATED_DISPLAY_VAR=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
else | |
echo "Warning: Config file '$USER_CONFIG_FILE' is empty or invalid. Treating as no user configured via config." | |
# Treat it like no user was configured via this file | |
VNC_DESKTOP_USER="" | |
VNC_DISPLAY_NUM="" | |
fi | |
# Validate if the user mentioned in the config actually exists | |
# Added 2>/dev/null to id check for robustness | |
if [ -n "$VNC_DESKTOP_USER" ] && id -u "$VNC_DESKTOP_USER" > /dev/null 2>/dev/null; then | |
CONFIG_USER_EXISTS=true | |
echo "Existing setup detected: Config file found referencing user '$VNC_DESKTOP_USER', and user exists." | |
if [ -n "$VNC_DISPLAY_NUM" ]; then | |
echo "Configured VNC Display: $VNC_DISPLAY_NUM" | |
else | |
echo "Warning: Configured user '$VNC_DESKTOP_USER' exists, but VNC display number is NOT set in config file." | |
fi | |
elif [ -n "$VNC_DESKTOP_USER" ]; then | |
echo "Existing setup detected: Config file found referencing user '$VNC_DESKTOP_USER', but user does not exist." | |
CONFIG_USER_EXISTS=false # User in config is gone | |
VNC_DESKTOP_USER="" # Clear the global variable as it points to a non-existent user | |
VNC_DISPLAY_NUM="" # Clear the global variable | |
# The config file still exists, indicating a previous attempt | |
else | |
echo "Existing setup detected: Config file found ($USER_CONFIG_FILE) but '$CREATED_USERNAME_VAR' variable is not set or is empty." | |
CONFIG_USER_EXISTS=false # Treat as no user configured | |
VNC_DESKTOP_USER="" # Ensure global variable is empty | |
VNC_DISPLAY_NUM="" # Ensure global variable is empty | |
fi | |
echo "" | |
echo "--- Existing Setup Menu ---" | |
echo "It looks like a VNC setup attempt has been made previously." | |
echo "Configured user: ${VNC_DESKTOP_USER:-<None configured in $USER_CONFIG_FILE>}" | |
echo "Does user exist? ${CONFIG_USER_EXISTS}" | |
if [ -n "$VNC_DISPLAY_NUM" ]; then echo "Configured Display: $VNC_DISPLAY_NUM"; fi | |
echo "" | |
echo "What would you like to do?" | |
echo " (R)einstall: Cleanly remove old setup, install fresh packages, create NEW user (optional), configure NEW VNC display." | |
echo " (P)urify: Only remove the VNC/LXDE packages, configuration, and optionally the user." | |
echo " (C)onfigure: Recreate config files, reset VNC password for the CURRENT configured user (keeps packages/user, finds NEW VNC display)." | |
echo " (F)ix/Refresh: Clean up VNC config/scripts, reset VNC password for the CURRENT user and DISPLAY (keeps packages/user/display)." | |
echo " (U) Refresh User: Recreate the user account (same username), reset password, and fix permissions (keeps packages/config, wipes home)." | |
echo " (X) Fix Permissions: Fix permissions for the configured user's VNC files/scripts." | |
echo " (S) Fix Sudo: Ensure sudo group has permissions in sudoers config." | |
echo " (A)bort: Do nothing and exit." | |
read -p "Choose an action [R/P/C/F/U/X/S/A]: " -n 1 -r | |
echo "" # Move to a new line | |
case "$REPLY" in | |
[Rr]) | |
echo "Option: Reinstall selected." | |
# Only reinstall desktop/VNC packages and reconfigure VNC/user scripts, do NOT remove packages or user | |
# 1. Reinstall desktop/VNC packages (do not remove, just force reinstall) | |
echo "Reinstalling desktop/VNC packages: $PACKAGES_TO_INSTALL" | |
if retry_apt_command apt install --reinstall -y $PACKAGES_TO_INSTALL; then | |
echo "Desktop/VNC packages reinstalled." | |
else | |
echo "Warning: Failed to reinstall all desktop/VNC packages after retries." | |
fi | |
# 2. Ensure sudo config is correct (in case it was missing or corrupted) | |
ensure_sudo_config | |
# 3. Reconfigure VNC for the current user (finds new display, sets password, scripts, perms, bashrc hints) | |
if [ "$CONFIG_USER_EXISTS" = true ]; then | |
configure_vnc_user_setup | |
echo "" | |
echo "--- Reinstallation Complete ---" | |
else | |
echo "" | |
echo "--- Reinstallation Complete (No User Configured) ---" | |
echo "Desktop environment packages reinstalled, but no user is configured." | |
echo "Run the script again to set up a user." | |
fi | |
;; | |
[Pp]) | |
echo "Option: Purify (Remove) selected." | |
# 1. Stop server (if user exists and display was configured) | |
if [ "$CONFIG_USER_EXISTS" = true ] && [ -n "$VNC_DISPLAY_NUM" ]; then stop_vnc_server "$VNC_DESKTOP_USER" "$VNC_DISPLAY_NUM" || true; fi | |
# 2. Cleanup old user config (if user exists) - removes ~/.vnc and user's scripts | |
if [ "$CONFIG_USER_EXISTS" = true ]; then cleanup_user_vnc_config "$VNC_DESKTOP_USER" || true; fi | |
# 3. Remove packages (Removes Desktop/VNC but NOT sudo) | |
remove_packages | |
# 4. Prompt to remove old user (if user existed and was configured) | |
# prompt_remove_user handles updating globals (VNC_DESKTOP_USER, CONFIG_USER_EXISTS) and removing config file if user removed | |
if [ "$CONFIG_USER_EXISTS" = true ]; then prompt_remove_user; fi | |
# 5. Ensure config file is gone if it existed at the start | |
if [ "$CONFIG_FILE_EXISTS" = true ]; then | |
echo "Removing user config file: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" || true | |
# Clear globals related to the config file as it's gone | |
CONFIG_FILE_EXISTS=false | |
VNC_DESKTOP_USER="" | |
VNC_DISPLAY_NUM="" | |
# CONFIG_USER_EXISTS might still be true if user was kept | |
fi | |
echo "" | |
echo "--- Purification (Removal) Complete ---" | |
echo "VNC/LXDE packages and configuration have been removed." | |
# Check global CONFIG_USER_EXISTS *after* potential removal | |
if [ "$CONFIG_USER_EXISTS" = true ]; then | |
echo "The user '$VNC_DESKTOP_USER' was kept as requested." | |
fi | |
;; | |
[Cc]) | |
echo "Option: Configure (Repair) selected." | |
# This option requires the configured user to exist | |
if [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Configure option requires a valid user to be configured and exist ('$VNC_DESKTOP_USER' as per $USER_CONFIG_FILE)." | |
echo "Please choose 'R' (Reinstall) to create a new user, or 'A' to abort." | |
# Also remove stale config if user didn't exist | |
if [ "$CONFIG_FILE_EXISTS" = true ]; then | |
echo "Removing stale user config file: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" || true | |
CONFIG_FILE_EXISTS=false | |
VNC_DESKTOP_USER="" | |
VNC_DISPLAY_NUM="" | |
fi | |
exit 1 | |
fi | |
echo "Proceeding with Configuration (Repair) for user '$VNC_DESKTOP_USER'." | |
# 1. Stop server (for the existing user if display was configured) | |
if [ -n "$VNC_DISPLAY_NUM" ]; then stop_vnc_server "$VNC_DESKTOP_USER" "$VNC_DISPLAY_NUM" || true; fi | |
# 2. Ensure sudo config is correct (in case it was missing or corrupted) | |
ensure_sudo_config | |
# 3. Cleanup old user config (for the existing user) - removes ~/.vnc and user's scripts | |
cleanup_user_vnc_config "$VNC_DESKTOP_USER" # This cleans up old config/scripts for the user | |
# Packages and user are kept. No package install/remove, no user prompt. | |
# 4. Configure VNC for the existing user - finds NEW display, updates config file, sets password, creates scripts, fixes perms, adds bashrc hint | |
configure_vnc_user_setup | |
echo "" | |
echo "--- Configuration/Repair Complete ---" | |
echo "VNC password, configuration, and scripts have been reset/recreated for user '$VNC_DESKTOP_USER'." | |
;; | |
[Ff]) # Option: Fix/Refresh | |
echo "Option: Fix/Refresh selected." | |
# This option requires the configured user to exist AND the display number to be in the config | |
if [ "$CONFIG_USER_EXISTS" = false ] || [ -z "$VNC_DISPLAY_NUM" ]; then | |
echo "Error: Fix/Refresh option requires a valid user to be configured AND a display number to be set in the config file ('$VNC_DESKTOP_USER', $VNC_DISPLAY_NUM as per $USER_CONFIG_FILE)." | |
echo "This option does NOT create a user, find a new display, or install packages." | |
echo "Please choose 'R' (Reinstall) or 'C' (Configure) to establish a user and find a display." | |
# Also remove stale config if user didn't exist or display wasn't set | |
if [ "$CONFIG_FILE_EXISTS" = true ] && ([ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ] || [ -z "$VNC_DISPLAY_NUM" ]); then | |
echo "Removing incomplete/stale user config file: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" || true | |
CONFIG_FILE_EXISTS=false | |
VNC_DESKTOP_USER="" | |
VNC_DISPLAY_NUM="" | |
CONFIG_USER_EXISTS=false # If it wasn't true before, ensure it's false now | |
fi | |
exit 1 | |
fi | |
echo "Proceeding with Fix/Refresh for user '$VNC_DESKTOP_USER' on configured display $VNC_DISPLAY_NUM." | |
# 1. Stop server (for the existing user and configured display) | |
stop_vnc_server "$VNC_DESKTOP_USER" "$VNC_DISPLAY_NUM" || true | |
# 2. Ensure sudo config is correct (in case it was missing or corrupted) | |
ensure_sudo_config | |
# 3. Cleanup old user VNC config (for the existing user) - removes ~/.vnc and user's scripts | |
cleanup_user_vnc_config "$VNC_DESKTOP_USER" # This cleans up old config/scripts for the user | |
# Packages are kept. User is kept. Display is kept. No package install/remove, no user prompt, no display search. | |
# 4. Re-configure VNC for the existing user and existing display - does NOT find new display, does NOT update config file with display | |
set_vnc_password | |
configure_xstartup # This template no longer includes 'exec newgrp sudo' | |
create_user_scripts # Recreates start/stop scripts (which read the *existing* display from config) | |
fix_user_vnc_permissions "$VNC_DESKTOP_USER" # Ensure correct permissions after recreation | |
add_bashrc_sudo_hint # Add the sudo hint to the user's bashrc | |
# Create/refresh the wipe-x-locks.sh script | |
create_wipe_x_locks_script | |
echo "" | |
echo "--- Fix/Refresh Complete ---" | |
echo "VNC password, configuration, and scripts have been reset/recreated for user '$VNC_DESKTOP_USER' on display $VNC_DISPLAY_NUM." | |
echo "Desktop packages were NOT reinstalled, user was NOT removed, display number was NOT changed." | |
;; | |
[Uu]) | |
echo "Option: Refresh User selected." | |
if [ -z "$VNC_DESKTOP_USER" ] || [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: No valid user is configured to refresh." | |
exit 1 | |
fi | |
echo "This will refresh the login message, bashrc hints, and related scripts for user '$VNC_DESKTOP_USER'." | |
# Re-add bashrc hints (sudo + VNC lock cleanup) | |
add_bashrc_sudo_hint | |
# Optionally, re-create wipe-x-locks.sh for convenience | |
create_wipe_x_locks_script | |
echo "" | |
echo "--- User Refresh Complete ---" | |
echo "Login message, bashrc hints, and wipe-x-locks.sh refreshed for user '$VNC_DESKTOP_USER'." | |
;; | |
[Xx]) # Option: Fix Permissions | |
echo "Option: Fix Permissions selected." | |
# This option requires the configured user to exist | |
if [ "$CONFIG_USER_EXISTS" = false ]; then | |
echo "Error: Fix Permissions option requires a valid user to be configured and exist ('$VNC_DESKTOP_USER' as per $USER_CONFIG_FILE)." | |
echo "Please choose 'R' (Reinstall) or 'A' to abort." | |
# Also remove stale config if user didn't exist | |
if [ "$CONFIG_FILE_EXISTS" = true ]; then | |
echo "Removing stale user config file: $USER_CONFIG_FILE" | |
rm -f "$USER_CONFIG_FILE" || true | |
CONFIG_FILE_EXISTS=false | |
VNC_DESKTOP_USER="" | |
VNC_DISPLAY_NUM="" | |
fi | |
exit 1 | |
fi | |
echo "Proceeding to fix permissions for user '$VNC_DESKTOP_USER'." | |
# Call the permission fixing function | |
fix_user_vnc_permissions "$VNC_DESKTOP_USER" | |
echo "" | |
echo "--- Permission Fixing Complete ---" | |
echo "Permissions for VNC files and scripts have been adjusted for user '$VNC_DESKTOP_USER'." | |
;; | |
[Ss]) # New Option: Fix Sudo | |
echo "Option: Fix Sudo selected." | |
# Check if sudo is even installed | |
if ! command -v sudo &> /dev/null; then | |
echo "Error: The 'sudo' command is not installed. Cannot fix sudo configuration." | |
echo "Please run the script again and choose option 'R' (Reinstall) to install packages including sudo." | |
exit 1 | |
fi | |
echo "Ensuring sudo configuration is correct..." | |
ensure_sudo_config | |
# Also ensure the sudo group exists and user is in it | |
if [ -n "$VNC_DESKTOP_USER" ] && [ "$CONFIG_USER_EXISTS" = true ]; then | |
if ! getent group sudo >/dev/null; then | |
echo "'sudo' group does not exist. Creating it..." | |
groupadd sudo | |
fi | |
if id -nG "$VNC_DESKTOP_USER" | grep -qw sudo; then | |
echo "User '$VNC_DESKTOP_USER' is already in the sudo group." | |
else | |
echo "Adding user '$VNC_DESKTOP_USER' to the sudo group..." | |
usermod -aG sudo "$VNC_DESKTOP_USER" | |
echo "User '$VNC_DESKTOP_USER' added to sudo group." | |
fi | |
# Add bashrc hint | |
add_bashrc_sudo_hint "$VNC_DESKTOP_USER" || true | |
echo "--- Sudo Configuration Complete ---" | |
echo "Checked/Fixed sudoers configuration and group membership." | |
echo "Note: For changes to take full effect in a user's interactive shell session, log out and back in." | |
else | |
echo "--- Sudo Configuration Complete ---" | |
echo "Checked/Fixed sudoers configuration." | |
echo "Note: For changes to take full effect, you may need to log out and back in as the user." | |
fi | |
;; | |
[Aa]|*) # Default case for Abort or any other input | |
echo "Option: Abort selected. Exiting." | |
exit 0 | |
;; | |
esac | |
else # No existing setup config file detected ($CONFIG_FILE_EXISTS is false) | |
show_initial_welcome | |
echo "No existing setup detected. Proceeding with fresh installation." | |
echo "" | |
# Proceed with standard installation steps | |
# 1. Install packages (installs sudo and desktop, ensures sudo config) | |
install_packages | |
# 2. Prompt to create user (sets VNC_DESKTOP_USER, CONFIG_USER_EXISTS, writes config *without* display for now) | |
# If user creation fails/aborted, prompt_create_user returns non-zero, but we don't exit here | |
prompt_create_user || true | |
# 3. Configure VNC for the new user (if user was successfully created) - finds NEW display, updates config file, sets password, creates scripts, fixes perms, adds bashrc hint | |
if [ "$CONFIG_USER_EXISTS" = true ]; then | |
configure_vnc_user_setup | |
echo "" | |
echo "--- Fresh Installation Complete ---" | |
else | |
echo "" | |
echo "--- Fresh Installation Complete (No User Created) ---" | |
echo "Desktop environment packages installed, but no user was created or configured." | |
echo "Run the script again for a fresh install to create a user." | |
# Ensure config file is gone if fresh install ends up with no user | |
rm -f "$USER_CONFIG_FILE" || true | |
CONFIG_FILE_EXISTS=false | |
VNC_DESKTOP_USER="" | |
VNC_DISPLAY_NUM="" | |
CONFIG_USER_EXISTS=false | |
fi | |
fi | |
# --- Final Instructions --- | |
echo "" | |
echo "--- Setup Process Finished ---" | |
# Check CONFIG_USER_EXISTS again as it might have changed during the script run | |
if [ "$CONFIG_USER_EXISTS" = true ]; then | |
echo "The VNC desktop environment is configured for user '$VNC_DESKTOP_USER'." | |
# Need to read display number again if this was a cleanup/reinstall that removed it | |
final_display_num="$VNC_DISPLAY_NUM" | |
if [ -z "$final_display_num" ] && [ -f "$USER_CONFIG_FILE" ]; then | |
# Use eval to source just the display variable from the file | |
eval "$(grep "^$CREATED_DISPLAY_VAR=" "$USER_CONFIG_FILE" 2>/dev/null)" || true | |
final_display_num="$VNC_DISPLAY_NUM" # VNC_DISPLAY_NUM might now be set | |
fi | |
final_port="" | |
if [ -n "$final_display_num" ]; then | |
final_port=$((5900 + ${final_display_num#:*})) | |
fi | |
echo "Configured VNC Display: ${final_display_num:-<Not set>}, Port: ${final_port:-<Not set>}" | |
echo "" | |
echo "To Start the VNC server:" | |
echo "1. Log into your Debian proot environment as user '$VNC_DESKTOP_USER':" | |
echo " proot-distro login debian --user $VNC_DESKTOP_USER" | |
echo " -> After logging in, type 'id' or 'groups' to verify 'sudo' is listed in your groups." | |
echo " -> If 'sudo' is listed but the 'sudo' command doesn't work, you may need to log out and log back in to refresh group membership." | |
echo "2. Run the start script in their home directory:" | |
final_user_home="$(eval echo ~$VNC_DESKTOP_USER)" | |
echo " $final_user_home/$START_SCRIPT" | |
echo "" | |
echo "To Stop the VNC server:" | |
echo "1. Log into your Debian proot environment as user '$VNC_DESKTOP_USER' (or as root)." | |
echo "2. If logged in as the user, run the stop script:" | |
echo " $final_user_home/$STOP_SCRIPT" | |
echo " To stop ALL VNC servers for user '$VNC_DESKTOP_USER', run:" | |
echo " $final_user_home/$STOP_SCRIPT all" | |
echo "3. If logged in as root, you can run:" | |
if [ -n "$final_display_num" ]; then | |
echo " runuser -l $VNC_DESKTOP_USER -c 'vncserver -kill $final_display_num'" | |
else | |
echo " Cannot use vncserver -kill as display is unknown. To stop all for the user:" | |
echo " pkill -u $VNC_DESKTOP_USER Xtightvnc" | |
fi | |
echo "" | |
echo "To Connect via VNC Client:" | |
echo " - Use a VNC client on your PC or another device." | |
echo " - The address is your Android phone's IP address followed by the VNC port." | |
if [ -n "$final_port" ]; then | |
echo " - Address: <your_android_phone_ip>:$final_port" | |
else | |
echo " - Address: <your_android_phone_ip>:<VNC_PORT>" | |
echo " (VNC Port is usually 5901 if display :1 was available)" | |
fi | |
echo " - Use the VNC password you set for user '$VNC_DESKTOP_USER'." | |
echo "" | |
echo "Note: Your Android phone's IP address can be found in your Wi-Fi settings." | |
echo "The VNC server runs in the background after starting when using the start script." | |
echo "The username and assigned VNC display number are stored in: $USER_CONFIG_FILE" | |
else | |
echo "No VNC desktop user was created or configured during this run." | |
echo "The VNC desktop environment is NOT fully set up." | |
echo "To set it up, run the script again (it will now act as a fresh install) and choose to create a user." | |
echo "The config file '$USER_CONFIG_FILE' was removed or was not created." | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment