- Move all old complex backup scripts to old_scripts/ - Archive previous documentation versions - Clean up temporary files and debian packages - Update README to focus on new simple system - Keep only the enhanced simple backup system in main directory Main directory now contains only: - simple_backup_gui.py (GUI interface) - enhanced_simple_backup.sh (CLI interface) - list_drives.sh (helper) - simple_backup.sh (basic CLI) - SIMPLE_BACKUP_README.md (detailed docs) - README.md (project overview)
389 lines
12 KiB
Bash
389 lines
12 KiB
Bash
#!/bin/bash
|
|
|
|
# Boot Repair and Emergency Recovery Tools
|
|
# Provides tools to fix boot issues after cloning
|
|
|
|
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
|
|
|
|
TARGET_DRIVE=""
|
|
WORK_DIR="/mnt/repair_work"
|
|
|
|
log() {
|
|
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $1" >&2
|
|
exit 1
|
|
}
|
|
|
|
warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
detect_target_drive() {
|
|
log "Detecting target drive to repair..."
|
|
|
|
# List available drives
|
|
echo "Available drives:"
|
|
lsblk -dpno NAME,SIZE,MODEL | grep -v "loop\|ram"
|
|
echo
|
|
|
|
read -p "Enter the drive to repair (e.g., /dev/sdb): " TARGET_DRIVE
|
|
|
|
if [ ! -b "$TARGET_DRIVE" ]; then
|
|
error "Drive $TARGET_DRIVE not found"
|
|
fi
|
|
|
|
echo "Selected drive for repair: $TARGET_DRIVE"
|
|
lsblk "$TARGET_DRIVE"
|
|
echo
|
|
|
|
read -p "Is this correct? [y/N]: " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
error "Operation cancelled"
|
|
fi
|
|
|
|
success "Target drive selected: $TARGET_DRIVE"
|
|
}
|
|
|
|
mount_target_system() {
|
|
log "Mounting target system for repair..."
|
|
|
|
mkdir -p "$WORK_DIR"
|
|
|
|
# Find partitions
|
|
local partitions=($(lsblk -pno NAME "$TARGET_DRIVE" | grep -v "^$TARGET_DRIVE$"))
|
|
local root_partition=""
|
|
local boot_partition=""
|
|
local efi_partition=""
|
|
|
|
for part in "${partitions[@]}"; do
|
|
local fstype=$(lsblk -no FSTYPE "$part")
|
|
local size_bytes=$(lsblk -bno SIZE "$part")
|
|
|
|
# Detect partitions by filesystem and size
|
|
if [[ "$fstype" == "vfat" && "$size_bytes" -lt 1073741824 ]]; then # Less than 1GB
|
|
efi_partition="$part"
|
|
elif [[ "$fstype" == "ext4" && "$size_bytes" -lt 5368709120 ]]; then # Between 100MB and 5GB
|
|
boot_partition="$part"
|
|
elif [[ "$fstype" == "ext4" && "$size_bytes" -gt 5368709120 ]]; then # Larger than 5GB
|
|
root_partition="$part"
|
|
elif [[ "$fstype" == "crypto_LUKS" ]]; then
|
|
# Try to unlock encrypted partition
|
|
local crypt_name="repair_$(basename "$part")"
|
|
echo "Found encrypted partition: $part"
|
|
echo "Please enter the password to unlock for repair:"
|
|
if cryptsetup open "$part" "$crypt_name"; then
|
|
local decrypted_fs=$(lsblk -no FSTYPE "/dev/mapper/$crypt_name")
|
|
if [[ "$decrypted_fs" == "ext4" ]]; then
|
|
root_partition="/dev/mapper/$crypt_name"
|
|
log "Using decrypted partition as root: $root_partition"
|
|
fi
|
|
else
|
|
warning "Could not unlock encrypted partition"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ -z "$root_partition" ]; then
|
|
error "Could not find root partition to repair"
|
|
fi
|
|
|
|
# Mount filesystems
|
|
log "Mounting root partition: $root_partition"
|
|
mount "$root_partition" "$WORK_DIR" || error "Failed to mount root partition"
|
|
|
|
if [ -n "$boot_partition" ]; then
|
|
log "Mounting boot partition: $boot_partition"
|
|
mkdir -p "$WORK_DIR/boot"
|
|
mount "$boot_partition" "$WORK_DIR/boot" || warning "Failed to mount boot partition"
|
|
fi
|
|
|
|
if [ -n "$efi_partition" ]; then
|
|
log "Mounting EFI partition: $efi_partition"
|
|
mkdir -p "$WORK_DIR/boot/efi"
|
|
mount "$efi_partition" "$WORK_DIR/boot/efi" || warning "Failed to mount EFI partition"
|
|
fi
|
|
|
|
success "Target system mounted at $WORK_DIR"
|
|
}
|
|
|
|
repair_grub() {
|
|
log "Repairing GRUB bootloader..."
|
|
|
|
# Bind mount necessary filesystems
|
|
mount --bind /dev "$WORK_DIR/dev"
|
|
mount --bind /proc "$WORK_DIR/proc"
|
|
mount --bind /sys "$WORK_DIR/sys"
|
|
mount --bind /run "$WORK_DIR/run"
|
|
|
|
# Repair GRUB
|
|
chroot "$WORK_DIR" /bin/bash -c "
|
|
echo 'Updating initramfs...'
|
|
update-initramfs -u -k all
|
|
|
|
echo 'Reinstalling GRUB...'
|
|
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian --recheck $TARGET_DRIVE
|
|
|
|
echo 'Updating GRUB configuration...'
|
|
update-grub
|
|
|
|
echo 'GRUB repair completed'
|
|
"
|
|
|
|
# Unmount bind mounts
|
|
umount "$WORK_DIR/dev" 2>/dev/null || true
|
|
umount "$WORK_DIR/proc" 2>/dev/null || true
|
|
umount "$WORK_DIR/sys" 2>/dev/null || true
|
|
umount "$WORK_DIR/run" 2>/dev/null || true
|
|
|
|
success "GRUB repair completed"
|
|
}
|
|
|
|
fix_fstab() {
|
|
log "Checking and fixing /etc/fstab..."
|
|
|
|
if [ ! -f "$WORK_DIR/etc/fstab" ]; then
|
|
warning "/etc/fstab not found"
|
|
return 0
|
|
fi
|
|
|
|
# Backup current fstab
|
|
cp "$WORK_DIR/etc/fstab" "$WORK_DIR/etc/fstab.backup.$(date +%Y%m%d_%H%M%S)"
|
|
|
|
# Get current UUIDs of all partitions
|
|
local partitions=($(lsblk -pno NAME "$TARGET_DRIVE" | grep -v "^$TARGET_DRIVE$"))
|
|
|
|
echo "Current partition UUIDs:"
|
|
for part in "${partitions[@]}"; do
|
|
local uuid=$(lsblk -no UUID "$part")
|
|
local fstype=$(lsblk -no FSTYPE "$part")
|
|
if [ -n "$uuid" ]; then
|
|
echo " $part ($fstype): $uuid"
|
|
fi
|
|
done
|
|
|
|
echo
|
|
echo "Current /etc/fstab content:"
|
|
cat "$WORK_DIR/etc/fstab"
|
|
echo
|
|
|
|
read -p "Do you want to regenerate /etc/fstab with current UUIDs? [y/N]: " -n 1 -r
|
|
echo
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
# Generate new fstab
|
|
echo "# /etc/fstab: static file system information." > "$WORK_DIR/etc/fstab.new"
|
|
echo "# Regenerated by repair script on $(date)" >> "$WORK_DIR/etc/fstab.new"
|
|
echo "#" >> "$WORK_DIR/etc/fstab.new"
|
|
echo "# <file system> <mount point> <type> <options> <dump> <pass>" >> "$WORK_DIR/etc/fstab.new"
|
|
|
|
for part in "${partitions[@]}"; do
|
|
local uuid=$(lsblk -no UUID "$part")
|
|
local fstype=$(lsblk -no FSTYPE "$part")
|
|
|
|
if [ -n "$uuid" ]; then
|
|
case "$fstype" in
|
|
"vfat")
|
|
echo "UUID=$uuid /boot/efi vfat defaults 0 2" >> "$WORK_DIR/etc/fstab.new"
|
|
;;
|
|
"ext4")
|
|
# Determine if it's boot or root by size
|
|
local size_bytes=$(lsblk -bno SIZE "$part")
|
|
if [ "$size_bytes" -lt 5368709120 ]; then # Less than 5GB = boot
|
|
echo "UUID=$uuid /boot ext4 defaults 0 2" >> "$WORK_DIR/etc/fstab.new"
|
|
else # Root partition
|
|
echo "UUID=$uuid / ext4 defaults 0 1" >> "$WORK_DIR/etc/fstab.new"
|
|
fi
|
|
;;
|
|
"swap")
|
|
echo "UUID=$uuid none swap sw 0 0" >> "$WORK_DIR/etc/fstab.new"
|
|
;;
|
|
esac
|
|
fi
|
|
done
|
|
|
|
# Add tmpfs
|
|
echo "tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0" >> "$WORK_DIR/etc/fstab.new"
|
|
|
|
# Show new fstab
|
|
echo
|
|
echo "New /etc/fstab content:"
|
|
cat "$WORK_DIR/etc/fstab.new"
|
|
echo
|
|
|
|
read -p "Apply this new /etc/fstab? [y/N]: " -n 1 -r
|
|
echo
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
mv "$WORK_DIR/etc/fstab.new" "$WORK_DIR/etc/fstab"
|
|
success "/etc/fstab updated"
|
|
else
|
|
rm "$WORK_DIR/etc/fstab.new"
|
|
log "New fstab not applied"
|
|
fi
|
|
fi
|
|
|
|
success "fstab check completed"
|
|
}
|
|
|
|
check_boot_configuration() {
|
|
log "Checking boot configuration..."
|
|
|
|
# Check if EFI boot entry exists
|
|
if command -v efibootmgr >/dev/null 2>&1; then
|
|
echo "Current EFI boot entries:"
|
|
efibootmgr
|
|
echo
|
|
fi
|
|
|
|
# Check GRUB configuration
|
|
if [ -f "$WORK_DIR/etc/default/grub" ]; then
|
|
echo "GRUB configuration (/etc/default/grub):"
|
|
cat "$WORK_DIR/etc/default/grub"
|
|
echo
|
|
fi
|
|
|
|
# Check if initramfs exists
|
|
echo "Available kernels and initramfs:"
|
|
ls -la "$WORK_DIR/boot/vmlinuz-"* 2>/dev/null || echo "No kernels found"
|
|
ls -la "$WORK_DIR/boot/initrd.img-"* 2>/dev/null || echo "No initramfs found"
|
|
echo
|
|
|
|
success "Boot configuration check completed"
|
|
}
|
|
|
|
regenerate_initramfs() {
|
|
log "Regenerating initramfs..."
|
|
|
|
# Bind mount necessary filesystems
|
|
mount --bind /dev "$WORK_DIR/dev"
|
|
mount --bind /proc "$WORK_DIR/proc"
|
|
mount --bind /sys "$WORK_DIR/sys"
|
|
mount --bind /run "$WORK_DIR/run"
|
|
|
|
chroot "$WORK_DIR" /bin/bash -c "
|
|
echo 'Regenerating initramfs for all kernels...'
|
|
update-initramfs -u -k all
|
|
echo 'Initramfs regeneration completed'
|
|
"
|
|
|
|
# Unmount bind mounts
|
|
umount "$WORK_DIR/dev" 2>/dev/null || true
|
|
umount "$WORK_DIR/proc" 2>/dev/null || true
|
|
umount "$WORK_DIR/sys" 2>/dev/null || true
|
|
umount "$WORK_DIR/run" 2>/dev/null || true
|
|
|
|
success "Initramfs regenerated"
|
|
}
|
|
|
|
cleanup_repair() {
|
|
log "Cleaning up repair environment..."
|
|
|
|
# Unmount all filesystems
|
|
umount "$WORK_DIR/boot/efi" 2>/dev/null || true
|
|
umount "$WORK_DIR/boot" 2>/dev/null || true
|
|
umount "$WORK_DIR" 2>/dev/null || true
|
|
|
|
# Close encrypted volumes
|
|
for mapper in /dev/mapper/repair_*; do
|
|
if [ -b "$mapper" ]; then
|
|
local crypt_name=$(basename "$mapper")
|
|
cryptsetup close "$crypt_name" 2>/dev/null || true
|
|
fi
|
|
done
|
|
|
|
# Remove work directory
|
|
rmdir "$WORK_DIR" 2>/dev/null || true
|
|
|
|
success "Cleanup completed"
|
|
}
|
|
|
|
main() {
|
|
echo -e "${GREEN}=== Boot Repair and Emergency Recovery Tools ===${NC}"
|
|
echo "This script helps fix boot issues after cloning"
|
|
echo
|
|
|
|
echo "Available repair options:"
|
|
echo "1. Full repair (mount system, fix fstab, repair GRUB, regenerate initramfs)"
|
|
echo "2. GRUB repair only"
|
|
echo "3. fstab fix only"
|
|
echo "4. Initramfs regeneration only"
|
|
echo "5. Check boot configuration"
|
|
echo
|
|
|
|
read -p "Select repair option [1-5]: " -n 1 -r
|
|
echo
|
|
|
|
case $REPLY in
|
|
1)
|
|
log "Performing full repair..."
|
|
detect_target_drive
|
|
mount_target_system
|
|
fix_fstab
|
|
regenerate_initramfs
|
|
repair_grub
|
|
check_boot_configuration
|
|
cleanup_repair
|
|
success "Full repair completed!"
|
|
;;
|
|
2)
|
|
log "Performing GRUB repair only..."
|
|
detect_target_drive
|
|
mount_target_system
|
|
repair_grub
|
|
cleanup_repair
|
|
success "GRUB repair completed!"
|
|
;;
|
|
3)
|
|
log "Fixing fstab only..."
|
|
detect_target_drive
|
|
mount_target_system
|
|
fix_fstab
|
|
cleanup_repair
|
|
success "fstab fix completed!"
|
|
;;
|
|
4)
|
|
log "Regenerating initramfs only..."
|
|
detect_target_drive
|
|
mount_target_system
|
|
regenerate_initramfs
|
|
cleanup_repair
|
|
success "Initramfs regeneration completed!"
|
|
;;
|
|
5)
|
|
log "Checking boot configuration..."
|
|
detect_target_drive
|
|
mount_target_system
|
|
check_boot_configuration
|
|
cleanup_repair
|
|
success "Boot configuration check completed!"
|
|
;;
|
|
*)
|
|
error "Invalid option selected"
|
|
;;
|
|
esac
|
|
|
|
echo
|
|
echo -e "${BLUE}Repair completed. Next steps:${NC}"
|
|
echo "1. Reboot your system"
|
|
echo "2. Set the repaired drive as first boot device in BIOS/UEFI"
|
|
echo "3. Try booting from the external drive"
|
|
echo "4. If issues persist, run this script again or check system logs"
|
|
}
|
|
|
|
# Trap to ensure cleanup on exit
|
|
trap cleanup_repair EXIT
|
|
|
|
main "$@" |