Files
backup_to_external_m.2/backup_script.sh
root 0367c3f7e6 Initial commit: Complete backup system with portable tools
- GUI and CLI backup/restore functionality
- Auto-detection of internal system drive
- Smart drive classification (internal vs external)
- Reboot integration for clean backups/restores
- Portable tools that survive cloning operations
- Tool preservation system for external M.2 SSD
- Complete disaster recovery workflow
- Safety features and multiple confirmations
- Desktop integration and launcher scripts
- Comprehensive documentation
2025-09-13 22:14:36 +02:00

339 lines
9.5 KiB
Bash
Executable File

#!/bin/bash
# System Backup Script - Command Line Version
# For use with cron jobs or manual execution
set -e
# Configuration
SOURCE_DRIVE="" # Will be auto-detected
TARGET_DRIVE="" # Will be detected or specified
RESTORE_MODE=false # Restore mode flag
LOG_FILE="/var/log/system_backup.log"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Logging function
log() {
local message="$1"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Log to console
echo "${timestamp} - ${message}"
# Log to file if writable
if [[ -w "$LOG_FILE" ]] || [[ -w "$(dirname "$LOG_FILE")" ]]; then
echo "${timestamp} - ${message}" >> "$LOG_FILE" 2>/dev/null
fi
}
# Error handling
error_exit() {
log "${RED}ERROR: $1${NC}"
exit 1
}
# Success message
success() {
log "${GREEN}SUCCESS: $1${NC}"
}
# Warning message
warning() {
log "${YELLOW}WARNING: $1${NC}"
}
# Check if running as root
check_root() {
if [[ $EUID -ne 0 ]]; then
error_exit "This script must be run as root (use sudo)"
fi
}
# Detect root filesystem drive
detect_root_drive() {
log "Detecting root filesystem drive..."
# Find the device containing the root filesystem
local root_device=$(df / | tail -1 | awk '{print $1}')
# Remove partition number to get base device
local base_device=$(echo "$root_device" | sed 's/[0-9]*$//')
# Handle nvme drives (e.g., /dev/nvme0n1p1 -> /dev/nvme0n1)
base_device=$(echo "$base_device" | sed 's/p$//')
echo "$base_device"
}
# Detect external drives
detect_external_drives() {
log "Detecting external drives..."
# Get all block devices
lsblk -d -n -o NAME,SIZE,TYPE,TRAN | while read -r line; do
if [[ $line == *"disk"* ]] && [[ $line == *"usb"* ]]; then
drive_name=$(echo "$line" | awk '{print $1}')
drive_size=$(echo "$line" | awk '{print $2}')
echo "/dev/$drive_name ($drive_size)"
fi
done
}
# Validate drives
validate_drives() {
if [[ ! -b "$SOURCE_DRIVE" ]]; then
error_exit "Source drive $SOURCE_DRIVE does not exist or is not a block device"
fi
if [[ ! -b "$TARGET_DRIVE" ]]; then
error_exit "Target drive $TARGET_DRIVE does not exist or is not a block device"
fi
if [[ "$SOURCE_DRIVE" == "$TARGET_DRIVE" ]]; then
error_exit "Source and target drives cannot be the same"
fi
# Check if target drive is mounted
if mount | grep -q "$TARGET_DRIVE"; then
warning "Target drive $TARGET_DRIVE is currently mounted. Unmounting..."
umount "$TARGET_DRIVE"* 2>/dev/null || true
fi
}
# Get drive size
get_drive_size() {
local drive=$1
blockdev --getsize64 "$drive"
}
# Clone drive
clone_drive() {
local source=$1
local target=$2
log "Starting drive clone operation..."
log "Source: $source"
log "Target: $target"
# Get sizes
source_size=$(get_drive_size "$source")
target_size=$(get_drive_size "$target")
log "Source size: $(numfmt --to=iec-i --suffix=B $source_size)"
log "Target size: $(numfmt --to=iec-i --suffix=B $target_size)"
if [[ $target_size -lt $source_size ]]; then
error_exit "Target drive is smaller than source drive"
fi
# Start cloning
log "Starting clone operation with dd..."
if command -v pv >/dev/null 2>&1; then
# Use pv for progress if available
dd if="$source" bs=4M | pv -s "$source_size" | dd of="$target" bs=4M conv=fdatasync
else
# Use dd with status=progress
dd if="$source" of="$target" bs=4M status=progress conv=fdatasync
fi
if [[ $? -eq 0 ]]; then
success "Drive cloning completed successfully!"
# Restore backup tools to external drive if this was a backup operation
if [[ "$RESTORE_MODE" != true ]]; then
log "Preserving backup tools on external drive..."
local restore_script="$(dirname "$0")/restore_tools_after_backup.sh"
if [[ -f "$restore_script" ]]; then
"$restore_script" "$target" || log "Warning: Could not preserve backup tools"
else
log "Warning: Tool preservation script not found"
fi
fi
# Sync to ensure all data is written
log "Syncing data to disk..."
sync
# Verify partition table
log "Verifying partition table on target drive..."
fdisk -l "$target" | head -20 | tee -a "$LOG_FILE"
success "Backup verification completed!"
else
error_exit "Drive cloning failed!"
fi
}
# Create desktop entry
create_desktop_entry() {
local desktop_file="$HOME/Desktop/System-Backup.desktop"
local script_path=$(realpath "$0")
cat > "$desktop_file" << EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=System Backup
Comment=Clone internal drive to external M.2 SSD
Exec=gnome-terminal -- sudo "$script_path" --gui
Icon=drive-harddisk
Terminal=false
Categories=System;Utility;
EOF
chmod +x "$desktop_file"
log "Desktop entry created: $desktop_file"
}
# Show usage
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -s, --source DRIVE Source drive (auto-detected if not specified)"
echo " -t, --target DRIVE Target drive (required)"
echo " -r, --restore Restore mode (reverse source and target)"
echo " -l, --list List available drives"
echo " -d, --desktop Create desktop entry"
echo " --gui Launch GUI version"
echo " -h, --help Show this help"
echo ""
echo "Examples:"
echo " $0 --list"
echo " $0 --source /dev/sda --target /dev/sdb"
echo " $0 --restore --source /dev/sdb --target /dev/sda"
echo " $0 --desktop"
echo " $0 --gui"
}
# Main function
main() {
# Auto-detect source drive if not specified
if [[ -z "$SOURCE_DRIVE" ]]; then
SOURCE_DRIVE=$(detect_root_drive)
log "Auto-detected root filesystem drive: $SOURCE_DRIVE"
fi
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-s|--source)
SOURCE_DRIVE="$2"
shift 2
;;
-t|--target)
TARGET_DRIVE="$2"
shift 2
;;
-r|--restore)
RESTORE_MODE=true
shift
;;
-l|--list)
echo "Available drives:"
lsblk -d -o NAME,SIZE,TYPE,TRAN
echo ""
echo "External drives:"
detect_external_drives
exit 0
;;
-d|--desktop)
create_desktop_entry
exit 0
;;
--gui)
python3 "$(dirname "$0")/backup_manager.py"
exit 0
;;
-h|--help)
show_usage
exit 0
;;
*)
error_exit "Unknown option: $1"
;;
esac
done
# In restore mode, swap source and target for user convenience
if [[ "$RESTORE_MODE" == true ]]; then
if [[ -n "$SOURCE_DRIVE" && -n "$TARGET_DRIVE" ]]; then
log "Restore mode: swapping source and target drives"
TEMP_DRIVE="$SOURCE_DRIVE"
SOURCE_DRIVE="$TARGET_DRIVE"
TARGET_DRIVE="$TEMP_DRIVE"
fi
fi
# Check if target drive is specified
if [[ -z "$TARGET_DRIVE" ]]; then
echo "Available external drives:"
detect_external_drives
echo ""
read -p "Enter target drive (e.g., /dev/sdb): " TARGET_DRIVE
if [[ -z "$TARGET_DRIVE" ]]; then
error_exit "Target drive not specified"
fi
fi
# Check root privileges
check_root
# Validate drives
validate_drives
# Confirm operation
echo ""
if [[ "$RESTORE_MODE" == true ]]; then
echo "🚨 RESTORE CONFIGURATION 🚨"
echo "This will RESTORE (overwrite target with source data):"
else
echo "BACKUP CONFIGURATION:"
echo "This will BACKUP (copy source to target):"
fi
echo "Source: $SOURCE_DRIVE"
echo "Target: $TARGET_DRIVE"
echo ""
echo "WARNING: All data on $TARGET_DRIVE will be DESTROYED!"
if [[ "$RESTORE_MODE" == true ]]; then
echo ""
echo "⚠️ CRITICAL WARNING FOR RESTORE MODE ⚠️"
echo "You are about to OVERWRITE $TARGET_DRIVE"
echo "Make sure this is what you intend to do!"
echo ""
read -p "Type 'RESTORE' to confirm or anything else to cancel: " confirm
if [[ "$confirm" != "RESTORE" ]]; then
log "Restore operation cancelled by user"
exit 0
fi
else
read -p "Are you sure you want to continue? (yes/no): " confirm
if [[ "$confirm" != "yes" ]]; then
log "Operation cancelled by user"
exit 0
fi
fi
# Start operation
if [[ "$RESTORE_MODE" == true ]]; then
log "Starting system restore operation..."
else
log "Starting system backup operation..."
fi
clone_drive "$SOURCE_DRIVE" "$TARGET_DRIVE"
log "System backup completed successfully!"
echo ""
echo "Backup completed! You can now safely remove the external drive."
}
# Run main function
main "$@"