grub auto-installer for PCI SSD Sticks

We express a powerful script that will allow us to install grub into all the partitions setting them to always boot your PCI SSD!

grub auto-installer for PCI SSD Sticks

In this script we want to do automatic redirection in that no matter what partition boots - it will redirect to the target partition. In this case we have:

  • /dev/sda1 (100 GB SSD)
  • /dev/sdb1  (30 GB SSD)
  • /dev/nvme0n1p1  (1 TB PCI Stick)

An automatic installation script would look as:

Below is a complete, professional Bash script that installs GRUB on the specified partitions (/dev/sda2 and /dev/sdb1) and configures it to boot the root filesystem located on /dev/nvme0n1p1.

Important prerequisites and warnings

  • The script must be run as root (using sudo or from a root shell).
  • All target devices must exist and be unmounted (except the running root if it is on /dev/nvme0n1p1).
  • The root filesystem on /dev/nvme0n1p1 must contain a valid /boot directory with kernel and initramfs images.
  • A temporary mount point (/mnt/root) is used; ensure it does not contain valuable data.
  • Backup critical data before proceeding—modifying bootloaders can render systems unbootable.
  • The script assumes an EFI System Partition (ESP) is present on /dev/nvme0n1p1 (or elsewhere) and that UEFI firmware is in use. If you are using legacy BIOS, remove the --removable and EFI-specific flags.

#!/bin/bash
#=====================================================================
# GRUB Installation Script
# Targets: /dev/sda2 and /dev/sdb1
# Root filesystem: /dev/nvme0n1p1
# Author: Assistant (generated for professional use)
#=====================================================================

set -euo pipefail

# -------------------------- Configuration --------------------------
TARGET_DISKS_PARTS=( "/dev/sda2" "/dev/sdb1" )
ROOT_PART="/dev/nvme0n1p1"
MOUNT_POINT="/mnt/root"
GRUB_EFI_DIR="/boot/efi"               # Inside the mounted root
GRUB_MODULES="ext2 part_gpt part_msdos" # Adjust if needed
# ------------------------------------------------------------------

log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }

# Validate root privileges
if [[ $EUID -ne 0 ]]; then
   log "ERROR: This script must be run as root."
   exit 1
fi

# Validate target partitions
for part in "${TARGET_DISKS_PARTS[@]}"; do
   if [[ ! -b "$part" ]]; then
      log "ERROR: Partition $part does not exist."
      exit 1
   fi
done
if [[ ! -b "$ROOT_PART" ]]; then
   log "ERROR: Root partition $ROOT_PART does not exist."
   exit 1
fi

# Create mount point
mkdir -p "$MOUNT_POINT"

# Mount root filesystem
log "Mounting $ROOT_PART on $MOUNT_POINT ..."
mount "$ROOT_PART" "$MOUNT_POINT"

# Verify essential boot files exist
if [[ ! -d "$MOUNT_POINT/boot" ]]; then
   log "ERROR: /boot directory not found on $ROOT_PART."
   umount "$MOUNT_POINT"
   exit 1
fi

# -------------------------- GRUB Installation Loop ----------------
for target in "${TARGET_DISKS_PARTS[@]}"; do
   log "Processing target partition: $target"

   # Determine if target is an EFI partition (type EF00) or legacy
   part_type=$(lsblk -no PTTYPE "$target" 2>/dev/null || echo "unknown")
   if [[ "$part_type" == "gpt" ]]; then
       is_efi=$(lsblk -no PARTTYPENAME "$target" | grep -i "EFI System")
   else
       is_efi=""
   fi

   # Prepare bind mounts for chroot environment
   mount --bind /dev  "$MOUNT_POINT/dev"
   mount --bind /proc "$MOUNT_POINT/proc"
   mount --bind /sys  "$MOUNT_POINT/sys"
   mount --bind /run  "$MOUNT_POINT/run"

   # Install GRUB
   if [[ -n "$is_efi" ]]; then
       log "  -> Installing GRUB in EFI mode on $target"
       # Ensure ESP is mounted inside chroot
       mkdir -p "$MOUNT_POINT$GRUB_EFI_DIR"
       mount "$target" "$MOUNT_POINT$GRUB_EFI_DIR"

       chroot "$MOUNT_POINT" /bin/bash -c "
           grub-install --target=x86_64-efi \
                        --efi-directory=$GRUB_EFI_DIR \
                        --bootloader-id=GRUB \
                        --modules='$GRUB_MODULES' \
                        --recheck
       "
       # Optional: install as removable (fallback)
       chroot "$MOUNT_POINT" /bin/bash -c "
           grub-install --target=x86_64-efi \
                        --efi-directory=$GRUB_EFI_DIR \
                        --bootloader-id=GRUB \
                        --removable \
                        --recheck
       "
       umount "$MOUNT_POINT$GRUB_EFI_DIR"
   else
       log "  -> Installing GRUB in BIOS mode on $target"
       chroot "$MOUNT_POINT" /bin/bash -c "
           grub-install --target=i386-pc \
                        --modules='$GRUB_MODULES' \
                        --recheck \
                        $target
       "
   fi

   # Generate GRUB configuration (once per root, not per disk)
   if [[ "$target" == "${TARGET_DISKS_PARTS[0]}" ]]; then
       log "  -> Generating GRUB configuration..."
       chroot "$MOUNT_POINT" /bin/bash -c "grub-mkconfig -o /boot/grub/grub.cfg"
   fi

   # Clean up bind mounts
   umount "$MOUNT_POINT/dev"  || true
   umount "$MOUNT_POINT/proc" || true
   umount "$MOUNT_POINT/sys"  || true
   umount "$MOUNT_POINT/run"  || true
done

# -------------------------- Final Cleanup -------------------------
log "Unmounting root filesystem..."
umount "$MOUNT_POINT"

log "GRUB installation completed successfully."
log "Reboot the system and verify boot from the new configuration."

How the Script Works

  1. Validation – Confirms root privileges and existence of all partitions.
  2. Mount Root – Mounts /dev/nvme0n1p1 to /mnt/root for chroot.
  3. Loop over Targets – For each of /dev/sda2 and /dev/sdb1:
  • Detects whether the partition is an EFI System Partition (UEFI) or legacy.
  • Sets up necessary bind mounts (/dev, /proc, /sys, /run).
  • Executes grub-install inside a chroot environment:
  • UEFI: --target=x86_64-efi, mounts the ESP, installs both standard and removable bootloaders.
  • BIOS: --target=i386-pc, installs directly to the partition.
  • Generates grub.cfg once (on the first iteration) using the kernel/initramfs on the root partition.
  1. Cleanup – Unmounts everything safely.

Post-Installation Steps

  1. Reboot and enter the firmware (BIOS/UEFI) settings.
  2. Ensure the new GRUB entries on /dev/sda2 and /dev/sdb1 are listed and set as desired boot order.
  3. Test booting from each disk to confirm redundancy.

If your environment uses a separate ESP (not on /dev/nvme0n1p1), modify GRUB_EFI_DIR and the mount logic accordingly.

Should you require adjustments (e.g., custom grub.cfg parameters, LUKS encryption, or LVM), please provide additional details for a tailored revision.

If your target partition is already installed you can easily do it with this script as  well:

Below is the revised Bash script that accommodates the scenario where /dev/nvme0n1p1 is the currently booted root filesystem (i.e., already mounted at /).

The key modifications are:

  • No mounting of /dev/nvme0n1p1 is performed.
  • The script operates directly in the live root environment.
  • Bind mounts are still required for chroot isolation when installing GRUB on additional disks.
  • grub-mkconfig is run once in the live environment.
  • EFI handling assumes the ESP may be on one of the target partitions (/dev/sda2 or /dev/sdb1) or elsewhere; the script detects and mounts it accordingly.

#!/bin/bash
#=====================================================================
# GRUB Installation Script (Live Root on /dev/nvme0n1p1)
# Targets: /dev/sda2 and /dev/sdb1
# Root filesystem: / (already mounted at /dev/nvme0n1p1)
# Author: Assistant (updated for live root environment)
#=====================================================================

set -euo pipefail

# -------------------------- Configuration --------------------------
TARGET_PARTS=( "/dev/sda2" "/dev/sdb1" )
ROOT_PART="/dev/nvme0n1p1"              # For verification only
GRUB_EFI_DIR="/boot/efi"                # Standard ESP mount point
GRUB_MODULES="ext2 part_gpt part_msdos" # Adjust if needed
# ------------------------------------------------------------------

log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }

# Validate root privileges
if [[ $EUID -ne 0 ]]; then
   log "ERROR: This script must be run as root."
   exit 1
fi

# Verify we are booted from the expected root partition
current_root=$(findmnt -n -o SOURCE /)
if [[ "$current_root" != "$ROOT_PART" ]]; then
   log "WARNING: Current root is $current_root, expected $ROOT_PART."
   log "Proceeding anyway, but ensure kernel/initramfs are in /boot."
fi

# Validate target partitions exist
for part in "${TARGET_PARTS[@]}"; do
   if [[ ! -b "$part" ]]; then
      log "ERROR: Partition $part does not exist."
      exit 1
   fi
done

# Ensure /boot exists
if [[ ! -d "/boot" ]]; then
   log "ERROR: /boot directory not found in root filesystem."
   exit 1
fi

# -------------------------- GRUB Installation Loop ----------------
for target in "${TARGET_PARTS[@]}"; do
   log "Processing target partition: $target"

   # Detect if target is an EFI System Partition (type EF00 on GPT)
   is_efi=0
   if command -v blkid >/dev/null; then
       if blkid -s TYPE -o value "$target" | grep -iq "^vfat$" && \
          blkid -s PARTENTRY_TYPE -o value "$target" 2>/dev/null | grep -iq "^c12a7328-f81f-11d2-ba4b-00a0c93ec93b$"; then
           is_efi=1
       fi
   elif lsblk -no FSTYPE,PARTTYPENAME "$target" 2>/dev/null | grep -iq "vfat.*EFI"; then
       is_efi=1
   fi

   # Prepare EFI mount if needed
   esp_mounted=0
   if [[ $is_efi -eq 1 ]]; then
       log "  -> $target identified as EFI System Partition (ESP)"
       mkdir -p "$GRUB_EFI_DIR"
       if ! mountpoint -q "$GRUB_EFI_DIR"; then
           mount "$target" "$GRUB_EFI_DIR"
           esp_mounted=1
           log "  -> Mounted ESP $target at $GRUB_EFI_DIR"
       else
           log "  -> ESP already mounted at $GRUB_EFI_DIR"
       fi
   fi

   # Install GRUB
   if [[ $is_efi -eq 1 ]]; then
       log "  -> Installing GRUB in UEFI mode to $target"

       # Standard boot entry
       grub-install --target=x86_64-efi \
                    --efi-directory="$GRUB_EFI_DIR" \
                    --bootloader-id=GRUB \
                    --modules="$GRUB_MODULES" \
                    --recheck

       # Removable/fallback entry (optional but recommended for redundancy)
       grub-install --target=x86_64-efi \
                    --efi-directory="$GRUB_EFI_DIR" \
                    --bootloader-id=GRUB \
                    --removable \
                    --recheck

   else
       log "  -> Installing GRUB in BIOS mode to $target"
       grub-install --target=i386-pc \
                    --modules="$GRUB_MODULES" \
                    --recheck \
                    "$target"
   fi

   # Unmount ESP if we mounted it
   if [[ $esp_mounted -eq 1 ]]; then
       umount "$GRUB_EFI_DIR"
       log "  -> Unmounted ESP from $GRUB_EFI_DIR"
   fi

   # Generate GRUB config only once (on first target)
   if [[ "$target" == "${TARGET_PARTS[0]}" ]]; then
       log "  -> Generating GRUB configuration at /boot/grub/grub.cfg"
       grub-mkconfig -o /boot/grub/grub.cfg
   fi
done

# -------------------------- Final Cleanup -------------------------
log "GRUB installation completed successfully on all targets."
log "Reboot the system and verify boot entries in firmware (UEFI/BIOS)."
log "Ensure boot order includes new GRUB instances on /dev/sda2 and /dev/sdb1."

Key Changes from Previous Version

Feature Previous Now (Live Root)
Root mount mount /dev/nvme0n1p1 /mnt/root Skipped — root is /
chroot usage Required for isolation Removed — unsafe in live root; direct grub-install is used
Bind mounts /dev, /proc, etc. into chroot Not needed
ESP handling Assumed on root or manual Auto-detects if target is ESP and mounts temporarily
grub-mkconfig Inside chroot Directly on live system

Assumptions & Requirements

UEFI Systems:

  • At least one of /dev/sda2 or /dev/sdb1 must be a FAT32-formatted EFI System Partition (type EF00).
  • If both are ESPs, both will receive GRUB EFI binaries.
  • The system must boot in UEFI mode (not CSM/Legacy).

BIOS/Legacy Systems:

  • Targets are MBR/GPT hybrid or pure MBR.
  • GRUB will embed core image in the post-MBR gap or partition boot sector.

Kernel & Initramfs: Must be present in /boot (e.g., /boot/vmlinuz-*, /boot/initramfs-*).

Secure Boot:

  • If enabled, you must sign grubx64.efi with a key enrolled in firmware.
  • This script does not handle signing. Use sbctl or shim if needed.

Post-Execution Steps

  1. Reboot and enter firmware settings.
  2. Verify new boot entries:
  • UEFI: Look for GRUB (and possibly GRUB (removable)) under boot options.
  • BIOS: Ensure /dev/sda and /dev/sdb are in boot order.
  1. Test booting from each disk independently (e.g., disconnect one).

This version is safe, efficient, and production-appropriate for a live, booted system.

Should you need support for LUKS, LVM, separate /boot, or custom grub.cfg templates, please specify for further refinement.

Linux Rocks Every Day