- Removed 40+ broken/messy scripts, moved to old_scripts/ - Created lvm_block_backup.sh - proper block-level LVM snapshot backup - Uses dd for block-level cloning instead of file-level rsync - Successfully tested: 462GB backup in 33 minutes - Creates exact, bootable clone of internal drive to external drive - Proper LVM snapshot management with cleanup - Clear documentation in README_BACKUP.md - Clean, minimal solution that actually works
369 lines
12 KiB
Bash
Executable File
369 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# Portable Backup Tool Installer for External M.2 SSD
|
|
# This script sets up the backup tools on the external drive so they survive cloning operations
|
|
|
|
set -e
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
print_status() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
print_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# Detect external drives
|
|
detect_external_drive() {
|
|
print_status "Detecting external M.2 SSD..."
|
|
|
|
# Look for USB-connected drives
|
|
local external_drives=()
|
|
while IFS= read -r line; do
|
|
if [[ $line == *"disk"* ]] && [[ $line == *"usb"* ]]; then
|
|
local drive_name=$(echo "$line" | awk '{print $1}')
|
|
local drive_size=$(echo "$line" | awk '{print $4}')
|
|
external_drives+=("/dev/$drive_name ($drive_size)")
|
|
fi
|
|
done < <(lsblk -d -o NAME,SIZE,TYPE,TRAN | grep -E "disk.*usb")
|
|
|
|
if [[ ${#external_drives[@]} -eq 0 ]]; then
|
|
print_error "No external USB drives found. Please connect your M.2 SSD."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ${#external_drives[@]} -eq 1 ]]; then
|
|
EXTERNAL_DRIVE=$(echo "${external_drives[0]}" | cut -d' ' -f1)
|
|
print_success "Auto-detected external drive: ${external_drives[0]}"
|
|
else
|
|
print_status "Multiple external drives found:"
|
|
for i in "${!external_drives[@]}"; do
|
|
echo " $((i+1)). ${external_drives[i]}"
|
|
done
|
|
read -p "Select drive number: " selection
|
|
EXTERNAL_DRIVE=$(echo "${external_drives[$((selection-1))]}" | cut -d' ' -f1)
|
|
fi
|
|
}
|
|
|
|
# Create backup tools partition
|
|
create_tools_partition() {
|
|
print_status "Setting up backup tools partition on $EXTERNAL_DRIVE..."
|
|
|
|
# Check if there's already a small partition at the end
|
|
local last_partition=$(lsblk -n -o NAME "$EXTERNAL_DRIVE" | tail -1)
|
|
local tools_partition="${EXTERNAL_DRIVE}p3" # Assuming nvme, adjust for sda
|
|
|
|
# If it's sda style, adjust
|
|
if [[ $EXTERNAL_DRIVE == *"sda"* ]]; then
|
|
tools_partition="${EXTERNAL_DRIVE}3"
|
|
fi
|
|
|
|
# Check if tools partition already exists
|
|
if lsblk | grep -q "$(basename "$tools_partition")"; then
|
|
print_warning "Tools partition already exists: $tools_partition"
|
|
TOOLS_PARTITION="$tools_partition"
|
|
return
|
|
fi
|
|
|
|
print_warning "This will create a 512MB partition at the end of $EXTERNAL_DRIVE"
|
|
print_warning "This will slightly reduce the cloneable space but preserve backup tools"
|
|
read -p "Continue? (yes/no): " confirm
|
|
|
|
if [[ "$confirm" != "yes" ]]; then
|
|
print_error "Operation cancelled"
|
|
exit 1
|
|
fi
|
|
|
|
# Create 512MB partition at the end using parted
|
|
sudo parted "$EXTERNAL_DRIVE" --script mkpart primary ext4 -512MiB 100%
|
|
|
|
# Get the new partition name
|
|
TOOLS_PARTITION=$(lsblk -n -o NAME "$EXTERNAL_DRIVE" | tail -1)
|
|
TOOLS_PARTITION="/dev/$TOOLS_PARTITION"
|
|
|
|
# Format the partition
|
|
sudo mkfs.ext4 -L "BACKUP_TOOLS" "$TOOLS_PARTITION"
|
|
|
|
print_success "Tools partition created: $TOOLS_PARTITION"
|
|
}
|
|
|
|
# Install backup tools to external drive
|
|
install_tools_to_external() {
|
|
local mount_point="/mnt/backup_tools"
|
|
|
|
print_status "Installing backup tools to external drive..."
|
|
|
|
# Create mount point
|
|
sudo mkdir -p "$mount_point"
|
|
|
|
# Mount tools partition
|
|
sudo mount "$TOOLS_PARTITION" "$mount_point"
|
|
|
|
# Copy all backup tools
|
|
sudo cp -r . "$mount_point/backup_system"
|
|
|
|
# Create launcher script that works from any location
|
|
sudo tee "$mount_point/backup_system/launch_backup_tools.sh" > /dev/null << 'EOF'
|
|
#!/bin/bash
|
|
# Portable launcher for backup tools
|
|
|
|
# Get the directory where this script is located
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Make sure scripts are executable
|
|
chmod +x *.sh *.py
|
|
|
|
# Launch GUI if X11 is available, otherwise show CLI options
|
|
if [[ -n "$DISPLAY" ]]; then
|
|
echo "Launching Backup Manager GUI..."
|
|
python3 backup_manager.py
|
|
else
|
|
echo "No GUI available. Command line options:"
|
|
./backup_script.sh --help
|
|
fi
|
|
EOF
|
|
|
|
sudo chmod +x "$mount_point/backup_system/launch_backup_tools.sh"
|
|
|
|
# Create desktop entry for when booted from external drive
|
|
sudo tee "$mount_point/backup_system/create_desktop_entry.sh" > /dev/null << 'EOF'
|
|
#!/bin/bash
|
|
# Create desktop entry when booted from external drive
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
DESKTOP_DIR="$HOME/Desktop"
|
|
APPLICATIONS_DIR="$HOME/.local/share/applications"
|
|
|
|
mkdir -p "$APPLICATIONS_DIR"
|
|
|
|
# Create desktop entry
|
|
cat > "$APPLICATIONS_DIR/portable-backup.desktop" << EOL
|
|
[Desktop Entry]
|
|
Version=1.0
|
|
Type=Application
|
|
Name=Portable Backup Manager
|
|
Comment=Restore internal drive from external backup
|
|
Exec=python3 "$SCRIPT_DIR/backup_manager.py"
|
|
Icon=drive-harddisk
|
|
Terminal=false
|
|
Categories=System;Utility;
|
|
StartupNotify=true
|
|
EOL
|
|
|
|
# Create desktop shortcut if Desktop exists
|
|
if [[ -d "$DESKTOP_DIR" ]]; then
|
|
cp "$APPLICATIONS_DIR/portable-backup.desktop" "$DESKTOP_DIR/"
|
|
chmod +x "$DESKTOP_DIR/portable-backup.desktop"
|
|
fi
|
|
|
|
echo "Desktop entry created for portable backup tools"
|
|
EOF
|
|
|
|
sudo chmod +x "$mount_point/backup_system/create_desktop_entry.sh"
|
|
|
|
# Unmount
|
|
sudo umount "$mount_point"
|
|
|
|
print_success "Backup tools installed to external drive"
|
|
}
|
|
|
|
# Create post-backup restoration script
|
|
create_restoration_script() {
|
|
print_status "Creating post-backup tool restoration script..."
|
|
|
|
# This script will be called after each backup to restore the tools
|
|
cat > "restore_tools_after_backup.sh" << 'EOF'
|
|
#!/bin/bash
|
|
# Restore backup tools after cloning operation
|
|
# This script runs automatically after backup to preserve tools on external drive
|
|
|
|
set -e
|
|
|
|
print_status() {
|
|
echo "[$(date '+%H:%M:%S')] $1"
|
|
}
|
|
|
|
# Detect the external drive (should be the target of backup)
|
|
EXTERNAL_DRIVE="$1"
|
|
if [[ -z "$EXTERNAL_DRIVE" ]]; then
|
|
print_status "Auto-detecting external drive..."
|
|
EXTERNAL_DRIVE=$(lsblk -d -o NAME,TRAN | grep usb | awk '{print "/dev/" $1}' | head -1)
|
|
fi
|
|
|
|
if [[ -z "$EXTERNAL_DRIVE" ]]; then
|
|
echo "Error: Could not detect external drive"
|
|
exit 1
|
|
fi
|
|
|
|
print_status "Restoring backup tools to $EXTERNAL_DRIVE"
|
|
|
|
# Find the tools partition (should be the last partition)
|
|
TOOLS_PARTITION=$(lsblk -n -o NAME "$EXTERNAL_DRIVE" | tail -1)
|
|
TOOLS_PARTITION="/dev/$TOOLS_PARTITION"
|
|
|
|
# Check if tools partition exists
|
|
if ! lsblk | grep -q "$(basename "$TOOLS_PARTITION")"; then
|
|
echo "Warning: Tools partition not found. Backup tools may have been overwritten."
|
|
exit 1
|
|
fi
|
|
|
|
# Mount tools partition
|
|
MOUNT_POINT="/mnt/backup_tools_restore"
|
|
mkdir -p "$MOUNT_POINT"
|
|
mount "$TOOLS_PARTITION" "$MOUNT_POINT"
|
|
|
|
# Check if tools exist
|
|
if [[ -d "$MOUNT_POINT/backup_system" ]]; then
|
|
print_status "Backup tools preserved on external drive"
|
|
|
|
# Update the tools with any changes from source
|
|
rsync -av --exclude='.git' "$(dirname "$0")/" "$MOUNT_POINT/backup_system/"
|
|
|
|
print_status "Backup tools updated on external drive"
|
|
else
|
|
print_status "Installing backup tools to external drive for first time"
|
|
cp -r "$(dirname "$0")" "$MOUNT_POINT/backup_system"
|
|
fi
|
|
|
|
# Ensure scripts are executable
|
|
chmod +x "$MOUNT_POINT/backup_system"/*.sh
|
|
chmod +x "$MOUNT_POINT/backup_system"/*.py
|
|
|
|
umount "$MOUNT_POINT"
|
|
print_status "Backup tools restoration complete"
|
|
EOF
|
|
|
|
chmod +x "restore_tools_after_backup.sh"
|
|
|
|
print_success "Post-backup restoration script created"
|
|
}
|
|
|
|
# Update backup scripts to call restoration
|
|
update_backup_scripts() {
|
|
print_status "Updating backup scripts to preserve tools..."
|
|
|
|
# Add tool restoration to GUI backup manager
|
|
if ! grep -q "restore_tools_after_backup" backup_manager.py; then
|
|
# Add restoration call after successful backup
|
|
sed -i '/self\.log("Backup completed successfully!")/a\\n # Restore backup tools to external drive\n try:\n subprocess.run([os.path.join(os.path.dirname(__file__), "restore_tools_after_backup.sh"), target], check=False)\n except Exception as e:\n self.log(f"Warning: Could not restore tools to external drive: {e}")' backup_manager.py
|
|
fi
|
|
|
|
# Add tool restoration to command line script
|
|
if ! grep -q "restore_tools_after_backup" backup_script.sh; then
|
|
sed -i '/success "Drive cloning completed successfully!"/a\\n # Restore backup tools to external drive\n log "Restoring backup tools to external drive..."\n if [[ -f "$(dirname "$0")/restore_tools_after_backup.sh" ]]; then\n "$(dirname "$0")/restore_tools_after_backup.sh" "$target" || log "Warning: Could not restore tools"\n fi' backup_script.sh
|
|
fi
|
|
|
|
print_success "Backup scripts updated to preserve tools"
|
|
}
|
|
|
|
# Create auto-mount script for tools partition
|
|
create_automount_script() {
|
|
print_status "Creating auto-mount script for backup tools..."
|
|
|
|
cat > "mount_backup_tools.sh" << 'EOF'
|
|
#!/bin/bash
|
|
# Auto-mount backup tools partition and create desktop shortcut
|
|
|
|
# Find tools partition by label
|
|
TOOLS_PARTITION=$(blkid -L "BACKUP_TOOLS" 2>/dev/null)
|
|
|
|
if [[ -z "$TOOLS_PARTITION" ]]; then
|
|
echo "Backup tools partition not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Create mount point
|
|
MOUNT_POINT="$HOME/backup_tools"
|
|
mkdir -p "$MOUNT_POINT"
|
|
|
|
# Mount if not already mounted
|
|
if ! mountpoint -q "$MOUNT_POINT"; then
|
|
mount "$TOOLS_PARTITION" "$MOUNT_POINT" 2>/dev/null || {
|
|
echo "Mounting with sudo..."
|
|
sudo mount "$TOOLS_PARTITION" "$MOUNT_POINT"
|
|
}
|
|
fi
|
|
|
|
echo "Backup tools mounted at: $MOUNT_POINT"
|
|
|
|
# Create desktop entry if tools exist
|
|
if [[ -d "$MOUNT_POINT/backup_system" ]]; then
|
|
cd "$MOUNT_POINT/backup_system"
|
|
./create_desktop_entry.sh
|
|
echo "Desktop entry created for backup tools"
|
|
fi
|
|
EOF
|
|
|
|
chmod +x "mount_backup_tools.sh"
|
|
|
|
print_success "Auto-mount script created"
|
|
}
|
|
|
|
# Main installation
|
|
main() {
|
|
echo ""
|
|
echo "=============================================="
|
|
echo " Portable Backup Tools Installer"
|
|
echo " For External M.2 SSD"
|
|
echo "=============================================="
|
|
echo ""
|
|
|
|
print_warning "This installer will:"
|
|
print_warning "1. Create a 512MB tools partition on your external M.2 SSD"
|
|
print_warning "2. Install backup tools that survive cloning operations"
|
|
print_warning "3. Set up automatic tool restoration after backups"
|
|
print_warning "4. Enable booting from external drive with restore capability"
|
|
echo ""
|
|
|
|
read -p "Continue? (yes/no): " confirm
|
|
if [[ "$confirm" != "yes" ]]; then
|
|
print_error "Installation cancelled"
|
|
exit 1
|
|
fi
|
|
|
|
detect_external_drive
|
|
create_tools_partition
|
|
install_tools_to_external
|
|
create_restoration_script
|
|
update_backup_scripts
|
|
create_automount_script
|
|
|
|
echo ""
|
|
print_success "Portable backup tools installation complete!"
|
|
echo ""
|
|
echo "Your external M.2 SSD now has:"
|
|
echo " • Preserved backup tools in separate partition"
|
|
echo " • Automatic tool restoration after each backup"
|
|
echo " • Bootable system restoration capability"
|
|
echo ""
|
|
echo "When booted from external drive:"
|
|
echo " • Run: ~/backup_tools/backup_system/launch_backup_tools.sh"
|
|
echo " • Or use desktop shortcut if available"
|
|
echo ""
|
|
print_warning "Note: Your external drive now has 512MB less space for cloning"
|
|
print_warning "But the backup tools will always be available for system recovery!"
|
|
}
|
|
|
|
# Check if running as root
|
|
if [[ $EUID -eq 0 ]]; then
|
|
print_error "Do not run as root. Script will use sudo when needed."
|
|
exit 1
|
|
fi
|
|
|
|
main "$@"
|