add Java JDK/JRE selection and patches

- Created dedicated `extras/java.sh` module for modular Temurin/Adoptium repository handling and isolated GPG key management.
- Implemented selective JRE/JDK installation paths: Gaming (Minecraft) vs Development environments with version control selectors.
- Enhanced user group membership logic (`_ensure_sudo_group`) to auto-configure administrative privileges on fresh installs.
- Introduced maintenance-friendly passwordless sudo for `apt`, `systemctl`, and shutdown commands via `/etc/sudoers.d/`.
- Added home directory ownership repair utility to fix root-owned files in user directories after improper `sudo` usage.
- Enabled visual password feedback (`pwfeedback`) toggle for enhanced terminal usability during authentication prompts.
- Refactored Debian 13/Trixie repository sourcing logic to ensure idempotency and prevent backports/duplicate sources conflicts.
- Updated Bullseye legacy modules (extras.sh, repos.sh) to exclude deprecated packages (`hx`, `vscodium`) and enforce Firefox ESR defaults.
- Cleaned repository configurations by removing obsolete `bullseye-updates` source entries to prevent dependency conflicts.
- Implemented NVTOP conditional detection logic ensuring display only on active Nvidia drivers or supported architectures (Trixie/Bookworm).
- Corrected `/modules/bullseye/extras.sh` menu mappings (Programming, Dev Tools) and verified package lists excluding incompatible tools (`hx`, `vscodium`).
- Integrated ClamAV security module with daemon state management and background scan execution flows in all Security menus.
- update README.md
This commit is contained in:
stornic56
2026-06-13 19:21:55 -05:00
committed by GitHub
parent 656f045163
commit 872f92d6b4
16 changed files with 1037 additions and 357 deletions
+236 -150
View File
@@ -49,43 +49,34 @@ Instalar?"; then
# ======================================================================
_cat_customization_bullseye() {
local items=()
if [ -f "${MODULES_DIR}/extras/themes/icons/icons.sh" ]; then
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 \
"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 ;;
2) _cat_icons_bullseye ;;
3) _cat_cursors_bullseye ;;
4) _cat_fonts_bullseye ;;
esac
else
_msg "Customization" "Themes submodules not found." 8 50
fi
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 \
"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 ;;
2) _cat_icons_bullseye ;;
3) _cat_cursors_bullseye ;;
4) _cat_fonts_bullseye ;;
esac
}
_cat_themes_bullseye() {
local theme_state; theme_state=$(_state "breeze")
local numix_state; numix_state=$(_state "numix-gtk-theme")
if [ "$theme_state" = "OFF" ] && [ "$numix_state" = "OFF" ]; then
theme_state="ON"
fi
local choices
choices=$(whiptail --title "Desktop Themes (Bullseye)" --checklist \
"Available themes in Bullseye repos ($TUI_ALTO linea):" \
$TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"breeze" "Breeze GTK theme (KDE)$(_inst breeze)" "$theme_state" \
"numix-gtk-theme" "Numix GTK theme$(_inst numix-gtk-theme)" "$numix_state" \
"Select desktop themes:" $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
@@ -97,19 +88,21 @@ _cat_themes_bullseye() {
}
_cat_icons_bullseye() {
_msg "Icon Themes (Bullseye)" \
"Adwaita, Humanity, DMZ y otros temas de iconos\n\
están disponibles desde los repos oficiales.\n\n\
Seleccione desde el menú de GNOME/KDE o instale\n\
el paquete 'gnome-icon-theme' o 'breeze-icon-theme'." 12 60
local items=(
"breeze-icon-theme" "Breeze icon theme$(_inst breeze-icon-theme)" "$(_state breeze-icon-theme)"
"deepin-icon-theme" "Deepin icon theme$(_inst deepin-icon-theme)" "$(_state deepin-icon-theme)"
"moka-icon-theme" "Moka icon theme$(_inst moka-icon-theme)" "$(_state moka-icon-theme)"
"numix-icon-theme" "Numix icon theme$(_inst numix-icon-theme)" "$(_state numix-icon-theme)"
"numix-icon-theme-circle" "Numix Circle icon theme$(_inst numix-icon-theme-circle)" "$(_state numix-icon-theme-circle)"
"obsidian-icon-theme" "Obsidian icon theme$(_inst obsidian-icon-theme)" "$(_state obsidian-icon-theme)"
"papirus-icon-theme" "Papirus icon theme$(_inst papirus-icon-theme)" "$(_state papirus-icon-theme)"
"paper-icon-theme" "Paper icon theme$(_inst paper-icon-theme)" "$(_state paper-icon-theme)"
"suru-icon-theme" "Suru icon theme$(_inst suru-icon-theme)" "$(_state suru-icon-theme)"
)
local choices
choices=$(whiptail --title "Icon Themes (Bullseye)" --checklist \
"Available icon themes:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"gnome-icon-theme" "GNOME icon theme$(_inst gnome-icon-theme)" "$(_state gnome-icon-theme)" \
"breeze-icon-theme" "Breeze icon theme$(_inst breeze-icon-theme)" "$(_state breeze-icon-theme)" \
"papirus-icon-theme" "Papirus icon theme$(_inst papirus-icon-theme)" "$(_state papirus-icon-theme)" \
3>&1 1>&2 2>&3)
"Select icon themes:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"${items[@]}" 3>&1 1>&2 2>&3)
clear
[ -z "$choices" ] && return
local cleaned; cleaned=$(echo "$choices" | tr -d '"')
@@ -122,10 +115,12 @@ el paquete 'gnome-icon-theme' o 'breeze-icon-theme'." 12 60
_cat_cursors_bullseye() {
local choices
choices=$(whiptail --title "Cursor Themes (Bullseye)" --checklist \
"Available cursor themes:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"dmz-cursor-theme" "DMZ cursor theme$(_inst dmz-cursor-theme)" "$(_state dmz-cursor-theme)" \
"breeze-cursor-theme" "Breeze cursor theme$(_inst breeze-cursor-theme)" "$(_state breeze-cursor-theme)" \
"oxygen-cursor-theme" "Oxygen cursor theme$(_inst oxygen-cursor-theme)" "$(_state oxygen-cursor-theme)" \
"Select cursor themes:" $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
@@ -155,19 +150,32 @@ _cat_fonts_bullseye() {
}
_cat_download_bullseye() {
local choices
choices=$(whiptail --title "Download & Torrent (Bullseye)" --checklist \
local choices1 choices2=""
choices1=$(whiptail --title "Downloaders" --checklist \
"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)" \
"qbittorrent" "BitTorrent client (Qt)$(_inst qbittorrent)" "$(_state qbittorrent)" \
"transmission-gtk" "BitTorrent client (GTK)$(_inst transmission-gtk)" "$(_state transmission-gtk)" \
"transmission-qt" "BitTorrent client (Qt)$(_inst transmission-qt)" "$(_state transmission-qt)" \
"deluge" "BitTorrent client (GTK)$(_inst deluge)" "$(_state deluge)" \
"aria2" "Multiprotocol downloader (CLI)$(_inst aria2)" "$(_state aria2)" \
"filezilla" "FTP/SFTP client (GUI)$(_inst filezilla)" "$(_state filezilla)" \
3>&1 1>&2 2>&3)
clear
[ -z "$choices" ] && return
local cleaned; cleaned=$(echo "$choices" | tr -d '"')
choices2=$(whiptail --title "Torrent Clients" --checklist \
"Select torrent clients:" $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)" \
"qbittorrent" "BitTorrent client (Qt)$(_inst qbittorrent)" "$(_state qbittorrent)" \
"qbittorrent-nox" "BitTorrent WebUI/CLI$(_inst qbittorrent-nox)" "$(_state qbittorrent-nox)" \
"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
cleaned=$(echo "$choices1 $choices2" | tr -d '"')
[ -z "$cleaned" ] && { echo "No download tools selected."; return; }
for pkg in $cleaned; do
if ! is_installed "$pkg"; then
_run_install "$pkg"
@@ -175,35 +183,46 @@ _cat_download_bullseye() {
echo "$pkg already installed."
fi
done
echo -e "${GREEN}Download tools installed.${NC}"
echo -e "${GREEN}Download & network tools installed.${NC}"
}
_cat_internet_bullseye() {
local ff_state; ff_state=$(_state "firefox-esr")
local tbird_state; tbird_state=$(_state "thunderbird")
local chr_state; chr_state=$(_state "chromium")
local choices
choices=$(whiptail --title "Internet (Bullseye)" --checklist \
"Select browsers, email:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"firefox-esr" "Firefox ESR (official Debian)$(_inst firefox-esr)" "$ff_state" \
"chromium" "Chromium web browser$(_inst chromium)" "$chr_state" \
"thunderbird" "Email client$(_inst thunderbird)" "$tbird_state" \
"dillo" "Lightweight graphical browser$(_inst dillo)" "$(_state dillo)" \
"elinks" "Text-mode web browser$(_inst elinks)" "$(_state elinks)" \
"konqueror" "KDE file manager / web browser$(_inst konqueror)" "$(_state konqueror)" \
"w3m" "Text-mode browser + deps$(_inst w3m)" "$(_state w3m)" \
"torbrowser-launcher" "Tor Browser launcher$(_inst torbrowser-launcher)" "$(_state torbrowser-launcher)" \
"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)" \
"epiphany-browser" "GNOME web browser$(_inst epiphany-browser)" "$(_state epiphany-browser)" \
"falkon" "KDE web browser (QtWebEngine)$(_inst falkon)" "$(_state falkon)" \
"firefox-esr" "Firefox ESR (official Debian)$(_inst firefox-esr)" "$(_state firefox-esr)" \
"konqueror" "KDE file manager / web browser$(_inst konqueror)" "$(_state konqueror)" \
"qutebrowser" "Keyboard-driven browser (Qt)$(_inst qutebrowser)" "$(_state qutebrowser)" \
"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 '"')
for pkg in $cleaned; do
if ! is_installed "$pkg"; then
_run_install "$pkg"
else
echo "$pkg already installed."
fi
case $pkg in
w3m)
local need=()
! is_installed "w3m" && need+=("w3m")
! is_installed "w3m-img" && need+=("w3m-img")
! is_installed "ca-certificates" && need+=("ca-certificates")
! is_installed "xsel" && need+=("xsel")
[ ${#need[@]} -gt 0 ] && _run_install_batch "${need[@]}" || echo "Already installed."
;;
*)
if ! is_installed "$pkg"; then
_run_install "$pkg"
else
echo "$pkg already installed."
fi
;;
esac
done
echo -e "${GREEN}Internet tools installed.${NC}"
}
@@ -232,14 +251,19 @@ _cat_design_bullseye() {
local choices
choices=$(whiptail --title "Multimedia & Design (Bullseye)" --checklist \
"Select multimedia and design tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"audacity" "Audio editor/recorder$(_inst audacity)" "$(_state audacity)" \
"blender" "3D modeling/animation suite$(_inst blender)" "$(_state blender)" \
"ffmpeg" "Multimedia framework (CLI)$(_inst ffmpeg)" "$(_state ffmpeg)" \
"gimp" "Image editor$(_inst gimp)" "$(_state gimp)" \
"inkscape" "Vector graphics editor$(_inst inkscape)" "$(_state inkscape)" \
"kdenlive" "Video editor (KDE)$(_inst kdenlive)" "$(_state kdenlive)" \
"obs-studio" "Streaming/recording studio$(_inst obs-studio)" "$(_state obs-studio)" \
"scribus" "Desktop publishing$(_inst scribus)" "$(_state scribus)" \
"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)" \
"ffmpeg" "Multimedia framework (CLI)$(_inst ffmpeg)" "$(_state ffmpeg)" \
"gimp" "Image editor$(_inst gimp)" "$(_state gimp)" \
"handbrake" "Video transcoder (DVD ripper)$(_inst handbrake)" "$(_state handbrake)" \
"inkscape" "Vector graphics editor$(_inst inkscape)" "$(_state inkscape)" \
"kdenlive" "Video editor (KDE)$(_inst kdenlive)" "$(_state kdenlive)" \
"krita" "Digital painting/illustration$(_inst krita)" "$(_state krita)" \
"obs-studio" "Screen recording/streaming$(_inst obs-studio)" "$(_state obs-studio)" \
"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
@@ -251,24 +275,22 @@ _cat_design_bullseye() {
echo "$pkg already installed."
fi
done
echo -e "${GREEN}Design tools installed.${NC}"
echo -e "${GREEN}Multimedia & design tools installed.${NC}"
}
_cat_programming_bullseye() {
local choices
choices=$(whiptail --title "Programming (Bullseye)" --checklist \
"Select programming tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"build-essential" "GCC/Clang compilers$(_inst build-essential)" "$(_state build-essential)" \
"python3" "Python 3 interpreter$(_inst python3)" "$(_state python3)" \
"python3-pip" "Python 3 package manager$(_inst python3-pip)" "$(_state python3-pip)" \
"nodejs" "Node.js (Debian repo)$(_inst nodejs)" "$(_state nodejs)" \
"npm" "Node.js package manager$(_inst npm)" "$(_state npm)" \
"openjdk-17-jdk" "OpenJDK 17 JDK$(_inst openjdk-17-jdk)" "$(_state openjdk-17-jdk)" \
"git" "Version control system$(_inst git)" "$(_state git)" \
"vim" "Text editor (Vim)$(_inst vim)" "$(_state vim)" \
"nano" "Text editor (Nano)$(_inst nano)" "$(_state nano)" \
"geany" "Lightweight IDE$(_inst geany)" "$(_state geany)" \
"codeblocks" "Cross-platform IDE$(_inst codeblocks)" "$(_state codeblocks)" \
choices=$(whiptail --title "Code Editors & IDEs (Bullseye)" --checklist \
"Select editors and IDEs:" $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)" \
"nano" "Simple terminal editor$(_inst nano)" "$(_state nano)" \
"emacs" "Extensible editor / IDE$(_inst emacs)" "$(_state emacs)" \
"kate" "KDE advanced text editor$(_inst kate)" "$(_state kate)" \
"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
@@ -280,57 +302,120 @@ _cat_programming_bullseye() {
echo "$pkg already installed."
fi
done
echo -e "${GREEN}Programming tools installed.${NC}"
echo -e "${GREEN}Code editors & IDEs installed.${NC}"
}
_cat_dev_bullseye() {
local choices
choices=$(whiptail --title "Servers & Dev Tools (Bullseye)" --checklist \
"Select development tools and servers:" $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)" \
"mariadb-server" "MariaDB database server$(_inst mariadb-server)" "$(_state mariadb-server)" \
"netcat-openbsd" "TCP/IP networking utility$(_inst netcat-openbsd)" "$(_state netcat-openbsd)" \
"nginx" "Nginx web server$(_inst nginx)" "$(_state nginx)" \
"openssh-server" "SSH server$(_inst openssh-server)" "$(_state openssh-server)" \
"openssl" "OpenSSL cryptography toolkit$(_inst openssl)" "$(_state openssl)" \
"postgresql" "PostgreSQL database server$(_inst postgresql)" "$(_state postgresql)" \
"python3-pip" "Python 3 pip + venv + dev$(_inst python3-pip)" "$(_state python3-pip)" \
"redis-server" "Redis key-value store$(_inst redis-server)" "$(_state redis-server)" \
"sqlite3" "SQLite database engine$(_inst sqlite3)" "$(_state sqlite3)" \
"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 '"')
for pkg in $cleaned; do
case $pkg in
docker)
local need=()
! is_installed "docker.io" && need+=("docker.io")
! is_installed "docker-compose" && need+=("docker-compose")
if [ ${#need[@]} -gt 0 ]; then
_run_install_batch "${need[@]}"
else
echo "Docker already installed."
fi
;;
python3-pip)
local need=()
! is_installed "python3-pip" && need+=("python3-pip")
! is_installed "python3-venv" && need+=("python3-venv")
! is_installed "python3-dev" && need+=("python3-dev")
if [ ${#need[@]} -gt 0 ]; then
_run_install_batch "${need[@]}"
else
echo "Python 3 tools already installed."
fi
;;
openjdk-dev-env)
_install_dev_java
;;
*)
if ! is_installed "$pkg"; then
_run_install "$pkg"
else
echo "$pkg already installed."
fi
;;
esac
done
echo -e "${GREEN}Servers & dev tools installed.${NC}"
}
_cat_security_bullseye() {
local choices
choices=$(whiptail --title "Security & Networking (Bullseye)" --checklist \
"Select security tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"nmap" "Network scanner$(_inst nmap)" "$(_state nmap)" \
"wireshark" "Packet analyzer$(_inst wireshark)" "$(_state wireshark)" \
"nikto" "Web server scanner$(_inst nikto)" "$(_state nikto)" \
"sqlmap" "SQL injection tool$(_inst sqlmap)" "$(_state sqlmap)" \
"gobuster" "Directory/file brute-forcer$(_inst gobuster)" "$(_state gobuster)" \
"hydra" "Login cracker$(_inst hydra)" "$(_state hydra)" \
"john" "John the Ripper password cracker$(_inst john)" "$(_state john)" \
"aircrack-ng" "Wireless security tool$(_inst aircrack-ng)" "$(_state aircrack-ng)" \
"Select security and networking tools:" $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 '"')
for pkg in $cleaned; do
if ! is_installed "$pkg"; then
_run_install "$pkg"
else
echo "$pkg already installed."
fi
case $pkg in
clamav)
_install_clamav
;;
*)
if ! is_installed "$pkg"; then
_run_install "$pkg"
else
echo "$pkg already installed."
fi
;;
esac
done
echo -e "${GREEN}Security tools installed.${NC}"
echo -e "${GREEN}Security & networking tools installed.${NC}"
}
_cat_general_bullseye() {
local choices
choices=$(whiptail --title "System Tools (Bullseye)" --checklist \
"Select system utilities:" $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)" \
"curl-wget" "HTTP transfer tools (curl, wget)$(_inst curl)" "$(_state curl)" \
"flatpak" "Flatpak sandbox (Bullseye native)$(_inst flatpak)" "$(_state flatpak)" \
"fwupd" "Firmware update daemon$(_inst fwupd)" "$(_state fwupd)" \
"gnome-disk-utility" "Disk management GUI$(_inst gnome-disk-utility)" "$(_state gnome-disk-utility)" \
"gparted" "Partition editor$(_inst gparted)" "$(_state gparted)" \
"htop" "Interactive process viewer$(_inst htop)" "$(_state htop)" \
"inxi" "System information tool$(_inst inxi)" "$(_state inxi)" \
"kvm" "QEMU/KVM virtualization$(_inst virt-manager)" "$(_state virt-manager)" \
"lshw" "List hardware details$(_inst lshw)" "$(_state lshw)" \
"mc" "Midnight Commander$(_inst mc)" "$(_state mc)" \
"ncdu" "Disk usage analyzer$(_inst ncdu)" "$(_state ncdu)" \
"psensor" "Temperature monitor$(_inst psensor)" "$(_state psensor)" \
"timeshift" "System restore snapshots$(_inst timeshift)" "$(_state timeshift)" \
"tmux" "Terminal multiplexer$(_inst tmux)" "$(_state tmux)" \
"wine" "Windows compatibility layer$(_inst wine)" "$(_state wine)" \
"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)" \
"curl-wget" "HTTP transfer tools (curl, wget)$(_inst curl)" "$(_state curl)" \
"flatpak" "Flatpak sandbox (Bullseye native)$(_inst flatpak)" "$(_state flatpak)" \
"fwupd" "Firmware update daemon$(_inst fwupd)" "$(_state fwupd)" \
"gnome-disk-utility" "Disk management GUI$(_inst gnome-disk-utility)" "$(_state gnome-disk-utility)" \
"gparted" "Partition editor$(_inst gparted)" "$(_state gparted)" \
"htop" "Interactive process viewer$(_inst htop)" "$(_state htop)" \
"inxi" "System information tool$(_inst inxi)" "$(_state inxi)" \
"kvm" "QEMU/KVM virtualization$(_inst virt-manager)" "$(_state virt-manager)" \
"lshw" "List hardware details$(_inst lshw)" "$(_state lshw)" \
"mc" "Midnight Commander$(_inst mc)" "$(_state mc)" \
"ncdu" "Disk usage analyzer$(_inst ncdu)" "$(_state ncdu)" \
"psensor" "Temperature monitor$(_inst psensor)" "$(_state psensor)" \
"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
@@ -345,9 +430,7 @@ _cat_general_bullseye() {
! is_installed "unrar" && need+=("unrar")
! is_installed "p7zip-full" && need+=("p7zip-full")
! is_installed "p7zip-rar" && need+=("p7zip-rar")
if [ ${#need[@]} -gt 0 ]; then
_run_install_batch "${need[@]}"
fi
[ ${#need[@]} -gt 0 ] && _run_install_batch "${need[@]}"
;;
curl-wget)
local need=()
@@ -409,7 +492,7 @@ _cat_general_bullseye() {
_cat_fetch_bullseye() {
local items=(
"neofetch" "System info fetcher$(_inst neofetch)" "$(_state neofetch)"
"neofetch" "System info fetcher$(_inst neofetch)" "$(_state neofetch)"
"screenfetch" "System info (BSD/Linux)$(_inst screenfetch)" "$(_state screenfetch)"
"linuxlogo" "Linux logo + system info$(_inst linuxlogo)" "$(_state linuxlogo)"
)
@@ -436,22 +519,24 @@ _cat_fetch_bullseye() {
# ======================================================================
install_extras_bullseye() {
echo -e "${YELLOW}Extra software — Bullseye mode (official repos only).${NC}"
_load_extras
while true; do
local cat_choice
cat_choice=$(whiptail --title "Extra Software — Bullseye" --menu \
"Select a category:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
"0" "Essential Pack" \
"1" "Customization System" \
"2" "Download & Network" \
"3" "Internet (Browsers, Email)" \
"4" "Media Players" \
"5" "Multimedia & Design" \
"6" "Programming Applications" \
"7" "Security & Networking" \
"8" "System Tools" \
"9" "Fetch / System Info" \
"10" "Back to main menu" \
"0" "Essential Pack" \
"1" "Customization System" \
"2" "Download & Network" \
"3" "Internet (Browsers, Email)" \
"4" "Media Players" \
"5" "Multimedia & Design" \
"6" "Code Editors & IDEs" \
"7" "Servers & Dev Tools" \
"8" "Security & Networking" \
"9" "System Tools" \
"10" "Fetch / System Info" \
"11" "Back to main menu" \
3>&1 1>&2 2>&3)
[ -z "$cat_choice" ] && return
@@ -465,10 +550,11 @@ install_extras_bullseye() {
4) _cat_players_bullseye ;;
5) _cat_design_bullseye ;;
6) _cat_programming_bullseye ;;
7) _cat_security_bullseye ;;
8) _cat_general_bullseye ;;
9) _cat_fetch_bullseye ;;
10) return ;;
7) _cat_dev_bullseye ;;
8) _cat_security_bullseye ;;
9) _cat_general_bullseye ;;
10) _cat_fetch_bullseye ;;
11) return ;;
esac
clear
done
+18 -16
View File
@@ -116,18 +116,18 @@ install_gaming_bullseye() {
local enable_32bit=false
if _confirm "32-bit Support" \
"Habilitar arquitectura i386 para juegos?\n\n\
Requieren los juegos nativos de 32 bits y ciertas\n\
bibliotecas de emulación."; then
"Enable i386 architecture for 32-bit games?\n\n\
Required by Steam/Proton for 32-bit games.\n\
Installs matching 32-bit graphics drivers."; then
enable_32bit=true
fi
if $enable_32bit; then
echo "Activando soporte multiarquitectura i386..."
echo "Enabling i386 multi-architecture support..."
if ! dpkg --print-foreign-architectures | grep -q i386; then
sudo dpkg --add-architecture i386
fi
_run_cmd "APT Update" "sudo apt update" "Actualizando listas..."
_run_cmd "APT Update" "sudo apt update" "Updating package lists..."
if [ "$GPU_TYPE" = "nvidia" ]; then
local nv32_pkg="nvidia-driver-libs:i386"
@@ -139,10 +139,10 @@ bibliotecas de emulación."; then
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}" \
"Instalando librerías NVIDIA 32-bit..."
"Installing NVIDIA 32-bit libraries..."
fi
else
echo "nvidia-driver-libs:i386 no disponible en Bullseye."
echo "nvidia-driver-libs:i386 not available on Bullseye."
fi
else
# Mesa 32-bit
@@ -158,20 +158,20 @@ bibliotecas de emulación."; then
awk 'NR==3 {print $2; exit}')
local comp_line="Components: Vulkan:i386, OpenGL:i386, GLX:i386, EGL:i386, VA-API:i386"
local msg="Mesa 32-bit drivers para gaming.\n\n"
local msg="Mesa 32-bit drivers for gaming.\n\n"
msg+="Source: Debian Bullseye Stable\n"
msg+="Mesa ${ref_ver}\n"
msg+="${comp_line}\n\n"
msg+="Instalar drivers 32-bit?"
msg+="Install 32-bit drivers?"
if _confirm "Mesa 32-bit" "$msg" 14 70; then
_run_cmd "Mesa 32-bit" "sudo apt install -y ${mesa_32[*]}" \
"Instalando Mesa 32-bit..."
"Installing Mesa 32-bit..."
fi
fi
fi
# Gaming tools checklist (sin Steam ni Heroic)
# Gaming tools checklist (no Steam, no Heroic)
local choices
choices=$(whiptail --title "Gaming Tools — Bullseye" --checklist \
"Select gaming optimization tools:" $TUI_ALTO $TUI_ANCHO $TUI_ALTO_LISTA \
@@ -179,6 +179,7 @@ bibliotecas de emulación."; then
"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)
if [ -z "$choices" ]; then
@@ -192,20 +193,21 @@ bibliotecas de emulación."; then
for pkg in $cleaned; do
case $pkg in
mangohud)
_run_cmd "MangoHud" "sudo apt install -y mangohud" "Instalando MangoHud..."
_run_cmd "MangoHud" "sudo apt install -y mangohud" "Installing MangoHud..."
if $enable_32bit; then
local mh32_ver
mh32_ver=$(apt-cache policy mangohud:i386 2>/dev/null | \
awk 'NR==3 {print $2; exit}')
if [ -n "$mh32_ver" ] && [ "$mh32_ver" != "(none)" ]; then
_run_cmd "MangoHud" "sudo apt install -y mangohud:i386" \
"Instalando MangoHud 32-bit..."
"Installing MangoHud 32-bit..."
fi
fi
;;
gamemode) _run_cmd "GameMode" "sudo apt install -y gamemode" "Instalando GameMode..." ;;
goverlay) _run_cmd "GOverlay" "sudo apt install -y goverlay" "Instalando GOverlay..." ;;
lutris) _run_cmd "Lutris" "sudo apt install -y lutris" "Instalando Lutris..." ;;
gamemode) _run_cmd "GameMode" "sudo apt install -y gamemode" "Installing GameMode..." ;;
goverlay) _run_cmd "GOverlay" "sudo apt install -y goverlay" "Installing GOverlay..." ;;
lutris) _run_cmd "Lutris" "sudo apt install -y lutris" "Installing Lutris..." ;;
java) _install_gaming_java ;;
*) _run_install "$pkg" ;;
esac
done
+12 -16
View File
@@ -5,19 +5,19 @@
configure_repos_bullseye() {
echo -e "${YELLOW}Repository configuration — Debian 11 Bullseye${NC}"
local info="Configuración de repositorios para Debian 11 Bullseye.\n\n"
info+="Se usarán los repositorios oficiales con componentes\n"
info+="main, contrib y non-free (sin non-free-firmware).\n"
info+="No se utiliza formato DEB822.\n"
local info="Repository configuration for Debian 11 Bullseye.\n\n"
info+="Official repositories will be used with components\n"
info+="main, contrib and non-free (non-free-firmware excluded).\n"
info+="DEB822 format is not used.\n"
if $BULLSEYE_USE_ARCHIVE; then
info+="\nModo Archive: Las URLs apuntarán a archive.debian.org\n"
info+="(Bullseye LTS finalizó el 31 Ago 2026)."
info+="\nArchive Mode: URLs will point to archive.debian.org\n"
info+="(Bullseye LTS ended on 31 Aug 2026)."
fi
_msg "Repositorios — Bullseye" "$info" 12 65
_msg "Repositories — Bullseye" "$info" 12 65
if [ -f /etc/apt/sources.list ]; then
if ! _confirm "Repositorios" "Ya existe /etc/apt/sources.list.\n\nSobrescribir con la configuración de Bullseye?"; then
echo "Manteniendo configuración actual."
if ! _confirm "Repositories" "/etc/apt/sources.list already exists.\n\nOverwrite with Bullseye configuration?"; then
echo "Keeping current configuration."
return 0
fi
fi
@@ -34,21 +34,17 @@ configure_repos_bullseye() {
content+="deb ${base_uri} bullseye main contrib non-free\n"
content+="#deb-src ${base_uri} bullseye main contrib non-free\n\n"
content+="# Updates\n"
content+="deb ${base_uri} bullseye-updates main contrib non-free\n"
content+="#deb-src ${base_uri} bullseye-updates main contrib non-free\n\n"
content+="# Security\n"
content+="deb ${security_uri} bullseye-security main contrib non-free\n"
content+="#deb-src ${security_uri} bullseye-security main contrib non-free\n"
echo -e "$content" | sudo tee /etc/apt/sources.list > /dev/null
echo "Actualizando listas de paquetes..."
echo "Updating package lists..."
if sudo apt update; then
echo -e "${GREEN}Repositorios de Debian 11 Bullseye configurados.${NC}"
echo -e "${GREEN}Debian 11 Bullseye repositories configured.${NC}"
else
echo -e "${RED}apt update falló. Revise su conexión de red.${NC}"
echo -e "${RED}apt update failed. Check your network connection.${NC}"
return 1
fi
}
+11 -9
View File
@@ -35,11 +35,12 @@ install_extras() {
"3" "Internet (Browsers, Email, VPN)" \
"4" "Media Players" \
"5" "Multimedia & Design" \
"6" "Programming Applications" \
"7" "Security & Networking" \
"8" "System Tools" \
"9" "Fetch / System Info" \
"10" "Back to main menu" \
"6" "Code Editors & IDEs" \
"7" "Servers & Dev Tools" \
"8" "Security & Networking" \
"9" "System Tools" \
"10" "Fetch / System Info" \
"11" "Back to main menu" \
3>&1 1>&2 2>&3)
[ -z "$cat_choice" ] && return
@@ -53,10 +54,11 @@ install_extras() {
4) _cat_players ;;
5) _cat_design ;;
6) _cat_programming ;;
7) _cat_security ;;
8) _cat_general ;;
9) _cat_fetch ;;
10) return ;;
7) _cat_dev ;;
8) _cat_security ;;
9) _cat_general ;;
10) _cat_fetch ;;
11) return ;;
esac
clear
done
+21
View File
@@ -8,3 +8,24 @@ _inst() {
_state() {
is_installed "$1" && echo "ON" || echo "OFF"
}
_install_clamav() {
if is_installed "clamav"; then
echo "ClamAV already installed."
return
fi
_run_install "clamav"
echo -e "${GREEN}ClamAV installed.${NC}"
if _confirm "ClamAV" "Update virus signatures now (freshclam)?"; then
sudo systemctl stop clamav-freshclam 2>/dev/null || true
sudo freshclam || true
sudo systemctl start clamav-freshclam 2>/dev/null || true
fi
if _confirm "ClamAV" "Run quick scan on /bin to verify engine works?"; then
echo "Running background scan on /bin..."
sudo clamscan --recursive --infected /bin &
echo "Scan running in background (PID $!). Check results later."
fi
}
+6
View File
@@ -17,6 +17,8 @@ _cat_dev() {
local pip_state; pip_state=$(_state "python3-pip")
local redis_state; redis_state=$(_state "redis-server")
local sqlite_state; sqlite_state=$(_state "sqlite3")
local jdk_desc; jdk_desc=$(_any_jdk_installed_desc)
local jdk_state; jdk_state=$(_any_jdk_state)
local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6))
local choices
@@ -35,6 +37,7 @@ _cat_dev() {
"python3-pip" "Python 3 pip + venv + dev$(_inst python3-pip)" "$pip_state" \
"redis-server" "Redis key-value store$(_inst redis-server)" "$redis_state" \
"sqlite3" "SQLite database engine$(_inst sqlite3)" "$sqlite_state" \
"openjdk-dev-env" "Adoptium Temurin JDK (17, 21, 25 LTS)${jdk_desc}" "${jdk_state}" \
3>&1 1>&2 2>&3)
clear
@@ -65,6 +68,9 @@ _cat_dev() {
echo "Docker already installed."
fi
;;
openjdk-dev-env)
_install_dev_java
;;
*)
if ! is_installed "$pkg"; then
_run_install "$pkg"
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# java.sh — Adoptium Temurin repository setup and Java version selectors
# License GPL v3
_ensure_adoptium_repo() {
[ -f /etc/apt/sources.list.d/adoptium.list ] && return 0
local deps=()
! is_installed "wget" && deps+=("wget")
! is_installed "apt-transport-https" && deps+=("apt-transport-https")
! is_installed "gpg" && deps+=("gpg")
[ ${#deps[@]} -gt 0 ] && _run_install_batch "${deps[@]}"
wget -qO - "https://packages.adoptium.net/artifactory/api/gpg/key/public" \
| sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/adoptium.gpg 2>/dev/null
local codename
codename=$(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release)
echo "deb https://packages.adoptium.net/artifactory/deb ${codename} main" \
| sudo tee /etc/apt/sources.list.d/adoptium.list > /dev/null
sudo apt update \
-o Dir::Etc::sourcelist=/etc/apt/sources.list.d/adoptium.list \
-o Dir::Etc::sourceparts="-" \
2>/dev/null || true
}
_install_gaming_java() {
local ver
ver=$(whiptail --title "Java Runtimes for Gaming" --menu \
"Select Java version:" 12 65 3 \
"8" "Java 8 — For classic mods & Minecraft <= 1.16.5" \
"17" "Java 17 — For Minecraft era 1.17 to 1.20.4" \
"21" "Java 21 — For modern Minecraft >= 1.20.5 & 1.21+" \
3>&1 1>&2 2>&3)
[ -z "$ver" ] && { echo "No Java version selected."; return; }
_ensure_adoptium_repo
_run_install "temurin-${ver}-jre"
}
_install_dev_java() {
local ver
ver=$(whiptail --title "Java Development Kits (JDK)" --menu \
"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)
[ -z "$ver" ] && { echo "No JDK version selected."; return; }
_ensure_adoptium_repo
_run_install "temurin-${ver}-jdk"
}
_any_jdk_installed_desc() {
local inst
inst=$(dpkg -l 'temurin-*-jdk' 2>/dev/null | awk '/^ii/ {print $2; exit}')
[ -n "$inst" ] && echo " ($inst installed)" || echo ""
}
_any_jdk_state() {
dpkg -l 'temurin-*-jdk' 2>/dev/null | grep -q '^ii' && echo "ON" || echo "OFF"
}
+6 -1
View File
@@ -9,16 +9,18 @@ _cat_security() {
local zenmap_state; zenmap_state=$(_state "zenmap")
local fail2ban_state; fail2ban_state=$(_state "fail2ban")
local ufw_state; ufw_state=$(_state "ufw")
local clamav_state; clamav_state=$(_state "clamav")
local TUI_ANCHO_REFORZADO=$((TUI_ANCHO + 6))
local choices
choices=$(whiptail --title "Security & Networking" --checklist \
"Select security and networking tools (5 items):" $TUI_ALTO $TUI_ANCHO_REFORZADO $TUI_ALTO_LISTA \
"Select security and networking tools (6 items):" $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
@@ -31,6 +33,9 @@ _cat_security() {
zenmap)
install_backports_or_stable zenmap
;;
clamav)
_install_clamav
;;
*)
if ! is_installed "$pkg"; then
_run_install "$pkg"
+2
View File
@@ -128,6 +128,7 @@ install_gaming() {
"gamemode" "Game performance optimization" ON \
"mangohud" "Performance overlay (Vulkan/OpenGL)" ON \
"heroic" "Heroic Launcher (Epic/GOG)" OFF \
"java-jre" "Java Runtimes (8, 17, 21)" OFF \
"goverlay" "MangoHud config GUI" ON \
"lutris" "Game launcher/manager" OFF \
3>&1 1>&2 2>&3)
@@ -157,6 +158,7 @@ install_gaming() {
fi
;;
heroic) install_heroic ;;
java) _install_gaming_java ;;
mangohud) install_mangohud ;;
gamemode) install_gamemode ;;
goverlay) install_goverlay ;;
+6
View File
@@ -134,6 +134,12 @@ install_mesa_stable() {
}
offer_generic_tools() {
if [ "$DEBIAN_VERSION" = "11" ]; then
if ! lsmod 2>/dev/null | grep -q "^nvidia "; then
echo "nvtop skipped on Bullseye — NVIDIA driver not loaded."
return
fi
fi
local tool_pkgs
tool_pkgs=$(pkg_versions nvtop vainfo)
if _confirm "GPU Tools" "Install monitoring and info tools?\n\n${tool_pkgs}"; then
+22 -3
View File
@@ -20,7 +20,11 @@ offer_amd_tools() {
fi
local pkgs
pkgs=$(pkg_versions "${amd_tools[@]}" nvtop vainfo)
if [ "$DEBIAN_VERSION" = "11" ]; then
pkgs=$(pkg_versions "${amd_tools[@]}" vainfo)
else
pkgs=$(pkg_versions "${amd_tools[@]}" nvtop vainfo)
fi
if $corectrl_available; then
local ctrl_ver
ctrl_ver=$(apt-cache policy corectrl 2>/dev/null | awk 'NR==3 {print $2; exit}')
@@ -32,7 +36,11 @@ offer_amd_tools() {
return
fi
_run_cmd "AMD Tools" "sudo apt install -y ${amd_tools[*]} nvtop vainfo" "Installing AMD tools..."
if [ "$DEBIAN_VERSION" = "11" ]; then
_run_cmd "AMD Tools" "sudo apt install -y ${amd_tools[*]} vainfo" "Installing AMD tools..."
else
_run_cmd "AMD Tools" "sudo apt install -y ${amd_tools[*]} nvtop vainfo" "Installing AMD tools..."
fi
vainfo
if $corectrl_available; then
@@ -73,7 +81,18 @@ offer_intel_tools() {
[ -d "/sys/bus/pci/drivers/xe" ] && has_xe=true
[ -d "/sys/bus/pci/drivers/i915" ] && has_i915=true
if $has_xe; then
if [ "$DEBIAN_VERSION" = "11" ]; then
if $has_xe; then
echo "Intel Xe GPU detected. No monitoring tools available on Bullseye."
return
elif $has_i915; then
driver_info="Classic Intel GPU detected (i915 driver)."
pkg_list=("intel-gpu-tools")
else
echo "Intel GPU driver not identified. No monitoring tools available on Bullseye."
return
fi
elif $has_xe; then
driver_info="Modern Intel GPU detected (Xe driver).\nintel-gpu-tools is NOT compatible with Xe.\nOnly nvtop will be offered."
pkg_list=("nvtop")
elif $has_i915; then
+312 -86
View File
@@ -5,9 +5,11 @@ REPO_BACKUP_DIR=""
backup_current_repos() {
REPO_BACKUP_DIR=$(mktemp -d)
for f in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources; do
for f in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources \
/etc/apt/sources.list.d/debian-backports.list /etc/apt/sources.list.d/debian-backports.sources; do
if [ -f "$f" ]; then
cp "$f" "$REPO_BACKUP_DIR/$(basename "$f")"
mkdir -p "$REPO_BACKUP_DIR/$(dirname "${f#/etc/apt/}")"
cp "$f" "$REPO_BACKUP_DIR/$(dirname "${f#/etc/apt/}")/$(basename "$f")"
fi
done
}
@@ -17,17 +19,22 @@ restore_previous_repos() {
return
fi
echo -e "${RED}Restoring previous repository configuration...${NC}"
if [ -f "$REPO_BACKUP_DIR/sources.list" ]; then
sudo cp "$REPO_BACKUP_DIR/sources.list" /etc/apt/sources.list
else
sudo rm -f /etc/apt/sources.list
local found=false
for f in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources \
/etc/apt/sources.list.d/debian-backports.list /etc/apt/sources.list.d/debian-backports.sources; do
local rel="${f#/etc/apt/}"
local backup_file="$REPO_BACKUP_DIR/$rel"
if [ -f "$backup_file" ]; then
sudo cp "$backup_file" "$f"
found=true
elif [ -f "$f" ]; then
sudo rm -f "$f"
found=true
fi
done
if $found; then
sudo rm -f /etc/apt/sources.list.disabled
fi
if [ -f "$REPO_BACKUP_DIR/debian.sources" ]; then
sudo cp "$REPO_BACKUP_DIR/debian.sources" /etc/apt/sources.list.d/debian.sources
else
sudo rm -f /etc/apt/sources.list.d/debian.sources
fi
sudo rm -f /etc/apt/sources.list.disabled
rm -rf "$REPO_BACKUP_DIR"
REPO_BACKUP_DIR=""
}
@@ -39,40 +46,312 @@ cleanup_repo_backup() {
fi
}
finalize_deb822() {
if [ -f /etc/apt/sources.list ]; then
sudo mv /etc/apt/sources.list /etc/apt/sources.list.disabled
echo "Classic sources.list disabled (renamed to sources.list.disabled)"
# ---------------------------------------------------------------------------
# Cleanup helpers for embedded backports
# ---------------------------------------------------------------------------
_clean_embedded_backports_classic() {
local codename="$1"
local file="/etc/apt/sources.list"
[ ! -f "$file" ] && return
grep -qE "^[^#]*${codename}-backports\b" "$file" 2>/dev/null || return
if _confirm "Clean Classic Sources" "Remove backports line from ${file}?"; then
sudo sed -i "/${codename}-backports/d" "$file"
echo "Removed backports from ${file}"
fi
cleanup_repo_backup
}
configure_repos() {
echo -e "${YELLOW}Repository configuration...${NC}"
_clean_embedded_backports_deb822() {
local codename="$1"
local file="/etc/apt/sources.list.d/debian.sources"
[ ! -f "$file" ] && return
local use_deb822=false
if [ "$DEBIAN_CODENAME" = "trixie" ]; then
if whiptail --title "Repository Format" --defaultno --yesno "Use deb822 format (modern .sources)?" 8 60; then
use_deb822=true
# Only proceed if the Suites line contains the backports token
grep -qE "^Suites:.*${codename}-backports\b" "$file" 2>/dev/null || return
if _confirm "Clean deb822 Sources" "Remove backports suite from ${file}?"; then
# Remove only the backports token, leaving other suites intact
sudo sed -i "s/[[:space:]]*${codename}-backports[[:space:]]*/ /g" "$file"
# Clean up whitespace on Suites lines
sudo sed -i '/^Suites:[[:space:]]*$/d' "$file" 2>/dev/null || true
echo "Removed backports suite from ${file}"
fi
}
# ---------------------------------------------------------------------------
# Write functions idempotent, with _confirm dialogs
# ---------------------------------------------------------------------------
_write_deb822() {
local codename="$1" action="$2" bp_enabled="$3" bp_location="$4"
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+="\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"
if content_differs "$main_file" "$main_content"; then
if _confirm "Deb822 Sources" "Write main deb822 configuration to ${main_file}?"; then
sudo mkdir -p /etc/apt/sources.list.d
echo -e "$main_content" | sudo tee "$main_file" > /dev/null
echo "Wrote ${main_file}"
else
echo "Main repository configuration skipped."
return 1
fi
fi
local enable_backports=false
if _confirm "Backports" "Enable backports repository?\n\nProvides newer kernel, drivers, Mesa."; then
enable_backports=true
# Backports: always in separate file
if [ "$bp_enabled" = true ]; then
_write_deb822_backports "$codename"
else
_remove_deb822_backports "$codename"
fi
# On migration from classic, disable the old file
if [ "$action" = "migrate" ] && [ "$bp_location" = "embedded-classic" -o "$bp_location" = "standalone-classic" ]; then
if [ -f /etc/apt/sources.list ]; then
if _confirm "Disable Classic" "Migrating to deb822. Disable /etc/apt/sources.list?"; then
sudo mv /etc/apt/sources.list /etc/apt/sources.list.disabled
echo "Classic sources.list disabled (renamed to sources.list.disabled)"
fi
fi
fi
# Clean embedded backports from old classic file if they existed there
if [ "$bp_location" = "embedded-classic" ]; then
_clean_embedded_backports_classic "$codename"
fi
}
_write_deb822_backports() {
local codename="$1"
local bp_file="/etc/apt/sources.list.d/debian-backports.sources"
local bp_content=""
bp_content+="Types: deb\n"
bp_content+="URIs: https://deb.debian.org/debian\n"
bp_content+="Suites: ${codename}-backports\n"
bp_content+="Components: main contrib non-free non-free-firmware\n"
if content_differs "$bp_file" "$bp_content"; then
if _confirm "Deb822 Backports" "Write backports to ${bp_file}?"; then
sudo mkdir -p /etc/apt/sources.list.d
echo -e "$bp_content" | sudo tee "$bp_file" > /dev/null
echo "Wrote ${bp_file}"
fi
fi
# If backports were formerly embedded in debian.sources, clean them
grep -qE "^Suites:.*${codename}-backports\b" /etc/apt/sources.list.d/debian.sources 2>/dev/null && \
_clean_embedded_backports_deb822 "$codename"
}
_remove_deb822_backports() {
local codename="$1"
local bp_file="/etc/apt/sources.list.d/debian-backports.sources"
if [ -f "$bp_file" ]; then
if _confirm "Remove Backports" "Remove ${bp_file}?"; then
sudo rm -f "$bp_file"
echo "Removed ${bp_file}"
fi
fi
# Also clean any embedded backports in main debian.sources
grep -qE "^Suites:.*${codename}-backports\b" /etc/apt/sources.list.d/debian.sources 2>/dev/null && \
_clean_embedded_backports_deb822 "$codename"
# Clean embedded backports from classic file too (safety net)
_clean_embedded_backports_classic "$codename"
}
_write_classic() {
local codename="$1" action="$2" bp_enabled="$3" bp_location="$4"
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+="\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+="\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"
if content_differs "$main_file" "$main_content"; then
if _confirm "Classic Sources" "Write main classic configuration to ${main_file}?"; then
echo -e "$main_content" | sudo tee "$main_file" > /dev/null
echo "Wrote ${main_file}"
else
echo "Main repository configuration skipped."
return 1
fi
fi
# Backports: always in separate file
if [ "$bp_enabled" = true ]; then
_write_classic_backports "$codename"
else
_remove_classic_backports "$codename"
fi
# On migration from deb822, disable the old file
if [ "$action" = "migrate" ]; then
if [ -f /etc/apt/sources.list.d/debian.sources ]; then
if _confirm "Disable Deb822" "Migrating to classic format. Disable /etc/apt/sources.list.d/debian.sources?"; then
sudo mv /etc/apt/sources.list.d/debian.sources /etc/apt/sources.list.d/debian.sources.disabled
echo "Deb822 sources disabled (renamed to debian.sources.disabled)"
fi
fi
fi
# Clean embedded backports from old deb822 file if they existed there
if [ "$bp_location" = "embedded-deb822" ]; then
_clean_embedded_backports_deb822 "$codename"
fi
}
_write_classic_backports() {
local codename="$1"
local bp_file="/etc/apt/sources.list.d/debian-backports.list"
local bp_content=""
bp_content+="# Backports\n"
bp_content+="deb https://deb.debian.org/debian ${codename}-backports main contrib non-free non-free-firmware\n"
if content_differs "$bp_file" "$bp_content"; then
if _confirm "Classic Backports" "Write backports to ${bp_file}?"; then
sudo mkdir -p /etc/apt/sources.list.d
echo -e "$bp_content" | sudo tee "$bp_file" > /dev/null
echo "Wrote ${bp_file}"
fi
fi
# If backports were formerly embedded in sources.list, clean them
grep -qE "^[^#]*${codename}-backports\b" /etc/apt/sources.list 2>/dev/null && \
_clean_embedded_backports_classic "$codename"
}
_remove_classic_backports() {
local codename="$1"
local bp_file="/etc/apt/sources.list.d/debian-backports.list"
if [ -f "$bp_file" ]; then
if _confirm "Remove Backports" "Remove ${bp_file}?"; then
sudo rm -f "$bp_file"
echo "Removed ${bp_file}"
fi
fi
# Also clean any embedded backports in main sources.list
grep -qE "^[^#]*${codename}-backports\b" /etc/apt/sources.list 2>/dev/null && \
_clean_embedded_backports_classic "$codename"
# Clean embedded backports from deb822 file too (safety net)
_clean_embedded_backports_deb822 "$codename"
}
# ---------------------------------------------------------------------------
# Main entry point
# ---------------------------------------------------------------------------
configure_repos() {
echo -e "${YELLOW}Repository configuration...${NC}"
if [ -z "$DEBIAN_CODENAME" ]; then
echo -e "${RED}Error: Could not detect Debian codename. Aborting.${NC}"
return 1
fi
# Detect current state
local current_format
current_format=$(detect_repo_format)
local bp_status
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)"
# Choose format (only Trixie gets the choice)
local use_deb822=false
if [ "$DEBIAN_CODENAME" = "trixie" ]; then
local default_text="no"
[ "$current_format" = "deb822" ] && default_text="yes"
if whiptail --title "Repository Format" --defaultno --yesno "Use deb822 format (modern .sources)?" 8 60; then
use_deb822=true
fi
elif [ "$current_format" = "deb822" ]; then
use_deb822=true
fi
# Choose backports
local enable_backports=false
if _confirm "Backports" "Enable backports repository?\n\nProvides newer kernel, drivers, Mesa."; 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
fi
backup_current_repos
if $use_deb822; then
generate_deb822_sources "$DEBIAN_CODENAME" "$enable_backports"
_write_deb822 "$DEBIAN_CODENAME" "$action" "$enable_backports" "$bp_location"
else
generate_classic_sources "$DEBIAN_CODENAME" "$enable_backports"
_write_classic "$DEBIAN_CODENAME" "$action" "$enable_backports" "$bp_location"
fi
echo "Updating package lists..."
@@ -83,11 +362,14 @@ configure_repos() {
echo -e "${GREEN}Repositories configured and updated successfully.${NC}"
if $use_deb822; then
finalize_deb822
# Remove any leftover disabled files from old classic format
[ -f /etc/apt/sources.list.disabled ] && sudo rm -f /etc/apt/sources.list.disabled
else
cleanup_repo_backup
[ -f /etc/apt/sources.list.d/debian.sources.disabled ] && sudo rm -f /etc/apt/sources.list.d/debian.sources.disabled
fi
cleanup_repo_backup
local upgradable
upgradable=$(apt list --upgradable 2>/dev/null | grep -c /)
if [ "$upgradable" -gt 0 ]; then
@@ -108,59 +390,3 @@ configure_repos() {
return 1
fi
}
generate_classic_sources() {
local codename="$1"
local backports="$2"
local content=""
content="# Official repository\n"
content+="deb https://deb.debian.org/debian ${codename} main contrib non-free non-free-firmware\n"
content+="# deb-src https://deb.debian.org/debian ${codename} main contrib non-free non-free-firmware\n\n"
content+="# Updates\n"
content+="deb https://deb.debian.org/debian ${codename}-updates main contrib non-free non-free-firmware\n"
content+="# deb-src https://deb.debian.org/debian ${codename}-updates main contrib non-free non-free-firmware\n\n"
content+="# Security\n"
content+="deb https://security.debian.org/debian-security ${codename}-security main contrib non-free non-free-firmware\n"
content+="# deb-src https://security.debian.org/debian-security ${codename}-security main contrib non-free non-free-firmware\n\n"
if $backports; then
content+="# Backports (active)\n"
content+="deb https://deb.debian.org/debian ${codename}-backports main contrib non-free non-free-firmware\n"
content+="# deb-src https://deb.debian.org/debian ${codename}-backports main contrib non-free non-free-firmware\n"
else
content+="# Backports (not enabled)\n"
content+="# deb https://deb.debian.org/debian ${codename}-backports main contrib non-free non-free-firmware\n"
fi
echo -e "$content" | sudo tee /etc/apt/sources.list > /dev/null
}
generate_deb822_sources() {
local codename="$1"
local backports="$2"
sudo mkdir -p /etc/apt/sources.list.d
local content=""
content="Types: deb\n"
content+="URIs: https://deb.debian.org/debian\n"
content+="Suites: ${codename} ${codename}-updates\n"
content+="Components: main contrib non-free non-free-firmware\n\n"
content+="Types: deb\n"
content+="URIs: https://security.debian.org/debian-security\n"
content+="Suites: ${codename}-security\n"
content+="Components: main contrib non-free non-free-firmware\n\n"
if $backports; then
content+="Types: deb\n"
content+="URIs: https://deb.debian.org/debian\n"
content+="Suites: ${codename}-backports\n"
content+="Components: main contrib non-free non-free-firmware\n"
fi
echo -e "$content" | sudo tee /etc/apt/sources.list.d/debian.sources > /dev/null
}
+81
View File
@@ -0,0 +1,81 @@
# shellcheck disable=SC2148
# repo_detect.sh Detection-only helpers for idempotent repository configuration.
# Part A of the two-part architecture. No user dialogs, no writes.
# Detect the format of the main repo file
# Returns: "deb822", "classic", or "none"
detect_repo_format() {
if [ -f /etc/apt/sources.list.d/debian.sources ]; then
echo "deb822"
elif [ -f /etc/apt/sources.list ]; then
echo "classic"
else
echo "none"
fi
}
# Check whether backports are currently enabled (any format)
# Returns: 0 if enabled, 1 otherwise
detect_backports_status() {
local codename="$1"
if [ -f /etc/apt/sources.list.d/debian.sources ]; then
grep -qE "^Suites:.*${codename}-backports" /etc/apt/sources.list.d/debian.sources 2>/dev/null && return 0
fi
if [ -f /etc/apt/sources.list ]; then
grep -qE "^[^#]*${codename}-backports" /etc/apt/sources.list 2>/dev/null && return 0
fi
if [ -f /etc/apt/sources.list.d/debian-backports.sources ]; then
grep -qE "^Suites:.*${codename}-backports" /etc/apt/sources.list.d/debian-backports.sources 2>/dev/null && return 0
fi
if [ -f /etc/apt/sources.list.d/debian-backports.list ]; then
grep -qE "^[^#]*${codename}-backports" /etc/apt/sources.list.d/debian-backports.list 2>/dev/null && return 0
fi
return 1
}
# Locate where backports are configured
# Returns: "standalone-deb822" (debian-backports.sources),
# "standalone-classic" (debian-backports.list),
# "embedded-deb822" (inside debian.sources),
# "embedded-classic" (inside sources.list),
# "none"
detect_backports_location() {
local codename="$1"
if [ -f /etc/apt/sources.list.d/debian-backports.sources ] && \
grep -qE "^Suites:.*${codename}-backports" /etc/apt/sources.list.d/debian-backports.sources 2>/dev/null; then
echo "standalone-deb822"
elif [ -f /etc/apt/sources.list.d/debian-backports.list ] && \
grep -qE "^[^#]*${codename}-backports" /etc/apt/sources.list.d/debian-backports.list 2>/dev/null; then
echo "standalone-classic"
elif [ -f /etc/apt/sources.list.d/debian.sources ] && \
grep -qE "^Suites:.*${codename}-backports" /etc/apt/sources.list.d/debian.sources 2>/dev/null; then
echo "embedded-deb822"
elif [ -f /etc/apt/sources.list ] && \
grep -qE "^[^#]*${codename}-backports" /etc/apt/sources.list 2>/dev/null; then
echo "embedded-classic"
else
echo "none"
fi
}
# Compare generated content vs existing file (idempotency check)
# Returns: 0 if content differs, 1 if identical
content_differs() {
local file="$1"
local content="$2"
if [ ! -f "$file" ]; then
return 0
fi
local current
current=$(cat "$file")
local generated
generated=$(echo -e "$content")
if [ "$current" = "$generated" ]; then
return 1
fi
return 0
}
+143 -14
View File
@@ -1,30 +1,159 @@
#!/usr/bin/env bash
# Adds user to sudo group and optionally enables pwfeedback
# sudo_config.sh — User Privileges & Feedback submenu
# License GPL v3
config_sudo() {
echo -e "${YELLOW}Configuring sudo...${NC}"
echo -e "${YELLOW}User Privileges & Feedback${NC}"
while true; do
local choice
choice=$(whiptail --title "User Privileges & Feedback" --menu \
"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)
[ -z "$choice" ] && return
clear
case "$choice" in
1) _check_sudo_group ;;
2) _configure_nopasswd ;;
3) _repair_home_ownership ;;
4) _toggle_pwfeedback ;;
5) return ;;
esac
done
}
# ── Option 1: Sudo Group Membership ──
_check_sudo_group() {
if groups "$USER" | grep -qE '\bsudo\b'; then
echo "User is already in the sudo group."
_msg "Sudo Group" "User '$USER' is already in the sudo group."
else
echo "Adding user '$USER' to sudo group..."
if sudo usermod -aG sudo "$USER"; then
echo -e "${GREEN}Done. Note: you need to log out and back in for group changes to take effect.${NC}"
if _confirm "Sudo Group" \
"User '$USER' is NOT in the sudo group.\n\nAdd to sudo group?"; then
if sudo usermod -aG sudo "$USER"; then
_msg "Sudo Group" \
"User added to sudo group.\n\nLog out and back in for\ngroup changes to take effect." 10 60
else
_msg "Sudo Group" "Failed to add user to sudo group." 7 60
return 1
fi
fi
fi
}
# ── Option 2: Passwordless Sudo (NOPASSWD) ──
_configure_nopasswd() {
local nopasswd_file="/etc/sudoers.d/${USER}-nopasswd"
if [ -f "$nopasswd_file" ]; then
if _confirm "NOPASSWD" \
"Passwordless sudo is already configured.\n\nRemove it to restore password prompts?"; then
sudo rm -f "$nopasswd_file"
echo -e "${GREEN}Passwordless sudo removed.${NC}"
fi
return
fi
if _confirm "NOPASSWD" \
"Configure passwordless sudo for maintenance commands?\n\n\
- apt / apt-get (package management)\n\
- systemctl (service management)\n\
- shutdown / reboot / halt (power commands)\n\n\
Useful for automation but reduces security." 14 70; then
local choices
choices=$(whiptail --title "NOPASSWD Commands" --checklist \
"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)
clear
[ -z "$choices" ] && { echo "No commands selected."; return; }
local cleaned; cleaned=$(echo "$choices" | tr -d '"')
local content=""
for cmd in $cleaned; do
case $cmd in
apt)
content+="${USER} ALL=(root) NOPASSWD: /usr/bin/apt, /usr/bin/apt-get, /bin/apt, /bin/apt-get\n"
;;
systemctl)
content+="${USER} ALL=(root) NOPASSWD: /usr/bin/systemctl, /bin/systemctl\n"
;;
power)
content+="${USER} ALL=(root) NOPASSWD: /usr/sbin/shutdown, /sbin/shutdown, /usr/sbin/reboot, /sbin/reboot, /usr/sbin/halt, /sbin/halt\n"
;;
esac
done
echo -e "$content" | sudo tee "$nopasswd_file" > /dev/null
sudo chmod 0440 "$nopasswd_file"
if [ -f "$nopasswd_file" ]; then
echo -e "${GREEN}Passwordless sudo configured for selected commands.${NC}"
else
echo -e "${RED}Failed to add user to sudo group.${NC}"
echo -e "${RED}Failed to configure passwordless sudo.${NC}"
return 1
fi
fi
}
if _confirm "Sudo Password Feedback" "Show asterisks when typing the sudo password?"; then
echo 'Defaults pwfeedback' | sudo tee /etc/sudoers.d/pwfeedback > /dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}Password feedback enabled.${NC}"
else
echo -e "${RED}Failed to create /etc/sudoers.d/pwfeedback.${NC}"
# ── Option 3: Repair Home Directory Ownership ──
_repair_home_ownership() {
local home
home=$(eval echo "~$USER")
if [ ! -d "$home" ]; then
_msg "Home Directory" "Home directory '$home' does not exist." 8 60
return 1
fi
local uid uid_owner
uid=$(id -u "$USER" 2>/dev/null)
uid_owner=$(stat -c '%u' "$home" 2>/dev/null || echo "0")
if [ "$uid_owner" != "$uid" ]; then
local expected_user
expected_user=$(id -nu "$uid_owner" 2>/dev/null || echo "UID $uid_owner")
if _confirm "Home Permissions" \
"Home directory '$home' is owned by\n'$expected_user' (expected: '$USER').\n\nRepair ownership?" 12 65; then
if sudo chown -R "$USER:$USER" "$home"; then
echo -e "${GREEN}Home directory ownership repaired.${NC}"
else
echo -e "${RED}Failed to repair home directory ownership.${NC}"
return 1
fi
fi
else
echo "Skipping password feedback setting."
_msg "Home Permissions" "Home directory ownership is correct\n(owner: $USER)." 8 60
fi
}
# ── Option 4: Sudo Password Feedback (pwfeedback) ──
_toggle_pwfeedback() {
local fb_file="/etc/sudoers.d/pwfeedback"
if [ -f "$fb_file" ]; then
if _confirm "Password Feedback" \
"Asterisks are currently ENABLED when typing sudo password.\n\nDisable them?"; then
sudo rm -f "$fb_file"
echo -e "${GREEN}Password feedback disabled.${NC}"
fi
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
echo -e "${GREEN}Password feedback enabled.${NC}"
else
echo -e "${RED}Failed to create $fb_file${NC}"
return 1
fi
fi
fi
}