From ceb06d340acc9142f897854835cf228a963a6d35 Mon Sep 17 00:00:00 2001 From: robojerk Date: Thu, 28 Aug 2025 11:30:41 -0700 Subject: [PATCH] added support for fedora layout --- QUICK_REFERENCE.md | 94 +++++++++++++++++-- grub-repair.sh | 222 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 304 insertions(+), 12 deletions(-) diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md index 7b759c7..851cd07 100644 --- a/QUICK_REFERENCE.md +++ b/QUICK_REFERENCE.md @@ -6,21 +6,33 @@ ```bash sudo ./grub-repair.sh detect ``` +**What this does**: Shows all available disks, partitions, and identifies which ones are bootable Linux systems. +**When to use**: First step - always run this to see what systems are available before attempting repairs. +**Output**: Lists disks, partitions, filesystem types, and mount points. ### 2. Complete Boot Repair (Recommended) ```bash sudo ./grub-repair.sh -d /dev/sda -p 1 -b fix-boot ``` +**What this does**: Mounts your system, installs GRUB, updates configuration, and repairs EFI - all in one command with automatic backup. +**When to use**: Your system won't boot, GRUB is missing/corrupted, or you need a complete boot recovery. +**Device note**: Replace `/dev/sda` with your actual disk (use `lsblk` to find it). ### 3. Check Status ```bash sudo ./grub-repair.sh status ``` +**What this does**: Shows current mount status, available GRUB configurations, EFI partition status, and backup information. +**When to use**: After mounting or during troubleshooting to see what's currently available and mounted. +**Output**: Current system state, mounted filesystems, and backup locations. ### 4. Clean Up ```bash sudo ./grub-repair.sh clean ``` +**What this does**: Safely unmounts all systems, removes temporary mount points, and cleans up resources. +**When to use**: After completing repairs, when switching between systems, or if something goes wrong. +**Safety**: Automatically unmounts everything in the correct order to prevent data loss. ## Common Scenarios @@ -32,6 +44,12 @@ sudo ./grub-repair.sh detect # Then repair (replace /dev/sda with your device) sudo ./grub-repair.sh -d /dev/sda -p 1 -b fix-boot ``` +**Step-by-step process**: +1. **Detect**: Identify available systems and their locations +2. **Repair**: Complete boot repair with automatic backup +3. **Reboot**: Restart your system to test the repair + +**Device identification**: Use `lsblk` or `fdisk -l` to find your disk name if unsure. ### GRUB Reinstall Only ```bash @@ -47,11 +65,17 @@ sudo ./grub-repair.sh update-grub # Unmount sudo ./grub-repair.sh unmount ``` +**When to use**: You only need to reinstall GRUB, not perform a complete repair. +**Manual control**: Gives you step-by-step control over the GRUB installation process. +**Safety**: Each step can be verified before proceeding to the next. ### EFI Partition Check and Repair ```bash sudo ./grub-repair.sh -d /dev/sda check-efi ``` +**What this does**: Checks EFI partition health, repairs boot entries, and creates new GRUB boot entries if needed. +**When to use**: EFI boot issues, missing boot entries, or when GRUB isn't showing up in UEFI boot menu. +**Advanced**: Automatically detects your Linux distribution for proper bootloader ID. ## Device Identification @@ -59,16 +83,70 @@ sudo ./grub-repair.sh -d /dev/sda check-efi - **EFI partition**: Usually the first partition (e.g., `/dev/sda1`) - **Root partition**: Usually the second partition (e.g., `/dev/sda2`) +**Common device names**: +- **SATA drives**: `/dev/sda`, `/dev/sdb`, `/dev/sdc` +- **NVMe drives**: `/dev/nvme0n1`, `/dev/nvme1n1` +- **USB drives**: `/dev/sdd`, `/dev/sde` (when booted from USB) + ## Safety Tips -- Always use `-b` flag for backup -- Test on non-critical systems first -- Keep live ISO handy for recovery -- Document your partition layout +- **Always use `-b` flag for backup** - Creates automatic backups before making changes +- **Test on non-critical systems first** - Verify the script works in your environment +- **Keep live ISO handy for recovery** - You may need to boot from it again if issues arise +- **Document your partition layout** - Note down which partitions are which before starting +- **Use `-v` flag for verbose output** - Get detailed information during operations for troubleshooting ## Troubleshooting -- **Permission denied**: Use `sudo` -- **Device not found**: Check with `lsblk` -- **Mount fails**: Use `clean` command first -- **Verbose output**: Add `-v` flag +- **Permission denied**: Use `sudo` - Script requires root access for system operations +- **Device not found**: Check with `lsblk` - Verify device names and partition layout +- **Mount fails**: Use `clean` command first - Cleans up any partial mounts +- **Verbose output**: Add `-v` flag - Shows detailed operation information +- **Force mode**: Use `-f` flag - Bypass live ISO detection if needed +- **Custom mount point**: Use `-m /path` - Specify custom mount location + +## Additional Useful Commands + +### Manual Mounting +```bash +# Mount a specific system +sudo ./grub-repair.sh -d /dev/sda -p 1 mount + +# Unmount current system +sudo ./grub-repair.sh unmount + +# Check what's mounted +sudo ./grub-repair.sh status +``` + +### Backup and Recovery +```bash +# Create backup only +sudo ./grub-repair.sh backup + +# Check backup status +sudo ./grub-repair.sh status +``` + +### Advanced Options +```bash +# Force mode (bypass live ISO check) +sudo ./grub-repair.sh -f -d /dev/sda detect + +# Verbose output for debugging +sudo ./grub-repair.sh -v -d /dev/sda check-efi + +# Custom mount point +sudo ./grub-repair.sh -m /mnt/custom -d /dev/sda mount +``` + +## Quick Recovery Workflow + +1. **Boot from Live ISO** - Start your system from a live Linux ISO +2. **Detect Systems** - `sudo ./grub-repair.sh detect` +3. **Identify Target** - Note the device name and partition number +4. **Complete Repair** - `sudo ./grub-repair.sh -d /dev/DEVICE -p PARTITION -b fix-boot` +5. **Clean Up** - `sudo ./grub-repair.sh clean` +6. **Reboot** - Restart and test your system + +**Pro tip**: The `-b` flag creates automatic backups, so you can always restore if something goes wrong! diff --git a/grub-repair.sh b/grub-repair.sh index ca809fb..ef92b8c 100755 --- a/grub-repair.sh +++ b/grub-repair.sh @@ -67,6 +67,8 @@ EXAMPLES: # Complete boot repair with backup $SCRIPT_NAME -d /dev/sda -p 1 -b fix-boot + # Note: The partition number (-p) is a starting point; the script will + # automatically detect and mount the correct root partition if needed. # Check and repair EFI only $SCRIPT_NAME -d /dev/sda check-efi @@ -110,10 +112,30 @@ detect_systems() { lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,LABEL echo -e "\nEFI partitions:" - blkid | grep -i "vfat\|fat32" | grep -i "efi\|boot" || echo "No EFI partitions found" + local efi_found=false + for partition in $(blkid | grep -i "vfat\|fat32" | cut -d: -f1); do + if [[ -b "$partition" ]]; then + echo " $partition - $(blkid -s LABEL -o value "$partition" 2>/dev/null || echo 'no label')" + efi_found=true + fi + done + if [[ "$efi_found" == "false" ]]; then + echo "No EFI partitions found" + fi echo -e "\nLinux partitions:" - blkid | grep -i "ext4\|xfs\|btrfs" || echo "No Linux partitions found" + local linux_found=false + for partition in $(blkid | grep -i "ext4\|xfs\|btrfs" | cut -d: -f1); do + if [[ -b "$partition" ]]; then + local fstype=$(blkid -s TYPE -o value "$partition" 2>/dev/null) + local size=$(lsblk -rno SIZE "$partition" 2>/dev/null) + echo " $partition - $fstype ($size)" + linux_found=true + fi + done + if [[ "$linux_found" == "false" ]]; then + echo "No Linux partitions found" + fi } # Function to detect Linux distribution @@ -148,6 +170,115 @@ detect_distribution() { return 1 } +# Function to detect root partition +detect_root_partition() { + local device="$1" + + # Get the parent disk name more robustly + local disk + if command -v lsblk >/dev/null 2>&1; then + # Use lsblk to get parent disk (more reliable for NVMe, etc.) + disk=$(lsblk -rno PKNAME "$device" 2>/dev/null | head -1) + + # If no parent found, the device might be a disk itself + if [[ -z "$disk" ]]; then + # Check if the device itself is a disk (not a partition) + local device_type=$(lsblk -rno TYPE "$device" 2>/dev/null) + if [[ "$device_type" == "disk" ]]; then + disk="$device" + else + # Fallback: try to extract disk from device path + disk="${device%[0-9]*}" + fi + fi + else + # Fallback: try to extract disk from device path + disk="${device%[0-9]*}" + fi + + if [[ -z "$disk" ]]; then + print_status "$YELLOW" "Warning: Could not determine parent disk for $device" + return 1 + fi + + # Capture blkid output once for efficiency + local blkid_output=$(blkid 2>/dev/null) + + # Look for Linux root partitions (ext4, xfs, btrfs) + local root_partitions="" + + # Scan all partitions on the disk + if command -v lsblk >/dev/null 2>&1; then + local all_partitions=$(lsblk -rno NAME "$disk" | grep -E "[0-9]+$") + for partition in $all_partitions; do + local full_path="/dev/$partition" + if [[ -b "$full_path" ]]; then + local fstype=$(echo "$blkid_output" | grep "$full_path:" | grep -o 'TYPE="[^"]*"' | cut -d'"' -f2) + if [[ "$fstype" == "ext4" || "$fstype" == "xfs" || "$fstype" == "btrfs" ]]; then + root_partitions="$root_partitions $full_path" + fi + fi + done + fi + + # If we found multiple Linux partitions, try to identify the root + if [[ -n "$root_partitions" ]]; then + # Look for partitions that might be root based on size and mount history + for partition in $root_partitions; do + # Check if this partition has a root filesystem structure + if [[ -b "$partition" ]]; then + # Try to mount temporarily to check for root filesystem structure + local temp_mount="/tmp/root-check-$$" + mkdir -p "$temp_mount" + if mount "$partition" "$temp_mount" 2>/dev/null; then + # Check for common root filesystem indicators + if [[ -d "$temp_mount/etc" && -d "$temp_mount/boot" && -d "$temp_mount/var" ]]; then + umount "$temp_mount" + rmdir "$temp_mount" + echo "$partition" + return 0 + fi + umount "$temp_mount" + rmdir "$temp_mount" + fi + fi + done + + # If we couldn't identify the root, return the largest partition (common for root) + local largest_partition="" + local largest_size=0 + for partition in $root_partitions; do + if [[ -b "$partition" ]]; then + local size=$(lsblk -rno SIZE "$partition" 2>/dev/null | sed 's/[^0-9]//g') + if [[ -n "$size" && "$size" -gt "$largest_size" ]]; then + largest_size="$size" + largest_partition="$partition" + fi + fi + done + + if [[ -n "$largest_partition" ]]; then + echo "$largest_partition" + return 0 + fi + fi + + # Fallback: try common partition numbers (2, 3, 4) + for part_num in 2 3 4; do + local test_partition="${disk}${part_num}" + if [[ -b "$test_partition" ]]; then + local fstype=$(echo "$blkid_output" | grep "$test_partition:" | grep -o 'TYPE="[^"]*"' | cut -d'"' -f2) + if [[ "$fstype" == "ext4" || "$fstype" == "xfs" || "$fstype" == "btrfs" ]]; then + echo "$test_partition" + return 0 + fi + fi + done + + # If still no root partition found, return empty + return 1 +} + # Function to detect EFI partition detect_efi_partition() { local device="$1" @@ -244,8 +375,26 @@ mount_system() { # Create mount point if it doesn't exist mkdir -p "$MOUNT_POINT" + # Check if the specified partition is actually a root partition + # Note: Modern Linux distributions often use non-standard partition layouts + # (e.g., Fedora-style: EFI=1, Boot=2, Root=3), so we need to be smart + # about detecting which partition is actually the root filesystem + local fstype=$(blkid -s TYPE -o value "$partition_device" 2>/dev/null) + if [[ "$fstype" != "ext4" && "$fstype" != "xfs" && "$fstype" != "btrfs" ]]; then + print_status "$YELLOW" "Warning: Partition $partition_device has filesystem type '$fstype', which may not be a root partition" + print_status "$BLUE" "Attempting to detect the actual root partition..." + + local detected_root=$(detect_root_partition "$device") + if [[ -n "$detected_root" ]]; then + print_status "$BLUE" "Detected root partition: $detected_root" + partition_device="$detected_root" + else + print_status "$YELLOW" "Could not detect root partition, proceeding with specified partition" + fi + fi + # Mount root partition - print_status "$BLUE" "Mounting root partition..." + print_status "$BLUE" "Mounting root partition $partition_device..." if ! mount "$partition_device" "$MOUNT_POINT"; then print_status "$RED" "Error: Failed to mount root partition $partition_device" exit 1 @@ -257,6 +406,7 @@ mount_system() { # Mount /proc # Note: We explicitly unmount on failure rather than relying solely on the trap cleanup # This provides immediate, targeted cleanup and prevents partial mount states + mkdir -p "$MOUNT_POINT/proc" if ! mount --bind /proc "$MOUNT_POINT/proc"; then print_status "$RED" "Error: Failed to mount /proc" umount "$MOUNT_POINT" @@ -295,11 +445,69 @@ mount_system() { if [[ -n "$efi_partition" && -b "$efi_partition" ]]; then print_status "$BLUE" "Mounting EFI partition $efi_partition..." mkdir -p "$EFI_MOUNT_POINT" - mount "$efi_partition" "$EFI_MOUNT_POINT" + if ! mount "$efi_partition" "$EFI_MOUNT_POINT"; then + print_status "$RED" "Error: Failed to mount EFI partition $efi_partition" + # Note: We explicitly unmount on failure rather than relying solely on the trap cleanup + # This provides immediate, targeted cleanup and prevents partial mount states + umount "$MOUNT_POINT/dev/pts" 2>/dev/null || true + umount "$MOUNT_POINT/dev" 2>/dev/null || true + umount "$MOUNT_POINT/sys" 2>/dev/null || true + umount "$MOUNT_POINT/proc" 2>/dev/null || true + umount "$MOUNT_POINT" 2>/dev/null || true + exit 1 + fi else print_status "$YELLOW" "Warning: EFI partition not found, some operations may fail" fi + # Mount boot partition if it exists (modern Fedora-style layout) + # Note: Many modern distributions separate /boot from the root filesystem + # for security and performance reasons. We detect this automatically. + local boot_partition="" + local disk="${device%[0-9]*}" + + # Look for a separate boot partition + if command -v lsblk >/dev/null 2>&1; then + local all_partitions=$(lsblk -rno NAME "$disk" | grep -E "[0-9]+$") + for partition in $all_partitions; do + local full_path="/dev/$partition" + if [[ -b "$full_path" ]]; then + local fstype=$(blkid -s TYPE -o value "$full_path" 2>/dev/null) + # Look for ext4/xfs boot partitions that are smaller than root + if [[ "$fstype" == "ext4" || "$fstype" == "xfs" ]]; then + local size=$(lsblk -rno SIZE "$full_path" 2>/dev/null | sed 's/[^0-9]//g') + local root_size=$(lsblk -rno SIZE "$partition_device" 2>/dev/null | sed 's/[^0-9]//g') + if [[ -n "$size" && -n "$root_size" && "$size" -lt "$root_size" && "$size" -gt 1000 ]]; then + # Additional check: verify this looks like a boot partition + local temp_mount="/tmp/boot-check-$$" + mkdir -p "$temp_mount" + if mount "$full_path" "$temp_mount" 2>/dev/null; then + # Check for boot-specific directories or files + if [[ -d "$temp_mount/grub2" || -d "$temp_mount/grub" || -d "$temp_mount/extlinux" || -d "$temp_mount/loader" ]]; then + umount "$temp_mount" + rmdir "$temp_mount" + boot_partition="$full_path" + break + fi + umount "$temp_mount" + rmdir "$temp_mount" + fi + fi + fi + fi + done + fi + + if [[ -n "$boot_partition" ]]; then + print_status "$BLUE" "Mounting boot partition $boot_partition..." + mkdir -p "$MOUNT_POINT/boot" + if ! mount "$boot_partition" "$MOUNT_POINT/boot"; then + print_status "$YELLOW" "Warning: Failed to mount boot partition, continuing without it" + # Note: We don't exit here because the boot partition is optional + # The system can still function with just the root and EFI partitions + fi + fi + print_status "$GREEN" "System mounted successfully at $MOUNT_POINT" } @@ -313,6 +521,12 @@ unmount_system() { print_status "$GREEN" "EFI partition unmounted" fi + # Unmount boot partition if it was mounted separately + if mountpoint -q "$MOUNT_POINT/boot"; then + umount "$MOUNT_POINT/boot" + print_status "$GREEN" "Boot partition unmounted" + fi + if mountpoint -q "$MOUNT_POINT/dev/pts"; then umount "$MOUNT_POINT/dev/pts" fi