256 lines
7.0 KiB
Bash
256 lines
7.0 KiB
Bash
#!/bin/bash
|
|
# =============================================
|
|
# Debian Distribution Upgrade Script
|
|
# Upgrades Debian to the next stable release
|
|
# =============================================
|
|
# Configuration
|
|
LOG_FILE="/var/log/debian_upgrade.log"
|
|
BACKUP_DIR="/root/debian_upgrade_backup_$(date +%Y%m%d_%H%M%S)"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[1;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Function to log messages
|
|
log() {
|
|
echo -e "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Function to ask for confirmation
|
|
ask_confirmation() {
|
|
local message="$1"
|
|
local default="$2" # "y" or "n"
|
|
while true; do
|
|
if [ "$default" = "y" ]; then
|
|
read -p "$message [Y/n]: " choice < /dev/tty
|
|
else
|
|
read -p "$message [y/N]: " choice < /dev/tty
|
|
fi
|
|
# Default choice if user just presses Enter
|
|
if [ -z "$choice" ]; then
|
|
choice="$default"
|
|
fi
|
|
case "$choice" in
|
|
y|Y|yes|Yes|YES)
|
|
return 0
|
|
;;
|
|
n|N|no|No|NO)
|
|
return 1
|
|
;;
|
|
*)
|
|
echo "Please answer yes or no."
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Function to check if running on Raspberry Pi
|
|
is_raspberry_pi() {
|
|
if [ -f /proc/device-tree/model ] && grep -q "Raspberry Pi" /proc/device-tree/model; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to validate if curl is installed
|
|
check_curl() {
|
|
if ! command -v curl >/dev/null 2>&1; then
|
|
log "Installing curl..."
|
|
if ! apt install -y curl; then
|
|
log "${RED}Failed to install curl${NC}"
|
|
return 1
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Function to get current Debian version
|
|
get_current_version() {
|
|
CURRENT_VERSION=$(cat /etc/debian_version | cut -d'.' -f1)
|
|
CURRENT_CODENAME=$(grep -oP '(?<=VERSION_CODENAME=).*' /etc/os-release)
|
|
log "Current Debian version: $CURRENT_CODENAME (Debian $CURRENT_VERSION)"
|
|
}
|
|
|
|
# Function to get next Debian stable version
|
|
get_next_version() {
|
|
if ! check_curl; then
|
|
return 1
|
|
fi
|
|
|
|
NEXT_CODENAME=$(curl -s "http://ftp.debian.org/debian/dists/stable/Release" | grep -oP '(?<=Codename: ).*' | head -n 1)
|
|
if [ -z "$NEXT_CODENAME" ]; then
|
|
log "${RED}Failed to fetch next Debian version${NC}"
|
|
return 1
|
|
fi
|
|
|
|
NEXT_VERSION=$(curl -s "http://ftp.debian.org/debian/dists/${NEXT_CODENAME}/Release" | grep -oP '(?<=Version: ).*' | cut -d'.' -f1)
|
|
log "Next Debian version available: $NEXT_CODENAME (Debian $NEXT_VERSION)"
|
|
return 0
|
|
}
|
|
|
|
# Function to backup important configurations
|
|
backup_configs() {
|
|
log "Creating backup of important configurations in $BACKUP_DIR..."
|
|
mkdir -p "$BACKUP_DIR" || {
|
|
log "${RED}Failed to create backup directory${NC}"
|
|
return 1
|
|
}
|
|
|
|
# Backup APT sources
|
|
cp -a /etc/apt/sources.list "$BACKUP_DIR/" || {
|
|
log "${RED}Failed to backup /etc/apt/sources.list${NC}"
|
|
return 1
|
|
}
|
|
cp -a /etc/apt/sources.list.d/ "$BACKUP_DIR/" 2>/dev/null || true
|
|
|
|
# Backup installed packages
|
|
dpkg --get-selections > "$BACKUP_DIR/installed_packages.txt" || {
|
|
log "${RED}Failed to backup installed packages${NC}"
|
|
return 1
|
|
}
|
|
|
|
# Backup important system configs
|
|
cp -a /etc/network/interfaces "$BACKUP_DIR/" 2>/dev/null || true
|
|
cp -a /etc/resolv.conf "$BACKUP_DIR/" 2>/dev/null || true
|
|
cp -a /etc/ssh/sshd_config "$BACKUP_DIR/" 2>/dev/null || true
|
|
|
|
log "${GREEN}Backup completed successfully${NC}"
|
|
return 0
|
|
}
|
|
|
|
# Function to update APT repositories
|
|
update_repositories() {
|
|
log "Updating APT repositories to $NEXT_CODENAME..."
|
|
sed -i "s/$CURRENT_CODENAME/$NEXT_CODENAME/g" /etc/apt/sources.list || {
|
|
log "${RED}Failed to update /etc/apt/sources.list${NC}"
|
|
return 1
|
|
}
|
|
|
|
if [ -d /etc/apt/sources.list.d/ ]; then
|
|
find /etc/apt/sources.list.d/ -type f -name "*.list" -exec sed -i "s/$CURRENT_CODENAME/$NEXT_CODENAME/g" {} \; || {
|
|
log "${RED}Failed to update repositories in /etc/apt/sources.list.d/${NC}"
|
|
return 1
|
|
}
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to perform the upgrade
|
|
perform_upgrade() {
|
|
log "Updating package lists..."
|
|
if ! apt update; then
|
|
log "${RED}Failed to update package lists${NC}"
|
|
return 1
|
|
fi
|
|
|
|
log "Performing full upgrade..."
|
|
if ! apt full-upgrade -y; then
|
|
log "${RED}Failed to perform full upgrade${NC}"
|
|
return 1
|
|
fi
|
|
|
|
log "Performing distribution upgrade to $NEXT_CODENAME..."
|
|
if ! apt dist-upgrade -y; then
|
|
log "${RED}Failed to perform distribution upgrade${NC}"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to clean up after upgrade
|
|
cleanup() {
|
|
log "Cleaning up..."
|
|
apt autoremove -y || log "${YELLOW}Warning: Failed to autoremove packages${NC}"
|
|
apt clean || log "${YELLOW}Warning: Failed to clean APT cache${NC}"
|
|
return 0
|
|
}
|
|
|
|
# Function to verify upgrade
|
|
verify_upgrade() {
|
|
NEW_CODENAME=$(grep -oP '(?<=VERSION_CODENAME=).*' /etc/os-release)
|
|
if [ "$NEW_CODENAME" != "$NEXT_CODENAME" ]; then
|
|
log "${RED}Upgrade verification failed. Current codename is still $NEW_CODENAME${NC}"
|
|
return 1
|
|
fi
|
|
log "${GREEN}Successfully upgraded to $NEXT_CODENAME (Debian $NEXT_VERSION)${NC}"
|
|
return 0
|
|
}
|
|
|
|
# Main function
|
|
main() {
|
|
# Check if running as root
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
log "${RED}This script must be run as root. Use 'sudo'.${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if this is a Debian system
|
|
if [ ! -f /etc/debian_version ]; then
|
|
log "${RED}This script is only for Debian-based systems.${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if running on Raspberry Pi
|
|
if is_raspberry_pi; then
|
|
log "${RED}WARNING: This is a Raspberry Pi device.${NC}"
|
|
log "${RED}Upgrading the Debian distribution may break compatibility with Raspberry Pi OS.${NC}"
|
|
if ! ask_confirmation "Are you sure you want to continue?" "n"; then
|
|
log "${YELLOW}Aborting Debian distribution upgrade${NC}"
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Get current and next Debian versions
|
|
get_current_version
|
|
if ! get_next_version; then
|
|
exit 1
|
|
fi
|
|
|
|
# Check if upgrade is needed
|
|
if [ "$CURRENT_CODENAME" == "$NEXT_CODENAME" ]; then
|
|
log "No new Debian stable version available. Current version: $CURRENT_CODENAME"
|
|
exit 0
|
|
fi
|
|
|
|
# Ask for confirmation
|
|
if ! ask_confirmation "Do you want to upgrade from $CURRENT_CODENAME to $NEXT_CODENAME?" "n"; then
|
|
log "${YELLOW}Skipping Debian distribution upgrade${NC}"
|
|
exit 0
|
|
fi
|
|
|
|
# Backup configurations
|
|
if ! backup_configs; then
|
|
exit 1
|
|
fi
|
|
|
|
# Update repositories
|
|
if ! update_repositories; then
|
|
exit 1
|
|
fi
|
|
|
|
# Perform upgrade
|
|
if ! perform_upgrade; then
|
|
exit 1
|
|
fi
|
|
|
|
# Clean up
|
|
cleanup
|
|
|
|
# Verify upgrade
|
|
if ! verify_upgrade; then
|
|
exit 1
|
|
fi
|
|
|
|
log "${YELLOW}Please reboot the system to complete the upgrade${NC}"
|
|
exit 0
|
|
}
|
|
|
|
# Call main function
|
|
main
|