Files
backup_to_external_m.2/lvm-migration-tools/create_alpine_backup_usb.sh
Migration Tools 9d25520de9 Initial commit: Complete LVM migration toolset with fixes
- Fixed partition size calculation bugs in migrate_to_lvm.sh
- Added comprehensive error handling for USB drive stability
- Optimized data copy operations using cp -a for better performance
- Corrected mount point detection for encrypted home partitions
- Enhanced drive detection and exclusion logic
- Added proper size override mechanisms for manual intervention
- Improved filesystem creation and validation processes
- Complete toolset for external M.2 drive migration scenarios

Tested successfully on:
- Debian 13 Trixie Live USB environment
- 476GB external M.2 drives via USB 3.0
- Complex partition layouts (root/home/EFI + encryption)
- Large data transfers (314GB+ encrypted home directories)
2025-09-25 05:53:12 +00:00

308 lines
8.4 KiB
Bash
Executable File

#!/bin/bash
# Create Truly Bootable Backup USB with Alpine Linux
# This creates a complete bootable environment that preserves existing boot capability
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
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"
}
# 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
print_status "Bootable Backup USB Creator (Preserves Existing Boot)"
echo "=========================================================="
echo
# Check current USB drive status
USB_DRIVE="/dev/sda" # Your current USB
print_status "Analyzing current USB structure..."
lsblk "$USB_DRIVE"
echo
# Check if it already has a bootable system
HAS_BOOT=$(lsblk "$USB_DRIVE" | grep -i boot || true)
if [[ -n "$HAS_BOOT" ]]; then
print_warning "USB appears to have existing boot partition"
print_warning "We'll preserve this and add backup functionality"
else
print_status "No existing boot detected - will create complete bootable system"
fi
read -p "Continue to make this USB fully bootable with backup functionality? (yes/no): " confirm
if [[ "$confirm" != "yes" ]]; then
exit 0
fi
# Create temporary directory for Alpine Linux
WORK_DIR="/tmp/alpine_usb_$$"
mkdir -p "$WORK_DIR"
cd "$WORK_DIR"
print_status "Downloading Alpine Linux (minimal, fast-booting)..."
# Download Alpine Linux (very small, perfect for this)
ALPINE_VERSION="3.18.4"
ALPINE_ISO="alpine-standard-${ALPINE_VERSION}-x86_64.iso"
if [[ ! -f "$ALPINE_ISO" ]]; then
wget "https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/$ALPINE_ISO" || {
print_error "Failed to download Alpine Linux"
exit 1
}
fi
print_status "Preparing bootable USB with backup functionality..."
# Mount the ISO to extract files
ISO_MOUNT="$WORK_DIR/iso_mount"
mkdir -p "$ISO_MOUNT"
sudo mount -o loop "$ALPINE_ISO" "$ISO_MOUNT"
# Create mount points for USB partitions
BOOT_MOUNT="$WORK_DIR/usb_boot"
DATA_MOUNT="$WORK_DIR/usb_data"
mkdir -p "$BOOT_MOUNT" "$DATA_MOUNT"
# Mount USB partitions (created by previous script)
sudo mount "${USB_DRIVE}1" "$BOOT_MOUNT"
sudo mount "${USB_DRIVE}2" "$DATA_MOUNT"
print_status "Installing Alpine Linux boot files..."
# Copy Alpine Linux files to boot partition
sudo cp -r "$ISO_MOUNT"/* "$BOOT_MOUNT/"
# Install GRUB for UEFI/BIOS boot
print_status "Installing GRUB bootloader..."
sudo grub-install --target=x86_64-efi --efi-directory="$BOOT_MOUNT" --boot-directory="$BOOT_MOUNT/boot" --removable --force
# Create GRUB configuration for automatic backup boot
sudo tee "$BOOT_MOUNT/boot/grub/grub.cfg" > /dev/null << 'EOF'
set timeout=10
set default=0
menuentry "Automatic System Backup" {
linux /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage quiet alpine_dev=sda2:/backup-tools/alpine.apkovl.tar.gz
initrd /boot/initramfs-lts
}
menuentry "Manual Backup Mode" {
linux /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage alpine_dev=sda2:/backup-tools/alpine.apkovl.tar.gz
initrd /boot/initramfs-lts
}
menuentry "Alpine Linux (Standard)" {
linux /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage
initrd /boot/initramfs-lts
}
EOF
print_status "Creating backup environment overlay..."
# Create Alpine overlay for automatic backup
OVERLAY_DIR="$WORK_DIR/overlay"
mkdir -p "$OVERLAY_DIR/etc/init.d"
mkdir -p "$OVERLAY_DIR/usr/local/bin"
mkdir -p "$OVERLAY_DIR/etc/runlevels/default"
# Create backup script that runs on boot
sudo tee "$OVERLAY_DIR/usr/local/bin/backup-menu" > /dev/null << 'EOF'
#!/bin/sh
# Interactive backup menu
clear
echo "========================================"
echo " AUTOMATIC BACKUP SYSTEM"
echo "========================================"
echo
echo "Available drives:"
lsblk -d -o NAME,SIZE,TYPE,TRAN | grep -E "(disk|NAME)"
echo
# Auto-detect drives
INTERNAL_CANDIDATES=$(lsblk -d -n -o NAME,TYPE,TRAN | grep "disk" | grep -v "usb" | awk '{print "/dev/" $1}')
EXTERNAL_CANDIDATES=$(lsblk -d -n -o NAME,TYPE,TRAN | grep "disk" | grep "usb" | awk '{print "/dev/" $1}' | grep -v sda)
echo "Drive Selection:"
echo "=================="
# Select source drive
echo "Available internal drives:"
echo "$INTERNAL_CANDIDATES" | nl -v 1
echo
read -p "Select source drive number (or enter path): " SOURCE_CHOICE
if echo "$SOURCE_CHOICE" | grep -q "^[0-9]"; then
SOURCE_DRIVE=$(echo "$INTERNAL_CANDIDATES" | sed -n "${SOURCE_CHOICE}p")
else
SOURCE_DRIVE="$SOURCE_CHOICE"
fi
# Select target drive
echo
echo "Available external drives:"
echo "$EXTERNAL_CANDIDATES" | nl -v 1
echo
read -p "Select target drive number (or enter path): " TARGET_CHOICE
if echo "$TARGET_CHOICE" | grep -q "^[0-9]"; then
TARGET_DRIVE=$(echo "$EXTERNAL_CANDIDATES" | sed -n "${TARGET_CHOICE}p")
else
TARGET_DRIVE="$TARGET_CHOICE"
fi
echo
echo "BACKUP CONFIGURATION:"
echo "===================="
echo "Source (will be copied FROM): $SOURCE_DRIVE"
echo "Target (will be overwritten): $TARGET_DRIVE"
echo
echo "⚠️ ALL DATA ON $TARGET_DRIVE WILL BE DESTROYED! ⚠️"
echo
read -p "Continue with backup? (yes/no): " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
echo "Backup cancelled"
read -p "Press Enter to shutdown..."
poweroff
exit 0
fi
echo
echo "Starting backup..."
echo "=================="
# Get drive sizes for progress
SOURCE_SIZE=$(blockdev --getsize64 "$SOURCE_DRIVE")
SOURCE_SIZE_GB=$((SOURCE_SIZE / 1024 / 1024 / 1024))
echo "Copying $SOURCE_SIZE_GB GB from $SOURCE_DRIVE to $TARGET_DRIVE"
echo
# Perform backup with progress
if command -v pv >/dev/null 2>&1; then
dd if="$SOURCE_DRIVE" bs=4M | pv -s "$SOURCE_SIZE" | dd of="$TARGET_DRIVE" bs=4M conv=fdatasync
else
dd if="$SOURCE_DRIVE" of="$TARGET_DRIVE" bs=4M status=progress conv=fdatasync
fi
if [ $? -eq 0 ]; then
echo
echo "========================================"
echo " BACKUP COMPLETED SUCCESSFULLY!"
echo "========================================"
echo "Source: $SOURCE_DRIVE"
echo "Target: $TARGET_DRIVE"
echo "Size: $SOURCE_SIZE_GB GB"
else
echo
echo "========================================"
echo " BACKUP FAILED!"
echo "========================================"
fi
echo
echo "System will shutdown in 30 seconds..."
echo "Press Ctrl+C to cancel shutdown"
sleep 30
poweroff
EOF
chmod +x "$OVERLAY_DIR/usr/local/bin/backup-menu"
# Create init script to run backup on boot
sudo tee "$OVERLAY_DIR/etc/init.d/autobackup" > /dev/null << 'EOF'
#!/sbin/openrc-run
name="autobackup"
description="Automatic backup system"
depend() {
need localmount
after *
}
start() {
ebegin "Starting automatic backup system"
# Wait for devices to settle
sleep 5
# Check kernel command line for auto mode
if grep -q "autobackup" /proc/cmdline; then
/usr/local/bin/backup-menu
else
# Manual mode - provide choice
echo "Press 'b' for backup or any other key to continue to shell..."
read -t 10 -n 1 choice
if [ "$choice" = "b" ] || [ "$choice" = "B" ]; then
/usr/local/bin/backup-menu
fi
fi
eend $?
}
EOF
chmod +x "$OVERLAY_DIR/etc/init.d/autobackup"
# Enable the service
ln -sf /etc/init.d/autobackup "$OVERLAY_DIR/etc/runlevels/default/autobackup"
# Create the overlay archive
cd "$OVERLAY_DIR"
tar czf "$DATA_MOUNT/alpine.apkovl.tar.gz" *
# Copy our backup tools to the data partition as well
SCRIPT_DIR=$(dirname "$(realpath "$0")")
sudo cp "$SCRIPT_DIR"/*.sh "$DATA_MOUNT/"
print_status "Installing additional tools..."
# Create an Alpine package cache with useful tools
sudo mkdir -p "$DATA_MOUNT/apk-cache"
# Cleanup
cd "$WORK_DIR/.."
sudo umount "$ISO_MOUNT" "$BOOT_MOUNT" "$DATA_MOUNT" 2>/dev/null || true
rm -rf "$WORK_DIR"
print_success "Fully bootable backup USB created!"
print_success "USB: $USB_DRIVE"
echo
print_success "WHAT YOU CAN NOW DO:"
print_success "1. Boot from this USB in BIOS/UEFI menu"
print_success "2. Select 'Automatic System Backup' from GRUB menu"
print_success "3. Choose source and target drives from interactive menu"
print_success "4. Backup runs automatically with progress display"
print_success "5. System shuts down when complete"
echo
print_warning "The USB remains bootable for future backups!"
print_warning "Your backup tools are preserved in the data partition"
EOF