From 10bd148ce35fa5415b6d709e35c9f55bc25ba5e6 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Wed, 2 Jan 2013 22:08:01 -0500 Subject: [PATCH] New script to help with juggling installation locations. --- mvrefind.sh | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100755 mvrefind.sh diff --git a/mvrefind.sh b/mvrefind.sh new file mode 100755 index 0000000..bdab41a --- /dev/null +++ b/mvrefind.sh @@ -0,0 +1,275 @@ +#!/bin/bash +# +# Linux script to move an existing rEFInd installation from one directory to another +# +# Usage: +# +# ./mvrefind.sh /path/to/source /path/to/destination +# +# Typically used to "hijack" or "unhijack" a Windows boot loader location or +# to help convert a rEFInd installation made in BIOS mode to one that works +# in EFI mode. +# +# Revision history: +# +# 0.6.3 -- Initial release +# +# Note: mvrefind.sh version numbers match those of the rEFInd package +# with which they first appeared. + +RootDir="/" +SourceX64="refind_x64.efi" +TargetX64=$SourceX64 +SourceIA32="refind_ia32.efi" +TargetIA32=$SourceIA32 +SourceShim="shim.efi" +TargetShim=$SourceShim +SourceDir=${1} +TargetDir=${2} + +# Identifies the ESP's location (/boot or /boot/efi); aborts if the ESP isn't +# mounted at either location. Also splits the ESP location from SourceDir and +# TargetDir, leaving them intact but creating new EspSourceDir and EspTargetDir +# variables containing only the ESP components thereof. These new variables +# are also converted to all-lowercase and any trailing slash is stripped, to +# assist in comparisons. (This is reasonable because FAT is case-insensitive.) +# Sets InstallDir to the ESP mount point. +FindLinuxESP() { + EspLine=`df $RootDir/boot/efi 2> /dev/null | grep boot/efi` + if [[ ! -n $EspLine ]] ; then + EspLine=`df $RootDir/boot | grep boot` + fi + InstallDir=`echo $EspLine | cut -d " " -f 6` + if [[ -n $InstallDir ]] ; then + EspFilesystem=`grep $InstallDir /etc/mtab | cut -d " " -f 3` + fi + if [[ $EspFilesystem != 'vfat' ]] ; then + echo "$RootDir/boot/efi doesn't seem to be on a VFAT filesystem. The ESP must be" + echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!" + exit 1 + fi + + # Sanity check on source & target.... + EspPathLength=`expr length $InstallDir` + Temp=`echo $SourceDir | cut -c 1-$EspPathLength` + if [[ $Temp != $InstallDir ]] ; then + echo "$SourceDir isn't on the ESP ($InstallDir)! Aborting!" + exit 1 + fi + Temp=`echo $TargetDir | cut -c 1-$EspPathLength` + if [[ $Temp != $InstallDir ]] ; then + echo "$TargetDir isn't on the ESP ($InstallDir)! Aborting!" + exit 1 + fi + + # Temporarily replace "/" in pathnames with ",", so as to enable sed to + # work on them + TempInstallDir=`echo $InstallDir | tr '/' ','` + Temp=`echo $SourceDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'` + EspSourceDir=`dirname $Temp`/`basename $Temp` + Temp=`echo $TargetDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'` + EspTargetDir=`dirname $Temp`/`basename $Temp` + if [[ $EspSourceDir == $EspTargetDir ]] ; then + echo "$SourceDir is the same as $TargetDir! Aborting!" + exit 1 + fi +} # FindLinuxESP + +# Adjust filename variables appropriately for their locations and detected +# presence (or lack thereof) of shim installation +AdjustFilenames() { + echo "Entering AdjustFilenames()" + if [[ -f $SourceDir/grubx64.efi ]] ; then + SourceX64="grubx64.efi" + TargetX64=$SourceX64 + if [[ $EspSourceDir == "/efi/boot" ]] ; then + SourceShim="bootx64.efi" + elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then + SourceShim="bootmgfw.efi" + fi + else + SourceShim="none" + TargetShim="none" + if [[ $EspSourceDir == "/efi/boot" ]] ; then + SourceX64="bootx64.efi" + SourceIA32="bootia32.efi" + elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then + SourceX64="bootmgfw.efi" + fi + fi + + if [[ $EspTargetDir == "/efi/boot" ]] ; then + if [[ $TargetShim == "none" ]] ; then + TargetX64="bootx64.efi" + TargetIA32="bootia32.efi" + else + TargetShim="bootx64.efi" + fi + elif [[ $EspTargetDir == "/efi/microsoft/boot" ]] ; then + if [[ $TargetShim == "none" ]] ; then + TargetX64="bootmgfw.efi" + else + TargetShim="bootmgfw.efi" + fi + fi + + echo "Leaving AdjustFilenames():" + echo " SourceX64 = $SourceX64, TargetX64 = $TargetX64" + echo " SourceIA32 = $SourceIA32, TargetIA32 = $TargetIA32" + echo " SourceShim = $SourceShim, TargetShim = $TargetShim" +} # AdjustFilenames() + +# Checks for the presence of necessary files, including both boot loaders +# and support utilities (efibootmgr, etc.) +CheckForFiles() { + echo "Entering CheckForFiles()" + if [[ (! -f $SourceDir/$SourceX64 && ! -f $SourceDir/$SourceIA32) || + ($SourceShim != "none" && ! -f $SourceDir/SourceShim) || + ! -f $SourceDir/refind.conf ]] ; then + echo "There doesn't seem to be a rEFInd installation at $SourceDir!" + echo "Aborting!" + exit 1 + fi + if [[ $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then + Efibootmgr=`which efibootmgr 2> /dev/null` + if [[ ! -f $Efibootmgr ]] ; then + echo "Moving to a non-default directory requires a working efibootmgr utility, but" + echo "one can't be found! Aborting!" + exit 1 + elif [[ ! -d "/sys/firmware/efi" ]] ; then + echo "Moving to a non-default directory requires a boot into EFI mode, but we seem" + echo "to be running in BIOS mode. (Perhaps typing 'modprobe efivars' will fix this." + echo "Aborting!" + fi + fi +} # CheckForFiles() + +# Do final checks & then move the files! +MoveFiles() { + echo "Entering MoveFiles()" + ExistingFiles=`find $TargetDir -name "*.efi" 2> /dev/null` + if [[ -n $ExistingFiles && $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then + echo "$TargetDir isn't empty! Aborting!" + exit 1 + fi + + if [[ $EspTargetDir == "/efi/boot" && -d $TargetDir ]] ; then + if [[ -d $InstallDir/EFI/BOOT-rEFIndBackup ]] ; then + echo "" + echo "Caution: An existing backup of a default boot loader exists! If the current" + echo "default boot loader and the backup are different boot loaders, the current" + echo "one will become inaccessible." + echo "" + echo -n "Do you want to proceed with moving (Y/N)? " + read YesNo + if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then + echo "OK; continuing with the move..." + else + exit 0 + fi + else + mv $TargetDir $InstallDir/EFI/BOOT-refindBackup &> /dev/null + fi + fi + + if [[ $EspTargetDir == "/efi/microsoft/boot" && -d $TargetDir ]] ; then + mv -n $EspTargetDir/bootmgfw.efi $InstallDir/EFI/Microsoft/ + fi + + mkdir -p $TargetDir + mv $SourceDir/icons $TargetDir/ 2> /dev/null + mv $SourceDir/icons-backup $TargetDir/ 2> /dev/null + mv $SourceDir/drivers_* $TargetDir/ 2> /dev/null + mv $SourceDir/keys $TargetDir 2> /dev/null + mv $SourceDir/$SourceX64 $TargetDir/$TargetX64 2> /dev/null + mv $SourceDir/$SourceIA32 $TargetDir/$TargetIA32 2> /dev/null + mv $SourceDir/$SourceShim $TargetDir/$TargetShim 2> /dev/null + mv $SourceDir/refind.conf* $TargetDir/ 2> /dev/null + rmdir $SourceDir 2> /dev/null +} # MoveFiles() + +# Clean up after moving files -- mainly restoring old backed-up files, if present +PostMoveCleanup() { + if [[ $EfiSourceDir == "/efi/boot" && -d $InstallDir/EFI/BOOT-rEFIndBackup && ! -d $SourceDir ]] ; then + mv $InstallDir/EFI/BOOT-rEFIndBackup $SourceDir 2> /dev/null + fi + if [[ $EfiSourceDir == "/efi/microsoft/boot" && -f $InstallDir/EFI/Microsoft/bootmgfw.efi ]] ; then + mv -n $InstallDir/EFI/Microsoft/bootmgfw.efi $SourceDir/bootmgfw.efi + fi +} # PostMoveCleanup() + +# If necessary, create a new NVRAM entry for the new location +AddNvramEntry() { + echo "Entering AddNvramEntry()" + InstallIt="0" + Efibootmgr=`which efibootmgr 2> /dev/null` + InstallDisk=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 1-8` + PartNum=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 9-10` + + if [[ $TargetShim != "none" ]] ; then + EntryFilename=$TargetDir/$TargetShim + else + CpuType=`uname -m` + if [[ $CpuType == 'x86_64' ]] ; then + EntryFilename=$TargetDir/$TargetX64 + else + EntryFilename=$TargetDir/$TargetIA32 + fi + fi # if/else + + EfiEntryFilename=`echo ${EntryFilename//\//\\\}` + EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g` + ExistingEntry=`$Efibootmgr -v | grep $EfiEntryFilename2` + + if [[ $ExistingEntry ]] ; then + ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8` + FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15` + if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then + echo "An existing rEFInd boot entry exists, but isn't set as the default boot" + echo "manager. The boot order is being adjusted to make rEFInd the default boot" + echo "manager. If this is NOT what you want, you should use efibootmgr to" + echo "manually adjust your EFI's boot order." + $Efibootmgr -b $ExistingEntryBootNum -B &> /dev/null + InstallIt="1" + fi + else + InstallIt="1" + fi + + if [[ $InstallIt == "1" ]] ; then + $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null + if [[ $? != 0 ]] ; then + EfibootmgrProblems=1 + fi + fi + + if [[ $EfibootmgrProblems ]] ; then + echo + echo "ALERT: There were problems running the efibootmgr program! Your moved rEFInd" + echo "might not run!" + echo + fi +} # AddNvramEntry + +# +# Main body of script +# + +if [[ $# != 2 ]] ; then + echo "Usage: $0 {source-directory} {target-directory}" + exit 1 +fi +if [[ `whoami` != "root" ]] ; then + echo "Not running as root! Aborting!" + exit 1 +fi + +FindLinuxESP +AdjustFilenames +CheckForFiles +MoveFiles +PostMoveCleanup +echo "EspTargetDir == \"$EspTargetDir\"" +if [[ $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then + AddNvramEntry +fi -- 2.39.2