Freepoorman
Active Member
Hi everyone,
I recently critically misconfigured my system while trying to implement security enhancements, and my backup/restore script let me down big time.
I have worked on this new backup script now the whole day, hoping that it is a secure alternative to the one I used before.
I have audited it and implemented as many improvements to functionality as possible while prioritizing system stability.
Please feel free to judge me as much as you want, all criticism and advice is welcome. And feel free to use this script for yourselves if you like it:
restore_backup.sh:
/home/erik/.backup_config:
I would very much appreciate if I could get input from more experienced guys before I attempt running it..
I recently critically misconfigured my system while trying to implement security enhancements, and my backup/restore script let me down big time.
I have worked on this new backup script now the whole day, hoping that it is a secure alternative to the one I used before.
I have audited it and implemented as many improvements to functionality as possible while prioritizing system stability.
Please feel free to judge me as much as you want, all criticism and advice is welcome. And feel free to use this script for yourselves if you like it:
restore_backup.sh:
Bash:
#!/bin/bash
# Configuration file path
CONFIG_FILE="/home/erik/.backup_config"
# Load configuration
source "$CONFIG_FILE" || handle_error "Failed to load configuration file."
# Function to prompt user for confirmation
confirm() {
while true; do
read -p "$1 [Y/N]: " response
case $response in
[Yy]* ) return 0;;
[Nn]* ) return 1;;
* ) echo "Please answer Yes or No.";;
esac
done
}
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Function to handle errors
handle_error() {
log_message "Error: $1"
read -n 1 -s -r -p "Press any key to close the terminal..."
exit 1
}
# Function to rotate log file
rotate_log() {
local max_log_size=$((1024 * 1024 * 10)) # 10 MB
if [ -f "$LOG_FILE" ] && [ "$(stat -c%s "$LOG_FILE")" -gt "$max_log_size" ]; then
mv "$LOG_FILE" "${LOG_FILE}.1"
log_message "Log file rotated."
fi
}
# Check if the script is run as root
if [ "$EUID" -ne 0 ]; then
handle_error "This script must be run as root. Please use sudo or run as root."
fi
# Function to verify backup integrity
verify_backup_integrity() {
local backup_dir="$1"
local checksum_file="${backup_dir}/checksum.md5"
if [ ! -f "$checksum_file" ]; then
handle_error "Checksum file not found. Backup integrity cannot be verified."
fi
log_message "Verifying backup integrity..."
if md5sum -c "$checksum_file"; then
log_message "Backup integrity verified."
else
handle_error "Backup integrity check failed. Please ensure the backup is intact."
fi
}
# Function to restore snaps
restore_snaps() {
local backup_dir="$1"
local snaps_dir="${backup_dir}/snaps"
if [ -d "$snaps_dir" ]; then
log_message "Restoring snaps..."
for snap in "$snaps_dir"/*; do
snap_name=$(basename "$snap")
if ! snap list | grep -q "$snap_name"; then
log_message "Restoring snap: $snap_name"
snap install "$snap"
else
log_message "Snap $snap_name is already installed. Skipping..."
fi
done
log_message "Snaps restored successfully."
else
log_message "No snaps found to restore."
fi
}
# Function to restore flatpaks
restore_flatpaks() {
local backup_dir="$1"
local flatpaks_dir="${backup_dir}/flatpaks"
if [ -d "$flatpaks_dir" ]; then
log_message "Restoring flatpaks..."
for flatpak in "$flatpaks_dir"/*; do
flatpak_name=$(basename "$flatpak")
if ! flatpak list --app | grep -q "$flatpak_name"; then
log_message "Restoring flatpak: $flatpak_name"
flatpak install --user "$flatpak"
else
log_message "Flatpak $flatpak_name is already installed. Skipping..."
fi
done
log_message "Flatpaks restored successfully."
else
log_message "No flatpaks found to restore."
fi
}
# Function to perform backup
perform_backup() {
# Rotate log file if necessary
rotate_log
# Check if the destination directory exists, if not, create it
if [ ! -d "$DEST" ]; then
mkdir -p "$DEST" || handle_error "Failed to create destination directory $DEST."
fi
# Calculate total size of files to be backed up
total_size=$(du -sb --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/swapfile","/home/*"} "$SOURCE" | awk '{print $1}')
# Perform the backup using rsync with pv for progress monitoring
log_message "Starting backup..."
if rsync -av --delete --ignore-missing-args --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/swapfile","/home/*"} "$SOURCE" "$DEST" | pv -s "$total_size" > /dev/null; then
log_message "Backup completed successfully."
# Generate checksum file for backup integrity verification
log_message "Generating checksum file..."
find "$DEST" -type f -exec md5sum {} + > "${DEST}/checksum.md5"
log_message "Checksum file generated."
else
handle_error "Backup failed with error code $?"
fi
}
# Function to perform restore
perform_restore() {
# Rotate log file if necessary
rotate_log
# Check if the source directory exists
if [ ! -d "$SOURCE" ]; then
handle_error "Source directory $SOURCE not found. Please ensure the 2Tb_ext4 drive is mounted."
fi
# Verify backup integrity
verify_backup_integrity "$SOURCE"
# Prompt user to confirm restore
if confirm "Do you want to restore a backup?"; then
if confirm "Are you sure you want to proceed with the restore?"; then
# Calculate total size of files to be restored
total_size=$(du -sb "$SOURCE" | awk '{print $1}')
# Perform the restore using rsync with pv for progress monitoring
log_message "Starting restore..."
if rsync -av --delete "$SOURCE" "$DEST" | pv -s "$total_size" > /dev/null; then
log_message "Restore completed successfully."
# Restore snaps
restore_snaps "$SOURCE"
# Restore flatpaks
restore_flatpaks "$SOURCE"
else
handle_error "Restore failed with error code $?"
fi
else
log_message "Restore operation cancelled."
exit 0
fi
else
log_message "Restore operation cancelled."
exit 0
fi
}
# Function to view logs
view_logs() {
if [ -f "$LOG_FILE" ]; then
less "$LOG_FILE"
else
handle_error "Log file not found."
fi
}
# Interactive menu for backup or restore
PS3="Please select an option: "
options=("Backup" "Restore" "View Logs" "Check Backup Integrity" "Exit")
select opt in "${options[@]}"
do
case $opt in
"Backup")
perform_backup
break
;;
"Restore")
perform_restore
break
;;
"View Logs")
view_logs
;;
"Check Backup Integrity")
verify_backup_integrity "$DEST"
;;
"Exit")
log_message "Exiting script."
exit 0
;;
*) handle_error "Invalid option. Please select a valid option.";;
esac
done
/home/erik/.backup_config:
Bash:
# Backup Configuration
SOURCE="/"
DEST="/media/erik/2Tb_ext4/AAA_System/backup_recovery-rsync/"
LOG_FILE="/var/log/backup_script.log"
I would very much appreciate if I could get input from more experienced guys before I attempt running it..
Last edited: