diff --git a/debianito.sh b/debianito.sh index 7339c2f..3d094aa 100644 --- a/debianito.sh +++ b/debianito.sh @@ -29,6 +29,7 @@ source "${MODULES_DIR}/repos.sh" [ -f "${MODULES_DIR}/zram.sh" ] && source "${MODULES_DIR}/zram.sh" [ -f "${MODULES_DIR}/extras/java.sh" ] && source "${MODULES_DIR}/extras/java.sh" [ -f "${MODULES_DIR}/rescue.sh" ] && source "${MODULES_DIR}/rescue.sh" +[ -f "${MODULES_DIR}/swap.sh" ] && source "${MODULES_DIR}/swap.sh" # ── Bullseye-specific modules (loaded only on Debian 11) ── if [ -d "${MODULES_DIR}/bullseye" ]; then @@ -43,7 +44,7 @@ DEBIAN_CODENAME="" main_menu() { # Auto-adjust TUI dimensions for small terminals - if [ "$LINES" -lt $((TUI_ALTO + 6)) ] || [ "$COLUMNS" -lt $((TUI_ANCHO + 6)) ]; then + if [ "${LINES:-24}" -lt $((TUI_ALTO + 6)) ] || [ "${COLUMNS:-80}" -lt $((TUI_ANCHO + 6)) ]; then TUI_ALTO=$((LINES - 4 > 8 ? LINES - 4 : 8)) TUI_ANCHO=$((COLUMNS - 4 > 50 ? COLUMNS - 4 : 50)) TUI_ALTO_LISTA=$((TUI_ALTO - 10 > 4 ? TUI_ALTO - 10 : 4)) @@ -51,7 +52,7 @@ main_menu() { while true; do local choice - choice=$(whiptail --title "DEBIANITO — simple configurator script" --menu "" \ + choice=$(_menu "DEBIANITO — simple configurator script" "" \ $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "1" "System Info" \ "2" "User Privileges & Feedback" \ @@ -60,11 +61,11 @@ main_menu() { "5" "Graphics Drivers & Mesa Stack" \ "6" "Backports Kernel" \ "7" "Gaming Setup" \ - "8" "ZRAM (Swap)" \ - "9" "Install Programs and Software" \ - "10" "Boot Rescue & Repair" \ - "11" "Exit" \ - 3>&1 1>&2 2>&3) + "8" "ZRAM" \ + "9" "Swap Management" \ + "10" "Install Programs and Software" \ + "11" "Boot Rescue & Repair" \ + "12" "Exit") clear @@ -104,15 +105,16 @@ kernels. Use the stable kernel provided by Bullseye." 10 60 fi ;; 8) install_zram || true ;; - 9) + 9) manage_swap || true ;; + 10) if [ "$DEBIAN_VERSION" = "11" ] && type install_extras_bullseye &>/dev/null; then install_extras_bullseye || true else install_extras || true fi ;; - 10) rescue_boot || true ;; - 11) echo "Exiting."; exit 0 ;; + 11) rescue_boot || true ;; + 12) echo "Exiting."; exit 0 ;; esac done } diff --git a/modules/bullseye/extras.sh b/modules/bullseye/extras.sh index 7825238..111c12c 100644 --- a/modules/bullseye/extras.sh +++ b/modules/bullseye/extras.sh @@ -60,13 +60,12 @@ Instalar?"; then _cat_customization_bullseye() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local sub - sub=$(whiptail --title "Customization (Bullseye)" --menu \ - "Select type:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + sub=$(_menu "Customization (Bullseye)" "Select type:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "1" "Desktop Themes (GTK/KDE)" \ "2" "Icon Themes" \ "3" "Cursor Themes" \ "4" "Fonts" \ - 3>&1 1>&2 2>&3) + ) [ -z "$sub" ] && return case $sub in 1) _cat_themes_bullseye ;; @@ -78,15 +77,14 @@ _cat_customization_bullseye() { _cat_themes_bullseye() { local choices - choices=$(whiptail --title "Desktop Themes (Bullseye)" --checklist \ - "Select desktop themes${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Desktop Themes (Bullseye)" "Select desktop themes${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "arc-theme" "Arc GTK theme$(_inst arc-theme)" "$(_state arc-theme)" \ "blackbird-gtk-theme" "Blackbird GTK theme$(_inst blackbird-gtk-theme)" "$(_state blackbird-gtk-theme)" \ "bluebird-gtk-theme" "Bluebird GTK theme$(_inst bluebird-gtk-theme)" "$(_state bluebird-gtk-theme)" \ "breeze-gtk-theme" "Breeze GTK theme (KDE port)$(_inst breeze-gtk-theme)" "$(_state breeze-gtk-theme)" \ "greybird-gtk-theme" "Greybird GTK theme$(_inst greybird-gtk-theme)" "$(_state greybird-gtk-theme)" \ "numix-gtk-theme" "Numix GTK theme$(_inst numix-gtk-theme)" "$(_state numix-gtk-theme)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -109,9 +107,8 @@ _cat_icons_bullseye() { "suru-icon-theme" "Suru icon theme$(_inst suru-icon-theme)" "$(_state suru-icon-theme)" ) local choices - choices=$(whiptail --title "Icon Themes (Bullseye)" --checklist \ - "Select icon themes${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ - "${items[@]}" 3>&1 1>&2 2>&3) + choices=$(_checklist "Icon Themes (Bullseye)" "Select icon themes${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + "${items[@]}" ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -123,14 +120,13 @@ _cat_icons_bullseye() { _cat_cursors_bullseye() { local choices - choices=$(whiptail --title "Cursor Themes (Bullseye)" --checklist \ - "Select cursor themes${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Cursor Themes (Bullseye)" "Select cursor themes${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "breeze-cursor-theme" "Breeze cursors (KDE)$(_inst breeze-cursor-theme)" "$(_state breeze-cursor-theme)" \ "chameleon-cursor-theme" "Chameleon cursors$(_inst chameleon-cursor-theme)" "$(_state chameleon-cursor-theme)" \ "dmz-cursor-theme" "DMZ cursors$(_inst dmz-cursor-theme)" "$(_state dmz-cursor-theme)" \ "oxygencursors" "Oxygen cursors (KDE legacy)$(_inst oxygencursors)" "$(_state oxygencursors)" \ "xcursor-themes" "X11 base cursors$(_inst xcursor-themes)" "$(_state xcursor-themes)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -142,13 +138,12 @@ _cat_cursors_bullseye() { _cat_fonts_bullseye() { local choices - choices=$(whiptail --title "Fonts (Bullseye)" --checklist \ - "Available fonts${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Fonts (Bullseye)" "Available fonts${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "fonts-firacode" "Fira Code monospace font$(_inst fonts-firacode)" "$(_state fonts-firacode)" \ "fonts-noto" "Noto fonts (Google)$(_inst fonts-noto)" "$(_state fonts-noto)" \ "fonts-dejavu-core" "DejaVu core fonts$(_inst fonts-dejavu-core)" "$(_state fonts-dejavu-core)" \ "ttf-mscorefonts-installer" "Microsoft Core Fonts$(_inst ttf-mscorefonts-installer)" "$(_state ttf-mscorefonts-installer)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -161,15 +156,13 @@ _cat_fonts_bullseye() { _cat_download_bullseye() { local choices1 choices2="" - choices1=$(whiptail --title "Downloaders" --checklist \ - "Select download tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices1=$(_checklist "Downloaders" "Select download tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "aria2" "Multiprotocol downloader (CLI)$(_inst aria2)" "$(_state aria2)" \ "filezilla" "FTP/SFTP client (GUI)$(_inst filezilla)" "$(_state filezilla)" \ - 3>&1 1>&2 2>&3) + ) clear - choices2=$(whiptail --title "Torrent Clients" --checklist \ - "Select torrent clients${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices2=$(_checklist "Torrent Clients" "Select torrent clients${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "deluge" "BitTorrent client (GTK)$(_inst deluge)" "$(_state deluge)" \ "deluged" "BitTorrent daemon/server$(_inst deluged)" "$(_state deluged)" \ "mktorrent" "Torrent metainfo creator (CLI)$(_inst mktorrent)" "$(_state mktorrent)" \ @@ -178,7 +171,7 @@ _cat_download_bullseye() { "transmission-cli" "BitTorrent client (CLI)$(_inst transmission-cli)" "$(_state transmission-cli)" \ "transmission-gtk" "BitTorrent client (GTK)$(_inst transmission-gtk)" "$(_state transmission-gtk)" \ "transmission-qt" "BitTorrent client (Qt)$(_inst transmission-qt)" "$(_state transmission-qt)" \ - 3>&1 1>&2 2>&3) + ) clear local cleaned @@ -197,8 +190,7 @@ _cat_download_bullseye() { _cat_internet_bullseye() { local choices - choices=$(whiptail --title "Internet (Bullseye)" --checklist \ - "Select browsers, email${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Internet (Bullseye)" "Select browsers, email${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "chromium" "Chromium web browser$(_inst chromium)" "$(_state chromium)" \ "dillo" "Lightweight graphical browser$(_inst dillo)" "$(_state dillo)" \ "elinks" "Text-mode web browser$(_inst elinks)" "$(_state elinks)" \ @@ -210,7 +202,7 @@ _cat_internet_bullseye() { "thunderbird" "Email client$(_inst thunderbird)" "$(_state thunderbird)" \ "torbrowser-launcher" "Tor Browser launcher$(_inst torbrowser-launcher)" "$(_state torbrowser-launcher)" \ "w3m" "Text-mode browser + deps$(_inst w3m)" "$(_state w3m)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -238,11 +230,10 @@ _cat_internet_bullseye() { _cat_players_bullseye() { local choices - choices=$(whiptail --title "Media Players (Bullseye)" --checklist \ - "Select media players${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Media Players (Bullseye)" "Select media players${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "mpv" "Lightweight media player$(_inst mpv)" "$(_state mpv)" \ "vlc" "VLC media player$(_inst vlc)" "$(_state vlc)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -258,8 +249,7 @@ _cat_players_bullseye() { _cat_design_bullseye() { local choices - choices=$(whiptail --title "Multimedia & Design (Bullseye)" --checklist \ - "Select multimedia and design tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Multimedia & Design (Bullseye)" "Select multimedia and design tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "ardour" "Digital audio workstation$(_inst ardour)" "$(_state ardour)" \ "audacity" "Audio editor/recorder$(_inst audacity)" "$(_state audacity)" \ "blender" "3D modeling/animation suite$(_inst blender)" "$(_state blender)" \ @@ -273,7 +263,7 @@ _cat_design_bullseye() { "openshot-qt" "Video editor (simple)$(_inst openshot-qt)" "$(_state openshot-qt)" \ "scribus" "Desktop publishing (DTP)$(_inst scribus)" "$(_state scribus)" \ "shotcut" "Video editor (cross-platform)$(_inst shotcut)" "$(_state shotcut)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -289,8 +279,7 @@ _cat_design_bullseye() { _cat_programming_bullseye() { local choices - choices=$(whiptail --title "Code Editors & IDEs (Bullseye)" --checklist \ - "Select editors and IDEs${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Code Editors & IDEs (Bullseye)" "Select editors and IDEs${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "vim" "Classic terminal editor$(_inst vim)" "$(_state vim)" \ "vim-gtk3" "Vim with GTK3 GUI$(_inst vim-gtk3)" "$(_state vim-gtk3)" \ "neovim" "Modern vim fork$(_inst neovim)" "$(_state neovim)" \ @@ -300,7 +289,7 @@ _cat_programming_bullseye() { "mousepad" "Xfce text editor$(_inst mousepad)" "$(_state mousepad)" \ "gedit" "GNOME text editor$(_inst gedit)" "$(_state gedit)" \ "geany" "Lightweight IDE$(_inst geany)" "$(_state geany)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -316,8 +305,7 @@ _cat_programming_bullseye() { _cat_dev_bullseye() { local choices - choices=$(whiptail --title "Servers & Dev Tools (Bullseye)" --checklist \ - "Select development tools and servers${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Servers & Dev Tools (Bullseye)" "Select development tools and servers${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "apache2" "Apache web server$(_inst apache2)" "$(_state apache2)" \ "build-essential" "C/C++ build tools (gcc, make)$(_inst build-essential)" "$(_state build-essential)" \ "docker" "Docker container runtime$(_inst docker.io)" "$(_state docker.io)" \ @@ -332,7 +320,7 @@ _cat_dev_bullseye() { "sqlite3" "SQLite database engine$(_inst sqlite3)" "$(_state sqlite3)" \ "jellyfin" "Jellyfin Media Server (Web GUI on port 8096)$(_inst jellyfin)" OFF \ "openjdk-dev-env" "Adoptium Temurin JDK (17, 21, 25 LTS)$(_any_jdk_installed_desc)" "$(_any_jdk_state)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -379,14 +367,13 @@ _cat_dev_bullseye() { } _cat_security_bullseye() { local choices - choices=$(whiptail --title "Security & Networking (Bullseye)" --checklist \ - "Select security and networking tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Security & Networking (Bullseye)" "Select security and networking tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "wireshark" "Network protocol analyzer (GUI)$(_inst wireshark)" "$(_state wireshark)" \ "tcpdump" "Command-line packet analyzer$(_inst tcpdump)" "$(_state tcpdump)" \ "fail2ban" "Brute-force protection daemon$(_inst fail2ban)" "$(_state fail2ban)" \ "ufw" "Uncomplicated firewall$(_inst ufw)" "$(_state ufw)" \ "clamav" "Antivirus engine (ClamAV)$(_inst clamav)" "$(_state clamav)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -409,8 +396,7 @@ _cat_security_bullseye() { _cat_general_bullseye() { local choices - choices=$(whiptail --title "System Tools (Bullseye)" --checklist \ - "Select system utilities${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "System Tools (Bullseye)" "Select system utilities${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "compress" "Compression tools (zip, unrar, p7zip)$(_inst zip)" "$(_state zip)" \ "conky" "System monitor for desktop$(_inst conky)" "$(_state conky)" \ "cpu-x" "CPU-X (alternative to CPU-Z)$(_inst cpu-x)" "$(_state cpu-x)" \ @@ -430,7 +416,7 @@ _cat_general_bullseye() { "timeshift" "System restore snapshots$(_inst timeshift)" "$(_state timeshift)" \ "tmux" "Terminal multiplexer$(_inst tmux)" "$(_state tmux)" \ "wine" "Windows compatibility layer$(_inst wine)" "$(_state wine)" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -519,9 +505,8 @@ _cat_fetch_bullseye() { ) local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "Fetch Tools (Bullseye)" --checklist \ - "Select system info tools:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ - "${items[@]}" 3>&1 1>&2 2>&3) + choices=$(_checklist "Fetch Tools (Bullseye)" "Select system info tools:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + "${items[@]}" ) clear [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') @@ -544,8 +529,7 @@ install_extras_bullseye() { while true; do local cat_choice - cat_choice=$(whiptail --title "Extra Software — Bullseye" --menu \ - "Select a category${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + cat_choice=$(_menu "Extra Software — Bullseye" "Select a category${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "0" "Essential Pack" \ "1" "Customization System" \ "2" "Download & Network" \ @@ -559,7 +543,7 @@ install_extras_bullseye() { "10" "System Tools" \ "11" "Fetch / System Info" \ "12" "Back to main menu" \ - 3>&1 1>&2 2>&3) + ) [ -z "$cat_choice" ] && return clear @@ -585,11 +569,10 @@ install_extras_bullseye() { _cat_software_centers_bullseye() { local sc_choice - sc_choice=$(whiptail --title "Software Centers" --menu \ - "Choose a software store to install:" 12 65 2 \ + sc_choice=$(_menu "Software Centers" "Choose a software store to install:" 12 65 2 \ "gnome-software" "Software Center for GNOME$(_inst gnome-software)" \ "plasma-discover" "Software manager for Plasma$(_inst plasma-discover)" \ - 3>&1 1>&2 2>&3) + ) [ -z "$sc_choice" ] && return _run_cmd "Install" "sudo apt install -y $sc_choice" "Installing ${sc_choice}..." diff --git a/modules/bullseye/legacy.sh b/modules/bullseye/legacy.sh index b3f70e1..2a96208 100644 --- a/modules/bullseye/legacy.sh +++ b/modules/bullseye/legacy.sh @@ -164,14 +164,13 @@ Installs matching 32-bit graphics drivers."; then # Gaming tools checklist (no Steam, no Heroic) local choices - choices=$(whiptail --title "Gaming Tools — Bullseye" --checklist \ + choices=$(_checklist "Gaming Tools — Bullseye" \ "Select gaming optimization tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "gamemode" "Game performance optimization" ON \ "mangohud" "Performance overlay (Vulkan/OpenGL)" ON \ "goverlay" "MangoHud config GUI" ON \ "lutris" "Game launcher/manager" OFF \ - "java" "Java Runtimes (8, 17, 21)" OFF \ - 3>&1 1>&2 2>&3) + "java" "Java Runtimes (8, 17, 21)" OFF) if [ -z "$choices" ]; then echo "No gaming tools selected." diff --git a/modules/extras.sh b/modules/extras.sh index 50f9b7b..e548938 100644 --- a/modules/extras.sh +++ b/modules/extras.sh @@ -27,7 +27,7 @@ install_extras() { while true; do local cat_choice - cat_choice=$(whiptail --title "Extra Software" --menu \ + cat_choice=$(_menu "Extra Software" \ "Select a category${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "0" "Essential Pack" \ "1" "Customization System" \ @@ -42,8 +42,7 @@ install_extras() { "10" "Office & Productivity" \ "11" "System Tools" \ "12" "Fetch / System Info" \ - "13" "Back to main menu" \ - 3>&1 1>&2 2>&3) + "13" "Back to main menu") [ -z "$cat_choice" ] && return clear diff --git a/modules/extras/design/design.sh b/modules/extras/design/design.sh index 7cf5dd6..27338bf 100644 --- a/modules/extras/design/design.sh +++ b/modules/extras/design/design.sh @@ -19,8 +19,7 @@ _cat_design() { local shotcut_state; shotcut_state=$(_state "shotcut") local choices - choices=$(whiptail --title "Multimedia & Design" --checklist \ - "Select multimedia and design tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Multimedia & Design" "Select multimedia and design tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "audacity" "Audio editor/recorder$(_inst audacity)" "$audacity_state" \ "ardour" "Digital audio workstation$(_inst ardour)" "$ardour_state" \ "blender" "3D modeling/animation suite$(_inst blender)" "$blender_state" \ @@ -34,7 +33,7 @@ _cat_design() { "openshot-qt" "Video editor (simple)$(_inst openshot-qt)" "$openshot_state" \ "scribus" "Desktop publishing (DTP)$(_inst scribus)" "$scribus_state" \ "shotcut" "Video editor (cross-platform)$(_inst shotcut)" "$shotcut_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/dev/dev.sh b/modules/extras/dev/dev.sh index 1023e31..b06c13b 100644 --- a/modules/extras/dev/dev.sh +++ b/modules/extras/dev/dev.sh @@ -22,8 +22,7 @@ _cat_dev() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "Development & Servers" --checklist \ - "Select development tools and servers${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices=$(_checklist "Development & Servers" "Select development tools and servers${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "apache2" "Apache web server$(_inst apache2)" "$apache_state" \ "build-essential" "C/C++ build tools (gcc, make)$(_inst build-essential)" "$build_state" \ "certbot" "Let's Encrypt TLS certificates$(_inst certbot)" "$certbot_state" \ @@ -39,7 +38,7 @@ _cat_dev() { "sqlite3" "SQLite database engine$(_inst sqlite3)" "$sqlite_state" \ "jellyfin" "Jellyfin Media Server (Web GUI on port 8096)$(_inst jellyfin)" OFF \ "openjdk-dev-env" "Adoptium Temurin JDK (17, 21, 25 LTS)${jdk_desc}" "${jdk_state}" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/download/download.sh b/modules/extras/download/download.sh index e7cb695..658c726 100644 --- a/modules/extras/download/download.sh +++ b/modules/extras/download/download.sh @@ -21,17 +21,15 @@ _cat_download() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices1 choices2="" - choices1=$(whiptail --title "Downloaders" --checklist \ - "Select download tools:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices1=$(_checklist "Downloaders" "Select download tools:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "aria2" "Multiprotocol downloader (CLI)$(_inst aria2)" "$aria2_state" \ "filezilla" "FTP/SFTP client (GUI)$(_inst filezilla)" "$filezilla_state" \ "yt-dlp" "Video downloader CLI$(_inst yt-dlp)" "$ytdlp_state" \ "youtubedl-gui" "GUI for yt-dlp$(_inst youtubedl-gui)" "$ytdlp_gui_state" \ - 3>&1 1>&2 2>&3) + ) clear - choices2=$(whiptail --title "Torrent Clients" --checklist \ - "Select torrent clients:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices2=$(_checklist "Torrent Clients" "Select torrent clients:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "deluge" "BitTorrent client (GTK)$(_inst deluge)" "$deluge_state" \ "deluged" "BitTorrent daemon/server$(_inst deluged)" "$deluged_state" \ "mktorrent" "Torrent metainfo creator (CLI)$(_inst mktorrent)" "$mktorrent_state" \ @@ -40,7 +38,7 @@ _cat_download() { "transmission-cli" "BitTorrent client (CLI)$(_inst transmission-cli)" "$tr_cli_state" \ "transmission-gtk" "BitTorrent client (GTK)$(_inst transmission-gtk)" "$tr_gtk_state" \ "transmission-qt" "BitTorrent client (Qt)$(_inst transmission-qt)" "$tr_qt_state" \ - 3>&1 1>&2 2>&3) + ) clear local cleaned diff --git a/modules/extras/fetch/fetch.sh b/modules/extras/fetch/fetch.sh index a0e5e86..d4e7f6c 100644 --- a/modules/extras/fetch/fetch.sh +++ b/modules/extras/fetch/fetch.sh @@ -37,10 +37,9 @@ _cat_fetch() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "Fetch Tools" --checklist \ - "Select system info tools:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices=$(_checklist "Fetch Tools" "Select system info tools:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "${items[@]}" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/internet/internet.sh b/modules/extras/internet/internet.sh index 4113c7e..d7225fc 100644 --- a/modules/extras/internet/internet.sh +++ b/modules/extras/internet/internet.sh @@ -144,8 +144,7 @@ _cat_internet() { local protonvpn_state; protonvpn_state=$(_state "protonvpn") local choices - choices=$(whiptail --title "Internet" --checklist \ - "Select browsers, email, and VPN tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Internet" "Select browsers, email, and VPN tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "chromium" "Chromium web browser$(_inst chromium)" "$chromium_state" \ "dillo" "Lightweight graphical browser$(_inst dillo)" "$dillo_state" \ "elinks" "Text-mode web browser$(_inst elinks)" "$elinks_state" \ @@ -167,7 +166,7 @@ _cat_internet() { "mullvad-vpn" "Mullvad VPN client (WireGuard)$(_inst mullvad-vpn)" "$mullvad_state" \ "mullvad-browser" "Mullvad privacy browser$(_inst mullvad-browser)" "$mullvadbrowser_state" \ "protonvpn" "ProtonVPN client$(_inst protonvpn)" "$protonvpn_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/java.sh b/modules/extras/java.sh index 0c2f2f4..90f0c7c 100644 --- a/modules/extras/java.sh +++ b/modules/extras/java.sh @@ -15,12 +15,11 @@ _enable_temurin_repo() { install_minecraft_java() { local choices - choices=$(whiptail --title "Java Runtimes for Minecraft" --checklist \ + choices=$(_checklist "Java Runtimes for Minecraft" \ "Select Java version(s) to install:" 14 65 3 \ "8" "Java 8 — Classic mods & Minecraft <= 1.16.5" OFF \ "17" "Java 17 — Minecraft 1.17 to 1.20.4" ON \ - "21" "Java 21 — Modern Minecraft >= 1.20.5 & 1.21+" OFF \ - 3>&1 1>&2 2>&3) + "21" "Java 21 — Modern Minecraft >= 1.20.5 & 1.21+" OFF) [ -z "$choices" ] && { echo "No Java version selected."; return; } _enable_temurin_repo local cleaned @@ -33,12 +32,11 @@ install_minecraft_java() { _install_dev_java() { local ver - ver=$(whiptail --title "Java Development Kits (JDK)" --menu \ + ver=$(_menu "Java Development Kits (JDK)" \ "Select JDK version:" 12 60 3 \ "17" "Java 17 LTS Development Kit" \ "21" "Java 21 LTS Development Kit" \ - "25" "Java 25 LTS Development Kit" \ - 3>&1 1>&2 2>&3) + "25" "Java 25 LTS Development Kit") [ -z "$ver" ] && { echo "No JDK version selected."; return; } _enable_temurin_repo _run_install "temurin-${ver}-jdk" diff --git a/modules/extras/office/office.sh b/modules/extras/office/office.sh index 7e5ecb3..71e90a2 100644 --- a/modules/extras/office/office.sh +++ b/modules/extras/office/office.sh @@ -61,11 +61,10 @@ install_libreoffice_bpo() { _cat_office() { local choices - choices=$(whiptail --title "Office & Productivity" --checklist \ - "Select office applications${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Office & Productivity" "Select office applications${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "onlyoffice" "OnlyOffice Desktop Editors (extrepo)" OFF \ "libreoffice" "LibreOffice (backports on Bookworm/Trixie)" OFF \ - 3>&1 1>&2 2>&3) + ) [ -z "$choices" ] && return local cleaned; cleaned=$(echo "$choices" | tr -d '"') diff --git a/modules/extras/players/players.sh b/modules/extras/players/players.sh index e091f94..634d0a9 100644 --- a/modules/extras/players/players.sh +++ b/modules/extras/players/players.sh @@ -9,11 +9,10 @@ _cat_players() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "Media Players" --checklist \ - "Select media players:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices=$(_checklist "Media Players" "Select media players:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "mpv" "Lightweight media player$(_inst mpv)" "$mpv_state" \ "vlc" "VLC media player$(_inst vlc)" "$vlc_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/programming/programming.sh b/modules/extras/programming/programming.sh index fa8619a..2632e59 100644 --- a/modules/extras/programming/programming.sh +++ b/modules/extras/programming/programming.sh @@ -22,8 +22,7 @@ _cat_programming() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "Programming Applications" --checklist \ - "Select editors and IDEs${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices=$(_checklist "Programming Applications" "Select editors and IDEs${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "vim" "Classic terminal editor$(_inst vim)" "$vim_state" \ "vim-gtk3" "Vim with GTK3 GUI$(_inst vim-gtk3)" "$vimgtk_state" \ "neovim" "Modern vim fork$(_inst neovim)" "$neovim_state" \ @@ -36,7 +35,7 @@ _cat_programming() { "geany" "Lightweight IDE$(_inst geany)" "$geany_state" \ "gnome-text-editor" "GNOME modern text editor$(_inst gnome-text-editor)" "$gte_state" \ "vscodium" "VS Code open-source (extrepo)$(_inst codium)" "$codium_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/security/security.sh b/modules/extras/security/security.sh index 927148b..a01fac4 100644 --- a/modules/extras/security/security.sh +++ b/modules/extras/security/security.sh @@ -13,15 +13,14 @@ _cat_security() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "Security & Networking" --checklist \ - "Select security and networking tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices=$(_checklist "Security & Networking" "Select security and networking tools${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "wireshark" "Network protocol analyzer (GUI)$(_inst wireshark)" "$wireshark_state" \ "tcpdump" "Command-line packet analyzer$(_inst tcpdump)" "$tcpdump_state" \ "zenmap" "Network scanner GUI (Nmap frontend)$(_inst zenmap)" "$zenmap_state" \ "fail2ban" "Brute-force protection daemon$(_inst fail2ban)" "$fail2ban_state" \ "ufw" "Uncomplicated firewall$(_inst ufw)" "$ufw_state" \ "clamav" "Antivirus engine (ClamAV)$(_inst clamav)" "$clamav_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/system/software_centers.sh b/modules/extras/system/software_centers.sh index 2f37d56..26f820c 100644 --- a/modules/extras/system/software_centers.sh +++ b/modules/extras/system/software_centers.sh @@ -4,11 +4,10 @@ _cat_software_centers() { local de_type de_type=$(_detect_desktop_type) local sc_choice - sc_choice=$(whiptail --title "Software Centers" --menu \ - "Choose a software store to install:" 12 65 2 \ + sc_choice=$(_menu "Software Centers" "Choose a software store to install:" 12 65 2 \ "gnome-software" "Software Center for GNOME$(_inst gnome-software)" \ "plasma-discover" "Software manager for Plasma$(_inst plasma-discover)" \ - 3>&1 1>&2 2>&3) + ) [ -z "$sc_choice" ] && return if { [ "$de_type" = "qt" ] && [ "$sc_choice" = "gnome-software" ]; } || \ diff --git a/modules/extras/system/system.sh b/modules/extras/system/system.sh index c278957..4466517 100644 --- a/modules/extras/system/system.sh +++ b/modules/extras/system/system.sh @@ -61,8 +61,7 @@ _cat_general() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local choices - choices=$(whiptail --title "System Tools" --checklist \ - "Select system utilities to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + choices=$(_checklist "System Tools" "Select system utilities to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "alacritty" "GPU-accelerated terminal$(_inst alacritty)" "$alacritty_state" \ "btop" "Resource monitor (fancy top)$(_inst btop)" "$btop_state" \ "compress" "Compression tools (zip, unrar, 7z)$(_inst zip)" "$compress_state" \ @@ -92,7 +91,7 @@ _cat_general() { "timeshift" "System restore snapshots$(_inst timeshift)" "$timeshift_state" \ "tmux" "Terminal multiplexer$(_inst tmux)" "$tmux_state" \ "wine" "Windows compatibility layer$(_inst wine)" "$wine_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/themes/cursors/cursors.sh b/modules/extras/themes/cursors/cursors.sh index ede36b7..5d67922 100644 --- a/modules/extras/themes/cursors/cursors.sh +++ b/modules/extras/themes/cursors/cursors.sh @@ -10,15 +10,14 @@ _cat_cursors() { local oxygen_state; oxygen_state=$(_state "oxygencursors") local choices - choices=$(whiptail --title "Cursor Themes" --checklist \ - "Select cursor themes to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Cursor Themes" "Select cursor themes to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "bibata-cursor-theme" "Bibata cursors$(_inst bibata-cursor-theme)" "$bibata_state" \ "breeze-cursor-theme" "Breeze cursors (KDE)$(_inst breeze-cursor-theme)" "$breeze_state" \ "chameleon-cursor-theme" "Chameleon cursors$(_inst chameleon-cursor-theme)" "$chameleon_state" \ "dmz-cursor-theme" "DMZ cursors$(_inst dmz-cursor-theme)" "$dmz_state" \ "xcursor-themes" "X11 base cursors$(_inst xcursor-themes)" "$xcursor_state" \ "oxygencursors" "Oxygen cursors (KDE legacy)$(_inst oxygencursors)" "$oxygen_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/themes/desktop-themes/desktop-themes.sh b/modules/extras/themes/desktop-themes/desktop-themes.sh index 5f44528..aaf8e14 100644 --- a/modules/extras/themes/desktop-themes/desktop-themes.sh +++ b/modules/extras/themes/desktop-themes/desktop-themes.sh @@ -13,8 +13,7 @@ _cat_themes() { local orchis_state; orchis_state=$(_state "orchis-gtk-theme") local choices - choices=$(whiptail --title "Desktop Themes (GTK/KDE)" --checklist \ - "Select desktop themes to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Desktop Themes (GTK/KDE)" "Select desktop themes to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "arc-theme" "Arc GTK theme$(_inst arc-theme)" "$arc_state" \ "blackbird-gtk-theme" "Blackbird GTK theme$(_inst blackbird-gtk-theme)" "$blackbird_state" \ "bluebird-gtk-theme" "Bluebird GTK theme$(_inst bluebird-gtk-theme)" "$bluebird_state" \ @@ -22,7 +21,7 @@ _cat_themes() { "greybird-gtk-theme" "Greybird GTK theme$(_inst greybird-gtk-theme)" "$greybird_state" \ "numix-gtk-theme" "Numix GTK theme$(_inst numix-gtk-theme)" "$numix_gtk_state" \ "orchis-gtk-theme" "Orchis GTK theme$(_inst orchis-gtk-theme)" "$orchis_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/themes/fonts/fonts.sh b/modules/extras/themes/fonts/fonts.sh index 2043533..0a48b12 100644 --- a/modules/extras/themes/fonts/fonts.sh +++ b/modules/extras/themes/fonts/fonts.sh @@ -12,8 +12,7 @@ _cat_fonts() { local recommended_state; recommended_state=$(_state "fonts-recommended") local choices - choices=$(whiptail --title "Fonts" --checklist \ - "Select fonts to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Fonts" "Select fonts to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "fonts-bebas-neue" "Bebas Neue (display)$(_inst fonts-bebas-neue)" "$bebas_state" \ "fonts-anonymous-pro" "Anonymous Pro (monospace)$(_inst fonts-anonymous-pro)" "$anon_state" \ "fonts-adf-verana" "ADF Verana (sans-serif)$(_inst fonts-adf-verana)" "$verana_state" \ @@ -22,7 +21,7 @@ _cat_fonts() { "ttf-mscorefonts-installer" "Microsoft fonts (EULA required)$(_inst ttf-mscorefonts-installer)" "$mscore_state" \ "fonts-ubuntu" "Ubuntu font family$(_inst fonts-ubuntu)" "$ubuntu_state" \ "fonts-recommended" "Debian recommended fonts$(_inst fonts-recommended)" "$recommended_state" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/themes/icons/icons.sh b/modules/extras/themes/icons/icons.sh index e8d345b..3a0594e 100644 --- a/modules/extras/themes/icons/icons.sh +++ b/modules/extras/themes/icons/icons.sh @@ -41,10 +41,9 @@ _cat_icons() { fi local choices - choices=$(whiptail --title "Icon Themes" --checklist \ - "Select icon themes to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ + choices=$(_checklist "Icon Themes" "Select icon themes to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "${items[@]}" \ - 3>&1 1>&2 2>&3) + ) clear [ -z "$choices" ] && return diff --git a/modules/extras/themes/themes.sh b/modules/extras/themes/themes.sh index 90a2d07..76760b5 100644 --- a/modules/extras/themes/themes.sh +++ b/modules/extras/themes/themes.sh @@ -4,13 +4,12 @@ _cat_customization() { local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6)) local sub - sub=$(whiptail --title "Customization System" --menu \ - "Select type:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ + sub=$(_menu "Customization System" "Select type:" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \ "1" "Desktop Themes (GTK/KDE)" \ "2" "Icon Themes" \ "3" "Cursor Themes" \ "4" "Fonts" \ - 3>&1 1>&2 2>&3) + ) [ -z "$sub" ] && return case $sub in 1) _cat_themes ;; diff --git a/modules/gaming.sh b/modules/gaming.sh index 3cbc385..7ec0dde 100644 --- a/modules/gaming.sh +++ b/modules/gaming.sh @@ -49,105 +49,20 @@ ensure_contrib_repo() { install_gaming() { echo -e "${YELLOW}Gaming setup...${NC}" - # 1. 32-bit support prompt FIRST - local enable_32bit=false - if _confirm "32-bit Support" "Enable i386 architecture for 32-bit games?\n\nRequired by Steam/Proton for 32-bit games.\nInstalls matching 32-bit graphics drivers."; then - enable_32bit=true - fi - - if $enable_32bit; then - echo "Enabling 32-bit architecture (i386)..." - if ! dpkg --print-foreign-architectures | grep -q i386; then - sudo dpkg --add-architecture i386 - fi - _run_cmd "APT Update" "sudo apt update" "Updating package lists..." - - echo "Installing 32-bit graphics drivers..." - if [ "$GPU_TYPE" = "nvidia" ]; then - case "${NVIDIA_DRIVER_MODE:-stable}" in - cuda-repo) - local nv32_pkg="nvidia-driver-libs:i386" - local nv32_ver - nv32_ver=$(dpkg -l "$nv32_pkg" 2>/dev/null | awk '/^ii/ {print $3}') - if [ -z "$nv32_ver" ] || ! echo "$nv32_ver" | grep -q "^590"; then - local msg="Source: NVIDIA CUDA Repository (Pinned v590)\n" - msg+="NVIDIA 32-bit Libraries (v590 branch)\n\n" - msg+="[+] nvidia-driver-libs:i386" - if _confirm "NVIDIA 32-bit" "$msg" 12 70; then - _run_cmd "32-bit NVIDIA" \ - "sudo apt install -y ${nv32_pkg}" \ - "Installing 32-bit NVIDIA libraries from CUDA repo..." - fi - else - _msg "NVIDIA 32-bit" \ - "32-bit NVIDIA CUDA libraries already deployed.\n\nv590 ${nv32_ver}" 10 70 - fi - ;; - backports) - local nv32_pkg="nvidia-driver-libs:i386" - local nv32_ver - nv32_ver=$(apt-cache policy "$nv32_pkg" 2>/dev/null | awk 'NR==3 {print $2; exit}') - local msg="Source: Debian ${DEBIAN_CODENAME^}-Backports\n" - msg+="NVIDIA 32-bit Libraries ${nv32_ver:-unknown}\n\n" - msg+="[+] nvidia-driver-libs:i386" - if _confirm "NVIDIA 32-bit" "$msg" 12 70; then - _run_cmd "32-bit NVIDIA" "sudo apt install -y -t ${DEBIAN_CODENAME}-backports ${nv32_pkg}" \ - "Installing 32-bit NVIDIA drivers from backports..." - fi - ;; - stable) - local nv32_pkg="nvidia-driver-libs:i386" - local nv32_ver - nv32_ver=$(apt-cache policy "$nv32_pkg" 2>/dev/null | awk 'NR==3 {print $2; exit}') - local use_bpo32=false - if [ "$(is_backports_enabled)" == "true" ]; then - local bpo_nv32_ver - bpo_nv32_ver=$(apt-cache madison "$nv32_pkg" 2>/dev/null | \ - grep "${DEBIAN_CODENAME}-backports" | awk '{print $3}' | head -1) - if [ -n "$bpo_nv32_ver" ]; then - local msg="Source: Debian ${DEBIAN_CODENAME^} (Backports available)\n" - msg+="NVIDIA 32-bit Libraries: ${nv32_pkg}\n\n" - msg+=" Backports: ${bpo_nv32_ver}\n" - msg+=" Stable: ${nv32_ver:-unknown}\n\n" - msg+="Choose version:" - if _confirm_custom "NVIDIA 32-bit" "$msg" "Backports" "Stable" 14 70; then - use_bpo32=true - fi - fi - fi - if $use_bpo32; then - _run_cmd "32-bit NVIDIA" "sudo apt install -y -t ${DEBIAN_CODENAME}-backports ${nv32_pkg}" \ - "Installing 32-bit NVIDIA drivers from backports..." - else - local msg="Source: Debian ${DEBIAN_CODENAME^} Stable\n" - msg+="NVIDIA 32-bit Libraries ${nv32_ver:-unknown}\n\n" - msg+="[+] nvidia-driver-libs:i386" - if _confirm "NVIDIA 32-bit" "$msg" 12 70; then - _run_cmd "32-bit NVIDIA" "sudo apt install -y ${nv32_pkg}" \ - "Installing 32-bit NVIDIA drivers..." - fi - fi - ;; - esac - else - _install_mesa_32bit - fi - fi - - # 2. Gaming packages checklist + # 1. Single checklist with ALL options (including i386 toggle) local choices - choices=$(whiptail --title "Gaming Setup" --checklist \ + choices=$(_checklist "Gaming Setup" \ "Select gaming packages to install${SCROLL_HINT}:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "steam" "Steam (requires 32-bit support)" ON \ "gamemode" "Game performance optimization" ON \ "mangohud" "Performance overlay (Vulkan/OpenGL)" ON \ - "heroic" "Heroic Launcher (Epic/GOG)" OFF \ - "java" "Java Runtimes (8, 17, 21)" OFF \ "goverlay" "MangoHud config GUI" ON \ + "heroic" "Heroic Launcher (Epic/GOG)" OFF \ + "java" "Minecraft Java Runtime" OFF \ "openrgb" "OpenRGB (RGB lighting control)$(_inst openrgb)" OFF \ - "lutris" "Game launcher/manager" OFF \ + "lutris" "Lutris + Wine (requires 32-bit support)" OFF \ "retroarch" "RetroArch Emulator Frontend$(_inst retroarch)" OFF \ - 3>&1 1>&2 2>&3) + "i386" "Enable 32-bit (i386) architecture" ON) if [ -z "$choices" ]; then echo "No gaming packages selected." @@ -158,14 +73,37 @@ install_gaming() { local cleaned cleaned=$(echo "$choices" | tr -d '"') - # 3. Warn if Steam selected without 32-bit - if echo "$cleaned" | grep -qw "steam" && ! $enable_32bit; then - echo -e "${YELLOW}Warning: Steam requires 32-bit support.${NC}" - echo "Installation may fail. Re-run this option and enable 32-bit support." + # 2. Determine if 32-bit is needed (steam, lutris, or explicit i386 toggle) + local need_32bit=false + for p in $cleaned; do + case $p in steam|lutris) need_32bit=true ;; esac + done + echo "$cleaned" | grep -qw i386 && need_32bit=true + + # Strip pseudo-entry "i386" from the install list + local install_list + install_list=$(echo "$cleaned" | tr ' ' '\n' | grep -v '^i386$' | tr '\n' ' ') + install_list=${install_list% } + + # 3. Enable i386 architecture if needed + if $need_32bit && ! dpkg --print-foreign-architectures 2>/dev/null | grep -q i386; then + echo -e "${YELLOW}Enabling i386 architecture (required by selection)...${NC}" + sudo dpkg --add-architecture i386 + _run_cmd "APT Update" "sudo apt update" "Updating package lists..." fi - # 4. Install selected packages - for pkg in $cleaned; do + # 4. Install 32-bit graphics drivers only if 32-bit is needed + if $need_32bit; then + echo "Installing 32-bit graphics drivers..." + if [ "$GPU_TYPE" = "nvidia" ]; then + _install_nvidia_32bit + else + _install_mesa_32bit + fi + fi + + # 5. Install selected packages + for pkg in $install_list; do case $pkg in steam) if ensure_contrib_repo; then diff --git a/modules/gaming/_helpers.sh b/modules/gaming/_helpers.sh index 68bb226..98d226c 100644 --- a/modules/gaming/_helpers.sh +++ b/modules/gaming/_helpers.sh @@ -2,66 +2,79 @@ # Shared helpers for gaming submodules _install_mesa_32bit() { - local mesa_pkgs=( - "mesa-vulkan-drivers" "mesa-vulkan-drivers:i386" - "libgl1-mesa-dri" "libgl1-mesa-dri:i386" - "libglx-mesa0" "libglx-mesa0:i386" - "libegl-mesa0" "libegl-mesa0:i386" - "mesa-va-drivers" "mesa-va-drivers:i386" + local base_pkgs=( + "mesa-vulkan-drivers" + "libgl1-mesa-dri" + "libglx-mesa0" + "libegl-mesa0" + "mesa-va-drivers" + "mesa-libgallium" ) - local ref_ver - ref_ver=$(apt-cache policy mesa-vulkan-drivers:i386 2>/dev/null | awk 'NR==3 {print $2; exit}') - local ref_bpo_ver - ref_bpo_ver=$(apt-cache madison mesa-vulkan-drivers:i386 2>/dev/null | \ - grep "${DEBIAN_CODENAME}-backports" | awk '{print $3}' | head -1) - local comp_line="Components: Vulkan:i386, OpenGL:i386, GLX:i386, EGL:i386, VA-API:i386" + local i386_active=false + dpkg --print-foreign-architectures 2>/dev/null | grep -q i386 && i386_active=true - if [ "$(is_backports_enabled)" == "true" ] && [ -n "$ref_bpo_ver" ]; then - local bpo_pkgs=() - local stable_pkgs=() + local install_list=() - for mpkg in "${mesa_pkgs[@]}"; do - local bpo_ver - bpo_ver=$(apt-cache madison "$mpkg" 2>/dev/null | \ - grep "${DEBIAN_CODENAME}-backports" | awk '{print $3}' | head -1) - if [ -n "$bpo_ver" ]; then - bpo_pkgs+=("$mpkg") - else - stable_pkgs+=("$mpkg") - fi - done - - local src_label="Debian ${DEBIAN_CODENAME^}-Backports" - [ ${#stable_pkgs[@]} -gt 0 ] && src_label+=" + Stable" - - local msg="Mesa 32-bit drivers required for gaming.\n\n" - msg+="Source: ${src_label}\n" - msg+="Mesa ${ref_bpo_ver:-$ref_ver}\n" - msg+="${comp_line}\n\n" - [ ${#stable_pkgs[@]} -gt 0 ] && msg+="Some packages only available in stable.\n" - msg+="Choose version:" - - if _confirm_custom "Mesa 32-bit" "$msg" "Backports" "Stable" 14 70; then - _run_cmd "Mesa 32-bit" "sudo apt install -y -t ${DEBIAN_CODENAME}-backports ${bpo_pkgs[*]}" \ - "Installing 32-bit Mesa from backports..." - if [ ${#stable_pkgs[@]} -gt 0 ]; then - _run_cmd "Mesa 32-bit" "sudo apt install -y ${stable_pkgs[*]}" \ - "Installing remaining 32-bit Mesa from stable..." - fi - else - _run_cmd "Mesa 32-bit" "sudo apt install -y ${mesa_pkgs[*]}" \ - "Installing 32-bit Mesa from stable..." + for p in "${base_pkgs[@]}"; do + if apt-cache show "$p" >/dev/null 2>&1; then + install_list+=("$p") fi - else - local msg="Mesa 32-bit drivers required for gaming.\n\n" - msg+="Source: Debian Stable\n" - msg+="Mesa ${ref_ver}\n" - msg+="${comp_line}\n\n" - msg+="Install Mesa 32-bit drivers?" - if _confirm "Mesa 32-bit" "$msg" 14 70; then - _run_cmd "Mesa 32-bit" "sudo apt install -y ${mesa_pkgs[*]}" \ - "Installing 32-bit Mesa..." + if $i386_active && apt-cache show "${p}:i386" >/dev/null 2>&1; then + install_list+=("${p}:i386") fi + done + + if [ ${#install_list[@]} -eq 0 ]; then + echo "No Mesa 32-bit packages available for installation." + return + fi + + _run_cmd "Mesa 32-bit" "sudo apt install -y ${install_list[*]}" \ + "Installing Mesa drivers (${#install_list[@]} packages)..." +} + +apt_cache_exists() { + apt-cache show "$1" >/dev/null 2>&1 +} + +_detect_installed_nvidia_driver() { + dpkg -l 2>/dev/null | awk ' + /^ii/ && ($2=="nvidia-driver" || $2=="nvidia-open" || + $2 ~ /^nvidia-legacy-[0-9]+xx-driver$/ || + $2 ~ /^nvidia-tesla-[0-9]+-driver$/) {print $2; exit}' +} + +_nvidia_libs_pkg() { + case "$1" in + nvidia-driver|nvidia-open) echo "nvidia-driver-libs" ;; + *) echo "${1}-libs" ;; + esac +} + +_install_nvidia_32bit() { + local drv_pkg + drv_pkg=$(_detect_installed_nvidia_driver) + if [ -z "$drv_pkg" ]; then + _msg "NVIDIA 32-bit" \ + "No NVIDIA driver detected.\n\nRun Graphics Drivers (option 5) first,\nthen return to add 32-bit libraries." 10 60 + return 0 + fi + + local drv_ver + drv_ver=$(dpkg -s "$drv_pkg" 2>/dev/null | sed -n 's/^Version: //p') + local libs_pkg + libs_pkg=$(_nvidia_libs_pkg "$drv_pkg") + + if ! apt_cache_exists "${libs_pkg}:i386"; then + _msg "NVIDIA 32-bit" \ + "No ${libs_pkg}:i386 available for your driver (${drv_pkg}).\nSkipping 32-bit NVIDIA libraries." 10 60 + return 0 + fi + + if _confirm "NVIDIA 32-bit" \ + "Driver: ${drv_pkg} ${drv_ver}\n\nInstall ${libs_pkg}:i386 (same version to prevent ABI mismatch)." 12 70; then + _run_cmd "NVIDIA 32-bit" "sudo apt install -y ${libs_pkg}:i386=${drv_ver}" \ + "Installing 32-bit NVIDIA libraries (${drv_ver})..." fi } diff --git a/modules/gaming/heroic.sh b/modules/gaming/heroic.sh index f0959c9..d503950 100644 --- a/modules/gaming/heroic.sh +++ b/modules/gaming/heroic.sh @@ -3,17 +3,37 @@ install_heroic() { local heroic_deb="/tmp/heroic.deb" - _run_cmd "Heroic" "sudo apt install -y curl wget" "Installing dependencies..." - local gh_url - gh_url=$(curl -s --connect-timeout 10 https://api.github.com/repos/Heroic-Games-Launcher/\ -HeroicGamesLauncher/releases/latest | \ - grep -oP 'https://[^"]+amd64\.deb' | head -1) - if [ -z "$gh_url" ]; then - echo -e "${RED}Could not determine latest Heroic release.${NC}" - else - _run_cmd "Heroic" "wget -O $heroic_deb $gh_url" "Downloading Heroic..." - _run_cmd "Heroic" "sudo apt install -y $heroic_deb" "Installing Heroic..." - rm -f "$heroic_deb" - echo -e "${GREEN}Heroic Games Launcher installed.${NC}" + local ua="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + + _run_cmd "Heroic" "sudo apt install -y curl jq" "Installing dependencies..." + + local json + json=$(curl -s --connect-timeout 10 -H "User-Agent: $ua" \ + "https://api.github.com/repos/Heroic-Games-Launcher/HeroicGamesLauncher/releases/latest") || { + _msg "Heroic Error" "Could not fetch release data from GitHub API." 8 60 + return 1 + } + + local deb_url + deb_url=$(echo "$json" | jq -r ' + .assets[] | select(.name | endswith("amd64.deb")) | .browser_download_url + ' 2>/dev/null || true) + + if [ -z "$deb_url" ]; then + _msg "Heroic Error" "Could not find amd64.deb asset in latest release." 10 60 + return 1 fi + + _run_cmd "Heroic" "curl -sL -H 'User-Agent: $ua' -o '$heroic_deb' '$deb_url'" "Downloading Heroic..." + + if ! dpkg-deb --info "$heroic_deb" >/dev/null 2>&1; then + _msg "Heroic Error" "Downloaded .deb is corrupted or truncated.\n\nRemoving file." 10 60 + rm -f "$heroic_deb" + return 1 + fi + + echo -e "${GREEN}Package integrity verified.${NC}" + _run_cmd "Heroic" "sudo apt install -y '$heroic_deb'" "Installing Heroic..." + rm -f "$heroic_deb" + echo -e "${GREEN}Heroic Games Launcher installed.${NC}" } diff --git a/modules/gaming/tools.sh b/modules/gaming/tools.sh index c66c28d..b8ddebb 100644 --- a/modules/gaming/tools.sh +++ b/modules/gaming/tools.sh @@ -26,34 +26,63 @@ install_lutris() { } install_openrgb() { - local url - if [ "$DEBIAN_VERSION" = "12" ]; then - url="https://codeberg.org/OpenRGB/OpenRGB/releases/download/release_candidate_1.0rc2/openrgb_1.0rc2_amd64_bookworm_0fca93e.deb" - elif [ "$DEBIAN_VERSION" = "13" ]; then - url="https://codeberg.org/OpenRGB/OpenRGB/releases/download/release_candidate_1.0rc2/openrgb_1.0rc2_amd64_trixie_0fca93e.deb" - else - echo "OpenRGB requires Debian 12 (Bookworm) or 13 (Trixie)." - return 1 - fi + local deb_suffix + case "$DEBIAN_CODENAME" in + bookworm) deb_suffix="bookworm" ;; + trixie) deb_suffix="trixie" ;; + *) + echo "OpenRGB requires Debian 12 (Bookworm) or 13 (Trixie)." + return 1 + ;; + esac local deb_path="/tmp/openrgb.deb" local ua="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" - _run_cmd "OpenRGB" "curl -L -o ${deb_path} -A '${ua}' '${url}'" "Downloading OpenRGB..." + _run_cmd "OpenRGB" "sudo apt install -y curl jq" "Installing dependencies..." - if [ ! -s "${deb_path}" ]; then - echo -e "${RED}[-]${NC} Download failed: empty or missing file." - rm -f "${deb_path}" + local json + json=$(curl -s --connect-timeout 10 \ + "https://codeberg.org/api/v1/repos/OpenRGB/OpenRGB/releases?limit=1") || { + echo -e "${RED}Could not fetch OpenRGB releases from Codeberg API.${NC}" + return 1 + } + + local deb_url sha256 + while IFS=' ' read -r url hash; do + deb_url="$url" + sha256="$hash" + done < <(echo "$json" | jq -r ' + .[0].assets[] | select(.name | contains("amd64_'"${deb_suffix}"'.deb")) | + "\(.browser_download_url) \(.sha256 // "")" + ' 2>/dev/null) + + if [ -z "$deb_url" ]; then + echo -e "${RED}Could not find OpenRGB .deb for ${DEBIAN_CODENAME^}.${NC}" return 1 fi - echo -e "${GREEN}[+]${NC} Installing OpenRGB package..." - if ! sudo apt install -y "${deb_path}"; then - rm -f "${deb_path}" - echo -e "${RED}[-]${NC} Package installation failed." - return 1 + _run_cmd "OpenRGB" "curl -L -o '${deb_path}' -A '${ua}' '${deb_url}'" "Downloading OpenRGB..." + + if [ -n "$sha256" ]; then + if ! echo "$sha256 $deb_path" | sha256sum -c --strict; then + echo -e "${RED}SHA256 mismatch! Downloaded file may be corrupted. Removing.${NC}" + rm -f "$deb_path" + return 1 + fi + echo -e "${GREEN}SHA256 verified.${NC}" + else + if ! dpkg-deb --info "$deb_path" >/dev/null 2>&1; then + echo -e "${RED}Downloaded .deb is corrupted. Removing.${NC}" + rm -f "$deb_path" + return 1 + fi + echo -e "${YELLOW}No SHA256 in API, validated via dpkg-deb.${NC}" fi + sudo apt install -y "$deb_path" + rm -f "$deb_path" + sudo modprobe i2c-dev if ! grep -q "^i2c-dev" /etc/modules 2>/dev/null; then echo "i2c-dev" | sudo tee -a /etc/modules >/dev/null @@ -62,8 +91,7 @@ install_openrgb() { sudo udevadm control --reload-rules && sudo udevadm trigger sudo setcap cap_sys_rawio=ep /usr/bin/openrgb 2>/dev/null || true - rm -f "${deb_path}" - echo -e "${GREEN}OpenRGB installed. NOTE: You must reboot or log out/in for the 'i2c' group to take effect.${NC}" + echo -e "${GREEN}OpenRGB installed. Reboot or log out/in for i2c group to take effect.${NC}" _pause } diff --git a/modules/repos.sh b/modules/repos.sh index 746b83b..ea86c95 100644 --- a/modules/repos.sh +++ b/modules/repos.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +source "${MODULES_DIR}/repos/migrate.sh" 2>/dev/null || true + # State for backup/restore REPO_BACKUP_DIR="" @@ -84,18 +86,19 @@ _clean_embedded_backports_deb822() { _write_deb822() { local codename="$1" action="$2" bp_enabled="$3" bp_location="$4" + local components="${5:-main contrib non-free non-free-firmware}" local main_file="/etc/apt/sources.list.d/debian.sources" local main_content="" main_content+="Types: deb\n" main_content+="URIs: https://deb.debian.org/debian\n" main_content+="Suites: ${codename} ${codename}-updates\n" - main_content+="Components: main contrib non-free non-free-firmware\n" + main_content+="Components: ${components}\n" main_content+="\n" main_content+="Types: deb\n" main_content+="URIs: https://security.debian.org/debian-security\n" main_content+="Suites: ${codename}-security\n" - main_content+="Components: main contrib non-free non-free-firmware\n" + main_content+="Components: ${components}\n" if content_differs "$main_file" "$main_content"; then if _confirm "Deb822 Sources" "Write main deb822 configuration to ${main_file}?"; then @@ -174,20 +177,21 @@ _remove_deb822_backports() { _write_classic() { local codename="$1" action="$2" bp_enabled="$3" bp_location="$4" + local components="${5:-main contrib non-free non-free-firmware}" local main_file="/etc/apt/sources.list" local main_content="" main_content+="# Official repository\n" - main_content+="deb https://deb.debian.org/debian ${codename} main contrib non-free non-free-firmware\n" - main_content+="# deb-src https://deb.debian.org/debian ${codename} main contrib non-free non-free-firmware\n" + main_content+="deb https://deb.debian.org/debian ${codename} ${components}\n" + main_content+="# deb-src https://deb.debian.org/debian ${codename} ${components}\n" main_content+="\n" main_content+="# Updates\n" - main_content+="deb https://deb.debian.org/debian ${codename}-updates main contrib non-free non-free-firmware\n" - main_content+="# deb-src https://deb.debian.org/debian ${codename}-updates main contrib non-free non-free-firmware\n" + main_content+="deb https://deb.debian.org/debian ${codename}-updates ${components}\n" + main_content+="# deb-src https://deb.debian.org/debian ${codename}-updates ${components}\n" main_content+="\n" main_content+="# Security\n" - main_content+="deb https://security.debian.org/debian-security ${codename}-security main contrib non-free non-free-firmware\n" - main_content+="# deb-src https://security.debian.org/debian-security ${codename}-security main contrib non-free non-free-firmware\n" + main_content+="deb https://security.debian.org/debian-security ${codename}-security ${components}\n" + main_content+="# deb-src https://security.debian.org/debian-security ${codename}-security ${components}\n" if content_differs "$main_file" "$main_content"; then if _confirm "Classic Sources" "Write main classic configuration to ${main_file}?"; then @@ -273,144 +277,219 @@ configure_repos() { return 1 fi - # ── Informational banner ── - _msg "Repositories" \ -"This section will automatically enable the 'contrib' and \n\ -'non-free' branches in your official Debian repositories. \n\ -(The 'non-free-firmware' branch is already enabled by default in Debian 12 and 13.)\n\n\ -This is CRUCIAL for obtaining proprietary software packages and\n\ -essential hardware drivers, including graphics drivers,\n\ -Wi-Fi firmware, and CPU microcode." 14 70 + # ── Repositories submenu ── + while true; do + local repo_choice - # Detect current state - local current_format + if [ "$DEBIAN_CODENAME" = "sid" ]; then + repo_choice=$(_menu "Repositories" \ + "Select an option:" $TUI_ALTO $TUI_ANCHO 6 \ + "1" "Enable Contrib & Non-Free Components" \ + "2" "Migrate traditional sources.list to DEB822 format" \ + "3" "Back to main menu") + else + repo_choice=$(_menu "Repositories" \ + "Select an option:" $TUI_ALTO $TUI_ANCHO 6 \ + "1" "Enable Contrib & Non-Free Components" \ + "2" "Migrate traditional sources.list to DEB822 format" \ + "3" "Setup/Update Backports repositories" \ + "4" "[ADVANCED] Upgrade system branch (Testing / SID)" \ + "5" "Back to main menu") + fi + + [ -z "$repo_choice" ] && break + clear + + case "$repo_choice" in + 1) _repos_enable_components ;; + 2) _repos_migrate_format ;; + 3) + if [ "$DEBIAN_CODENAME" = "sid" ]; then + break + else + _repos_setup_backports + fi + ;; + 4) _branch_migration || true ;; + 5) break ;; + esac + done +} + +# --------------------------------------------------------------------------- +# Submenu helpers +# --------------------------------------------------------------------------- + +_components_enabled() { + if [ -f /etc/apt/sources.list.d/debian.sources ]; then + grep -qE "^Components:.*\b(contrib|non-free)\b" /etc/apt/sources.list.d/debian.sources 2>/dev/null && return 0 + fi + if [ -f /etc/apt/sources.list ]; then + grep -qE "^[^#]*\b(contrib|non-free)\b" /etc/apt/sources.list 2>/dev/null && return 0 + fi + return 1 +} + +_repos_offer_upgrade() { + local upgradable + upgradable=$(apt list --upgradable 2>/dev/null | grep -c /) + if [ "$upgradable" -gt 0 ]; then + if _confirm "Upgrade System" "$upgradable packages can be upgraded. Upgrade now?"; then + sudo apt-mark hold tzdata 2>/dev/null || true + _run_cmd "Upgrade" "sudo apt upgrade -y" "Upgrading system..." + sudo apt-mark unhold tzdata 2>/dev/null || true + sudo apt autoremove -y + sudo apt autoclean + echo -e "${GREEN}System upgraded.${NC}" + else + echo "Skipping upgrade." + fi + fi +} + +_repos_enable_components() { + local current_format bp_enabled bp_location components current_format=$(detect_repo_format) - local bp_status + + if _components_enabled; then + if ! _confirm "Disable Components" \ + "Contrib and non-free are already enabled. Disable them?"; then + echo "No changes made." + _pause + return + fi + components="main" + else + if ! _confirm "Enable Components" \ + "Enable contrib and non-free components?\n\n\ +Needed for proprietary drivers, firmware, and other popular\n\ +software (like gaming platforms and proprietary tools)." 12 60; then + echo "No changes made." + _pause + return + fi + components="main contrib non-free non-free-firmware" + fi + + bp_enabled=false + bp_location="none" + if detect_backports_status "$DEBIAN_CODENAME"; then + bp_enabled=true + bp_location=$(detect_backports_location "$DEBIAN_CODENAME") + fi + + backup_current_repos + + if [ "$current_format" = "deb822" ] || [ "$current_format" = "none" ]; then + _write_deb822 "$DEBIAN_CODENAME" "write" "$bp_enabled" "$bp_location" "$components" + else + _write_classic "$DEBIAN_CODENAME" "write" "$bp_enabled" "$bp_location" "$components" + fi + + echo "Updating package lists..." + if sudo apt update; then + REPOS_CONFIGURED=true + cleanup_repo_backup + echo -e "${GREEN}Repository components configured.${NC}" + _repos_offer_upgrade + else + restore_previous_repos + echo -e "${RED}apt update failed. Previous configuration restored.${NC}" + fi + _pause +} + +_repos_migrate_format() { + local current_format bp_enabled bp_location + current_format=$(detect_repo_format) + + if [ "$current_format" != "classic" ]; then + echo "Repositories are already in DEB822 format." + _pause + return + fi + + if [ "$DEBIAN_CODENAME" != "trixie" ]; then + echo "Format migration is only relevant for Debian 13 (Trixie)." + _pause + return + fi + + # Preserve existing backports state across format migration + bp_enabled=false + bp_location="none" + if detect_backports_status "$DEBIAN_CODENAME"; then + bp_enabled=true + bp_location=$(detect_backports_location "$DEBIAN_CODENAME") + fi + + backup_current_repos + _write_deb822 "$DEBIAN_CODENAME" "migrate" "$bp_enabled" "$bp_location" + + echo "Updating package lists..." + if sudo apt update; then + REPOS_CONFIGURED=true + cleanup_repo_backup + echo -e "${GREEN}Repository format migrated to DEB822.${NC}" + else + restore_previous_repos + echo -e "${RED}apt update failed. Backup restored.${NC}" + fi + _pause +} + +_repos_setup_backports() { + local current_format bp_status bp_location + current_format=$(detect_repo_format) + if detect_backports_status "$DEBIAN_CODENAME"; then bp_status="enabled" else bp_status="disabled" fi - local bp_location bp_location=$(detect_backports_location "$DEBIAN_CODENAME") - echo "Current format: ${current_format:-none}" - echo "Backports: $bp_status (location: $bp_location)" + echo "Backports are currently $bp_status." - # ── Format selection dialog (only Trixie gets the choice) ── - local use_deb822=false - if [ "$DEBIAN_CODENAME" = "trixie" ]; then - if whiptail --title "Repository Format" --defaultno --yesno \ -"Do you want to migrate your repositories to the new -DEB822 (.sources) format? - -DEB822 is the modern, structured Debian standard. It won't -harm your system, and the script will handle the transition -safely if you accept. - -NOTE: 'NO' (default) is recommended to maintain the classic -linear format as it comes pre-configured in Debian 13 (Trixie)." 16 70; then - use_deb822=true - fi - elif [ "$current_format" = "deb822" ]; then - use_deb822=true - fi - - # Choose backports local enable_backports=false if _confirm "Backports" "Do you want to enable the official Debian Backports repository?\n\n\ -Backports provides newer, selectively updated packages from the\n\ -next Debian testing branch, recompiled to run stably on your\n\ -current system.\n\n\ -This is HIGHLY RECOMMENDED if you have modern hardware, as it\n\ -delivers newer Linux Kernels, updated display drivers, and modern\n\ -Mesa versions without compromising overall system stability." 16 70; then +Backports provides newer, selectively updated packages from the next\n\ +Debian testing branch, recompiled to run stably on your current system.\n\n\ +Answer NO to disable or remove backports if they are currently enabled." 16 70; then enable_backports=true fi - # Determine what to do - local target_format - $use_deb822 && target_format="deb822" || target_format="classic" - - if [ "$current_format" = "none" ]; then - local action="write" - elif [ "$target_format" != "$current_format" ]; then - local action="migrate" - else - local action="update" - fi - - # If nothing changed (same format + same backports state), skip - if [ "$action" = "update" ] && [ "$enable_backports" = "$bp_status" ]; then - # Check if backports location is correct (standalone) - if $enable_backports; then - local correct_location="standalone-deb822" - $use_deb822 || correct_location="standalone-classic" - if [ "$bp_location" = "$correct_location" ]; then - # Also verify no embedded backports linger - if [ "$target_format" = "deb822" ]; then - ! grep -qE "^Suites:.*${DEBIAN_CODENAME}-backports\b" /etc/apt/sources.list.d/debian.sources 2>/dev/null || { action="update"; true; } - else - ! grep -qE "^[^#]*${DEBIAN_CODENAME}-backports\b" /etc/apt/sources.list 2>/dev/null || { action="update"; true; } - fi - if [ "$action" = "update" ]; then - echo "Repository configuration is already up-to-date. Skipping." - return 0 - fi - fi - else - # Backports disabled: verify no backports files exist - if [ ! -f /etc/apt/sources.list.d/debian-backports.sources ] && \ - [ ! -f /etc/apt/sources.list.d/debian-backports.list ]; then - echo "Repository configuration is already up-to-date. Skipping." - return 0 - fi - fi + # Nothing to do — already in desired state + if { $enable_backports && [ "$bp_status" = "enabled" ]; } || \ + { ! $enable_backports && [ "$bp_status" = "disabled" ]; }; then + echo "Backports are already configured as requested." + _pause + return fi backup_current_repos - if $use_deb822; then - _write_deb822 "$DEBIAN_CODENAME" "$action" "$enable_backports" "$bp_location" + if $enable_backports; then + if [ "$current_format" = "deb822" ]; then + _write_deb822_backports "$DEBIAN_CODENAME" + else + _write_classic_backports "$DEBIAN_CODENAME" + fi else - _write_classic "$DEBIAN_CODENAME" "$action" "$enable_backports" "$bp_location" + if [ "$current_format" = "deb822" ]; then + _remove_deb822_backports "$DEBIAN_CODENAME" + else + _remove_classic_backports "$DEBIAN_CODENAME" + fi fi echo "Updating package lists..." - sudo apt update - local apt_rc=$? - if [ $apt_rc -eq 0 ]; then - REPOS_CONFIGURED=true - echo -e "${GREEN}Repositories configured and updated successfully.${NC}" - - if $use_deb822; then - # Remove any leftover disabled files from old classic format - [ -f /etc/apt/sources.list.disabled ] && sudo rm -f /etc/apt/sources.list.disabled - else - [ -f /etc/apt/sources.list.d/debian.sources.disabled ] && sudo rm -f /etc/apt/sources.list.d/debian.sources.disabled - fi - + if sudo apt update; then cleanup_repo_backup - - local upgradable - upgradable=$(apt list --upgradable 2>/dev/null | grep -c /) - if [ "$upgradable" -gt 0 ]; then - if _confirm "Upgrade System" "$upgradable packages can be upgraded. Upgrade now?"; then - sudo apt-mark hold tzdata 2>/dev/null || true - _run_cmd "Upgrade" "sudo apt upgrade -y" "Upgrading system..." - sudo apt-mark unhold tzdata 2>/dev/null || true - sudo apt autoremove -y - sudo apt autoclean - echo -e "${GREEN}System upgraded.${NC}" - _pause - else - echo "Skipping upgrade." - fi - fi + echo -e "${GREEN}Backports configured.${NC}" else restore_previous_repos - echo -e "${RED}apt update failed. Previous repository configuration restored.${NC}" - _pause - return 1 + echo -e "${RED}apt update failed. Backup restored.${NC}" fi + _pause } diff --git a/modules/repos/migrate.sh b/modules/repos/migrate.sh new file mode 100644 index 0000000..c04870f --- /dev/null +++ b/modules/repos/migrate.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +# migrate.sh — Stable → Testing / SID branch migration +# License GPL v3 + +_MIGRATE_BACKUP="" + +_persistent_backup_repos() { + local stamp + stamp=$(date +%Y%m%d-%H%M%S) + _MIGRATE_BACKUP="/var/backups/debianito-repos-${stamp}.tar.gz" + sudo mkdir -p /var/backups + local files=() + [ -f /etc/apt/sources.list ] && files+=("/etc/apt/sources.list") + [ -d /etc/apt/sources.list.d ] && files+=("/etc/apt/sources.list.d") + [ ${#files[@]} -eq 0 ] && return 1 + sudo tar czf "$_MIGRATE_BACKUP" "${files[@]}" 2>/dev/null + echo "Backup: $_MIGRATE_BACKUP" +} + +_restore_backup() { + if [ -z "$_MIGRATE_BACKUP" ] || [ ! -f "$_MIGRATE_BACKUP" ]; then + _msg "Restore Error" "No backup found at $_MIGRATE_BACKUP.\nCannot restore. Your system may be in an inconsistent state." 10 70 + return 1 + fi + echo -e "${YELLOW}Restoring repository backup...${NC}" + sudo tar xzf "$_MIGRATE_BACKUP" -C / 2>/dev/null + echo -e "${GREEN}Backup restored from $_MIGRATE_BACKUP${NC}" +} + +_write_deb822_branch() { + local target="$1" + local main_file="/etc/apt/sources.list.d/debian.sources" + + local main_content="" + if [ "$target" = "sid" ]; then + main_content+="Types: deb\n" + main_content+="URIs: https://deb.debian.org/debian\n" + main_content+="Suites: sid\n" + main_content+="Components: main contrib non-free non-free-firmware\n" + main_content+="\n" + main_content+="Types: deb\n" + main_content+="URIs: https://security.debian.org/debian-security\n" + main_content+="Suites: sid\n" + main_content+="Components: main contrib non-free non-free-firmware\n" + else + # testing + main_content+="Types: deb\n" + main_content+="URIs: https://deb.debian.org/debian\n" + main_content+="Suites: testing testing-updates\n" + main_content+="Components: main contrib non-free non-free-firmware\n" + main_content+="\n" + main_content+="Types: deb\n" + main_content+="URIs: https://security.debian.org/debian-security\n" + main_content+="Suites: testing-security\n" + main_content+="Components: main contrib non-free non-free-firmware\n" + fi + + sudo mkdir -p /etc/apt/sources.list.d + echo -e "$main_content" | sudo tee "$main_file" > /dev/null + echo "Wrote $main_file" +} + +_branch_migration() { + # ── Screen 1: Risk warning ── + _msg "WARNING: Branch Migration" \ +"Migrating from Debian Stable to Testing or SID is a\n\ +MAJOR change and CAN make your system UNBOOTABLE.\n\n\ +Risks include:\n\ + • NVIDIA / DKMS drivers may break\n\ + • System may fail to boot after reboot\n\ + • Some packages may be removed or replaced\n\ + • SID (unstable) receives NO security updates\n\n\ +A full persistent backup will be saved to /var/backups/\n\ +so you can restore if things go wrong." 16 70 || true + + if ! _confirm "Branch Migration" "Do you want to proceed with the migration?"; then + echo "Migration cancelled." + return + fi + + # ── Screen 2: Plan summary ── + local plan="This operation will:\n\n" + plan+=" 1. Backup current APT sources to /var/backups/\n" + plan+=" 2. Remove any backports configuration\n" + plan+=" 3. Write new DEB822 sources for the target branch\n" + plan+=" 4. Run: apt update\n" + plan+=" 5. Run: apt upgrade -y\n" + plan+=" 6. Run: apt full-upgrade -y\n" + plan+=" 7. Run: apt autoremove -y\n\n" + plan+="If apt update fails, the backup is restored immediately." + + _msg "Migration Plan" "$plan" 16 70 || true + + if ! _confirm "Migration Plan" "Proceed with the plan?"; then + echo "Migration cancelled." + return + fi + + # ── Screen 3: Branch selection ── + local branch + branch=$(_inputbox "Target Branch" \ + "Type exactly TESTING or SID (case-sensitive):" 10 60 "") + + [ -z "$branch" ] && { echo "Migration cancelled."; return; } + + if [ "$branch" != "TESTING" ] && [ "$branch" != "SID" ]; then + _msg "Invalid Branch" "You typed: $branch\n\nExpected: TESTING or SID (exact, case-sensitive).\nAborting." 10 60 + return + fi + + # Normalize to lowercase for internal use + local target + target=$(echo "$branch" | tr '[:upper:]' '[:lower:]') + + # ── Screen 4: Execution ── + echo -e "${YELLOW}Starting branch migration to ${target}...${NC}" + + # 4a. Persistent backup + echo "Creating backup..." + _persistent_backup_repos || { + _msg "Backup Error" "Failed to create backup. Aborting." 8 60 + return + } + + # 4b. Clean backports + echo "Removing backports configuration..." + [ -f /etc/apt/sources.list.d/debian-backports.sources ] && sudo rm -f /etc/apt/sources.list.d/debian-backports.sources + [ -f /etc/apt/sources.list.d/debian-backports.list ] && sudo rm -f /etc/apt/sources.list.d/debian-backports.list + + # 4c. Remove any old classic source files to avoid conflicts + [ -f /etc/apt/sources.list ] && sudo rm -f /etc/apt/sources.list + + # 4d. Write new sources + _write_deb822_branch "$target" + + # 4e. SID guardrails: install bug alerts before upgrade + if [ "$target" = "sid" ]; then + echo -e "${YELLOW}Installing apt-listbugs and apt-listchanges (SID guardrails)...${NC}" + sudo apt update -qq 2>/dev/null || true + sudo DEBIAN_FRONTEND=noninteractive apt install -y apt-listbugs apt-listchanges || true + fi + + # 4f. apt update with rollback on failure + echo -e "${YELLOW}Running apt update...${NC}" + if ! sudo apt update; then + echo -e "${RED}apt update failed. Restoring backup...${NC}" + _restore_backup + _msg "Migration Failed" \ +"apt update failed. Backup has been restored from:\n\ +$_MIGRATE_BACKUP\n\n\ +Your system should be back to its previous state.\n\ +Run 'sudo apt update' manually to verify." 12 70 + return + fi + + # 4g. Full upgrade + _run_cmd "Upgrade" "sudo apt upgrade -y" "Upgrading packages..." + _run_cmd "Full-Upgrade" "sudo apt full-upgrade -y" "Running full-upgrade..." + _run_cmd "Autoremove" "sudo apt autoremove -y" "Removing obsolete packages..." + + # 4h. Re-run detection to reflect new branch + echo -e "${YELLOW}Re-running system detection for new branch...${NC}" + detect_debian_version + detect_kernel + detect_gpu + detect_storage + + echo -e "${GREEN}Branch migration to ${target} completed successfully.${NC}" + + # ── Screen 5: Reboot reminder ── + _msg "Migration Complete" \ +"System has been migrated to ${target}.\n\n\ +Backup saved at:\n $_MIGRATE_BACKUP\n\n\ +REBOOT your system.\nIf it fails to boot, restore the backup manually:\n\ + sudo tar xzf $_MIGRATE_BACKUP -C /\n sudo apt update\n sudo apt upgrade" 16 70 +} diff --git a/modules/rescue.sh b/modules/rescue.sh index a107bec..c31eac1 100644 --- a/modules/rescue.sh +++ b/modules/rescue.sh @@ -56,13 +56,12 @@ _rescue_initramfs() { rescue_boot() { while true; do local choice - choice=$(whiptail --title "Boot Rescue & Repair" --menu \ + choice=$(_menu "Boot Rescue & Repair" \ "Select a rescue operation${SCROLL_HINT}:" \ $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "1" "Refirm Secure Boot (shim + GRUB)" \ "2" "Regenerate initramfs (all kernels)" \ - "3" "Return to main menu" \ - 3>&1 1>&2 2>&3) + "3" "Return to main menu") [ -z "$choice" ] && return clear diff --git a/modules/sudo_config.sh b/modules/sudo_config.sh index 103e254..2b04832 100644 --- a/modules/sudo_config.sh +++ b/modules/sudo_config.sh @@ -7,14 +7,13 @@ config_sudo() { while true; do local choice - choice=$(whiptail --title "User Privileges & Feedback" --menu \ + choice=$(_menu "User Privileges & Feedback" \ "Select an option:" $TUI_ALTO $TUI_ANCHO 6 \ "1" "Sudo Group Membership" \ "2" "Passwordless Sudo (maintenance commands)" \ "3" "Repair Home Directory Ownership" \ "4" "Sudo Password Feedback (asterisks)" \ - "5" "Back to main menu" \ - 3>&1 1>&2 2>&3) + "5" "Back to main menu") [ -z "$choice" ] && return clear @@ -67,12 +66,11 @@ _configure_nopasswd() { - shutdown / reboot / halt (power commands)\n\n\ Useful for automation but reduces security." 14 70; then local choices - choices=$(whiptail --title "NOPASSWD Commands" --checklist \ + choices=$(_checklist "NOPASSWD Commands" \ "Select commands to allow without password:" 12 60 3 \ "apt" "APT package management" ON \ "systemctl" "Systemd service management" ON \ - "power" "Shutdown, reboot, halt" ON \ - 3>&1 1>&2 2>&3) + "power" "Shutdown, reboot, halt" ON) clear [ -z "$choices" ] && { echo "No commands selected."; return; } @@ -93,12 +91,10 @@ Useful for automation but reduces security." 14 70; then esac done - echo -e "$content" | sudo tee "$nopasswd_file" > /dev/null - sudo chmod 0440 "$nopasswd_file" - if [ -f "$nopasswd_file" ]; then + local content_str; content_str=$(echo -e "$content") + if _validate_sudoers "$content_str" "$nopasswd_file"; then echo -e "${GREEN}Passwordless sudo configured for selected commands.${NC}" else - echo -e "${RED}Failed to configure passwordless sudo.${NC}" return 1 fi fi @@ -148,10 +144,9 @@ _toggle_pwfeedback() { else if _confirm "Password Feedback" \ "Show asterisks when typing the sudo password?"; then - if echo 'Defaults pwfeedback' | sudo tee "$fb_file" > /dev/null 2>&1; then + if _validate_sudoers 'Defaults pwfeedback' "$fb_file"; then echo -e "${GREEN}Password feedback enabled.${NC}" else - echo -e "${RED}Failed to create $fb_file${NC}" return 1 fi fi diff --git a/modules/swap.sh b/modules/swap.sh new file mode 100644 index 0000000..009a58e --- /dev/null +++ b/modules/swap.sh @@ -0,0 +1,187 @@ +#!/usr/bin/env bash +# swap.sh — Disk-based swap management (swapfile + swappiness) +# Independent of zram.sh. Uses pri=10 to coexist with ZRAM priority=100. + +readonly SWAP_FILE="/swapfile" +readonly SWAP_FSTAB_TAG="# debianito-managed-swap" +readonly SWAP_PRIORITY="10" +readonly SWAP_CONF="/etc/sysctl.d/99-swappiness-debianito.conf" +readonly SWAP_LOCK="/run/lock/debianito-swap.lock" + +# ── Helpers ── + +_swap_valid_fstab() { + local tmp="$1" + sudo findmnt --verify --fstab "$tmp" >/dev/null 2>&1 +} + +_swap_safe_write_fstab() { + local line="$1" + local tmp + tmp=$(mktemp) || return 1 + sudo cp /etc/fstab "$tmp" + sudo sed -i "/$SWAP_FSTAB_TAG/d" "$tmp" + [ -n "$line" ] && printf '%s\n' "$line" >> "$tmp" + if _swap_valid_fstab "$tmp"; then + sudo install -o root -g root -m 0644 "$tmp" /etc/fstab + else + local err + err=$(sudo findmnt --verify --fstab "$tmp" 2>&1 || true) + rm -f "$tmp" + _msg "fstab Error" "Validation failed — changes NOT applied.\n\n$err" 12 70 + return 1 + fi + rm -f "$tmp" +} + +_swap_recommend_gb() { + if [ -z "${RAM_GB:-}" ]; then + echo 2 + return + fi + local ram + ram=$(echo "$RAM_GB" | awk '{print int($1)}') + if [ "$ram" -ge 16 ]; then + echo 2 + elif [ "$ram" -ge 8 ]; then + echo 4 + else + local rec + rec=$((ram * 2)) + [ "$rec" -lt 1 ] && rec=1 + echo "$rec" + fi +} + +# ── Menu options ── + +_swap_current_status() { + echo "── Current swap ──" + sudo swapon --show 2>/dev/null || echo "(none active)" + echo "" + echo "swappiness: $(cat /proc/sys/vm/swappiness)" + echo "" + echo "fstab swap entries:" + grep -E 'swap|SWAP' /etc/fstab 2>/dev/null || echo "(none in fstab)" + _pause +} + +_swap_create_file() { + local fstype rec_gb + fstype=$(stat -f -c %T "$(dirname "$SWAP_FILE")" 2>/dev/null || echo "ext4") + rec_gb=$(_swap_recommend_gb) + + local warn="" + if [ "$fstype" = "btrfs" ]; then + warn="Filesystem: Btrfs\nSwapfile on Btrfs needs extra steps (nodatacow).\nHibernation requires swap ≥ RAM and manual resume= config.\n\n" + fi + warn+="ZRAM (priority 100) is used first.\nDisk swap (priority $SWAP_PRIORITY) is only consumed after ZRAM fills." + + _msg "Swapfile Info" "$warn" 14 65 + + local size_gb + size_gb=$(_inputbox "Swapfile Size" "Size in GB for $SWAP_FILE:" 10 60 "$rec_gb") + [ -z "$size_gb" ] && return + [[ "$size_gb" =~ ^[0-9]+$ ]] && [ "$size_gb" -gt 0 ] || { + _msg "Error" "Enter a positive integer." 8 40 + return + } + + if [ -f "$SWAP_FILE" ]; then + _confirm "Swapfile exists" "$SWAP_FILE already exists.\nRecreate it (${size_gb} GB)?" || return + sudo swapoff "$SWAP_FILE" 2>/dev/null || true + sudo rm -f "$SWAP_FILE" + fi + + echo -e "${YELLOW}Allocating ${size_gb}G swapfile...${NC}" + if [ "$fstype" = "btrfs" ]; then + sudo touch "$SWAP_FILE" + sudo chattr +C "$SWAP_FILE" 2>/dev/null || true + sudo dd if=/dev/zero of="$SWAP_FILE" bs=1M count=$((size_gb * 1024)) status=progress + else + sudo fallocate -l "${size_gb}G" "$SWAP_FILE" || \ + sudo dd if=/dev/zero of="$SWAP_FILE" bs=1M count=$((size_gb * 1024)) status=progress + fi + + sudo chmod 600 "$SWAP_FILE" + sudo mkswap "$SWAP_FILE" >/dev/null + sudo swapon "$SWAP_FILE" + + local fstab_line + fstab_line="$SWAP_FILE none swap sw,pri=$SWAP_PRIORITY 0 0 $SWAP_FSTAB_TAG # pri=$SWAP_PRIORITY (below zram 100)" + if _swap_safe_write_fstab "$fstab_line"; then + _msg "Swapfile" "Swapfile created and added to fstab (persistent).\n\nPriority: $SWAP_PRIORITY (below ZRAM 100)." 12 65 + else + sudo swapoff "$SWAP_FILE" 2>/dev/null || true + sudo rm -f "$SWAP_FILE" + fi +} + +_swap_remove_file() { + local has_tag + has_tag=$(grep -c "$SWAP_FSTAB_TAG" /etc/fstab 2>/dev/null || echo 0) + [ "$has_tag" -eq 0 ] && [ ! -f "$SWAP_FILE" ] && { + _msg "Swap" "No managed swapfile found." 8 50 + return + } + + _confirm "Remove Swapfile" "Disable and delete $SWAP_FILE?\n\nRemoves fstab entry and deletes the file." || return + + sudo swapoff "$SWAP_FILE" 2>/dev/null || true + _swap_safe_write_fstab "" + sudo rm -f "$SWAP_FILE" + _msg "Swap" "Swapfile removed and fstab entry cleaned." 8 60 +} + +_swap_set_swappiness() { + local cur val + cur=$(cat /proc/sys/vm/swappiness 2>/dev/null || echo 60) + val=$(_inputbox "Swappiness" "Current value: $cur\nEnter new value (0-100):" 10 60 "$cur") + [ -z "$val" ] && return + [[ "$val" =~ ^[0-9]+$ ]] && [ "$val" -le 100 ] || { + _msg "Error" "Value must be 0-100." 8 40 + return + } + + local tmp + tmp=$(mktemp) || return + printf 'vm.swappiness=%s\n' "$val" > "$tmp" + sudo install -o root -g root -m 0644 "$tmp" "$SWAP_CONF" + sudo sysctl -w "vm.swappiness=$val" >/dev/null + rm -f "$tmp" + _msg "Swappiness" "swappiness set to $val (persistent)." 8 60 +} + +# ── Entry point ── + +manage_swap() { + exec 9>"$SWAP_LOCK" + flock -n 9 || { + _msg "Busy" "Another swap operation is already running." 8 55 + return + } + + while true; do + local choice + choice=$(_menu "Swap Management (disk)" \ + "Select an option:" $TUI_ALTO $TUI_ANCHO 6 \ + "1" "Show current swap & swappiness" \ + "2" "Create / resize swapfile" \ + "3" "Remove swapfile" \ + "4" "Change swappiness" \ + "5" "Back to main menu") + + [ -z "$choice" ] && break + clear + + case "$choice" in + 1) _swap_current_status ;; + 2) _swap_create_file ;; + 3) _swap_remove_file ;; + 4) _swap_set_swappiness ;; + 5) break ;; + esac + done + + exec 9>&- +} diff --git a/modules/utils.sh b/modules/utils.sh index eb594a2..4081bd5 100644 --- a/modules/utils.sh +++ b/modules/utils.sh @@ -369,23 +369,31 @@ detect_displayserver() { } # --------------------------------------- -# Storage summary via lsblk (NVMe / SSD / HDD) +# Storage summary via lsblk (NVMe / SSD / HDD / USB-SD) # --------------------------------------- detect_storage() { local parts=() - local name size rota type + local name size rota type rm - while read -r name size rota; do + while read -r name size rota type; do [ "$name" = "NAME" ] && continue + echo "$name" | grep -q "zram" && continue + [ "$type" = "loop" ] || [ "$type" = "rom" ] && continue + if echo "$name" | grep -q "nvme"; then type="NVMe" elif [ "$rota" = "1" ]; then type="HDD" else - type="SSD" + rm=$(cat /sys/block/"$name"/removable 2>/dev/null || echo 0) + if [ "$rm" = "1" ]; then + type="USB/SD" + else + type="SSD" + fi fi parts+=("${size} ${type}") - done < <(lsblk -d -o NAME,SIZE,ROTA 2>/dev/null || true) + done < <(lsblk -d -o NAME,SIZE,ROTA,TYPE -e 7,11 2>/dev/null || true) if [ ${#parts[@]} -eq 0 ]; then STORAGE_SUMMARY="No disks detected" @@ -539,7 +547,38 @@ _confirm_custom() { } _msg() { - whiptail --title "$1" --msgbox "$2" "${3:-10}" "${4:-65}" + whiptail --title "$1" --msgbox "$2" "${3:-10}" "${4:-65}" || true +} + +_menu() { + local title="$1" text="$2" h="$3" w="$4" lh="$5"; shift 5 + whiptail --title "$title" --menu "$text" "$h" "$w" "$lh" "$@" 3>&1 1>&2 2>&3 || true +} + +_checklist() { + local title="$1" text="$2" h="$3" w="$4" lh="$5"; shift 5 + whiptail --title "$title" --checklist "$text" "$h" "$w" "$lh" "$@" 3>&1 1>&2 2>&3 || true +} + +_inputbox() { + whiptail --title "$1" --inputbox "$2" "${3:-10}" "${4:-60}" "${5:-}" 3>&1 1>&2 2>&3 || true +} + +_validate_sudoers() { + local content="$1" dest="$2" + local tmpfile + tmpfile=$(mktemp) || return 1 + echo "$content" > "$tmpfile" + if ! visudo -cf "$tmpfile" &>/dev/null; then + local err + err=$(visudo -cf "$tmpfile" 2>&1 || true) + rm -f "$tmpfile" + _msg "Sudoers Error" "Invalid sudoers syntax in:\n\n${err}\n\nFile was NOT written.\nThis prevents broken sudo access." 12 70 + return 1 + fi + sudo cp "$tmpfile" "$dest" + sudo chmod 0440 "$dest" + rm -f "$tmpfile" } _pause() { @@ -554,7 +593,7 @@ _run_cmd() { clear echo -e "${GREEN}[+]${NC} $success_msg" echo "──────────────────────────────────────────────" - eval "$command" + bash -c "$command" local rc=$? echo "──────────────────────────────────────────────" if [ $rc -eq 0 ]; then diff --git a/modules/zram.sh b/modules/zram.sh index 02d3289..7e5c05b 100644 --- a/modules/zram.sh +++ b/modules/zram.sh @@ -12,7 +12,7 @@ install_zram() { local half_ram_mb=$(( ((RAM_KB / 1024 / 1024 + 1) / 2) * 1024 )) local algo - algo=$(whiptail --title "ZRAM Compression" --menu \ + algo=$(_menu "ZRAM Compression" \ "ZRAM compresses a portion of RAM into compressed swap,\ effectively increasing available memory. @@ -22,8 +22,7 @@ more swap space without disk writes. Choose compression algorithm:" \ $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \ "lz4" "Fastest, low CPU (recommended)" \ - "zstd" "Better ratio, more CPU" \ - 3>&1 1>&2 2>&3) + "zstd" "Better ratio, more CPU") if [ -z "$algo" ]; then echo "ZRAM configuration cancelled." @@ -34,8 +33,7 @@ Choose compression algorithm:" \ if _confirm "ZRAM Size" "Use recommended size for ZRAM? (${half_ram_mb} MB out of ${RAM_SUMMARY})"; then zram_size=$half_ram_mb else - zram_size=$(whiptail --title "ZRAM Size" --inputbox \ - "Enter ZRAM size in MB:" 8 60 "$half_ram_mb" 3>&1 1>&2 2>&3) + zram_size=$(_inputbox "ZRAM Size" "Enter ZRAM size in MB:" 8 60 "$half_ram_mb") if [ -z "$zram_size" ] || ! [[ "$zram_size" =~ ^[0-9]+$ ]] || [ "$zram_size" -eq 0 ]; then echo "ZRAM configuration cancelled." return 0