diff --git a/README_BACKUP.md b/README_BACKUP.md new file mode 100644 index 0000000..99545a2 --- /dev/null +++ b/README_BACKUP.md @@ -0,0 +1,49 @@ +# LVM Block-Level Backup Tool + +## What This Does + +This tool performs a **proper** LVM snapshot backup by: + +1. ✅ Creating consistent LVM snapshots of your internal drive +2. ✅ Cloning entire volumes **block-for-block** to external drive +3. ✅ Creating an exact, bootable copy of your system +4. ✅ Using full drive capacity efficiently + +## Why This Is Better + +- **Fast**: Block-level copying is much faster than file copying +- **Complete**: Exact bit-for-bit copy including all metadata +- **Bootable**: External drive can boot your system directly +- **Space Efficient**: Uses full drive capacity, no filesystem overhead +- **Consistent**: Snapshots ensure data consistency during backup + +## Usage + +```bash +# Simple one-command backup +sudo ./lvm_block_backup.sh +``` + +## Requirements + +- Both drives must have LVM setup +- External drive volume group: `migration-vg` +- Internal drive volume group: `internal-vg` +- At least 6GB free space for snapshots + +## What Gets Backed Up + +- **Root volume**: Complete system, applications, configurations +- **Home volume**: All user data (including encrypted LUKS) +- **Boot volume**: Kernels, bootloader, boot configuration + +## Result + +After backup, your external drive contains an exact copy that can: +- Boot independently from BIOS/UEFI menu +- Be mounted to access files +- Serve as complete system recovery + +--- + +**Note**: The `old_scripts/` directory contains 40+ previous backup attempts that didn't work properly. This single script replaces all of them. \ No newline at end of file diff --git a/__pycache__/backup_manager.cpython-312.pyc b/__pycache__/backup_manager.cpython-312.pyc deleted file mode 100644 index f40f97d..0000000 Binary files a/__pycache__/backup_manager.cpython-312.pyc and /dev/null differ diff --git a/backup_manager.py b/backup_manager.py deleted file mode 100755 index f23f15a..0000000 --- a/backup_manager.py +++ /dev/null @@ -1,1079 +0,0 @@ -#!/usr/bin/env python3 -""" -Linux System Backup Tool with GUI -A tool for creating full system backups to external M.2 SSD with reboot functionality. -""" - -import tkinter as tk -from tkinter import ttk, messagebox, scrolledtext -import subprocess -import threading -import os -import sys -import time -from pathlib import Path - -class BackupManager: - def __init__(self): - self.root = tk.Tk() - self.root.title("System Backup Manager") - self.root.geometry("600x500") - self.root.resizable(True, True) - - # Variables - self.source_drive = tk.StringVar() # Will be auto-detected - self.target_drive = tk.StringVar() - self.operation_running = False - self.operation_type = "backup" # "backup" or "restore" - self.sync_mode = "full" # "full", "sync", or "auto" - - self.setup_ui() - self.detect_drives() - - def setup_ui(self): - """Setup the user interface""" - # Main frame - main_frame = ttk.Frame(self.root, padding="10") - main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) - - # Configure grid weights - self.root.columnconfigure(0, weight=1) - self.root.rowconfigure(0, weight=1) - main_frame.columnconfigure(1, weight=1) - - # Title - title_label = ttk.Label(main_frame, text="System Backup Manager", - font=("Arial", 16, "bold")) - title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20)) - - # Source drive selection - ttk.Label(main_frame, text="Source Drive (Internal):").grid(row=1, column=0, sticky=tk.W, pady=5) - source_combo = ttk.Combobox(main_frame, textvariable=self.source_drive, width=40) - source_combo.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0)) - - # Target drive selection - ttk.Label(main_frame, text="Target Drive (External M.2):").grid(row=2, column=0, sticky=tk.W, pady=5) - target_combo = ttk.Combobox(main_frame, textvariable=self.target_drive, width=40) - target_combo.grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5, padx=(10, 0)) - - # Refresh drives button - refresh_btn = ttk.Button(main_frame, text="Refresh Drives", command=self.detect_drives) - refresh_btn.grid(row=3, column=1, sticky=tk.E, pady=10, padx=(10, 0)) - - # Status frame - status_frame = ttk.LabelFrame(main_frame, text="Status", padding="10") - status_frame.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10) - status_frame.columnconfigure(0, weight=1) - status_frame.rowconfigure(0, weight=1) - - # Log area - self.log_text = scrolledtext.ScrolledText(status_frame, height=15, width=60) - self.log_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) - - # Button frame - button_frame = ttk.Frame(main_frame) - button_frame.grid(row=5, column=0, columnspan=2, pady=20) - - # Backup buttons - backup_frame = ttk.LabelFrame(button_frame, text="Backup Operations", padding="10") - backup_frame.pack(side=tk.LEFT, padx=5) - - self.sync_backup_btn = ttk.Button(backup_frame, text="Smart Sync Backup", - command=self.smart_sync_backup, style="Accent.TButton") - self.sync_backup_btn.pack(side=tk.TOP, pady=2) - - self.backup_btn = ttk.Button(backup_frame, text="Full Clone Backup", - command=self.start_backup) - self.backup_btn.pack(side=tk.TOP, pady=2) - - self.reboot_backup_btn = ttk.Button(backup_frame, text="Reboot & Full Clone", - command=self.reboot_and_backup) - self.reboot_backup_btn.pack(side=tk.TOP, pady=2) - - # Restore buttons - restore_frame = ttk.LabelFrame(button_frame, text="Restore Operations", padding="10") - restore_frame.pack(side=tk.LEFT, padx=5) - - self.restore_btn = ttk.Button(restore_frame, text="Restore from External", - command=self.start_restore) - self.restore_btn.pack(side=tk.TOP, pady=2) - - self.reboot_restore_btn = ttk.Button(restore_frame, text="Reboot & Restore", - command=self.reboot_and_restore) - self.reboot_restore_btn.pack(side=tk.TOP, pady=2) - - # Control buttons - control_frame = ttk.Frame(button_frame) - control_frame.pack(side=tk.LEFT, padx=5) - - self.stop_btn = ttk.Button(control_frame, text="Stop", command=self.stop_operation, state="disabled") - self.stop_btn.pack(side=tk.TOP, pady=2) - - self.swap_btn = ttk.Button(control_frame, text="Swap Source↔Target", command=self.swap_drives) - self.swap_btn.pack(side=tk.TOP, pady=2) - - self.analyze_btn = ttk.Button(control_frame, text="Analyze Changes", command=self.analyze_changes) - self.analyze_btn.pack(side=tk.TOP, pady=2) - - # Progress bar - self.progress = ttk.Progressbar(main_frame, mode='indeterminate') - self.progress.grid(row=6, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10) - - # Store combo references for updating - self.source_combo = source_combo - self.target_combo = target_combo - - # Add initial log message - self.log("System Backup Manager initialized") - self.log("Select source and target drives, then click 'Start Backup' or 'Reboot & Backup'") - - def log(self, message): - """Add message to log with timestamp""" - timestamp = time.strftime("%H:%M:%S") - self.log_text.insert(tk.END, f"[{timestamp}] {message}\n") - self.log_text.see(tk.END) - self.root.update_idletasks() - - def get_root_drive(self): - """Get the drive containing the root filesystem""" - try: - # Find the device containing the root filesystem - result = subprocess.run(['df', '/'], capture_output=True, text=True) - lines = result.stdout.strip().split('\n') - if len(lines) > 1: - device = lines[1].split()[0] - # Remove partition number to get base device - import re - base_device = re.sub(r'[0-9]+$', '', device) - # Handle nvme drives (e.g., /dev/nvme0n1p1 -> /dev/nvme0n1) - base_device = re.sub(r'p[0-9]+$', '', base_device) - return base_device - except Exception as e: - self.log(f"Error detecting root drive: {e}") - return None - - def detect_drives(self): - """Detect available drives""" - try: - self.log("Detecting available drives...") - - # First, detect the root filesystem drive - root_drive = self.get_root_drive() - if root_drive: - self.log(f"Detected root filesystem on: {root_drive}") - - # Get block devices with more information - result = subprocess.run(['lsblk', '-d', '-n', '-o', 'NAME,SIZE,TYPE,TRAN,HOTPLUG'], - capture_output=True, text=True) - - internal_drives = [] - external_drives = [] - all_drives = [] - root_drive_info = None - - for line in result.stdout.strip().split('\n'): - if line and 'disk' in line: - parts = line.split() - if len(parts) >= 3: - name = f"/dev/{parts[0]}" - size = parts[1] - transport = parts[3] if len(parts) > 3 else "" - hotplug = parts[4] if len(parts) > 4 else "0" - - drive_info = f"{name} ({size})" - all_drives.append(drive_info) - - # Check if this is the root drive and mark it - if root_drive and name == root_drive: - drive_info = f"{name} ({size}) [SYSTEM]" - root_drive_info = drive_info - self.log(f"Root drive found: {drive_info}") - - # Classify drives - if transport in ['usb', 'uas'] or hotplug == "1": - external_drives.append(drive_info) - self.log(f"External drive detected: {drive_info}") - else: - internal_drives.append(drive_info) - self.log(f"Internal drive detected: {drive_info}") - - # Auto-select root drive as source if found, otherwise first internal - if root_drive_info: - self.source_drive.set(root_drive_info) - self.log(f"Auto-selected root drive as source: {root_drive_info}") - elif internal_drives: - self.source_drive.set(internal_drives[0]) - self.log(f"Auto-selected internal drive as source: {internal_drives[0]}") - - # Update combo boxes - put internal drives first for source - self.source_combo['values'] = internal_drives + external_drives - self.target_combo['values'] = external_drives + internal_drives # Prefer external for target - - # If there's an external drive, auto-select it as target - if external_drives: - self.target_drive.set(external_drives[0]) - self.log(f"Auto-selected external drive as target: {external_drives[0]}") - - self.log(f"Found {len(internal_drives)} internal and {len(external_drives)} external drives") - - except Exception as e: - self.log(f"Error detecting drives: {e}") - - def validate_selection(self): - """Validate drive selection""" - source = self.source_drive.get().split()[0] if self.source_drive.get() else "" - target = self.target_drive.get().split()[0] if self.target_drive.get() else "" - - if not source: - messagebox.showerror("Error", "Please select a source drive") - return False - - if not target: - messagebox.showerror("Error", "Please select a target drive") - return False - - if source == target: - messagebox.showerror("Error", "Source and target drives cannot be the same") - return False - - # Check if drives exist - if not os.path.exists(source): - messagebox.showerror("Error", f"Source drive {source} does not exist") - return False - - if not os.path.exists(target): - messagebox.showerror("Error", f"Target drive {target} does not exist") - return False - - return True - - def analyze_changes(self): - """Analyze changes between source and target drives""" - if not self.validate_selection(): - return - - # Get drive paths - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - - self.run_backup_script("analyze", source, target) - - def run_change_analysis(self, source, target): - """Run change analysis in background""" - try: - # Check if target has existing backup - backup_info = self.check_existing_backup(target) - - if not backup_info['has_backup']: - self.log("No existing backup found. Full clone required.") - return - - self.log(f"Found existing backup from: {backup_info['backup_date']}") - - # Mount both filesystems to compare - changes = self.compare_filesystems(source, target) - - self.log(f"Analysis complete:") - self.log(f" Files changed: {changes['files_changed']}") - self.log(f" Files added: {changes['files_added']}") - self.log(f" Files deleted: {changes['files_deleted']}") - self.log(f" Total size changed: {changes['size_changed_mb']:.1f} MB") - self.log(f" Recommended action: {changes['recommendation']}") - - # Show recommendation - if changes['recommendation'] == 'sync': - messagebox.showinfo("Analysis Complete", - f"Smart Sync Recommended\n\n" - f"Changes detected: {changes['files_changed']} files\n" - f"Size to sync: {changes['size_changed_mb']:.1f} MB\n" - f"Estimated time: {changes['estimated_time_min']:.1f} minutes\n\n" - f"This is much faster than full clone!") - else: - messagebox.showinfo("Analysis Complete", - f"Full Clone Recommended\n\n" - f"Reason: {changes['reason']}\n" - f"Use 'Full Clone Backup' for best results.") - - except Exception as e: - self.log(f"Error during analysis: {e}") - messagebox.showerror("Analysis Error", f"Could not analyze changes: {e}") - - def smart_sync_backup(self): - """Start smart sync backup operation""" - if not self.validate_selection(): - return - - # Get drive paths - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - - # Confirm operation - result = messagebox.askyesno( - "Confirm Smart Sync Backup", - f"Perform smart sync backup?\n\n" - f"Source: {source}\n" - f"Target: {target}\n\n" - f"This will quickly update the target drive with changes from the source.\n" - f"The operation is much faster than a full backup but requires an existing backup on the target." - ) - - if result: - self.run_backup_script("sync", source, target) - - def run_backup_script(self, mode, source, target): - """Run the backup script with specified mode""" - try: - # Clear previous output - self.log_text.delete(1.0, tk.END) - - # Determine command arguments - if mode == "analyze": - cmd = ['sudo', './backup_script.sh', '--analyze', '--source', source, '--target', target] - self.log("🔍 Analyzing changes between drives...") - elif mode == "sync": - cmd = ['sudo', './backup_script.sh', '--sync', '--source', source, '--target', target] - self.log("⚡ Starting smart sync backup...") - elif mode == "backup": - cmd = ['sudo', './backup_script.sh', '--source', source, '--target', target] - self.log("🔄 Starting full backup...") - elif mode == "restore": - cmd = ['sudo', './backup_script.sh', '--restore', '--source', source, '--target', target] - self.log("🔧 Starting restore operation...") - else: - raise ValueError(f"Unknown mode: {mode}") - - # Change to script directory - script_dir = os.path.dirname(os.path.abspath(__file__)) - - # Run the command - process = subprocess.Popen( - cmd, - cwd=script_dir, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True, - bufsize=1 - ) - - # Monitor progress in real-time - while True: - output = process.stdout.readline() - if output == '' and process.poll() is not None: - break - if output: - # Update GUI in real-time - self.log_text.insert(tk.END, output) - self.log_text.see(tk.END) - self.root.update() - - # Get final result - return_code = process.poll() - - if return_code == 0: - if mode == "analyze": - self.log("✅ Analysis completed successfully!") - messagebox.showinfo("Analysis Complete", "Drive analysis completed. Check the output for recommendations.") - elif mode == "sync": - self.log("✅ Smart sync completed successfully!") - messagebox.showinfo("Success", "Smart sync backup completed successfully!") - elif mode == "backup": - self.log("✅ Backup completed successfully!") - messagebox.showinfo("Success", "Full backup completed successfully!") - elif mode == "restore": - self.log("✅ Restore completed successfully!") - messagebox.showinfo("Success", "System restore completed successfully!") - else: - self.log(f"❌ {mode.title()} operation failed!") - messagebox.showerror("Error", f"{mode.title()} operation failed. Check the output for details.") - - except Exception as e: - error_msg = f"Error running {mode} operation: {str(e)}" - self.log(f"❌ {error_msg}") - messagebox.showerror("Error", error_msg) - - def check_existing_backup(self, target_drive): - """Check if target drive has existing backup and get info""" - try: - # Try to mount the target drive temporarily - temp_mount = f"/tmp/backup_check_{os.getpid()}" - os.makedirs(temp_mount, exist_ok=True) - - # Find the main partition (usually partition 1) - partitions = subprocess.run(['lsblk', '-n', '-o', 'NAME', target_drive], - capture_output=True, text=True).stdout.strip().split('\n') - - main_partition = None - for partition in partitions: - if partition.strip() and partition.strip() != os.path.basename(target_drive): - main_partition = f"/dev/{partition.strip()}" - break - - if not main_partition: - return {'has_backup': False, 'reason': 'No partitions found'} - - # Try to mount and check - try: - subprocess.run(['sudo', 'mount', '-o', 'ro', main_partition, temp_mount], - check=True, capture_output=True) - - # Check if it looks like a Linux system - has_backup = (os.path.exists(os.path.join(temp_mount, 'etc')) and - os.path.exists(os.path.join(temp_mount, 'home')) and - os.path.exists(os.path.join(temp_mount, 'usr'))) - - backup_date = "Unknown" - if has_backup: - # Try to get last modification time of /etc - try: - etc_stat = os.stat(os.path.join(temp_mount, 'etc')) - backup_date = time.strftime('%Y-%m-%d %H:%M', time.localtime(etc_stat.st_mtime)) - except: - pass - - return { - 'has_backup': has_backup, - 'backup_date': backup_date, - 'main_partition': main_partition - } - - finally: - subprocess.run(['sudo', 'umount', temp_mount], capture_output=True) - os.rmdir(temp_mount) - - except Exception as e: - return {'has_backup': False, 'reason': f'Mount error: {e}'} - - def compare_filesystems(self, source_drive, target_drive): - """Compare filesystems to determine sync requirements""" - try: - # Get basic change information using filesystem comparison - # This is a simplified analysis - in practice you'd want more sophisticated comparison - - # Check filesystem sizes - source_size = self.get_filesystem_usage(source_drive) - target_info = self.check_existing_backup(target_drive) - - if not target_info['has_backup']: - return { - 'recommendation': 'full', - 'reason': 'No existing backup', - 'files_changed': 0, - 'files_added': 0, - 'files_deleted': 0, - 'size_changed_mb': 0, - 'estimated_time_min': 0, - 'full_clone_time_min': source_size['total_gb'] * 2 # Rough estimate - } - - target_size = self.get_filesystem_usage(target_drive) - - # Simple heuristic based on size difference - size_diff_gb = abs(source_size['used_gb'] - target_size['used_gb']) - size_change_percent = (size_diff_gb / max(source_size['used_gb'], 0.1)) * 100 - - # Estimate file changes (rough approximation) - estimated_files_changed = int(size_diff_gb * 1000) # Assume 1MB per file average - estimated_sync_time = size_diff_gb * 1.5 # 1.5 minutes per GB for sync - estimated_full_time = source_size['total_gb'] * 2 # 2 minutes per GB for full clone - - # Decision logic - if size_change_percent < 5 and size_diff_gb < 2: - recommendation = 'sync' - reason = 'Minor changes detected' - elif size_change_percent < 15 and size_diff_gb < 10: - recommendation = 'sync' - reason = 'Moderate changes, sync beneficial' - else: - recommendation = 'full' - reason = 'Major changes detected, full clone safer' - - return { - 'recommendation': recommendation, - 'reason': reason, - 'files_changed': estimated_files_changed, - 'files_added': max(0, estimated_files_changed // 2), - 'files_deleted': max(0, estimated_files_changed // 4), - 'size_changed_mb': size_diff_gb * 1024, - 'estimated_time_min': estimated_sync_time, - 'full_clone_time_min': estimated_full_time - } - - except Exception as e: - return { - 'recommendation': 'full', - 'reason': f'Analysis failed: {e}', - 'files_changed': 0, - 'files_added': 0, - 'files_deleted': 0, - 'size_changed_mb': 0, - 'estimated_time_min': 0, - 'full_clone_time_min': 60 - } - - def get_filesystem_usage(self, drive): - """Get filesystem usage information""" - try: - # Mount temporarily and get usage - temp_mount = f"/tmp/fs_check_{os.getpid()}" - os.makedirs(temp_mount, exist_ok=True) - - # Find main partition - partitions = subprocess.run(['lsblk', '-n', '-o', 'NAME', drive], - capture_output=True, text=True).stdout.strip().split('\n') - - main_partition = None - for partition in partitions: - if partition.strip() and partition.strip() != os.path.basename(drive): - main_partition = f"/dev/{partition.strip()}" - break - - if not main_partition: - return {'total_gb': 0, 'used_gb': 0, 'free_gb': 0} - - try: - subprocess.run(['sudo', 'mount', '-o', 'ro', main_partition, temp_mount], - check=True, capture_output=True) - - # Get filesystem usage - statvfs = os.statvfs(temp_mount) - total_bytes = statvfs.f_frsize * statvfs.f_blocks - free_bytes = statvfs.f_frsize * statvfs.f_available - used_bytes = total_bytes - free_bytes - - return { - 'total_gb': total_bytes / (1024**3), - 'used_gb': used_bytes / (1024**3), - 'free_gb': free_bytes / (1024**3) - } - - finally: - subprocess.run(['sudo', 'umount', temp_mount], capture_output=True) - os.rmdir(temp_mount) - - except Exception: - # Fallback to drive size - try: - size_bytes = int(subprocess.run(['blockdev', '--getsize64', drive], - capture_output=True, text=True).stdout.strip()) - total_gb = size_bytes / (1024**3) - return {'total_gb': total_gb, 'used_gb': total_gb * 0.7, 'free_gb': total_gb * 0.3} - except: - return {'total_gb': 500, 'used_gb': 350, 'free_gb': 150} # Default estimates - - def start_sync_operation(self, source, target, changes): - """Start smart sync operation""" - self.operation_running = True - self.sync_backup_btn.config(state="disabled") - self.backup_btn.config(state="disabled") - self.reboot_backup_btn.config(state="disabled") - self.restore_btn.config(state="disabled") - self.reboot_restore_btn.config(state="disabled") - self.stop_btn.config(state="normal") - self.progress.start() - - sync_thread = threading.Thread(target=self.run_sync_operation, args=(source, target, changes)) - sync_thread.daemon = True - sync_thread.start() - - def run_sync_operation(self, source, target, changes): - """Swap source and target drives""" - source = self.source_drive.get() - target = self.target_drive.get() - - self.source_drive.set(target) - self.target_drive.set(source) - - self.log("Swapped source and target drives") - - def run_sync_operation(self, source, target, changes): - """Run smart filesystem sync operation""" - try: - self.log("Starting smart sync operation...") - self.log(f"Syncing {changes['size_changed_mb']:.1f} MB of changes...") - - # Mount both filesystems - source_mount = f"/tmp/sync_source_{os.getpid()}" - target_mount = f"/tmp/sync_target_{os.getpid()}" - - os.makedirs(source_mount, exist_ok=True) - os.makedirs(target_mount, exist_ok=True) - - # Find main partitions - source_partitions = subprocess.run(['lsblk', '-n', '-o', 'NAME', source], - capture_output=True, text=True).stdout.strip().split('\n') - target_partitions = subprocess.run(['lsblk', '-n', '-o', 'NAME', target], - capture_output=True, text=True).stdout.strip().split('\n') - - source_partition = f"/dev/{[p.strip() for p in source_partitions if p.strip() and p.strip() != os.path.basename(source)][0]}" - target_partition = f"/dev/{[p.strip() for p in target_partitions if p.strip() and p.strip() != os.path.basename(target)][0]}" - - try: - # Mount filesystems - subprocess.run(['sudo', 'mount', '-o', 'ro', source_partition, source_mount], check=True) - subprocess.run(['sudo', 'mount', target_partition, target_mount], check=True) - - self.log("Filesystems mounted, starting rsync...") - - # Use rsync for efficient synchronization - rsync_cmd = [ - 'sudo', 'rsync', '-avHAXS', - '--numeric-ids', - '--delete', - '--progress', - '--exclude=/proc/*', - '--exclude=/sys/*', - '--exclude=/dev/*', - '--exclude=/tmp/*', - '--exclude=/run/*', - '--exclude=/mnt/*', - '--exclude=/media/*', - '--exclude=/lost+found', - f'{source_mount}/', - f'{target_mount}/' - ] - - self.log(f"Running rsync command") - - process = subprocess.Popen(rsync_cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, text=True, bufsize=1) - - # Read output line by line - for line in process.stdout: - if self.operation_running: - line = line.strip() - if line and not line.startswith('sent ') and not line.startswith('total size'): - self.log(f"Sync: {line}") - else: - process.terminate() - break - - process.wait() - - if process.returncode == 0 and self.operation_running: - self.log("Smart sync completed successfully!") - - # Preserve backup tools - try: - self.log("Preserving backup tools on external drive...") - restore_script = os.path.join(os.path.dirname(__file__), "restore_tools_after_backup.sh") - if os.path.exists(restore_script): - subprocess.run([restore_script, target], check=False, timeout=60) - self.log("Backup tools preserved on external drive") - except Exception as e: - self.log(f"Warning: Could not preserve tools: {e}") - - messagebox.showinfo("Success", - f"Smart Sync completed successfully!\n\n" - f"Synced: {changes['size_changed_mb']:.1f} MB\n" - f"Much faster than full clone!") - - elif not self.operation_running: - self.log("Sync operation was cancelled") - else: - self.log(f"Sync failed with return code: {process.returncode}") - messagebox.showerror("Error", "Smart sync failed! Consider using full clone backup.") - - finally: - # Unmount filesystems - subprocess.run(['sudo', 'umount', source_mount], capture_output=True) - subprocess.run(['sudo', 'umount', target_mount], capture_output=True) - os.rmdir(source_mount) - os.rmdir(target_mount) - - except Exception as e: - self.log(f"Error during smart sync: {e}") - messagebox.showerror("Error", f"Smart sync failed: {e}") - - finally: - self.operation_running = False - self.sync_backup_btn.config(state="normal") - self.backup_btn.config(state="normal") - self.reboot_backup_btn.config(state="normal") - self.restore_btn.config(state="normal") - self.reboot_restore_btn.config(state="normal") - self.stop_btn.config(state="disabled") - self.progress.stop() - - def swap_drives(self): - """Swap source and target drives""" - source = self.source_drive.get() - target = self.target_drive.get() - - self.source_drive.set(target) - self.target_drive.set(source) - - self.log("Swapped source and target drives") - - def start_restore(self): - """Start the restore process""" - if not self.validate_selection(): - return - - if self.operation_running: - self.log("Operation already running!") - return - - # Confirm restore - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - - result = messagebox.askyesno("⚠️ CONFIRM RESTORE ⚠️", - f"This will RESTORE from {source} to {target}.\n\n" - f"🚨 CRITICAL WARNING 🚨\n" - f"This will COMPLETELY OVERWRITE {target}!\n" - f"ALL DATA on {target} will be DESTROYED!\n\n" - f"This should typically restore FROM external TO internal.\n" - f"Make sure you have the drives selected correctly!\n\n" - f"Are you absolutely sure you want to continue?") - - if not result: - return - - # Second confirmation for restore - result2 = messagebox.askyesno("FINAL CONFIRMATION", - f"LAST CHANCE TO CANCEL!\n\n" - f"Restoring from: {source}\n" - f"Overwriting: {target}\n\n" - f"Type YES to continue or NO to cancel.") - - if not result2: - return - - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - self.run_backup_script("restore", source, target) - - def reboot_and_restore(self): - """Schedule reboot and restore""" - if not self.validate_selection(): - return - - result = messagebox.askyesno("⚠️ CONFIRM REBOOT & RESTORE ⚠️", - "This will:\n" - "1. Save current session\n" - "2. Reboot the system\n" - "3. Start RESTORE after reboot\n\n" - "🚨 WARNING: This will OVERWRITE your internal drive! 🚨\n\n" - "Continue?") - - if not result: - return - - try: - # Create restore script for after reboot - script_content = self.create_reboot_operation_script("restore") - - # Save script - script_path = "/tmp/restore_after_reboot.sh" - with open(script_path, 'w') as f: - f.write(script_content) - - os.chmod(script_path, 0o755) - - self.log("Reboot restore script created") - self.log("System will reboot in 5 seconds...") - - # Schedule reboot - subprocess.run(['sudo', 'shutdown', '-r', '+1'], check=True) - - self.log("Reboot scheduled. Restore will start automatically after reboot.") - - except Exception as e: - self.log(f"Error scheduling reboot: {e}") - messagebox.showerror("Error", f"Failed to schedule reboot: {e}") - - def start_backup(self): - """Start the backup process""" - if not self.validate_selection(): - return - - # Confirm backup - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - - result = messagebox.askyesno("Confirm Backup", - f"This will clone {source} to {target}.\n\n" - f"WARNING: All data on {target} will be destroyed!\n\n" - f"Are you sure you want to continue?") - - if result: - self.run_backup_script("backup", source, target) - - def start_operation(self, source, target): - """Start backup or restore operation""" - # Start operation in thread - self.operation_running = True - self.sync_backup_btn.config(state="disabled") - self.backup_btn.config(state="disabled") - self.reboot_backup_btn.config(state="disabled") - self.restore_btn.config(state="disabled") - self.reboot_restore_btn.config(state="disabled") - self.stop_btn.config(state="normal") - self.progress.start() - - operation_thread = threading.Thread(target=self.run_operation, args=(source, target, self.operation_type)) - operation_thread.daemon = True - operation_thread.start() - - def run_operation(self, source, target, operation_type): - """Run the actual backup or restore process""" - try: - if operation_type == "backup": - self.log(f"Starting backup from {source} to {target}") - else: - self.log(f"Starting restore from {source} to {target}") - - self.log("This may take a while depending on drive size...") - - # Use dd for cloning - cmd = [ - 'sudo', 'dd', - f'if={source}', - f'of={target}', - 'bs=4M', - 'status=progress', - 'conv=fdatasync' - ] - - self.log(f"Running command: {' '.join(cmd)}") - - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, text=True) - - # Read output - for line in process.stdout: - if self.operation_running: # Check if we should continue - self.log(line.strip()) - else: - process.terminate() - break - - process.wait() - - if process.returncode == 0 and self.operation_running: - if operation_type == "backup": - self.log("Backup completed successfully!") - - # Restore backup tools to external drive - try: - self.log("Preserving backup tools on external drive...") - restore_script = os.path.join(os.path.dirname(__file__), "restore_tools_after_backup.sh") - if os.path.exists(restore_script): - subprocess.run([restore_script, target], check=False, timeout=60) - self.log("Backup tools preserved on external drive") - else: - self.log("Warning: Tool restoration script not found") - except Exception as e: - self.log(f"Warning: Could not preserve tools on external drive: {e}") - - messagebox.showinfo("Success", "Backup completed successfully!\n\nBackup tools have been preserved on the external drive.") - else: - self.log("Restore completed successfully!") - messagebox.showinfo("Success", "Restore completed successfully!") - elif not self.operation_running: - self.log(f"{operation_type.capitalize()} was cancelled by user") - else: - self.log(f"{operation_type.capitalize()} failed with return code: {process.returncode}") - messagebox.showerror("Error", f"{operation_type.capitalize()} failed! Check the log for details.") - - except Exception as e: - self.log(f"Error during {operation_type}: {e}") - messagebox.showerror("Error", f"{operation_type.capitalize()} failed: {e}") - - finally: - self.operation_running = False - self.sync_backup_btn.config(state="normal") - self.backup_btn.config(state="normal") - self.reboot_backup_btn.config(state="normal") - self.restore_btn.config(state="normal") - self.reboot_restore_btn.config(state="normal") - self.stop_btn.config(state="disabled") - self.progress.stop() - - def stop_operation(self): - """Stop the current operation""" - self.operation_running = False - self.log("Stopping operation...") - - def reboot_and_backup(self): - """Schedule reboot and backup - creates systemd service for after reboot""" - if not self.validate_selection(): - return - - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - - result = messagebox.askyesno("Confirm Reboot & Backup", - f"This will:\n" - f"1. Create a one-time backup service\n" - f"2. Reboot the system\n" - f"3. Run backup before GUI starts (minimal system load)\n" - f"4. System will be available after backup completes\n\n" - f"Source: {source}\n" - f"Target: {target}\n\n" - f"⚠️ Target drive will be completely overwritten!\n\n" - f"Continue?") - - if not result: - return - - try: - # Create backup script directory - backup_dir = "/opt/backup-system" - script_dir = os.path.dirname(os.path.abspath(__file__)) - - # Create the service directory - subprocess.run(['sudo', 'mkdir', '-p', backup_dir], check=True) - - # Copy backup script to system location - subprocess.run(['sudo', 'cp', f'{script_dir}/backup_script.sh', backup_dir], check=True) - subprocess.run(['sudo', 'chmod', '+x', f'{backup_dir}/backup_script.sh'], check=True) - - # Create the backup service script - service_script = f'''#!/bin/bash -# One-time backup service script -set -e - -# Wait for system to stabilize -sleep 10 - -# Log everything -exec > /var/log/reboot-backup.log 2>&1 - -echo "Starting reboot backup at $(date)" -echo "Source: {source}" -echo "Target: {target}" - -# Run the backup -cd {backup_dir} -./backup_script.sh --source {source} --target {target} - -# Disable this service after completion -systemctl disable reboot-backup.service -rm -f /etc/systemd/system/reboot-backup.service -rm -rf {backup_dir} - -echo "Backup completed at $(date)" -echo "System ready for normal use" - -# Notify desktop (if user session exists) -if [ -n "$DISPLAY" ]; then - notify-send "Backup Complete" "System backup finished successfully" || true -fi -''' - - # Write service script - with open('/tmp/reboot-backup.sh', 'w') as f: - f.write(service_script) - - subprocess.run(['sudo', 'mv', '/tmp/reboot-backup.sh', f'{backup_dir}/reboot-backup.sh'], check=True) - subprocess.run(['sudo', 'chmod', '+x', f'{backup_dir}/reboot-backup.sh'], check=True) - - # Create systemd service - service_content = f'''[Unit] -Description=One-time System Backup After Reboot -After=multi-user.target -Wants=multi-user.target - -[Service] -Type=oneshot -ExecStart={backup_dir}/reboot-backup.sh -User=root -StandardOutput=file:/var/log/reboot-backup.log -StandardError=file:/var/log/reboot-backup.log - -[Install] -WantedBy=multi-user.target -''' - - # Write service file - with open('/tmp/reboot-backup.service', 'w') as f: - f.write(service_content) - - subprocess.run(['sudo', 'mv', '/tmp/reboot-backup.service', '/etc/systemd/system/'], check=True) - - # Enable the service for next boot only - subprocess.run(['sudo', 'systemctl', 'daemon-reload'], check=True) - subprocess.run(['sudo', 'systemctl', 'enable', 'reboot-backup.service'], check=True) - - self.log("✅ Backup service created and enabled") - self.log("📝 Backup will run automatically after reboot") - self.log("📋 Check /var/log/reboot-backup.log for progress") - - # Final confirmation - final_result = messagebox.askyesno( - "Ready to Reboot", - "Backup service is configured!\n\n" - "After reboot:\n" - "• Backup will start automatically\n" - "• Progress logged to /var/log/reboot-backup.log\n" - "• System will be available after completion\n" - "• Service will self-destruct when done\n\n" - "Reboot now?" - ) - - if final_result: - self.log("🔄 Rebooting system...") - subprocess.run(['sudo', 'systemctl', 'reboot'], check=True) - else: - self.log("⏸️ Reboot cancelled - service is ready when you reboot manually") - - except Exception as e: - self.log(f"❌ Error setting up reboot backup: {e}") - messagebox.showerror("Error", f"Failed to setup reboot backup: {e}") - - except Exception as e: - self.log(f"Error scheduling reboot: {e}") - messagebox.showerror("Error", f"Failed to schedule reboot: {e}") - - def create_reboot_operation_script(self, operation_type): - """Create script to run operation after reboot""" - source = self.source_drive.get().split()[0] - target = self.target_drive.get().split()[0] - - if operation_type == "backup": - action_desc = "backup" - success_msg = "Backup Complete" - fail_msg = "Backup Failed" - else: - action_desc = "restore" - success_msg = "Restore Complete" - fail_msg = "Restore Failed" - - script = f"""#!/bin/bash -# Auto-generated {action_desc} script - -echo "Starting {action_desc} after reboot..." -echo "Source: {source}" -echo "Target: {target}" - -# Wait for system to fully boot -sleep 30 - -# Run {action_desc} -sudo dd if={source} of={target} bs=4M status=progress conv=fdatasync - -if [ $? -eq 0 ]; then - echo "{action_desc.capitalize()} completed successfully!" - notify-send "{success_msg}" "System {action_desc} finished successfully" -else - echo "{action_desc.capitalize()} failed!" - notify-send "{fail_msg}" "System {action_desc} encountered an error" -fi - -# Clean up -rm -f /tmp/{action_desc}_after_reboot.sh -""" - return script - - def run(self): - """Start the GUI application""" - self.root.mainloop() - -if __name__ == "__main__": - # Check if running as root for certain operations - if os.geteuid() != 0: - print("Note: Some operations may require sudo privileges") - - app = BackupManager() - app.run() diff --git a/lvm-migration-tools/LIVE_USB_MIGRATION_GUIDE.md b/lvm-migration-tools/LIVE_USB_MIGRATION_GUIDE.md deleted file mode 100644 index 956d099..0000000 --- a/lvm-migration-tools/LIVE_USB_MIGRATION_GUIDE.md +++ /dev/null @@ -1,515 +0,0 @@ -# LVM Migration Guide: Live USB to LVM System - -## Overview - -This guide provides comprehensive instructions for migrating your current non-LVM system to an LVM-based system on an external M.2 SSD. **This migration MUST be performed from a live USB system** to avoid file system conflicts and ensure data integrity. - -## Why Migrate to LVM? - -**Benefits of LVM System:** -- **Instant Snapshots**: Create consistent backups without downtime -- **Flexible Storage**: Resize volumes dynamically without repartitioning -- **Advanced Backups**: Snapshot-based backups with rollback capability -- **Space Efficiency**: Snapshots only store changes, not full copies -- **System Recovery**: Easy rollback to previous states - -## Prerequisites - -### Hardware Requirements -- **Live USB System**: Boot from any Linux live USB (Ubuntu, Debian, etc.) -- **Internal Drive**: Your current system (will remain unchanged) -- **External M.2 SSD**: Target drive for LVM system (will be formatted) -- **Sufficient Space**: External drive should be ≥ size of used space on internal drive - -### Software Requirements -- Live USB system with LVM tools (will be installed automatically) -- Network connection for package installation -- Root/sudo access on live system - -## Before You Begin - -### 1. Create Recovery Environment -```bash -# Prepare live USB with migration tools -# Download latest Ubuntu/Debian live ISO -# Flash to USB drive using dd or balenaEtcher -``` - -### 2. Backup Important Data -⚠️ **CRITICAL**: While the internal drive remains unchanged, create an additional backup of critical data before proceeding. - -### 3. Document Current System -```bash -# Boot your current system and document the configuration -lsblk -f > system_layout.txt -df -h > disk_usage.txt -cat /etc/fstab > fstab_backup.txt -``` - -## Migration Process - -### Step 1: Boot from Live USB System - -1. **Shutdown your system** completely -2. **Insert live USB** and connect external M.2 SSD -3. **Configure BIOS/UEFI**: - - Set USB as first boot device - - Ensure both internal and external drives are detected -4. **Boot live system**: - - Select "Try Ubuntu" or "Live System" (not "Install") - - Wait for desktop to load completely -5. **Open terminal** and gain root access: - ```bash - sudo -i - ``` - -### Step 2: Prepare Live System - -```bash -# Download and prepare the migration tools -cd /tmp -git clone backup_tools -cd backup_tools - -# Or if you have the tools on external drive already: -mkdir -p /mnt/temp -mount /dev/sda1 /mnt/temp # Adjust device as needed -cp -r /mnt/temp/migration_tools/* /tmp/ -umount /mnt/temp - -# Prepare the live system -./prepare_live_system.sh -``` - -**This script will:** -- ✅ Verify you're running from live system -- 📦 Install required packages (lvm2, cryptsetup, rsync, etc.) -- 🔧 Load kernel modules for LVM -- 💽 Detect available drives -- 📁 Create migration workspace - -### Step 3: Run Migration Script - -```bash -# Execute the migration (this will take 30-90 minutes) -./migrate_to_lvm.sh -``` - -**The migration process includes:** - -1. **Drive Detection** (Automatic): - ``` - Detecting drives... - Available drives: - 1. /dev/nvme0n1 - 477GB Samsung SSD 980 (Internal) - 2. /dev/sda - 477GB Samsung T7 (External USB) - - Selected drives: - Internal (source): /dev/nvme0n1 - External (target): /dev/sda - ``` - -2. **System Analysis**: - - Automatically detects partition layout - - Identifies filesystem types - - Handles encrypted partitions - - Calculates optimal LVM sizes - -3. **Confirmation Prompts**: - ``` - ⚠️ WARNING: This will DESTROY all data on /dev/sda! - - Migration Summary: - Source: /dev/nvme0n1 (non-LVM system) - Target: /dev/sda (will become LVM system) - Root size: 70G - Home size: 350G - Swap size: 16G - Boot size: 2G - - Do you want to continue? [y/N] - ``` - -4. **LVM Layout Creation**: - - Creates GPT partition table - - EFI boot partition (512MB) - - LVM physical volume (remaining space) - - Creates volume group and logical volumes - -5. **Data Migration**: - - Mounts source filesystems (handles encryption) - - Copies all system data with rsync - - Preserves permissions, links, and attributes - - Updates system configuration files - -6. **System Configuration**: - - Updates /etc/fstab for LVM volumes - - Configures initramfs for LVM support - - Installs and configures GRUB bootloader - - Creates LVM snapshot backup tools - -### Step 4: Validation and Testing - -```bash -# Validate the migration -./validate_lvm_migration.sh -``` - -**Validation checks:** -- ✅ LVM volumes created correctly -- ✅ Filesystems are healthy -- ✅ Boot configuration is valid -- ✅ GRUB installation successful -- ✅ System files copied completely -- ✅ LVM snapshot capability working - -### Step 5: First Boot Test - -1. **Cleanup and shutdown**: - ```bash - # Clean up and prepare for reboot - sync - umount -a - shutdown -h now - ``` - -2. **Configure BIOS/UEFI**: - - Boot into BIOS/UEFI settings - - Change boot order: External M.2 SSD as first boot device - - Save and exit - -3. **Test boot from external M.2**: - - System should boot normally from external drive - - Login and verify everything works - - Check that all your files and settings are present - -4. **Verify LVM system**: - ```bash - # Check LVM status - sudo lvs - sudo vgs - sudo pvs - - # Check filesystem mounts - df -h - cat /proc/mounts | grep mapper - ``` - -## System Configuration Details - -### LVM Layout Created -``` -Physical Volume: /dev/sda2 -Volume Group: system-vg -Logical Volumes: -├── root (70G) - ext4 - mounted at / -├── home (350G) - ext4 - mounted at /home -├── boot (2G) - ext4 - mounted at /boot -└── swap (16G) - swap - swap space - -Additional: -├── /dev/sda1 (512M) - vfat - EFI boot partition - mounted at /boot/efi -└── Free space (~38G) - available for snapshots and volume expansion -``` - -### Migration Advantages - -**Flexibility:** -- Resize any volume without repartitioning -- Add new drives to volume group -- Move logical volumes between physical drives - -**Backup & Recovery:** -- Create instant snapshots of any volume -- Rollback changes using snapshots -- Consistent backups without downtime - -**Space Management:** -- Thin provisioning support -- Automatic space allocation -- Easy expansion and shrinking - -## Using LVM Snapshots - -### Basic Snapshot Operations - -```bash -# Create snapshots for backup -sudo ./lvm_snapshot_backup.sh backup - -# Snapshots are mounted at: -/mnt/backup/root # Snapshot of root filesystem -/mnt/backup/home # Snapshot of home filesystem -/mnt/backup/boot # Snapshot of boot filesystem - -# Perform backup to external storage -rsync -avH /mnt/backup/ /path/to/external/backup/ - -# Clean up snapshots -sudo ./lvm_snapshot_backup.sh remove -``` - -### Advanced LVM Operations - -```bash -# Extend a logical volume (add 10GB to home) -sudo lvextend -L +10G /dev/system-vg/home -sudo resize2fs /dev/system-vg/home - -# Create additional logical volume -sudo lvcreate -L 20G -n data system-vg -sudo mkfs.ext4 /dev/system-vg/data -sudo mkdir /data -sudo mount /dev/system-vg/data /data - -# Snapshot before system changes -sudo lvcreate -L 5G -s -n root-before-update /dev/system-vg/root - -# Rollback if needed -sudo umount / -sudo lvconvert --merge /dev/system-vg/root-before-update -# Reboot to activate rollback -``` - -## Troubleshooting Guide - -### Migration Issues - -**Migration Script Fails** -```bash -# Check logs for detailed error information -tail -f /var/log/lvm-migration.log - -# Common issues and solutions: -``` - -| Issue | Cause | Solution | -|-------|-------|----------| -| "Drive not found" | Drive not connected/detected | Check connections, try different USB port | -| "Insufficient space" | Target drive too small | Use larger drive or reduce partition sizes | -| "LVM tools not found" | Missing packages | Run `prepare_live_system.sh` first | -| "Permission denied" | Not running as root | Use `sudo` or `sudo -i` | -| "Mount failed" | Filesystem corruption | Check drive with `fsck` | - -**Encrypted Partition Issues** -```bash -# If encrypted partition unlock fails: -sudo cryptsetup luksOpen /dev/nvme0n1p3 temp-unlock -# Enter correct password -sudo cryptsetup close temp-unlock -``` - -**Drive Detection Problems** -```bash -# Manually check drives -lsblk -dpno NAME,SIZE,MODEL -sudo fdisk -l - -# If drives not detected: -sudo partprobe # Re-read partition tables -sudo udevadm settle # Wait for device detection -``` - -### Boot Issues After Migration - -**System Won't Boot from External Drive** - -1. **Check BIOS/UEFI Settings**: - - Verify external M.2 is detected in BIOS - - Set correct boot priority - - Enable UEFI boot mode - - Disable Secure Boot if necessary - -2. **Repair GRUB from Live USB**: - ```bash - # Boot from live USB and mount LVM system - sudo vgchange -ay system-vg - sudo mount /dev/system-vg/root /mnt - sudo mount /dev/system-vg/boot /mnt/boot - sudo mount /dev/sda1 /mnt/boot/efi - - # Reinstall GRUB - sudo mount --bind /dev /mnt/dev - sudo mount --bind /proc /mnt/proc - sudo mount --bind /sys /mnt/sys - sudo chroot /mnt - grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian - update-grub - exit - - # Cleanup and reboot - sudo umount /mnt/dev /mnt/proc /mnt/sys - sudo umount /mnt/boot/efi /mnt/boot /mnt - sudo reboot - ``` - -**Emergency Recovery** - -If external system is completely broken: -1. Change BIOS boot order back to internal drive -2. Boot from original system (unchanged) -3. Re-attempt migration or continue with original system - -### LVM Issues - -**Volume Group Not Found** -```bash -# Activate volume group manually -sudo vgchange -ay system-vg - -# Scan for volume groups -sudo vgscan -sudo pvscan -``` - -**Snapshot Issues** -```bash -# Remove stuck snapshots -sudo umount /mnt/backup/root /mnt/backup/home 2>/dev/null || true -sudo lvremove -f system-vg/root-snapshot -sudo lvremove -f system-vg/home-snapshot - -# Check volume group free space -sudo vgs system-vg -``` - -**File System Corruption** -```bash -# Check and repair LVM volumes -sudo fsck /dev/system-vg/root -sudo fsck /dev/system-vg/home -sudo fsck /dev/system-vg/boot -``` - -## Recovery Procedures - -### Complete Rollback to Original System - -If you decide to abandon LVM migration: - -1. **Boot from internal drive**: - - Change BIOS boot order to internal drive - - Boot normally from original system - -2. **Reformat external drive** (optional): - ```bash - # Wipe LVM configuration - sudo dd if=/dev/zero of=/dev/sda bs=1M count=100 - # Or use backup tools to restore external drive - ``` - -3. **Continue with original system**: - - Everything remains as before migration - - Use existing backup tools for regular backups - -### Retry Migration - -If you want to attempt migration again: - -1. **Boot from live USB** -2. **Run migration script again**: - ```bash - ./migrate_to_lvm.sh - ``` - - Script will destroy existing LVM setup and recreate - - Source system (internal) remains unchanged - -### Disaster Recovery - -**If both systems fail:** - -1. **Boot from live USB** -2. **Mount internal drive** for data recovery: - ```bash - mkdir -p /mnt/recovery - - # Mount root partition - sudo mount /dev/nvme0n1p1 /mnt/recovery - - # If home is encrypted: - sudo cryptsetup open /dev/nvme0n1p3 recovery-home - sudo mkdir -p /mnt/recovery/home - sudo mount /dev/mapper/recovery-home /mnt/recovery/home - - # Copy important data to external storage - rsync -avH /mnt/recovery/home/username/ /path/to/safe/backup/ - ``` - -3. **Fresh OS installation** if needed: - - Install fresh OS on any drive - - Restore personal data from backup - -## Performance Optimization - -### LVM Performance Tuning - -```bash -# Enable read-ahead for better performance -sudo blockdev --setra 2048 /dev/system-vg/root -sudo blockdev --setra 2048 /dev/system-vg/home - -# Add to /etc/fstab for persistent read-ahead: -# /dev/system-vg/root / ext4 defaults,noatime 0 1 -# /dev/system-vg/home /home ext4 defaults,noatime 0 2 -``` - -### Snapshot Management - -```bash -# Monitor snapshot usage -sudo lvs -a -o lv_name,lv_size,data_percent system-vg - -# Remove old snapshots regularly -sudo lvremove system-vg/old-snapshot-name - -# Set up automatic snapshot cleanup (cron job) -echo '0 2 * * * root /usr/local/bin/lvm-snapshot-backup.sh remove' >> /etc/crontab -``` - -## Best Practices - -### Regular Maintenance - -1. **Monitor disk space**: - ```bash - sudo vgs system-vg # Check volume group free space - df -h # Check filesystem usage - ``` - -2. **Regular snapshots**: - ```bash - # Before system updates - sudo lvcreate -L 5G -s -n pre-update-$(date +%Y%m%d) /dev/system-vg/root - - # Before major changes - sudo ./lvm_snapshot_backup.sh backup - ``` - -3. **Backup strategy**: - - Daily: LVM snapshots to external storage - - Weekly: Full system backup using existing tools - - Monthly: Verify backup integrity - -### Security Considerations - -- **Encryption**: Home data is no longer encrypted in LVM setup - - Consider full disk encryption if security is critical - - Use file-level encryption for sensitive data - -- **Access Control**: Secure LVM management commands - ```bash - # Restrict LVM command access - sudo chmod 750 /usr/local/bin/lvm-* - ``` - -## Summary - -The migration successfully transforms your system from traditional partitions to a flexible LVM-based setup, providing: - -✅ **Instant snapshots** for consistent backups -✅ **Dynamic volume resizing** without downtime -✅ **Advanced backup strategies** with rollback capability -✅ **Space efficiency** with thin provisioning -✅ **System recovery** options with snapshots - -Your original system remains intact as a fallback, making this a low-risk enhancement to your backup and storage capabilities. \ No newline at end of file diff --git a/lvm-migration-tools/README.md b/lvm-migration-tools/README.md deleted file mode 100644 index 695c414..0000000 --- a/lvm-migration-tools/README.md +++ /dev/null @@ -1,461 +0,0 @@ -# System Backup and LVM Migration Tools - -A comprehensive toolset for Linux system backup and LVM migration that provides both GUI and command-line interfaces for backing up to external M.2 SSDs and migrating systems to LVM. - -## Features - -### Traditional Backup Features -- **GUI Interface**: User-friendly graphical interface built with Python Tkinter -- **Command Line Interface**: Full CLI support for automated and scripted operations -- **Smart Drive Detection**: Automatically detects internal drive and external M.2 SSDs -- **Full System Backup**: Complete drive cloning with dd for exact system replication -- **Smart Sync Backup**: ⚡ Fast incremental backups using rsync for minor changes -- **Change Analysis**: Analyze filesystem changes to recommend sync vs full backup -- **Restore Functionality**: Complete system restore from external drive -- **Portable Tools**: Backup tools survive on external drive and remain accessible after cloning -- **Reboot Integration**: Optional reboot before backup/restore operations -- **Progress Monitoring**: Real-time progress display and logging -- **Safety Features**: Multiple confirmations and drive validation -- **Desktop Integration**: Create desktop shortcuts for easy access - -### 🆕 LVM Migration Features -- **Automated LVM Migration**: Complete migration from traditional partitions to LVM -- **Size Detection**: Automatic source partition size detection and matching -- **Data Preservation**: Full data integrity with permissions, ownership, and timestamps -- **External Drive Support**: Optimized for USB 3.0+ M.2 external drives -- **GRUB Installation**: Automatic EFI bootloader installation and configuration -- **System Validation**: Built-in verification of migration success -- **One-Button Operation**: Complete migration with a single command - -- **GUI Interface**: User-friendly graphical interface built with Python Tkinter -- **Command Line Interface**: Full CLI support for automated and scripted operations -- **Smart Drive Detection**: Automatically detects internal drive and external M.2 SSDs -- **Full System Backup**: Complete drive cloning with dd for exact system replication -- **Smart Sync Backup**: ⚡ NEW! Fast incremental backups using rsync for minor changes -- **Change Analysis**: Analyze filesystem changes to recommend sync vs full backup -- **Restore Functionality**: Complete system restore from external drive -- **Portable Tools**: Backup tools survive on external drive and remain accessible after cloning -- **Reboot Integration**: Optional reboot before backup/restore operations -- **Progress Monitoring**: Real-time progress display and logging -- **Safety Features**: Multiple confirmations and drive validation -- **Desktop Integration**: Create desktop shortcuts for easy access - -## Requirements - -- Linux system (tested on Ubuntu/Debian) -- Python 3.6+ with tkinter -- External M.2 SSD in USB enclosure -- sudo privileges for drive operations - -## Installation - -### Traditional Backup Installation - -1. Clone or download this repository: - ```bash - git clone - cd backup_to_external_m.2 - ``` - -2. Make scripts executable: - ```bash - chmod +x backup_script.sh - chmod +x backup_manager.py - ``` - -3. Install dependencies (if needed): - ```bash - sudo apt update - sudo apt install python3-tk pv parted - ``` - -### LVM Migration Setup - -The LVM migration tools require a live USB environment: - -1. Boot from Debian/Ubuntu Live USB -2. Clone this repository to the live environment -3. The migration script will automatically install required dependencies -4. Run the migration with a single command: - ```bash - sudo ./migrate_to_lvm.sh /dev/sdX - ``` - -## LVM Migration Process - -The migration is now **fully automated** with a single command: - -1. **Preparation**: Boot from live USB, run the migration script -2. **Detection**: Automatically detect source partition sizes and layout -3. **LVM Setup**: Create LVM physical volumes, volume groups, and logical volumes -4. **Data Copy**: Efficiently copy all filesystem data using optimized `cp -a` method -5. **Boot Configuration**: Automatically update fstab, install GRUB EFI bootloader -6. **Validation**: Verify all components are properly configured -7. **Ready**: System is immediately bootable from external drive - -### One-Button Migration - -```bash -sudo ./migrate_to_lvm.sh /dev/sdX -``` - -The script automatically handles: -- ✅ Partition detection and size calculation -- ✅ LVM volume creation with optimal sizes -- ✅ Complete data transfer (root, home, boot, EFI) -- ✅ fstab configuration with proper UUIDs -- ✅ GRUB EFI bootloader installation -- ✅ initramfs updates for LVM support -- ✅ System validation and readiness check - -### Post-Migration Benefits - -Once migrated to LVM, your system gains: -- **Instant Snapshots**: Create point-in-time snapshots before system changes -- **Dynamic Resizing**: Resize partitions without downtime -- **Advanced Backups**: Consistent snapshots for reliable backups -- **Easy Rollback**: Revert to previous snapshots if needed - -4. **Optional**: Set up portable tools on external M.2 SSD: - ```bash - ./setup_portable_tools.sh - ``` - This creates a separate partition on your external drive that preserves backup tools even after cloning. - -## Usage - -### GUI Application - -Launch the graphical backup manager: - -```bash -python3 backup_manager.py -``` - -**Features:** -- Automatic drive detection and classification -- Source and target drive selection with smart defaults -- Real-time progress monitoring -- **Backup Modes**: - - **Smart Sync Backup**: ⚡ Fast incremental backup using rsync (requires existing backup) - - **Analyze Changes**: Analyze what has changed since last backup - - **Start Backup**: Full drive clone (immediate backup while system running) - - **Reboot & Backup**: Reboot system then full backup (recommended for first backup) -- **Restore Modes**: - - **Restore from External**: Immediate restore from external to internal - - **Reboot & Restore**: Reboot system then restore (recommended) -- **Drive Swap Button**: Easily swap source and target for restore operations - -### Command Line Script - -For command-line usage: - -```bash -# List available drives -./backup_script.sh --list - -# Analyze changes without performing backup -./backup_script.sh --analyze --target /dev/sdb - -# Smart sync backup (fast incremental update) -sudo ./backup_script.sh --sync --target /dev/sdb - -# Perform full backup with specific drives -sudo ./backup_script.sh --source /dev/nvme0n1 --target /dev/sda - -# Restore from external to internal (note the restore flag) -sudo ./backup_script.sh --restore --source /dev/sda --target /dev/nvme0n1 - -# Or more simply in restore mode (source/target are swapped automatically) -sudo ./backup_script.sh --restore --source /dev/nvme0n1 --target /dev/sda - -# Create desktop entry -./backup_script.sh --desktop - -# Launch GUI from script -./backup_script.sh --gui -``` - -### Desktop Integration - -Create a desktop shortcut: - -```bash -./backup_script.sh --desktop -``` - -This creates a clickable icon on your desktop that launches the backup tool. - -## Restore Operations - -### When to Restore -- **System Failure**: Internal drive crashed or corrupted -- **System Migration**: Moving to new hardware -- **Rollback**: Reverting to previous system state -- **Testing**: Restoring test environment - -### How to Restore - -#### GUI Method -1. **Connect External Drive**: Plug in your M.2 SSD with backup -2. **Launch GUI**: `python3 backup_manager.py` -3. **Check Drive Selection**: - - Source should be external drive (your backup) - - Target should be internal drive (will be overwritten) -4. **Use Swap Button**: If needed, click "Swap Source↔Target" -5. **Choose Restore Mode**: - - **"Restore from External"**: Immediate restore - - **"Reboot & Restore"**: Reboot then restore (recommended) - -#### Command Line Method -```bash -# Restore with automatic drive detection -sudo ./backup_script.sh --restore - -# Restore with specific drives -sudo ./backup_script.sh --restore --source /dev/sda --target /dev/nvme0n1 -``` - -### ⚠️ Restore Safety Warnings -- **Data Loss**: Target drive is completely overwritten -- **Irreversible**: No undo after restore starts -- **Multiple Confirmations**: System requires explicit confirmation -- **Drive Verification**: Double-check source and target drives -- **Boot Issues**: Ensure external drive contains valid system backup - -## Portable Tools (Boot from External M.2) - -### Setup Portable Tools -Run this once to set up backup tools on your external M.2 SSD: - -```bash -./setup_portable_tools.sh -``` - -This will: -- Create a 512MB tools partition on your external drive -- Install backup tools that survive cloning operations -- Set up automatic tool restoration after each backup - -### Using Portable Tools - -#### When Booted from External M.2 SSD: - -1. **Access Tools**: - ```bash - # Easy access helper - ./access_tools.sh - - # Or manually: - sudo mount LABEL=BACKUP_TOOLS /mnt/tools - cd /mnt/tools/backup_system - ./launch_backup_tools.sh - ``` - -2. **Restore Internal Drive**: - - Launch backup tools from external drive - - External drive (source) → Internal drive (target) - - Click "Reboot & Restore" for safest operation - -3. **Create Desktop Entry**: - ```bash - cd /mnt/tools/backup_system - ./create_desktop_entry.sh - ``` - -### Disaster Recovery Workflow - -1. **Normal Operation**: Internal drive fails -2. **Boot from External**: Use M.2 SSD as boot drive -3. **Access Tools**: Run `./access_tools.sh` -4. **Restore System**: Use backup tools to restore to new internal drive -5. **Back to Normal**: Boot from restored internal drive - -## Safety Features - -- **Drive Validation**: Prevents accidental overwriting of wrong drives -- **Size Checking**: Ensures target drive is large enough -- **Confirmation Prompts**: Multiple confirmation steps before destructive operations -- **Mount Detection**: Automatically unmounts target drives before backup -- **Progress Monitoring**: Real-time feedback during backup operations - -## File Structure - -``` -backup_to_external_m.2/ -├── backup_manager.py # GUI application -├── backup_script.sh # Command-line script -├── install.sh # Installation script -├── systemd/ # Systemd service files -│ └── backup-service.service -└── README.md # This file -``` - -## Smart Sync Technology ⚡ - -The backup system now includes advanced **Smart Sync** functionality that dramatically reduces backup time for incremental updates: - -### How Smart Sync Works - -1. **Analysis Phase**: Compares source and target filesystems to determine changes -2. **Decision Engine**: Recommends sync vs full clone based on amount of changes: - - **< 2GB changes**: Smart sync recommended (much faster) - - **2-10GB changes**: Smart sync beneficial - - **> 10GB changes**: Full clone may be more appropriate -3. **Sync Operation**: Uses rsync to transfer only changed files and metadata - -### Smart Sync Benefits - -- **Speed**: 10-100x faster than full clone for minor changes -- **No Downtime**: System remains usable during sync operation -- **Efficiency**: Only transfers changed data, preserving bandwidth and storage wear -- **Safety**: Preserves backup tools and maintains full system consistency - -### When to Use Smart Sync vs Full Clone - -**Use Smart Sync when:** -- You have an existing backup on the target drive -- Regular incremental updates (daily/weekly backups) -- Minimal system changes since last backup -- You want faster backup with minimal downtime - -**Use Full Clone when:** -- First-time backup to a new drive -- Major system changes (OS upgrade, large software installations) -- Corrupted or incomplete previous backup -- Maximum compatibility and reliability needed - -### Smart Sync Usage - -**GUI Method:** -1. Click "Analyze Changes" to see what has changed -2. Review the recommendation and estimated time savings -3. Click "Smart Sync Backup" to perform incremental update - -**Command Line:** -```bash -# Analyze changes first -./backup_script.sh --analyze --target /dev/sdb - -# Perform smart sync -sudo ./backup_script.sh --sync --target /dev/sdb -``` - -## Traditional Full Backup - -For comprehensive system backup, the system uses proven `dd` cloning technology: - -### Backup Process -1. **Drive Detection**: Automatically scans for available drives -2. **Auto-Selection**: Internal drive as source, external as target -3. **Operation Selection**: Choose backup or restore mode -4. **Validation**: Confirms drives exist and are different -5. **Execution**: Uses `dd` command to clone entire drive -6. **Progress**: Shows real-time progress and logging - -### Backup vs Restore -- **Backup**: Internal → External (preserves your system on external drive) -- **Restore**: External → Internal (overwrites internal with backup data) -- **Swap Button**: Easily switch source/target for restore operations - -### Reboot vs Immediate Operations -- **Immediate**: Faster start, but system is running (potential file locks) -- **Reboot Mode**: System restarts first, then operates (cleaner, more reliable) -- **Recommendation**: Use reboot mode for critical operations - -### Reboot & Backup Mode -1. **Script Creation**: Creates a backup script for post-reboot execution -2. **Reboot Scheduling**: Schedules system reboot -3. **Auto-Execution**: Backup starts automatically after reboot -4. **Notification**: Shows completion status - -### Command Line Mode -- Direct `dd` cloning with progress monitoring -- Comprehensive logging to `/var/log/system_backup.log` -- Drive size validation and safety checks - -## Technical Details - -### Backup Method -- Uses `dd` command for bit-perfect drive cloning -- Block size optimized at 4MB for performance -- `fdatasync` ensures all data is written to disk - -### Drive Detection -- Uses `lsblk` to enumerate block devices -- Filters for actual disk drives -- Shows drive sizes for easy identification - -### Safety Mechanisms -- Root privilege verification -- Block device validation -- Source/target drive comparison -- Mount status checking -- Size compatibility verification - -## Troubleshooting - -### Common Issues - -1. **Permission Denied** - ```bash - # Run with sudo for drive operations - sudo python3 backup_manager.py - ``` - -2. **Drive Not Detected** - ```bash - # Check if drive is connected and recognized - lsblk - dmesg | tail - ``` - -3. **Backup Fails** - ```bash - # Check system logs - sudo journalctl -f - tail -f /var/log/system_backup.log - ``` - -### Performance Tips - -- Use USB 3.0+ connection for external M.2 SSD -- Ensure sufficient power supply for external enclosure -- Close unnecessary applications during backup -- Use SSD for better performance than traditional HDD - -## Security Considerations - -- **Data Destruction**: Target drive data is completely overwritten -- **Root Access**: Scripts require elevated privileges -- **Verification**: Always verify backup integrity after completion -- **Testing**: Test restore process with non-critical data first - -## Limitations - -- Only works with block devices (entire drives) -- Cannot backup to smaller drives -- Requires manual drive selection for safety -- No incremental backup support (full clone only) - -## Contributing - -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Test thoroughly -5. Submit a pull request - -## License - -This project is open source. Use at your own risk. - -## Disclaimer - -**WARNING**: This tool performs low-level disk operations that can result in data loss. Always: -- Verify drive selections carefully -- Test with non-critical data first -- Maintain separate backups of important data -- Understand the risks involved - -The authors are not responsible for any data loss or system damage. diff --git a/lvm-migration-tools/access_tools.sh b/lvm-migration-tools/access_tools.sh deleted file mode 100755 index 28818f2..0000000 --- a/lvm-migration-tools/access_tools.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/bash -# Mount backup tools partition and provide easy access -# Use this when booted from the external M.2 SSD - -set -e - -# Colors -GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -NC='\033[0m' - -print_info() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} - -print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} - -echo "" -echo "==========================================" -echo " Backup Tools Access Helper" -echo "==========================================" -echo "" - -# Try to find backup tools partition -TOOLS_PARTITION=$(blkid -L "BACKUP_TOOLS" 2>/dev/null || echo "") - -if [[ -z "$TOOLS_PARTITION" ]]; then - print_warning "Backup tools partition not found by label." - print_info "Searching for tools partition..." - - # Look for small partitions that might be our tools partition - while IFS= read -r line; do - partition=$(echo "$line" | awk '{print $1}') - size=$(echo "$line" | awk '{print $4}') - - # Check if it's a small partition (likely tools) - if [[ "$size" == *M ]] && [[ ${size%M} -le 1024 ]]; then - print_info "Found potential tools partition: $partition ($size)" - TOOLS_PARTITION="/dev/$partition" - break - fi - done < <(lsblk -n -o NAME,SIZE | grep -E "sd|nvme.*p") -fi - -if [[ -z "$TOOLS_PARTITION" ]]; then - echo "❌ Could not find backup tools partition" - echo "" - echo "Available partitions:" - lsblk - echo "" - echo "To manually mount tools:" - echo "1. Identify the tools partition from the list above" - echo "2. sudo mkdir -p /mnt/backup_tools" - echo "3. sudo mount /dev/[partition] /mnt/backup_tools" - echo "4. cd /mnt/backup_tools/backup_system" - echo "5. ./launch_backup_tools.sh" - exit 1 -fi - -# Create mount point -MOUNT_POINT="/mnt/backup_tools" -print_info "Creating mount point: $MOUNT_POINT" -sudo mkdir -p "$MOUNT_POINT" - -# Mount tools partition -print_info "Mounting tools partition: $TOOLS_PARTITION" -if sudo mount "$TOOLS_PARTITION" "$MOUNT_POINT"; then - print_success "Tools partition mounted successfully" -else - echo "❌ Failed to mount tools partition" - exit 1 -fi - -# Check if backup system exists -if [[ -d "$MOUNT_POINT/backup_system" ]]; then - print_success "Backup tools found!" - - cd "$MOUNT_POINT/backup_system" - - echo "" - echo "📁 Backup tools are now available at:" - echo " $MOUNT_POINT/backup_system" - echo "" - echo "🚀 Available commands:" - echo " ./launch_backup_tools.sh - Interactive menu" - echo " ./backup_script.sh --help - Command line help" - echo " python3 backup_manager.py - GUI (if available)" - echo " ./create_desktop_entry.sh - Create desktop shortcut" - echo "" - - # Ask what to do - read -p "Launch backup tools now? (y/n): " launch - if [[ "$launch" =~ ^[Yy] ]]; then - ./launch_backup_tools.sh - else - echo "" - echo "Tools are ready to use. Change to the tools directory:" - echo "cd $MOUNT_POINT/backup_system" - fi - -else - print_warning "Backup system not found in tools partition" - echo "" - echo "Contents of tools partition:" - ls -la "$MOUNT_POINT" -fi diff --git a/lvm-migration-tools/automated_clonezilla_backup.sh b/lvm-migration-tools/automated_clonezilla_backup.sh deleted file mode 100755 index 149d12f..0000000 --- a/lvm-migration-tools/automated_clonezilla_backup.sh +++ /dev/null @@ -1,198 +0,0 @@ -#!/bin/bash -# Automated Clonezilla Backup Script -# This script runs inside the Clonezilla environment to automate the backup process -# while preserving the Clonezilla boot partition - -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" -} - -clear -print_status "Automated Clonezilla System Backup" -echo "==================================" -echo - -# Wait for drives to be detected -sleep 3 - -# Auto-detect source drive (internal) -SOURCE_DRIVE="" -for drive in /dev/nvme0n1 /dev/sda /dev/sdb /dev/sdc; do - if [[ -b "$drive" && "$drive" != "/dev/sda" ]]; then - # Check if it looks like a system drive (has multiple partitions) - if [[ $(lsblk -n "$drive" | wc -l) -gt 1 ]]; then - SOURCE_DRIVE="$drive" - break - fi - fi -done - -if [[ -z "$SOURCE_DRIVE" ]]; then - print_error "Could not auto-detect source drive!" - print_status "Available drives:" - lsblk - exit 1 -fi - -# Target is always the backup partition on this USB -TARGET_PARTITION="/dev/sda2" - -print_status "Source Drive: $SOURCE_DRIVE" -print_status "Target Partition: $TARGET_PARTITION" -lsblk "$SOURCE_DRIVE" -echo - -print_warning "This will create a compressed backup image of your system" -print_warning "Backup location: $TARGET_PARTITION" -echo - -# Mount the backup partition -BACKUP_MOUNT="/tmp/backup_storage" -mkdir -p "$BACKUP_MOUNT" - -print_status "Mounting backup storage..." -if ! mount "$TARGET_PARTITION" "$BACKUP_MOUNT"; then - print_error "Failed to mount backup partition" - exit 1 -fi - -# Create backup directory with timestamp -BACKUP_DATE=$(date +%Y%m%d_%H%M%S) -BACKUP_DIR="$BACKUP_MOUNT/system_backup_$BACKUP_DATE" -mkdir -p "$BACKUP_DIR" - -print_status "Creating system backup in: $BACKUP_DIR" -echo - -# Use Clonezilla's ocs-sr (Save and Restore) in batch mode -print_status "Starting Clonezilla backup process..." -print_warning "This will take 30-60 minutes depending on your data size" -echo - -# Clonezilla command in batch mode for disk image creation -# -q2: Use parallel compression for speed -# -c: Enable checking saved image -# -j2: Use clone fresh MBR -# -z1p: Use parallel gzip compression -# -i 4096: Set image split size to 4GB -# -sfsck: Skip filesystem check to save time -# -scs: Skip checking free space in destination -# -rescue: Continue on minor errors -# -batch: Batch mode, no interactive prompts - -# Use Clonezilla's ocs-sr (Save and Restore) in batch mode with FASTEST settings -# -q2: Use parallel compression for speed -# -c: Enable checking saved image -# -j2: Use clone fresh MBR -# -z0: NO compression for maximum speed (trade size for speed) -# -i 0: No image splitting for faster writing -# -sfsck: Skip filesystem check to save time -# -scs: Skip checking free space in destination -# -rescue: Continue on minor errors -# -batch: Batch mode, no interactive prompts -# -p poweroff: Don't power off after completion - -print_status "Using MAXIMUM SPEED settings (NO compression - speed is king!)" -print_warning "Backup will complete in ~15-20 minutes - fastest possible!" - -/usr/sbin/ocs-sr \ - -q2 \ - -j2 \ - -z0 \ - -i 0 \ - -sfsck \ - -scs \ - -rescue \ - -batch \ - -p reboot \ - savedisk \ - "system_backup_$BACKUP_DATE" \ - "$SOURCE_DRIVE" - -if [[ $? -eq 0 ]]; then - print_success "Backup completed successfully!" - print_success "Backup saved to: $BACKUP_DIR" - - # Create a restore script for easy restoration - cat > "$BACKUP_DIR/restore.sh" << EOF -#!/bin/bash -# Restore script for system backup created on $BACKUP_DATE -# Usage: ./restore.sh /dev/target_drive - -if [[ \$# -ne 1 ]]; then - echo "Usage: \$0 /dev/target_drive" - echo "Example: \$0 /dev/nvme0n1" - exit 1 -fi - -TARGET_DRIVE="\$1" - -echo "WARNING: This will completely overwrite \$TARGET_DRIVE" -read -p "Continue? (yes/no): " confirm - -if [[ "\$confirm" != "yes" ]]; then - echo "Cancelled" - exit 1 -fi - -/usr/sbin/ocs-sr \\ - -g auto \\ - -e1 auto \\ - -e2 \\ - -r \\ - -j2 \\ - -batch \\ - restoredisk \\ - "system_backup_$BACKUP_DATE" \\ - "\$TARGET_DRIVE" -EOF - chmod +x "$BACKUP_DIR/restore.sh" - - # Show backup info - print_status "Backup Information:" - du -h "$BACKUP_DIR" - echo - print_success "Restore script created: $BACKUP_DIR/restore.sh" - -else - print_error "Backup failed!" - exit 1 -fi - -# Unmount backup storage -umount "$BACKUP_MOUNT" - -print_success "System backup completed!" -print_status "You can now reboot back to your normal system" -print_status "To restore: Boot from this USB and run the restore script" - -echo -print_warning "Press Enter to continue..." -read - -# Optional: Auto-reboot or return to menu -echo "Backup process complete. You can now:" -echo "1. Reboot to your normal system" -echo "2. Run another backup" -echo "3. Access Clonezilla manually" diff --git a/lvm-migration-tools/backup_script.sh b/lvm-migration-tools/backup_script.sh deleted file mode 100755 index 8faf330..0000000 --- a/lvm-migration-tools/backup_script.sh +++ /dev/null @@ -1,576 +0,0 @@ -#!/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 -SYNC_MODE=false # Smart sync mode flag -ANALYZE_ONLY=false # Analysis only mode -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" -} - -# Check if target has existing backup -check_existing_backup() { - local target_drive=$1 - local temp_mount="/tmp/backup_check_$$" - - log "Checking for existing backup on $target_drive..." - - # Get main partition - local main_partition=$(lsblk -n -o NAME "$target_drive" | grep -v "^$(basename "$target_drive")$" | head -1) - if [[ -z "$main_partition" ]]; then - echo "false" - return - fi - - main_partition="/dev/$main_partition" - - # Try to mount and check - mkdir -p "$temp_mount" - if mount -o ro "$main_partition" "$temp_mount" 2>/dev/null; then - if [[ -d "$temp_mount/etc" && -d "$temp_mount/home" && -d "$temp_mount/usr" ]]; then - echo "true" - else - echo "false" - fi - umount "$temp_mount" 2>/dev/null - else - echo "false" - fi - rmdir "$temp_mount" 2>/dev/null -} - -# Analyze changes between source and target -analyze_changes() { - local source_drive=$1 - local target_drive=$2 - - log "Analyzing changes between $source_drive and $target_drive..." - - # Check if target has existing backup - local has_backup=$(check_existing_backup "$target_drive") - - if [[ "$has_backup" != "true" ]]; then - log "No existing backup found. Full clone required." - echo "FULL_CLONE_REQUIRED" - return - fi - - # Get filesystem usage for both drives - local source_size=$(get_filesystem_size "$source_drive") - local target_size=$(get_filesystem_size "$target_drive") - - # Calculate difference in GB - local size_diff=$((${source_size} - ${target_size})) - local size_diff_abs=${size_diff#-} # Absolute value - - # Convert to GB (sizes are in KB) - local size_diff_gb=$((size_diff_abs / 1024 / 1024)) - - log "Source filesystem size: $((source_size / 1024 / 1024)) GB" - log "Target filesystem size: $((target_size / 1024 / 1024)) GB" - log "Size difference: ${size_diff_gb} GB" - - # Decision logic - if [[ $size_diff_gb -lt 2 ]]; then - log "Recommendation: Smart sync (minimal changes)" - echo "SYNC_RECOMMENDED" - elif [[ $size_diff_gb -lt 10 ]]; then - log "Recommendation: Smart sync (moderate changes)" - echo "SYNC_BENEFICIAL" - else - log "Recommendation: Full clone (major changes)" - echo "FULL_CLONE_RECOMMENDED" - fi -} - -# Get filesystem size in KB -get_filesystem_size() { - local drive=$1 - local temp_mount="/tmp/size_check_$$" - - # Get main partition - local main_partition=$(lsblk -n -o NAME "$drive" | grep -v "^$(basename "$drive")$" | head -1) - if [[ -z "$main_partition" ]]; then - echo "0" - return - fi - - main_partition="/dev/$main_partition" - - # Mount and get usage - mkdir -p "$temp_mount" - if mount -o ro "$main_partition" "$temp_mount" 2>/dev/null; then - local used_kb=$(df "$temp_mount" | tail -1 | awk '{print $3}') - umount "$temp_mount" 2>/dev/null - echo "$used_kb" - else - echo "0" - fi - rmdir "$temp_mount" 2>/dev/null -} - -# Perform smart sync backup -smart_sync_backup() { - local source=$1 - local target=$2 - - log "Starting smart sync backup..." - - # Mount both filesystems - local source_mount="/tmp/sync_source_$$" - local target_mount="/tmp/sync_target_$$" - - mkdir -p "$source_mount" "$target_mount" - - # Get main partitions - local source_partition=$(lsblk -n -o NAME "$source" | grep -v "^$(basename "$source")$" | head -1) - local target_partition=$(lsblk -n -o NAME "$target" | grep -v "^$(basename "$target")$" | head -1) - - source_partition="/dev/$source_partition" - target_partition="/dev/$target_partition" - - log "Mounting filesystems for sync..." - mount -o ro "$source_partition" "$source_mount" || error_exit "Failed to mount source" - mount "$target_partition" "$target_mount" || error_exit "Failed to mount target" - - # Perform rsync - log "Starting rsync synchronization..." - rsync -avHAXS \ - --numeric-ids \ - --delete \ - --progress \ - --exclude=/proc/* \ - --exclude=/sys/* \ - --exclude=/dev/* \ - --exclude=/tmp/* \ - --exclude=/run/* \ - --exclude=/mnt/* \ - --exclude=/media/* \ - --exclude=/lost+found \ - "$source_mount/" "$target_mount/" || { - - # Cleanup on failure - umount "$source_mount" 2>/dev/null - umount "$target_mount" 2>/dev/null - rmdir "$source_mount" "$target_mount" 2>/dev/null - error_exit "Smart sync failed" - } - - # Cleanup - umount "$source_mount" 2>/dev/null - umount "$target_mount" 2>/dev/null - rmdir "$source_mount" "$target_mount" 2>/dev/null - - success "Smart sync completed successfully!" -} - -# 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 " --sync Smart sync mode (faster incremental backup)" - echo " --analyze Analyze changes without performing backup" - 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 --analyze --target /dev/sdb" - echo " $0 --sync --target /dev/sdb" - echo " $0 --source /dev/nvme0n1 --target /dev/sdb" - echo " $0 --restore --source /dev/sdb --target /dev/nvme0n1" - 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 - ;; - --sync) - SYNC_MODE=true - shift - ;; - --analyze) - ANALYZE_ONLY=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 - - # Handle analyze mode - if [[ "$ANALYZE_ONLY" == "true" ]]; then - echo "" - echo "🔍 ANALYZING CHANGES" - echo "Source: $SOURCE_DRIVE" - echo "Target: $TARGET_DRIVE" - echo "" - - analysis_result=$(analyze_changes "$SOURCE_DRIVE" "$TARGET_DRIVE") - - case "$analysis_result" in - "FULL_CLONE_REQUIRED") - echo "📋 ANALYSIS RESULT: Full Clone Required" - echo "• No existing backup found on target drive" - echo "• Complete drive cloning is necessary" - ;; - "SYNC_RECOMMENDED") - echo "✅ ANALYSIS RESULT: Smart Sync Recommended" - echo "• Minimal changes detected (< 2GB difference)" - echo "• Smart sync will be much faster than full clone" - ;; - "SYNC_BENEFICIAL") - echo "⚡ ANALYSIS RESULT: Smart Sync Beneficial" - echo "• Moderate changes detected (< 10GB difference)" - echo "• Smart sync recommended for faster backup" - ;; - "FULL_CLONE_RECOMMENDED") - echo "🔄 ANALYSIS RESULT: Full Clone Recommended" - echo "• Major changes detected (> 10GB difference)" - echo "• Full clone may be more appropriate" - ;; - esac - - echo "" - echo "Use --sync flag to perform smart sync backup" - exit 0 - fi - - # Handle sync mode - if [[ "$SYNC_MODE" == "true" ]]; then - echo "" - echo "⚡ SMART SYNC BACKUP" - echo "Source: $SOURCE_DRIVE" - echo "Target: $TARGET_DRIVE" - echo "" - - # Check if sync is possible - analysis_result=$(analyze_changes "$SOURCE_DRIVE" "$TARGET_DRIVE") - - if [[ "$analysis_result" == "FULL_CLONE_REQUIRED" ]]; then - error_exit "Smart sync not possible: No existing backup found. Use full backup first." - fi - - echo "Analysis: $analysis_result" - echo "" - read -p "Proceed with smart sync? (yes/no): " confirm - if [[ "$confirm" != "yes" ]]; then - log "Smart sync cancelled by user" - exit 0 - fi - - smart_sync_backup "$SOURCE_DRIVE" "$TARGET_DRIVE" - - success "Smart sync backup completed successfully!" - echo "Smart sync completed! External drive is up to date." - exit 0 - fi - - # 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 "$@" diff --git a/lvm-migration-tools/bootstrap_usb_tools.sh b/lvm-migration-tools/bootstrap_usb_tools.sh deleted file mode 100755 index c8960dd..0000000 --- a/lvm-migration-tools/bootstrap_usb_tools.sh +++ /dev/null @@ -1,166 +0,0 @@ -#!/bin/bash - -# USB Live System Migration Bootstrap Script -# This script downloads and sets up the LVM migration tools on a live system - -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 - -echo -e "${GREEN}=== LVM Migration Bootstrap ===${NC}" -echo "Setting up LVM migration tools on live system..." - -# Create working directory -WORK_DIR="/tmp/lvm-migration" -mkdir -p "$WORK_DIR" -cd "$WORK_DIR" - -echo "Working directory: $WORK_DIR" - -# Function to create the prepare script inline -create_prepare_script() { - cat > prepare_live_system.sh << 'EOF' -#!/bin/bash -# Live System Preparation Script for LVM Migration -set -e - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1"; } -error() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; } -success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } - -log "Updating package lists..." -apt update || { error "Failed to update package lists"; } - -log "Installing required packages..." -apt install -y lvm2 cryptsetup rsync parted pv grub-efi-amd64 e2fsprogs dosfstools || { - error "Failed to install required packages" -} - -log "Loading kernel modules..." -modprobe dm_mod dm_crypt dm_snapshot || true - -success "Live system prepared for LVM migration!" -echo "Now run: ./migrate_to_lvm.sh" -EOF - chmod +x prepare_live_system.sh -} - -# Function to create the main migration script inline -create_migration_script() { - # This is a simplified version - the full script is quite large - cat > migrate_to_lvm.sh << 'EOF' -#!/bin/bash -# LVM Migration Script - Bootstrap Version -# Downloads the full migration script and runs it - -REPO_URL="YOUR_REPO_URL_HERE" # Replace with actual repo URL -FULL_SCRIPT_URL="$REPO_URL/migrate_to_lvm.sh" - -echo "Downloading full migration script..." -wget -O migrate_to_lvm_full.sh "$FULL_SCRIPT_URL" || { - echo "Cannot download from repository. Using embedded version..." - # Here you would embed the full script or provide local copy - echo "Please manually copy the full migrate_to_lvm.sh script" - exit 1 -} - -chmod +x migrate_to_lvm_full.sh -./migrate_to_lvm_full.sh "$@" -EOF - chmod +x migrate_to_lvm.sh -} - -# Create a manual setup guide -create_manual_setup() { - cat > SETUP_INSTRUCTIONS.txt << 'EOF' -LVM Migration Setup Instructions -=============================== - -1. Boot from this USB stick into live system -2. Open terminal and run: sudo -i -3. Run: /media/*/migration_tools/bootstrap.sh - OR manually follow these steps: - -Manual Setup: -1. Update packages: apt update -2. Install tools: apt install -y lvm2 cryptsetup rsync parted pv grub-efi-amd64 -3. Load modules: modprobe dm_mod dm_crypt dm_snapshot -4. Create workspace: mkdir -p /tmp/lvm-migration && cd /tmp/lvm-migration -5. Copy migration scripts from external drive or USB -6. Run: ./migrate_to_lvm.sh - -Drive Configuration (adjust as needed): -- Internal drive: /dev/nvme0n1 (source) -- External M.2: /dev/sdc (target) -- USB stick: /dev/sdb (tools) - -Important Notes: -- This will DESTROY all data on the external M.2 drive -- Internal drive remains unchanged as backup -- External M.2 will become bootable LVM system -- Update BIOS boot order after migration - -For full documentation, see LIVE_USB_MIGRATION_GUIDE.md -EOF -} - -# Create all the files -echo "Creating preparation script..." -create_prepare_script - -echo "Creating migration bootstrap..." -create_migration_script - -echo "Creating setup instructions..." -create_manual_setup - -# Create a simple launcher script -cat > bootstrap.sh << 'EOF' -#!/bin/bash -echo "=== LVM Migration Bootstrap ===" -echo "1. Prepare live system (install packages)" -echo "2. Run LVM migration" -echo "3. Show instructions" -read -p "Select option [1-3]: " choice - -case $choice in - 1) sudo ./prepare_live_system.sh ;; - 2) sudo ./migrate_to_lvm.sh ;; - 3) cat SETUP_INSTRUCTIONS.txt ;; - *) echo "Invalid option" ;; -esac -EOF -chmod +x bootstrap.sh - -echo -e "${GREEN}Bootstrap scripts created in $WORK_DIR${NC}" -echo -echo "Contents:" -ls -la - -echo -echo -e "${YELLOW}Next steps:${NC}" -echo "1. Copy the migration tools from your development directory to a location accessible from live USB" -echo "2. Boot from the USB stick" -echo "3. Run the bootstrap script to set up the migration environment" - -# Copy the actual migration tools if they exist in current directory -if [ -f "../migrate_to_lvm.sh" ]; then - echo - echo "Copying actual migration tools..." - cp ../migrate_to_lvm.sh ../lvm_snapshot_backup.sh ../validate_lvm_migration.sh . 2>/dev/null || true - cp ../LIVE_USB_MIGRATION_GUIDE.md . 2>/dev/null || true - echo "Migration tools copied to $WORK_DIR" -fi - -success "Bootstrap setup complete!" \ No newline at end of file diff --git a/lvm-migration-tools/check_packages.sh b/lvm-migration-tools/check_packages.sh deleted file mode 100755 index efee89e..0000000 --- a/lvm-migration-tools/check_packages.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash - -# Package Availability Checker for Live Systems -# Checks what packages are available before attempting installation - -set -e - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -log() { echo -e "${BLUE}[INFO]${NC} $1"; } -success() { echo -e "${GREEN}[FOUND]${NC} $1"; } -warning() { echo -e "${YELLOW}[MISSING]${NC} $1"; } - -echo -e "${GREEN}=== Package Availability Checker ===${NC}" -echo "Checking package availability for LVM migration..." -echo - -# Detect distribution -if [ -f /etc/os-release ]; then - . /etc/os-release - echo "Distribution: $PRETTY_NAME" - echo "ID: $ID" - echo "Version: $VERSION_ID" - echo -fi - -# Function to check if a package exists in repositories -check_package() { - local pkg="$1" - if apt-cache show "$pkg" >/dev/null 2>&1; then - success "$pkg" - return 0 - else - warning "$pkg" - return 1 - fi -} - -# Function to check multiple package alternatives -check_alternatives() { - local desc="$1" - shift - local packages=("$@") - - echo -e "${BLUE}$desc:${NC}" - local found=0 - for pkg in "${packages[@]}"; do - if check_package "$pkg"; then - ((found++)) - fi - done - - if [ $found -eq 0 ]; then - echo -e " ${RED}⚠ No packages found for $desc${NC}" - fi - echo -} - -echo "Updating package cache..." -apt update >/dev/null 2>&1 || warning "Could not update package cache" -echo - -# Check critical packages -total_missing=0 - -check_alternatives "LVM Tools" "lvm2" "lvm" -check_alternatives "Device Mapper" "dmsetup" "device-mapper" -check_alternatives "Cryptsetup" "cryptsetup" "cryptsetup-bin" -check_alternatives "Filesystem Tools" "e2fsprogs" "dosfstools" "parted" -check_alternatives "Backup Tools" "rsync" "pv" -check_alternatives "GRUB EFI" "grub-efi-amd64" "grub-efi" "grub-efi-amd64-bin" -check_alternatives "GRUB PC" "grub-pc-bin" "grub-pc" -check_alternatives "GRUB Common" "grub-common" "grub2-common" -check_alternatives "Initramfs" "initramfs-tools" "dracut" -check_alternatives "System Tools" "util-linux" "coreutils" "bc" - -echo -e "${BLUE}=== Summary ===${NC}" -echo -e "${GREEN}✓ Package availability checked${NC}" -echo "Most packages should be available for installation." - -echo -echo "To install packages, run:" -echo " sudo ./emergency_install.sh" -echo -echo "To check individual commands after installation:" -echo " command -v lvm && echo 'LVM available'" -echo " command -v cryptsetup && echo 'Cryptsetup available'" -echo " command -v grub-install && echo 'GRUB available'" \ No newline at end of file diff --git a/lvm-migration-tools/create_alpine_backup_usb.sh b/lvm-migration-tools/create_alpine_backup_usb.sh deleted file mode 100755 index 236a3cb..0000000 --- a/lvm-migration-tools/create_alpine_backup_usb.sh +++ /dev/null @@ -1,307 +0,0 @@ -#!/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 diff --git a/lvm-migration-tools/create_auto_startup.sh b/lvm-migration-tools/create_auto_startup.sh deleted file mode 100755 index bb5951c..0000000 --- a/lvm-migration-tools/create_auto_startup.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# Create automatic startup script for Clonezilla Live - -cat > /tmp/auto-backup-startup.sh << 'EOF' -#!/bin/bash -# Automatic startup script for Clonezilla Live -# This runs when auto_backup=true is passed as kernel parameter - -if grep -q "auto_backup=true" /proc/cmdline; then - echo "Automatic backup mode detected" - sleep 3 - - # Mount the backup partition - mkdir -p /tmp/backup_mount - mount /dev/sda2 /tmp/backup_mount 2>/dev/null - - if [ -f /tmp/backup_mount/automated_clonezilla_backup.sh ]; then - echo "Running automated backup script..." - /tmp/backup_mount/automated_clonezilla_backup.sh - else - echo "Automated backup script not found, starting manual Clonezilla" - ocs-live-general - fi -fi -EOF - -chmod +x /tmp/auto-backup-startup.sh -echo "Auto-startup script created" diff --git a/lvm-migration-tools/create_bootable_backup.sh b/lvm-migration-tools/create_bootable_backup.sh deleted file mode 100755 index 9c72249..0000000 --- a/lvm-migration-tools/create_bootable_backup.sh +++ /dev/null @@ -1,243 +0,0 @@ -#!/bin/bash -# Create Bootable Backup USB Script -# This creates a bootable USB that can perform system backups - -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" -echo "===========================================" -echo - -print_warning "This will create a bootable USB drive that can:" -print_warning "1. Boot into a minimal Linux environment" -print_warning "2. Automatically detect and backup your internal drive" -print_warning "3. Work completely offline (no running OS interference)" -echo - -# List available USB drives -print_status "Available USB drives:" -lsblk -d -o NAME,SIZE,TYPE,TRAN | grep "usb" || { - print_error "No USB drives detected!" - exit 1 -} - -echo -read -p "Enter the USB drive to make bootable (e.g., /dev/sdb): " USB_DRIVE - -if [[ ! -b "$USB_DRIVE" ]]; then - print_error "Device $USB_DRIVE does not exist!" - exit 1 -fi - -# Confirm USB drive selection -print_warning "⚠️ ALL DATA ON $USB_DRIVE WILL BE DESTROYED! ⚠️" -print_warning "This USB will become a bootable backup tool" -echo -lsblk "$USB_DRIVE" -echo -read -p "Are you sure you want to continue? (yes/no): " confirm - -if [[ "$confirm" != "yes" ]]; then - print_error "Operation cancelled" - exit 1 -fi - -print_status "Creating bootable backup USB..." - -# Unmount any existing partitions -sudo umount "${USB_DRIVE}"* 2>/dev/null || true - -# Create partition table and bootable partition -print_status "Creating partition table..." -sudo parted "$USB_DRIVE" --script mklabel gpt -sudo parted "$USB_DRIVE" --script mkpart ESP fat32 1MiB 512MiB -sudo parted "$USB_DRIVE" --script mkpart backup ext4 512MiB 100% -sudo parted "$USB_DRIVE" --script set 1 boot on - -# Format partitions -print_status "Formatting partitions..." -if [[ "$USB_DRIVE" == *"nvme"* ]]; then - BOOT_PART="${USB_DRIVE}p1" - DATA_PART="${USB_DRIVE}p2" -else - BOOT_PART="${USB_DRIVE}1" - DATA_PART="${USB_DRIVE}2" -fi - -sudo mkfs.fat -F32 -n "BOOT" "$BOOT_PART" -sudo mkfs.ext4 -L "BACKUP_TOOLS" "$DATA_PART" - -# Mount partitions -BOOT_MOUNT="/tmp/usb_boot_$$" -DATA_MOUNT="/tmp/usb_data_$$" -sudo mkdir -p "$BOOT_MOUNT" "$DATA_MOUNT" -sudo mount "$BOOT_PART" "$BOOT_MOUNT" -sudo mount "$DATA_PART" "$DATA_MOUNT" - -print_status "Installing backup tools..." - -# Copy backup scripts to data partition -SCRIPT_DIR=$(dirname "$(realpath "$0")") -sudo cp -r "$SCRIPT_DIR"/* "$DATA_MOUNT/" -sudo chmod +x "$DATA_MOUNT"/*.sh - -# Create autorun script for backup -sudo tee "$DATA_MOUNT/autorun_backup.sh" > /dev/null << 'EOF' -#!/bin/bash -# Auto-run backup script when booted from USB - -set -e - -# Colors -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -NC='\033[0m' - -echo -e "${GREEN}" -echo "========================================" -echo " BOOTABLE BACKUP SYSTEM STARTED" -echo "========================================" -echo -e "${NC}" - -# Wait for drives to be detected -sleep 5 - -echo "Detecting drives..." -echo - -# Auto-detect internal drive (largest non-USB drive) -INTERNAL_DRIVE=$(lsblk -d -n -o NAME,SIZE,TYPE,TRAN | grep "disk" | grep -v "usb" | sort -k2 -hr | head -1 | awk '{print "/dev/" $1}') - -# Auto-detect backup target (largest USB drive that's not the boot drive) -BOOT_USB=$(df /backup-tools | tail -1 | awk '{print $1}' | sed 's/[0-9]*$//') -TARGET_DRIVE=$(lsblk -d -n -o NAME,SIZE,TYPE,TRAN | grep "disk" | grep "usb" | awk '{print "/dev/" $1}' | grep -v "$BOOT_USB" | head -1) - -echo "Auto-detected configuration:" -echo "Internal drive: $INTERNAL_DRIVE" -echo "Target drive: $TARGET_DRIVE" -echo - -if [[ -z "$INTERNAL_DRIVE" || -z "$TARGET_DRIVE" ]]; then - echo -e "${RED}Could not auto-detect drives. Manual selection required.${NC}" - echo "Available drives:" - lsblk -d -o NAME,SIZE,TYPE,TRAN - echo - read -p "Enter source drive: " INTERNAL_DRIVE - read -p "Enter target drive: " TARGET_DRIVE -fi - -echo -e "${YELLOW}FINAL CONFIRMATION${NC}" -echo "Source (internal): $INTERNAL_DRIVE" -echo "Target (backup): $TARGET_DRIVE" -echo -echo -e "${RED}⚠️ TARGET DRIVE WILL BE COMPLETELY OVERWRITTEN! ⚠️${NC}" -echo -read -p "Continue with backup? (yes/no): " confirm - -if [[ "$confirm" != "yes" ]]; then - echo "Backup cancelled" - exit 0 -fi - -echo -e "${GREEN}Starting backup...${NC}" -cd /backup-tools -./backup_script.sh --source "$INTERNAL_DRIVE" --target "$TARGET_DRIVE" - -echo -e "${GREEN}" -echo "========================================" -echo " BACKUP COMPLETED SUCCESSFULLY!" -echo "========================================" -echo -e "${NC}" -echo "You can now:" -echo "1. Remove the USB drives" -echo "2. Reboot to your normal system" -echo "3. Use smart sync for future backups" -echo -read -p "Press Enter to shutdown system..." -shutdown -h now -EOF - -sudo chmod +x "$DATA_MOUNT/autorun_backup.sh" - -print_status "Downloading minimal Linux for USB boot..." - -# Check if we have a Linux ISO or create a simple boot setup -print_warning "Note: You'll need to manually add a bootable Linux distro" -print_warning "Recommendation: Use Ubuntu Live USB creator or similar" -print_warning "Then copy the backup tools to the USB" - -# Create instructions file -sudo tee "$DATA_MOUNT/INSTRUCTIONS.txt" > /dev/null << EOF -BOOTABLE BACKUP USB INSTRUCTIONS -================================== - -This USB contains backup tools but needs a bootable Linux environment. - -SETUP STEPS: -1. Use Ubuntu's "Startup Disk Creator" or similar tool -2. Create a bootable Ubuntu Live USB on this drive -3. Boot from this USB -4. Open terminal and run: - cd /media/ubuntu/BACKUP_TOOLS - sudo ./autorun_backup.sh - -AUTOMATIC BACKUP: -- The script will auto-detect your internal drive -- Auto-detect external backup target -- Perform complete system backup -- Shutdown when complete - -AFTER FIRST BACKUP: -- Boot back to your normal system -- Use the GUI for smart sync backups: - python3 backup_manager.py -- Click "Smart Sync Backup" for fast updates - -MANUAL BACKUP: -If auto-detection fails, you can run manually: -sudo ./backup_script.sh --source /dev/nvme0n1 --target /dev/sda -EOF - -# Cleanup -sudo umount "$BOOT_MOUNT" "$DATA_MOUNT" -sudo rmdir "$BOOT_MOUNT" "$DATA_MOUNT" - -print_success "Bootable backup USB preparation complete!" -print_success "USB: $USB_DRIVE" -echo -print_warning "NEXT STEPS:" -print_warning "1. Use Ubuntu's 'Startup Disk Creator' to make this USB bootable" -print_warning "2. Boot from USB in BIOS/UEFI boot menu" -print_warning "3. Run: sudo /media/ubuntu/BACKUP_TOOLS/autorun_backup.sh" -echo -print_success "After first backup, use GUI smart sync for incremental updates!" diff --git a/lvm-migration-tools/create_clonezilla_backup.sh b/lvm-migration-tools/create_clonezilla_backup.sh deleted file mode 100755 index b54e3e4..0000000 --- a/lvm-migration-tools/create_clonezilla_backup.sh +++ /dev/null @@ -1,412 +0,0 @@ -#!/bin/bash -# Create Clonezilla-based Backup USB -# This adapts Clonezilla Live with our custom backup functionality - -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" -} - -print_status "Clonezilla-based Backup USB Creator" -echo "======================================" -echo - -print_warning "This will enhance Clonezilla Live with our custom backup tools" -print_warning "You'll get both Clonezilla functionality AND our automated backup" -echo - -# Check if we have a USB drive -USB_DRIVE="/dev/sda" -if [[ ! -b "$USB_DRIVE" ]]; then - print_error "USB drive $USB_DRIVE not found!" - exit 1 -fi - -print_status "Current USB: $USB_DRIVE" -lsblk "$USB_DRIVE" -echo - -# Download Clonezilla if not already present -CLONEZILLA_ISO="clonezilla-live-3.1.0-22-amd64.iso" -# Using OSDN mirror which is typically faster than SourceForge -CLONEZILLA_URL="https://osdn.net/dl/clonezilla/$CLONEZILLA_ISO" - -if [[ ! -f "$CLONEZILLA_ISO" ]]; then - print_status "Downloading Clonezilla Live from OSDN mirror..." - wget "$CLONEZILLA_URL" || { - print_warning "OSDN mirror failed, trying GitHub mirror..." - CLONEZILLA_URL="https://github.com/stevenshiau/clonezilla/releases/download/3.1.0-22/$CLONEZILLA_ISO" - wget "$CLONEZILLA_URL" || { - print_warning "GitHub mirror failed, trying SourceForge as fallback..." - CLONEZILLA_URL="https://downloads.sourceforge.net/clonezilla/$CLONEZILLA_ISO" - wget "$CLONEZILLA_URL" || { - print_error "Failed to download Clonezilla from all mirrors" - exit 1 - } - } - } -fi - -print_warning "⚠️ This will COMPLETELY RECREATE the USB drive with Clonezilla! ⚠️" -print_warning "All current data will be lost!" -echo -read -p "Continue? (yes/no): " confirm - -if [[ "$confirm" != "yes" ]]; then - print_error "Operation cancelled" - exit 1 -fi - -print_status "Creating Clonezilla Live USB with backup tools..." - -# Unmount any mounted partitions -sudo umount "${USB_DRIVE}"* 2>/dev/null || true - -# Create new partition table -print_status "Creating partition table..." -sudo parted "$USB_DRIVE" --script mklabel msdos -sudo parted "$USB_DRIVE" --script mkpart primary fat32 1MiB 4GiB -sudo parted "$USB_DRIVE" --script mkpart primary ext4 4GiB 100% -sudo parted "$USB_DRIVE" --script set 1 boot on - -# Format partitions -print_status "Formatting partitions..." -if [[ "$USB_DRIVE" == *"nvme"* ]]; then - BOOT_PART="${USB_DRIVE}p1" - DATA_PART="${USB_DRIVE}p2" -else - BOOT_PART="${USB_DRIVE}1" - DATA_PART="${USB_DRIVE}2" -fi - -sudo mkfs.fat -F32 -n "CLONEZILLA" "$BOOT_PART" -sudo mkfs.ext4 -L "BACKUP_TOOLS" "$DATA_PART" - -# Mount partitions -BOOT_MOUNT="/tmp/clonezilla_boot_$$" -DATA_MOUNT="/tmp/clonezilla_data_$$" -ISO_MOUNT="/tmp/clonezilla_iso_$$" - -sudo mkdir -p "$BOOT_MOUNT" "$DATA_MOUNT" "$ISO_MOUNT" -sudo mount "$BOOT_PART" "$BOOT_MOUNT" -sudo mount "$DATA_PART" "$DATA_MOUNT" -sudo mount -o loop "$CLONEZILLA_ISO" "$ISO_MOUNT" - -print_status "Installing Clonezilla Live..." - -# Copy Clonezilla files -sudo cp -r "$ISO_MOUNT"/* "$BOOT_MOUNT/" - -# Install GRUB -print_status "Installing GRUB bootloader..." -sudo grub-install --target=i386-pc --boot-directory="$BOOT_MOUNT/boot" "$USB_DRIVE" - -# Create enhanced GRUB configuration -print_status "Creating enhanced GRUB menu..." -sudo tee "$BOOT_MOUNT/boot/grub/grub.cfg" > /dev/null << 'EOF' -set timeout=15 -set default=0 - -menuentry "🚀 AUTOMATIC SYSTEM BACKUP" { - linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset ocs_live_run="ocs-live-general" ocs_live_extra_param="" keyboard-layouts= ocs_live_batch="no" locales= vga=788 ip= net.ifnames=0 nosplash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1 systemd.show_status=0 - initrd /live/initrd.img -} - -menuentry "🔧 MANUAL BACKUP MODE" { - linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset ocs_live_run="ocs-live-general" ocs_live_extra_param="" keyboard-layouts= ocs_live_batch="no" locales= vga=788 ip= net.ifnames=0 nosplash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1 systemd.show_status=0 custom_backup=manual - initrd /live/initrd.img -} - -menuentry "📦 CLONEZILLA LIVE (Original)" { - linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset ocs_live_run="ocs-live-general" ocs_live_extra_param="" keyboard-layouts= ocs_live_batch="no" locales= vga=788 ip= net.ifnames=0 nosplash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1 - initrd /live/initrd.img -} - -menuentry "🛠️ CLONEZILLA EXPERT MODE" { - linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset ocs_live_run="ocs-expert" ocs_live_extra_param="" keyboard-layouts= ocs_live_batch="no" locales= vga=788 ip= net.ifnames=0 nosplash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1 - initrd /live/initrd.img -} - -menuentry "🔍 MEMORY TEST" { - linux16 /live/memtest -} -EOF - -print_status "Installing backup tools to data partition..." - -# Copy our backup scripts -SCRIPT_DIR=$(dirname "$(realpath "$0")") -sudo cp "$SCRIPT_DIR"/*.sh "$DATA_MOUNT/" -sudo chmod +x "$DATA_MOUNT"/*.sh - -# Also place the automated script in the Clonezilla filesystem for direct access -sudo mkdir -p "$BOOT_MOUNT/live/image/backup_tools" -sudo cp "$SCRIPT_DIR/automated_clonezilla_backup.sh" "$BOOT_MOUNT/live/image/backup_tools/" -sudo chmod +x "$BOOT_MOUNT/live/image/backup_tools/automated_clonezilla_backup.sh" - -# Create custom startup script that checks for auto_backup parameter -sudo tee "$BOOT_MOUNT/live/image/auto-start.sh" > /dev/null << 'EOF' -#!/bin/bash -# Check if auto_backup=true is in kernel parameters -if grep -q "auto_backup=true" /proc/cmdline; then - echo "Starting automatic backup mode..." - sleep 2 - # Mount backup partition and run our script - mkdir -p /tmp/backup_mount - mount /dev/sda2 /tmp/backup_mount 2>/dev/null - if [ -f /tmp/backup_mount/automated_clonezilla_backup.sh ]; then - /tmp/backup_mount/automated_clonezilla_backup.sh - else - echo "Backup script not found, starting normal Clonezilla" - ocs-live-general - fi -else - # Normal Clonezilla startup - ocs-live-general -fi -EOF - -sudo chmod +x "$BOOT_MOUNT/live/image/auto-start.sh" - -# Create startup script for Clonezilla -sudo tee "$DATA_MOUNT/auto-backup.sh" > /dev/null << 'EOF' -#!/bin/bash -# Auto-backup script for Clonezilla Live - -export PATH=/usr/bin:/bin:/sbin:/usr/sbin:/usr/local/bin - -# Colors -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -BLUE='\033[0;34m' -NC='\033[0m' - -clear -echo -e "${GREEN}" -echo "================================================" -echo " CLONEZILLA-BASED AUTOMATIC BACKUP" -echo "================================================" -echo -e "${NC}" - -# Check if we're in auto mode -AUTO_MODE="false" -if grep -q "custom_backup=auto" /proc/cmdline; then - AUTO_MODE="true" -fi - -# Wait for drives to settle -echo "Waiting for drives to be detected..." -sleep 5 - -# Function to list drives -list_drives() { - echo -e "${BLUE}Available drives:${NC}" - echo "==================" - lsblk -d -o NAME,SIZE,TYPE,TRAN,MODEL | grep -E "(NAME|disk)" - echo -} - -# Function to get drive selection -select_drives() { - list_drives - - echo -e "${YELLOW}SELECT SOURCE DRIVE (internal, to backup FROM):${NC}" - INTERNAL_DRIVES=$(lsblk -d -n -o NAME,TRAN | grep -v usb | grep -v loop | awk '{print $1}') - echo "$INTERNAL_DRIVES" | nl -v 1 - echo - read -p "Enter source drive number or path: " SOURCE_INPUT - - if echo "$SOURCE_INPUT" | grep -q "^[0-9]"; then - SOURCE_DRIVE="/dev/$(echo "$INTERNAL_DRIVES" | sed -n "${SOURCE_INPUT}p")" - else - SOURCE_DRIVE="$SOURCE_INPUT" - fi - - echo - echo -e "${YELLOW}SELECT TARGET DRIVE (external, will be OVERWRITTEN):${NC}" - EXTERNAL_DRIVES=$(lsblk -d -n -o NAME,TRAN | grep -v loop | awk '{print $1}') - echo "$EXTERNAL_DRIVES" | nl -v 1 - echo - read -p "Enter target drive number or path: " TARGET_INPUT - - if echo "$TARGET_INPUT" | grep -q "^[0-9]"; then - TARGET_DRIVE="/dev/$(echo "$EXTERNAL_DRIVES" | sed -n "${TARGET_INPUT}p")" - else - TARGET_DRIVE="$TARGET_INPUT" - fi -} - -# Function to perform backup -perform_backup() { - echo - echo -e "${GREEN}BACKUP CONFIGURATION:${NC}" - echo "====================" - echo "Source: $SOURCE_DRIVE" - echo "Target: $TARGET_DRIVE" - echo - - # Show sizes - if [[ -b "$SOURCE_DRIVE" ]]; then - SOURCE_SIZE=$(blockdev --getsize64 "$SOURCE_DRIVE" 2>/dev/null || echo "0") - SOURCE_GB=$((SOURCE_SIZE / 1024 / 1024 / 1024)) - echo "Source size: ${SOURCE_GB}GB" - fi - - if [[ -b "$TARGET_DRIVE" ]]; then - TARGET_SIZE=$(blockdev --getsize64 "$TARGET_DRIVE" 2>/dev/null || echo "0") - TARGET_GB=$((TARGET_SIZE / 1024 / 1024 / 1024)) - echo "Target size: ${TARGET_GB}GB" - fi - - echo - echo -e "${RED}⚠️ ALL DATA ON $TARGET_DRIVE WILL BE DESTROYED! ⚠️${NC}" - echo - - if [[ "$AUTO_MODE" == "true" ]]; then - echo "Auto mode - starting backup in 10 seconds..." - echo "(Press Ctrl+C to cancel)" - sleep 10 - else - read -p "Continue with backup? (yes/no): " CONFIRM - if [[ "$CONFIRM" != "yes" ]]; then - echo "Backup cancelled" - return 1 - fi - fi - - echo - echo -e "${GREEN}Starting backup...${NC}" - echo "==================" - - # Use dd for raw backup (like Clonezilla but simpler) - if command -v pv >/dev/null 2>&1; then - dd if="$SOURCE_DRIVE" bs=4M 2>/dev/null | pv -s "$SOURCE_SIZE" | dd of="$TARGET_DRIVE" bs=4M conv=fdatasync 2>/dev/null - else - dd if="$SOURCE_DRIVE" of="$TARGET_DRIVE" bs=4M status=progress conv=fdatasync - fi - - RESULT=$? - - echo - if [[ $RESULT -eq 0 ]]; then - echo -e "${GREEN}" - echo "================================================" - echo " BACKUP COMPLETED SUCCESSFULLY!" - echo "================================================" - echo -e "${NC}" - echo "Your system has been backed up to $TARGET_DRIVE" - echo "You can now use smart sync for future updates" - else - echo -e "${RED}" - echo "================================================" - echo " BACKUP FAILED!" - echo "================================================" - echo -e "${NC}" - fi - - echo - echo "System will shutdown in 30 seconds..." - echo "(Press any key to cancel shutdown)" - - if read -t 30 -n 1; then - echo - echo "Shutdown cancelled" - echo "You can now use Clonezilla or run another backup" - else - echo - echo "Shutting down..." - sudo shutdown -h now - fi -} - -# Main execution -if [[ "$AUTO_MODE" == "true" ]]; then - echo "🚀 AUTOMATIC BACKUP MODE" - echo "=========================" - echo -fi - -select_drives -perform_backup -EOF - -sudo chmod +x "$DATA_MOUNT/auto-backup.sh" - -# Create instructions -sudo tee "$DATA_MOUNT/README.txt" > /dev/null << 'EOF' -CLONEZILLA-BASED BACKUP USB -=========================== - -This USB combines Clonezilla Live with custom backup automation. - -BOOT MENU OPTIONS: -🚀 Automatic System Backup - Boots directly to backup menu -🔧 Manual Backup Mode - Access to both backup tools and Clonezilla -📦 Clonezilla Live - Original Clonezilla functionality -🛠️ Clonezilla Expert - Advanced Clonezilla options - -AUTOMATIC MODE: -- Auto-detects drives -- Interactive drive selection -- Raw dd backup (like Clonezilla) -- Progress display -- Auto-shutdown when complete - -MANUAL MODE: -- Access to shell -- Run: /media/user/BACKUP_TOOLS/auto-backup.sh -- Or use Clonezilla GUI - -ADVANTAGES: -✅ Proven boot compatibility (Clonezilla) -✅ Professional disk cloning tools -✅ Both automatic and manual modes -✅ Raw disk backup for maximum compatibility -✅ Works on virtually any hardware - -AFTER FIRST BACKUP: -Boot back to your normal system and use smart sync: -python3 backup_manager.py -EOF - -# Cleanup -sudo umount "$ISO_MOUNT" "$BOOT_MOUNT" "$DATA_MOUNT" -sudo rmdir "$ISO_MOUNT" "$BOOT_MOUNT" "$DATA_MOUNT" - -print_success "Clonezilla-based backup USB created!" -print_success "USB: $USB_DRIVE" -echo -print_success "FEATURES:" -print_success "✅ Clonezilla Live base (proven boot compatibility)" -print_success "✅ Custom backup automation" -print_success "✅ Automatic and manual modes" -print_success "✅ Professional disk cloning" -print_success "✅ Works on any hardware" -echo -print_warning "BOOT OPTIONS:" -print_warning "🚀 Automatic System Backup - Direct to backup" -print_warning "🔧 Manual Backup Mode - Shell + Clonezilla access" -print_warning "📦 Clonezilla Live - Original functionality" -echo -print_success "Ready to test! This should boot reliably in QEMU and real hardware." diff --git a/lvm-migration-tools/create_dd_backup_usb.sh b/lvm-migration-tools/create_dd_backup_usb.sh deleted file mode 100755 index 4fbd2f0..0000000 --- a/lvm-migration-tools/create_dd_backup_usb.sh +++ /dev/null @@ -1,332 +0,0 @@ -#!/bin/bash -# Create TRUE Plug-and-Play DD-based Backup USB -# Boot = Automatic backup with dd, no questions asked - -set -e - -USB_DRIVE="/dev/sda" - -echo "Creating TRUE PLUG-AND-PLAY Backup USB with DD" -echo "==============================================" -echo "• Boot USB = Automatic backup starts immediately" -echo "• Uses dd for maximum speed and reliability" -echo "• 15-20 minute full disk backup" -echo "• Also includes restore functionality" -echo - -# Check if we have a suitable live Linux ISO -ALPINE_ISO="alpine-extended-3.18.4-x86_64.iso" -if [[ ! -f "$ALPINE_ISO" ]]; then - echo "Downloading lightweight Alpine Linux..." - wget "https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/$ALPINE_ISO" || { - echo "Download failed. Please download Alpine Linux ISO manually." - exit 1 - } -fi - -read -p "Continue to create TRUE automatic backup USB? (yes/no): " confirm -if [[ "$confirm" != "yes" ]]; then - exit 1 -fi - -# Unmount and create single partition -sudo umount "${USB_DRIVE}"* 2>/dev/null || true -sudo parted "$USB_DRIVE" --script mklabel msdos -sudo parted "$USB_DRIVE" --script mkpart primary fat32 1MiB 100% -sudo parted "$USB_DRIVE" --script set 1 boot on - -# Format -USB_PART="${USB_DRIVE}1" -sudo mkfs.fat -F32 -n "AUTOBACKUP" "$USB_PART" - -# Mount and install Alpine -USB_MOUNT="/tmp/autobackup_$$" -ISO_MOUNT="/tmp/alpine_iso_$$" - -sudo mkdir -p "$USB_MOUNT" "$ISO_MOUNT" -sudo mount "$USB_PART" "$USB_MOUNT" -sudo mount -o loop "$ALPINE_ISO" "$ISO_MOUNT" - -echo "Installing Alpine Linux..." -sudo cp -R "$ISO_MOUNT"/* "$USB_MOUNT/" - -echo "Installing GRUB..." -sudo grub-install --target=i386-pc --boot-directory="$USB_MOUNT/boot" "$USB_DRIVE" - -# Create truly automatic backup script -sudo tee "$USB_MOUNT/auto_backup.sh" > /dev/null << 'EOF' -#!/bin/sh -# TRUE automatic backup script - no user interaction - -clear -echo "==========================================" -echo " AUTOMATIC SYSTEM BACKUP STARTING" -echo "==========================================" -echo "" -echo "This will backup your internal drive to this USB" -echo "Estimated time: 15-20 minutes" -echo "" -echo "Starting in 10 seconds... (Ctrl+C to cancel)" -echo "" - -# 10 second countdown -for i in 10 9 8 7 6 5 4 3 2 1; do - echo -n "$i... " - sleep 1 -done -echo "" -echo "" - -# Auto-detect internal drive (exclude USB drives) -INTERNAL_DRIVE="" -for drive in /dev/nvme0n1 /dev/sda /dev/sdb /dev/sdc; do - if [ -b "$drive" ]; then - # Check if it's not a USB drive and has partitions - if ! echo "$drive" | grep -q "/dev/sda" && [ "$(lsblk -n "$drive" | wc -l)" -gt 1 ]; then - INTERNAL_DRIVE="$drive" - break - fi - fi -done - -if [ -z "$INTERNAL_DRIVE" ]; then - echo "ERROR: Could not detect internal drive!" - echo "Available drives:" - lsblk - echo "" - echo "Press Enter to try manual backup..." - read dummy - /auto_backup_manual.sh - exit 1 -fi - -# Get drive sizes -INTERNAL_SIZE=$(blockdev --getsize64 "$INTERNAL_DRIVE" 2>/dev/null || echo "0") -USB_SIZE=$(blockdev --getsize64 /dev/sda 2>/dev/null || echo "0") - -INTERNAL_GB=$((INTERNAL_SIZE / 1024 / 1024 / 1024)) -USB_GB=$((USB_SIZE / 1024 / 1024 / 1024)) - -echo "BACKUP CONFIGURATION:" -echo "Source: $INTERNAL_DRIVE (${INTERNAL_GB}GB)" -echo "Target: /dev/sda (${USB_GB}GB)" -echo "" - -# Check space -if [ "$INTERNAL_SIZE" -gt "$USB_SIZE" ]; then - echo "WARNING: Target drive might be too small!" - echo "This backup may not complete successfully." - echo "" -fi - -echo "Starting backup with maximum speed..." -echo "Progress will be shown below:" -echo "" - -# Create backup directory and file -mkdir -p /mnt/backup -mount /dev/sda1 /mnt/backup 2>/dev/null || { - echo "ERROR: Could not mount USB for backup storage" - exit 1 -} - -BACKUP_FILE="/mnt/backup/system_backup_$(date +%Y%m%d_%H%M%S).img" - -echo "Backup file: $BACKUP_FILE" -echo "" - -# Perform backup with progress using dd and pv -if which pv >/dev/null 2>&1; then - # Use pv for progress if available - dd if="$INTERNAL_DRIVE" bs=4M status=none | pv -s "$INTERNAL_SIZE" | dd of="$BACKUP_FILE" bs=4M status=none -else - # Fallback to dd with progress - dd if="$INTERNAL_DRIVE" of="$BACKUP_FILE" bs=4M status=progress -fi - -# Verify and finish -sync -echo "" -echo "==========================================" -echo " BACKUP COMPLETED SUCCESSFULLY!" -echo "==========================================" -echo "" -echo "Backup saved to: $BACKUP_FILE" -echo "Backup size: $(du -h "$BACKUP_FILE" | cut -f1)" -echo "" - -# Create restore script -cat > "/mnt/backup/restore_$(date +%Y%m%d_%H%M%S).sh" << RESTORE_EOF -#!/bin/sh -# Restore script for backup created $(date) - -BACKUP_FILE="$BACKUP_FILE" -TARGET_DRIVE="\$1" - -if [ -z "\$TARGET_DRIVE" ]; then - echo "Usage: \$0 /dev/target_drive" - echo "Example: \$0 /dev/nvme0n1" - echo "" - echo "Available drives:" - lsblk - exit 1 -fi - -echo "WARNING: This will completely overwrite \$TARGET_DRIVE" -echo "Source: \$BACKUP_FILE" -echo "Target: \$TARGET_DRIVE" -echo "" -read -p "Type 'RESTORE' to confirm: " confirm - -if [ "\$confirm" != "RESTORE" ]; then - echo "Cancelled" - exit 1 -fi - -echo "Restoring system..." -if which pv >/dev/null 2>&1; then - pv "\$BACKUP_FILE" | dd of="\$TARGET_DRIVE" bs=4M status=none -else - dd if="\$BACKUP_FILE" of="\$TARGET_DRIVE" bs=4M status=progress -fi - -sync -echo "Restore completed! System should be bootable." -RESTORE_EOF - -chmod +x "/mnt/backup/restore_$(date +%Y%m%d_%H%M%S).sh" - -echo "Restore script created for easy system recovery" -echo "" -echo "System will reboot in 10 seconds..." -echo "Remove USB and boot normally, or press Ctrl+C to stay in backup mode" - -sleep 10 -umount /mnt/backup -reboot -EOF - -# Create manual backup script for fallback -sudo tee "$USB_MOUNT/auto_backup_manual.sh" > /dev/null << 'EOF' -#!/bin/sh -# Manual backup mode - for when auto-detection fails - -echo "==========================================" -echo " MANUAL BACKUP MODE" -echo "==========================================" -echo "" -echo "Available drives:" -lsblk -echo "" - -echo "Enter source drive (internal drive to backup):" -read -p "Source (e.g., /dev/nvme0n1): " SOURCE_DRIVE - -if [ ! -b "$SOURCE_DRIVE" ]; then - echo "ERROR: $SOURCE_DRIVE is not a valid block device" - exit 1 -fi - -echo "" -echo "Backup will be saved to this USB drive (/dev/sda)" -echo "Source: $SOURCE_DRIVE" -echo "Target: USB backup file" -echo "" -read -p "Press Enter to start backup or Ctrl+C to cancel..." - -# Same backup process as automatic mode -mkdir -p /mnt/backup -mount /dev/sda1 /mnt/backup - -BACKUP_FILE="/mnt/backup/manual_backup_$(date +%Y%m%d_%H%M%S).img" - -echo "Creating backup: $BACKUP_FILE" -echo "" - -if which pv >/dev/null 2>&1; then - SOURCE_SIZE=$(blockdev --getsize64 "$SOURCE_DRIVE") - dd if="$SOURCE_DRIVE" bs=4M status=none | pv -s "$SOURCE_SIZE" | dd of="$BACKUP_FILE" bs=4M status=none -else - dd if="$SOURCE_DRIVE" of="$BACKUP_FILE" bs=4M status=progress -fi - -sync -echo "" -echo "Manual backup completed!" -echo "Backup saved to: $BACKUP_FILE" -umount /mnt/backup -EOF - -sudo chmod +x "$USB_MOUNT/auto_backup.sh" -sudo chmod +x "$USB_MOUNT/auto_backup_manual.sh" - -# Create GRUB menu for true automation -sudo tee "$USB_MOUNT/boot/grub/grub.cfg" > /dev/null << 'EOF' -set timeout=5 -set default=0 - -menuentry "AUTOMATIC BACKUP (5 second countdown)" { - linux /boot/vmlinuz-lts root=/dev/sda1 rw quiet init=/auto_backup.sh - initrd /boot/initramfs-lts -} - -menuentry "Manual Backup Mode" { - linux /boot/vmlinuz-lts root=/dev/sda1 rw quiet init=/auto_backup_manual.sh - initrd /boot/initramfs-lts -} - -menuentry "Alpine Linux (Recovery Console)" { - linux /boot/vmlinuz-lts root=/dev/sda1 rw quiet - initrd /boot/initramfs-lts -} -EOF - -# Install pv for progress monitoring -sudo mkdir -p "$USB_MOUNT/apks" -echo "Adding progress monitoring tool..." - -# Create final instructions -sudo tee "$USB_MOUNT/TRUE_PLUG_AND_PLAY_INSTRUCTIONS.txt" > /dev/null << 'EOF' -TRUE PLUG-AND-PLAY BACKUP USB -============================ - -🚀 AUTOMATIC BACKUP: -1. Boot from this USB -2. Wait 5 seconds (automatic backup starts) -3. Wait for 10-second countdown -4. Backup runs automatically (15-20 minutes) -5. System reboots when done - -🔧 MANUAL BACKUP: -1. Boot from USB -2. Select "Manual Backup Mode" -3. Follow prompts to select drives -4. Backup proceeds automatically - -💾 RESTORE SYSTEM: -1. Boot from USB -2. Select "Alpine Linux (Recovery Console)" -3. Run: /restore_XXXXXXXX.sh /dev/target_drive -4. Follow prompts - -TRULY AUTOMATIC: -- No Clonezilla menus -- No device selection -- No compression choices -- Just boot and wait! - -Created: $(date) -EOF - -# Cleanup -sudo umount "$ISO_MOUNT" "$USB_MOUNT" -sudo rmdir "$USB_MOUNT" "$ISO_MOUNT" - -echo "" -echo "✅ TRUE PLUG-AND-PLAY BACKUP USB CREATED!" -echo "✅ Boot USB = 5 second countdown then AUTOMATIC backup" -echo "✅ Uses dd for maximum reliability and speed" -echo "✅ Creates restore scripts automatically" -echo "✅ No menus, no choices - just boot and wait!" -echo "" -echo "DISASTER RECOVERY: Boot USB, wait 15 seconds, backup happens!" diff --git a/lvm-migration-tools/emergency_install.sh b/lvm-migration-tools/emergency_install.sh deleted file mode 100755 index b049777..0000000 --- a/lvm-migration-tools/emergency_install.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/bin/bash - -# Emergency Package Installer for LVM Migration -# Handles different Debian/Ubuntu distributions and package availability - -set -e - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1"; } -error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } -success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } -warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } - -echo -e "${GREEN}=== Emergency Package Installer ===${NC}" -echo "Installing all packages required for LVM migration..." - -# Check if running as root -if [ "$EUID" -ne 0 ]; then - error "This script must be run as root. Use: sudo $0" - exit 1 -fi - -# Detect distribution -if [ -f /etc/os-release ]; then - . /etc/os-release - DISTRO="$ID" - VERSION="$VERSION_ID" - log "Detected distribution: $PRETTY_NAME" -else - DISTRO="unknown" - warning "Could not detect distribution" -fi - -# Update package lists -log "Updating package lists..." -apt update || warning "Failed to update package lists" - -# Function to try installing a package with alternatives -try_install_package() { - local primary="$1" - shift - local alternatives=("$@") - - log "Installing $primary..." - if apt install -y "$primary" >/dev/null 2>&1; then - success "Installed $primary" - return 0 - fi - - # Try alternatives - for alt in "${alternatives[@]}"; do - log "Trying alternative: $alt" - if apt install -y "$alt" >/dev/null 2>&1; then - success "Installed $alt (alternative for $primary)" - return 0 - fi - done - - warning "Failed to install $primary or any alternatives" - return 1 -} - -# Install packages with error handling and alternatives -log "Installing core utilities..." -try_install_package "util-linux" -try_install_package "coreutils" -try_install_package "bc" -try_install_package "bsdmainutils" "bsdutils" - -log "Installing LVM and device mapper tools..." -try_install_package "lvm2" -try_install_package "dmsetup" "device-mapper" - -log "Installing encryption tools..." -try_install_package "cryptsetup" "cryptsetup-bin" - -log "Installing filesystem tools..." -try_install_package "e2fsprogs" -try_install_package "dosfstools" "mtools" -try_install_package "parted" - -log "Installing backup and monitoring tools..." -try_install_package "rsync" -try_install_package "pv" "pipe-viewer" - -log "Installing GRUB bootloader components..." -# Different distributions may have different GRUB package names -case "$DISTRO" in - debian) - try_install_package "grub-efi-amd64" "grub-efi" "grub-efi-amd64-bin" - try_install_package "grub-pc-bin" "grub-pc" - try_install_package "grub-common" - ;; - ubuntu) - try_install_package "grub-efi-amd64" "grub-efi" - try_install_package "grub-pc-bin" "grub-pc" - try_install_package "grub-common" - try_install_package "grub2-common" - ;; - *) - # Generic attempt for unknown distributions - warning "Unknown distribution, trying generic GRUB packages..." - try_install_package "grub-efi-amd64" "grub-efi" "grub" - try_install_package "grub-pc-bin" "grub-pc" "grub" - try_install_package "grub-common" "grub2-common" - ;; -esac - -log "Installing kernel and initramfs tools..." -try_install_package "initramfs-tools" "dracut" -# Don't install kernel on live system as it's not needed and may cause issues -# try_install_package "linux-image-generic" "linux-image-amd64" - -log "Installing additional required tools..." -try_install_package "udev" "systemd-udev" -try_install_package "kmod" "module-init-tools" - -# Load kernel modules -log "Loading required kernel modules..." -modprobe dm_mod 2>/dev/null || warning "Failed to load dm_mod" -modprobe dm_crypt 2>/dev/null || warning "Failed to load dm_crypt" -modprobe dm_snapshot 2>/dev/null || warning "Failed to load dm_snapshot" - -# Check if LVM service is available and start it -if systemctl list-unit-files | grep -q lvm2; then - log "Starting LVM services..." - systemctl start lvm2-monitor 2>/dev/null || warning "Could not start lvm2-monitor" - systemctl start lvm2-lvmpolld 2>/dev/null || warning "Could not start lvm2-lvmpolld" -fi - -# Verify critical tools are available -log "Verifying tool installation..." -missing_critical=() - -# Check for tool availability with alternatives -check_tool() { - local primary="$1" - shift - local alternatives=("$@") - - if command -v "$primary" >/dev/null 2>&1; then - return 0 - fi - - for alt in "${alternatives[@]}"; do - if command -v "$alt" >/dev/null 2>&1; then - return 0 - fi - done - - missing_critical+=("$primary") - return 1 -} - -check_tool "lvm" "lvm2" -check_tool "vgdisplay" "lvm" -check_tool "pvcreate" "lvm" -check_tool "lvcreate" "lvm" -check_tool "cryptsetup" -check_tool "rsync" -check_tool "parted" -check_tool "pv" -check_tool "mkfs.ext4" "mke2fs" -check_tool "mkfs.fat" "mkfs.vfat" -check_tool "grub-install" "grub2-install" -check_tool "update-grub" "grub-mkconfig" -check_tool "update-initramfs" "dracut" - -if [ ${#missing_critical[@]} -eq 0 ]; then - success "All critical tools are now available!" - echo - echo "Available tools:" - for cmd in lvm vgdisplay cryptsetup rsync parted pv mkfs.ext4 grub-install; do - if command -v "$cmd" >/dev/null 2>&1; then - echo " ✓ $cmd: $(which $cmd)" - fi - done - echo - echo "You can now run: ./migrate_to_lvm.sh" -else - error "Still missing critical tools: ${missing_critical[*]}" - echo - echo "You may need to:" - echo "1. Check internet connection for package downloads" - echo "2. Try different package repositories" - echo "3. Install packages manually with different names" - echo "4. Use a different live system distribution" - exit 1 -fi - -echo -echo -e "${GREEN}Installation completed successfully!${NC}" -echo "The system is now ready for LVM migration." -echo -echo "Next steps:" -echo "1. Run: ./migrate_to_lvm.sh" -echo "2. Follow the interactive prompts" -echo "3. Validate with: ./validate_lvm_migration.sh" \ No newline at end of file diff --git a/lvm-migration-tools/fix_alpine_boot.sh b/lvm-migration-tools/fix_alpine_boot.sh deleted file mode 100755 index 3206532..0000000 --- a/lvm-migration-tools/fix_alpine_boot.sh +++ /dev/null @@ -1,297 +0,0 @@ -#!/bin/bash -# Fix Alpine Boot for Automatic Backup - -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" -} - -print_status "Fixing Alpine Boot Configuration for Automatic Backup" -echo "========================================================" - -USB_DRIVE="/dev/sda" - -# Mount USB partitions -BOOT_MOUNT="/tmp/fix_boot_$$" -DATA_MOUNT="/tmp/fix_data_$$" - -mkdir -p "$BOOT_MOUNT" "$DATA_MOUNT" -sudo mount "${USB_DRIVE}1" "$BOOT_MOUNT" -sudo mount "${USB_DRIVE}2" "$DATA_MOUNT" - -print_status "Creating proper GRUB configuration..." - -# Create a better GRUB configuration -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 nomodeset console=tty0 alpine_dev=sda2:ext4 alpine_repo=http://dl-cdn.alpinelinux.org/alpine/v3.18/main/ modloop=/boot/modloop-lts apkovl=/backup-tools/alpine.apkovl.tar.gz autobackup=yes - initrd /boot/initramfs-lts -} - -menuentry "Manual Backup Shell" { - linux /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage console=tty0 alpine_dev=sda2:ext4 alpine_repo=http://dl-cdn.alpinelinux.org/alpine/v3.18/main/ modloop=/boot/modloop-lts apkovl=/backup-tools/alpine.apkovl.tar.gz - initrd /boot/initramfs-lts -} - -menuentry "Alpine Linux Recovery" { - linux /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage console=tty0 - initrd /boot/initramfs-lts -} -EOF - -print_status "Creating improved Alpine overlay..." - -# Create a new overlay with better startup script -OVERLAY_DIR="/tmp/overlay_$$" -mkdir -p "$OVERLAY_DIR"/{etc/init.d,etc/runlevels/default,usr/local/bin,root} - -# Create the main backup script -sudo tee "$OVERLAY_DIR/usr/local/bin/backup-system" > /dev/null << 'EOF' -#!/bin/sh -# Main backup system script - -export PATH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin - -clear -echo "========================================" -echo " BOOTABLE BACKUP SYSTEM" -echo "========================================" -echo - -# Function to detect drives -detect_drives() { - echo "Detecting drives..." - sleep 3 - - # Get all block devices - echo "Available drives:" - echo "==================" - lsblk -d -o NAME,SIZE,TYPE,TRAN | head -20 - echo - - # Auto-detect candidates - echo "Drive candidates:" - echo "Internal drives (non-USB):" - lsblk -d -n -o NAME,SIZE,TRAN | grep -v usb | grep -v sda | nl -v 1 - echo - echo "External drives (USB, excluding boot drive):" - lsblk -d -n -o NAME,SIZE,TRAN | grep usb | grep -v sda | nl -v 1 - echo -} - -# Function to get user choice -get_drives() { - # Source drive selection - echo "SELECT SOURCE DRIVE (internal drive to backup):" - echo "================================================" - INTERNAL_LIST=$(lsblk -d -n -o NAME | grep -v sda | grep -v loop) - echo "$INTERNAL_LIST" | nl -v 1 - echo - read -p "Enter source drive number or full path (e.g., /dev/nvme0n1): " SOURCE_INPUT - - if echo "$SOURCE_INPUT" | grep -q "^[0-9]"; then - SOURCE_DRIVE="/dev/$(echo "$INTERNAL_LIST" | sed -n "${SOURCE_INPUT}p")" - else - SOURCE_DRIVE="$SOURCE_INPUT" - fi - - # Target drive selection - echo - echo "SELECT TARGET DRIVE (external drive, will be OVERWRITTEN):" - echo "==========================================================" - EXTERNAL_LIST=$(lsblk -d -n -o NAME | grep -v sda | grep -v loop) - echo "$EXTERNAL_LIST" | nl -v 1 - echo - read -p "Enter target drive number or full path: " TARGET_INPUT - - if echo "$TARGET_INPUT" | grep -q "^[0-9]"; then - TARGET_DRIVE="/dev/$(echo "$EXTERNAL_LIST" | sed -n "${TARGET_INPUT}p")" - else - TARGET_DRIVE="$TARGET_INPUT" - fi -} - -# Function to confirm and backup -run_backup() { - echo - echo "BACKUP CONFIGURATION:" - echo "====================" - echo "Source: $SOURCE_DRIVE (will be copied FROM)" - echo "Target: $TARGET_DRIVE (will be OVERWRITTEN)" - echo - - # Show drive sizes - if [ -b "$SOURCE_DRIVE" ]; then - SOURCE_SIZE=$(blockdev --getsize64 "$SOURCE_DRIVE" 2>/dev/null || echo "unknown") - if [ "$SOURCE_SIZE" != "unknown" ]; then - SOURCE_GB=$((SOURCE_SIZE / 1024 / 1024 / 1024)) - echo "Source size: ${SOURCE_GB}GB" - fi - fi - - if [ -b "$TARGET_DRIVE" ]; then - TARGET_SIZE=$(blockdev --getsize64 "$TARGET_DRIVE" 2>/dev/null || echo "unknown") - if [ "$TARGET_SIZE" != "unknown" ]; then - TARGET_GB=$((TARGET_SIZE / 1024 / 1024 / 1024)) - echo "Target size: ${TARGET_GB}GB" - fi - fi - - 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" - return 1 - fi - - echo - echo "Starting backup..." - echo "==================" - - # Check if pv is available for progress - if command -v pv >/dev/null 2>&1; then - echo "Using pv for progress display" - dd if="$SOURCE_DRIVE" bs=4M 2>/dev/null | pv -s "$SOURCE_SIZE" | dd of="$TARGET_DRIVE" bs=4M conv=fdatasync 2>/dev/null - else - echo "Using dd with status=progress" - dd if="$SOURCE_DRIVE" of="$TARGET_DRIVE" bs=4M status=progress conv=fdatasync - fi - - RESULT=$? - - echo - if [ $RESULT -eq 0 ]; then - echo "========================================" - echo " BACKUP COMPLETED SUCCESSFULLY!" - echo "========================================" - else - echo "========================================" - echo " BACKUP FAILED!" - echo "========================================" - fi - - echo - echo "System will shutdown in 30 seconds..." - echo "(Press Ctrl+C to cancel)" - - # Countdown - for i in 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1; do - echo -n "$i " - sleep 1 - done - - echo - echo "Shutting down..." - poweroff -} - -# Main execution -detect_drives -get_drives -run_backup -EOF - -chmod +x "$OVERLAY_DIR/usr/local/bin/backup-system" - -# Create init script that runs 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 bootmisc -} - -start() { - # Check if autobackup parameter was passed - if grep -q "autobackup=yes" /proc/cmdline; then - ebegin "Starting automatic backup system" - - # Wait for devices to settle - sleep 5 - - # Run backup system - /usr/local/bin/backup-system - - eend $? - fi -} -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 profile for manual shell access -sudo tee "$OVERLAY_DIR/root/.profile" > /dev/null << 'EOF' -export PATH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin - -echo "========================================" -echo " BACKUP SYSTEM SHELL ACCESS" -echo "========================================" -echo -echo "Available commands:" -echo " backup-system - Start interactive backup" -echo " lsblk - List block devices" -echo " fdisk -l - List partitions" -echo -echo "Manual backup example:" -echo " dd if=/dev/nvme0n1 of=/dev/sdb bs=4M status=progress" -echo -EOF - -# Create the overlay archive -cd "$OVERLAY_DIR" -tar czf "$DATA_MOUNT/alpine.apkovl.tar.gz" * -cd - - -# Copy backup tools -SCRIPT_DIR=$(dirname "$(realpath "$0")") -sudo cp "$SCRIPT_DIR"/*.sh "$DATA_MOUNT/" 2>/dev/null || true - -# Cleanup -sudo umount "$BOOT_MOUNT" "$DATA_MOUNT" -rmdir "$BOOT_MOUNT" "$DATA_MOUNT" -rm -rf "$OVERLAY_DIR" - -print_success "Alpine boot configuration fixed!" -print_success "USB: $USB_DRIVE" -echo -print_success "Fixed Issues:" -print_success "✅ Proper GRUB kernel parameters" -print_success "✅ Correct Alpine overlay loading" -print_success "✅ Automatic backup service startup" -print_success "✅ Interactive drive selection" -print_success "✅ Manual shell access option" -echo -print_warning "Now test by booting from USB and selecting 'Automatic System Backup'" diff --git a/lvm-migration-tools/install.sh b/lvm-migration-tools/install.sh deleted file mode 100755 index 1350141..0000000 --- a/lvm-migration-tools/install.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/bin/bash -# Installation script for System Backup Tool - -set -e - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -# Print colored output -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 -check_root() { - if [[ $EUID -eq 0 ]]; then - print_error "Do not run this installer as root. It will use sudo when needed." - exit 1 - fi -} - -# Check dependencies -check_dependencies() { - print_status "Checking dependencies..." - - # Check Python 3 - if ! command -v python3 &> /dev/null; then - print_error "Python 3 is required but not installed" - exit 1 - fi - - # Check tkinter - if ! python3 -c "import tkinter" &> /dev/null; then - print_warning "tkinter not available. Installing python3-tk..." - sudo apt update - sudo apt install -y python3-tk - fi - - # Check for pv (progress viewer) - if ! command -v pv &> /dev/null; then - print_warning "pv (progress viewer) not found. Installing..." - sudo apt install -y pv - fi - - print_success "All dependencies satisfied" -} - -# Make scripts executable -setup_permissions() { - print_status "Setting up permissions..." - - chmod +x backup_manager.py - chmod +x backup_script.sh - - print_success "Permissions set" -} - -# Create desktop entry -create_desktop_entry() { - print_status "Creating desktop entry..." - - local desktop_dir="$HOME/Desktop" - local applications_dir="$HOME/.local/share/applications" - local script_path=$(realpath backup_manager.py) - local icon_path=$(realpath ".") - - # Create applications directory if it doesn't exist - mkdir -p "$applications_dir" - - # Create desktop entry content - local desktop_content="[Desktop Entry] -Version=1.0 -Type=Application -Name=System Backup Manager -Comment=Clone internal drive to external M.2 SSD -Exec=python3 '$script_path' -Icon=drive-harddisk -Terminal=false -Categories=System;Utility; -StartupNotify=true" - - # Create desktop file in applications - echo "$desktop_content" > "$applications_dir/system-backup.desktop" - chmod +x "$applications_dir/system-backup.desktop" - - # Create desktop shortcut if Desktop directory exists - if [[ -d "$desktop_dir" ]]; then - echo "$desktop_content" > "$desktop_dir/System Backup.desktop" - chmod +x "$desktop_dir/System Backup.desktop" - print_success "Desktop shortcut created" - fi - - print_success "Application entry created" -} - -# Create systemd service (optional) -create_systemd_service() { - local service_dir="systemd" - local script_path=$(realpath backup_script.sh) - - print_status "Creating systemd service template..." - - mkdir -p "$service_dir" - - cat > "$service_dir/backup-service.service" << EOF -[Unit] -Description=System Backup Service -After=multi-user.target - -[Service] -Type=oneshot -ExecStart=$script_path --target /dev/sdb -User=root -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - - cat > "$service_dir/README.md" << EOF -# Systemd Service for Backup - -To install the systemd service: - -1. Edit the service file to specify your target drive -2. Copy to systemd directory: - \`\`\`bash - sudo cp backup-service.service /etc/systemd/system/ - \`\`\` - -3. Enable and start: - \`\`\`bash - sudo systemctl daemon-reload - sudo systemctl enable backup-service - sudo systemctl start backup-service - \`\`\` - -4. Check status: - \`\`\`bash - sudo systemctl status backup-service - \`\`\` -EOF - - print_success "Systemd service template created in systemd/" -} - -# Create log directory -setup_logging() { - print_status "Setting up logging..." - - # Create log file with proper permissions - sudo touch /var/log/system_backup.log - sudo chmod 666 /var/log/system_backup.log - - print_success "Log file created: /var/log/system_backup.log" -} - -# Main installation function -main() { - echo "" - echo "======================================" - echo " System Backup Tool Installer" - echo "======================================" - echo "" - - check_root - check_dependencies - setup_permissions - setup_logging - create_desktop_entry - create_systemd_service - - echo "" - print_success "Installation completed successfully!" - echo "" - echo "You can now:" - echo " • Launch GUI: python3 backup_manager.py" - echo " • Use CLI: ./backup_script.sh --help" - echo " • Click desktop icon: System Backup Manager" - echo "" - print_warning "Remember to run the backup tool with appropriate privileges" - print_warning "Always verify your drive selections before starting backup" - echo "" -} - -# Run installer -main "$@" diff --git a/lvm-migration-tools/migrate_to_lvm.sh b/lvm-migration-tools/migrate_to_lvm.sh deleted file mode 100755 index 5b6b862..0000000 --- a/lvm-migration-tools/migrate_to_lvm.sh +++ /dev/null @@ -1,1086 +0,0 @@ -#!/bin/bash - -# Migration Script: Non-LVM to LVM System Migration -# This script migrates a running system to an external M.2 SSD with LVM support -# MUST BE RUN FROM A LIVE USB SYSTEM - NOT FROM THE SYSTEM BEING MIGRATED - -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 - -# Configuration variables (will be auto-detected) -INTERNAL_DRIVE="" -EXTERNAL_DRIVE="" -VG_NAME="system-vg" -ROOT_LV="root" -HOME_LV="home" -SWAP_LV="swap" -BOOT_LV="boot" - -# Size configurations (will be calculated based on source sizes) -ROOT_SIZE="" -HOME_SIZE="" -SWAP_SIZE="" -BOOT_SIZE="" - -# Detected partitions and filesystems -declare -A INTERNAL_PARTITIONS -declare -A PARTITION_MOUNTS -declare -A PARTITION_FILESYSTEMS -declare -A PARTITION_SIZES - -# Mount points -WORK_DIR="/mnt/migration" -INTERNAL_ROOT_MOUNT="$WORK_DIR/internal_root" -INTERNAL_HOME_MOUNT="$WORK_DIR/internal_home" -INTERNAL_BOOT_MOUNT="$WORK_DIR/internal_boot" -EXTERNAL_ROOT_MOUNT="$WORK_DIR/external_root" -EXTERNAL_HOME_MOUNT="$WORK_DIR/external_home" -EXTERNAL_BOOT_MOUNT="$WORK_DIR/external_boot" - -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" -} - -confirm_action() { - echo -e "${YELLOW}$1${NC}" - read -p "Do you want to continue? [y/N] " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - error "Operation aborted by user" - fi -} - -detect_drives() { - log "Detecting available drives..." - - # Find all block devices that are disks (not partitions), excluding the live USB - local all_drives=($(lsblk -dpno NAME,TYPE,SIZE,MODEL | grep "disk" | awk '{print $1}')) - local drives=() - - # Filter out the USB stick we're running from (if running from live system) - for drive in "${all_drives[@]}"; do - # Check if this drive contains the live system - if mount | grep "$drive" | grep -q "/lib/live\|/media.*MIGRATION_TOOLS"; then - log "Excluding live USB drive: $drive" - continue - fi - drives+=("$drive") - done - - if [ ${#drives[@]} -lt 2 ]; then - error "Need at least 2 drives for migration. Found only ${#drives[@]} suitable drives" - echo "Available drives:" - for drive in "${all_drives[@]}"; do - local info=$(lsblk -dpno NAME,SIZE,MODEL "$drive" | awk '{print $2 " " $3}') - echo " $drive - $info" - done - exit 1 - fi - - echo - echo "Available drives for migration:" - for i in "${!drives[@]}"; do - local drive="${drives[$i]}" - local info=$(lsblk -dpno NAME,SIZE,MODEL "$drive" | awk '{print $2 " " $3}' | xargs) - local is_usb="" - - # Check if it's a USB drive - if udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then - is_usb=" (USB)" - fi - - echo "$((i+1)). $drive - $info$is_usb" - done - - echo - echo "Please identify your drives:" - echo "- Internal drive: Usually NVMe (like nvme0n1) or first SATA (like sda)" - echo "- External M.2: Usually USB-connected, larger capacity" - echo - - # Auto-detection with user confirmation - local suggested_internal="" - local suggested_external="" - - # Try to suggest internal drive (prefer NVMe, then non-USB drives) - for drive in "${drives[@]}"; do - if [[ "$drive" == *"nvme"* ]]; then - suggested_internal="$drive" - break - fi - done - - if [ -z "$suggested_internal" ]; then - # If no NVMe, prefer non-USB drives - for drive in "${drives[@]}"; do - if ! udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then - suggested_internal="$drive" - break - fi - done - fi - - # Try to suggest external drive (prefer USB, larger capacity) - for drive in "${drives[@]}"; do - if [ "$drive" != "$suggested_internal" ]; then - if udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then - suggested_external="$drive" - break - fi - fi - done - - if [ -z "$suggested_external" ]; then - # If no USB found, use the other drive - for drive in "${drives[@]}"; do - if [ "$drive" != "$suggested_internal" ]; then - suggested_external="$drive" - break - fi - done - fi - - # Show suggestions and get user confirmation - if [ -n "$suggested_internal" ] && [ -n "$suggested_external" ]; then - echo "Suggested configuration:" - local internal_info=$(lsblk -dpno SIZE,MODEL "$suggested_internal" | xargs) - local external_info=$(lsblk -dpno SIZE,MODEL "$suggested_external" | xargs) - echo " Internal (source): $suggested_internal - $internal_info" - echo " External (target): $suggested_external - $external_info" - echo - read -p "Use this configuration? [Y/n]: " -n 1 -r - echo - if [[ $REPLY =~ ^[Nn]$ ]]; then - # Manual selection - INTERNAL_DRIVE="" - EXTERNAL_DRIVE="" - else - INTERNAL_DRIVE="$suggested_internal" - EXTERNAL_DRIVE="$suggested_external" - fi - fi - - # Manual selection if auto-detection failed or user declined - if [ -z "$INTERNAL_DRIVE" ]; then - echo "Select INTERNAL drive (source - your current system):" - for i in "${!drives[@]}"; do - local drive="${drives[$i]}" - local info=$(lsblk -dpno SIZE,MODEL "$drive" | xargs) - echo "$((i+1)). $drive - $info" - done - read -p "Enter number [1-${#drives[@]}]: " choice - if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#drives[@]}" ]; then - INTERNAL_DRIVE="${drives[$((choice-1))]}" - else - error "Invalid selection" - fi - fi - - if [ -z "$EXTERNAL_DRIVE" ]; then - echo - echo "Select EXTERNAL drive (target - will be wiped!):" - for i in "${!drives[@]}"; do - local drive="${drives[$i]}" - if [ "$drive" != "$INTERNAL_DRIVE" ]; then - local info=$(lsblk -dpno SIZE,MODEL "$drive" | xargs) - echo "$((i+1)). $drive - $info" - fi - done - read -p "Enter number [1-${#drives[@]}]: " choice - if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#drives[@]}" ]; then - local selected_drive="${drives[$((choice-1))]}" - if [ "$selected_drive" != "$INTERNAL_DRIVE" ]; then - EXTERNAL_DRIVE="$selected_drive" - else - error "Cannot use the same drive as both source and target!" - fi - else - error "Invalid selection" - fi - fi - - # Final validation - if [ "$INTERNAL_DRIVE" = "$EXTERNAL_DRIVE" ]; then - error "Internal and external drives cannot be the same!" - fi - - echo - echo "Final drive selection:" - echo " Internal (source): $INTERNAL_DRIVE ($(lsblk -dpno SIZE,MODEL "$INTERNAL_DRIVE" | xargs))" - echo " External (target): $EXTERNAL_DRIVE ($(lsblk -dpno SIZE,MODEL "$EXTERNAL_DRIVE" | xargs))" - - success "Drive detection completed" - - # Additional safety check - confirm the target drive - echo - echo -e "${RED}⚠️ FINAL SAFETY CHECK ⚠️${NC}" - echo "You have selected to COMPLETELY WIPE this drive:" - echo " Device: $EXTERNAL_DRIVE" - echo " Size: $(lsblk -dpno SIZE "$EXTERNAL_DRIVE")" - echo " Model: $(lsblk -dpno MODEL "$EXTERNAL_DRIVE")" - echo - echo "Current partitions on target drive:" - lsblk "$EXTERNAL_DRIVE" || true - echo - echo -e "${RED}This will DESTROY ALL DATA on $EXTERNAL_DRIVE!${NC}" - echo - read -p "Type 'YES' to confirm you want to wipe $EXTERNAL_DRIVE: " confirmation - if [ "$confirmation" != "YES" ]; then - error "Migration cancelled by user for safety" - fi -} - -analyze_internal_system() { - log "Analyzing internal system layout..." - - # Get all partitions on internal drive and clean up the tree formatting - local partitions=($(lsblk -pno NAME "$INTERNAL_DRIVE" | grep -v "^$INTERNAL_DRIVE$" | sed 's/^[├└]─//')) - - echo "Found partitions on $INTERNAL_DRIVE:" - for part in "${partitions[@]}"; do - # Verify the partition exists as a block device - if [ ! -b "$part" ]; then - warning "Skipping invalid partition: $part" - continue - fi - - local size=$(lsblk -no SIZE "$part") - local fstype=$(lsblk -no FSTYPE "$part") - local mountpoint=$(lsblk -no MOUNTPOINT "$part") - local label=$(lsblk -no LABEL "$part") - - echo " $part: $size, $fstype, mounted at: ${mountpoint:-'not mounted'}, label: ${label:-'no label'}" - - # Store partition information - PARTITION_FILESYSTEMS["$part"]="$fstype" - PARTITION_SIZES["$part"]="$size" - - # Try to identify partition purpose - if [[ "$fstype" == "vfat" ]]; then - INTERNAL_PARTITIONS["efi"]="$part" - BOOT_SIZE="1G" # Default EFI size - elif [[ "$fstype" == "ext4" ]] && ([[ "$mountpoint" == "/" ]] || [[ "$label" == "root"* ]] || [[ -z "${INTERNAL_PARTITIONS[root]}" ]]); then - INTERNAL_PARTITIONS["root"]="$part" - # Parse size more carefully, handle G/M/K suffixes - local size_num=$(echo "$size" | sed 's/[^0-9.]//g') - if [[ "$size" == *"G"* ]]; then - ROOT_SIZE="${size_num}G" # Use exact source size - elif [[ "$size" == *"M"* ]]; then - ROOT_SIZE="$(echo "scale=1; $size_num / 1024 + 1" | bc)G" - else - ROOT_SIZE="${size_num}G" - fi - elif [[ "$fstype" == "ext4" ]] && ([[ "$mountpoint" == "/home" ]] || [[ "$label" == "home"* ]]); then - INTERNAL_PARTITIONS["home"]="$part" - # Parse size more carefully - local size_num=$(echo "$size" | sed 's/[^0-9.]//g') - if [[ "$size" == *"G"* ]]; then - HOME_SIZE="$(echo "$size_num + 5" | bc)G" # Add some extra space - elif [[ "$size" == *"M"* ]]; then - HOME_SIZE="$(echo "scale=1; $size_num / 1024 + 1" | bc)G" - else - HOME_SIZE="${size_num}G" - fi - elif [[ "$fstype" == "ext4" ]] && ([[ "$mountpoint" == "/boot" ]] || [[ "$label" == "boot"* ]]); then - INTERNAL_PARTITIONS["boot"]="$part" - BOOT_SIZE="2G" # Standard boot size - elif [[ "$fstype" == "swap" ]]; then - INTERNAL_PARTITIONS["swap"]="$part" - local size_num=$(echo "$size" | sed 's/[^0-9.]//g') - if [[ "$size" == *"G"* ]]; then - SWAP_SIZE="${size_num}G" - elif [[ "$size" == *"M"* ]]; then - SWAP_SIZE="$(echo "scale=1; $size_num / 1024" | bc)G" - else - SWAP_SIZE="${size_num}G" - fi - elif [[ "$fstype" == "crypto_LUKS" ]]; then - log "Found encrypted partition: $part" - # This might be encrypted home or root - for now assume it's home - if [[ -z "${INTERNAL_PARTITIONS[home]}" ]]; then - INTERNAL_PARTITIONS["home_encrypted"]="$part" - # Calculate size based on the encrypted partition size - local size_num=$(echo "$size" | sed 's/[^0-9.]//g') - if [[ "$size" == *"G"* ]]; then - HOME_SIZE="$(echo "$size_num + 10" | bc)G" # Add some extra space - elif [[ "$size" == *"M"* ]]; then - HOME_SIZE="$(echo "scale=1; $size_num / 1024 + 10" | bc)G" - else - HOME_SIZE="${size_num}G" - fi - log "Encrypted home partition detected, setting HOME_SIZE to $HOME_SIZE" - fi - fi - done - - # If we didn't find a separate home partition, it's probably in root - if [ -z "${INTERNAL_PARTITIONS[home]}" ]; then - log "No separate /home partition found - assuming /home is in root partition" - # Increase root size to accommodate home - if [ -n "$ROOT_SIZE" ]; then - local root_num=$(echo "$ROOT_SIZE" | sed 's/G//') - # Use bc for decimal arithmetic - local new_root_size=$(echo "$root_num + 50" | bc -l | cut -d. -f1) - ROOT_SIZE="${new_root_size}G" # Add extra space - fi - HOME_SIZE="50G" # Create separate home in LVM - will be adjusted below based on detected encrypted home - fi - - # Set default swap size if not found - if [ -z "$SWAP_SIZE" ]; then - local mem_gb=$(free -g | awk '/^Mem:/ {print $2}') - SWAP_SIZE="$((mem_gb + 2))G" - log "No swap partition found, creating ${SWAP_SIZE} swap based on system memory" - fi - - # Check if we have encrypted home mounted and adjust size accordingly - if [[ -n "${INTERNAL_PARTITIONS[home_encrypted]}" ]]; then - local encrypted_home_mount=$(mount | grep "internal_home_encrypted" | awk '{print $3}') - if [[ -n "$encrypted_home_mount" ]]; then - log "Checking actual size requirements for encrypted home at $encrypted_home_mount" - local encrypted_total=$(df -BG "$encrypted_home_mount" | tail -1 | awk '{print $2}' | sed 's/G//') - local encrypted_used=$(df -BG "$encrypted_home_mount" | tail -1 | awk '{print $3}' | sed 's/G//') - # Use the exact total size from the encrypted partition - HOME_SIZE="${encrypted_total}G" - log "Encrypted home is ${encrypted_total}G total (${encrypted_used}G used), setting HOME_SIZE to $HOME_SIZE" - fi - fi - - # Set sensible defaults if sizes are missing - use exact source sizes - [ -z "$ROOT_SIZE" ] && ROOT_SIZE="58G" # Exact match to source - [ -z "$HOME_SIZE" ] && HOME_SIZE="411G" # Exact match to encrypted source - [ -z "$BOOT_SIZE" ] && BOOT_SIZE="2G" - [ -z "$SWAP_SIZE" ] && SWAP_SIZE="8G" - - # Ensure sizes are properly formatted (remove any extra decimals) - ROOT_SIZE=$(echo "$ROOT_SIZE" | sed 's/\.[0-9]*G/G/') - HOME_SIZE=$(echo "$HOME_SIZE" | sed 's/\.[0-9]*G/G/') - BOOT_SIZE=$(echo "$BOOT_SIZE" | sed 's/\.[0-9]*G/G/') - SWAP_SIZE=$(echo "$SWAP_SIZE" | sed 's/\.[0-9]*G/G/') - - echo - echo "System analysis summary:" - echo " EFI partition: ${INTERNAL_PARTITIONS[efi]:-'not found'}" - echo " Root partition: ${INTERNAL_PARTITIONS[root]:-'not found'}" - echo " Home partition: ${INTERNAL_PARTITIONS[home]:-${INTERNAL_PARTITIONS[home_encrypted]:-'integrated in root'}}" - echo " Boot partition: ${INTERNAL_PARTITIONS[boot]:-'integrated in root/efi'}" - echo " Swap partition: ${INTERNAL_PARTITIONS[swap]:-'not found'}" - if [ -n "${INTERNAL_PARTITIONS[home_encrypted]}" ]; then - echo " Encrypted home: ${INTERNAL_PARTITIONS[home_encrypted]}" - fi - - success "System analysis completed" -} - -check_prerequisites() { - log "Checking prerequisites..." - - # Check if running from live system - local root_device=$(df / | tail -1 | awk '{print $1}') - if [[ "$root_device" == *"loop"* ]] || [[ "$root_device" == *"overlay"* ]] || [[ "$root_device" == *"tmpfs"* ]]; then - success "Running from live system - good!" - else - warning "This might not be a live system. Please ensure you're running from live USB!" - confirm_action "Continue anyway? (Not recommended for production systems)" - fi - - # Check if tools are available and install if missing - local missing_tools=() - for tool in lvm cryptsetup rsync parted pv grub-install mkfs.ext4 mkfs.fat bc wipefs; do - if ! command -v $tool >/dev/null 2>&1; then - missing_tools+=("$tool") - fi - done - - if [ ${#missing_tools[@]} -gt 0 ]; then - warning "Missing required tools: ${missing_tools[*]}" - log "Attempting to install missing tools automatically..." - - # Try to run preparation script if it exists - local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - if [ -f "$script_dir/prepare_live_system.sh" ]; then - log "Running prepare_live_system.sh to install missing tools..." - bash "$script_dir/prepare_live_system.sh" || { - error "Failed to prepare live system. Please run: sudo ./prepare_live_system.sh" - } - else - # Fallback: try to install directly - log "Attempting direct package installation..." - if command -v apt >/dev/null 2>&1; then - apt update && apt install -y lvm2 cryptsetup rsync parted pv grub-efi-amd64 grub-common e2fsprogs dosfstools bc util-linux initramfs-tools || { - error "Failed to install required packages. Please install manually: lvm2 cryptsetup rsync parted pv grub-efi-amd64 grub-common e2fsprogs dosfstools bc" - } - else - error "Cannot install packages automatically. Please install missing tools: ${missing_tools[*]}" - fi - fi - - # Re-check after installation attempt - missing_tools=() - for tool in lvm cryptsetup rsync parted pv grub-install mkfs.ext4 mkfs.fat bc wipefs; do - if ! command -v $tool >/dev/null 2>&1; then - missing_tools+=("$tool") - fi - done - - if [ ${#missing_tools[@]} -gt 0 ]; then - error "Still missing required tools after installation attempt: ${missing_tools[*]}" - fi - fi - - success "Prerequisites check passed" -} - -setup_work_directories() { - log "Setting up work directories..." - mkdir -p "$WORK_DIR"/{internal_root,internal_home,internal_boot,external_root,external_home,external_boot} - success "Work directories created" -} - -backup_existing_external_data() { - log "Backing up any existing data on external drive..." - - # Check if target partition has existing LVM structures - if pvdisplay "${EXTERNAL_DRIVE}2" >/dev/null 2>&1; then - warning "Found existing LVM structures on ${EXTERNAL_DRIVE}2" - confirm_action "This will DESTROY all data on the external M.2 drive!" - - # Get the volume group name if it exists - local existing_vg=$(pvdisplay "${EXTERNAL_DRIVE}2" 2>/dev/null | grep "VG Name" | awk '{print $3}') - if [ -n "$existing_vg" ] && [ "$existing_vg" != "" ]; then - log "Deactivating existing volume group: $existing_vg" - vgchange -an "$existing_vg" || true - vgremove -f "$existing_vg" || true - fi - - log "Removing physical volume from ${EXTERNAL_DRIVE}2" - pvremove -f "${EXTERNAL_DRIVE}2" || true - fi - - # Also check if our target VG name already exists anywhere - if [ -d "/dev/$VG_NAME" ]; then - warning "Found existing $VG_NAME volume group" - confirm_action "This will DESTROY all data in the existing $VG_NAME volume group!" - - # Deactivate existing LVM volumes - vgchange -an "$VG_NAME" || true - vgremove -f "$VG_NAME" || true - fi - - success "External drive prepared for migration" -} - -create_lvm_layout() { - log "Creating new LVM layout on external drive..." - - # Debug: Show current size configuration - log "Size configuration:" - log " ROOT_SIZE: $ROOT_SIZE" - log " HOME_SIZE: $HOME_SIZE" - log " SWAP_SIZE: $SWAP_SIZE" - log " BOOT_SIZE: $BOOT_SIZE" - - # Wipe the drive and create new partition table - log "Wiping external drive: $EXTERNAL_DRIVE" - wipefs -a "$EXTERNAL_DRIVE" || warning "Failed to wipe drive signatures" - - log "Creating GPT partition table" - parted -s "$EXTERNAL_DRIVE" mklabel gpt || error "Failed to create partition table" - - # Create EFI boot partition (512MB) - log "Creating EFI boot partition" - parted -s "$EXTERNAL_DRIVE" mkpart primary fat32 1MiB 513MiB || error "Failed to create EFI partition" - parted -s "$EXTERNAL_DRIVE" set 1 boot on || warning "Failed to set boot flag" - parted -s "$EXTERNAL_DRIVE" set 1 esp on || warning "Failed to set ESP flag" - - # Create LVM partition (rest of disk) - log "Creating LVM partition" - parted -s "$EXTERNAL_DRIVE" mkpart primary 513MiB 100% || error "Failed to create LVM partition" - parted -s "$EXTERNAL_DRIVE" set 2 lvm on || warning "Failed to set LVM flag" - - # Wait for partition table to be re-read - log "Waiting for partition table update..." - sleep 3 - partprobe "$EXTERNAL_DRIVE" || warning "Failed to update partition table" - sleep 2 - - # Show partition layout for debugging - log "New partition layout:" - parted "$EXTERNAL_DRIVE" print || warning "Failed to display partition table" - - # Verify partitions exist - if [ ! -b "${EXTERNAL_DRIVE}1" ]; then - error "EFI partition ${EXTERNAL_DRIVE}1 not found after creation" - fi - if [ ! -b "${EXTERNAL_DRIVE}2" ]; then - error "LVM partition ${EXTERNAL_DRIVE}2 not found after creation" - fi - - # Create filesystems - log "Creating FAT32 filesystem on EFI partition" - mkfs.fat -F32 "${EXTERNAL_DRIVE}1" || error "Failed to create EFI filesystem" - - # Setup LVM - log "Creating LVM physical volume on ${EXTERNAL_DRIVE}2" - if ! pvcreate "${EXTERNAL_DRIVE}2"; then - warning "Initial pvcreate failed, trying with force flag..." - pvcreate -ff "${EXTERNAL_DRIVE}2" || error "Failed to create physical volume even with force flag" - fi - - log "Creating volume group: $VG_NAME" - vgcreate "$VG_NAME" "${EXTERNAL_DRIVE}2" || error "Failed to create volume group" - - # Validate sizes before creating logical volumes - log "Validating LVM sizes..." - - # Convert sizes to MB for calculation - local root_mb=$(echo "$ROOT_SIZE" | sed 's/G$//' | awk '{print $1 * 1024}') - local home_mb=$(echo "$HOME_SIZE" | sed 's/G$//' | awk '{print $1 * 1024}') - local swap_mb=$(echo "$SWAP_SIZE" | sed 's/G$//' | awk '{print $1 * 1024}') - local boot_mb=$(echo "$BOOT_SIZE" | sed 's/G$//' | awk '{print $1 * 1024}') - - local total_mb=$((root_mb + home_mb + swap_mb + boot_mb)) - log "Total space required: ${total_mb}MB" - - # Get available space in VG - local vg_free_mb=$(vgs --noheadings -o vg_free --units m "$VG_NAME" | tr -d ' m') - local vg_free_mb_int=${vg_free_mb%.*} - log "Available space in VG: ${vg_free_mb_int}MB" - - if [ "$total_mb" -gt "$vg_free_mb_int" ]; then - warning "Total required space ($total_mb MB) exceeds available space ($vg_free_mb_int MB)" - log "Reducing sizes proportionally..." - - # Reduce all sizes by 10% to leave space for snapshots - ROOT_SIZE=$((root_mb * 85 / 100 / 1024))"G" - HOME_SIZE=$((home_mb * 85 / 100 / 1024))"G" - SWAP_SIZE=$((swap_mb * 85 / 100 / 1024))"G" - BOOT_SIZE=$((boot_mb * 85 / 100 / 1024))"G" - - log "Adjusted sizes:" - log " ROOT_SIZE: $ROOT_SIZE" - log " HOME_SIZE: $HOME_SIZE" - log " SWAP_SIZE: $SWAP_SIZE" - log " BOOT_SIZE: $BOOT_SIZE" - fi - - # Create logical volumes with space for snapshots - log "Creating logical volume: root ($ROOT_SIZE)" - lvcreate --yes -L "$ROOT_SIZE" -n "$ROOT_LV" "$VG_NAME" || error "Failed to create root LV" - - log "Creating logical volume: home ($HOME_SIZE)" - lvcreate --yes -L "$HOME_SIZE" -n "$HOME_LV" "$VG_NAME" || error "Failed to create home LV" - - log "Creating logical volume: swap ($SWAP_SIZE)" - lvcreate --yes -L "$SWAP_SIZE" -n "$SWAP_LV" "$VG_NAME" || error "Failed to create swap LV" - - log "Creating logical volume: boot ($BOOT_SIZE)" - lvcreate --yes -L "$BOOT_SIZE" -n "$BOOT_LV" "$VG_NAME" || error "Failed to create boot LV" - - # Show LVM layout - log "LVM layout created:" - lvs "$VG_NAME" || warning "Failed to display LV layout" - - # Create filesystems on LVM volumes - log "Creating ext4 filesystem on root LV" - mkfs.ext4 -L "root" "/dev/$VG_NAME/$ROOT_LV" || error "Failed to create root filesystem" - - log "Creating ext4 filesystem on home LV" - mkfs.ext4 -L "home" "/dev/$VG_NAME/$HOME_LV" || error "Failed to create home filesystem" - - log "Creating ext4 filesystem on boot LV" - mkfs.ext4 -L "boot" "/dev/$VG_NAME/$BOOT_LV" || error "Failed to create boot filesystem" - - log "Creating swap on swap LV" - mkswap -L "swap" "/dev/$VG_NAME/$SWAP_LV" || error "Failed to create swap" - - success "LVM layout created successfully" -} - -handle_encrypted_partitions() { - log "Handling encrypted partitions..." - - local found_encrypted=false - - # Check each partition for encryption - for part_name in "${!INTERNAL_PARTITIONS[@]}"; do - local part_device="${INTERNAL_PARTITIONS[$part_name]}" - local fstype="${PARTITION_FILESYSTEMS[$part_device]}" - - if [[ "$fstype" == "crypto_LUKS" ]]; then - found_encrypted=true - log "Found encrypted partition: $part_device ($part_name)" - - local crypt_name="internal_${part_name}_luks" - - if ! cryptsetup status "$crypt_name" >/dev/null 2>&1; then - echo "Please enter the password for encrypted $part_name partition ($part_device):" - if cryptsetup open "$part_device" "$crypt_name"; then - success "Unlocked $part_device as /dev/mapper/$crypt_name" - # Update the partition reference to the decrypted device - INTERNAL_PARTITIONS["$part_name"]="/dev/mapper/$crypt_name" - # Update filesystem type of decrypted partition - local decrypted_fs=$(lsblk -no FSTYPE "/dev/mapper/$crypt_name") - PARTITION_FILESYSTEMS["/dev/mapper/$crypt_name"]="$decrypted_fs" - else - error "Failed to unlock encrypted partition $part_device" - fi - else - log "Encrypted partition $part_device already unlocked" - INTERNAL_PARTITIONS["$part_name"]="/dev/mapper/$crypt_name" - fi - fi - done - - if [ "$found_encrypted" = false ]; then - log "No encrypted partitions found" - fi - - success "Encrypted partition handling completed" -} - -mount_filesystems() { - log "Mounting filesystems..." - - # Mount internal filesystems - for part_name in "${!INTERNAL_PARTITIONS[@]}"; do - local part_device="${INTERNAL_PARTITIONS[$part_name]}" - local mount_point="$WORK_DIR/internal_$part_name" - - if [ ! -d "$mount_point" ]; then - mkdir -p "$mount_point" - fi - - log "Mounting $part_device to $mount_point" - if mount "$part_device" "$mount_point"; then - success "Mounted $part_name partition" - PARTITION_MOUNTS["$part_name"]="$mount_point" - else - error "Failed to mount $part_device" - fi - done - - # Mount external LVM filesystems - mount "/dev/$VG_NAME/$ROOT_LV" "$EXTERNAL_ROOT_MOUNT" - mount "/dev/$VG_NAME/$HOME_LV" "$EXTERNAL_HOME_MOUNT" - mount "/dev/$VG_NAME/$BOOT_LV" "$EXTERNAL_BOOT_MOUNT" - - # Mount EFI partition - mkdir -p "$EXTERNAL_ROOT_MOUNT/boot/efi" - mount "${EXTERNAL_DRIVE}1" "$EXTERNAL_ROOT_MOUNT/boot/efi" - - success "All filesystems mounted" -} - -copy_system_data() { - log "Copying system data (this will take a while)..." - - # Copy root filesystem - if [ -n "${INTERNAL_PARTITIONS[root]}" ]; then - log "Copying root filesystem..." - local source_mount="${PARTITION_MOUNTS[root]}" - - # If no separate home partition exists, exclude /home during root copy - local exclude_opts="" - if [ -z "${INTERNAL_PARTITIONS[home]}" ]; then - exclude_opts="--exclude=/home/*" - fi - - rsync -avxHAX --progress $exclude_opts \ - --exclude=/proc/* --exclude=/sys/* --exclude=/dev/* \ - --exclude=/run/* --exclude=/tmp/* --exclude=/var/tmp/* \ - "$source_mount/" "$EXTERNAL_ROOT_MOUNT/" - - success "Root filesystem copied" - else - error "No root partition found to copy" - fi - - # Copy home filesystem (if separate partition exists) - if [ -n "${INTERNAL_PARTITIONS[home]}" ]; then - log "Copying home filesystem from separate partition..." - local source_mount="${PARTITION_MOUNTS[home]}" - rsync -avxHAX --progress "$source_mount/" "$EXTERNAL_HOME_MOUNT/" - success "Home filesystem copied from separate partition" - else - log "Copying /home from root filesystem..." - # Create home directory structure on external home partition - if [ -d "${PARTITION_MOUNTS[root]}/home" ]; then - rsync -avxHAX --progress "${PARTITION_MOUNTS[root]}/home/" "$EXTERNAL_HOME_MOUNT/" - success "/home copied from root filesystem" - else - warning "No /home directory found in root filesystem" - fi - fi - - # Copy boot files - if [ -n "${INTERNAL_PARTITIONS[boot]}" ]; then - log "Copying boot files from separate boot partition..." - local source_mount="${PARTITION_MOUNTS[boot]}" - rsync -avxHAX --progress "$source_mount/" "$EXTERNAL_BOOT_MOUNT/" - else - log "Copying boot files from root filesystem..." - if [ -d "${PARTITION_MOUNTS[root]}/boot" ]; then - rsync -avxHAX --progress "${PARTITION_MOUNTS[root]}/boot/" "$EXTERNAL_BOOT_MOUNT/" - else - warning "No /boot directory found" - fi - fi - - success "System data copied successfully" -} - -update_system_configuration() { - log "Updating system configuration..." - - # Update crypttab (remove old encrypted home entry since we're using LVM now) - echo "# No encrypted partitions in LVM setup - using LVM volumes" > "$EXTERNAL_ROOT_MOUNT/etc/crypttab" - - # Ensure LVM tools are available in initramfs - echo "lvm2" >> "$EXTERNAL_ROOT_MOUNT/etc/initramfs-tools/modules" 2>/dev/null || true - - success "System configuration updated" -} - -install_bootloader() { - log "Installing bootloader (GRUB EFI)..." - - # Ensure EFI directory exists in chroot - mkdir -p "$EXTERNAL_ROOT_MOUNT/boot/efi" - mkdir -p "$EXTERNAL_ROOT_MOUNT/boot/grub" - - # Mount EFI partition in chroot environment - mount "${EXTERNAL_DRIVE}1" "$EXTERNAL_ROOT_MOUNT/boot/efi" - - # Bind mount necessary filesystems for chroot - mount --bind /dev "$EXTERNAL_ROOT_MOUNT/dev" - mount --bind /proc "$EXTERNAL_ROOT_MOUNT/proc" - mount --bind /sys "$EXTERNAL_ROOT_MOUNT/sys" - mount --bind /run "$EXTERNAL_ROOT_MOUNT/run" - - log "Updating system configuration for LVM..." - - # Update fstab with correct UUIDs (already done in update_system_configuration) - local root_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$ROOT_LV") - local home_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$HOME_LV") - local boot_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$BOOT_LV") - local efi_uuid=$(blkid -s UUID -o value "${EXTERNAL_DRIVE}1") - local swap_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$SWAP_LV") - - cat > "$EXTERNAL_ROOT_MOUNT/etc/fstab" << EOF -# /etc/fstab: static file system information. -# -# Use 'blkid' to print the universally unique identifier for a -# device; this may be used with UUID= as a more robust way to name devices -# that works even if disks are added and removed. See fstab(5). -# -# - -# Root filesystem (LVM) -UUID=$root_uuid / ext4 errors=remount-ro 0 1 - -# Boot partition (LVM) -UUID=$boot_uuid /boot ext4 defaults 0 2 - -# EFI boot partition -UUID=$efi_uuid /boot/efi vfat umask=0077 0 1 - -# Home partition (LVM) -UUID=$home_uuid /home ext4 defaults 0 2 - -# Swap (LVM) -UUID=$swap_uuid none swap sw 0 0 - -tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0 -EOF - - log "Installing GRUB bootloader..." - - # Install and configure GRUB in chroot environment - chroot "$EXTERNAL_ROOT_MOUNT" /bin/bash -c " - # Update initramfs to include LVM support - update-initramfs -u -k all - - # Generate GRUB configuration - update-grub - - # Install GRUB EFI bootloader - grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Ubuntu --recheck - - # Update GRUB configuration again after installation - update-grub - " 2>&1 | while IFS= read -r line; do - echo " GRUB: $line" - done - - # Verify EFI installation - if [ -f "$EXTERNAL_ROOT_MOUNT/boot/efi/EFI/Ubuntu/grubx64.efi" ]; then - success "GRUB EFI bootloader installed successfully" - log "EFI bootloader files:" - ls -la "$EXTERNAL_ROOT_MOUNT/boot/efi/EFI/Ubuntu/" | while IFS= read -r line; do - echo " $line" - done - else - error "GRUB EFI installation failed - bootloader files not found" - fi - - # Unmount bind mounts and EFI - umount "$EXTERNAL_ROOT_MOUNT/boot/efi" 2>/dev/null || true - umount "$EXTERNAL_ROOT_MOUNT/dev" 2>/dev/null || true - umount "$EXTERNAL_ROOT_MOUNT/proc" 2>/dev/null || true - umount "$EXTERNAL_ROOT_MOUNT/sys" 2>/dev/null || true - umount "$EXTERNAL_ROOT_MOUNT/run" 2>/dev/null || true - - success "Bootloader installation completed" -} - -validate_migration() { - log "Validating migration results..." - - # Check LVM volumes - local volumes_ok=true - for lv in "$ROOT_LV" "$HOME_LV" "$BOOT_LV" "$SWAP_LV"; do - if ! lvs "/dev/$VG_NAME/$lv" >/dev/null 2>&1; then - error "LVM volume /dev/$VG_NAME/$lv not found" - volumes_ok=false - fi - done - - # Check filesystems - local filesystems_ok=true - if ! tune2fs -l "/dev/$VG_NAME/$ROOT_LV" >/dev/null 2>&1; then - error "Root filesystem not properly created" - filesystems_ok=false - fi - if ! tune2fs -l "/dev/$VG_NAME/$HOME_LV" >/dev/null 2>&1; then - error "Home filesystem not properly created" - filesystems_ok=false - fi - if ! tune2fs -l "/dev/$VG_NAME/$BOOT_LV" >/dev/null 2>&1; then - error "Boot filesystem not properly created" - filesystems_ok=false - fi - - # Check EFI bootloader - local bootloader_ok=true - if [ ! -f "$EXTERNAL_ROOT_MOUNT/boot/efi/EFI/Ubuntu/grubx64.efi" ]; then - error "GRUB EFI bootloader not found" - bootloader_ok=false - fi - if [ ! -f "$EXTERNAL_ROOT_MOUNT/boot/grub/grub.cfg" ]; then - error "GRUB configuration not found" - bootloader_ok=false - fi - - # Check fstab - local fstab_ok=true - if ! grep -q "UUID.*ext4" "$EXTERNAL_ROOT_MOUNT/etc/fstab"; then - error "fstab not properly configured" - fstab_ok=false - fi - - # Summary - if [ "$volumes_ok" = true ] && [ "$filesystems_ok" = true ] && [ "$bootloader_ok" = true ] && [ "$fstab_ok" = true ]; then - success "Migration validation passed - all components properly configured" - return 0 - else - error "Migration validation failed - some components need attention" - return 1 - fi -} - log "Creating LVM snapshot backup script..." - - cat > "$EXTERNAL_ROOT_MOUNT/usr/local/bin/lvm-snapshot-backup.sh" << 'EOF' -#!/bin/bash - -# LVM Snapshot Backup Script -# Creates snapshots of LVM volumes for backup purposes - -set -e - -VG_NAME="system-vg" -SNAPSHOT_SIZE="10G" -BACKUP_DIR="/mnt/backup" - -create_snapshots() { - echo "Creating LVM snapshots..." - - # Create snapshots - lvcreate --yes -L "$SNAPSHOT_SIZE" -s -n root-snapshot "/dev/$VG_NAME/root" - lvcreate --yes -L "$SNAPSHOT_SIZE" -s -n home-snapshot "/dev/$VG_NAME/home" - - echo "Snapshots created successfully" - echo "root-snapshot: /dev/$VG_NAME/root-snapshot" - echo "home-snapshot: /dev/$VG_NAME/home-snapshot" -} - -mount_snapshots() { - echo "Mounting snapshots..." - mkdir -p "$BACKUP_DIR"/{root,home} - mount "/dev/$VG_NAME/root-snapshot" "$BACKUP_DIR/root" - mount "/dev/$VG_NAME/home-snapshot" "$BACKUP_DIR/home" - echo "Snapshots mounted at $BACKUP_DIR" -} - -remove_snapshots() { - echo "Cleaning up snapshots..." - umount "$BACKUP_DIR/root" 2>/dev/null || true - umount "$BACKUP_DIR/home" 2>/dev/null || true - lvremove -f "/dev/$VG_NAME/root-snapshot" 2>/dev/null || true - lvremove -f "/dev/$VG_NAME/home-snapshot" 2>/dev/null || true - echo "Snapshots removed" -} - -case "$1" in - create) - create_snapshots - ;; - mount) - mount_snapshots - ;; - remove) - remove_snapshots - ;; - backup) - create_snapshots - mount_snapshots - echo "Snapshots ready for backup at $BACKUP_DIR" - echo "Run 'lvm-snapshot-backup.sh remove' when backup is complete" - ;; - *) - echo "Usage: $0 {create|mount|remove|backup}" - echo " create - Create snapshots only" - echo " mount - Mount existing snapshots" - echo " remove - Remove snapshots and unmount" - echo " backup - Create and mount snapshots ready for backup" - exit 1 - ;; -esac -EOF - - chmod +x "$EXTERNAL_ROOT_MOUNT/usr/local/bin/lvm-snapshot-backup.sh" - - success "LVM snapshot backup script created" -} - -cleanup() { - log "Cleaning up..." - - # Unmount external filesystems - umount "$EXTERNAL_ROOT_MOUNT/boot/efi" 2>/dev/null || true - umount "$EXTERNAL_ROOT_MOUNT" 2>/dev/null || true - umount "$EXTERNAL_HOME_MOUNT" 2>/dev/null || true - umount "$EXTERNAL_BOOT_MOUNT" 2>/dev/null || true - - # Unmount internal filesystems - for part_name in "${!PARTITION_MOUNTS[@]}"; do - local mount_point="${PARTITION_MOUNTS[$part_name]}" - umount "$mount_point" 2>/dev/null || true - done - - # Close encrypted partitions - for part_name in "${!INTERNAL_PARTITIONS[@]}"; do - local part_device="${INTERNAL_PARTITIONS[$part_name]}" - if [[ "$part_device" == *"/dev/mapper/"* ]]; then - local crypt_name=$(basename "$part_device") - cryptsetup close "$crypt_name" 2>/dev/null || true - fi - done - - success "Cleanup completed" -} - -main() { - echo -e "${GREEN}=== LVM Migration Script ===${NC}" - echo "This script will migrate your non-LVM system to LVM on an external M.2 drive" - echo "Run this from a live USB system for best results" - echo - - check_prerequisites - detect_drives - analyze_internal_system - - # FORCE CORRECT SIZES - Override any previous calculations based on known source layout - log "Applying size corrections based on detected source partitions..." - ROOT_SIZE="58G" # Match internal nvme0n1p1 (58.6G) - HOME_SIZE="400G" # Fit encrypted home (411G total, 314G used) in available space - SWAP_SIZE="16G" # Standard swap size - BOOT_SIZE="2G" # Standard boot size - log "Corrected sizes: ROOT=$ROOT_SIZE, HOME=$HOME_SIZE, SWAP=$SWAP_SIZE, BOOT=$BOOT_SIZE" - - echo - echo "Migration Summary:" - echo " Source: $INTERNAL_DRIVE (non-LVM system)" - echo " Target: $EXTERNAL_DRIVE (will become LVM system)" - echo " Root size: $ROOT_SIZE" - echo " Home size: $HOME_SIZE" - echo " Swap size: $SWAP_SIZE" - echo " Boot size: $BOOT_SIZE" - echo - - confirm_action "WARNING: This will DESTROY all data on $EXTERNAL_DRIVE!" - - setup_work_directories - backup_existing_external_data - create_lvm_layout - handle_encrypted_partitions - mount_filesystems - copy_system_data - update_system_configuration - install_bootloader - validate_migration - create_lvm_snapshot_script - cleanup - - success "Migration completed successfully!" - echo - echo -e "${GREEN}✅ MIGRATION COMPLETE - Your system is ready to boot!${NC}" - echo - echo -e "${GREEN}What was accomplished:${NC}" - echo "• ✅ LVM layout created with proper volume sizes" - echo "• ✅ All system data copied (root, home, boot)" - echo "• ✅ fstab updated with LVM UUIDs" - echo "• ✅ GRUB bootloader installed on external M.2" - echo "• ✅ initramfs updated for LVM support" - echo "• ✅ EFI bootloader configured" - echo - echo -e "${GREEN}Next steps:${NC}" - echo "1. 🔌 Keep the external M.2 drive connected" - echo "2. 🔄 Reboot your system" - echo "3. ⚡ Enter BIOS/UEFI boot menu (F12/F8/ESC during startup)" - echo "4. 🎯 Select the external USB/M.2 drive to boot" - echo "5. 🚀 Your system should boot normally with LVM!" - echo - echo -e "${YELLOW}LVM Benefits now available:${NC}" - echo "• 📸 Create instant snapshots: sudo /usr/local/bin/lvm-snapshot-backup.sh backup" - echo "• 📏 Resize partitions dynamically: lvextend, lvreduce" - echo "• 🔄 Easy system rollback with snapshots" - echo "• 💾 Advanced backup strategies with consistent snapshots" - echo - echo -e "${CYAN}Safety note:${NC}" - echo "Your original internal drive is completely unchanged and serves as a fallback." -} - -# Trap to ensure cleanup on exit -trap cleanup EXIT - -main "$@" \ No newline at end of file diff --git a/lvm_block_backup.sh b/lvm_block_backup.sh new file mode 100755 index 0000000..bba965c --- /dev/null +++ b/lvm_block_backup.sh @@ -0,0 +1,193 @@ +#!/bin/bash + +# LVM Block-Level Backup Script +# Creates consistent snapshots and clones entire volumes block-for-block +# This is the ONLY backup script you need! + +set -e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Configuration +SOURCE_VG="internal-vg" +TARGET_VG="migration-vg" +SNAPSHOT_SIZE="2G" +LOG_FILE="/var/log/lvm-block-backup.log" + +log() { + local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1" + echo -e "${BLUE}$message${NC}" + echo "$message" >> "$LOG_FILE" +} + +error() { + local message="[ERROR] $1" + echo -e "${RED}$message${NC}" >&2 + echo "$message" >> "$LOG_FILE" + exit 1 +} + +success() { + local message="[SUCCESS] $1" + echo -e "${GREEN}$message${NC}" + echo "$message" >> "$LOG_FILE" +} + +warning() { + local message="[WARNING] $1" + echo -e "${YELLOW}$message${NC}" + echo "$message" >> "$LOG_FILE" +} + +check_requirements() { + log "Checking system requirements..." + + # Check if running as root + if [ "$EUID" -ne 0 ]; then + error "This script must be run as root. Use: sudo $0" + fi + + # Check if source VG exists + if ! vgs "$SOURCE_VG" >/dev/null 2>&1; then + error "Source volume group '$SOURCE_VG' not found" + fi + + # Check if target VG exists + if ! vgs "$TARGET_VG" >/dev/null 2>&1; then + error "Target volume group '$TARGET_VG' not found" + fi + + # Check if volumes exist + local volumes=("root" "home" "boot") + for vol in "${volumes[@]}"; do + if ! lvs "$SOURCE_VG/$vol" >/dev/null 2>&1; then + error "Source logical volume '$SOURCE_VG/$vol' not found" + fi + if ! lvs "$TARGET_VG/$vol" >/dev/null 2>&1; then + error "Target logical volume '$TARGET_VG/$vol' not found" + fi + done + + # Check available space for snapshots + local vg_free=$(vgs --noheadings -o vg_free --units g "$SOURCE_VG" | tr -d ' G') + local vg_free_int=${vg_free%.*} + + if [ "$vg_free_int" -lt 6 ]; then + error "Insufficient free space for snapshots. Need at least 6GB, have ${vg_free}GB" + fi + + success "System requirements check passed" +} + +cleanup_snapshots() { + log "Cleaning up any existing snapshots..." + lvremove -f "$SOURCE_VG/root-backup-snap" 2>/dev/null || true + lvremove -f "$SOURCE_VG/home-backup-snap" 2>/dev/null || true + lvremove -f "$SOURCE_VG/boot-backup-snap" 2>/dev/null || true +} + +create_snapshots() { + log "Creating LVM snapshots for consistent backup..." + + cleanup_snapshots + + # Create snapshots + lvcreate -L "$SNAPSHOT_SIZE" -s -n root-backup-snap "$SOURCE_VG/root" || error "Failed to create root snapshot" + lvcreate -L "$SNAPSHOT_SIZE" -s -n home-backup-snap "$SOURCE_VG/home" || error "Failed to create home snapshot" + lvcreate -L 1G -s -n boot-backup-snap "$SOURCE_VG/boot" || error "Failed to create boot snapshot" + + success "Snapshots created successfully" +} + +clone_volumes() { + log "Starting block-level volume cloning..." + + # Unmount target volumes if mounted + umount "/dev/$TARGET_VG/home" 2>/dev/null || true + umount "/dev/$TARGET_VG/root" 2>/dev/null || true + umount "/dev/$TARGET_VG/boot" 2>/dev/null || true + + # Clone root volume + log "Cloning root volume (this may take a while)..." + dd if="/dev/$SOURCE_VG/root-backup-snap" of="/dev/$TARGET_VG/root" bs=64M status=progress || error "Failed to clone root volume" + success "Root volume cloned" + + # Clone home volume + log "Cloning home volume (this will take the longest)..." + dd if="/dev/$SOURCE_VG/home-backup-snap" of="/dev/$TARGET_VG/home" bs=64M status=progress || error "Failed to clone home volume" + success "Home volume cloned" + + # Clone boot volume + log "Cloning boot volume..." + dd if="/dev/$SOURCE_VG/boot-backup-snap" of="/dev/$TARGET_VG/boot" bs=64M status=progress || error "Failed to clone boot volume" + success "Boot volume cloned" +} + +verify_backup() { + log "Verifying backup integrity..." + + # Check filesystem integrity + fsck -n "/dev/$TARGET_VG/root" || warning "Root filesystem check showed issues" + fsck -n "/dev/$TARGET_VG/boot" || warning "Boot filesystem check showed issues" + + # Note: Can't check encrypted home volume without decryption + + success "Backup verification completed" +} + +show_backup_info() { + log "Creating backup information..." + + cat << EOF + +===================================== +LVM Block-Level Backup Complete +===================================== +Date: $(date) +Source: $SOURCE_VG +Target: $TARGET_VG + +Volume Information: +$(lvs $SOURCE_VG $TARGET_VG) + +The external drive now contains an exact block-level copy of your internal drive. +You can boot from the external drive by selecting it in your BIOS/UEFI boot menu. + +To mount the backup volumes: + sudo mount /dev/$TARGET_VG/root /mnt/backup-root + sudo mount /dev/$TARGET_VG/boot /mnt/backup-boot + # Home volume needs LUKS decryption first + +EOF +} + +main() { + echo -e "${GREEN}=== LVM Block-Level Backup Tool ===${NC}" + echo "This will create an exact copy of your internal LVM volumes to the external drive." + echo + + read -p "Are you sure you want to proceed? This will OVERWRITE data on $TARGET_VG! [y/N]: " confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Backup cancelled." + exit 0 + fi + + check_requirements + create_snapshots + clone_volumes + cleanup_snapshots + verify_backup + show_backup_info + + success "Backup completed successfully!" +} + +# Trap to cleanup on exit +trap cleanup_snapshots EXIT + +main "$@" \ No newline at end of file diff --git a/lvm_snapshot_backup.sh b/lvm_snapshot_backup.sh deleted file mode 100755 index 5c137a0..0000000 --- a/lvm_snapshot_backup.sh +++ /dev/null @@ -1,409 +0,0 @@ -#!/bin/bash - -# Enhanced LVM Snapshot Backup System -# Integrates LVM snapshots with the existing backup system for M.2 external drives - -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 - -# Configuration -VG_NAME="system-vg" -SNAPSHOT_SIZE="10G" -BACKUP_BASE_DIR="/mnt/backup" -EXTERNAL_BACKUP_DRIVE="" # Will be auto-detected -LOG_FILE="/var/log/lvm-snapshot-backup.log" - -# Snapshot names -ROOT_SNAPSHOT="root-snapshot" -HOME_SNAPSHOT="home-snapshot" -BOOT_SNAPSHOT="boot-snapshot" - -log() { - local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1" - echo -e "${BLUE}$message${NC}" - echo "$message" >> "$LOG_FILE" -} - -error() { - local message="[ERROR] $1" - echo -e "${RED}$message${NC}" >&2 - echo "$message" >> "$LOG_FILE" - exit 1 -} - -warning() { - local message="[WARNING] $1" - echo -e "${YELLOW}$message${NC}" - echo "$message" >> "$LOG_FILE" -} - -success() { - local message="[SUCCESS] $1" - echo -e "${GREEN}$message${NC}" - echo "$message" >> "$LOG_FILE" -} - -check_lvm_system() { - log "Checking LVM system status..." - - # Check if we're running on an LVM system - if ! command -v lvm >/dev/null 2>&1; then - error "LVM tools not found. This system may not support LVM." - fi - - # Check if volume group exists - if ! vgs "$VG_NAME" >/dev/null 2>&1; then - error "Volume group '$VG_NAME' not found. Are you running on the migrated LVM system?" - fi - - # Check available space for snapshots - local vg_free=$(vgs --noheadings -o vg_free --units g "$VG_NAME" | tr -d ' G') - local snapshot_size_num=$(echo "$SNAPSHOT_SIZE" | tr -d 'G') - local required_space=$((snapshot_size_num * 3)) # 3 snapshots - - if (( $(echo "$vg_free < $required_space" | bc -l) )); then - warning "Low free space in volume group ($vg_free GB available, $required_space GB recommended)" - echo "Consider reducing snapshot size or extending volume group" - fi - - success "LVM system check passed" -} - -detect_backup_drive() { - log "Detecting external backup drive..." - - # Look for drives that are not the current root drive - local root_drive=$(lsblk -no PKNAME $(findmnt -no SOURCE /)) - local available_drives=($(lsblk -dpno NAME | grep -v "$root_drive")) - - if [ ${#available_drives[@]} -eq 0 ]; then - error "No external drives found for backup" - elif [ ${#available_drives[@]} -eq 1 ]; then - EXTERNAL_BACKUP_DRIVE="${available_drives[0]}" - log "Auto-selected backup drive: $EXTERNAL_BACKUP_DRIVE" - else - echo "Multiple external drives found:" - for i in "${!available_drives[@]}"; do - local drive="${available_drives[$i]}" - local info=$(lsblk -no SIZE,MODEL "$drive" | head -1) - echo "$((i+1)). $drive - $info" - done - - read -p "Select backup drive [1-${#available_drives[@]}]: " choice - EXTERNAL_BACKUP_DRIVE="${available_drives[$((choice-1))]}" - fi - - success "Selected backup drive: $EXTERNAL_BACKUP_DRIVE" -} - -create_snapshots() { - log "Creating LVM snapshots..." - - # Remove existing snapshots if they exist - remove_snapshots_quiet - - # Create snapshots for each logical volume - local volumes=("root" "home" "boot") - local snapshots=("$ROOT_SNAPSHOT" "$HOME_SNAPSHOT" "$BOOT_SNAPSHOT") - - for i in "${!volumes[@]}"; do - local volume="${volumes[$i]}" - local snapshot="${snapshots[$i]}" - - if lvs "$VG_NAME/$volume" >/dev/null 2>&1; then - log "Creating snapshot: $snapshot for $volume" - lvcreate -L "$SNAPSHOT_SIZE" -s -n "$snapshot" "/dev/$VG_NAME/$volume" || { - error "Failed to create snapshot $snapshot" - } - success "Created snapshot: $snapshot" - else - warning "Logical volume $volume not found, skipping" - fi - done - - success "All snapshots created successfully" -} - -mount_snapshots() { - log "Mounting snapshots for backup..." - - # Create mount points - mkdir -p "$BACKUP_BASE_DIR"/{root,home,boot} - - # Mount snapshots - local snapshots=("$ROOT_SNAPSHOT" "$HOME_SNAPSHOT" "$BOOT_SNAPSHOT") - local mount_points=("root" "home" "boot") - - for i in "${!snapshots[@]}"; do - local snapshot="${snapshots[$i]}" - local mount_point="$BACKUP_BASE_DIR/${mount_points[$i]}" - - if [ -e "/dev/$VG_NAME/$snapshot" ]; then - log "Mounting /dev/$VG_NAME/$snapshot to $mount_point" - mount "/dev/$VG_NAME/$snapshot" "$mount_point" || { - warning "Failed to mount snapshot $snapshot" - } - fi - done - - success "Snapshots mounted at $BACKUP_BASE_DIR" -} - -backup_to_external() { - log "Backing up snapshots to external drive..." - - if [ -z "$EXTERNAL_BACKUP_DRIVE" ]; then - detect_backup_drive - fi - - # Create backup directory on external drive - local external_mount="/mnt/external-backup" - mkdir -p "$external_mount" - - # Mount external drive (assume first partition) - mount "${EXTERNAL_BACKUP_DRIVE}1" "$external_mount" 2>/dev/null || { - # Try the whole drive if partition doesn't work - mount "$EXTERNAL_BACKUP_DRIVE" "$external_mount" || { - error "Failed to mount external backup drive" - } - } - - # Create timestamped backup directory - local backup_timestamp=$(date '+%Y%m%d_%H%M%S') - local backup_dir="$external_mount/lvm-snapshots/$backup_timestamp" - mkdir -p "$backup_dir" - - # Backup each mounted snapshot - local mount_points=("root" "home" "boot") - for mount_point in "${mount_points[@]}"; do - local source="$BACKUP_BASE_DIR/$mount_point" - local target="$backup_dir/$mount_point" - - if mountpoint -q "$source"; then - log "Backing up $mount_point to external drive..." - mkdir -p "$target" - rsync -avxHAX --progress "$source/" "$target/" || { - warning "Backup of $mount_point failed" - } - else - warning "Snapshot $mount_point not mounted, skipping" - fi - done - - # Create backup metadata - cat > "$backup_dir/backup-info.txt" << EOF -LVM Snapshot Backup Information -=============================== -Backup Date: $(date) -Source System: $(hostname) -Volume Group: $VG_NAME -Snapshot Size: $SNAPSHOT_SIZE -Backup Location: $backup_dir - -Logical Volumes: -$(lvs $VG_NAME) - -Volume Group Info: -$(vgs $VG_NAME) - -Physical Volumes: -$(pvs) -EOF - - # Unmount external drive - umount "$external_mount" - - success "Backup completed to $backup_dir" -} - -remove_snapshots_quiet() { - # Remove snapshots without error messages (used internally) - lvremove -f "/dev/$VG_NAME/$ROOT_SNAPSHOT" 2>/dev/null || true - lvremove -f "/dev/$VG_NAME/$HOME_SNAPSHOT" 2>/dev/null || true - lvremove -f "/dev/$VG_NAME/$BOOT_SNAPSHOT" 2>/dev/null || true -} - -remove_snapshots() { - log "Cleaning up snapshots..." - - # Unmount snapshots - umount "$BACKUP_BASE_DIR/root" 2>/dev/null || true - umount "$BACKUP_BASE_DIR/home" 2>/dev/null || true - umount "$BACKUP_BASE_DIR/boot" 2>/dev/null || true - - # Remove logical volumes - remove_snapshots_quiet - - success "Snapshots removed" -} - -list_snapshots() { - echo "Current LVM snapshots:" - lvs "$VG_NAME" | grep -E "(snapshot|Snap%)" || echo "No snapshots found" -} - -show_status() { - echo -e "${GREEN}=== LVM Snapshot Backup Status ===${NC}" - echo - - echo "Volume Group Information:" - vgs "$VG_NAME" 2>/dev/null || echo "Volume group not found" - echo - - echo "Logical Volumes:" - lvs "$VG_NAME" 2>/dev/null || echo "No logical volumes found" - echo - - echo "Current Snapshots:" - list_snapshots - echo - - echo "Mount Status:" - if mountpoint -q "$BACKUP_BASE_DIR/root" 2>/dev/null; then - echo " Root snapshot: mounted at $BACKUP_BASE_DIR/root" - else - echo " Root snapshot: not mounted" - fi - - if mountpoint -q "$BACKUP_BASE_DIR/home" 2>/dev/null; then - echo " Home snapshot: mounted at $BACKUP_BASE_DIR/home" - else - echo " Home snapshot: not mounted" - fi - - if mountpoint -q "$BACKUP_BASE_DIR/boot" 2>/dev/null; then - echo " Boot snapshot: mounted at $BACKUP_BASE_DIR/boot" - else - echo " Boot snapshot: not mounted" - fi -} - -integrate_with_backup_system() { - log "Integrating with existing backup system..." - - # Check if main backup system exists - if [ -f "./backup_script.sh" ]; then - log "Found main backup system - creating integration" - - # Create wrapper script that combines snapshot and full backup - cat > "./lvm_integrated_backup.sh" << 'EOF' -#!/bin/bash - -# Integrated LVM + Full System Backup -# Combines LVM snapshots with the main backup system - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -echo "=== Integrated LVM Backup System ===" -echo "1. LVM Snapshot Backup (fast, consistent)" -echo "2. Full System Backup (complete clone)" -echo "3. Combined Backup (snapshots + clone)" -echo - -read -p "Select backup type [1-3]: " choice - -case $choice in - 1) - echo "Performing LVM snapshot backup..." - sudo "$SCRIPT_DIR/lvm_snapshot_backup.sh" backup - ;; - 2) - echo "Performing full system backup..." - sudo "$SCRIPT_DIR/backup_script.sh" - ;; - 3) - echo "Performing combined backup..." - echo "Step 1: LVM snapshots..." - sudo "$SCRIPT_DIR/lvm_snapshot_backup.sh" backup - echo "Step 2: Full system clone..." - sudo "$SCRIPT_DIR/backup_script.sh" --sync - ;; - *) - echo "Invalid choice" - exit 1 - ;; -esac -EOF - chmod +x "./lvm_integrated_backup.sh" - success "Created integrated backup script: lvm_integrated_backup.sh" - else - warning "Main backup system not found in current directory" - fi -} - -show_usage() { - echo "Usage: $0 {create|mount|remove|backup|external|status|list|integrate}" - echo - echo "Commands:" - echo " create - Create LVM snapshots only" - echo " mount - Mount existing snapshots for access" - echo " remove - Remove snapshots and unmount" - echo " backup - Create snapshots and mount (ready for backup)" - echo " external - Full backup to external drive" - echo " status - Show current LVM and snapshot status" - echo " list - List current snapshots" - echo " integrate - Integrate with existing backup system" - echo - echo "Examples:" - echo " $0 backup # Create and mount snapshots" - echo " $0 external # Full backup to external drive" - echo " $0 remove # Clean up when backup complete" -} - -main() { - # Ensure log file exists and is writable - sudo touch "$LOG_FILE" 2>/dev/null || LOG_FILE="/tmp/lvm-backup.log" - - case "${1:-}" in - create) - check_lvm_system - create_snapshots - ;; - mount) - mount_snapshots - ;; - remove) - remove_snapshots - ;; - backup) - check_lvm_system - create_snapshots - mount_snapshots - echo "Snapshots ready for backup at $BACKUP_BASE_DIR" - echo "Run '$0 remove' when backup is complete" - ;; - external) - check_lvm_system - create_snapshots - mount_snapshots - backup_to_external - remove_snapshots - ;; - status) - show_status - ;; - list) - list_snapshots - ;; - integrate) - integrate_with_backup_system - ;; - *) - show_usage - exit 1 - ;; - esac -} - -# Check if running as root for LVM operations -if [ "$EUID" -ne 0 ] && [[ "$1" =~ ^(create|mount|remove|backup|external)$ ]]; then - error "LVM operations require root privileges. Use: sudo $0 $1" -fi - -main "$@" \ No newline at end of file diff --git a/START_LVM_MIGRATION.sh b/old_scripts/START_LVM_MIGRATION.sh similarity index 100% rename from START_LVM_MIGRATION.sh rename to old_scripts/START_LVM_MIGRATION.sh diff --git a/access_tools.sh b/old_scripts/access_tools.sh similarity index 100% rename from access_tools.sh rename to old_scripts/access_tools.sh diff --git a/automated_clonezilla_backup.sh b/old_scripts/automated_clonezilla_backup.sh similarity index 100% rename from automated_clonezilla_backup.sh rename to old_scripts/automated_clonezilla_backup.sh diff --git a/backup_script.sh b/old_scripts/backup_script.sh similarity index 100% rename from backup_script.sh rename to old_scripts/backup_script.sh diff --git a/old_scripts/boot_repair_tools.sh b/old_scripts/boot_repair_tools.sh new file mode 100755 index 0000000..1e7b9f6 --- /dev/null +++ b/old_scripts/boot_repair_tools.sh @@ -0,0 +1,389 @@ +#!/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 "# " >> "$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 "$@" \ No newline at end of file diff --git a/bootstrap_usb_tools.sh b/old_scripts/bootstrap_usb_tools.sh similarity index 100% rename from bootstrap_usb_tools.sh rename to old_scripts/bootstrap_usb_tools.sh diff --git a/check_packages.sh b/old_scripts/check_packages.sh similarity index 100% rename from check_packages.sh rename to old_scripts/check_packages.sh diff --git a/clean_external_lvm_boot.sh b/old_scripts/clean_external_lvm_boot.sh similarity index 100% rename from clean_external_lvm_boot.sh rename to old_scripts/clean_external_lvm_boot.sh diff --git a/create_alpine_backup_usb.sh b/old_scripts/create_alpine_backup_usb.sh similarity index 100% rename from create_alpine_backup_usb.sh rename to old_scripts/create_alpine_backup_usb.sh diff --git a/create_auto_startup.sh b/old_scripts/create_auto_startup.sh similarity index 100% rename from create_auto_startup.sh rename to old_scripts/create_auto_startup.sh diff --git a/create_bootable_backup.sh b/old_scripts/create_bootable_backup.sh similarity index 100% rename from create_bootable_backup.sh rename to old_scripts/create_bootable_backup.sh diff --git a/create_clonezilla_backup.sh b/old_scripts/create_clonezilla_backup.sh similarity index 100% rename from create_clonezilla_backup.sh rename to old_scripts/create_clonezilla_backup.sh diff --git a/create_dd_backup_usb.sh b/old_scripts/create_dd_backup_usb.sh similarity index 100% rename from create_dd_backup_usb.sh rename to old_scripts/create_dd_backup_usb.sh diff --git a/diagnose_boot_issue.sh b/old_scripts/diagnose_boot_issue.sh similarity index 100% rename from diagnose_boot_issue.sh rename to old_scripts/diagnose_boot_issue.sh diff --git a/old_scripts/direct_clone_backup.sh b/old_scripts/direct_clone_backup.sh new file mode 100755 index 0000000..1365f3b --- /dev/null +++ b/old_scripts/direct_clone_backup.sh @@ -0,0 +1,667 @@ +#!/bin/bash + +# Direct 1-to-1 Clone Script +# Creates an exact copy of internal drive to external drive without LVM conversion +# Preserves all partitions, LUKS encryption, and boot structures exactly as they are +# MUST BE RUN FROM A LIVE USB SYSTEM + +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 + +# Configuration variables +INTERNAL_DRIVE="" +EXTERNAL_DRIVE="" +WORK_DIR="/mnt/clone_work" + +# Partition mapping +declare -A PARTITION_MAP +declare -A PARTITION_FILESYSTEMS +declare -A PARTITION_LABELS +declare -A PARTITION_UUIDS + +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" +} + +confirm_action() { + echo -e "${YELLOW}$1${NC}" + read -p "Do you want to continue? [y/N] " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + error "Operation aborted by user" + fi +} + +detect_drives() { + log "Detecting available drives..." + + # Find all block devices that are disks (not partitions), excluding the live USB + local all_drives=($(lsblk -dpno NAME,TYPE,SIZE,MODEL | grep "disk" | awk '{print $1}')) + local drives=() + + # Filter out the USB stick we're running from (if running from live system) + for drive in "${all_drives[@]}"; do + # Check if this drive contains the live system + if mount | grep -q "$drive" && mount | grep -q "/lib/live\|/media.*live\|overlay"; then + log "Excluding live USB drive: $drive" + continue + fi + drives+=("$drive") + done + + if [ ${#drives[@]} -lt 2 ]; then + error "Need at least 2 drives for cloning. Found only ${#drives[@]} suitable drives" + echo "Available drives:" + for drive in "${all_drives[@]}"; do + local info=$(lsblk -dpno NAME,SIZE,MODEL "$drive" | awk '{print $2 " " $3}') + echo " $drive - $info" + done + exit 1 + fi + + echo + echo "Available drives for cloning:" + for i in "${!drives[@]}"; do + local drive="${drives[$i]}" + local info=$(lsblk -dpno NAME,SIZE,MODEL "$drive" | awk '{print $2 " " $3}' | xargs) + local is_usb="" + + # Check if it's a USB drive + if udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then + is_usb=" (USB)" + fi + + echo "$((i+1)). $drive - $info$is_usb" + + # Show partition layout + echo " Partitions:" + lsblk "$drive" | tail -n +2 | sed 's/^/ /' + echo + done + + # Auto-detection with user confirmation + local suggested_internal="" + local suggested_external="" + + # Try to suggest internal drive (prefer NVMe, then non-USB drives) + for drive in "${drives[@]}"; do + if [[ "$drive" == *"nvme"* ]]; then + suggested_internal="$drive" + break + fi + done + + if [ -z "$suggested_internal" ]; then + # If no NVMe, prefer non-USB drives + for drive in "${drives[@]}"; do + if ! udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then + suggested_internal="$drive" + break + fi + done + fi + + # Try to suggest external drive (prefer USB, larger capacity) + for drive in "${drives[@]}"; do + if [ "$drive" != "$suggested_internal" ]; then + if udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then + suggested_external="$drive" + break + fi + fi + done + + if [ -z "$suggested_external" ]; then + # If no USB found, use the other drive + for drive in "${drives[@]}"; do + if [ "$drive" != "$suggested_internal" ]; then + suggested_external="$drive" + break + fi + done + fi + + # Show suggestions and get user confirmation + if [ -n "$suggested_internal" ] && [ -n "$suggested_external" ]; then + echo "Suggested configuration:" + local internal_info=$(lsblk -dpno SIZE,MODEL "$suggested_internal" | xargs) + local external_info=$(lsblk -dpno SIZE,MODEL "$suggested_external" | xargs) + echo " Internal (source): $suggested_internal - $internal_info" + echo " External (target): $suggested_external - $external_info" + echo + read -p "Use this configuration? [Y/n]: " -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + # Manual selection + INTERNAL_DRIVE="" + EXTERNAL_DRIVE="" + else + INTERNAL_DRIVE="$suggested_internal" + EXTERNAL_DRIVE="$suggested_external" + fi + fi + + # Manual selection if auto-detection failed or user declined + if [ -z "$INTERNAL_DRIVE" ]; then + echo "Select INTERNAL drive (source - your current system):" + for i in "${!drives[@]}"; do + local drive="${drives[$i]}" + local info=$(lsblk -dpno SIZE,MODEL "$drive" | xargs) + echo "$((i+1)). $drive - $info" + done + read -p "Enter number [1-${#drives[@]}]: " choice + if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#drives[@]}" ]; then + INTERNAL_DRIVE="${drives[$((choice-1))]}" + else + error "Invalid selection" + fi + fi + + if [ -z "$EXTERNAL_DRIVE" ]; then + echo + echo "Select EXTERNAL drive (target - will be completely overwritten!):" + for i in "${!drives[@]}"; do + local drive="${drives[$i]}" + if [ "$drive" != "$INTERNAL_DRIVE" ]; then + local info=$(lsblk -dpno SIZE,MODEL "$drive" | xargs) + echo "$((i+1)). $drive - $info" + fi + done + read -p "Enter number [1-${#drives[@]}]: " choice + if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#drives[@]}" ]; then + local selected_drive="${drives[$((choice-1))]}" + if [ "$selected_drive" != "$INTERNAL_DRIVE" ]; then + EXTERNAL_DRIVE="$selected_drive" + else + error "Cannot use the same drive as both source and target!" + fi + else + error "Invalid selection" + fi + fi + + # Final validation + if [ "$INTERNAL_DRIVE" = "$EXTERNAL_DRIVE" ]; then + error "Internal and external drives cannot be the same!" + fi + + # Check drive sizes + local internal_size_bytes=$(lsblk -bno SIZE "$INTERNAL_DRIVE") + local external_size_bytes=$(lsblk -bno SIZE "$EXTERNAL_DRIVE") + + if [ "$external_size_bytes" -lt "$internal_size_bytes" ]; then + error "External drive ($EXTERNAL_DRIVE) is smaller than internal drive ($INTERNAL_DRIVE). Cannot clone." + fi + + echo + echo "Final drive selection:" + echo " Internal (source): $INTERNAL_DRIVE ($(lsblk -dpno SIZE,MODEL "$INTERNAL_DRIVE" | xargs))" + echo " External (target): $EXTERNAL_DRIVE ($(lsblk -dpno SIZE,MODEL "$EXTERNAL_DRIVE" | xargs))" + + success "Drive detection completed" + + # Final safety check + echo + echo -e "${RED}⚠️ FINAL SAFETY CHECK ⚠️${NC}" + echo "You are about to COMPLETELY CLONE this drive:" + echo " Source: $INTERNAL_DRIVE" + echo " Target: $EXTERNAL_DRIVE (will be completely overwritten!)" + echo + echo "Current partitions on target drive that will be DESTROYED:" + lsblk "$EXTERNAL_DRIVE" || true + echo + echo -e "${RED}This will DESTROY ALL DATA on $EXTERNAL_DRIVE!${NC}" + echo "The entire drive will be overwritten with an exact copy of $INTERNAL_DRIVE" + echo + read -p "Type 'CLONE' to confirm you want to overwrite $EXTERNAL_DRIVE: " confirmation + if [ "$confirmation" != "CLONE" ]; then + error "Clone operation cancelled by user for safety" + fi +} + +analyze_source_drive() { + log "Analyzing source drive structure..." + + # Get partition information + local partitions=($(lsblk -pno NAME "$INTERNAL_DRIVE" | grep -v "^$INTERNAL_DRIVE$")) + + echo "Source drive structure:" + lsblk "$INTERNAL_DRIVE" + echo + + for part in "${partitions[@]}"; do + local size=$(lsblk -no SIZE "$part") + local fstype=$(lsblk -no FSTYPE "$part") + local label=$(lsblk -no LABEL "$part") + local uuid=$(lsblk -no UUID "$part") + local mountpoint=$(lsblk -no MOUNTPOINT "$part") + + echo " $part:" + echo " Size: $size" + echo " Filesystem: ${fstype:-'unknown'}" + echo " Label: ${label:-'none'}" + echo " UUID: ${uuid:-'none'}" + echo " Mounted at: ${mountpoint:-'not mounted'}" + + # Store information for later use + PARTITION_FILESYSTEMS["$part"]="$fstype" + PARTITION_LABELS["$part"]="$label" + PARTITION_UUIDS["$part"]="$uuid" + + # Check if it's encrypted + if [[ "$fstype" == "crypto_LUKS" ]]; then + log "Found LUKS encrypted partition: $part" + fi + + echo + done + + success "Source drive analysis completed" +} + +check_prerequisites() { + log "Checking prerequisites..." + + # Check if running from live system + local root_device=$(df / | tail -1 | awk '{print $1}') + if [[ "$root_device" == *"loop"* ]] || [[ "$root_device" == *"overlay"* ]] || [[ "$root_device" == *"tmpfs"* ]]; then + success "Running from live system - good!" + else + warning "This might not be a live system. For safety, this should be run from a live USB!" + confirm_action "Continue anyway? (Not recommended)" + fi + + # Check for required tools + local missing_tools=() + for tool in dd pv rsync cryptsetup grub-install lsblk blkid partprobe; do + if ! command -v $tool >/dev/null 2>&1; then + missing_tools+=("$tool") + fi + done + + if [ ${#missing_tools[@]} -gt 0 ]; then + warning "Missing required tools: ${missing_tools[*]}" + log "Installing missing tools..." + apt update && apt install -y util-linux pv rsync cryptsetup grub-common grub-efi-amd64 || { + error "Failed to install required tools. Please install manually: ${missing_tools[*]}" + } + fi + + success "Prerequisites check passed" +} + +perform_direct_clone() { + log "Starting direct drive clone..." + log "This will create an exact bit-for-bit copy of $INTERNAL_DRIVE to $EXTERNAL_DRIVE" + + # Get drive size for progress tracking + local total_size_bytes=$(lsblk -bno SIZE "$INTERNAL_DRIVE") + local total_size_human=$(lsblk -no SIZE "$INTERNAL_DRIVE") + + log "Cloning $total_size_human from $INTERNAL_DRIVE to $EXTERNAL_DRIVE" + log "This will take a while depending on drive size and speed..." + + # Use dd with progress monitoring via pv + if dd if="$INTERNAL_DRIVE" bs=64M status=none | pv -s "$total_size_bytes" -w 80 | dd of="$EXTERNAL_DRIVE" bs=64M status=none; then + success "Drive clone completed successfully" + else + error "Drive clone failed!" + fi + + # Force kernel to re-read partition table + log "Updating partition table on cloned drive..." + partprobe "$EXTERNAL_DRIVE" || warning "Failed to update partition table" + sync + sleep 3 + + success "Direct clone operation completed" +} + +fix_uuids_and_boot() { + log "Fixing UUIDs and boot configuration on cloned drive..." + + mkdir -p "$WORK_DIR" + + # Get new partition list from cloned drive + local new_partitions=($(lsblk -pno NAME "$EXTERNAL_DRIVE" | grep -v "^$EXTERNAL_DRIVE$")) + + # Create new UUIDs for all partitions to avoid conflicts + for part in "${new_partitions[@]}"; do + local fstype=$(lsblk -no FSTYPE "$part") + local old_uuid=$(lsblk -no UUID "$part") + + log "Processing partition $part (filesystem: ${fstype:-'unknown'})" + + # Skip encrypted partitions - they'll keep their UUID + if [[ "$fstype" == "crypto_LUKS" ]]; then + log "Skipping LUKS partition UUID change - encryption handles this" + continue + fi + + # Skip swap partitions for now - we'll handle them separately + if [[ "$fstype" == "swap" ]]; then + log "Regenerating swap UUID for $part" + swapoff "$part" 2>/dev/null || true + mkswap -U random "$part" || warning "Failed to regenerate swap UUID" + continue + fi + + # Generate new UUID for filesystem partitions + if [[ -n "$fstype" && "$fstype" != "crypto_LUKS" ]]; then + case "$fstype" in + "ext2"|"ext3"|"ext4") + log "Generating new UUID for ext filesystem on $part" + tune2fs -U random "$part" || warning "Failed to change UUID for $part" + ;; + "vfat") + log "Generating new UUID for FAT filesystem on $part" + # For FAT32, we'll use mlabel (part of mtools) if available, or skip + if command -v mlabel >/dev/null 2>&1; then + # Generate a random 8-character hex string for FAT32 + local new_fat_uuid=$(openssl rand -hex 4 | tr '[:lower:]' '[:upper:]') + echo "mtools_skip_check=1" > ~/.mtoolsrc + mlabel -i "$part" -N "${new_fat_uuid:0:8}" || warning "Failed to change FAT UUID" + rm -f ~/.mtoolsrc + else + warning "Cannot change FAT UUID - mtools not available" + fi + ;; + *) + log "Skipping UUID change for unknown filesystem type: $fstype" + ;; + esac + fi + done + + # Now we need to update /etc/fstab on the cloned system + log "Mounting cloned system to update configuration..." + + # Find the root partition (usually the largest ext4 partition or check for typical structure) + local root_partition="" + local boot_partition="" + local efi_partition="" + + for part in "${new_partitions[@]}"; do + local fstype=$(lsblk -no FSTYPE "$part") + local size_bytes=$(lsblk -bno SIZE "$part") + + # Detect EFI partition (usually small FAT32) + if [[ "$fstype" == "vfat" && "$size_bytes" -lt 1073741824 ]]; then # Less than 1GB + efi_partition="$part" + log "Detected EFI partition: $part" + fi + + # Detect boot partition (usually ext4, smaller than root) + if [[ "$fstype" == "ext4" && "$size_bytes" -lt 5368709120 && "$size_bytes" -gt 104857600 ]]; then # Between 100MB and 5GB + boot_partition="$part" + log "Detected boot partition: $part" + fi + + # Detect root partition (usually largest ext4 or check for encrypted) + if [[ "$fstype" == "ext4" && "$size_bytes" -gt 5368709120 ]]; then # Larger than 5GB + root_partition="$part" + log "Detected root partition: $part" + fi + + # Handle LUKS encrypted partitions + if [[ "$fstype" == "crypto_LUKS" ]]; then + log "Found encrypted partition that might be root: $part" + # We'll try to unlock it if needed + local crypt_name="cloned_root_$(basename "$part")" + echo "This appears to be an encrypted partition. Please enter the password to mount and update configuration:" + if cryptsetup open "$part" "$crypt_name"; then + # Check if the decrypted partition is the root + 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. Configuration update may be incomplete." + continue + fi + fi + done + + if [ -z "$root_partition" ]; then + warning "Could not automatically detect root partition. Manual configuration may be needed." + return 0 + fi + + # Mount the cloned root filesystem + log "Mounting cloned root filesystem: $root_partition" + mount "$root_partition" "$WORK_DIR" || { + error "Failed to mount cloned root filesystem" + } + + # Mount boot partition if exists + 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 + + # Mount EFI partition if exists + 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 + + # Update /etc/fstab with new UUIDs + if [ -f "$WORK_DIR/etc/fstab" ]; then + log "Updating /etc/fstab with new UUIDs..." + cp "$WORK_DIR/etc/fstab" "$WORK_DIR/etc/fstab.backup" + + # Generate new fstab with current UUIDs + echo "# /etc/fstab: static file system information." > "$WORK_DIR/etc/fstab.new" + echo "# Updated after cloning $(date)" >> "$WORK_DIR/etc/fstab.new" + echo "#" >> "$WORK_DIR/etc/fstab.new" + echo "# " >> "$WORK_DIR/etc/fstab.new" + + # Add entries for each partition with current UUIDs + for part in "${new_partitions[@]}"; do + local current_uuid=$(lsblk -no UUID "$part") + local fstype=$(lsblk -no FSTYPE "$part") + + if [ -n "$current_uuid" ]; then + case "$part" in + *"1") + if [[ "$fstype" == "vfat" ]]; then + echo "UUID=$current_uuid /boot/efi vfat defaults 0 2" >> "$WORK_DIR/etc/fstab.new" + fi + ;; + *"2") + if [[ "$fstype" == "ext4" ]]; then + # Could be boot or root - determine by size + local size_bytes=$(lsblk -bno SIZE "$part") + if [ "$size_bytes" -lt 5368709120 ]; then # Less than 5GB = boot + echo "UUID=$current_uuid /boot ext4 defaults 0 2" >> "$WORK_DIR/etc/fstab.new" + else # Root partition + echo "UUID=$current_uuid / ext4 defaults 0 1" >> "$WORK_DIR/etc/fstab.new" + fi + fi + ;; + *"3") + if [[ "$fstype" == "ext4" ]]; then + echo "UUID=$current_uuid / ext4 defaults 0 1" >> "$WORK_DIR/etc/fstab.new" + elif [[ "$fstype" == "swap" ]]; then + echo "UUID=$current_uuid none swap sw 0 0" >> "$WORK_DIR/etc/fstab.new" + fi + ;; + *) + if [[ "$fstype" == "swap" ]]; then + echo "UUID=$current_uuid none swap sw 0 0" >> "$WORK_DIR/etc/fstab.new" + fi + ;; + esac + fi + done + + # Add tmpfs entry + echo "tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0" >> "$WORK_DIR/etc/fstab.new" + + # Replace old fstab with new one + mv "$WORK_DIR/etc/fstab.new" "$WORK_DIR/etc/fstab" + + success "Updated /etc/fstab with new UUIDs" + else + warning "/etc/fstab not found in cloned system" + fi + + success "UUID and boot configuration updated" +} + +install_bootloader() { + log "Installing/repairing bootloader on cloned drive..." + + # Bind mount necessary filesystems for chroot + mount --bind /dev "$WORK_DIR/dev" + mount --bind /proc "$WORK_DIR/proc" + mount --bind /sys "$WORK_DIR/sys" + mount --bind /run "$WORK_DIR/run" + + # Update GRUB configuration and reinstall bootloader + chroot "$WORK_DIR" /bin/bash -c " + # Update initramfs to ensure all modules are included + update-initramfs -u -k all + + # Reinstall GRUB bootloader + grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian --recheck $EXTERNAL_DRIVE + + # Update GRUB configuration + update-grub + " || warning "Some bootloader operations failed but continuing..." + + # 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 "Bootloader installation completed" +} + +cleanup_clone() { + log "Cleaning up..." + + # 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 any encrypted volumes we opened + for mapper in /dev/mapper/cloned_*; 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" +} + +verify_clone() { + log "Performing basic verification of cloned drive..." + + # Check if partition table was copied correctly + log "Verifying partition table..." + local internal_partcount=$(lsblk -no NAME "$INTERNAL_DRIVE" | grep -c "^[├└]─") + local external_partcount=$(lsblk -no NAME "$EXTERNAL_DRIVE" | grep -c "^[├└]─") + + if [ "$internal_partcount" -eq "$external_partcount" ]; then + success "Partition count matches: $internal_partcount partitions" + else + warning "Partition count mismatch: internal=$internal_partcount, external=$external_partcount" + fi + + # Show final layout + echo + echo "Original drive layout:" + lsblk "$INTERNAL_DRIVE" + echo + echo "Cloned drive layout:" + lsblk "$EXTERNAL_DRIVE" + + success "Basic verification completed" +} + +main() { + echo -e "${GREEN}=== Direct 1-to-1 Clone Script ===${NC}" + echo "This script creates an exact copy of your internal drive to external drive" + echo "WITHOUT any LVM conversion - preserves original structure exactly" + echo "Run this from a live USB system for best results" + echo + + check_prerequisites + detect_drives + analyze_source_drive + + echo + echo "Clone Summary:" + echo " Source: $INTERNAL_DRIVE" + echo " Target: $EXTERNAL_DRIVE (will be completely overwritten)" + echo " Operation: Bit-perfect clone preserving all partitions and structures" + echo + + confirm_action "WARNING: This will COMPLETELY OVERWRITE $EXTERNAL_DRIVE!" + + perform_direct_clone + fix_uuids_and_boot + install_bootloader + verify_clone + cleanup_clone + + success "Direct 1-to-1 clone completed successfully!" + echo + echo -e "${GREEN}=== CLONE COMPLETE ===${NC}" + echo "✅ Exact copy created on external drive" + echo "✅ UUIDs updated to prevent conflicts" + echo "✅ Bootloader installed and configured" + echo "✅ Original internal drive unchanged" + echo + echo -e "${BLUE}Next steps:${NC}" + echo "1. Reboot your system" + echo "2. Enter BIOS/UEFI settings and configure:" + echo " • Set external drive as first boot device" + echo " • Ensure UEFI mode is enabled (if system uses UEFI)" + echo " • Disable Secure Boot if having issues" + echo "3. Boot from external drive" + echo "4. Should ask for LUKS password (if encrypted) and boot normally" + echo + echo -e "${GREEN}Your cloned system features:${NC}" + echo "• Identical to original - same encryption, same structure" + echo "• Independent UUIDs to avoid conflicts" + echo "• Original internal drive preserved as backup" + echo "• No LVM complexity - simple and reliable" + echo + echo -e "${YELLOW}🎉 Simple 1-to-1 clone completed successfully!${NC}" + echo "The external drive should boot exactly like your original system!" +} + +# Trap to ensure cleanup on exit +trap cleanup_clone EXIT + +main "$@" \ No newline at end of file diff --git a/emergency_install.sh b/old_scripts/emergency_install.sh similarity index 100% rename from emergency_install.sh rename to old_scripts/emergency_install.sh diff --git a/fix_alpine_boot.sh b/old_scripts/fix_alpine_boot.sh similarity index 100% rename from fix_alpine_boot.sh rename to old_scripts/fix_alpine_boot.sh diff --git a/fix_grub_boot.sh b/old_scripts/fix_grub_boot.sh similarity index 100% rename from fix_grub_boot.sh rename to old_scripts/fix_grub_boot.sh diff --git a/fix_grub_lvm_boot.sh b/old_scripts/fix_grub_lvm_boot.sh similarity index 100% rename from fix_grub_lvm_boot.sh rename to old_scripts/fix_grub_lvm_boot.sh diff --git a/old_scripts/improved_lvm_migration.sh b/old_scripts/improved_lvm_migration.sh new file mode 100755 index 0000000..453cd09 --- /dev/null +++ b/old_scripts/improved_lvm_migration.sh @@ -0,0 +1,552 @@ +#!/bin/bash + +# Improved LVM Migration Script +# Fixes the boot issues from the previous failed LVM migration +# Properly handles LUKS + LVM combination with robust boot configuration + +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 + +# Configuration variables +INTERNAL_DRIVE="" +EXTERNAL_DRIVE="" +VG_NAME="system-vg" +ROOT_LV="root" +HOME_LV="home" +SWAP_LV="swap" +BOOT_LV="boot" + +# Work directory +WORK_DIR="/mnt/lvm_migration" + +# Detected partitions and info +declare -A INTERNAL_PARTITIONS +declare -A PARTITION_FILESYSTEMS +declare -A PARTITION_SIZES + +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" +} + +confirm_action() { + echo -e "${YELLOW}$1${NC}" + read -p "Do you want to continue? [y/N] " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + error "Operation aborted by user" + fi +} + +detect_drives() { + log "Detecting available drives..." + + local all_drives=($(lsblk -dpno NAME,TYPE | grep "disk" | awk '{print $1}')) + local drives=() + + # Filter out the USB stick we're running from + for drive in "${all_drives[@]}"; do + if mount | grep -q "$drive" && mount | grep -q "/lib/live\|overlay\|/media.*live"; then + log "Excluding live USB drive: $drive" + continue + fi + drives+=("$drive") + done + + if [ ${#drives[@]} -lt 2 ]; then + error "Need at least 2 drives for migration. Found only ${#drives[@]} suitable drives" + fi + + echo "Available drives:" + for i in "${!drives[@]}"; do + local drive="${drives[$i]}" + local info=$(lsblk -dpno SIZE,MODEL "$drive" | xargs) + echo "$((i+1)). $drive - $info" + lsblk "$drive" | tail -n +2 | sed 's/^/ /' + echo + done + + # Auto-detect with user confirmation + local suggested_internal="" + local suggested_external="" + + # Prefer NVMe for internal, USB for external + for drive in "${drives[@]}"; do + if [[ "$drive" == *"nvme"* ]]; then + suggested_internal="$drive" + break + fi + done + + for drive in "${drives[@]}"; do + if [ "$drive" != "$suggested_internal" ]; then + if udevadm info --query=property --name="$drive" 2>/dev/null | grep -q "ID_BUS=usb"; then + suggested_external="$drive" + break + fi + fi + done + + if [ -n "$suggested_internal" ] && [ -n "$suggested_external" ]; then + echo "Suggested configuration:" + echo " Internal (source): $suggested_internal" + echo " External (LVM target): $suggested_external" + read -p "Use this configuration? [Y/n]: " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Nn]$ ]]; then + INTERNAL_DRIVE="$suggested_internal" + EXTERNAL_DRIVE="$suggested_external" + fi + fi + + # Manual selection if needed + if [ -z "$INTERNAL_DRIVE" ]; then + read -p "Select INTERNAL drive number: " choice + INTERNAL_DRIVE="${drives[$((choice-1))]}" + fi + + if [ -z "$EXTERNAL_DRIVE" ]; then + read -p "Select EXTERNAL drive number: " choice + EXTERNAL_DRIVE="${drives[$((choice-1))]}" + fi + + # Safety checks + if [ "$INTERNAL_DRIVE" = "$EXTERNAL_DRIVE" ]; then + error "Internal and external drives cannot be the same!" + fi + + local external_size_bytes=$(lsblk -bno SIZE "$EXTERNAL_DRIVE") + local internal_size_bytes=$(lsblk -bno SIZE "$INTERNAL_DRIVE") + + if [ "$external_size_bytes" -lt "$internal_size_bytes" ]; then + error "External drive is smaller than internal drive" + fi + + echo + echo "Final configuration:" + echo " Internal (source): $INTERNAL_DRIVE" + echo " External (LVM target): $EXTERNAL_DRIVE" + + # Final safety confirmation + echo + echo -e "${RED}⚠️ FINAL SAFETY CHECK ⚠️${NC}" + echo "This will COMPLETELY WIPE: $EXTERNAL_DRIVE" + echo "Current partitions that will be DESTROYED:" + lsblk "$EXTERNAL_DRIVE" + echo + read -p "Type 'MIGRATE' to confirm LVM migration: " confirmation + if [ "$confirmation" != "MIGRATE" ]; then + error "Migration cancelled by user" + fi + + success "Drive selection completed" +} + +analyze_source_system() { + log "Analyzing source system..." + + local partitions=($(lsblk -pno NAME "$INTERNAL_DRIVE" | grep -v "^$INTERNAL_DRIVE$")) + + echo "Source drive partitions:" + for part in "${partitions[@]}"; do + local size=$(lsblk -no SIZE "$part") + local fstype=$(lsblk -no FSTYPE "$part") + local label=$(lsblk -no LABEL "$part") + local mountpoint=$(lsblk -no MOUNTPOINT "$part") + + echo " $part: $size, $fstype, ${label:-'no label'}" + + PARTITION_FILESYSTEMS["$part"]="$fstype" + PARTITION_SIZES["$part"]="$size" + + # Identify partitions + if [[ "$fstype" == "vfat" ]] && [[ "$part" == *"1" ]] || [[ "$part" == *"2" ]]; then + INTERNAL_PARTITIONS["efi"]="$part" + elif [[ "$mountpoint" == "/" ]] || [[ "$label" == "root"* ]] || [[ "$fstype" == "ext4" && "$part" == *"1" ]]; then + INTERNAL_PARTITIONS["root"]="$part" + elif [[ "$mountpoint" == "/home" ]] || [[ "$label" == "home"* ]]; then + INTERNAL_PARTITIONS["home"]="$part" + elif [[ "$fstype" == "crypto_LUKS" ]]; then + # Encrypted partition - likely home + INTERNAL_PARTITIONS["encrypted_home"]="$part" + fi + done + + success "Source system analysis completed" +} + +check_prerequisites() { + log "Checking prerequisites and installing required tools..." + + # Check if running from live system + if ! df / | grep -q "loop\|overlay\|tmpfs"; then + warning "Not running from live system - this may cause issues" + confirm_action "Continue anyway?" + fi + + # Install/update required packages + log "Installing required packages..." + apt update >/dev/null 2>&1 + apt install -y lvm2 cryptsetup rsync parted pv grub-efi-amd64 grub-common \ + e2fsprogs dosfstools bc util-linux initramfs-tools \ + efibootmgr os-prober >/dev/null 2>&1 + + # Ensure LVM2 is properly loaded + modprobe dm-mod + modprobe dm-crypt + vgchange -ay 2>/dev/null || true + + success "Prerequisites installed" +} + +create_lvm_layout() { + log "Creating LVM layout on external drive..." + + # Calculate sizes based on source + local root_size="70G" + local home_size="100G" + local swap_size="8G" + local boot_size="2G" + + # Adjust based on available space + local total_space_gb=$(lsblk -bno SIZE "$EXTERNAL_DRIVE" | awk '{print int($1/1024/1024/1024)}') + if [ "$total_space_gb" -gt 500 ]; then + home_size="200G" + root_size="100G" + fi + + log "LVM sizes: Root=$root_size, Home=$home_size, Swap=$swap_size, Boot=$boot_size" + + # Wipe and create partition table + wipefs -a "$EXTERNAL_DRIVE" + parted -s "$EXTERNAL_DRIVE" mklabel gpt + + # Create EFI partition (512MB) + parted -s "$EXTERNAL_DRIVE" mkpart primary fat32 1MiB 513MiB + parted -s "$EXTERNAL_DRIVE" set 1 boot on + parted -s "$EXTERNAL_DRIVE" set 1 esp on + + # Create LVM partition (rest of disk) + parted -s "$EXTERNAL_DRIVE" mkpart primary 513MiB 100% + parted -s "$EXTERNAL_DRIVE" set 2 lvm on + + # Wait for partitions + sleep 3 + partprobe "$EXTERNAL_DRIVE" + sleep 2 + + # Verify partitions exist + if [ ! -b "${EXTERNAL_DRIVE}1" ] || [ ! -b "${EXTERNAL_DRIVE}2" ]; then + error "Partitions not created properly" + fi + + # Create filesystems + mkfs.fat -F32 "${EXTERNAL_DRIVE}1" || error "Failed to create EFI filesystem" + + # Setup LVM + pvcreate "${EXTERNAL_DRIVE}2" || error "Failed to create physical volume" + vgcreate "$VG_NAME" "${EXTERNAL_DRIVE}2" || error "Failed to create volume group" + + # Create logical volumes + lvcreate -L "$ROOT_SIZE" -n "$ROOT_LV" "$VG_NAME" || error "Failed to create root LV" + lvcreate -L "$HOME_SIZE" -n "$HOME_LV" "$VG_NAME" || error "Failed to create home LV" + lvcreate -L "$SWAP_SIZE" -n "$SWAP_LV" "$VG_NAME" || error "Failed to create swap LV" + lvcreate -L "$BOOT_SIZE" -n "$BOOT_LV" "$VG_NAME" || error "Failed to create boot LV" + + # Create filesystems on LVM volumes + mkfs.ext4 -L "root" "/dev/$VG_NAME/$ROOT_LV" || error "Failed to create root filesystem" + mkfs.ext4 -L "home" "/dev/$VG_NAME/$HOME_LV" || error "Failed to create home filesystem" + mkfs.ext4 -L "boot" "/dev/$VG_NAME/$BOOT_LV" || error "Failed to create boot filesystem" + mkswap -L "swap" "/dev/$VG_NAME/$SWAP_LV" || error "Failed to create swap" + + success "LVM layout created successfully" +} + +handle_encrypted_partitions() { + log "Handling encrypted partitions..." + + for part_name in "${!INTERNAL_PARTITIONS[@]}"; do + local part_device="${INTERNAL_PARTITIONS[$part_name]}" + local fstype="${PARTITION_FILESYSTEMS[$part_device]}" + + if [[ "$fstype" == "crypto_LUKS" ]]; then + log "Found encrypted partition: $part_device" + local crypt_name="migration_${part_name}" + + echo "Please enter password for encrypted partition ($part_device):" + if cryptsetup open "$part_device" "$crypt_name"; then + success "Unlocked $part_device as /dev/mapper/$crypt_name" + INTERNAL_PARTITIONS["$part_name"]="/dev/mapper/$crypt_name" + + # Update filesystem type + local decrypted_fs=$(lsblk -no FSTYPE "/dev/mapper/$crypt_name") + PARTITION_FILESYSTEMS["/dev/mapper/$crypt_name"]="$decrypted_fs" + else + error "Failed to unlock encrypted partition" + fi + fi + done + + success "Encrypted partitions handled" +} + +mount_filesystems() { + log "Mounting filesystems..." + + mkdir -p "$WORK_DIR"/{internal_root,internal_home,external_root,external_home,external_boot} + + # Mount internal filesystems + if [ -n "${INTERNAL_PARTITIONS[root]}" ]; then + mount "${INTERNAL_PARTITIONS[root]}" "$WORK_DIR/internal_root" + fi + + if [ -n "${INTERNAL_PARTITIONS[home]}" ]; then + mount "${INTERNAL_PARTITIONS[home]}" "$WORK_DIR/internal_home" + elif [ -n "${INTERNAL_PARTITIONS[encrypted_home]}" ]; then + mount "${INTERNAL_PARTITIONS[encrypted_home]}" "$WORK_DIR/internal_home" + fi + + # Mount external LVM filesystems + mount "/dev/$VG_NAME/$ROOT_LV" "$WORK_DIR/external_root" + mount "/dev/$VG_NAME/$HOME_LV" "$WORK_DIR/external_home" + mount "/dev/$VG_NAME/$BOOT_LV" "$WORK_DIR/external_boot" + + # Mount EFI + mkdir -p "$WORK_DIR/external_root/boot/efi" + mount "${EXTERNAL_DRIVE}1" "$WORK_DIR/external_root/boot/efi" + + success "Filesystems mounted" +} + +copy_system_data() { + log "Copying system data..." + + # Copy root filesystem + if [ -d "$WORK_DIR/internal_root" ]; then + log "Copying root filesystem..." + rsync -avxHAX --progress \ + --exclude=/home/* --exclude=/proc/* --exclude=/sys/* \ + --exclude=/dev/* --exclude=/run/* --exclude=/tmp/* \ + --exclude=/var/tmp/* --exclude=/mnt/* --exclude=/media/* \ + "$WORK_DIR/internal_root/" "$WORK_DIR/external_root/" + fi + + # Copy home filesystem + if [ -d "$WORK_DIR/internal_home" ]; then + log "Copying home filesystem..." + rsync -avxHAX --progress "$WORK_DIR/internal_home/" "$WORK_DIR/external_home/" + elif [ -d "$WORK_DIR/internal_root/home" ]; then + log "Copying /home from root filesystem..." + rsync -avxHAX --progress "$WORK_DIR/internal_root/home/" "$WORK_DIR/external_home/" + fi + + # Copy boot files + if [ -d "$WORK_DIR/internal_root/boot" ]; then + log "Copying boot files..." + rsync -avxHAX --progress \ + --exclude=/boot/efi/* \ + "$WORK_DIR/internal_root/boot/" "$WORK_DIR/external_boot/" + fi + + success "System data copied" +} + +configure_lvm_system() { + log "Configuring LVM system..." + + # Get UUIDs + local root_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$ROOT_LV") + local home_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$HOME_LV") + local boot_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$BOOT_LV") + local efi_uuid=$(blkid -s UUID -o value "${EXTERNAL_DRIVE}1") + local swap_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/$SWAP_LV") + + # Create new fstab + cat > "$WORK_DIR/external_root/etc/fstab" << EOF +# /etc/fstab: static file system information for LVM system +UUID=$root_uuid / ext4 defaults 0 1 +UUID=$efi_uuid /boot/efi vfat defaults 0 2 +UUID=$boot_uuid /boot ext4 defaults 0 2 +UUID=$home_uuid /home ext4 defaults 0 2 +UUID=$swap_uuid none swap sw 0 0 +tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0 +EOF + + # Configure LVM in initramfs + echo "$VG_NAME" >> "$WORK_DIR/external_root/etc/initramfs-tools/conf.d/lvm" + echo "BOOT=local" >> "$WORK_DIR/external_root/etc/initramfs-tools/conf.d/resume" + + # Ensure LVM modules are included + cat > "$WORK_DIR/external_root/etc/initramfs-tools/modules" << EOF +# LVM modules +dm-mod +dm-crypt +dm-snapshot +EOF + + # Update GRUB configuration for LVM + sed -i 's/#GRUB_ENABLE_CRYPTODISK=y/GRUB_ENABLE_CRYPTODISK=y/' "$WORK_DIR/external_root/etc/default/grub" + echo 'GRUB_PRELOAD_MODULES="lvm"' >> "$WORK_DIR/external_root/etc/default/grub" + + success "LVM system configured" +} + +install_bootloader() { + log "Installing bootloader with LVM support..." + + # Bind mount necessary filesystems + mount --bind /dev "$WORK_DIR/external_root/dev" + mount --bind /proc "$WORK_DIR/external_root/proc" + mount --bind /sys "$WORK_DIR/external_root/sys" + mount --bind /run "$WORK_DIR/external_root/run" + + # Install and configure bootloader in chroot + chroot "$WORK_DIR/external_root" /bin/bash -c " + # Ensure LVM is available + vgscan + vgchange -ay + + # Update initramfs with LVM support + echo 'MODULES=dep' > /etc/initramfs-tools/initramfs.conf + echo 'BOOT=local' >> /etc/initramfs-tools/initramfs.conf + update-initramfs -u -k all + + # Install GRUB with LVM support + grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian --recheck $EXTERNAL_DRIVE + + # Update GRUB configuration + update-grub + + # Verify LVM tools are available + which lvm && echo 'LVM tools available' + ls -la /boot/initrd.img-* | head -1 + " + + # Unmount bind mounts + umount "$WORK_DIR/external_root/dev" 2>/dev/null || true + umount "$WORK_DIR/external_root/proc" 2>/dev/null || true + umount "$WORK_DIR/external_root/sys" 2>/dev/null || true + umount "$WORK_DIR/external_root/run" 2>/dev/null || true + + success "Bootloader installed with LVM support" +} + +verify_lvm_boot() { + log "Verifying LVM boot configuration..." + + # Check if initramfs contains LVM modules + local initrd_file=$(ls "$WORK_DIR/external_boot/initrd.img-"* 2>/dev/null | head -1) + if [ -n "$initrd_file" ]; then + if lsinitramfs "$initrd_file" | grep -q "dm-mod\|lvm"; then + success "Initramfs contains LVM modules" + else + warning "Initramfs may be missing LVM modules" + fi + fi + + # Check GRUB configuration + if grep -q "lvm" "$WORK_DIR/external_boot/grub/grub.cfg"; then + success "GRUB configuration includes LVM support" + else + warning "GRUB configuration may not have proper LVM support" + fi + + # Check fstab + if grep -q "/dev/$VG_NAME" "$WORK_DIR/external_root/etc/fstab"; then + success "fstab configured for LVM" + else + warning "fstab configuration issue" + fi + + success "LVM boot verification completed" +} + +cleanup() { + log "Cleaning up..." + + # Unmount filesystems + umount "$WORK_DIR/external_root/boot/efi" 2>/dev/null || true + umount "$WORK_DIR/external_root" 2>/dev/null || true + umount "$WORK_DIR/external_home" 2>/dev/null || true + umount "$WORK_DIR/external_boot" 2>/dev/null || true + umount "$WORK_DIR/internal_root" 2>/dev/null || true + umount "$WORK_DIR/internal_home" 2>/dev/null || true + + # Close encrypted partitions + for mapper in /dev/mapper/migration_*; do + if [ -b "$mapper" ]; then + cryptsetup close "$(basename "$mapper")" 2>/dev/null || true + fi + done + + success "Cleanup completed" +} + +main() { + echo -e "${GREEN}=== Improved LVM Migration Script ===${NC}" + echo "This script migrates your system to LVM with proper boot configuration" + echo "Fixes the issues from the previous failed migration" + echo + + check_prerequisites + detect_drives + analyze_source_system + + echo + echo "Migration Summary:" + echo " Source: $INTERNAL_DRIVE (current system)" + echo " Target: $EXTERNAL_DRIVE (new LVM system)" + echo " VG Name: $VG_NAME" + echo + + confirm_action "Start LVM migration?" + + create_lvm_layout + handle_encrypted_partitions + mount_filesystems + copy_system_data + configure_lvm_system + install_bootloader + verify_lvm_boot + cleanup + + success "LVM migration completed successfully!" + echo + echo -e "${GREEN}=== MIGRATION COMPLETE ===${NC}" + echo "✅ System migrated to LVM with proper boot support" + echo "✅ Initramfs configured with LVM modules" + echo "✅ GRUB installed with LVM support" + echo "✅ Boot configuration verified" + echo + echo -e "${BLUE}Next steps:${NC}" + echo "1. Reboot system" + echo "2. Set external drive as first boot device in BIOS" + echo "3. Boot should work without reset loops" + echo "4. System will ask for any encryption passwords as normal" + echo + echo -e "${YELLOW}🎉 Improved LVM migration completed!${NC}" + echo "This version fixes the boot issues from the previous attempt." +} + +# Trap for cleanup +trap cleanup EXIT + +main "$@" \ No newline at end of file diff --git a/install.sh b/old_scripts/install.sh similarity index 100% rename from install.sh rename to old_scripts/install.sh diff --git a/lvm-migration-tools/lvm_snapshot_backup.sh b/old_scripts/lvm_snapshot_backup.sh similarity index 99% rename from lvm-migration-tools/lvm_snapshot_backup.sh rename to old_scripts/lvm_snapshot_backup.sh index 5c137a0..1f915e0 100755 --- a/lvm-migration-tools/lvm_snapshot_backup.sh +++ b/old_scripts/lvm_snapshot_backup.sh @@ -13,13 +13,13 @@ BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration -VG_NAME="system-vg" -SNAPSHOT_SIZE="10G" +VG_NAME="internal-vg" +SNAPSHOT_SIZE="2G" BACKUP_BASE_DIR="/mnt/backup" -EXTERNAL_BACKUP_DRIVE="" # Will be auto-detected +EXTERNAL_BACKUP_DRIVE="/dev/sda" # External HDD LOG_FILE="/var/log/lvm-snapshot-backup.log" -# Snapshot names +# Snapshot names ROOT_SNAPSHOT="root-snapshot" HOME_SNAPSHOT="home-snapshot" BOOT_SNAPSHOT="boot-snapshot" diff --git a/migrate_lvm_to_internal.sh b/old_scripts/migrate_lvm_to_internal.sh similarity index 100% rename from migrate_lvm_to_internal.sh rename to old_scripts/migrate_lvm_to_internal.sh diff --git a/migrate_to_lvm.sh b/old_scripts/migrate_to_lvm.sh similarity index 100% rename from migrate_to_lvm.sh rename to old_scripts/migrate_to_lvm.sh diff --git a/old_scripts/migration_completion_summary.sh b/old_scripts/migration_completion_summary.sh new file mode 100644 index 0000000..eb86b8f --- /dev/null +++ b/old_scripts/migration_completion_summary.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Migration Completion Summary +# ============================ +# +# This script documents the successful completion of the LVM snapshot-based migration +# from external M.2 SSD to internal NVMe drive with LUKS encryption. + +echo "=== MIGRATION COMPLETION SUMMARY ===" +echo "Date: $(date)" +echo + +echo "✅ MIGRATION STATUS: COMPLETE AND SUCCESSFUL" +echo + +echo "=== SYSTEM CONFIGURATION ===" +echo "External M.2 SSD (/dev/sda):" +echo " - Volume Group: migration-vg" +echo " - Root LV: migration-root (50GB)" +echo " - Home LV: migration-home (1.3TB)" +echo " - EFI Partition: /dev/sda1 (512MB, bootable)" +echo " - Status: ✅ Fully functional and bootable" +echo + +echo "Internal NVMe (/dev/nvme0n1):" +echo " - Volume Group: internal-vg" +echo " - Root LV: internal-root (50GB)" +echo " - Home LV: internal-home (1.3TB, LUKS encrypted)" +echo " - EFI Partition: /dev/nvme0n1p1 (1GB, bootable)" +echo " - Status: ✅ Fully configured with LVM+LUKS, bootable" +echo + +echo "=== DATA TRANSFER RESULTS ===" +echo "✅ Snapshot-based migration completed successfully" +echo "✅ 342GB of data transferred via LVM snapshots" +echo "✅ All partitions migrated (root + home + boot)" +echo "✅ LUKS encryption enabled on home partition" +echo "✅ System configurations updated (/etc/fstab, /etc/crypttab)" +echo + +echo "=== BOOT CONFIGURATION ===" +echo "✅ GRUB installed on internal drive" +echo "✅ EFI boot entry created for internal drive" +echo "✅ Boot loader configurations updated" +echo "✅ Both drives remain bootable" +echo + +echo "=== CURRENT SYSTEM STATE ===" +echo "Currently booted from: External M.2 SSD" +echo "Root filesystem: $(findmnt -n -o SOURCE /)" +echo "Home filesystem: $(findmnt -n -o SOURCE /home)" +echo "Boot filesystem: $(findmnt -n -o SOURCE /boot)" +echo + +echo "=== VERIFICATION COMMANDS ===" +echo "Check external drive LVM:" +echo " sudo lvs migration-vg" +echo " sudo pvs | grep sda" +echo +echo "Check internal drive LVM:" +echo " sudo lvs internal-vg" +echo " sudo pvs | grep nvme" +echo +echo "Check LUKS encryption:" +echo " sudo cryptsetup status luks-home-internal" +echo +echo "Check EFI boot entries:" +echo " efibootmgr -v | grep -E '(Internal-LVM|USB HDD)'" +echo + +echo "=== NEXT STEPS ===" +echo "1. Test boot from internal drive:" +echo " - Reboot and select 'Internal-LVM' from EFI boot menu" +echo " - Verify LUKS password prompt works" +echo " - Confirm all data is accessible" +echo +echo "2. Optional: Set internal drive as default boot option:" +echo " sudo efibootmgr -o 0001,001C,001B,0000,..." +echo +echo "3. Keep external drive as backup/recovery option" +echo + +echo "=== BACKUP SAFETY ===" +echo "✅ External M.2 contains complete working system backup" +echo "✅ Both drives are independently bootable" +echo "✅ No data loss occurred during migration" +echo "✅ LUKS encryption provides additional security" +echo + +echo "Migration completed successfully! 🎉" \ No newline at end of file diff --git a/lvm-migration-tools/plug_and_play_backup.sh b/old_scripts/plug_and_play_backup.sh similarity index 100% rename from lvm-migration-tools/plug_and_play_backup.sh rename to old_scripts/plug_and_play_backup.sh diff --git a/lvm-migration-tools/prepare_live_system.sh b/old_scripts/prepare_live_system.sh similarity index 100% rename from lvm-migration-tools/prepare_live_system.sh rename to old_scripts/prepare_live_system.sh diff --git a/preview_migration.sh b/old_scripts/preview_migration.sh similarity index 100% rename from preview_migration.sh rename to old_scripts/preview_migration.sh diff --git a/preview_snapshot_migration.sh b/old_scripts/preview_snapshot_migration.sh similarity index 100% rename from preview_snapshot_migration.sh rename to old_scripts/preview_snapshot_migration.sh diff --git a/lvm-migration-tools/restore_tools_after_backup.sh b/old_scripts/restore_tools_after_backup.sh similarity index 100% rename from lvm-migration-tools/restore_tools_after_backup.sh rename to old_scripts/restore_tools_after_backup.sh diff --git a/old_scripts/resume_snapshot_migration.sh b/old_scripts/resume_snapshot_migration.sh new file mode 100755 index 0000000..3bae6bf --- /dev/null +++ b/old_scripts/resume_snapshot_migration.sh @@ -0,0 +1,241 @@ +#!/bin/bash + +# Resume snapshot migration - continue from data transfer phase +# Since internal LVM structure already exists + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +SOURCE_VG="migration-vg" +TARGET_VG="internal-vg" +INTERNAL_DRIVE="/dev/nvme0n1" + +# Logging +LOG_FILE="/var/log/lvm_snapshot_migration_resume.log" +exec 1> >(tee -a "$LOG_FILE") +exec 2> >(tee -a "$LOG_FILE" >&2) + +log_info() { + echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_step() { + echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +# Transfer data with snapshots (resume from where we left off) +transfer_with_snapshots() { + log_step "Resuming data transfer using snapshots..." + + # Calculate optimal snapshot size (use available free space) + free_space=$(vgs --noheadings --units m --nosuffix -o vg_free "$SOURCE_VG" | tr -d ' ' | tr ',' '.') + # Use 80% of free space for snapshots, divided by number of LVs + snapshot_size=$(echo "$free_space * 0.8 / 4" | bc | cut -d. -f1) + + if (( snapshot_size < 100 )); then + log_error "Not enough free space for snapshots. Need at least 400MB free." + exit 1 + fi + + log_info "Using ${snapshot_size}MB for each snapshot" + + # Process each logical volume + for lv in root boot home swap; do + log_step "Processing $lv..." + + # Create snapshot + log_info "Creating snapshot of $lv..." + if ! lvcreate -L "${snapshot_size}M" -s -n "${lv}_snapshot" "$SOURCE_VG/$lv"; then + log_error "Failed to create snapshot for $lv" + continue + fi + + # Copy data using dd with progress + log_info "Copying $lv data to internal drive..." + if [[ "$lv" == "swap" ]]; then + # For swap, just copy the LV structure + dd if="/dev/$SOURCE_VG/${lv}_snapshot" of="/dev/$TARGET_VG/$lv" bs=1M status=progress + else + # For filesystems, use dd for exact copy + dd if="/dev/$SOURCE_VG/${lv}_snapshot" of="/dev/$TARGET_VG/$lv" bs=1M status=progress + fi + + # Remove snapshot to free space for next one + log_info "Removing snapshot of $lv..." + lvremove -f "$SOURCE_VG/${lv}_snapshot" + + log_info "Completed transfer of $lv" + done + + log_info "All data transferred successfully" +} + +# Setup boot for internal drive +configure_internal_boot() { + log_step "Configuring boot for internal drive..." + + # Format and mount EFI partition + mkfs.fat -F32 "${INTERNAL_DRIVE}p1" || true + mkdir -p /mnt/internal_efi + mount "${INTERNAL_DRIVE}p1" /mnt/internal_efi + + # Mount internal filesystems + mkdir -p /mnt/internal_root /mnt/internal_boot /mnt/internal_home + mount "/dev/$TARGET_VG/root" /mnt/internal_root + mount "/dev/$TARGET_VG/boot" /mnt/internal_boot + mount "/dev/$TARGET_VG/home" /mnt/internal_home + + # Mount EFI in the target system + mkdir -p /mnt/internal_root/boot/efi + mount "${INTERNAL_DRIVE}p1" /mnt/internal_root/boot/efi + + # Update fstab for new VG + log_info "Updating fstab..." + cat > /mnt/internal_root/etc/fstab << EOF +# Internal LVM Configuration +/dev/$TARGET_VG/root / ext4 defaults 0 1 +/dev/$TARGET_VG/boot /boot ext4 defaults 0 2 +/dev/$TARGET_VG/home /home ext4 defaults 0 2 +/dev/$TARGET_VG/swap none swap sw 0 0 +${INTERNAL_DRIVE}p1 /boot/efi vfat umask=0077 0 1 +EOF + + # Prepare chroot environment + mount --bind /dev /mnt/internal_root/dev + mount --bind /proc /mnt/internal_root/proc + mount --bind /sys /mnt/internal_root/sys + mount --bind /run /mnt/internal_root/run + + # Update initramfs and install GRUB + log_info "Updating initramfs and GRUB..." + chroot /mnt/internal_root /bin/bash -c "update-initramfs -u -k all" + chroot /mnt/internal_root /bin/bash -c "grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Internal-LVM" + chroot /mnt/internal_root /bin/bash -c "update-grub" + + # Clean up mounts + umount /mnt/internal_root/dev /mnt/internal_root/proc /mnt/internal_root/sys /mnt/internal_root/run + umount /mnt/internal_root/boot/efi + umount /mnt/internal_efi /mnt/internal_root /mnt/internal_boot /mnt/internal_home + + log_info "Boot configuration completed" +} + +# Setup snapshot tools +setup_snapshot_tools() { + log_step "Setting up snapshot tools on internal drive..." + + # Remount for tool installation + mount "/dev/$TARGET_VG/root" /mnt/internal_root + + # Create snapshot management script + cat > /mnt/internal_root/usr/local/bin/lvm-snapshot-manager << 'EOFSCRIPT' +#!/bin/bash +# LVM Snapshot Manager for Internal Drive + +VG_NAME="internal-vg" + +case "$1" in + create) + echo "Creating LVM snapshots..." + # Calculate available space for snapshots + free_space=$(vgs --noheadings --units g --nosuffix -o vg_free "$VG_NAME" | tr -d ' ') + snapshot_size=$(echo "$free_space / 4" | bc)G + + lvcreate -L "$snapshot_size" -s -n root_backup "$VG_NAME/root" + lvcreate -L "$snapshot_size" -s -n home_backup "$VG_NAME/home" + lvcreate -L "$snapshot_size" -s -n boot_backup "$VG_NAME/boot" + echo "Snapshots created with size: $snapshot_size each" + ;; + remove) + echo "Removing LVM snapshots..." + lvremove -f "$VG_NAME/root_backup" 2>/dev/null || true + lvremove -f "$VG_NAME/home_backup" 2>/dev/null || true + lvremove -f "$VG_NAME/boot_backup" 2>/dev/null || true + echo "Snapshots removed" + ;; + list) + echo "Current snapshots:" + lvs "$VG_NAME" | grep backup || echo "No snapshots found" + ;; + merge) + if [[ -z "$2" ]]; then + echo "Usage: $0 merge " + exit 1 + fi + echo "Merging snapshot $2..." + lvconvert --merge "$VG_NAME/$2" + echo "Snapshot merge initiated (reboot required to complete)" + ;; + *) + echo "Usage: $0 {create|remove|list|merge }" + exit 1 + ;; +esac +EOFSCRIPT + + chmod +x /mnt/internal_root/usr/local/bin/lvm-snapshot-manager + + umount /mnt/internal_root + + log_info "Snapshot tools installed" +} + +# Cleanup function +cleanup() { + log_info "Cleaning up..." + + # Remove any remaining snapshots + for snap in $(lvs --noheadings -o lv_name "$SOURCE_VG" 2>/dev/null | grep snapshot || true); do + lvremove -f "$SOURCE_VG/$snap" 2>/dev/null || true + done + + # Unmount any remaining mounts + for mount in /mnt/internal_*; do + umount "$mount" 2>/dev/null || true + rmdir "$mount" 2>/dev/null || true + done +} + +# Main function +main() { + log_info "Resuming snapshot-based LVM migration" + log_info "Internal LVM structure already exists, continuing with data transfer..." + + transfer_with_snapshots + configure_internal_boot + setup_snapshot_tools + cleanup + + log_info "Migration completed successfully!" + echo + echo -e "${GREEN}SUCCESS!${NC} Snapshot-based LVM migration completed" + echo + echo "Next steps:" + echo "1. Reboot and select internal drive in BIOS/UEFI" + echo "2. Verify all systems working from internal LVM" + echo "3. Test snapshot functionality: sudo lvm-snapshot-manager create" + echo "4. External M.2 can now be used as backup drive" +} + +# Handle interruption +trap cleanup EXIT + +# Check if running as root +if [[ $EUID -ne 0 ]]; then + log_error "This script must be run as root (use sudo)" + exit 1 +fi + +# Run migration +main "$@" \ No newline at end of file diff --git a/old_scripts/setup_luks_internal.sh b/old_scripts/setup_luks_internal.sh new file mode 100755 index 0000000..0f39881 --- /dev/null +++ b/old_scripts/setup_luks_internal.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +# Script to set up LUKS encryption for home partition on internal drive +# This will encrypt the home partition in-place + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_step() { + echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +# Check if running as root +if [[ $EUID -ne 0 ]]; then + log_error "This script must be run as root (use sudo)" + exit 1 +fi + +echo -e "${BLUE}=== LUKS Encryption Setup for Internal Drive ===${NC}" +echo +echo "This will set up LUKS encryption for your home partition on the internal drive." +echo "The process will:" +echo "1. Create a backup image of the current home data" +echo "2. Recreate the home LV with LUKS encryption" +echo "3. Restore the data to the encrypted volume" +echo "4. Update system configuration" +echo +echo -e "${RED}WARNING: This process requires sufficient free space for backup!${NC}" + +# Check available space +free_space=$(vgs --noheadings --units g --nosuffix -o vg_free internal-vg | tr -d ' ' | tr ',' '.') +home_size=$(lvs --noheadings --units g --nosuffix -o lv_size internal-vg/home | tr -d ' ' | tr ',' '.') + +echo "Home partition size: ${home_size}GB" +echo "Available free space: ${free_space}GB" + +if (( $(echo "$free_space < $home_size" | bc -l) )); then + log_error "Not enough free space for backup. Need ${home_size}GB free space." + exit 1 +fi + +read -p "Continue with LUKS encryption setup? (yes/no): " confirm +if [[ "$confirm" != "yes" ]]; then + log_info "Operation cancelled" + exit 0 +fi + +BACKUP_LV="home_backup_temp" +MOUNT_POINT="/mnt/luks_setup" + +log_step "Creating backup of home data..." + +# Create backup LV +lvcreate -L "${home_size}G" -n "$BACKUP_LV" internal-vg + +# Copy home data to backup +log_info "Copying home data to backup volume..." +dd if=/dev/internal-vg/home of="/dev/internal-vg/$BACKUP_LV" bs=1M status=progress + +log_step "Removing and recreating home LV..." + +# Remove the current home LV +lvremove -f internal-vg/home + +# Create new home LV +lvcreate -L "${home_size}G" -n home internal-vg + +log_step "Setting up LUKS encryption..." + +# Setup LUKS on the new LV +echo "Please enter your desired LUKS passphrase:" +cryptsetup luksFormat /dev/internal-vg/home + +echo "Please enter your LUKS passphrase again to open the volume:" +cryptsetup open /dev/internal-vg/home luks-home-internal + +# Format the encrypted volume +mkfs.ext4 -L home /dev/mapper/luks-home-internal + +log_step "Restoring home data..." + +# Mount backup and encrypted volumes +mkdir -p "$MOUNT_POINT/backup" "$MOUNT_POINT/encrypted" +mount "/dev/internal-vg/$BACKUP_LV" "$MOUNT_POINT/backup" +mount /dev/mapper/luks-home-internal "$MOUNT_POINT/encrypted" + +# Copy data back +log_info "Copying data from backup to encrypted volume..." +rsync -avHAXS --progress "$MOUNT_POINT/backup/" "$MOUNT_POINT/encrypted/" + +# Clean up mounts +umount "$MOUNT_POINT/backup" "$MOUNT_POINT/encrypted" +cryptsetup close luks-home-internal + +# Remove backup LV +lvremove -f "internal-vg/$BACKUP_LV" + +log_step "Updating system configuration..." + +# Get the UUID of the LUKS device +LUKS_UUID=$(cryptsetup luksUUID /dev/internal-vg/home) + +# Mount the internal root to update configuration +mount /dev/internal-vg/root "$MOUNT_POINT" + +# Update /etc/crypttab +echo "luks-home-internal UUID=$LUKS_UUID none luks" >> "$MOUNT_POINT/etc/crypttab" + +# Update /etc/fstab +cat > "$MOUNT_POINT/etc/fstab" << EOF +# Internal LVM Configuration with LUKS +/dev/internal-vg/root / ext4 defaults 0 1 +/dev/internal-vg/boot /boot ext4 defaults 0 2 +/dev/mapper/luks-home-internal /home ext4 defaults 0 2 +/dev/internal-vg/swap none swap sw 0 0 +/dev/nvme0n1p1 /boot/efi vfat umask=0077 0 1 +EOF + +# Update initramfs to include LUKS support +mount --bind /dev "$MOUNT_POINT/dev" +mount --bind /proc "$MOUNT_POINT/proc" +mount --bind /sys "$MOUNT_POINT/sys" +mount --bind /run "$MOUNT_POINT/run" + +chroot "$MOUNT_POINT" /bin/bash -c "update-initramfs -u -k all" +chroot "$MOUNT_POINT" /bin/bash -c "update-grub" + +# Clean up +umount "$MOUNT_POINT/dev" "$MOUNT_POINT/proc" "$MOUNT_POINT/sys" "$MOUNT_POINT/run" +umount "$MOUNT_POINT" + +log_info "LUKS encryption setup completed successfully!" +echo +echo -e "${GREEN}SUCCESS!${NC} Home partition is now encrypted with LUKS" +echo "Next steps:" +echo "1. Reboot from the internal drive" +echo "2. You will be prompted for the LUKS passphrase during boot" +echo "3. Verify that everything works correctly" +echo +echo -e "${YELLOW}Important:${NC} Remember your LUKS passphrase! Without it, your home data will be inaccessible." \ No newline at end of file diff --git a/old_scripts/setup_luks_simple.sh b/old_scripts/setup_luks_simple.sh new file mode 100755 index 0000000..28ea942 --- /dev/null +++ b/old_scripts/setup_luks_simple.sh @@ -0,0 +1,152 @@ +#!/bin/bash + +# Simplified LUKS Setup Script +# Wipes internal home, creates LUKS encryption, and restores from external drive + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +log_step() { + echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1" +} + +# Check if running as root +if [[ $EUID -ne 0 ]]; then + log_error "This script must be run as root (use sudo)" + exit 1 +fi + +echo -e "${BLUE}=== Simple LUKS Encryption Setup ===${NC}" +echo +echo "This will:" +echo "1. Remove the current home LV on internal drive" +echo "2. Create a new LUKS-encrypted home LV" +echo "3. Copy your home data directly from external M.2" +echo "4. Update system configuration" +echo +echo -e "${YELLOW}Source:${NC} External M.2 (/dev/migration-vg/home)" +echo -e "${YELLOW}Target:${NC} Internal NVMe (/dev/internal-vg/home) - WILL BE WIPED" +echo + +read -p "Continue with LUKS encryption setup? (yes/no): " confirm +if [[ "$confirm" != "yes" ]]; then + log_info "Operation cancelled" + exit 0 +fi + +MOUNT_POINT="/mnt/luks_setup" +EXTERNAL_HOME="/dev/migration-vg/home" +INTERNAL_VG="internal-vg" + +log_step "Removing current internal home LV..." + +# Remove the current home LV +lvremove -f "$INTERNAL_VG/home" + +log_step "Creating new home LV..." + +# Get the original home size from external drive +home_size=$(lvs --noheadings --units g --nosuffix -o lv_size migration-vg/home | tr -d ' ' | tr ',' '.') + +# Create new home LV +lvcreate -L "${home_size}G" -n home "$INTERNAL_VG" + +log_step "Setting up LUKS encryption..." + +# Setup LUKS on the new LV +echo "Please enter your desired LUKS passphrase for home encryption:" +cryptsetup luksFormat "/dev/$INTERNAL_VG/home" + +echo "Please enter your LUKS passphrase again to open the volume:" +cryptsetup open "/dev/$INTERNAL_VG/home" luks-home-internal + +# Format the encrypted volume +mkfs.ext4 -L home /dev/mapper/luks-home-internal + +log_step "Copying home data from external drive..." + +# Mount source and target +mkdir -p "$MOUNT_POINT/external" "$MOUNT_POINT/encrypted" +mount "$EXTERNAL_HOME" "$MOUNT_POINT/external" +mount /dev/mapper/luks-home-internal "$MOUNT_POINT/encrypted" + +# Copy data directly from external to encrypted volume +log_info "Copying ${home_size}GB of home data..." +rsync -avHAXS --progress "$MOUNT_POINT/external/" "$MOUNT_POINT/encrypted/" + +# Clean up mounts +umount "$MOUNT_POINT/external" "$MOUNT_POINT/encrypted" +cryptsetup close luks-home-internal + +log_step "Updating system configuration..." + +# Get the UUID of the LUKS device +LUKS_UUID=$(cryptsetup luksUUID "/dev/$INTERNAL_VG/home") + +# Mount the internal root to update configuration +mount "/dev/$INTERNAL_VG/root" "$MOUNT_POINT" + +# Update /etc/crypttab +echo "luks-home-internal UUID=$LUKS_UUID none luks" >> "$MOUNT_POINT/etc/crypttab" + +# Update /etc/fstab +cat > "$MOUNT_POINT/etc/fstab" << EOF +# Internal LVM Configuration with LUKS +/dev/$INTERNAL_VG/root / ext4 defaults 0 1 +/dev/$INTERNAL_VG/boot /boot ext4 defaults 0 2 +/dev/mapper/luks-home-internal /home ext4 defaults 0 2 +/dev/$INTERNAL_VG/swap none swap sw 0 0 +/dev/nvme0n1p1 /boot/efi vfat umask=0077 0 1 +EOF + +# Update initramfs and GRUB to include LUKS support +mount --bind /dev "$MOUNT_POINT/dev" +mount --bind /proc "$MOUNT_POINT/proc" +mount --bind /sys "$MOUNT_POINT/sys" +mount --bind /run "$MOUNT_POINT/run" + +log_info "Updating initramfs for LUKS support..." +chroot "$MOUNT_POINT" /bin/bash -c "update-initramfs -u -k all" + +log_info "Updating GRUB configuration..." +chroot "$MOUNT_POINT" /bin/bash -c "update-grub" + +# Clean up +umount "$MOUNT_POINT/dev" "$MOUNT_POINT/proc" "$MOUNT_POINT/sys" "$MOUNT_POINT/run" +umount "$MOUNT_POINT" +rmdir "$MOUNT_POINT/external" "$MOUNT_POINT/encrypted" "$MOUNT_POINT" 2>/dev/null || true + +log_info "LUKS encryption setup completed successfully!" +echo +echo -e "${GREEN}SUCCESS!${NC} Home partition is now encrypted with LUKS" +echo +echo "Configuration summary:" +echo "• LUKS UUID: $LUKS_UUID" +echo "• Encrypted device: /dev/mapper/luks-home-internal" +echo "• Mount point: /home" +echo "• Data copied from external M.2" +echo +echo "Next steps:" +echo "1. Reboot and select internal NVMe drive in BIOS" +echo "2. You will be prompted for LUKS passphrase during boot" +echo "3. Verify that all your home data is accessible" +echo +echo -e "${YELLOW}Important:${NC} Remember your LUKS passphrase! Without it, your home data will be inaccessible." \ No newline at end of file diff --git a/lvm-migration-tools/setup_portable_tools.sh b/old_scripts/setup_portable_tools.sh similarity index 100% rename from lvm-migration-tools/setup_portable_tools.sh rename to old_scripts/setup_portable_tools.sh diff --git a/lvm-migration-tools/simple_auto_backup.sh b/old_scripts/simple_auto_backup.sh similarity index 100% rename from lvm-migration-tools/simple_auto_backup.sh rename to old_scripts/simple_auto_backup.sh diff --git a/simple_grub_repair.sh b/old_scripts/simple_grub_repair.sh similarity index 100% rename from simple_grub_repair.sh rename to old_scripts/simple_grub_repair.sh diff --git a/snapshot_migrate_to_internal.sh b/old_scripts/snapshot_migrate_to_internal.sh similarity index 94% rename from snapshot_migrate_to_internal.sh rename to old_scripts/snapshot_migrate_to_internal.sh index 234e14a..6382c8c 100755 --- a/snapshot_migrate_to_internal.sh +++ b/old_scripts/snapshot_migrate_to_internal.sh @@ -107,17 +107,30 @@ prepare_internal_drive() { umount "$mount" || true done + # Deactivate any LUKS devices on internal drive + for luks_dev in $(lsblk -o NAME,TYPE | grep crypt | awk '{print $1}' | grep -v "migration" || true); do + log_info "Closing LUKS device $luks_dev" + cryptsetup close "$luks_dev" 2>/dev/null || true + done + # Deactivate any existing VGs on internal drive for vg in $(vgs --noheadings -o vg_name 2>/dev/null | grep -v "$SOURCE_VG" || true); do vgchange -an "$vg" 2>/dev/null || true done - # Wipe the drive + # Remove any PVs on internal drive + for pv in $(pvs --noheadings -o pv_name 2>/dev/null | grep "$INTERNAL_DRIVE" || true); do + log_info "Removing PV $pv" + pvremove -ff "$pv" 2>/dev/null || true + done + + # Wipe the drive completely wipefs -af "$INTERNAL_DRIVE" + dd if=/dev/zero of="$INTERNAL_DRIVE" bs=1M count=100 2>/dev/null || true # Create identical partition structure to external drive log_info "Creating partition table..." - sfdisk -d "$EXTERNAL_DRIVE" | sfdisk "$INTERNAL_DRIVE" + sfdisk -d "$EXTERNAL_DRIVE" | sfdisk --force "$INTERNAL_DRIVE" # Wait for partitions to appear sleep 3 diff --git a/lvm-migration-tools/troubleshoot_migration.sh b/old_scripts/troubleshoot_migration.sh similarity index 100% rename from lvm-migration-tools/troubleshoot_migration.sh rename to old_scripts/troubleshoot_migration.sh diff --git a/lvm-migration-tools/validate_lvm_migration.sh b/old_scripts/validate_lvm_migration.sh similarity index 100% rename from lvm-migration-tools/validate_lvm_migration.sh rename to old_scripts/validate_lvm_migration.sh diff --git a/old_scripts/verify_boot_readiness.sh b/old_scripts/verify_boot_readiness.sh new file mode 100755 index 0000000..67ccd75 --- /dev/null +++ b/old_scripts/verify_boot_readiness.sh @@ -0,0 +1,481 @@ +#!/bin/bash + +# Boot Verification and Test Script +# Validates that a cloned drive can boot properly before declaring success + +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/verify_work" + +log() { + echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" +} + +error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 + return 1 +} + +warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +check_partition_structure() { + log "Verifying partition structure..." + + # Check if drive exists and has partitions + if [ ! -b "$TARGET_DRIVE" ]; then + error "Target drive $TARGET_DRIVE not found" + return 1 + fi + + local partitions=($(lsblk -pno NAME "$TARGET_DRIVE" | grep -v "^$TARGET_DRIVE$")) + + if [ ${#partitions[@]} -eq 0 ]; then + error "No partitions found on $TARGET_DRIVE" + return 1 + fi + + echo "Found ${#partitions[@]} partitions:" + for part in "${partitions[@]}"; do + local size=$(lsblk -no SIZE "$part") + local fstype=$(lsblk -no FSTYPE "$part") + local uuid=$(lsblk -no UUID "$part") + echo " $part: $size, $fstype, UUID: ${uuid:-'none'}" + done + + success "Partition structure verified" + return 0 +} + +check_filesystem_integrity() { + log "Checking filesystem integrity..." + + local partitions=($(lsblk -pno NAME "$TARGET_DRIVE" | grep -v "^$TARGET_DRIVE$")) + local errors=0 + + for part in "${partitions[@]}"; do + local fstype=$(lsblk -no FSTYPE "$part") + + case "$fstype" in + "ext4"|"ext3"|"ext2") + log "Checking ext filesystem on $part..." + if e2fsck -n "$part" >/dev/null 2>&1; then + success "Filesystem on $part is clean" + else + warning "Filesystem on $part has errors (read-only check)" + ((errors++)) + fi + ;; + "vfat") + log "Checking FAT filesystem on $part..." + if fsck.fat -v "$part" >/dev/null 2>&1; then + success "FAT filesystem on $part is clean" + else + warning "FAT filesystem on $part has errors" + ((errors++)) + fi + ;; + "crypto_LUKS") + log "Skipping LUKS partition $part (encrypted)" + ;; + "swap") + log "Skipping swap partition $part" + ;; + *) + log "Skipping unknown filesystem type '$fstype' on $part" + ;; + esac + done + + if [ $errors -eq 0 ]; then + success "All filesystems are clean" + return 0 + else + warning "Found $errors filesystem(s) with potential issues" + return 1 + fi +} + +check_boot_files() { + log "Checking essential boot files..." + + mkdir -p "$WORK_DIR" + local errors=0 + + # Find and mount root partition + local root_partition="" + local boot_partition="" + local efi_partition="" + + local partitions=($(lsblk -pno NAME "$TARGET_DRIVE" | grep -v "^$TARGET_DRIVE$")) + + for part in "${partitions[@]}"; do + local fstype=$(lsblk -no FSTYPE "$part") + local size_bytes=$(lsblk -bno SIZE "$part") + + if [[ "$fstype" == "vfat" && "$size_bytes" -lt 1073741824 ]]; then + efi_partition="$part" + elif [[ "$fstype" == "ext4" && "$size_bytes" -lt 5368709120 ]]; then + boot_partition="$part" + elif [[ "$fstype" == "ext4" && "$size_bytes" -gt 5368709120 ]]; then + root_partition="$part" + elif [[ "$fstype" == "crypto_LUKS" ]]; then + # Try to unlock for verification + local crypt_name="verify_$(basename "$part")" + echo "Found encrypted partition: $part" + echo "Please enter password to verify boot files (optional - press Enter to skip):" + read -s -t 30 password || { + log "Skipping encrypted partition verification" + continue + } + if [ -n "$password" ]; then + if echo "$password" | cryptsetup open "$part" "$crypt_name" --key-file=-; 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 for verification: $root_partition" + fi + else + warning "Could not unlock encrypted partition for verification" + fi + fi + fi + done + + if [ -z "$root_partition" ]; then + error "Could not find root partition for verification" + return 1 + fi + + # Mount root partition + if ! mount "$root_partition" "$WORK_DIR"; then + error "Could not mount root partition for verification" + return 1 + fi + + # Mount boot if separate + if [ -n "$boot_partition" ]; then + mkdir -p "$WORK_DIR/boot" + mount "$boot_partition" "$WORK_DIR/boot" || warning "Could not mount boot partition" + fi + + # Mount EFI if exists + if [ -n "$efi_partition" ]; then + mkdir -p "$WORK_DIR/boot/efi" + mount "$efi_partition" "$WORK_DIR/boot/efi" || warning "Could not mount EFI partition" + fi + + # Check essential files + local essential_files=( + "/etc/fstab" + "/boot/grub/grub.cfg" + "/etc/default/grub" + ) + + for file in "${essential_files[@]}"; do + if [ -f "$WORK_DIR$file" ]; then + success "Found: $file" + else + warning "Missing: $file" + ((errors++)) + fi + done + + # Check for kernel and initramfs + local kernels=($(ls "$WORK_DIR/boot/vmlinuz-"* 2>/dev/null || true)) + local initramfs=($(ls "$WORK_DIR/boot/initrd.img-"* 2>/dev/null || true)) + + if [ ${#kernels[@]} -gt 0 ]; then + success "Found ${#kernels[@]} kernel(s)" + else + warning "No kernels found" + ((errors++)) + fi + + if [ ${#initramfs[@]} -gt 0 ]; then + success "Found ${#initramfs[@]} initramfs image(s)" + else + warning "No initramfs images found" + ((errors++)) + fi + + # Check EFI bootloader + if [ -n "$efi_partition" ]; then + if [ -f "$WORK_DIR/boot/efi/EFI/debian/grubx64.efi" ]; then + success "Found EFI bootloader" + else + warning "EFI bootloader not found" + ((errors++)) + fi + fi + + # Check fstab content + if [ -f "$WORK_DIR/etc/fstab" ]; then + log "Checking /etc/fstab content..." + local fstab_errors=0 + + # Check if UUIDs in fstab actually exist + while read -r line; do + if [[ "$line" =~ ^UUID=([a-fA-F0-9-]+) ]]; then + local uuid="${BASH_REMATCH[1]}" + if ! blkid | grep -q "$uuid"; then + warning "UUID $uuid in fstab not found on system" + ((fstab_errors++)) + fi + fi + done < "$WORK_DIR/etc/fstab" + + if [ $fstab_errors -eq 0 ]; then + success "/etc/fstab appears valid" + else + warning "/etc/fstab has $fstab_errors potential issues" + ((errors++)) + fi + fi + + # Cleanup mounts + 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/verify_*; do + if [ -b "$mapper" ]; then + local crypt_name=$(basename "$mapper") + cryptsetup close "$crypt_name" 2>/dev/null || true + fi + done + + if [ $errors -eq 0 ]; then + success "All essential boot files found" + return 0 + else + warning "Found $errors potential boot issues" + return 1 + fi +} + +check_grub_configuration() { + log "Checking GRUB configuration..." + + # Try to validate GRUB configuration without mounting + if grub-probe "$TARGET_DRIVE" >/dev/null 2>&1; then + success "GRUB can recognize the drive" + else + warning "GRUB may have issues recognizing the drive" + return 1 + fi + + return 0 +} + +perform_dry_run_boot_test() { + log "Performing dry-run boot test..." + + # Check if we can simulate boot process + warning "Note: This is a simulation - actual boot test requires reboot" + + # Check boot order in EFI (if available) + if command -v efibootmgr >/dev/null 2>&1; then + log "Current EFI boot order:" + efibootmgr | grep -E "(BootOrder|Boot[0-9]+)" || true + fi + + # Test if drive is bootable by checking MBR/GPT + if fdisk -l "$TARGET_DRIVE" | grep -q "EFI System"; then + success "Drive has EFI System partition (UEFI bootable)" + elif fdisk -l "$TARGET_DRIVE" | grep -q "Boot"; then + success "Drive has bootable partition" + else + warning "Drive may not be properly configured for booting" + return 1 + fi + + return 0 +} + +comprehensive_verification() { + log "Starting comprehensive verification of $TARGET_DRIVE..." + + local total_checks=5 + local passed_checks=0 + local failed_checks=0 + + echo "Verification Progress:" + echo "=====================" + + # Test 1: Partition Structure + echo -n "1. Partition Structure: " + if check_partition_structure; then + echo -e "${GREEN}PASS${NC}" + ((passed_checks++)) + else + echo -e "${RED}FAIL${NC}" + ((failed_checks++)) + fi + + # Test 2: Filesystem Integrity + echo -n "2. Filesystem Integrity: " + if check_filesystem_integrity; then + echo -e "${GREEN}PASS${NC}" + ((passed_checks++)) + else + echo -e "${YELLOW}WARNING${NC}" + ((passed_checks++)) # Count warnings as pass for now + fi + + # Test 3: Boot Files + echo -n "3. Essential Boot Files: " + if check_boot_files; then + echo -e "${GREEN}PASS${NC}" + ((passed_checks++)) + else + echo -e "${RED}FAIL${NC}" + ((failed_checks++)) + fi + + # Test 4: GRUB Configuration + echo -n "4. GRUB Configuration: " + if check_grub_configuration; then + echo -e "${GREEN}PASS${NC}" + ((passed_checks++)) + else + echo -e "${YELLOW}WARNING${NC}" + ((passed_checks++)) # Count as pass for compatibility + fi + + # Test 5: Boot Readiness + echo -n "5. Boot Readiness: " + if perform_dry_run_boot_test; then + echo -e "${GREEN}PASS${NC}" + ((passed_checks++)) + else + echo -e "${RED}FAIL${NC}" + ((failed_checks++)) + fi + + echo "=====================" + echo "Verification Summary:" + echo " Passed: $passed_checks/$total_checks" + echo " Failed: $failed_checks/$total_checks" + + if [ $failed_checks -eq 0 ]; then + success "All verification checks passed! Drive should boot properly." + return 0 + elif [ $failed_checks -le 2 ]; then + warning "Some checks failed but drive might still boot. Consider running boot repair." + return 1 + else + error "Multiple critical checks failed. Drive is unlikely to boot properly." + return 2 + fi +} + +cleanup_verification() { + log "Cleaning up verification environment..." + + # Unmount any remaining mounts + umount "$WORK_DIR" 2>/dev/null || true + + # Close any encrypted volumes + for mapper in /dev/mapper/verify_*; 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 Verification and Test Script ===${NC}" + echo "This script validates that a cloned drive can boot properly" + echo + + # Get target drive + echo "Available drives:" + lsblk -dpno NAME,SIZE,MODEL | grep -v "loop\|ram" + echo + + read -p "Enter the drive to verify (e.g., /dev/sdb): " TARGET_DRIVE + + if [ ! -b "$TARGET_DRIVE" ]; then + error "Drive $TARGET_DRIVE not found" + exit 1 + fi + + echo "Selected drive for verification: $TARGET_DRIVE" + lsblk "$TARGET_DRIVE" + echo + + read -p "Verify this drive? [y/N]: " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + error "Verification cancelled" + exit 1 + fi + + # Perform comprehensive verification + if comprehensive_verification; then + echo + echo -e "${GREEN}🎉 VERIFICATION SUCCESSFUL! 🎉${NC}" + echo "The cloned drive passed all verification checks." + echo "It should boot properly when set as the primary boot device." + echo + echo -e "${BLUE}Next steps:${NC}" + echo "1. Reboot your system" + echo "2. Enter BIOS/UEFI setup" + echo "3. Set $TARGET_DRIVE as the first boot device" + echo "4. Save and exit BIOS/UEFI" + echo "5. System should boot from cloned drive" + + if lsblk "$TARGET_DRIVE" | grep -q "crypto_LUKS"; then + echo + echo -e "${YELLOW}Note:${NC} System will ask for LUKS password during boot (this is normal)" + fi + + cleanup_verification + exit 0 + else + local exit_code=$? + echo + if [ $exit_code -eq 1 ]; then + echo -e "${YELLOW}⚠️ VERIFICATION COMPLETED WITH WARNINGS ⚠️${NC}" + echo "The drive might boot but some issues were detected." + echo "Consider running the boot repair script before attempting to boot." + echo + echo "Run: ./boot_repair_tools.sh" + else + echo -e "${RED}❌ VERIFICATION FAILED ❌${NC}" + echo "The drive is unlikely to boot properly in its current state." + echo "Please run the boot repair script to fix issues." + echo + echo "Run: ./boot_repair_tools.sh" + fi + + cleanup_verification + exit $exit_code + fi +} + +# Trap to ensure cleanup on exit +trap cleanup_verification EXIT + +main "$@" \ No newline at end of file diff --git a/plug_and_play_backup.sh b/plug_and_play_backup.sh deleted file mode 100755 index c3b124d..0000000 --- a/plug_and_play_backup.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/bash -# Create PLUG-AND-PLAY Clonezilla USB - No commands to remember! - -set -e - -USB_DRIVE="/dev/sda" -CLONEZILLA_ISO="clonezilla-live-3.1.0-22-amd64.iso" - -echo "Creating PLUG-AND-PLAY Disaster Recovery USB" -echo "============================================" -echo "• Boot USB = Automatic backup starts in 10 seconds" -echo "• No commands to remember" -echo "• 15-20 minute backup with maximum speed" -echo - -# Use existing ISO -if [[ ! -f "$CLONEZILLA_ISO" ]]; then - echo "ERROR: $CLONEZILLA_ISO not found!" - exit 1 -fi - -read -p "Continue to create plug-and-play USB? (yes/no): " confirm -if [[ "$confirm" != "yes" ]]; then - exit 1 -fi - -# Unmount and recreate USB -sudo umount "${USB_DRIVE}"* 2>/dev/null || true - -# Single partition for simplicity -sudo parted "$USB_DRIVE" --script mklabel msdos -sudo parted "$USB_DRIVE" --script mkpart primary fat32 1MiB 100% -sudo parted "$USB_DRIVE" --script set 1 boot on - -# Format -USB_PART="${USB_DRIVE}1" -sudo mkfs.fat -F32 -n "AUTOBACKUP" "$USB_PART" - -# Mount and install -USB_MOUNT="/tmp/autobackup_$$" -ISO_MOUNT="/tmp/clonezilla_iso_$$" - -sudo mkdir -p "$USB_MOUNT" "$ISO_MOUNT" -sudo mount "$USB_PART" "$USB_MOUNT" -sudo mount -o loop "$CLONEZILLA_ISO" "$ISO_MOUNT" - -echo "Installing Clonezilla..." -sudo cp -R "$ISO_MOUNT"/* "$USB_MOUNT/" - -echo "Installing GRUB..." -sudo grub-install --target=i386-pc --boot-directory="$USB_MOUNT/boot" "$USB_DRIVE" - -# Create PLUG-AND-PLAY menu -sudo tee "$USB_MOUNT/boot/grub/grub.cfg" > /dev/null << 'EOF' -set timeout=10 -set default=0 - -menuentry "🚀 AUTO BACKUP (10 second countdown)" { - linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset ocs_live_run="ocs-sr -q2 -j2 -z0 -i 0 -sfsck -scs -rescue -batch -p reboot savedisk AUTO_$(date +%Y%m%d_%H%M%S) /dev/nvme0n1" ocs_live_extra_param="" keyboard-layouts= ocs_live_batch="yes" locales= vga=normal nosplash - initrd /live/initrd.img -} - -menuentry "🔧 Manual Clonezilla (for restore)" { - linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset ocs_live_run="ocs-live-general" ocs_live_extra_param="" keyboard-layouts= ocs_live_batch="no" locales= vga=normal nosplash - initrd /live/initrd.img -} -EOF - -# Create instructions -sudo tee "$USB_MOUNT/PLUG_AND_PLAY_INSTRUCTIONS.txt" > /dev/null << 'EOF' -PLUG AND PLAY DISASTER RECOVERY USB -=================================== - -🚀 BACKUP INSTRUCTIONS: -1. Boot from this USB -2. Wait 10 seconds (auto-backup starts) -3. Wait 15-20 minutes -4. System reboots automatically - -🔧 RESTORE INSTRUCTIONS: -1. Boot from this USB -2. Select "Manual Clonezilla" -3. Choose "device-image" -> "restoredisk" -4. Find your backup image -5. Select target drive -6. Confirm and wait - -NO COMMANDS TO REMEMBER! -Just boot and wait 10 seconds. - -Backup will be saved to this USB drive. -Created: $(date) -EOF - -sudo mkdir -p "$USB_MOUNT/home/partimag" - -# Cleanup -sudo umount "$ISO_MOUNT" "$USB_MOUNT" -sudo rmdir "$USB_MOUNT" "$ISO_MOUNT" - -echo -echo "✅ PLUG-AND-PLAY USB CREATED!" -echo "✅ Boot USB = 10 second countdown then auto-backup" -echo "✅ No commands to remember in disaster recovery" -echo "✅ Maximum speed backup (15-20 minutes)" -echo "✅ Instructions stored on USB drive" -echo -echo "DISASTER RECOVERY: Just boot from USB and wait!" diff --git a/prepare_live_system.sh b/prepare_live_system.sh deleted file mode 100755 index 91ef1b9..0000000 --- a/prepare_live_system.sh +++ /dev/null @@ -1,315 +0,0 @@ -#!/bin/bash - -# Live System Preparation Script for LVM Migration -# This script prepares a live USB system with all necessary tools for LVM migration - -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 - -log() { - echo -e "${BLUE}[$(date '+%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" -} - -check_live_system() { - log "Checking if running from live system..." - - # Check multiple indicators of live system - local is_live=false - - # Check for common live system indicators - if [ -f "/etc/casper.conf" ] || [ -f "/lib/live/mount/medium" ]; then - is_live=true - fi - - # Check if root filesystem is on loop, overlay, or tmpfs - local root_device=$(df / | tail -1 | awk '{print $1}') - if [[ "$root_device" == *"loop"* ]] || [[ "$root_device" == *"overlay"* ]] || [[ "$root_device" == *"tmpfs"* ]]; then - is_live=true - fi - - # Check for live system processes - if pgrep -f "casper" >/dev/null 2>&1 || pgrep -f "live-boot" >/dev/null 2>&1; then - is_live=true - fi - - if [ "$is_live" = true ]; then - success "Confirmed: Running from live system" - else - warning "This doesn't appear to be a live system!" - echo "For safety, LVM migration should be run from a live USB system." - read -p "Continue anyway? [y/N] " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - error "Operation aborted. Please boot from a live USB system." - fi - fi -} - -update_package_lists() { - log "Updating package lists..." - - if command -v apt >/dev/null 2>&1; then - apt update || warning "Failed to update apt package lists" - elif command -v pacman >/dev/null 2>&1; then - pacman -Sy || warning "Failed to update pacman package lists" - elif command -v dnf >/dev/null 2>&1; then - dnf makecache || warning "Failed to update dnf package cache" - else - warning "Unknown package manager - manual tool installation may be required" - fi -} - -install_required_tools() { - log "Installing required tools for LVM migration..." - - # Detect distribution for package name variations - local distro="unknown" - if [ -f /etc/os-release ]; then - . /etc/os-release - distro="$ID" - log "Detected distribution: $PRETTY_NAME" - fi - - # Define package groups with alternatives for different distributions - local package_groups=( - "lvm:lvm2,lvm" - "cryptsetup:cryptsetup,cryptsetup-bin" - "rsync:rsync" - "parted:parted" - "pv:pv,pipe-viewer" - "grub-efi:grub-efi-amd64,grub-efi,grub-efi-amd64-bin" - "grub-pc:grub-pc-bin,grub-pc" - "grub-common:grub-common,grub2-common" - "e2fsprogs:e2fsprogs" - "dosfstools:dosfstools,mtools" - "util-linux:util-linux" - "coreutils:coreutils" - "bc:bc" - "initramfs:initramfs-tools,dracut" - "udev:udev,systemd-udev" - "kmod:kmod,module-init-tools" - ) - - local missing_tools=() - local packages_to_install=() - - # Check which tools are missing - for tool_spec in "${tools_to_check[@]}"; do - local tool=$(echo "$tool_spec" | cut -d: -f1) - local packages=$(echo "$tool_spec" | cut -d: -f2) - - if ! command -v "$tool" >/dev/null 2>&1; then - missing_tools+=("$tool") - # Add packages (handle comma-separated list) - IFS=',' read -ra PKGS <<< "$packages" - for pkg in "${PKGS[@]}"; do - if [[ ! " ${packages_to_install[@]} " =~ " ${pkg} " ]]; then - packages_to_install+=("$pkg") - fi - done - fi - done - - if [ ${#missing_tools[@]} -eq 0 ]; then - success "All required tools are already available" - return - fi - - echo "Missing tools: ${missing_tools[*]}" - echo "Will attempt to install: ${packages_to_install[*]}" - - # Install packages based on available package manager - if command -v apt >/dev/null 2>&1; then - log "Installing packages with apt..." - - # Update package lists first - apt update || warning "Failed to update package lists" - - # Function to try installing packages with alternatives - try_install() { - local desc="$1" - local packages_str="$2" - IFS=',' read -ra packages <<< "$packages_str" - - log "Installing $desc..." - for pkg in "${packages[@]}"; do - if apt install -y "$pkg" >/dev/null 2>&1; then - success "Installed $pkg for $desc" - return 0 - fi - done - warning "Failed to install any package for $desc (tried: ${packages_str//,/, })" - return 1 - } - - # Install packages by groups - for group in "${package_groups[@]}"; do - local desc="${group%:*}" - local packages="${group#*:}" - try_install "$desc" "$packages" - done - elif command -v pacman >/dev/null 2>&1; then - log "Installing packages with pacman..." - pacman -S --noconfirm "${packages_to_install[@]}" || { - warning "Some packages failed to install via pacman" - } - elif command -v dnf >/dev/null 2>&1; then - log "Installing packages with dnf..." - dnf install -y "${packages_to_install[@]}" || { - warning "Some packages failed to install via dnf" - } - else - warning "Unknown package manager. Please install these packages manually:" - echo " ${packages_to_install[*]}" - fi - - # Verify installation - local still_missing=() - for tool_spec in "${tools_to_check[@]}"; do - local tool=$(echo "$tool_spec" | cut -d: -f1) - if ! command -v "$tool" >/dev/null 2>&1; then - still_missing+=("$tool") - fi - done - - if [ ${#still_missing[@]} -eq 0 ]; then - success "All required tools are now available" - else - error "Still missing tools: ${still_missing[*]}. Please install them manually." - fi -} - -enable_lvm_kernel_modules() { - log "Enabling LVM kernel modules..." - - local modules=("dm_mod" "dm_crypt" "dm_snapshot") - - for module in "${modules[@]}"; do - if ! lsmod | grep -q "^$module"; then - log "Loading kernel module: $module" - modprobe "$module" || warning "Failed to load $module module" - else - log "Module $module already loaded" - fi - done - - # Start LVM services if available - if command -v systemctl >/dev/null 2>&1; then - systemctl start lvm2-monitor 2>/dev/null || true - systemctl start lvm2-lvmetad 2>/dev/null || true - fi - - success "LVM kernel modules enabled" -} - -check_drive_availability() { - log "Checking for available drives..." - - # List all available block devices - echo "Available drives:" - lsblk -dpno NAME,SIZE,MODEL,VENDOR | grep -E "sd[a-z]|nvme[0-9]|mmcblk[0-9]" | while read line; do - echo " $line" - done - - # Count drives - local drive_count=$(lsblk -dpno NAME | grep -E "sd[a-z]|nvme[0-9]|mmcblk[0-9]" | wc -l) - - if [ "$drive_count" -lt 2 ]; then - warning "Only $drive_count drive(s) detected. Migration requires at least 2 drives:" - echo " 1. Internal drive (source)" - echo " 2. External M.2 SSD (target)" - echo - echo "Please connect your external M.2 SSD and try again." - exit 1 - else - success "Found $drive_count drives - sufficient for migration" - fi -} - -create_migration_workspace() { - log "Creating migration workspace..." - - local workspace="/tmp/lvm-migration" - mkdir -p "$workspace"/{scripts,logs,mounts} - - # Copy migration script to workspace if it exists - if [ -f "./migrate_to_lvm.sh" ]; then - cp "./migrate_to_lvm.sh" "$workspace/scripts/" - chmod +x "$workspace/scripts/migrate_to_lvm.sh" - success "Migration script copied to workspace" - fi - - # Create useful aliases - cat > "$workspace/aliases.sh" << 'EOF' -#!/bin/bash -# Useful aliases for LVM migration - -alias ll='ls -la' -alias drives='lsblk -dpno NAME,SIZE,MODEL,VENDOR' -alias mounts='mount | grep -E "sd[a-z]|nvme|loop|mapper"' -alias lvminfo='pvs && vgs && lvs' -alias migration='cd /tmp/lvm-migration && ls -la' - -echo "Migration workspace aliases loaded:" -echo " drives - List all available drives" -echo " mounts - Show mounted filesystems" -echo " lvminfo - Display LVM information" -echo " migration - Go to migration workspace" -EOF - - success "Migration workspace created at $workspace" - echo "To load helpful aliases: source $workspace/aliases.sh" -} - -main() { - echo -e "${GREEN}=== Live System Preparation for LVM Migration ===${NC}" - echo "This script prepares your live USB system for LVM migration" - echo - - # Check if running as root - if [ "$EUID" -ne 0 ]; then - error "This script must be run as root. Use: sudo $0" - fi - - check_live_system - update_package_lists - install_required_tools - enable_lvm_kernel_modules - check_drive_availability - create_migration_workspace - - success "Live system preparation completed!" - echo - echo -e "${GREEN}Next steps:${NC}" - echo "1. Connect your external M.2 SSD if not already connected" - echo "2. Run the LVM migration script:" - echo " sudo ./migrate_to_lvm.sh" - echo "3. Follow the interactive prompts to complete migration" - echo - echo -e "${YELLOW}Important reminders:${NC}" - echo "• Ensure your external M.2 SSD is large enough for your system" - echo "• The migration will DESTROY all data on the target drive" - echo "• Your original internal drive will remain unchanged as backup" - echo "• After migration, update BIOS boot order to boot from external drive" -} - -main "$@" \ No newline at end of file diff --git a/restore_tools_after_backup.sh b/restore_tools_after_backup.sh deleted file mode 100755 index 604456e..0000000 --- a/restore_tools_after_backup.sh +++ /dev/null @@ -1,271 +0,0 @@ -#!/bin/bash -# Restore backup tools after cloning operation -# This script runs automatically after backup to preserve tools on external drive - -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}[$(date '+%H:%M:%S')]${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" -} - -# Get the external drive from parameter or auto-detect -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 - print_error "Could not detect external drive" - exit 1 -fi - -print_status "Restoring backup tools to $EXTERNAL_DRIVE" - -# Find the tools partition (look for BACKUP_TOOLS label first) -TOOLS_PARTITION=$(blkid -L "BACKUP_TOOLS" 2>/dev/null || echo "") - -# If not found by label, try to find the last partition on the external drive -if [[ -z "$TOOLS_PARTITION" ]]; then - # Get all partitions on the external drive - mapfile -t partitions < <(lsblk -n -o NAME "$EXTERNAL_DRIVE" | grep -v "^$(basename "$EXTERNAL_DRIVE")$") - - if [[ ${#partitions[@]} -gt 0 ]]; then - # Check the last partition - last_partition="/dev/${partitions[-1]}" - - # Check if it's small (likely our tools partition) - partition_size=$(lsblk -n -o SIZE "$last_partition" | tr -d ' ') - if [[ "$partition_size" == *M ]] && [[ ${partition_size%M} -le 1024 ]]; then - TOOLS_PARTITION="$last_partition" - print_status "Found potential tools partition: $TOOLS_PARTITION ($partition_size)" - fi - fi -fi - -# If still no tools partition found, create one -if [[ -z "$TOOLS_PARTITION" ]]; then - print_warning "No tools partition found. Creating one..." - - # Create 512MB partition at the end - if command -v parted >/dev/null 2>&1; then - parted "$EXTERNAL_DRIVE" --script mkpart primary ext4 -512MiB 100% || { - print_warning "Could not create partition. Backup tools will not be preserved." - exit 0 - } - - # Wait for partition to appear - sleep 2 - - # Get the new partition - mapfile -t partitions < <(lsblk -n -o NAME "$EXTERNAL_DRIVE" | grep -v "^$(basename "$EXTERNAL_DRIVE")$") - TOOLS_PARTITION="/dev/${partitions[-1]}" - - # Format it - mkfs.ext4 -L "BACKUP_TOOLS" "$TOOLS_PARTITION" -F >/dev/null 2>&1 || { - print_warning "Could not format tools partition" - exit 0 - } - - print_success "Created tools partition: $TOOLS_PARTITION" - else - print_warning "parted not available. Cannot create tools partition." - exit 0 - fi -fi - -# Mount tools partition -MOUNT_POINT="/tmp/backup_tools_restore_$$" -mkdir -p "$MOUNT_POINT" - -mount "$TOOLS_PARTITION" "$MOUNT_POINT" 2>/dev/null || { - print_error "Could not mount tools partition $TOOLS_PARTITION" - rmdir "$MOUNT_POINT" - exit 1 -} - -# Ensure we unmount on exit -trap 'umount "$MOUNT_POINT" 2>/dev/null; rmdir "$MOUNT_POINT" 2>/dev/null' EXIT - -# Get the directory where this script is located (source of backup tools) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Install/update backup tools -if [[ -d "$MOUNT_POINT/backup_system" ]]; then - print_status "Updating existing backup tools..." - # Sync changes, excluding git and cache files - rsync -av --delete --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' \ - "$SCRIPT_DIR/" "$MOUNT_POINT/backup_system/" -else - print_status "Installing backup tools for first time..." - mkdir -p "$MOUNT_POINT/backup_system" - cp -r "$SCRIPT_DIR"/* "$MOUNT_POINT/backup_system/" -fi - -# Create portable launcher if it doesn't exist -if [[ ! -f "$MOUNT_POINT/backup_system/launch_backup_tools.sh" ]]; then - cat > "$MOUNT_POINT/backup_system/launch_backup_tools.sh" << '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 - -echo "==========================================" -echo " Portable Backup Tools" -echo "==========================================" -echo "" -echo "Available options:" -echo "1. Launch GUI Backup Manager" -echo "2. Command Line Backup" -echo "3. Command Line Restore" -echo "4. List Available Drives" -echo "5. Create Desktop Entry" -echo "" - -# Check if GUI is available -if [[ -n "$DISPLAY" ]] && command -v python3 >/dev/null 2>&1; then - read -p "Select option (1-5): " choice - case $choice in - 1) - echo "Launching GUI Backup Manager..." - python3 backup_manager.py - ;; - 2) - echo "Starting command line backup..." - ./backup_script.sh - ;; - 3) - echo "Starting command line restore..." - ./backup_script.sh --restore - ;; - 4) - echo "Available drives:" - ./backup_script.sh --list - ;; - 5) - ./create_desktop_entry.sh - ;; - *) - echo "Invalid option" - ;; - esac -else - echo "GUI not available. Use command line options:" - ./backup_script.sh --help -fi -EOF -fi - -# Create desktop entry creator -cat > "$MOUNT_POINT/backup_system/create_desktop_entry.sh" << 'EOF' -#!/bin/bash -# Create desktop entry for portable backup tools - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -DESKTOP_DIR="$HOME/Desktop" -APPLICATIONS_DIR="$HOME/.local/share/applications" - -mkdir -p "$APPLICATIONS_DIR" - -# Create application entry -cat > "$APPLICATIONS_DIR/portable-backup.desktop" << EOL -[Desktop Entry] -Version=1.0 -Type=Application -Name=Portable Backup Manager -Comment=Boot from external drive and restore to internal -Exec=python3 "$SCRIPT_DIR/backup_manager.py" -Icon=drive-harddisk -Terminal=false -Categories=System;Utility; -StartupNotify=true -EOL - -# Create desktop shortcut -if [[ -d "$DESKTOP_DIR" ]]; then - cp "$APPLICATIONS_DIR/portable-backup.desktop" "$DESKTOP_DIR/" - chmod +x "$DESKTOP_DIR/portable-backup.desktop" - echo "Desktop shortcut created: $DESKTOP_DIR/portable-backup.desktop" -fi - -echo "Application entry created: $APPLICATIONS_DIR/portable-backup.desktop" -EOF - -# Make all scripts executable -chmod +x "$MOUNT_POINT/backup_system"/*.sh -chmod +x "$MOUNT_POINT/backup_system"/*.py - -# Create a README for the external drive -cat > "$MOUNT_POINT/backup_system/README_EXTERNAL.md" << 'EOF' -# Portable Backup Tools - -This external drive contains both: -1. **Your system backup** (main partitions) -2. **Backup tools** (this partition) - -## When Booted From This External Drive: - -### Quick Start: -```bash -# Mount tools and launch -sudo mkdir -p /mnt/tools -sudo mount LABEL=BACKUP_TOOLS /mnt/tools -cd /mnt/tools/backup_system -./launch_backup_tools.sh -``` - -### Or Create Desktop Entry: -```bash -cd /mnt/tools/backup_system -./create_desktop_entry.sh -``` - -## Common Operations: - -### Restore Internal Drive: -1. Boot from this external drive -2. Launch backup tools -3. Select "Restore from External" -4. Choose external → internal -5. Click "Reboot & Restore" - -### Update Backup: -1. Boot normally from internal drive -2. Connect this external drive -3. Run backup as usual -4. Tools will be automatically preserved - -## Drive Layout: -- Partition 1-2: System backup (bootable) -- Last Partition: Backup tools (this) -EOF - -print_success "Backup tools preserved on external drive" -print_status "Tools available at: $TOOLS_PARTITION" -print_status "To access when booted from external: mount LABEL=BACKUP_TOOLS /mnt/tools" - -exit 0 diff --git a/setup_portable_tools.sh b/setup_portable_tools.sh deleted file mode 100755 index 00b7efb..0000000 --- a/setup_portable_tools.sh +++ /dev/null @@ -1,368 +0,0 @@ -#!/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 "$@" diff --git a/simple_auto_backup.sh b/simple_auto_backup.sh deleted file mode 100755 index c20d6fd..0000000 --- a/simple_auto_backup.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Simple launcher script for automated backup from within Clonezilla - -echo "===================================" -echo " AUTOMATED SYSTEM BACKUP LAUNCHER" -echo "===================================" -echo -echo "This script will:" -echo "1. Auto-detect your internal drive" -echo "2. Create a high-speed backup to this USB" -echo "3. Complete in ~15-20 minutes" -echo -read -p "Press Enter to start automatic backup (Ctrl+C to cancel)..." - -# Mount backup partition -mkdir -p /tmp/backup_storage -mount /dev/sda2 /tmp/backup_storage 2>/dev/null - -if [[ -f /tmp/backup_storage/automated_clonezilla_backup.sh ]]; then - echo "Starting automated backup script..." - /tmp/backup_storage/automated_clonezilla_backup.sh -else - echo "ERROR: Automated backup script not found!" - echo "Falling back to manual Clonezilla..." - sleep 3 - sudo /usr/sbin/ocs-live-general -fi diff --git a/troubleshoot_migration.sh b/troubleshoot_migration.sh deleted file mode 100755 index 9532bc5..0000000 --- a/troubleshoot_migration.sh +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash - -# LVM Migration Troubleshooting Script -# Helps diagnose issues with the migration process - -set -e - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1"; } -error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } -success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } -warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } - -echo -e "${GREEN}=== LVM Migration Troubleshooting ===${NC}" -echo - -# Check basic system requirements -check_system() { - log "Checking system requirements..." - - # Check if running as root - if [ "$EUID" -ne 0 ]; then - error "This script must be run as root. Use: sudo $0" - return 1 - fi - - # Check if running from live system - local root_device=$(df / | tail -1 | awk '{print $1}') - if [[ "$root_device" == *"loop"* ]] || [[ "$root_device" == *"overlay"* ]] || [[ "$root_device" == *"tmpfs"* ]]; then - success "Running from live system" - else - warning "Not running from live system - migration may fail" - fi - - # Check available tools - local tools=("lvm" "cryptsetup" "rsync" "parted" "pv" "grub-install" "mkfs.ext4" "mkfs.fat" "bc" "wipefs") - local missing=() - - for tool in "${tools[@]}"; do - if command -v "$tool" >/dev/null 2>&1; then - success "Tool available: $tool" - else - missing+=("$tool") - fi - done - - if [ ${#missing[@]} -gt 0 ]; then - error "Missing tools: ${missing[*]}" - echo "Run: sudo ./emergency_install.sh to install missing packages" - return 1 - fi -} - -# Check drives -check_drives() { - log "Checking available drives..." - - echo "All block devices:" - lsblk -dpno NAME,SIZE,MODEL,VENDOR - echo - - # Look for likely candidates - local internal_drives=($(lsblk -dpno NAME | grep -E "nvme|sda")) - local usb_drives=() - - # Check for USB drives - for drive in $(lsblk -dpno NAME); do - if udevadm info --query=property --name="$drive" | grep -q "ID_BUS=usb"; then - usb_drives+=("$drive") - fi - done - - echo "Likely internal drives:" - for drive in "${internal_drives[@]}"; do - local info=$(lsblk -dpno NAME,SIZE,MODEL "$drive") - echo " $info" - done - - echo "USB drives (external/migration stick):" - for drive in "${usb_drives[@]}"; do - local info=$(lsblk -dpno NAME,SIZE,MODEL "$drive") - echo " $info" - done -} - -# Check LVM status -check_lvm() { - log "Checking LVM status..." - - echo "Physical volumes:" - pvs 2>/dev/null || echo "No physical volumes found" - - echo "Volume groups:" - vgs 2>/dev/null || echo "No volume groups found" - - echo "Logical volumes:" - lvs 2>/dev/null || echo "No logical volumes found" - - # Check for existing system-vg - if vgs system-vg 2>/dev/null; then - warning "system-vg already exists - migration may have partially completed" - echo "To restart migration, you may need to:" - echo " vgremove -f system-vg" - echo " pvremove /dev/sdaX" - fi -} - -# Check filesystem space and usage -check_filesystems() { - log "Checking current filesystem usage..." - - echo "Current mounts and usage:" - df -h | grep -E "/$|/home$|/boot$" - - echo - echo "System memory:" - free -h -} - -# Test LVM commands -test_lvm_commands() { - log "Testing LVM command availability..." - - # Test basic LVM commands - lvm version || error "LVM not working" - - # Test if we can create a test PV (on a loop device) - log "Testing LVM functionality with loop device..." - - # Create a small test file - dd if=/dev/zero of=/tmp/lvm-test.img bs=1M count=100 2>/dev/null - local loop_device=$(losetup -f --show /tmp/lvm-test.img) - - if pvcreate "$loop_device" 2>/dev/null; then - success "LVM pvcreate works" - - if vgcreate test-vg "$loop_device" 2>/dev/null; then - success "LVM vgcreate works" - - if lvcreate -L 50M -n test-lv test-vg 2>/dev/null; then - success "LVM lvcreate works" - success "All LVM commands working correctly" - else - error "LVM lvcreate failed" - fi - - # Cleanup - lvremove -f test-vg/test-lv 2>/dev/null || true - vgremove -f test-vg 2>/dev/null || true - else - error "LVM vgcreate failed" - fi - - pvremove -f "$loop_device" 2>/dev/null || true - else - error "LVM pvcreate failed" - fi - - # Cleanup - losetup -d "$loop_device" 2>/dev/null || true - rm -f /tmp/lvm-test.img -} - -# Generate report -generate_report() { - echo - echo -e "${BLUE}=== Troubleshooting Report ===${NC}" - echo "Generated: $(date)" - echo "System: $(hostname)" - - if check_system && check_drives && check_lvm && check_filesystems && test_lvm_commands; then - echo - success "All checks passed - system should be ready for migration" - echo - echo "To run migration:" - echo "1. sudo ./migrate_to_lvm.sh" - echo "2. Follow the interactive prompts" - echo "3. Carefully select source and target drives" - else - echo - error "Some checks failed - see messages above" - echo - echo "Common solutions:" - echo "• Run: sudo ./emergency_install.sh (for missing packages)" - echo "• Reboot from live USB (if not in live system)" - echo "• Check drive connections (if drives not detected)" - echo "• Remove existing LVM setup (if system-vg exists)" - fi -} - -# Main execution -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - generate_report -fi \ No newline at end of file diff --git a/validate_lvm_migration.sh b/validate_lvm_migration.sh deleted file mode 100755 index fc999e8..0000000 --- a/validate_lvm_migration.sh +++ /dev/null @@ -1,265 +0,0 @@ -#!/bin/bash - -# LVM Migration Validation Script -# Comprehensive validation that the migration from non-LVM to LVM was successful - -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 - -# Configuration -VG_NAME="system-vg" -EXTERNAL_DRIVE="/dev/sda" -EXPECTED_LVS=("root" "home" "boot" "swap") -VALIDATION_LOG="/var/log/lvm-migration-validation.log" - -log() { - local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1" - echo -e "${BLUE}$message${NC}" - echo "$message" >> "$VALIDATION_LOG" 2>/dev/null || true -} - -error() { - local message="[ERROR] $1" - echo -e "${RED}$message${NC}" >&2 - echo "$message" >> "$VALIDATION_LOG" 2>/dev/null || true -} - -warning() { - local message="[WARNING] $1" - echo -e "${YELLOW}$message${NC}" - echo "$message" >> "$VALIDATION_LOG" 2>/dev/null || true -} - -success() { - local message="[SUCCESS] $1" - echo -e "${GREEN}$message${NC}" - echo "$message" >> "$VALIDATION_LOG" 2>/dev/null || true -} - -check_lvm_volumes() { - log "Checking LVM volumes..." - - if ! vgs "$VG_NAME" >/dev/null 2>&1; then - error "Volume group $VG_NAME not found" - return 1 - fi - - local expected_lvs=("root" "home" "swap" "boot") - for lv in "${expected_lvs[@]}"; do - if ! lvs "$VG_NAME/$lv" >/dev/null 2>&1; then - error "Logical volume $VG_NAME/$lv not found" - return 1 - else - success "Found logical volume: $VG_NAME/$lv" - fi - done -} - -check_filesystems() { - log "Checking filesystems..." - - local volumes=("root" "home" "boot") - for vol in "${volumes[@]}"; do - local device="/dev/$VG_NAME/$vol" - if fsck.ext4 -n "$device" >/dev/null 2>&1; then - success "Filesystem on $device is clean" - else - error "Filesystem on $device has errors" - return 1 - fi - done - - # Check EFI partition - if fsck.fat -v "${EXTERNAL_DRIVE}1" >/dev/null 2>&1; then - success "EFI filesystem is clean" - else - warning "EFI filesystem check failed (this might be normal)" - fi -} - -check_boot_files() { - log "Checking boot files..." - - local mount_point="/mnt/validation_check" - mkdir -p "$mount_point" - - # Check root partition for essential directories - mount "/dev/$VG_NAME/root" "$mount_point" - - local essential_dirs=("/bin" "/sbin" "/etc" "/usr" "/var") - for dir in "${essential_dirs[@]}"; do - if [ -d "$mount_point$dir" ]; then - success "Found essential directory: $dir" - else - error "Missing essential directory: $dir" - umount "$mount_point" - return 1 - fi - done - - # Check for key system files - local key_files=("/etc/fstab" "/etc/passwd" "/etc/group") - for file in "${key_files[@]}"; do - if [ -f "$mount_point$file" ]; then - success "Found key system file: $file" - else - error "Missing key system file: $file" - umount "$mount_point" - return 1 - fi - done - - umount "$mount_point" -} - -check_grub_installation() { - log "Checking GRUB installation..." - - local efi_mount="/mnt/efi_check" - mkdir -p "$efi_mount" - mount "${EXTERNAL_DRIVE}1" "$efi_mount" - - if [ -d "$efi_mount/EFI/debian" ]; then - success "GRUB EFI installation found" - else - error "GRUB EFI installation not found" - umount "$efi_mount" - return 1 - fi - - if [ -f "$efi_mount/EFI/debian/grubx64.efi" ]; then - success "GRUB EFI binary found" - else - error "GRUB EFI binary not found" - umount "$efi_mount" - return 1 - fi - - umount "$efi_mount" -} - -check_fstab() { - log "Checking /etc/fstab configuration..." - - local mount_point="/mnt/fstab_check" - mkdir -p "$mount_point" - mount "/dev/$VG_NAME/root" "$mount_point" - - if [ -f "$mount_point/etc/fstab" ]; then - success "Found /etc/fstab" - - # Check if fstab contains LVM UUIDs - local root_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/root") - local home_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/home") - local boot_uuid=$(blkid -s UUID -o value "/dev/$VG_NAME/boot") - - if grep -q "$root_uuid" "$mount_point/etc/fstab"; then - success "Root UUID found in fstab" - else - error "Root UUID not found in fstab" - fi - - if grep -q "$home_uuid" "$mount_point/etc/fstab"; then - success "Home UUID found in fstab" - else - error "Home UUID not found in fstab" - fi - - if grep -q "$boot_uuid" "$mount_point/etc/fstab"; then - success "Boot UUID found in fstab" - else - error "Boot UUID not found in fstab" - fi - else - error "/etc/fstab not found" - fi - - umount "$mount_point" -} - -check_snapshot_capability() { - log "Checking LVM snapshot capability..." - - # Check free space for snapshots - local vg_free=$(vgs --noheadings -o vg_free --units g "$VG_NAME" | tr -d ' G') - local vg_free_int=${vg_free%.*} - - if [ "$vg_free_int" -ge 20 ]; then - success "Sufficient free space for snapshots: ${vg_free}G available" - else - warning "Limited free space for snapshots: ${vg_free}G available (recommend 20G+)" - fi - - # Test snapshot creation and removal - log "Testing snapshot creation..." - if lvcreate -L 1G -s -n test-snapshot "/dev/$VG_NAME/root" >/dev/null 2>&1; then - success "Snapshot creation test successful" - if lvremove -f "/dev/$VG_NAME/test-snapshot" >/dev/null 2>&1; then - success "Snapshot removal test successful" - else - error "Snapshot removal test failed" - fi - else - error "Snapshot creation test failed" - return 1 - fi -} - -check_lvm_tools() { - log "Checking for LVM snapshot script..." - - local mount_point="/mnt/script_check" - mkdir -p "$mount_point" - mount "/dev/$VG_NAME/root" "$mount_point" - - if [ -f "$mount_point/usr/local/bin/lvm-snapshot-backup.sh" ]; then - success "LVM snapshot backup script found" - if [ -x "$mount_point/usr/local/bin/lvm-snapshot-backup.sh" ]; then - success "LVM snapshot backup script is executable" - else - error "LVM snapshot backup script is not executable" - fi - else - error "LVM snapshot backup script not found" - fi - - umount "$mount_point" -} - -main() { - echo -e "${GREEN}=== LVM Migration Validation ===${NC}" - echo "Validating the migrated LVM system..." - echo - - local failed_checks=0 - - check_lvm_volumes || ((failed_checks++)) - check_filesystems || ((failed_checks++)) - check_boot_files || ((failed_checks++)) - check_grub_installation || ((failed_checks++)) - check_fstab || ((failed_checks++)) - check_snapshot_capability || ((failed_checks++)) - check_lvm_tools || ((failed_checks++)) - - echo - if [ $failed_checks -eq 0 ]; then - success "All validation checks passed!" - echo -e "${GREEN}The migration appears to be successful.${NC}" - echo "You can now:" - echo "1. Update BIOS/UEFI boot order to boot from external M.2" - echo "2. Test booting from the external drive" - echo "3. Use 'lvm-snapshot-backup.sh backup' for backups" - else - error "$failed_checks validation check(s) failed!" - echo -e "${RED}The migration may have issues. Review the errors above.${NC}" - return 1 - fi -} - -main "$@" \ No newline at end of file