]> code.delx.au - refind/blobdiff - install.sh
Fix memory management error; version 0.6.4 release.
[refind] / install.sh
index 0559d584412e8c8f83d3a961f809f2b60dd644b9..8268e409187dc7bd35a29317b27e6dd548a71284 100755 (executable)
 #
 # Revision history:
 #
+# 0.6.4   -- Copies ext2 driver rather than ext4 driver for ext2/3fs
+# 0.6.3   -- Support for detecting rEFInd in EFI/BOOT and EFI/Microsoft/Boot
+#            directories & for installing to EFI/BOOT in BIOS mode
+# 0.6.2-1 -- Added --yes option & tweaked key-copying for use with RPM install script
 # 0.6.1   -- Added --root option; minor bug fixes
 # 0.6.0   -- Changed --drivers to --alldrivers and added --nodrivers option;
 #            changed default driver installation behavior in Linux to install
@@ -52,10 +56,12 @@ RootDir="/"
 TargetDir=/EFI/refind
 LocalKeysBase="refind_local"
 ShimSource="none"
+TargetShim="default"
 TargetX64="refind_x64.efi"
 TargetIA32="refind_ia32.efi"
 LocalKeys=0
 DeleteRefindDir=0
+AlwaysYes=0
 
 #
 # Functions used by both OS X and Linux....
@@ -91,9 +97,11 @@ GetParams() {
               ;;
          --nodrivers) InstallDrivers="none"
               ;;
+         --yes) AlwaysYes=1
+              ;;
          * ) echo "Usage: $0 [--esp | --usedefault {device-file} | --root {directory} ]"
              echo "                  [--nodrivers | --alldrivers] [--shim {shim-filename}]"
-             echo "                  [--localkeys]"
+             echo "                  [--localkeys] [--yes]"
              exit 1
       esac
       shift
@@ -116,6 +124,18 @@ GetParams() {
    EtcKeysDir="$RootDir/etc/refind.d/keys"
 } # GetParams()
 
+# Get a yes/no response from the user and place it in the YesNo variable.
+# If the AlwaysYes variable is set to 1, skip the user input and set "Y"
+# in the YesNo variable.
+ReadYesNo() {
+   if [[ $AlwaysYes == 1 ]] ; then
+      YesNo="Y"
+      echo "Y"
+   else
+      read YesNo
+   fi
+}
+
 # Abort if the rEFInd files can't be found.
 # Also sets $ConfFile to point to the configuration file,
 # $IconsDir to point to the icons directory, and
@@ -200,12 +220,17 @@ CopyDrivers() {
       BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
       DriverType=""
       case $BootFS in
-         ext2 | ext3 | ext4) DriverType="ext4"
+         ext2 | ext3) DriverType="ext2"
+              # Could use ext4, but that can create unwanted entries from symbolic
+              # links in / to /boot/vmlinuz if a separate /boot partition is used.
+              ;;
+         ext4) DriverType="ext4"
               ;;
          reiserfs) DriverType="reiserfs"
               ;;
          hfsplus) DriverType="hfs"
               ;;
+         *) BootFS=""
       esac
       if [[ -n $BootFS ]] ; then
          echo "Installing driver for $BootFS (${DriverType}_$1.efi)"
@@ -219,7 +244,7 @@ CopyDrivers() {
 # Copy the rEFInd files to the ESP or OS X root partition.
 # Sets Problems=1 if any critical commands fail.
 CopyRefindFiles() {
-   mkdir -p $InstallDir/$TargetDir &> /dev/null
+   mkdir -p $InstallDir/$TargetDir
    if [[ $TargetDir == '/EFI/BOOT' ]] ; then
       cp $RefindDir/refind_ia32.efi $InstallDir/$TargetDir/$TargetIA32 2> /dev/null
       if [[ $? != 0 ]] ; then
@@ -239,14 +264,7 @@ CopyRefindFiles() {
       fi
       Refind=""
       CopyKeys
-   elif [[ $Platform == 'EFI32' ]] ; then
-      cp $RefindDir/refind_ia32.efi $InstallDir/$TargetDir/$TargetIA32
-      if [[ $? != 0 ]] ; then
-         Problems=1
-      fi
-      CopyDrivers ia32
-      Refind="refind_ia32.efi"
-   elif [[ $Platform == 'EFI64' ]] ; then
+   elif [[ $Platform == 'EFI64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then
       cp $RefindDir/refind_x64.efi $InstallDir/$TargetDir/$TargetX64
       if [[ $? != 0 ]] ; then
          Problems=1
@@ -255,16 +273,25 @@ CopyRefindFiles() {
       Refind="refind_x64.efi"
       CopyKeys
       if [[ $ShimSource != "none" ]] ; then
-         TargetShim=`basename $ShimSource`
+         if [[ $TargetShim == "default" ]] ; then
+            TargetShim=`basename $ShimSource`
+         fi
          CopyShimFiles
          Refind=$TargetShim
          if [[ $LocalKeys == 0 ]] ; then
             echo "Storing copies of rEFInd Secure Boot public keys in $EtcKeysDir"
             mkdir -p $EtcKeysDir
-            cp $ThisDir/keys/refind.cer $EtcKeysDir
-            cp $ThisDir/keys/refind.crt $EtcKeysDir
+            cp $ThisDir/keys/refind.cer $EtcKeysDir 2> /dev/null
+            cp $ThisDir/keys/refind.crt $EtcKeysDir 2> /dev/null
          fi
       fi
+   elif [[ $Platform == 'EFI32' ]] ; then
+      cp $RefindDir/refind_ia32.efi $InstallDir/$TargetDir/$TargetIA32
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
+      CopyDrivers ia32
+      Refind="refind_ia32.efi"
    else
       echo "Unknown platform! Aborting!"
       exit 1
@@ -280,7 +307,9 @@ CopyRefindFiles() {
    if [[ $? != 0 ]] ; then
       Problems=1
    fi
-   cp -rf $ThisDir/keys $InstallDir/$TargetDir/
+   mkdir -p $InstallDir/$TargetDir/keys
+   cp -rf $ThisDir/keys/*.[cd]er $InstallDir/$TargetDir/keys/ 2> /dev/null
+   cp -rf $EtcKeysDir/*.[cd]er $InstallDir/$TargetDir/keys/ 2> /dev/null
    if [[ -f $InstallDir/$TargetDir/refind.conf ]] ; then
       echo "Existing refind.conf file found; copying sample file as refind.conf-sample"
       echo "to avoid overwriting your customizations."
@@ -376,7 +405,7 @@ InstallOnOSX() {
       echo "/Library/StartupItems/rEFItBlesser found!"
       echo "This program is part of rEFIt, and will cause rEFInd to fail to work after"
       echo -n "its first boot. Do you want to remove rEFItBlesser (Y/N)? "
-      read YesNo
+      ReadYesNo
       if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
          echo "Deleting /Library/StartupItems/rEFItBlesser..."
          rm -r /Library/StartupItems/rEFItBlesser
@@ -417,8 +446,8 @@ CheckSecureBoot() {
       echo "http://www.rodsbooks.com/refind/secureboot.html."
       echo ""
       echo -n "Do you want to proceed with installation (Y/N)? "
-      read ContYN
-      if [[ $ContYN == "Y" || $ContYN == "y" ]] ; then
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
          echo "OK; continuing with the installation..."
       else
          exit 0
@@ -435,8 +464,8 @@ CheckSecureBoot() {
       echo "http://www.rodsbooks.com/refind/secureboot.html."
       echo ""
       echo -n "Do you want to proceed with installation (Y/N)? "
-      read ContYN
-      if [[ $ContYN == "Y" || $ContYN == "y" ]] ; then
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
          echo "OK; continuing with the installation..."
       else
          exit 0
@@ -452,8 +481,8 @@ CheckSecureBoot() {
       echo "more about it at http://www.rodsbooks.com/refind/secureboot.html."
       echo ""
       echo -n "Do you want to proceed with installation (Y/N)? "
-      read ContYN
-      if [[ $ContYN == "Y" || $ContYN == "y" ]] ; then
+      ReadYesNo
+      if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
          echo "OK; continuing with the installation..."
       else
          exit 0
@@ -534,7 +563,7 @@ ReSignBinaries() {
    mkdir -p $TempDir/drivers_x64
    cp $RefindDir/refind.conf-sample $TempDir 2> /dev/null
    cp $ThisDir/refind.conf-sample $TempDir 2> /dev/null
-   cp $RefindDir/refind_ia32.efi $TempDir
+   cp $RefindDir/refind_ia32.efi $TempDir 2> /dev/null
    cp -a $RefindDir/drivers_ia32 $TempDir 2> /dev/null
    cp -a $ThisDir/drivers_ia32 $TempDir 2> /dev/null
    SignOneBinary $RefindDir/refind_x64.efi $TempDir/refind_x64.efi
@@ -565,7 +594,7 @@ FindLinuxESP() {
       exit 1
    fi
    echo "ESP was found at $InstallDir using $EspFilesystem"
-} # MountLinuxESP
+} # FindLinuxESP
 
 # Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM.
 # If this fails, sets Problems=1
@@ -573,17 +602,14 @@ AddBootEntry() {
    InstallIt="0"
    Efibootmgr=`which efibootmgr 2> /dev/null`
    if [[ $Efibootmgr ]] ; then
-      modprobe efivars &> /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`
       EntryFilename=$TargetDir/$Refind
       EfiEntryFilename=`echo ${EntryFilename//\//\\\}`
       EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g`
-      ExistingEntry=`$Efibootmgr -v | grep $EfiEntryFilename2`
-      # NOTE: Below protects against duplicate entries, but only for non-Secure Boot
-      # installations.
-      # TODO: Improve to detect & protect against duplicating a Secure Boot entry.
-      if [[ $ExistingEntry && $ShimSource == "none" ]] ; then
+      ExistingEntry=`$Efibootmgr -v | grep -i $EfiEntryFilename2`
+
+      if [[ $ExistingEntry ]] ; then
          ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8`
          FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15`
          if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then
@@ -597,18 +623,21 @@ AddBootEntry() {
       else
          InstallIt="1"
       fi
+
       if [[ $InstallIt == "1" ]] ; then
          echo "Installing it!"
-         $Efibootmgr -c -l $EfiEntryFilename -L rEFInd -d $InstallDisk -p $PartNum &> /dev/null
+         $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
          if [[ $? != 0 ]] ; then
             EfibootmgrProblems=1
             Problems=1
          fi
       fi
-   else
+
+   else # efibootmgr not found
       EfibootmgrProblems=1
       Problems=1
    fi
+
    if [[ $EfibootmgrProblems ]] ; then
       echo
       echo "ALERT: There were problems running the efibootmgr program! You may need to"
@@ -620,10 +649,12 @@ AddBootEntry() {
 
 # Create a minimal/sample refind_linux.conf file in /boot.
 GenerateRefindLinuxConf() {
-   if [[ ! -f $RLConfFile ]] ; then
-      if [[ -f /etc/default/grub ]] ; then
+   if [[ -f $RLConfFile ]] ; then
+      echo "Existing $RLConfFile found; not overwriting."
+   else
+      if [[ -f "$RootDir/etc/default/grub" ]] ; then
          # We want the default options used by the distribution, stored here....
-         source /etc/default/grub
+         source "$RootDir/etc/default/grub"
       fi
       RootFS=`df $RootDir | grep dev | cut -f 1 -d " "`
       StartOfDevname=`echo $RootFS | cut -b 1-7`
@@ -641,52 +672,148 @@ GenerateRefindLinuxConf() {
    fi
 }
 
+# Set varaibles for installation in EFI/BOOT directory
+SetVarsForBoot() {
+   TargetDir="/EFI/BOOT"
+   if [[ $ShimSource == "none" ]] ; then
+      TargetX64="bootx64.efi"
+      TargetIA32="bootia32.efi"
+   else
+      TargetX64="grubx64.efi"
+      TargetIA32="bootia32.efi"
+      TargetShim="bootx64.efi"
+   fi
+} # SetFilenamesForBoot()
+
+# Set variables for installation in EFI/Microsoft/Boot directory
+SetVarsForMsBoot() {
+   TargetDir="/EFI/Microsoft/Boot"
+   if [[ $ShimSource == "none" ]] ; then
+      TargetX64="bootmgfw.efi"
+   else
+      TargetX64="grubx64.efi"
+      TargetShim="bootmgfw.efi"
+   fi
+}
+
+# TargetDir defaults to /EFI/refind; however, this function adjusts it as follows:
+# - If an existing refind.conf is available in /EFI/BOOT or /EFI/Microsoft/Boot,
+#   install to that directory under the suitable name; but DO NOT do this if
+#   refind.conf is also in /EFI/refind.
+# - If booted in BIOS mode and the ESP lacks any other EFI files, install to
+#   /EFI/BOOT
+# - If booted in BIOS mode and there's no refind.conf file and there is a
+#   /EFI/Microsoft/Boot/bootmgfw.efi file, move it down one level and
+#   install under that name, "hijacking" the Windows boot loader filename
+DetermineTargetDir() {
+   Upgrade=0
+
+   if [[ -f $InstallDir/EFI/BOOT/refind.conf ]] ; then
+      SetVarsForBoot
+      Upgrade=1
+   fi
+   if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf ]] ; then
+      SetVarsForMsBoot
+      Upgrade=1
+   fi
+   if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      TargetDir="/EFI/refind"
+      Upgrade=1
+   fi
+   if [[ $Upgrade == 1 ]] ; then
+      echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it."
+   fi
+
+   if [[ ! -d /sys/firmware/efi && $Upgrade == 0 ]] ; then     # BIOS-mode
+      FoundEfiFiles=`find $InstallDir/EFI/BOOT -name "*.efi" 2> /dev/null`
+      FoundConfFiles=`find $InstallDir -name "refind\.conf" 2> /dev/null`
+      if [[ ! -n $FoundConfFiles && -f $InstallDir/EFI/Microsoft/Boot/bootmgfw.efi ]] ; then
+         mv -n $InstallDir/EFI/Microsoft/Boot/bootmgfw.efi $InstallDir/EFI/Microsoft &> /dev/null
+         SetVarsForMsBoot
+         echo "Running in BIOS mode with a suspected Windows installation; moving boot loader"
+         echo "files so as to install to $InstallDir$TargetDir."
+      elif [[ ! -n $FoundEfiFiles ]] ; then  # In BIOS mode and no default loader; install as default loader
+         SetVarsForBoot
+         echo "Running in BIOS mode with no existing default boot loader; installing to"
+         echo $InstallDir$TargetDir
+      else
+         echo "Running in BIOS mode with an existing default boot loader; backing it up and"
+         echo "installing rEFInd in its place."
+         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 installation (Y/N)? "
+            ReadYesNo
+            if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+               echo "OK; continuing with the installation..."
+            else
+               exit 0
+            fi
+         fi
+         mv -n $InstallDir/EFI/BOOT $InstallDir/EFI/BOOT-rEFIndBackup
+         SetVarsForBoot
+      fi
+   fi # BIOS-mode
+} # DetermineTargetDir()
+
 # Controls rEFInd installation under Linux.
 # Sets Problems=1 if something goes wrong.
 InstallOnLinux() {
    echo "Installing rEFInd on Linux...."
+   modprobe efivars &> /dev/null
    if [[ $TargetDir == "/EFI/BOOT" ]] ; then
       MountDefaultTarget
    else
       FindLinuxESP
+      DetermineTargetDir
    fi
    CpuType=`uname -m`
    if [[ $CpuType == 'x86_64' ]] ; then
       Platform="EFI64"
-      if [[ $LocalKeys == 1 ]] ; then
-         ReSignBinaries
-      fi
-   elif [[ $CpuType == 'i386' || $CpuType == 'i486' || $CpuType == 'i586' || $CpuType == 'i686' ]] ; then
-      if [[ $ShimSource != "none" && $TargetDir != "/BOOT/EFI" ]] ; then
-         echo ""
-         echo "CAUTION: Neither rEFInd nor shim currently supports 32-bit systems, so you"
-         echo "should not use the --shim option to install on such systems. Aborting!"
-         echo ""
-         exit 1
-      fi
+   elif [[ ($CpuType == 'i386' || $CpuType == 'i486' || $CpuType == 'i586' || $CpuType == 'i686') ]] ; then
       Platform="EFI32"
-      echo
-      echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based"
-      echo "computers are VERY RARE. If you've installed a 32-bit version of Linux"
-      echo "on a 64-bit computer, you should manually install the 64-bit version of"
-      echo "rEFInd. If you're installing on a Mac, you should do so from OS X. If"
-      echo "you're positive you want to continue with this installation, answer 'Y'"
-      echo "to the following question..."
-      echo
-      echo -n "Are you sure you want to continue (Y/N)? "
-      read ContYN
-      if [[ $ContYN == "Y" || $ContYN == "y" ]] ; then
-         echo "OK; continuing with the installation..."
-      else
-         exit 0
-      fi
+      # If we're in EFI mode, do some sanity checks, and alert the user or even
+      # abort. Not in BIOS mode, though, since that could be used on an emergency
+      # disc to try to recover a troubled Linux installation.
+      if [[ -d /sys/firmware/efi ]] ; then
+         if [[ $ShimSource != "none" && $TargetDir != "/BOOT/EFI" ]] ; then
+            echo ""
+            echo "CAUTION: Neither rEFInd nor shim currently supports 32-bit systems, so you"
+            echo "should not use the --shim option to install on such systems. Aborting!"
+            echo ""
+            exit 1
+         fi
+         echo
+         echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based"
+         echo "computers are VERY RARE. If you've installed a 32-bit version of Linux"
+         echo "on a 64-bit computer, you should manually install the 64-bit version of"
+         echo "rEFInd. If you're installing on a Mac, you should do so from OS X. If"
+         echo "you're positive you want to continue with this installation, answer 'Y'"
+         echo "to the following question..."
+         echo
+         echo -n "Are you sure you want to continue (Y/N)? "
+         ReadYesNo
+         if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
+            echo "OK; continuing with the installation..."
+         else
+            exit 0
+         fi
+      fi # in EFI mode
    else
       echo "Unknown CPU type '$CpuType'; aborting!"
       exit 1
    fi
+
+   if [[ $LocalKeys == 1 ]] ; then
+      ReSignBinaries
+   fi
+
    CheckSecureBoot
    CopyRefindFiles
-   if [[ $TargetDir != "/EFI/BOOT" ]] ; then
+   if [[ $TargetDir != "/EFI/BOOT" && $TargetDir != "/EFI/Microsoft/Boot" ]] ; then
       AddBootEntry
       GenerateRefindLinuxConf
    fi