Files
debianito-post-install/modules/repos.sh
T
stornic56 54257d5a8a Security hardening & DRY refactoring
- Fixed command injection in desktop_display.sh by converting word-splitting loops to safe array-based iteration for LightDM/GDM3 configuration and XFCE package installation.
- Added symlink detection guard before repository file operations in repos.sh to prevent TOCTOU attacks during restore_previous_repos().
- Hardened SUDO_USER resolution with awk validation against /etc/passwd to prevent root fallback and ensure real login users are targeted for sudoers configuration.
- Implemented algorithm (lz4/zstd) and size validation before ZRAM configuration writes in zram.sh to reject invalid inputs.
- Protected grep MemTotal read from /proc/meminfo with 2>/dev/null and default assignment under set -u.
- Added || true guards around apt-cache madison pipelines in firmware.sh, kernel.sh, gpu.sh, and utils.sh to prevent pipefail aborts when backports unavailable.
- Wrapped whiptail installation in if/else blocks to allow offline error messages instead of script termination under set -e.
- Fixed grep -c output duplication in swap.sh with proper || true pattern and default variable assignment.
- Replaced unquoted $cleaned loops with array conversion using while read for secure package iteration across gaming, desktop_display, firmware, and kernel modules.
- Anchored sed regex patterns to space-delimited "main" components to prevent mirror URL corruption in sources.list editing.
- Escaped % characters in _msg() function before passing to whiptail to prevent printf format interpretation crashes.
- Consolidated package version helpers into canonical wrappers: _get_pkg_version, _get_installed_version, _get_backports_version for consistent apt/dpkg queries.
- Created _install_if_missing() and _install_pkg() with proper error handling that respects set -e while providing user feedback on installation failures.
- Removed 6 dead code functions (~51 lines): check_system_time, sync_system_time, get_cpu_summary, get_ram_summary, pkg_versions, get_backports_kernel_version.
- Added detect_displayserver and detect_audio_server to refresh_system_state() for complete state refresh when returning from menus.
- Enhanced _on_interrupt() trap handler to kill lingering apt/dpkg child processes and clean /tmp/debianito.* temporary files on Ctrl+C or TERM.
- Improved restore_previous_repos() with manifest-based backup verification (.backed_up_* markers) to prevent destructive repository file deletion.
- Added mktemp usage for secure temporary deb file downloads in nvidia.sh, heroic.sh, and tools.sh to eliminate TOCTOU vulnerabilities in /tmp.
- Fixed Bluetooth USB dongle misclassification as WiFi devices by excluding "bluetooth" strings from USB_WIFI_DEVS detection in firmware.sh.
- Properly utilized the need array for selective package installation in internet.sh instead of hardcoding full package list.
- Corrected fwupdmgr duplicate execution and grep false positives in system.sh with strict pattern matching for available updates.
- update docs and added quickstart guide
2026-09-14 20:31:48 -05:00

654 lines
23 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
source "${MODULES_DIR}/repos/migrate.sh" 2>/dev/null || true
# State for backup/restore
REPO_BACKUP_DIR=""
backup_current_repos() {
cleanup_repo_backup # never orphan a previous backup by overwriting the pointer
REPO_BACKUP_DIR=$(mktemp -d) || {
REPO_BACKUP_DIR=""
return 1
}
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
local rel="${f#/etc/apt/}"
mkdir -p "$REPO_BACKUP_DIR/$(dirname "$rel")" || return 1
cp "$f" "$REPO_BACKUP_DIR/$rel" || return 1
touch "$REPO_BACKUP_DIR/.backed_up_$(basename "$rel")"
fi
done
}
restore_previous_repos() {
if [ -z "$REPO_BACKUP_DIR" ] || [ ! -d "$REPO_BACKUP_DIR" ]; then
return
fi
echo -e "${RED}Restoring previous repository configuration...${NC}"
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
if sudo cp "$backup_file" "$f"; then
found=true
else
echo -e "${RED}Failed to restore $f${NC}"
fi
elif [ -f "$f" ] && [ ! -f "$REPO_BACKUP_DIR/.backed_up_$(basename "$f")" ]; then
# Only delete a live file if the manifest proves it did not exist
# when the backup was taken (protects against a failed cp).
# SECURITY: Verify file is not a symlink to prevent TOCTOU attack.
if [ -L "$f" ]; then
echo -e "${RED}[$f] is a symlink. Aborting to prevent TOCTOU attack.${NC}" >&2
continue
fi
sudo rm -f "$f" || true
found=true
fi
done
if $found; then
sudo rm -f /etc/apt/sources.list.disabled
fi
rm -rf "$REPO_BACKUP_DIR"
REPO_BACKUP_DIR=""
}
cleanup_repo_backup() {
if [ -n "$REPO_BACKUP_DIR" ] && [ -d "$REPO_BACKUP_DIR" ]; then
rm -rf "$REPO_BACKUP_DIR"
REPO_BACKUP_DIR=""
fi
}
# ---------------------------------------------------------------------------
# Cleanup helpers for embedded backports
# ---------------------------------------------------------------------------
_clean_embedded_backports_classic() {
local codename="$1"
local file="/etc/apt/sources.list"
[ ! -f "$file" ] && return 0
grep -qE "^[^#]*${codename}-backports\b" "$file" 2>/dev/null || return 0
if _confirm "Clean Classic Sources" "Remove backports line from ${file}?"; then
sudo sed -i "/${codename}-backports/d" "$file"
echo "Removed backports from ${file}"
fi
}
_clean_embedded_backports_deb822() {
local codename="$1"
local file="/etc/apt/sources.list.d/debian.sources"
[ ! -f "$file" ] && return 0
# Only proceed if the Suites line contains the backports token
grep -qE "^Suites:.*${codename}-backports\b" "$file" 2>/dev/null || return 0
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 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: ${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: ${components}\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 || return 1
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_deb822_backports "$codename" || true
else
_remove_deb822_backports "$codename" || true
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}"
else
return 1
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" || true
}
_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}"
else
return 1
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 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} ${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 ${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 ${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
echo -e "$main_content" | sudo tee "$main_file" >/dev/null || return 1
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" || true
else
_remove_classic_backports "$codename" || true
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}"
else
return 1
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" || true
}
_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}"
else
return 1
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
# ── Repositories submenu ──
while true; do
local repo_choice
if [ "$DEBIAN_CODENAME" = "sid" ]; then
repo_choice=$(_menu "Configure 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 "Configure 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
for c in $(grep "^Components:" /etc/apt/sources.list.d/debian.sources 2>/dev/null | cut -d: -f2-); do
[ "$c" = "contrib" ] || [ "$c" = "non-free" ] && return 0
done
fi
if [ -f /etc/apt/sources.list ]; then
local components
components=$(grep "^[^#]*deb .* main" /etc/apt/sources.list 2>/dev/null | head -1 | sed 's/.*main\s*//')
for c in $components; do
[ "$c" = "contrib" ] || [ "$c" = "non-free" ] && return 0
done
fi
return 1
}
_repos_offer_upgrade() {
local upgradable
upgradable=$(apt list --upgradable 2>/dev/null | grep -c / || true)
# BH-005: grep -c / returns rc=1 if apt list produces no output
# (0 upgradable packages or network failure). pipefail propagates rc=1.
upgradable=${upgradable:-0}
[[ "$upgradable" =~ ^[0-9]+$ ]] || upgradable=0
# Validate that the result is a positive integer.
# If apt list fails, upgradable stays as "0" and the upgrade is skipped.
if [ "$upgradable" -gt 0 ]; then
if _confirm "Upgrade System" "$upgradable packages can be upgraded. Upgrade now?"; then
_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
}
# Bootstrap a complete repository configuration from scratch when no active
# sources exist. Caller must run backup_current_repos() first so that a failed
# apt update can restore the previous state.
# Returns: 0 on success, 1 if skipped, declined or failed
bootstrap_repositories() {
local components="$1"
local bp_enabled="${2:-false}"
local bp_location="${3:-none}"
if [ -z "$DEBIAN_CODENAME" ]; then
_msg "Error" "Cannot bootstrap repositories: Debian codename unknown." 10 65
return 1
fi
# non-free-firmware does not exist on Bullseye
if [ "$DEBIAN_VERSION" = "11" ]; then
components=$(echo "$components" | sed 's/ non-free-firmware//g')
fi
if ! _confirm "Bootstrap Repositories" \
"No active APT sources were found (empty or missing sources.list).\n\n\
Configure repositories from scratch?" 10 65; then
echo "Repository configuration skipped."
cleanup_repo_backup
return 1
fi
if has_active_deb_sources; then
if ! _confirm "Custom Sources Found" \
"Active sources exist in other files (e.g. sources.list.d/*.sources).\n\n\
Adding deb.debian.org may duplicate your current mirror configuration. Continue?" 10 65; then
cleanup_repo_backup
return 1
fi
fi
# DEB822 is Trixie-only; Debian 11/12 always use classic
local use_deb822=false
if [ "$DEBIAN_VERSION" = "13" ]; then
local choice
choice=$(_menu "Repo Format" "Choose the repository format:" 12 60 3 \
"deb822" "Native DEB822 format (sources.list.d/debian.sources)" \
"classic" "Classic format (/etc/apt/sources.list)")
if [ "$choice" = "deb822" ]; then
use_deb822=true
fi
fi
if $use_deb822; then
_write_deb822 "$DEBIAN_CODENAME" "write" "$bp_enabled" "$bp_location" "$components" || {
cleanup_repo_backup
return 1
}
else
_write_classic "$DEBIAN_CODENAME" "write" "$bp_enabled" "$bp_location" "$components" || {
cleanup_repo_backup
return 1
}
fi
# Tidy: with deb822 chosen, an empty classic file is no longer needed
if $use_deb822 && [ -f /etc/apt/sources.list ] && ! grep -qE '^[^#]*\bdeb\b' /etc/apt/sources.list 2>/dev/null; then
if _confirm "Disable Classic" "An empty /etc/apt/sources.list is no longer needed. Move it aside (sources.list.disabled)?"; then
sudo mv /etc/apt/sources.list /etc/apt/sources.list.disabled
echo "Empty sources.list renamed to sources.list.disabled"
fi
fi
echo "Updating package lists..."
if sudo apt update; then
cleanup_repo_backup
echo -e "${GREEN}Repository components configured.${NC}"
return 0
else
restore_previous_repos
echo -e "${RED}apt update failed. Previous configuration restored.${NC}"
return 1
fi
}
_repos_enable_components() {
local current_format bp_enabled bp_location components
current_format=$(detect_repo_format)
if _components_enabled; then
if _confirm "Disable Components" \
"Contrib and non-free are already enabled. Disable them?"; then
components="main"
else
components=$(detect_active_components)
echo "Keeping current components: $components"
fi
else
if ! _confirm "Enable Components" \
"Enable contrib and non-free components?\n\n\
Needed for proprietary drivers, firmware, and other
popular software (like gaming platforms and proprietary tools)." 12 60; then
echo "No changes made."
_pause
return
fi
if [ "$DEBIAN_VERSION" = "11" ]; then
components="main contrib non-free"
else
components="main contrib non-free non-free-firmware"
fi
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" = "none" ]; then
if ! bootstrap_repositories "$components" "$bp_enabled" "$bp_location"; then
_pause
return
fi
_repos_offer_upgrade
echo -e "${GREEN}Cleaning old packages...${NC}"
sudo apt autoremove -y
sudo apt autoclean
echo -e "${GREEN}System packages cleaned.${NC}"
_pause
return
fi
echo "Verifying repository configuration (main, updates, security)..."
if [ "$current_format" = "deb822" ]; then
# Mixed-state guard: active classic lines alongside deb822 would duplicate sources
if [ -f /etc/apt/sources.list ] && grep -qE '^[^#]*\bdeb\b' /etc/apt/sources.list 2>/dev/null; then
if ! _confirm "Duplicate Config" \
"Active classic sources were also found in /etc/apt/sources.list.\n\n\
Writing debian.sources may duplicate your configuration. Continue?" 10 65; then
echo "No changes made."
_pause
return
fi
fi
if ! _write_deb822 "$DEBIAN_CODENAME" "write" "$bp_enabled" "$bp_location" "$components"; then
echo "No changes made."
_pause
return
fi
else
if ! _write_classic "$DEBIAN_CODENAME" "write" "$bp_enabled" "$bp_location" "$components"; then
echo "No changes made."
_pause
return
fi
fi
echo "Updating package lists..."
if sudo apt update; then
cleanup_repo_backup
echo -e "${GREEN}Repository components configured.${NC}"
_repos_offer_upgrade
echo -e "${GREEN}Cleaning old packages...${NC}"
sudo apt autoremove -y
sudo apt autoclean
echo -e "${GREEN}System packages cleaned.${NC}"
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
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
bp_location=$(detect_backports_location "$DEBIAN_CODENAME")
echo "Backports are currently $bp_status."
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 next Debian testing branch, recompiled to run stably on your current system.\n
Answer NO to disable or remove backports if they are currently enabled." 16 70; then
enable_backports=true
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
local write_ok=true
if $enable_backports; then
if [ "$current_format" = "deb822" ]; then
_write_deb822_backports "$DEBIAN_CODENAME" || write_ok=false
else
_write_classic_backports "$DEBIAN_CODENAME" || write_ok=false
fi
elif [ "$current_format" = "deb822" ]; then
_remove_deb822_backports "$DEBIAN_CODENAME" || write_ok=false
else
_remove_classic_backports "$DEBIAN_CODENAME" || write_ok=false
fi
if ! $write_ok; then
echo "No changes made."
_pause
return
fi
echo "Updating package lists..."
if sudo apt update; then
cleanup_repo_backup
echo -e "${GREEN}Backports configured.${NC}"
else
restore_previous_repos
echo -e "${RED}apt update failed. Backup restored.${NC}"
fi
_pause
}