bluethefox

Untitled

Dec 6th, 2024
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 98.60 KB | Source Code | 0 0
  1. #!/bin/bash
  2.  
  3. # Exit immediately if a command exits with a non-zero status
  4. set -e
  5. set -o pipefail
  6.  
  7. # Define backup directory
  8. BACKUP_DIR="$HOME/.systemd_unit_backup"
  9.  
  10. # Ensure the backup directory exists
  11. mkdir -p "$BACKUP_DIR"
  12.  
  13. # Declare associative array for Desktop Environments and their corresponding packages
  14. declare -A DESKTOP_ENVS=(
  15.     [GNOME]="gnome-shell"
  16.     [KDE]="kde-plasma-desktop"
  17.     [XFCE]="xfce4"
  18.     [LXDE]="lxde"
  19.     [MATE]="mate-desktop-environment"
  20.     [Cinnamon]="cinnamon"
  21.     [Budgie]="budgie-desktop"
  22.     [Deepin]="deepin-desktop-environment"
  23.     [LXQt]="lxqt"
  24. )
  25.  
  26. # Log file for script operations
  27. LOG_FILE="$BACKUP_DIR/system_maintenance_$(date +%F_%T).log"
  28.  
  29. # Function to log messages
  30. log() {
  31.     echo "$(date '+%Y-%m-%d %H:%M:%S') : $*" | tee -a "$LOG_FILE"
  32. }
  33.  
  34. # Function to handle errors
  35. handle_error() {
  36.     local exit_code=$?
  37.     local message="$1"
  38.     if [ "$exit_code" -ne 0 ]; then
  39.         whiptail --title "Error" --msgbox "$message" 8 78
  40.         log "ERROR: $message"
  41.     fi
  42.     return "$exit_code"
  43. }
  44.  
  45. # Function to ask for sudo privileges
  46. ask_for_sudo() {
  47.     if ! sudo -v; then
  48.         whiptail --title "Sudo Access Required" --msgbox "Sudo access is required to proceed. Please ensure you have sufficient permissions." 8 78
  49.         exit 1
  50.     else
  51.         # Keep-alive: update existing sudo timestamp until script finishes
  52.         sudo -v
  53.         while true; do
  54.             sleep 60
  55.             sudo -n true
  56.             kill -0 "$$" || exit
  57.         done 2>/dev/null &
  58.     fi
  59. }
  60.  
  61. # Generic function to display menus
  62. display_menu() {
  63.     local title="$1"
  64.     local prompt="$2"
  65.     shift 2
  66.     local options=("$@")
  67.  
  68.     whiptail --title "$title" --menu "$prompt" 25 78 15 "${options[@]}" 3>&2 2>&1 1>&3
  69. }
  70.  
  71. # Function for confirmation prompts
  72. confirm_action() {
  73.     local title="$1"
  74.     local message="$2"
  75.  
  76.     whiptail --title "$title" --yesno "$message" 10 60
  77. }
  78.  
  79. # Function to display the main menu
  80. main_menu() {
  81.     local choice
  82.     choice=$(display_menu "System Maintenance Menu" "Choose a category:" \
  83.         "1" "System Updates & Drivers" \
  84.         "2" "Desktop Environment & Display" \
  85.         "3" "Boot & Disk Management" \
  86.         "4" "Network & Security" \
  87.         "5" "System Tools & Utilities" \
  88.         "6" "Backup & Restore" \
  89.         "7" "Exit")
  90.  
  91.     case $choice in
  92.         1) system_updates_drivers_menu ;;
  93.         2) desktop_environment_display_menu ;;
  94.         3) boot_disk_management_menu ;;
  95.         4) network_security_menu ;;
  96.         5) system_tools_utilities_menu ;;
  97.         6) backup_restore_menu ;;
  98.         7) exit 0 ;;
  99.         *) log "Invalid selection: $choice"; main_menu ;;
  100.     esac
  101. }
  102.  
  103. # Function for Backup & Restore menu
  104. backup_restore_menu() {
  105.     local choice
  106.     choice=$(display_menu "Backup & Restore" "Choose an action:" \
  107.         "1" "Backup System" \
  108.         "2" "Restore System from Backup" \
  109.         "3" "Back to Main Menu")
  110.  
  111.     case $choice in
  112.         1) backup_system ;;
  113.         2) restore_system_from_backup ;;
  114.         3) main_menu ;;
  115.         *) log "Invalid selection: $choice"; backup_restore_menu ;;
  116.     esac
  117. }
  118.  
  119. # Function to backup the system
  120. backup_system() {
  121.     # Prompt the user to select a backup destination
  122.     local backup_folder
  123.     backup_folder=$(whiptail --title "Select Backup Folder" --inputbox "Enter the path to an empty folder for backup:" 10 60 "$HOME/backup" 3>&1 1>&2 2>&3)
  124.  
  125.     if [ $? -ne 0 ]; then
  126.         log "Backup cancelled by the user."
  127.         return
  128.     fi
  129.  
  130.     if [ -z "$backup_folder" ]; then
  131.         whiptail --title "Error" --msgbox "No backup folder specified." 8 78
  132.         log "Backup failed: No backup folder specified."
  133.         return
  134.     fi
  135.  
  136.     # Check if the folder exists; if not, create it
  137.     if [ ! -d "$backup_folder" ]; then
  138.         mkdir -p "$backup_folder" || handle_error "Failed to create backup directory."
  139.     fi
  140.  
  141.     # Ensure the folder is empty
  142.     if [ "$(ls -A "$backup_folder")" ]; then
  143.         whiptail --title "Error" --msgbox "The selected folder is not empty. Please choose an empty folder." 8 78
  144.         log "Backup failed: Backup folder is not empty."
  145.         return
  146.     fi
  147.  
  148.     # Start the backup process with a progress gauge
  149.     whiptail --title "Backing Up System" --gauge "Starting system backup..." 10 60 0
  150.  
  151.     # Perform the backup using rsync with progress
  152.     rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} / "$backup_folder" &>> "$LOG_FILE" &
  153.  
  154.     local pid=$!
  155.     local delay=0
  156.     local progress=0
  157.  
  158.     while kill -0 "$pid" 2>/dev/null; do
  159.         sleep 1
  160.         delay=$((delay + 1))
  161.         progress=$(( progress + 5 ))
  162.         if [ "$progress" -ge 100 ]; then
  163.             progress=99
  164.         fi
  165.         whiptail --title "Backing Up System" --gauge "Backing up system..." 10 60 "$progress"
  166.     done
  167.  
  168.     wait "$pid"
  169.     local exit_code=$?
  170.     if [ "$exit_code" -eq 0 ]; then
  171.         whiptail --title "Backup Complete" --msgbox "System backup completed successfully to $backup_folder." 8 78
  172.         log "System backup completed successfully to $backup_folder."
  173.     else
  174.         handle_error "System backup failed. Check the log file at $LOG_FILE for details."
  175.     fi
  176. }
  177.  
  178. # Function to restore the system from a backup
  179. restore_system_from_backup() {
  180.     # Prompt the user to select a backup directory
  181.     local backup_folder
  182.     backup_folder=$(whiptail --title "Select Backup Folder" --inputbox "Enter the path to the backup folder:" 10 60 "$HOME/backup" 3>&1 1>&2 2>&3)
  183.  
  184.     if [ $? -ne 0 ]; then
  185.         log "Restore cancelled by the user."
  186.         return
  187.     fi
  188.  
  189.     if [ -z "$backup_folder" ] || [ ! -d "$backup_folder" ]; then
  190.         whiptail --title "Error" --msgbox "Invalid backup folder specified." 8 78
  191.         log "Restore failed: Invalid backup folder."
  192.         return
  193.     fi
  194.  
  195.     # Confirm restoration as it will overwrite system files
  196.     if ! confirm_action "Confirm Restore" "Are you sure you want to restore the system from $backup_folder? This will overwrite current system files."; then
  197.         log "Restore cancelled by the user."
  198.         return
  199.     fi
  200.  
  201.     # Start the restoration process with a progress gauge
  202.     whiptail --title "Restoring System" --gauge "Starting system restoration..." 10 60 0
  203.  
  204.     # Perform the restoration using rsync with progress
  205.     rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} "$backup_folder"/ / &>> "$LOG_FILE" &
  206.  
  207.     local pid=$!
  208.     local delay=0
  209.     local progress=0
  210.  
  211.     while kill -0 "$pid" 2>/dev/null; do
  212.         sleep 1
  213.         delay=$((delay + 1))
  214.         progress=$(( progress + 5 ))
  215.         if [ "$progress" -ge 100 ]; then
  216.             progress=99
  217.         fi
  218.         whiptail --title "Restoring System" --gauge "Restoring system..." 10 60 "$progress"
  219.     done
  220.  
  221.     wait "$pid"
  222.     local exit_code=$?
  223.     if [ "$exit_code" -eq 0 ]; then
  224.         whiptail --title "Restore Complete" --msgbox "System restored successfully from $backup_folder." 8 78
  225.         log "System restored successfully from $backup_folder."
  226.     else
  227.         handle_error "System restore failed. Check the log file at $LOG_FILE for details."
  228.     fi
  229. }
  230.  
  231. # Function for System Updates & Drivers menu
  232. system_updates_drivers_menu() {
  233.     local choice
  234.     choice=$(display_menu "System Updates & Drivers" "Choose an action:" \
  235.         "1" "Update and Upgrade System" \
  236.         "2" "Install Missing Drivers" \
  237.         "3" "Remove NVIDIA Drivers" \
  238.         "4" "Fix Package Dependencies" \
  239.         "5" "Remove Unused Packages" \
  240.         "6" "Install NVIDIA Drivers" \
  241.         "7" "Flatpak Repair" \
  242.         "8" "Back to Main Menu")
  243.  
  244.     case $choice in
  245.         1) update_system ;;
  246.         2) install_missing_drivers ;;
  247.         3) remove_nvidia_drivers ;;
  248.         4) fix_package_dependencies ;;
  249.         5) remove_unused_packages ;;
  250.         6) install_nvidia ;;
  251.         7) flatpak_repair ;;
  252.         8) main_menu ;;
  253.         *) log "Invalid selection: $choice"; system_updates_drivers_menu ;;
  254.     esac
  255. }
  256.  
  257. # Function to update and upgrade the system
  258. update_system() {
  259.     whiptail --title "System Update" --infobox "Updating package lists..." 8 78
  260.     sudo apt-get update &>> "$LOG_FILE" || handle_error "Failed to update package lists."
  261.  
  262.     whiptail --title "System Upgrade" --infobox "Upgrading installed packages..." 8 78
  263.     sudo apt-get upgrade -y &>> "$LOG_FILE" || handle_error "Failed to upgrade packages."
  264.  
  265.     whiptail --title "System Update" --msgbox "System successfully updated and upgraded." 8 78
  266.     log "System successfully updated and upgraded."
  267. }
  268.  
  269. # Function to install missing drivers
  270. install_missing_drivers() {
  271.     whiptail --title "Install Missing Drivers" --infobox "Identifying and installing missing drivers..." 8 78
  272.     sudo ubuntu-drivers autoinstall &>> "$LOG_FILE" || handle_error "Failed to install missing drivers."
  273.  
  274.     whiptail --title "Install Missing Drivers" --msgbox "Missing drivers have been installed successfully." 8 78
  275.     log "Missing drivers installed successfully."
  276. }
  277.  
  278. # Function to remove NVIDIA drivers
  279. remove_nvidia_drivers() {
  280.     if ! confirm_action "Remove NVIDIA Drivers" "Are you sure you want to remove all NVIDIA drivers and related packages?"; then
  281.         log "NVIDIA driver removal cancelled by the user."
  282.         return
  283.     fi
  284.  
  285.     whiptail --title "Removing NVIDIA Drivers" --infobox "Removing NVIDIA drivers and related packages..." 8 78
  286.  
  287.     sudo apt-get purge '^nvidia-.*' -y &>> "$LOG_FILE" || handle_error "Failed to purge NVIDIA packages."
  288.     sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove NVIDIA dependencies."
  289.  
  290.     # Remove NVIDIA related directories and files
  291.     sudo rm -rf /usr/local/cuda* /usr/local/nvidia* /etc/OpenCL/vendors/nvidia.icd &>> "$LOG_FILE" || handle_error "Failed to remove NVIDIA directories."
  292.     sudo rm -rf /etc/X11/xorg.conf.d/10-nvidia.conf /etc/modprobe.d/nvidia-installer-disable-nouveau.conf &>> "$LOG_FILE" || handle_error "Failed to remove NVIDIA configuration files."
  293.     sudo rm -rf /var/log/nvidia* /var/lib/nvidia* &>> "$LOG_FILE" || handle_error "Failed to remove NVIDIA log and lib files."
  294.  
  295.     whiptail --title "Remove NVIDIA Drivers" --msgbox "NVIDIA drivers and related files have been removed successfully." 8 78
  296.     log "NVIDIA drivers and related files removed successfully."
  297. }
  298.  
  299. # Function to fix package dependencies
  300. fix_package_dependencies() {
  301.     if ! confirm_action "Fix Package Dependencies" "Attempt to fix any broken package dependencies?"; then
  302.         log "Fix package dependencies cancelled by the user."
  303.         return
  304.     fi
  305.  
  306.     whiptail --title "Fixing Package Dependencies" --infobox "Attempting to fix package dependencies..." 8 78
  307.     sudo apt-get update &>> "$LOG_FILE" || handle_error "Failed to update package lists."
  308.     sudo apt-get -f install -y &>> "$LOG_FILE" || handle_error "Failed to fix package dependencies."
  309.  
  310.     whiptail --title "Fix Package Dependencies" --msgbox "Package dependencies fixed successfully." 8 78
  311.     log "Package dependencies fixed successfully."
  312. }
  313.  
  314. # Function to remove unused packages
  315. remove_unused_packages() {
  316.     if ! confirm_action "Remove Unused Packages" "Remove packages that are no longer needed?"; then
  317.         log "Remove unused packages cancelled by the user."
  318.         return
  319.     fi
  320.  
  321.     whiptail --title "Removing Unused Packages" --infobox "Removing unused packages..." 8 78
  322.     sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to remove unused packages."
  323.  
  324.     whiptail --title "Remove Unused Packages" --msgbox "Unused packages removed successfully." 8 78
  325.     log "Unused packages removed successfully."
  326. }
  327.  
  328. # Function to install NVIDIA drivers
  329. install_nvidia() {
  330.     whiptail --title "Installing NVIDIA Drivers" --infobox "Updating system packages..." 8 78
  331.     sudo apt-get update && sudo apt-get upgrade -y &>> "$LOG_FILE" || handle_error "Failed to update and upgrade system."
  332.  
  333.     whiptail --title "Installing NVIDIA Drivers" --infobox "Installing necessary software properties..." 8 78
  334.     sudo apt-get install software-properties-common -y &>> "$LOG_FILE" || handle_error "Failed to install software-properties-common."
  335.  
  336.     whiptail --title "Installing NVIDIA Drivers" --infobox "Adding the graphics drivers PPA..." 8 78
  337.     sudo add-apt-repository ppa:graphics-drivers/ppa -y &>> "$LOG_FILE" || handle_error "Failed to add graphics drivers PPA."
  338.     sudo apt-get update &>> "$LOG_FILE" || handle_error "Failed to update package lists after adding PPA."
  339.  
  340.     whiptail --title "Installing NVIDIA Drivers" --infobox "Identifying the recommended NVIDIA driver..." 8 78
  341.     local recommended_driver
  342.     recommended_driver=$(ubuntu-drivers devices | grep "recommended" | awk '{print $3}')
  343.     if [[ -z "$recommended_driver" ]]; then
  344.         whiptail --title "NVIDIA Driver Installation" --msgbox "No recommended NVIDIA driver found. Please check your system and try again." 8 78
  345.         log "No recommended NVIDIA driver found."
  346.         return
  347.     fi
  348.  
  349.     whiptail --title "Installing NVIDIA Drivers" --infobox "Installing the recommended NVIDIA driver ($recommended_driver)..." 8 78
  350.     sudo apt-get install "$recommended_driver" nvidia-settings -y &>> "$LOG_FILE" || handle_error "Failed to install NVIDIA driver."
  351.  
  352.     # Backup existing Xorg configuration if it exists
  353.     if [[ -f "/etc/X11/xorg.conf" ]]; then
  354.         sudo cp /etc/X11/xorg.conf "$BACKUP_DIR/xorg.conf.bak_$(date +%F_%T)" &>> "$LOG_FILE" || handle_error "Failed to backup existing Xorg configuration."
  355.     fi
  356.  
  357.     whiptail --title "Installing NVIDIA Drivers" --infobox "Configuring NVIDIA settings..." 8 78
  358.     sudo nvidia-xconfig &>> "$LOG_FILE" || handle_error "Failed to configure NVIDIA Xorg settings."
  359.  
  360.     # Ensure LightDM is installed and enabled
  361.     if ! dpkg -s lightdm &>/dev/null; then
  362.         whiptail --title "Installing LightDM" --infobox "Installing LightDM display manager..." 8 78
  363.         sudo apt-get install lightdm -y &>> "$LOG_FILE" || handle_error "Failed to install LightDM."
  364.     fi
  365.  
  366.     sudo systemctl enable lightdm &>> "$LOG_FILE" || handle_error "Failed to enable LightDM."
  367.     sudo systemctl restart lightdm &>> "$LOG_FILE" || handle_error "Failed to restart LightDM."
  368.  
  369.     whiptail --title "NVIDIA Driver Installation" --msgbox "NVIDIA drivers, configuration tools, and LightDM have been installed and configured successfully." 8 78
  370.     log "NVIDIA drivers installed and configured successfully."
  371. }
  372.  
  373. # Function to repair Flatpak packages
  374. flatpak_repair() {
  375.     whiptail --title "Flatpak Repair" --infobox "Repairing Flatpak packages..." 8 78
  376.     sudo flatpak repair &>> "$LOG_FILE" || handle_error "Failed to repair Flatpak packages."
  377.  
  378.     whiptail --title "Flatpak Update" --infobox "Updating Flatpak packages..." 8 78
  379.     sudo flatpak update -y &>> "$LOG_FILE" || handle_error "Failed to update Flatpak packages."
  380.  
  381.     whiptail --title "Flatpak Repair" --msgbox "Flatpak repair and update completed successfully." 8 78
  382.     log "Flatpak repair and update completed successfully."
  383. }
  384.  
  385. # Function for Desktop Environment & Display menu
  386. desktop_environment_display_menu() {
  387.     local choice
  388.     choice=$(display_menu "Desktop Environment & Display" "Choose an action:" \
  389.         "1" "Purge Xorg" \
  390.         "2" "Reset X11" \
  391.         "3" "LightDM Reset" \
  392.         "4" "Make Wayland Default" \
  393.         "5" "Desktop Environment Installer/Remover" \
  394.         "6" "Startx Attempt" \
  395.         "7" "Cinnamon Repair" \
  396.         "8" "Back to Main Menu")
  397.  
  398.     case $choice in
  399.         1) purge_xorg ;;
  400.         2) reset_x11 ;;
  401.         3) lightdm_reset ;;
  402.         4) make_wayland_default ;;
  403.         5) desktop_environment_installer_remover ;;
  404.         6) startx_attempt ;;
  405.         7) cinnamon_repair ;;
  406.         8) main_menu ;;
  407.         *) log "Invalid selection: $choice"; desktop_environment_display_menu ;;
  408.     esac
  409. }
  410.  
  411. # Function to purge Xorg packages
  412. purge_xorg() {
  413.     if ! confirm_action "Purge Xorg" "Are you sure you want to purge all Xorg packages? This may affect your graphical interface."; then
  414.         log "Purge Xorg cancelled by the user."
  415.         return
  416.     fi
  417.  
  418.     whiptail --title "Purging Xorg" --infobox "Purging Xorg packages..." 8 78
  419.     sudo apt-get purge '^xorg-.*' -y &>> "$LOG_FILE" || handle_error "Failed to purge Xorg packages."
  420.     sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after purging Xorg."
  421.  
  422.     whiptail --title "Purge Xorg" --msgbox "Xorg packages have been purged successfully." 8 78
  423.     log "Xorg packages purged successfully."
  424. }
  425.  
  426. # Function to reset X11 configuration
  427. reset_x11() {
  428.     if ! confirm_action "Reset X11" "This will attempt to reset X11 configuration to distribution defaults and may affect display settings. Continue?"; then
  429.         log "Reset X11 cancelled by the user."
  430.         return
  431.     fi
  432.  
  433.     whiptail --title "Reset X11" --infobox "Reconfiguring Xserver..." 8 78
  434.     sudo dpkg-reconfigure xserver-xorg &>> "$LOG_FILE" || handle_error "Failed to reconfigure Xserver."
  435.  
  436.     # Remove user-specific X11 settings
  437.     local x11_conf_files=("$HOME/.config/monitors.xml" "$HOME/.Xauthority" "$HOME/.xinitrc")
  438.     for conf_file in "${x11_conf_files[@]}"; do
  439.         if [[ -f "$conf_file" ]]; then
  440.             rm -f "$conf_file" || handle_error "Failed to remove $conf_file."
  441.             log "Removed user-specific X11 configuration: $conf_file."
  442.         fi
  443.     done
  444.  
  445.     # Reconfigure display manager if LightDM is active
  446.     if systemctl is-active --quiet lightdm; then
  447.         whiptail --title "Reset X11" --infobox "Reconfiguring LightDM..." 8 78
  448.         sudo dpkg-reconfigure lightdm &>> "$LOG_FILE" || handle_error "Failed to reconfigure LightDM."
  449.     fi
  450.  
  451.     # Prompt to restart display manager
  452.     if confirm_action "Restart Display Manager" "Would you like to restart the display manager now? This will close all open applications."; then
  453.         sudo systemctl restart lightdm &>> "$LOG_FILE" || handle_error "Failed to restart LightDM."
  454.     else
  455.         whiptail --title "Reset X11" --msgbox "X11 configuration has been reset. Please reboot your system to apply changes." 8 78
  456.     fi
  457.  
  458.     whiptail --title "Reset X11" --msgbox "X11 configuration has been reset to the distribution default." 8 78
  459.     log "X11 configuration reset successfully."
  460. }
  461.  
  462. # Function to reset LightDM
  463. lightdm_reset() {
  464.     if ! confirm_action "Reset LightDM" "This will reinstall LightDM and reset its configuration to default. Continue?"; then
  465.         log "Reset LightDM cancelled by the user."
  466.         return
  467.     fi
  468.  
  469.     # Ensure backup directory exists
  470.     mkdir -p "$BACKUP_DIR"
  471.  
  472.     # Backup existing LightDM configuration
  473.     local lightdm_conf="/etc/lightdm/lightdm.conf"
  474.     if [[ -f "$lightdm_conf" ]]; then
  475.         sudo cp "$lightdm_conf" "$BACKUP_DIR/lightdm.conf.bak_$(date +%F_%T)" &>> "$LOG_FILE" || handle_error "Failed to backup LightDM configuration."
  476.         log "Backed up LightDM configuration to $BACKUP_DIR/lightdm.conf.bak_$(date +%F_%T)."
  477.     fi
  478.  
  479.     # Reinstall LightDM
  480.     whiptail --title "Resetting LightDM" --infobox "Reinstalling LightDM..." 8 78
  481.     sudo apt-get install --reinstall lightdm -y &>> "$LOG_FILE" || handle_error "Failed to reinstall LightDM."
  482.  
  483.     # Reconfigure LightDM to ensure it's the default display manager
  484.     sudo dpkg-reconfigure lightdm &>> "$LOG_FILE" || handle_error "Failed to reconfigure LightDM."
  485.  
  486.     # Restart LightDM
  487.     sudo systemctl restart lightdm &>> "$LOG_FILE" || handle_error "Failed to restart LightDM."
  488.  
  489.     whiptail --title "LightDM Reset" --msgbox "LightDM has been reset to its distribution default and restarted successfully." 8 78
  490.     log "LightDM reset and restarted successfully."
  491. }
  492.  
  493. # Function to make Wayland the default display server
  494. make_wayland_default() {
  495.     # Check if GDM3 is installed
  496.     if ! dpkg -s gdm3 &>/dev/null; then
  497.         whiptail --title "Error" --msgbox "GDM3 is not installed. This script currently supports making Wayland default for GDM3 only." 8 78
  498.         log "Make Wayland Default failed: GDM3 not installed."
  499.         return
  500.     fi
  501.  
  502.     # Backup existing GDM3 configuration
  503.     local gdm_config="/etc/gdm3/custom.conf"
  504.     if [[ -f "$gdm_config" ]]; then
  505.         sudo cp "$gdm_config" "$BACKUP_DIR/custom.conf.bak_$(date +%F_%T)" &>> "$LOG_FILE" || handle_error "Failed to backup GDM3 configuration."
  506.         log "Backed up GDM3 configuration to $BACKUP_DIR/custom.conf.bak_$(date +%F_%T)."
  507.     fi
  508.  
  509.     # Enable Wayland in GDM3 configuration
  510.     sudo sed -i 's/^#WaylandEnable=false/WaylandEnable=true/' "$gdm_config" || handle_error "Failed to enable Wayland in GDM3 configuration."
  511.     log "Enabled Wayland in GDM3 configuration."
  512.  
  513.     # Remove Xorg configuration if exists
  514.     if [[ -f "/etc/X11/xorg.conf" ]]; then
  515.         sudo mv /etc/X11/xorg.conf "$BACKUP_DIR/xorg.conf.bak_$(date +%F_%T)" &>> "$LOG_FILE" || handle_error "Failed to backup Xorg configuration."
  516.         log "Moved existing Xorg configuration to backup."
  517.     fi
  518.  
  519.     # Restart GDM3 to apply changes
  520.     sudo systemctl restart gdm3 &>> "$LOG_FILE" || handle_error "Failed to restart GDM3."
  521.  
  522.     whiptail --title "Make Wayland Default" --msgbox "Wayland has been set as the default display server. GDM3 has been restarted to apply changes." 8 78
  523.     log "Wayland set as default display server and GDM3 restarted."
  524. }
  525.  
  526. # Function to install or remove desktop environments
  527. desktop_environment_installer_remover() {
  528.     # Refresh the installation status
  529.     check_installed_desktops
  530.  
  531.     # Prepare checklist options
  532.     local choices=()
  533.     for DE in "${!DESKTOP_ENVS[@]}"; do
  534.         local status="${DESKTOP_ENVS[$DE]}"
  535.         if [[ "$status" == "installed" ]]; then
  536.             choices+=("$DE" "Installed" "ON")
  537.         else
  538.             choices+=("$DE" "Not Installed" "OFF")
  539.         fi
  540.     done
  541.  
  542.     # Prompt user to select desktop environments to install/remove
  543.     local selected_des
  544.     selected_des=$(whiptail --title "Desktop Environment Installer/Remover" --checklist \
  545.         "Select desktop environments to install or remove:" 20 80 12 \
  546.         "${choices[@]}" 3>&1 1>&2 2>&3)
  547.  
  548.     # Check if user made a selection
  549.     if [ -z "$selected_des" ]; then
  550.         log "No desktop environments selected for installation/removal."
  551.         return
  552.     fi
  553.  
  554.     # Convert selection to an array
  555.     read -r -a selected_des <<< "$(echo "$selected_des" | tr -d '"')"
  556.  
  557.     # Iterate through selected desktop environments
  558.     for DE in "${selected_des[@]}"; do
  559.         if [[ "${DESKTOP_ENVS[$DE]}" == "installed" ]]; then
  560.             # Prompt to remove the desktop environment
  561.             if confirm_action "Remove $DE" "Do you want to remove the $DE desktop environment?"; then
  562.                 whiptail --title "Removing $DE" --infobox "Removing $DE desktop environment..." 8 78
  563.                 sudo apt-get purge "${DESKTOP_ENVS[$DE]}" -y &>> "$LOG_FILE" || handle_error "Failed to remove $DE."
  564.                 sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after removing $DE."
  565.                 whiptail --title "Remove $DE" --msgbox "$DE has been removed successfully." 8 78
  566.                 log "$DE desktop environment removed successfully."
  567.             else
  568.                 log "Removal of $DE cancelled by the user."
  569.             fi
  570.         else
  571.             # Prompt to install the desktop environment
  572.             if confirm_action "Install $DE" "Do you want to install the $DE desktop environment?"; then
  573.                 whiptail --title "Installing $DE" --infobox "Installing $DE desktop environment..." 8 78
  574.                 sudo apt-get install "${DESKTOP_ENVS[$DE]}" -y &>> "$LOG_FILE" || handle_error "Failed to install $DE."
  575.                 whiptail --title "Install $DE" --msgbox "$DE has been installed successfully." 8 78
  576.                 log "$DE desktop environment installed successfully."
  577.             else
  578.                 log "Installation of $DE cancelled by the user."
  579.             fi
  580.         fi
  581.     done
  582.  
  583.     # Refresh desktop environment status
  584.     check_installed_desktops
  585. }
  586.  
  587. # Function to attempt running startx
  588. startx_attempt() {
  589.     whiptail --title "Startx Attempt" --msgbox "Attempting to start X server using startx. This will close all open applications." 8 78
  590.     log "Attempting to start X server using startx."
  591.  
  592.     # Execute startx and log output
  593.     startx &>> "$LOG_FILE" || handle_error "Failed to start X server with startx."
  594.  
  595.     whiptail --title "Startx Attempt" --msgbox "startx command executed. Check the log file for details." 8 78
  596.     log "startx command executed."
  597. }
  598.  
  599. # Function to repair Cinnamon desktop environment
  600. cinnamon_repair() {
  601.     if ! dpkg -s cinnamon &>/dev/null && ! dpkg -s mint-meta-cinnamon &>/dev/null; then
  602.         whiptail --title "Error" --msgbox "Cinnamon is not installed on your system." 8 78
  603.         log "Cinnamon repair failed: Cinnamon is not installed."
  604.         return
  605.     fi
  606.  
  607.     whiptail --title "Cinnamon Repair" --infobox "Reinstalling Cinnamon packages..." 8 78
  608.     sudo apt-get install --reinstall cinnamon mint-meta-cinnamon -y &>> "$LOG_FILE" || handle_error "Failed to reinstall Cinnamon packages."
  609.  
  610.     whiptail --title "Cinnamon Repair" --infobox "Resetting Cinnamon settings..." 8 78
  611.     dconf reset -f /org/cinnamon/ &>> "$LOG_FILE" || handle_error "Failed to reset Cinnamon settings."
  612.  
  613.     whiptail --title "Cinnamon Repair" --msgbox "Cinnamon has been repaired and reset successfully." 8 78
  614.     log "Cinnamon repaired and reset successfully."
  615. }
  616.  
  617. # Function for Boot & Disk Management menu
  618. boot_disk_management_menu() {
  619.     local choice
  620.     choice=$(display_menu "Boot & Disk Management" "Choose an action:" \
  621.         "1" "Optimize Boot Sequence" \
  622.         "2" "Fix Slow Boot Issues" \
  623.         "3" "Restore Original Boot Sequence" \
  624.         "4" "Manually Adjust Boot Sequence" \
  625.         "5" "Remove Linux Kernel Versions" \
  626.         "6" "Check Disk Health" \
  627.         "7" "Back to Main Menu")
  628.  
  629.     case $choice in
  630.         1) optimize_boot_sequence ;;
  631.         2) fix_slow_boot ;;
  632.         3) restore_to_distro_default ;;
  633.         4) manually_adjust_boot_sequence ;;
  634.         5) remove_kernel_versions ;;
  635.         6) check_disk_health ;;
  636.         7) main_menu ;;
  637.         *) log "Invalid selection: $choice"; boot_disk_management_menu ;;
  638.     esac
  639. }
  640.  
  641. # Function to optimize boot sequence
  642. optimize_boot_sequence() {
  643.     whiptail --title "Optimizing Boot Sequence" --infobox "Backing up current unit files..." 8 78
  644.     sudo systemctl list-unit-files --state=enabled > "$BACKUP_DIR/unit_files_$(date +%F_%T).backup" || handle_error "Failed to backup unit files."
  645.  
  646.     declare -A SERVICE_CATEGORIES=(
  647.         [system]="systemd-* udev*"
  648.         [filesystem]="*.mount"
  649.         [drivers]="*-drivers.*"
  650.         [user]="user@*.service"
  651.         [user_defined]="httpd* mysqld* sshd*"
  652.     )
  653.  
  654.     local services_to_process=()
  655.  
  656.     for category in "${!SERVICE_CATEGORIES[@]}"; do
  657.         for pattern in ${SERVICE_CATEGORIES[$category]}; do
  658.             while IFS= read -r line; do
  659.                 services_to_process+=("$line")
  660.             done < <(systemctl list-unit-files --state=enabled | grep "$pattern" | awk '{print $1}')
  661.         done
  662.     done
  663.  
  664.     local total_services=${#services_to_process[@]}
  665.     local counter=0
  666.     local error_occurred=0
  667.  
  668.     {
  669.         for service in "${services_to_process[@]}"; do
  670.             let counter+=1
  671.             if ! sudo systemctl disable "$service" &>> "$LOG_FILE"; then
  672.                 error_occurred=1
  673.                 echo "XXX"
  674.                 echo "Failed disabling $service ($counter of $total_services)"
  675.                 echo "XXX"
  676.                 echo $((counter * 50 / total_services))
  677.                 break
  678.             fi
  679.             echo "XXX"
  680.             echo "Disabling $service ($counter of $total_services)"
  681.             echo "XXX"
  682.             echo $((counter * 50 / total_services))
  683.         done
  684.  
  685.         if (( error_occurred == 0 )); then
  686.             for service in "${services_to_process[@]}"; do
  687.                 let counter+=1
  688.                 if ! sudo systemctl enable "$service" &>> "$LOG_FILE"; then
  689.                     error_occurred=1
  690.                     echo "XXX"
  691.                     echo "Failed enabling $service ($counter of $total_services)"
  692.                     echo "XXX"
  693.                     echo $((counter * 50 / total_services + 50))
  694.                     break
  695.                 fi
  696.                 echo "XXX"
  697.                 echo "Enabling $service ($counter of $total_services)"
  698.                 echo "XXX"
  699.                 echo $((counter * 50 / total_services + 50))
  700.             done
  701.         fi
  702.     } | whiptail --gauge "Optimizing boot sequence..." 20 70 0
  703.  
  704.     if (( error_occurred )); then
  705.         whiptail --title "Error" --msgbox "An error occurred during the optimization process. Check the log file for details." 8 78
  706.         log "Boot sequence optimization encountered errors."
  707.     else
  708.         whiptail --title "Optimize Boot Sequence" --msgbox "Boot sequence optimized successfully." 8 78
  709.         log "Boot sequence optimized successfully."
  710.     fi
  711. }
  712.  
  713. # Function to fix slow boot issues
  714. fix_slow_boot() {
  715.     whiptail --title "Fix Slow Boot Issues" --infobox "Backing up GRUB configuration..." 8 78
  716.     sudo cp /etc/default/grub "$BACKUP_DIR/grub.bak_$(date +%F_%T)" || handle_error "Failed to backup GRUB configuration."
  717.  
  718.     # Disable plymouth-quit-wait.service
  719.     sudo systemctl disable plymouth-quit-wait.service &>> "$LOG_FILE" || handle_error "Failed to disable plymouth-quit-wait.service."
  720.     log "Disabled plymouth-quit-wait.service."
  721.  
  722.     # Reduce GRUB timeout
  723.     sudo sed -i 's/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=5/' /etc/default/grub || handle_error "Failed to set GRUB_TIMEOUT."
  724.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB."
  725.  
  726.     # Optimize systemd services
  727.     local slow_units
  728.     slow_units=$(systemd-analyze blame | head -n 5 | awk '{print $2}')
  729.  
  730.     for unit in $slow_units; do
  731.         if confirm_action "Disable $unit" "Do you want to disable the slow service: $unit?"; then
  732.             sudo systemctl disable "$unit" &>> "$LOG_FILE" || handle_error "Failed to disable $unit."
  733.             log "Disabled slow service: $unit."
  734.         fi
  735.     done
  736.  
  737.     # Check for failed systemd units
  738.     local failed_units
  739.     failed_units=$(systemctl --failed --no-legend | grep ".service" | awk '{print $1}')
  740.     if [ -n "$failed_units" ]; then
  741.         whiptail --title "Failed Services" --msgbox "The following services have failed and may require manual intervention:\n$failed_units" 10 78
  742.         log "Failed services detected: $failed_units."
  743.     fi
  744.  
  745.     whiptail --title "Fix Slow Boot" --msgbox "Attempted to fix slow boot issues. Some changes might require a reboot." 8 78
  746.     log "Attempted to fix slow boot issues."
  747. }
  748.  
  749. # Function to restore boot sequence to distribution default
  750. restore_to_distro_default() {
  751.     whiptail --title "Restore Boot Sequence" --infobox "Restoring boot sequence to distribution defaults..." 8 78
  752.  
  753.     sudo systemctl preset-all &>> "$LOG_FILE" || handle_error "Failed to preset all systemd unit files."
  754.  
  755.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB."
  756.  
  757.     whiptail --title "Restore Boot Sequence" --msgbox "Boot sequence has been restored to distribution defaults successfully." 8 78
  758.     log "Boot sequence restored to distribution defaults."
  759. }
  760.  
  761. # Function to manually adjust boot sequence
  762. manually_adjust_boot_sequence() {
  763.     # List all enabled services
  764.     local services
  765.     services=$(systemctl list-unit-files --state=enabled | awk '{print $1}' | grep '.service')
  766.  
  767.     # Prepare checklist options
  768.     local choices=()
  769.     for svc in $services; do
  770.         choices+=("$svc" "" "OFF")
  771.     done
  772.  
  773.     # Prompt user to select services to enable/disable
  774.     local selected_services
  775.     selected_services=$(whiptail --title "Adjust Boot Sequence" --checklist \
  776.         "Select services to toggle (use space to select):" 20 100 15 \
  777.         "${choices[@]}" 3>&1 1>&2 2>&3)
  778.  
  779.     # Check if user made a selection
  780.     if [ -z "$selected_services" ]; then
  781.         log "No services selected for manual adjustment."
  782.         return
  783.     fi
  784.  
  785.     # Convert selection to an array
  786.     read -r -a selected_services <<< "$(echo "$selected_services" | tr -d '"')"
  787.  
  788.     # Iterate through selected services
  789.     for svc in "${selected_services[@]}"; do
  790.         if systemctl is-enabled --quiet "$svc"; then
  791.             if confirm_action "Disable $svc" "Do you want to disable the service: $svc?"; then
  792.                 sudo systemctl disable "$svc" &>> "$LOG_FILE" || handle_error "Failed to disable $svc."
  793.                 log "Disabled service: $svc."
  794.             fi
  795.         else
  796.             if confirm_action "Enable $svc" "Do you want to enable the service: $svc?"; then
  797.                 sudo systemctl enable "$svc" &>> "$LOG_FILE" || handle_error "Failed to enable $svc."
  798.                 log "Enabled service: $svc."
  799.             fi
  800.         fi
  801.     done
  802.  
  803.     whiptail --title "Adjust Boot Sequence" --msgbox "Boot sequence has been manually adjusted." 8 78
  804.     log "Boot sequence manually adjusted."
  805. }
  806.  
  807. # Function to remove old Linux kernel versions
  808. remove_kernel_versions() {
  809.     # Get current kernel version
  810.     local current_kernel
  811.     current_kernel=$(uname -r)
  812.  
  813.     # List all installed kernel packages excluding the current one
  814.     local kernels
  815.     kernels=$(dpkg --list | grep 'linux-image-[0-9]' | awk '{print $2}' | grep -v "$current_kernel")
  816.  
  817.     if [ -z "$kernels" ]; then
  818.         whiptail --title "Remove Kernel" --msgbox "No additional kernels found to remove." 8 78
  819.         log "No additional kernels found for removal."
  820.         return
  821.     fi
  822.  
  823.     # Prepare checklist options
  824.     local choices=()
  825.     for kernel in $kernels; do
  826.         choices+=("$kernel" "Installed" "OFF")
  827.     done
  828.  
  829.     # Prompt user to select kernels to remove
  830.     local selected_kernels
  831.     selected_kernels=$(whiptail --title "Remove Kernel Versions" --checklist \
  832.         "Select kernels to uninstall:" 20 100 15 \
  833.         "${choices[@]}" 3>&1 1>&2 2>&3)
  834.  
  835.     # Check if user made a selection
  836.     if [ -z "$selected_kernels" ]; then
  837.         log "No kernels selected for removal."
  838.         return
  839.     fi
  840.  
  841.     # Convert selection to an array
  842.     read -r -a selected_kernels <<< "$(echo "$selected_kernels" | tr -d '"')"
  843.  
  844.     # Iterate through selected kernels and remove them
  845.     for kernel in "${selected_kernels[@]}"; do
  846.         if confirm_action "Remove $kernel" "Are you sure you want to remove $kernel?"; then
  847.             whiptail --title "Removing $kernel" --infobox "Removing $kernel..." 8 78
  848.             sudo apt-get purge "$kernel" -y &>> "$LOG_FILE" || handle_error "Failed to remove $kernel."
  849.             sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after removing $kernel."
  850.             log "Removed kernel: $kernel."
  851.         fi
  852.     done
  853.  
  854.     # Update GRUB after kernel removal
  855.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB after kernel removal."
  856.  
  857.     whiptail --title "Remove Kernel Versions" --msgbox "Selected kernels have been removed successfully. Please reboot your system." 8 78
  858.     log "Selected kernels removed successfully."
  859. }
  860.  
  861. # Function to check disk health using smartctl
  862. check_disk_health() {
  863.     # Ensure smartmontools is installed
  864.     if ! dpkg -s smartmontools &>/dev/null; then
  865.         if confirm_action "Install smartmontools" "smartmontools is not installed. Do you want to install it now?"; then
  866.             sudo apt-get update && sudo apt-get install smartmontools -y &>> "$LOG_FILE" || handle_error "Failed to install smartmontools."
  867.             log "smartmontools installed successfully."
  868.         else
  869.             log "smartmontools not installed. Cannot check disk health."
  870.             whiptail --title "Error" --msgbox "smartmontools is required to check disk health." 8 78
  871.             return
  872.         fi
  873.     fi
  874.  
  875.     # List available disks excluding loop devices
  876.     local disks=($(lsblk -d -o NAME,TYPE | awk '$2=="disk"{print $1}'))
  877.  
  878.     if [ ${#disks[@]} -eq 0 ]; then
  879.         whiptail --title "Error" --msgbox "No disks found to check." 8 78
  880.         log "No disks found for health check."
  881.         return
  882.     fi
  883.  
  884.     # Prepare radiolist options
  885.     local choices=()
  886.     for disk in "${disks[@]}"; do
  887.         local size
  888.         size=$(lsblk -d -o SIZE -n "/dev/$disk")
  889.         choices+=("/dev/$disk" "Size: $size" OFF)
  890.     done
  891.  
  892.     # Prompt user to select a disk
  893.     local selected_disk
  894.     selected_disk=$(whiptail --title "Select Disk for Health Check" --radiolist \
  895.         "Choose a disk to check its health:" 20 78 10 \
  896.         "${choices[@]}" 3>&1 1>&2 2>&3)
  897.  
  898.     # Check if user made a selection
  899.     if [ -z "$selected_disk" ]; then
  900.         log "Disk health check cancelled by the user."
  901.         return
  902.     fi
  903.  
  904.     selected_disk=$(echo "$selected_disk" | tr -d '"')
  905.  
  906.     # Run SMART health check
  907.     whiptail --title "Disk Health Check" --infobox "Running SMART health check on $selected_disk..." 8 78
  908.     local health_report
  909.     health_report=$(sudo smartctl -H "$selected_disk" 2>> "$LOG_FILE") || handle_error "Failed to retrieve SMART health report for $selected_disk."
  910.  
  911.     # Parse health status
  912.     local health_status
  913.     health_status=$(echo "$health_report" | grep -oP 'SMART overall-health self-assessment test result: \K.*')
  914.  
  915.     # Interpret the health status
  916.     local message=""
  917.     if [[ "$health_status" =~ ^(PASSED|OK)$ ]]; then
  918.         message="✅ Your disk ($selected_disk) is in good health."
  919.     else
  920.         message="⚠️ Warning: Potential issues detected with disk ($selected_disk). Please investigate further."
  921.     fi
  922.  
  923.     # Display the result
  924.     whiptail --title "Disk Health Check" --msgbox "$message\n\n$health_report" 20 78
  925.     log "Disk health check for $selected_disk: $health_status."
  926. }
  927.  
  928. # Function for Network & Security menu
  929. network_security_menu() {
  930.     local choice
  931.     choice=$(display_menu "Network & Security" "Choose an action:" \
  932.         "1" "Reset Network Configuration" \
  933.         "2" "Reset Firewall Rules" \
  934.         "3" "Back to Main Menu")
  935.  
  936.     case $choice in
  937.         1) reset_network_configuration ;;
  938.         2) reset_firewall_rules ;;
  939.         3) main_menu ;;
  940.         *) log "Invalid selection: $choice"; network_security_menu ;;
  941.     esac
  942. }
  943.  
  944. # Function to reset network configuration
  945. reset_network_configuration() {
  946.     if ! confirm_action "Reset Network Configuration" "Are you sure you want to reset network configuration to default? This will disrupt all active network connections."; then
  947.         log "Reset network configuration cancelled by the user."
  948.         return
  949.     fi
  950.  
  951.     whiptail --title "Reset Network Configuration" --infobox "Resetting network configuration..." 8 78
  952.     sudo systemctl restart NetworkManager &>> "$LOG_FILE" || handle_error "Failed to restart NetworkManager."
  953.  
  954.     # Optionally, reset network settings using nmcli
  955.     sudo nmcli networking off &>> "$LOG_FILE" || handle_error "Failed to turn off networking."
  956.     sudo nmcli networking on &>> "$LOG_FILE" || handle_error "Failed to turn on networking."
  957.  
  958.     whiptail --title "Reset Network Configuration" --msgbox "Network configuration has been reset successfully." 8 78
  959.     log "Network configuration reset successfully."
  960. }
  961.  
  962. # Function to reset firewall rules to default
  963. reset_firewall_rules() {
  964.     if ! confirm_action "Reset Firewall Rules" "Are you sure you want to reset all firewall rules to default? This will remove all custom rules."; then
  965.         log "Reset firewall rules cancelled by the user."
  966.         return
  967.     fi
  968.  
  969.     whiptail --title "Reset Firewall Rules" --infobox "Resetting firewall rules..." 8 78
  970.  
  971.     # Flush iptables rules
  972.     sudo iptables -F &>> "$LOG_FILE" || handle_error "Failed to flush iptables rules."
  973.     sudo iptables -X &>> "$LOG_FILE" || handle_error "Failed to delete iptables chains."
  974.     sudo iptables -t nat -F &>> "$LOG_FILE" || handle_error "Failed to flush NAT table."
  975.     sudo iptables -t nat -X &>> "$LOG_FILE" || handle_error "Failed to delete NAT chains."
  976.  
  977.     # Reset default policies
  978.     sudo iptables -P INPUT ACCEPT &>> "$LOG_FILE" || handle_error "Failed to set INPUT policy."
  979.     sudo iptables -P FORWARD ACCEPT &>> "$LOG_FILE" || handle_error "Failed to set FORWARD policy."
  980.     sudo iptables -P OUTPUT ACCEPT &>> "$LOG_FILE" || handle_error "Failed to set OUTPUT policy."
  981.  
  982.     whiptail --title "Reset Firewall Rules" --msgbox "Firewall rules have been reset to default successfully." 8 78
  983.     log "Firewall rules reset to default successfully."
  984. }
  985.  
  986. # Function for System Tools & Utilities menu
  987. system_tools_utilities_menu() {
  988.     local choice
  989.     choice=$(display_menu "System Tools & Utilities" "Choose an action:" \
  990.         "1" "System Info" \
  991.         "2" "Repair File System" \
  992.         "3" "Clear System Logs" \
  993.         "4" "Reset User Password" \
  994.         "5" "The Final Solution" \
  995.         "6" "Back to Main Menu")
  996.  
  997.     case $choice in
  998.         1) system_info ;;
  999.         2) repair_file_system ;;
  1000.         3) clear_system_logs ;;
  1001.         4) reset_user_password ;;
  1002.         5) the_final_solution ;;
  1003.         6) main_menu ;;
  1004.         *) log "Invalid selection: $choice"; system_tools_utilities_menu ;;
  1005.     esac
  1006. }
  1007.  
  1008. # Function to display system information
  1009. system_info() {
  1010.     # Install required packages if missing
  1011.     local required_pkgs=("neofetch" "lscpu")
  1012.     local missing_pkgs=()
  1013.  
  1014.     for pkg in "${required_pkgs[@]}"; do
  1015.         if ! dpkg -s "$pkg" &>/dev/null; then
  1016.             missing_pkgs+=("$pkg")
  1017.         fi
  1018.     done
  1019.  
  1020.     if [ ${#missing_pkgs[@]} -ne 0 ]; then
  1021.         if confirm_action "Install Missing Packages" "The following packages are missing: ${missing_pkgs[*]}. Install them now?"; then
  1022.             sudo apt-get update && sudo apt-get install -y "${missing_pkgs[@]}" &>> "$LOG_FILE" || handle_error "Failed to install required packages."
  1023.             log "Installed missing packages: ${missing_pkgs[*]}."
  1024.         else
  1025.             whiptail --title "System Info" --msgbox "Cannot display system information without required packages." 8 78
  1026.             log "System info display failed: Required packages missing."
  1027.             return
  1028.         fi
  1029.     fi
  1030.  
  1031.     # Collect system information
  1032.     local sysinfo=""
  1033.     sysinfo+="$(neofetch --stdout)\n"
  1034.     sysinfo+="\nCPU Information:\n$(lscpu)\n"
  1035.     sysinfo+="\nMemory Information:\n$(free -h)\n"
  1036.     sysinfo+="\nDisk Usage:\n$(df -h | grep '^/dev/')\n"
  1037.     sysinfo+="\nKernel Information:\n$(uname -a)\n"
  1038.  
  1039.     # Display the information in a scrollable box
  1040.     whiptail --title "System Information" --scrolltext --msgbox "$sysinfo" 20 100
  1041.     log "Displayed system information."
  1042. }
  1043.  
  1044. # Function to repair file system
  1045. repair_file_system() {
  1046.     # Prompt user to select a disk
  1047.     local disks=($(lsblk -d -o NAME,TYPE | awk '$2=="disk"{print $1}'))
  1048.  
  1049.     if [ ${#disks[@]} -eq 0 ]; then
  1050.         whiptail --title "Error" --msgbox "No disks found to repair." 8 78
  1051.         log "No disks found for file system repair."
  1052.         return
  1053.     fi
  1054.  
  1055.     # Prepare radiolist options
  1056.     local choices=()
  1057.     for disk in "${disks[@]}"; do
  1058.         local size
  1059.         size=$(lsblk -d -o SIZE -n "/dev/$disk")
  1060.         choices+=("/dev/$disk" "Size: $size" OFF)
  1061.     done
  1062.  
  1063.     # Prompt user to select a disk
  1064.     local selected_disk
  1065.     selected_disk=$(whiptail --title "Repair File System" --radiolist \
  1066.         "Select a disk to repair its file system:" 20 80 10 \
  1067.         "${choices[@]}" 3>&1 1>&2 2>&3)
  1068.  
  1069.     # Check if user made a selection
  1070.     if [ -z "$selected_disk" ]; then
  1071.         log "File system repair cancelled by the user."
  1072.         return
  1073.     fi
  1074.  
  1075.     selected_disk=$(echo "$selected_disk" | tr -d '"')
  1076.  
  1077.     # Confirm the repair operation
  1078.     if ! confirm_action "Confirm Repair" "This will check and attempt to repair the file system on $selected_disk. It's recommended to close all other applications before proceeding. Continue?"; then
  1079.         log "File system repair cancelled by the user."
  1080.         return
  1081.     fi
  1082.  
  1083.     # Inform user to perform repair in terminal
  1084.     whiptail --title "Repair File System" --msgbox "Please perform the file system repair on $selected_disk manually in the terminal. Press OK to continue." 8 78
  1085.     log "Prompted user to perform file system repair manually."
  1086.  
  1087.     # Open a terminal window to run fsck (assuming gnome-terminal is available)
  1088.     if command -v gnome-terminal &>/dev/null; then
  1089.         gnome-terminal -- bash -c "sudo fsck -f $selected_disk; exec bash" &
  1090.         log "Opened gnome-terminal for fsck on $selected_disk."
  1091.     else
  1092.         # Fallback to executing fsck in the current terminal
  1093.         sudo fsck -f "$selected_disk" &>> "$LOG_FILE" || handle_error "fsck failed on $selected_disk."
  1094.         log "fsck executed on $selected_disk."
  1095.     fi
  1096.  
  1097.     whiptail --title "Repair File System" --msgbox "File system repair initiated for $selected_disk. Please monitor the terminal for progress." 8 78
  1098. }
  1099.  
  1100. # Function to clear system logs
  1101. clear_system_logs() {
  1102.     if ! confirm_action "Clear System Logs" "Are you sure you want to clear all system logs? This action cannot be undone."; then
  1103.         log "Clear system logs cancelled by the user."
  1104.         return
  1105.     fi
  1106.  
  1107.     whiptail --title "Clearing System Logs" --infobox "Clearing system logs..." 8 78
  1108.     sudo journalctl --rotate &>> "$LOG_FILE" || handle_error "Failed to rotate journal logs."
  1109.     sudo journalctl --vacuum-time=1s &>> "$LOG_FILE" || handle_error "Failed to vacuum journal logs."
  1110.  
  1111.     whiptail --title "Clear System Logs" --msgbox "System logs have been cleared successfully." 8 78
  1112.     log "System logs cleared successfully."
  1113. }
  1114.  
  1115. # Function to reset a user's password
  1116. reset_user_password() {
  1117.     # Prompt for the username
  1118.     local username
  1119.     username=$(whiptail --title "Reset User Password" --inputbox "Enter the username to reset the password for:" 8 60 3>&1 1>&2 2>&3)
  1120.  
  1121.     if [ $? -ne 0 ]; then
  1122.         log "Reset user password cancelled by the user."
  1123.         return
  1124.     fi
  1125.  
  1126.     if [ -z "$username" ]; then
  1127.         whiptail --title "Error" --msgbox "No username entered. Please provide a valid username." 8 78
  1128.         log "Reset user password failed: No username entered."
  1129.         return
  1130.     fi
  1131.  
  1132.     # Check if the user exists
  1133.     if ! id "$username" &>/dev/null; then
  1134.         whiptail --title "Error" --msgbox "User '$username' does not exist." 8 78
  1135.         log "Reset user password failed: User '$username' does not exist."
  1136.         return
  1137.     fi
  1138.  
  1139.     # Prompt user to enter a new password
  1140.     local new_password
  1141.     new_password=$(whiptail --title "Reset User Password" --passwordbox "Enter a new password for $username:" 10 60 3>&1 1>&2 2>&3)
  1142.  
  1143.     if [ $? -ne 0 ]; then
  1144.         log "Reset user password cancelled during password entry."
  1145.         return
  1146.     fi
  1147.  
  1148.     if [ -z "$new_password" ]; then
  1149.         whiptail --title "Error" --msgbox "No password entered. Please provide a valid password." 8 78
  1150.         log "Reset user password failed: No password entered."
  1151.         return
  1152.     fi
  1153.  
  1154.     # Reset the user's password
  1155.     echo "$username:$new_password" | sudo chpasswd &>> "$LOG_FILE" || handle_error "Failed to reset password for $username."
  1156.  
  1157.     whiptail --title "Reset User Password" --msgbox "Password for user '$username' has been reset successfully." 8 78
  1158.     log "Password for user '$username' reset successfully."
  1159. }
  1160.  
  1161. # Function for the final solution (extreme measures)
  1162. the_final_solution() {
  1163.     # Warn the user about the consequences
  1164.     whiptail --title "Warning: The Final Solution" --msgbox "This action will remove everything, including plymouth, xorg, gnome (if installed), cinnamon (if installed), kde (if installed), gdm3, and any other configurations. All original configurations for certain tools will be lost. Proceed with caution and only use this as a last resort." 10 78
  1165.  
  1166.     # Ask for user confirmation
  1167.     if confirm_action "Confirm The Final Solution" "This action is non-reversible. Are you sure you want to proceed with the last resort fresh installation?"; then
  1168.         # Purge critical packages
  1169.         whiptail --title "Executing The Final Solution" --infobox "Purging critical packages..." 8 78
  1170.         sudo apt-get purge '^nvidia.*' '^plymouth.*' '^xorg.*' '^gnome.*' '^cinnamon.*' '^kde.*' '^gdm3.*' '^mate.*' '^xfce.*' '^ubuntu.*' -y &>> "$LOG_FILE" || handle_error "Failed to purge critical packages."
  1171.  
  1172.         # Reinstall essential packages
  1173.         whiptail --title "Reinstalling Essential Packages" --infobox "Reinstalling plymouth, xorg, and cinnamon..." 8 78
  1174.         sudo apt-get install plymouth xorg cinnamon -y &>> "$LOG_FILE" || handle_error "Failed to reinstall essential packages."
  1175.  
  1176.         whiptail --title "The Final Solution" --msgbox "The system has been reset to a fresh installation state. Please reboot your system." 8 78
  1177.         log "The Final Solution executed successfully."
  1178.     else
  1179.         log "The Final Solution cancelled by the user."
  1180.         main_menu
  1181.     fi
  1182. }
  1183.  
  1184. # Function to check installed desktop environments
  1185. check_installed_desktops() {
  1186.     for DE in "${!DESKTOP_ENVS[@]}"; do
  1187.         # Initial assumption is that it's not installed
  1188.         DESKTOP_ENVS[$DE]="not installed"
  1189.  
  1190.         # Check if the package is installed
  1191.         if dpkg -s "${DESKTOP_ENVS[$DE]}" &>/dev/null; then
  1192.             DESKTOP_ENVS[$DE]="installed"
  1193.         else
  1194.             # Additional checks can be added here if necessary
  1195.             :
  1196.         fi
  1197.     done
  1198. }
  1199.  
  1200. # Function for Boot & Disk Management menu
  1201. boot_disk_management_menu() {
  1202.     local choice
  1203.     choice=$(display_menu "Boot & Disk Management" "Choose an action:" \
  1204.         "1" "Optimize Boot Sequence" \
  1205.         "2" "Fix Slow Boot Issues" \
  1206.         "3" "Restore Original Boot Sequence" \
  1207.         "4" "Manually Adjust Boot Sequence" \
  1208.         "5" "Remove Linux Kernel Versions" \
  1209.         "6" "Check Disk Health" \
  1210.         "7" "Back to Main Menu")
  1211.  
  1212.     case $choice in
  1213.         1) optimize_boot_sequence ;;
  1214.         2) fix_slow_boot ;;
  1215.         3) restore_to_distro_default ;;
  1216.         4) manually_adjust_boot_sequence ;;
  1217.         5) remove_kernel_versions ;;
  1218.         6) check_disk_health ;;
  1219.         7) main_menu ;;
  1220.         *) log "Invalid selection: $choice"; boot_disk_management_menu ;;
  1221.     esac
  1222. }
  1223.  
  1224. # Function to optimize boot sequence
  1225. optimize_boot_sequence() {
  1226.     whiptail --title "Optimizing Boot Sequence" --infobox "Backing up current unit files..." 8 78
  1227.     sudo systemctl list-unit-files --state=enabled > "$BACKUP_DIR/unit_files_$(date +%F_%T).backup" || handle_error "Failed to backup unit files."
  1228.  
  1229.     declare -A SERVICE_CATEGORIES=(
  1230.         [system]="systemd-* udev*"
  1231.         [filesystem]="*.mount"
  1232.         [drivers]="*-drivers.*"
  1233.         [user]="user@*.service"
  1234.         [user_defined]="httpd* mysqld* sshd*"
  1235.     )
  1236.  
  1237.     local services_to_process=()
  1238.  
  1239.     for category in "${!SERVICE_CATEGORIES[@]}"; do
  1240.         for pattern in ${SERVICE_CATEGORIES[$category]}; do
  1241.             while IFS= read -r line; do
  1242.                 services_to_process+=("$line")
  1243.             done < <(systemctl list-unit-files --state=enabled | grep "$pattern" | awk '{print $1}')
  1244.         done
  1245.     done
  1246.  
  1247.     local total_services=${#services_to_process[@]}
  1248.     local counter=0
  1249.     local error_occurred=0
  1250.  
  1251.     {
  1252.         for service in "${services_to_process[@]}"; do
  1253.             let counter+=1
  1254.             if ! sudo systemctl disable "$service" &>> "$LOG_FILE"; then
  1255.                 error_occurred=1
  1256.                 echo "XXX"
  1257.                 echo "Failed disabling $service ($counter of $total_services)"
  1258.                 echo "XXX"
  1259.                 echo $((counter * 50 / total_services))
  1260.                 break
  1261.             fi
  1262.             echo "XXX"
  1263.             echo "Disabling $service ($counter of $total_services)"
  1264.             echo "XXX"
  1265.             echo $((counter * 50 / total_services))
  1266.         done
  1267.  
  1268.         if (( error_occurred == 0 )); then
  1269.             for service in "${services_to_process[@]}"; do
  1270.                 let counter+=1
  1271.                 if ! sudo systemctl enable "$service" &>> "$LOG_FILE"; then
  1272.                     error_occurred=1
  1273.                     echo "XXX"
  1274.                     echo "Failed enabling $service ($counter of $total_services)"
  1275.                     echo "XXX"
  1276.                     echo $((counter * 50 / total_services + 50))
  1277.                     break
  1278.                 fi
  1279.                 echo "XXX"
  1280.                 echo "Enabling $service ($counter of $total_services)"
  1281.                 echo "XXX"
  1282.                 echo $((counter * 50 / total_services + 50))
  1283.             done
  1284.         fi
  1285.     } | whiptail --gauge "Optimizing boot sequence..." 20 70 0
  1286.  
  1287.     if (( error_occurred )); then
  1288.         whiptail --title "Error" --msgbox "An error occurred during the optimization process. Check the log file for details." 8 78
  1289.         log "Boot sequence optimization encountered errors."
  1290.     else
  1291.         whiptail --title "Optimize Boot Sequence" --msgbox "Boot sequence optimized successfully." 8 78
  1292.         log "Boot sequence optimized successfully."
  1293.     fi
  1294. }
  1295.  
  1296. # Function to fix slow boot issues
  1297. fix_slow_boot() {
  1298.     whiptail --title "Fix Slow Boot Issues" --infobox "Backing up GRUB configuration..." 8 78
  1299.     sudo cp /etc/default/grub "$BACKUP_DIR/grub.bak_$(date +%F_%T)" || handle_error "Failed to backup GRUB configuration."
  1300.  
  1301.     # Disable plymouth-quit-wait.service
  1302.     sudo systemctl disable plymouth-quit-wait.service &>> "$LOG_FILE" || handle_error "Failed to disable plymouth-quit-wait.service."
  1303.     log "Disabled plymouth-quit-wait.service."
  1304.  
  1305.     # Reduce GRUB timeout
  1306.     sudo sed -i 's/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=5/' /etc/default/grub || handle_error "Failed to set GRUB_TIMEOUT."
  1307.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB."
  1308.  
  1309.     # Optimize systemd services
  1310.     local slow_units
  1311.     slow_units=$(systemd-analyze blame | head -n 5 | awk '{print $2}')
  1312.  
  1313.     for unit in $slow_units; do
  1314.         if confirm_action "Disable $unit" "Do you want to disable the slow service: $unit?"; then
  1315.             sudo systemctl disable "$unit" &>> "$LOG_FILE" || handle_error "Failed to disable $unit."
  1316.             log "Disabled slow service: $unit."
  1317.         fi
  1318.     done
  1319.  
  1320.     # Check for failed systemd units
  1321.     local failed_units
  1322.     failed_units=$(systemctl --failed --no-legend | grep ".service" | awk '{print $1}')
  1323.     if [ -n "$failed_units" ]; then
  1324.         whiptail --title "Failed Services" --msgbox "The following services have failed and may require manual intervention:\n$failed_units" 10 78
  1325.         log "Failed services detected: $failed_units."
  1326.     fi
  1327.  
  1328.     whiptail --title "Fix Slow Boot" --msgbox "Attempted to fix slow boot issues. Some changes might require a reboot." 8 78
  1329.     log "Attempted to fix slow boot issues."
  1330. }
  1331.  
  1332. # Function to restore boot sequence to distribution default
  1333. restore_to_distro_default() {
  1334.     whiptail --title "Restore Boot Sequence" --infobox "Restoring boot sequence to distribution defaults..." 8 78
  1335.  
  1336.     sudo systemctl preset-all &>> "$LOG_FILE" || handle_error "Failed to preset all systemd unit files."
  1337.  
  1338.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB."
  1339.  
  1340.     whiptail --title "Restore Boot Sequence" --msgbox "Boot sequence has been restored to distribution defaults successfully." 8 78
  1341.     log "Boot sequence restored to distribution defaults."
  1342. }
  1343.  
  1344. # Function to manually adjust boot sequence
  1345. manually_adjust_boot_sequence() {
  1346.     # List all enabled services
  1347.     local services
  1348.     services=$(systemctl list-unit-files --state=enabled | awk '{print $1}' | grep '.service')
  1349.  
  1350.     # Prepare checklist options
  1351.     local choices=()
  1352.     for svc in $services; do
  1353.         choices+=("$svc" "" "OFF")
  1354.     done
  1355.  
  1356.     # Prompt user to select services to enable/disable
  1357.     local selected_services
  1358.     selected_services=$(whiptail --title "Adjust Boot Sequence" --checklist \
  1359.         "Select services to toggle (use space to select):" 20 100 15 \
  1360.         "${choices[@]}" 3>&1 1>&2 2>&3)
  1361.  
  1362.     # Check if user made a selection
  1363.     if [ -z "$selected_services" ]; then
  1364.         log "No services selected for manual adjustment."
  1365.         return
  1366.     fi
  1367.  
  1368.     # Convert selection to an array
  1369.     read -r -a selected_services <<< "$(echo "$selected_services" | tr -d '"')"
  1370.  
  1371.     # Iterate through selected services
  1372.     for svc in "${selected_services[@]}"; do
  1373.         if systemctl is-enabled --quiet "$svc"; then
  1374.             if confirm_action "Disable $svc" "Do you want to disable the service: $svc?"; then
  1375.                 sudo systemctl disable "$svc" &>> "$LOG_FILE" || handle_error "Failed to disable $svc."
  1376.                 log "Disabled service: $svc."
  1377.             fi
  1378.         else
  1379.             if confirm_action "Enable $svc" "Do you want to enable the service: $svc?"; then
  1380.                 sudo systemctl enable "$svc" &>> "$LOG_FILE" || handle_error "Failed to enable $svc."
  1381.                 log "Enabled service: $svc."
  1382.             fi
  1383.         fi
  1384.     done
  1385.  
  1386.     whiptail --title "Adjust Boot Sequence" --msgbox "Boot sequence has been manually adjusted." 8 78
  1387.     log "Boot sequence manually adjusted."
  1388. }
  1389.  
  1390. # Function to remove old Linux kernel versions
  1391. remove_kernel_versions() {
  1392.     # Get current kernel version
  1393.     local current_kernel
  1394.     current_kernel=$(uname -r)
  1395.  
  1396.     # List all installed kernel packages excluding the current one
  1397.     local kernels
  1398.     kernels=$(dpkg --list | grep 'linux-image-[0-9]' | awk '{print $2}' | grep -v "$current_kernel")
  1399.  
  1400.     if [ -z "$kernels" ]; then
  1401.         whiptail --title "Remove Kernel" --msgbox "No additional kernels found to remove." 8 78
  1402.         log "No additional kernels found for removal."
  1403.         return
  1404.     fi
  1405.  
  1406.     # Prepare checklist options
  1407.     local choices=()
  1408.     for kernel in $kernels; do
  1409.         choices+=("$kernel" "Installed" "OFF")
  1410.     done
  1411.  
  1412.     # Prompt user to select kernels to remove
  1413.     local selected_kernels
  1414.     selected_kernels=$(whiptail --title "Remove Kernel Versions" --checklist \
  1415.         "Select kernels to uninstall:" 20 100 15 \
  1416.         "${choices[@]}" 3>&1 1>&2 2>&3)
  1417.  
  1418.     # Check if user made a selection
  1419.     if [ -z "$selected_kernels" ]; then
  1420.         log "No kernels selected for removal."
  1421.         return
  1422.     fi
  1423.  
  1424.     # Convert selection to an array
  1425.     read -r -a selected_kernels <<< "$(echo "$selected_kernels" | tr -d '"')"
  1426.  
  1427.     # Iterate through selected kernels and remove them
  1428.     for kernel in "${selected_kernels[@]}"; do
  1429.         if confirm_action "Remove $kernel" "Are you sure you want to remove $kernel?"; then
  1430.             whiptail --title "Removing $kernel" --infobox "Removing $kernel..." 8 78
  1431.             sudo apt-get purge "$kernel" -y &>> "$LOG_FILE" || handle_error "Failed to remove $kernel."
  1432.             sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after removing $kernel."
  1433.             log "Removed kernel: $kernel."
  1434.         fi
  1435.     done
  1436.  
  1437.     # Update GRUB after kernel removal
  1438.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB after kernel removal."
  1439.  
  1440.     whiptail --title "Remove Kernel Versions" --msgbox "Selected kernels have been removed successfully. Please reboot your system." 8 78
  1441.     log "Selected kernels removed successfully."
  1442. }
  1443.  
  1444. # Function to check disk health using smartctl
  1445. check_disk_health() {
  1446.     # Ensure smartmontools is installed
  1447.     if ! dpkg -s smartmontools &>/dev/null; then
  1448.         if confirm_action "Install smartmontools" "smartmontools is not installed. Do you want to install it now?"; then
  1449.             sudo apt-get update && sudo apt-get install smartmontools -y &>> "$LOG_FILE" || handle_error "Failed to install smartmontools."
  1450.             log "smartmontools installed successfully."
  1451.         else
  1452.             log "smartmontools not installed. Cannot check disk health."
  1453.             whiptail --title "Error" --msgbox "smartmontools is required to check disk health." 8 78
  1454.             return
  1455.         fi
  1456.     fi
  1457.  
  1458.     # List available disks excluding loop devices
  1459.     local disks=($(lsblk -d -o NAME,TYPE | awk '$2=="disk"{print $1}'))
  1460.  
  1461.     if [ ${#disks[@]} -eq 0 ]; then
  1462.         whiptail --title "Error" --msgbox "No disks found to check." 8 78
  1463.         log "No disks found for health check."
  1464.         return
  1465.     fi
  1466.  
  1467.     # Prepare radiolist options
  1468.     local choices=()
  1469.     for disk in "${disks[@]}"; do
  1470.         local size
  1471.         size=$(lsblk -d -o SIZE -n "/dev/$disk")
  1472.         choices+=("/dev/$disk" "Size: $size" OFF)
  1473.     done
  1474.  
  1475.     # Prompt user to select a disk
  1476.     local selected_disk
  1477.     selected_disk=$(whiptail --title "Select Disk for Health Check" --radiolist \
  1478.         "Choose a disk to check its health:" 20 78 10 \
  1479.         "${choices[@]}" 3>&1 1>&2 2>&3)
  1480.  
  1481.     # Check if user made a selection
  1482.     if [ -z "$selected_disk" ]; then
  1483.         log "Disk health check cancelled by the user."
  1484.         return
  1485.     fi
  1486.  
  1487.     selected_disk=$(echo "$selected_disk" | tr -d '"')
  1488.  
  1489.     # Run SMART health check
  1490.     whiptail --title "Disk Health Check" --infobox "Running SMART health check on $selected_disk..." 8 78
  1491.     local health_report
  1492.     health_report=$(sudo smartctl -H "$selected_disk" 2>> "$LOG_FILE") || handle_error "Failed to retrieve SMART health report for $selected_disk."
  1493.  
  1494.     # Parse health status
  1495.     local health_status
  1496.     health_status=$(echo "$health_report" | grep -oP 'SMART overall-health self-assessment test result: \K.*')
  1497.  
  1498.     # Interpret the health status
  1499.     local message=""
  1500.     if [[ "$health_status" =~ ^(PASSED|OK)$ ]]; then
  1501.         message="✅ Your disk ($selected_disk) is in good health."
  1502.     else
  1503.         message="⚠️ Warning: Potential issues detected with disk ($selected_disk). Please investigate further."
  1504.     fi
  1505.  
  1506.     # Display the result
  1507.     whiptail --title "Disk Health Check" --msgbox "$message\n\n$health_report" 20 78
  1508.     log "Disk health check for $selected_disk: $health_status."
  1509. }
  1510.  
  1511. # Function for Network & Security menu
  1512. network_security_menu() {
  1513.     local choice
  1514.     choice=$(display_menu "Network & Security" "Choose an action:" \
  1515.         "1" "Reset Network Configuration" \
  1516.         "2" "Reset Firewall Rules" \
  1517.         "3" "Back to Main Menu")
  1518.  
  1519.     case $choice in
  1520.         1) reset_network_configuration ;;
  1521.         2) reset_firewall_rules ;;
  1522.         3) main_menu ;;
  1523.         *) log "Invalid selection: $choice"; network_security_menu ;;
  1524.     esac
  1525. }
  1526.  
  1527. # Function to reset network configuration
  1528. reset_network_configuration() {
  1529.     if ! confirm_action "Reset Network Configuration" "Are you sure you want to reset network configuration to default? This will disrupt all active network connections."; then
  1530.         log "Reset network configuration cancelled by the user."
  1531.         return
  1532.     fi
  1533.  
  1534.     whiptail --title "Reset Network Configuration" --infobox "Resetting network configuration..." 8 78
  1535.     sudo systemctl restart NetworkManager &>> "$LOG_FILE" || handle_error "Failed to restart NetworkManager."
  1536.  
  1537.     # Optionally, reset network settings using nmcli
  1538.     sudo nmcli networking off &>> "$LOG_FILE" || handle_error "Failed to turn off networking."
  1539.     sudo nmcli networking on &>> "$LOG_FILE" || handle_error "Failed to turn on networking."
  1540.  
  1541.     whiptail --title "Reset Network Configuration" --msgbox "Network configuration has been reset successfully." 8 78
  1542.     log "Network configuration reset successfully."
  1543. }
  1544.  
  1545. # Function to reset firewall rules to default
  1546. reset_firewall_rules() {
  1547.     if ! confirm_action "Reset Firewall Rules" "Are you sure you want to reset all firewall rules to default? This will remove all custom rules."; then
  1548.         log "Reset firewall rules cancelled by the user."
  1549.         return
  1550.     fi
  1551.  
  1552.     whiptail --title "Reset Firewall Rules" --infobox "Resetting firewall rules..." 8 78
  1553.  
  1554.     # Flush iptables rules
  1555.     sudo iptables -F &>> "$LOG_FILE" || handle_error "Failed to flush iptables rules."
  1556.     sudo iptables -X &>> "$LOG_FILE" || handle_error "Failed to delete iptables chains."
  1557.     sudo iptables -t nat -F &>> "$LOG_FILE" || handle_error "Failed to flush NAT table."
  1558.     sudo iptables -t nat -X &>> "$LOG_FILE" || handle_error "Failed to delete NAT chains."
  1559.  
  1560.     # Reset default policies
  1561.     sudo iptables -P INPUT ACCEPT &>> "$LOG_FILE" || handle_error "Failed to set INPUT policy."
  1562.     sudo iptables -P FORWARD ACCEPT &>> "$LOG_FILE" || handle_error "Failed to set FORWARD policy."
  1563.     sudo iptables -P OUTPUT ACCEPT &>> "$LOG_FILE" || handle_error "Failed to set OUTPUT policy."
  1564.  
  1565.     whiptail --title "Reset Firewall Rules" --msgbox "Firewall rules have been reset to default successfully." 8 78
  1566.     log "Firewall rules reset to default successfully."
  1567. }
  1568.  
  1569. # Function for System Tools & Utilities menu
  1570. system_tools_utilities_menu() {
  1571.     local choice
  1572.     choice=$(display_menu "System Tools & Utilities" "Choose an action:" \
  1573.         "1" "System Info" \
  1574.         "2" "Repair File System" \
  1575.         "3" "Clear System Logs" \
  1576.         "4" "Reset User Password" \
  1577.         "5" "The Final Solution" \
  1578.         "6" "Back to Main Menu")
  1579.  
  1580.     case $choice in
  1581.         1) system_info ;;
  1582.         2) repair_file_system ;;
  1583.         3) clear_system_logs ;;
  1584.         4) reset_user_password ;;
  1585.         5) the_final_solution ;;
  1586.         6) main_menu ;;
  1587.         *) log "Invalid selection: $choice"; system_tools_utilities_menu ;;
  1588.     esac
  1589. }
  1590.  
  1591. # Function to display system information
  1592. system_info() {
  1593.     # Install required packages if missing
  1594.     local required_pkgs=("neofetch" "lscpu")
  1595.     local missing_pkgs=()
  1596.  
  1597.     for pkg in "${required_pkgs[@]}"; do
  1598.         if ! dpkg -s "$pkg" &>/dev/null; then
  1599.             missing_pkgs+=("$pkg")
  1600.         fi
  1601.     done
  1602.  
  1603.     if [ ${#missing_pkgs[@]} -ne 0 ]; then
  1604.         if confirm_action "Install Missing Packages" "The following packages are missing: ${missing_pkgs[*]}. Install them now?"; then
  1605.             sudo apt-get update && sudo apt-get install -y "${missing_pkgs[@]}" &>> "$LOG_FILE" || handle_error "Failed to install required packages."
  1606.             log "Installed missing packages: ${missing_pkgs[*]}."
  1607.         else
  1608.             whiptail --title "System Info" --msgbox "Cannot display system information without required packages." 8 78
  1609.             log "System info display failed: Required packages missing."
  1610.             return
  1611.         fi
  1612.     fi
  1613.  
  1614.     # Collect system information
  1615.     local sysinfo=""
  1616.     sysinfo+="$(neofetch --stdout)\n"
  1617.     sysinfo+="\nCPU Information:\n$(lscpu)\n"
  1618.     sysinfo+="\nMemory Information:\n$(free -h)\n"
  1619.     sysinfo+="\nDisk Usage:\n$(df -h | grep '^/dev/')\n"
  1620.     sysinfo+="\nKernel Information:\n$(uname -a)\n"
  1621.  
  1622.     # Display the information in a scrollable box
  1623.     whiptail --title "System Information" --scrolltext --msgbox "$sysinfo" 20 100
  1624.     log "Displayed system information."
  1625. }
  1626.  
  1627. # Function to repair file system
  1628. repair_file_system() {
  1629.     # Prompt user to select a disk
  1630.     local disks=($(lsblk -d -o NAME,TYPE | awk '$2=="disk"{print $1}'))
  1631.  
  1632.     if [ ${#disks[@]} -eq 0 ]; then
  1633.         whiptail --title "Error" --msgbox "No disks found to repair." 8 78
  1634.         log "No disks found for file system repair."
  1635.         return
  1636.     fi
  1637.  
  1638.     # Prepare radiolist options
  1639.     local choices=()
  1640.     for disk in "${disks[@]}"; do
  1641.         local size
  1642.         size=$(lsblk -d -o SIZE -n "/dev/$disk")
  1643.         choices+=("/dev/$disk" "Size: $size" OFF)
  1644.     done
  1645.  
  1646.     # Prompt user to select a disk
  1647.     local selected_disk
  1648.     selected_disk=$(whiptail --title "Repair File System" --radiolist \
  1649.         "Select a disk to repair its file system:" 20 80 10 \
  1650.         "${choices[@]}" 3>&1 1>&2 2>&3)
  1651.  
  1652.     # Check if user made a selection
  1653.     if [ -z "$selected_disk" ]; then
  1654.         log "File system repair cancelled by the user."
  1655.         return
  1656.     fi
  1657.  
  1658.     selected_disk=$(echo "$selected_disk" | tr -d '"')
  1659.  
  1660.     # Confirm the repair operation
  1661.     if ! confirm_action "Confirm Repair" "This will check and attempt to repair the file system on $selected_disk. It's recommended to close all other applications before proceeding. Continue?"; then
  1662.         log "File system repair cancelled by the user."
  1663.         return
  1664.     fi
  1665.  
  1666.     # Inform user to perform repair in terminal
  1667.     whiptail --title "Repair File System" --msgbox "Please perform the file system repair on $selected_disk manually in the terminal. Press OK to continue." 8 78
  1668.     log "Prompted user to perform file system repair manually."
  1669.  
  1670.     # Open a terminal window to run fsck (assuming gnome-terminal is available)
  1671.     if command -v gnome-terminal &>/dev/null; then
  1672.         gnome-terminal -- bash -c "sudo fsck -f $selected_disk; exec bash" &
  1673.         log "Opened gnome-terminal for fsck on $selected_disk."
  1674.     else
  1675.         # Fallback to executing fsck in the current terminal
  1676.         sudo fsck -f "$selected_disk" &>> "$LOG_FILE" || handle_error "fsck failed on $selected_disk."
  1677.         log "fsck executed on $selected_disk."
  1678.     fi
  1679.  
  1680.     whiptail --title "Repair File System" --msgbox "File system repair initiated for $selected_disk. Please monitor the terminal for progress." 8 78
  1681. }
  1682.  
  1683. # Function to clear system logs
  1684. clear_system_logs() {
  1685.     if ! confirm_action "Clear System Logs" "Are you sure you want to clear all system logs? This action cannot be undone."; then
  1686.         log "Clear system logs cancelled by the user."
  1687.         return
  1688.     fi
  1689.  
  1690.     whiptail --title "Clearing System Logs" --infobox "Clearing system logs..." 8 78
  1691.     sudo journalctl --rotate &>> "$LOG_FILE" || handle_error "Failed to rotate journal logs."
  1692.     sudo journalctl --vacuum-time=1s &>> "$LOG_FILE" || handle_error "Failed to vacuum journal logs."
  1693.  
  1694.     whiptail --title "Clear System Logs" --msgbox "System logs have been cleared successfully." 8 78
  1695.     log "System logs cleared successfully."
  1696. }
  1697.  
  1698. # Function to reset a user's password
  1699. reset_user_password() {
  1700.     # Prompt for the username
  1701.     local username
  1702.     username=$(whiptail --title "Reset User Password" --inputbox "Enter the username to reset the password for:" 8 60 3>&1 1>&2 2>&3)
  1703.  
  1704.     if [ $? -ne 0 ]; then
  1705.         log "Reset user password cancelled by the user."
  1706.         return
  1707.     fi
  1708.  
  1709.     if [ -z "$username" ]; then
  1710.         whiptail --title "Error" --msgbox "No username entered. Please provide a valid username." 8 78
  1711.         log "Reset user password failed: No username entered."
  1712.         return
  1713.     fi
  1714.  
  1715.     # Check if the user exists
  1716.     if ! id "$username" &>/dev/null; then
  1717.         whiptail --title "Error" --msgbox "User '$username' does not exist." 8 78
  1718.         log "Reset user password failed: User '$username' does not exist."
  1719.         return
  1720.     fi
  1721.  
  1722.     # Prompt user to enter a new password
  1723.     local new_password
  1724.     new_password=$(whiptail --title "Reset User Password" --passwordbox "Enter a new password for $username:" 10 60 3>&1 1>&2 2>&3)
  1725.  
  1726.     if [ $? -ne 0 ]; then
  1727.         log "Reset user password cancelled during password entry."
  1728.         return
  1729.     fi
  1730.  
  1731.     if [ -z "$new_password" ]; then
  1732.         whiptail --title "Error" --msgbox "No password entered. Please provide a valid password." 8 78
  1733.         log "Reset user password failed: No password entered."
  1734.         return
  1735.     fi
  1736.  
  1737.     # Reset the user's password
  1738.     echo "$username:$new_password" | sudo chpasswd &>> "$LOG_FILE" || handle_error "Failed to reset password for $username."
  1739.  
  1740.     whiptail --title "Reset User Password" --msgbox "Password for user '$username' has been reset successfully." 8 78
  1741.     log "Password for user '$username' reset successfully."
  1742. }
  1743.  
  1744. # Function for the final solution (extreme measures)
  1745. the_final_solution() {
  1746.     # Warn the user about the consequences
  1747.     whiptail --title "Warning: The Final Solution" --msgbox "This action will remove everything, including plymouth, xorg, gnome (if installed), cinnamon (if installed), kde (if installed), gdm3, and any other configurations. All original configurations for certain tools will be lost. Proceed with caution and only use this as a last resort." 10 78
  1748.  
  1749.     # Ask for user confirmation
  1750.     if confirm_action "Confirm The Final Solution" "This action is non-reversible. Are you sure you want to proceed with the last resort fresh installation?"; then
  1751.         # Purge critical packages
  1752.         whiptail --title "Executing The Final Solution" --infobox "Purging critical packages..." 8 78
  1753.         sudo apt-get purge '^nvidia.*' '^plymouth.*' '^xorg.*' '^gnome.*' '^cinnamon.*' '^kde.*' '^gdm3.*' '^mate.*' '^xfce.*' '^ubuntu.*' -y &>> "$LOG_FILE" || handle_error "Failed to purge critical packages."
  1754.  
  1755.         # Reinstall essential packages
  1756.         whiptail --title "Reinstalling Essential Packages" --infobox "Reinstalling plymouth, xorg, and cinnamon..." 8 78
  1757.         sudo apt-get install plymouth xorg cinnamon -y &>> "$LOG_FILE" || handle_error "Failed to reinstall essential packages."
  1758.  
  1759.         whiptail --title "The Final Solution" --msgbox "The system has been reset to a fresh installation state. Please reboot your system." 8 78
  1760.         log "The Final Solution executed successfully."
  1761.     else
  1762.         log "The Final Solution cancelled by the user."
  1763.         main_menu
  1764.     fi
  1765. }
  1766.  
  1767. # Function to check installed desktop environments
  1768. check_installed_desktops() {
  1769.     for DE in "${!DESKTOP_ENVS[@]}"; do
  1770.         # Initial assumption is that it's not installed
  1771.         DESKTOP_ENVS[$DE]="not installed"
  1772.  
  1773.         # Check if the package is installed
  1774.         if dpkg -s "${DESKTOP_ENVS[$DE]}" &>/dev/null; then
  1775.             DESKTOP_ENVS[$DE]="installed"
  1776.         else
  1777.             # Additional checks can be added here if necessary
  1778.             :
  1779.         fi
  1780.     done
  1781. }
  1782.  
  1783. # Function for Desktop Environment & Display menu
  1784. desktop_environment_display_menu() {
  1785.     local choice
  1786.     choice=$(display_menu "Desktop Environment & Display" "Choose an action:" \
  1787.         "1" "Purge Xorg" \
  1788.         "2" "Reset X11" \
  1789.         "3" "LightDM Reset" \
  1790.         "4" "Make Wayland Default" \
  1791.         "5" "Desktop Environment Installer/Remover" \
  1792.         "6" "Startx Attempt" \
  1793.         "7" "Cinnamon Repair" \
  1794.         "8" "Back to Main Menu")
  1795.  
  1796.     case $choice in
  1797.         1) purge_xorg ;;
  1798.         2) reset_x11 ;;
  1799.         3) lightdm_reset ;;
  1800.         4) make_wayland_default ;;
  1801.         5) desktop_environment_installer_remover ;;
  1802.         6) startx_attempt ;;
  1803.         7) cinnamon_repair ;;
  1804.         8) main_menu ;;
  1805.         *) log "Invalid selection: $choice"; desktop_environment_display_menu ;;
  1806.     esac
  1807. }
  1808.  
  1809. # Function to install or remove desktop environments
  1810. desktop_environment_installer_remover() {
  1811.     # Refresh the installation status
  1812.     check_installed_desktops
  1813.  
  1814.     # Prepare checklist options
  1815.     local choices=()
  1816.     for DE in "${!DESKTOP_ENVS[@]}"; do
  1817.         local status="${DESKTOP_ENVS[$DE]}"
  1818.         if [[ "$status" == "installed" ]]; then
  1819.             choices+=("$DE" "Installed" "ON")
  1820.         else
  1821.             choices+=("$DE" "Not Installed" "OFF")
  1822.         fi
  1823.     done
  1824.  
  1825.     # Prompt user to select desktop environments to install/remove
  1826.     local selected_des
  1827.     selected_des=$(whiptail --title "Desktop Environment Installer/Remover" --checklist \
  1828.         "Select desktop environments to install or remove:" 20 80 12 \
  1829.         "${choices[@]}" 3>&1 1>&2 2>&3)
  1830.  
  1831.     # Check if user made a selection
  1832.     if [ -z "$selected_des" ]; then
  1833.         log "No desktop environments selected for installation/removal."
  1834.         return
  1835.     fi
  1836.  
  1837.     # Convert selection to an array
  1838.     read -r -a selected_des <<< "$(echo "$selected_des" | tr -d '"')"
  1839.  
  1840.     # Iterate through selected desktop environments
  1841.     for DE in "${selected_des[@]}"; do
  1842.         if [[ "${DESKTOP_ENVS[$DE]}" == "installed" ]]; then
  1843.             # Prompt to remove the desktop environment
  1844.             if confirm_action "Remove $DE" "Do you want to remove the $DE desktop environment?"; then
  1845.                 whiptail --title "Removing $DE" --infobox "Removing $DE desktop environment..." 8 78
  1846.                 sudo apt-get purge "${DESKTOP_ENVS[$DE]}" -y &>> "$LOG_FILE" || handle_error "Failed to remove $DE."
  1847.                 sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after removing $DE."
  1848.                 whiptail --title "Remove $DE" --msgbox "$DE has been removed successfully." 8 78
  1849.                 log "$DE desktop environment removed successfully."
  1850.             else
  1851.                 log "Removal of $DE cancelled by the user."
  1852.             fi
  1853.         else
  1854.             # Prompt to install the desktop environment
  1855.             if confirm_action "Install $DE" "Do you want to install the $DE desktop environment?"; then
  1856.                 whiptail --title "Installing $DE" --infobox "Installing $DE desktop environment..." 8 78
  1857.                 sudo apt-get install "${DESKTOP_ENVS[$DE]}" -y &>> "$LOG_FILE" || handle_error "Failed to install $DE."
  1858.                 whiptail --title "Install $DE" --msgbox "$DE desktop environment has been installed successfully." 8 78
  1859.                 log "$DE desktop environment installed successfully."
  1860.             else
  1861.                 log "Installation of $DE cancelled by the user."
  1862.             fi
  1863.         fi
  1864.     done
  1865.  
  1866.     # Refresh desktop environment status
  1867.     check_installed_desktops
  1868. }
  1869.  
  1870. # Function to attempt running startx
  1871. startx_attempt() {
  1872.     whiptail --title "Startx Attempt" --msgbox "Attempting to start X server using startx. This will close all open applications." 8 78
  1873.     log "Attempting to start X server using startx."
  1874.  
  1875.     # Execute startx and log output
  1876.     startx &>> "$LOG_FILE" || handle_error "Failed to start X server with startx."
  1877.  
  1878.     whiptail --title "Startx Attempt" --msgbox "startx command executed. Check the log file for details." 8 78
  1879.     log "startx command executed."
  1880. }
  1881.  
  1882. # Function to repair Cinnamon desktop environment
  1883. cinnamon_repair() {
  1884.     if ! dpkg -s cinnamon &>/dev/null && ! dpkg -s mint-meta-cinnamon &>/dev/null; then
  1885.         whiptail --title "Error" --msgbox "Cinnamon is not installed on your system." 8 78
  1886.         log "Cinnamon repair failed: Cinnamon is not installed."
  1887.         return
  1888.     fi
  1889.  
  1890.     whiptail --title "Cinnamon Repair" --infobox "Reinstalling Cinnamon packages..." 8 78
  1891.     sudo apt-get install --reinstall cinnamon mint-meta-cinnamon -y &>> "$LOG_FILE" || handle_error "Failed to reinstall Cinnamon packages."
  1892.  
  1893.     whiptail --title "Cinnamon Repair" --infobox "Resetting Cinnamon settings..." 8 78
  1894.     dconf reset -f /org/cinnamon/ &>> "$LOG_FILE" || handle_error "Failed to reset Cinnamon settings."
  1895.  
  1896.     whiptail --title "Cinnamon Repair" --msgbox "Cinnamon has been repaired and reset successfully." 8 78
  1897.     log "Cinnamon repaired and reset successfully."
  1898. }
  1899.  
  1900. # Function for System Tools & Utilities menu
  1901. system_tools_utilities_menu() {
  1902.     local choice
  1903.     choice=$(display_menu "System Tools & Utilities" "Choose an action:" \
  1904.         "1" "System Info" \
  1905.         "2" "Repair File System" \
  1906.         "3" "Clear System Logs" \
  1907.         "4" "Reset User Password" \
  1908.         "5" "The Final Solution" \
  1909.         "6" "Back to Main Menu")
  1910.  
  1911.     case $choice in
  1912.         1) system_info ;;
  1913.         2) repair_file_system ;;
  1914.         3) clear_system_logs ;;
  1915.         4) reset_user_password ;;
  1916.         5) the_final_solution ;;
  1917.         6) main_menu ;;
  1918.         *) log "Invalid selection: $choice"; system_tools_utilities_menu ;;
  1919.     esac
  1920. }
  1921.  
  1922. # Function for the final solution (extreme measures)
  1923. the_final_solution() {
  1924.     # Warn the user about the consequences
  1925.     whiptail --title "Warning: The Final Solution" --msgbox "This action will remove everything, including plymouth, xorg, gnome (if installed), cinnamon (if installed), kde (if installed), gdm3, and any other configurations. All original configurations for certain tools will be lost. Proceed with caution and only use this as a last resort." 10 78
  1926.  
  1927.     # Ask for user confirmation
  1928.     if confirm_action "Confirm The Final Solution" "This action is non-reversible. Are you sure you want to proceed with the last resort fresh installation?"; then
  1929.         # Purge critical packages
  1930.         whiptail --title "Executing The Final Solution" --infobox "Purging critical packages..." 8 78
  1931.         sudo apt-get purge '^nvidia.*' '^plymouth.*' '^xorg.*' '^gnome.*' '^cinnamon.*' '^kde.*' '^gdm3.*' '^mate.*' '^xfce.*' '^ubuntu.*' -y &>> "$LOG_FILE" || handle_error "Failed to purge critical packages."
  1932.  
  1933.         # Reinstall essential packages
  1934.         whiptail --title "Reinstalling Essential Packages" --infobox "Reinstalling plymouth, xorg, and cinnamon..." 8 78
  1935.         sudo apt-get install plymouth xorg cinnamon -y &>> "$LOG_FILE" || handle_error "Failed to reinstall essential packages."
  1936.  
  1937.         whiptail --title "The Final Solution" --msgbox "The system has been reset to a fresh installation state. Please reboot your system." 8 78
  1938.         log "The Final Solution executed successfully."
  1939.     else
  1940.         log "The Final Solution cancelled by the user."
  1941.         main_menu
  1942.     fi
  1943. }
  1944.  
  1945. # Function to check installed desktop environments
  1946. check_installed_desktops() {
  1947.     for DE in "${!DESKTOP_ENVS[@]}"; do
  1948.         # Initial assumption is that it's not installed
  1949.         DESKTOP_ENVS[$DE]="not installed"
  1950.  
  1951.         # Check if the package is installed
  1952.         if dpkg -s "${DESKTOP_ENVS[$DE]}" &>/dev/null; then
  1953.             DESKTOP_ENVS[$DE]="installed"
  1954.         else
  1955.             # Additional checks can be added here if necessary
  1956.             :
  1957.         fi
  1958.     done
  1959. }
  1960.  
  1961. # Function for Boot & Disk Management menu
  1962. boot_disk_management_menu() {
  1963.     local choice
  1964.     choice=$(display_menu "Boot & Disk Management" "Choose an action:" \
  1965.         "1" "Optimize Boot Sequence" \
  1966.         "2" "Fix Slow Boot Issues" \
  1967.         "3" "Restore Original Boot Sequence" \
  1968.         "4" "Manually Adjust Boot Sequence" \
  1969.         "5" "Remove Linux Kernel Versions" \
  1970.         "6" "Check Disk Health" \
  1971.         "7" "Back to Main Menu")
  1972.  
  1973.     case $choice in
  1974.         1) optimize_boot_sequence ;;
  1975.         2) fix_slow_boot ;;
  1976.         3) restore_to_distro_default ;;
  1977.         4) manually_adjust_boot_sequence ;;
  1978.         5) remove_kernel_versions ;;
  1979.         6) check_disk_health ;;
  1980.         7) main_menu ;;
  1981.         *) log "Invalid selection: $choice"; boot_disk_management_menu ;;
  1982.     esac
  1983. }
  1984.  
  1985. # Function to optimize boot sequence
  1986. optimize_boot_sequence() {
  1987.     whiptail --title "Optimizing Boot Sequence" --infobox "Backing up current unit files..." 8 78
  1988.     sudo systemctl list-unit-files --state=enabled > "$BACKUP_DIR/unit_files_$(date +%F_%T).backup" || handle_error "Failed to backup unit files."
  1989.  
  1990.     declare -A SERVICE_CATEGORIES=(
  1991.         [system]="systemd-* udev*"
  1992.         [filesystem]="*.mount"
  1993.         [drivers]="*-drivers.*"
  1994.         [user]="user@*.service"
  1995.         [user_defined]="httpd* mysqld* sshd*"
  1996.     )
  1997.  
  1998.     local services_to_process=()
  1999.  
  2000.     for category in "${!SERVICE_CATEGORIES[@]}"; do
  2001.         for pattern in ${SERVICE_CATEGORIES[$category]}; do
  2002.             while IFS= read -r line; do
  2003.                 services_to_process+=("$line")
  2004.             done < <(systemctl list-unit-files --state=enabled | grep "$pattern" | awk '{print $1}')
  2005.         done
  2006.     done
  2007.  
  2008.     local total_services=${#services_to_process[@]}
  2009.     local counter=0
  2010.     local error_occurred=0
  2011.  
  2012.     {
  2013.         for service in "${services_to_process[@]}"; do
  2014.             let counter+=1
  2015.             if ! sudo systemctl disable "$service" &>> "$LOG_FILE"; then
  2016.                 error_occurred=1
  2017.                 echo "XXX"
  2018.                 echo "Failed disabling $service ($counter of $total_services)"
  2019.                 echo "XXX"
  2020.                 echo $((counter * 50 / total_services))
  2021.                 break
  2022.             fi
  2023.             echo "XXX"
  2024.             echo "Disabling $service ($counter of $total_services)"
  2025.             echo "XXX"
  2026.             echo $((counter * 50 / total_services))
  2027.         done
  2028.  
  2029.         if (( error_occurred == 0 )); then
  2030.             for service in "${services_to_process[@]}"; do
  2031.                 let counter+=1
  2032.                 if ! sudo systemctl enable "$service" &>> "$LOG_FILE"; then
  2033.                     error_occurred=1
  2034.                     echo "XXX"
  2035.                     echo "Failed enabling $service ($counter of $total_services)"
  2036.                     echo "XXX"
  2037.                     echo $((counter * 50 / total_services + 50))
  2038.                     break
  2039.                 fi
  2040.                 echo "XXX"
  2041.                 echo "Enabling $service ($counter of $total_services)"
  2042.                 echo "XXX"
  2043.                 echo $((counter * 50 / total_services + 50))
  2044.             done
  2045.         fi
  2046.     } | whiptail --gauge "Optimizing boot sequence..." 20 70 0
  2047.  
  2048.     if (( error_occurred )); then
  2049.         whiptail --title "Error" --msgbox "An error occurred during the optimization process. Check the log file for details." 8 78
  2050.         log "Boot sequence optimization encountered errors."
  2051.     else
  2052.         whiptail --title "Optimize Boot Sequence" --msgbox "Boot sequence optimized successfully." 8 78
  2053.         log "Boot sequence optimized successfully."
  2054.     fi
  2055. }
  2056.  
  2057. # Function to fix slow boot issues
  2058. fix_slow_boot() {
  2059.     whiptail --title "Fix Slow Boot Issues" --infobox "Backing up GRUB configuration..." 8 78
  2060.     sudo cp /etc/default/grub "$BACKUP_DIR/grub.bak_$(date +%F_%T)" || handle_error "Failed to backup GRUB configuration."
  2061.  
  2062.     # Disable plymouth-quit-wait.service
  2063.     sudo systemctl disable plymouth-quit-wait.service &>> "$LOG_FILE" || handle_error "Failed to disable plymouth-quit-wait.service."
  2064.     log "Disabled plymouth-quit-wait.service."
  2065.  
  2066.     # Reduce GRUB timeout
  2067.     sudo sed -i 's/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=5/' /etc/default/grub || handle_error "Failed to set GRUB_TIMEOUT."
  2068.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB."
  2069.  
  2070.     # Optimize systemd services
  2071.     local slow_units
  2072.     slow_units=$(systemd-analyze blame | head -n 5 | awk '{print $2}')
  2073.  
  2074.     for unit in $slow_units; do
  2075.         if confirm_action "Disable $unit" "Do you want to disable the slow service: $unit?"; then
  2076.             sudo systemctl disable "$unit" &>> "$LOG_FILE" || handle_error "Failed to disable $unit."
  2077.             log "Disabled slow service: $unit."
  2078.         fi
  2079.     done
  2080.  
  2081.     # Check for failed systemd units
  2082.     local failed_units
  2083.     failed_units=$(systemctl --failed --no-legend | grep ".service" | awk '{print $1}')
  2084.     if [ -n "$failed_units" ]; then
  2085.         whiptail --title "Failed Services" --msgbox "The following services have failed and may require manual intervention:\n$failed_units" 10 78
  2086.         log "Failed services detected: $failed_units."
  2087.     fi
  2088.  
  2089.     whiptail --title "Fix Slow Boot" --msgbox "Attempted to fix slow boot issues. Some changes might require a reboot." 8 78
  2090.     log "Attempted to fix slow boot issues."
  2091. }
  2092.  
  2093. # Function to restore boot sequence to distribution default
  2094. restore_to_distro_default() {
  2095.     whiptail --title "Restore Boot Sequence" --infobox "Restoring boot sequence to distribution defaults..." 8 78
  2096.  
  2097.     sudo systemctl preset-all &>> "$LOG_FILE" || handle_error "Failed to preset all systemd unit files."
  2098.  
  2099.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB."
  2100.  
  2101.     whiptail --title "Restore Boot Sequence" --msgbox "Boot sequence has been restored to distribution defaults successfully." 8 78
  2102.     log "Boot sequence restored to distribution defaults."
  2103. }
  2104.  
  2105. # Function to manually adjust boot sequence
  2106. manually_adjust_boot_sequence() {
  2107.     # List all enabled services
  2108.     local services
  2109.     services=$(systemctl list-unit-files --state=enabled | awk '{print $1}' | grep '.service')
  2110.  
  2111.     # Prepare checklist options
  2112.     local choices=()
  2113.     for svc in $services; do
  2114.         choices+=("$svc" "" "OFF")
  2115.     done
  2116.  
  2117.     # Prompt user to select services to enable/disable
  2118.     local selected_services
  2119.     selected_services=$(whiptail --title "Adjust Boot Sequence" --checklist \
  2120.         "Select services to toggle (use space to select):" 20 100 15 \
  2121.         "${choices[@]}" 3>&1 1>&2 2>&3)
  2122.  
  2123.     # Check if user made a selection
  2124.     if [ -z "$selected_services" ]; then
  2125.         log "No services selected for manual adjustment."
  2126.         return
  2127.     fi
  2128.  
  2129.     # Convert selection to an array
  2130.     read -r -a selected_services <<< "$(echo "$selected_services" | tr -d '"')"
  2131.  
  2132.     # Iterate through selected services
  2133.     for svc in "${selected_services[@]}"; do
  2134.         if systemctl is-enabled --quiet "$svc"; then
  2135.             if confirm_action "Disable $svc" "Do you want to disable the service: $svc?"; then
  2136.                 sudo systemctl disable "$svc" &>> "$LOG_FILE" || handle_error "Failed to disable $svc."
  2137.                 log "Disabled service: $svc."
  2138.             fi
  2139.         else
  2140.             if confirm_action "Enable $svc" "Do you want to enable the service: $svc?"; then
  2141.                 sudo systemctl enable "$svc" &>> "$LOG_FILE" || handle_error "Failed to enable $svc."
  2142.                 log "Enabled service: $svc."
  2143.             fi
  2144.         fi
  2145.     done
  2146.  
  2147.     whiptail --title "Adjust Boot Sequence" --msgbox "Boot sequence has been manually adjusted." 8 78
  2148.     log "Boot sequence manually adjusted."
  2149. }
  2150.  
  2151. # Function to remove old Linux kernel versions
  2152. remove_kernel_versions() {
  2153.     # Get current kernel version
  2154.     local current_kernel
  2155.     current_kernel=$(uname -r)
  2156.  
  2157.     # List all installed kernel packages excluding the current one
  2158.     local kernels
  2159.     kernels=$(dpkg --list | grep 'linux-image-[0-9]' | awk '{print $2}' | grep -v "$current_kernel")
  2160.  
  2161.     if [ -z "$kernels" ]; then
  2162.         whiptail --title "Remove Kernel" --msgbox "No additional kernels found to remove." 8 78
  2163.         log "No additional kernels found for removal."
  2164.         return
  2165.     fi
  2166.  
  2167.     # Prepare checklist options
  2168.     local choices=()
  2169.     for kernel in $kernels; do
  2170.         choices+=("$kernel" "Installed" "OFF")
  2171.     done
  2172.  
  2173.     # Prompt user to select kernels to remove
  2174.     local selected_kernels
  2175.     selected_kernels=$(whiptail --title "Remove Kernel Versions" --checklist \
  2176.         "Select kernels to uninstall:" 20 100 15 \
  2177.         "${choices[@]}" 3>&1 1>&2 2>&3)
  2178.  
  2179.     # Check if user made a selection
  2180.     if [ -z "$selected_kernels" ]; then
  2181.         log "No kernels selected for removal."
  2182.         return
  2183.     fi
  2184.  
  2185.     # Convert selection to an array
  2186.     read -r -a selected_kernels <<< "$(echo "$selected_kernels" | tr -d '"')"
  2187.  
  2188.     # Iterate through selected kernels and remove them
  2189.     for kernel in "${selected_kernels[@]}"; do
  2190.         if confirm_action "Remove $kernel" "Are you sure you want to remove $kernel?"; then
  2191.             whiptail --title "Removing $kernel" --infobox "Removing $kernel..." 8 78
  2192.             sudo apt-get purge "$kernel" -y &>> "$LOG_FILE" || handle_error "Failed to remove $kernel."
  2193.             sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after removing $kernel."
  2194.             log "Removed kernel: $kernel."
  2195.         fi
  2196.     done
  2197.  
  2198.     # Update GRUB after kernel removal
  2199.     sudo update-grub &>> "$LOG_FILE" || handle_error "Failed to update GRUB after kernel removal."
  2200.  
  2201.     whiptail --title "Remove Kernel Versions" --msgbox "Selected kernels have been removed successfully. Please reboot your system." 8 78
  2202.     log "Selected kernels removed successfully."
  2203. }
  2204.  
  2205. # Function to check disk health using smartctl
  2206. check_disk_health() {
  2207.     # Ensure smartmontools is installed
  2208.     if ! dpkg -s smartmontools &>/dev/null; then
  2209.         if confirm_action "Install smartmontools" "smartmontools is not installed. Do you want to install it now?"; then
  2210.             sudo apt-get update && sudo apt-get install smartmontools -y &>> "$LOG_FILE" || handle_error "Failed to install smartmontools."
  2211.             log "smartmontools installed successfully."
  2212.         else
  2213.             log "smartmontools not installed. Cannot check disk health."
  2214.             whiptail --title "Error" --msgbox "smartmontools is required to check disk health." 8 78
  2215.             return
  2216.         fi
  2217.     fi
  2218.  
  2219.     # List available disks excluding loop devices
  2220.     local disks=($(lsblk -d -o NAME,TYPE | awk '$2=="disk"{print $1}'))
  2221.  
  2222.     if [ ${#disks[@]} -eq 0 ]; then
  2223.         whiptail --title "Error" --msgbox "No disks found to check." 8 78
  2224.         log "No disks found for health check."
  2225.         return
  2226.     fi
  2227.  
  2228.     # Prepare radiolist options
  2229.     local choices=()
  2230.     for disk in "${disks[@]}"; do
  2231.         local size
  2232.         size=$(lsblk -d -o SIZE -n "/dev/$disk")
  2233.         choices+=("/dev/$disk" "Size: $size" OFF)
  2234.     done
  2235.  
  2236.     # Prompt user to select a disk
  2237.     local selected_disk
  2238.     selected_disk=$(whiptail --title "Select Disk for Health Check" --radiolist \
  2239.         "Choose a disk to check its health:" 20 78 10 \
  2240.         "${choices[@]}" 3>&1 1>&2 2>&3)
  2241.  
  2242.     # Check if user made a selection
  2243.     if [ -z "$selected_disk" ]; then
  2244.         log "Disk health check cancelled by the user."
  2245.         return
  2246.     fi
  2247.  
  2248.     selected_disk=$(echo "$selected_disk" | tr -d '"')
  2249.  
  2250.     # Run SMART health check
  2251.     whiptail --title "Disk Health Check" --infobox "Running SMART health check on $selected_disk..." 8 78
  2252.     local health_report
  2253.     health_report=$(sudo smartctl -H "$selected_disk" 2>> "$LOG_FILE") || handle_error "Failed to retrieve SMART health report for $selected_disk."
  2254.  
  2255.     # Parse health status
  2256.     local health_status
  2257.     health_status=$(echo "$health_report" | grep -oP 'SMART overall-health self-assessment test result: \K.*')
  2258.  
  2259.     # Interpret the health status
  2260.     local message=""
  2261.     if [[ "$health_status" =~ ^(PASSED|OK)$ ]]; then
  2262.         message="✅ Your disk ($selected_disk) is in good health."
  2263.     else
  2264.         message="⚠️ Warning: Potential issues detected with disk ($selected_disk). Please investigate further."
  2265.     fi
  2266.  
  2267.     # Display the result
  2268.     whiptail --title "Disk Health Check" --msgbox "$message\n\n$health_report" 20 78
  2269.     log "Disk health check for $selected_disk: $health_status."
  2270. }
  2271.  
  2272. # Function to install or remove desktop environments
  2273. desktop_environment_installer_remover() {
  2274.     # Refresh the installation status
  2275.     check_installed_desktops
  2276.  
  2277.     # Prepare checklist options
  2278.     local choices=()
  2279.     for DE in "${!DESKTOP_ENVS[@]}"; do
  2280.         local status="${DESKTOP_ENVS[$DE]}"
  2281.         if [[ "$status" == "installed" ]]; then
  2282.             choices+=("$DE" "Installed" "ON")
  2283.         else
  2284.             choices+=("$DE" "Not Installed" "OFF")
  2285.         fi
  2286.     done
  2287.  
  2288.     # Prompt user to select desktop environments to install/remove
  2289.     local selected_des
  2290.     selected_des=$(whiptail --title "Desktop Environment Installer/Remover" --checklist \
  2291.         "Select desktop environments to install or remove:" 20 80 12 \
  2292.         "${choices[@]}" 3>&1 1>&2 2>&3)
  2293.  
  2294.     # Check if user made a selection
  2295.     if [ -z "$selected_des" ]; then
  2296.         log "No desktop environments selected for installation/removal."
  2297.         return
  2298.     fi
  2299.  
  2300.     # Convert selection to an array
  2301.     read -r -a selected_des <<< "$(echo "$selected_des" | tr -d '"')"
  2302.  
  2303.     # Iterate through selected desktop environments
  2304.     for DE in "${selected_des[@]}"; do
  2305.         if [[ "${DESKTOP_ENVS[$DE]}" == "installed" ]]; then
  2306.             # Prompt to remove the desktop environment
  2307.             if confirm_action "Remove $DE" "Do you want to remove the $DE desktop environment?"; then
  2308.                 whiptail --title "Removing $DE" --infobox "Removing $DE desktop environment..." 8 78
  2309.                 sudo apt-get purge "${DESKTOP_ENVS[$DE]}" -y &>> "$LOG_FILE" || handle_error "Failed to remove $DE."
  2310.                 sudo apt-get autoremove -y &>> "$LOG_FILE" || handle_error "Failed to autoremove dependencies after removing $DE."
  2311.                 whiptail --title "Remove $DE" --msgbox "$DE has been removed successfully." 8 78
  2312.                 log "$DE desktop environment removed successfully."
  2313.             else
  2314.                 log "Removal of $DE cancelled by the user."
  2315.             fi
  2316.         else
  2317.             # Prompt to install the desktop environment
  2318.             if confirm_action "Install $DE" "Do you want to install the $DE desktop environment?"; then
  2319.                 whiptail --title "Installing $DE" --infobox "Installing $DE desktop environment..." 8 78
  2320.                 sudo apt-get install "${DESKTOP_ENVS[$DE]}" -y &>> "$LOG_FILE" || handle_error "Failed to install $DE."
  2321.                 whiptail --title "Install $DE" --msgbox "$DE desktop environment has been installed successfully." 8 78
  2322.                 log "$DE desktop environment installed successfully."
  2323.             else
  2324.                 log "Installation of $DE cancelled by the user."
  2325.             fi
  2326.         fi
  2327.     done
  2328.  
  2329.     # Refresh desktop environment status
  2330.     check_installed_desktops
  2331. }
  2332.  
  2333. # Function to attempt running startx
  2334. startx_attempt() {
  2335.     whiptail --title "Startx Attempt" --msgbox "Attempting to start X server using startx. This will close all open applications." 8 78
  2336.     log "Attempting to start X server using startx."
  2337.  
  2338.     # Execute startx and log output
  2339.     startx &>> "$LOG_FILE" || handle_error "Failed to start X server with startx."
  2340.  
  2341.     whiptail --title "Startx Attempt" --msgbox "startx command executed. Check the log file for details." 8 78
  2342.     log "startx command executed."
  2343. }
  2344.  
  2345. # Function to repair Cinnamon desktop environment
  2346. cinnamon_repair() {
  2347.     if ! dpkg -s cinnamon &>/dev/null && ! dpkg -s mint-meta-cinnamon &>/dev/null; then
  2348.         whiptail --title "Error" --msgbox "Cinnamon is not installed on your system." 8 78
  2349.         log "Cinnamon repair failed: Cinnamon is not installed."
  2350.         return
  2351.     fi
  2352.  
  2353.     whiptail --title "Cinnamon Repair" --infobox "Reinstalling Cinnamon packages..." 8 78
  2354.     sudo apt-get install --reinstall cinnamon mint-meta-cinnamon -y &>> "$LOG_FILE" || handle_error "Failed to reinstall Cinnamon packages."
  2355.  
  2356.     whiptail --title "Cinnamon Repair" --infobox "Resetting Cinnamon settings..." 8 78
  2357.     dconf reset -f /org/cinnamon/ &>> "$LOG_FILE" || handle_error "Failed to reset Cinnamon settings."
  2358.  
  2359.     whiptail --title "Cinnamon Repair" --msgbox "Cinnamon has been repaired and reset successfully." 8 78
  2360.     log "Cinnamon repaired and reset successfully."
  2361. }
  2362.  
  2363. # Function to check installed desktop environments
  2364. check_installed_desktops() {
  2365.     for DE in "${!DESKTOP_ENVS[@]}"; do
  2366.         # Initial assumption is that it's not installed
  2367.         DESKTOP_ENVS[$DE]="not installed"
  2368.  
  2369.         # Check if the package is installed
  2370.         if dpkg -s "${DESKTOP_ENVS[$DE]}" &>/dev/null; then
  2371.             DESKTOP_ENVS[$DE]="installed"
  2372.         else
  2373.             # Additional checks can be added here if necessary
  2374.             :
  2375.         fi
  2376.     done
  2377. }
  2378.  
  2379. # Function to ensure smartmontools is installed
  2380. ensure_smartmontools_installed() {
  2381.     if ! dpkg -s smartmontools &>/dev/null; then
  2382.         if confirm_action "Install smartmontools" "smartmontools is not installed. Do you want to install it now?"; then
  2383.             sudo apt-get update && sudo apt-get install smartmontools -y &>> "$LOG_FILE" || handle_error "Failed to install smartmontools."
  2384.             log "smartmontools installed successfully."
  2385.         else
  2386.             log "smartmontools not installed."
  2387.         fi
  2388.     fi
  2389. }
  2390.  
  2391. # Main function to start the script
  2392. main() {
  2393.     ask_for_sudo
  2394.     ensure_smartmontools_installed
  2395.     check_installed_desktops
  2396.     while true; do
  2397.         main_menu
  2398.     done
  2399. }
  2400.  
  2401. # Start the script
  2402. main
  2403.  
Add Comment
Please, Sign In to add comment