64883d4f02
Enable interpretation of backslash escapes in log messages across all debian scripts for consistent formatting and proper escape sequence handling
285 lines
8.0 KiB
Bash
285 lines
8.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
|
|
MAX_LOG_SIZE_KB=1024 # 1MB
|
|
|
|
# Função de Log (modificada para usar logger)
|
|
log() {
|
|
local message="$1"
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
# Escreve no ficheiro de log
|
|
echo -e "$timestamp: $message" | tee -a "$LOG_FILE"
|
|
|
|
# Envia para o syslog (opcional)
|
|
logger -t "debian_upgrade" "$message"
|
|
}
|
|
|
|
# Função para limitar o tamanho do log
|
|
limit_log_size() {
|
|
local log_file="$1"
|
|
local max_size_kb="$2"
|
|
local max_size_bytes=$((max_size_kb * 1024))
|
|
|
|
if [ -f "$log_file" ]; then
|
|
local current_size=$(stat -c %s "$log_file" 2>/dev/null || wc -c < "$log_file" 2>/dev/null)
|
|
|
|
if [ "$current_size" -gt "$max_size_bytes" ]; then
|
|
log "Aviso: Ficheiro de log $log_file excedeu $max_size_kb KB. A truncar..."
|
|
tail -n 500 "$log_file" > "${log_file}.tmp" && mv "${log_file}.tmp" "$log_file"
|
|
log "Ficheiro de log truncado. As últimas 500 linhas foram mantidas."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 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
|
|
|
|
mkdir -p "$(dirname "$LOG_FILE")"
|
|
limit_log_size "$LOG_FILE" "$MAX_LOG_SIZE_KB" # Verifica o tamanho do log no início
|
|
|
|
|
|
# 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
|