Skip to content

Instantly share code, notes, and snippets.

@cyberofficial
Last active May 13, 2025 14:36
Show Gist options
  • Save cyberofficial/ff3ba83361f1a0f12b954f0706028a2c to your computer and use it in GitHub Desktop.
Save cyberofficial/ff3ba83361f1a0f12b954f0706028a2c to your computer and use it in GitHub Desktop.
ProotSetUp.sh
#!/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