]> code.delx.au - refind/blobdiff - install.sh
Version 0.9.2 release
[refind] / install.sh
index 645c1b46660bfd8f2dfc9162771d6370105e22f3..3a2cffc9b04262ec5fc444c15db3e6494cfa1b6f 100755 (executable)
@@ -7,11 +7,13 @@
 # ./install.sh [options]
 #
 # options include:
-#    "--esp" to install to the ESP rather than to the system's root
-#           filesystem. This is the default on Linux
+#    "--notesp" to install to the OS X root filesystem rather than to the ESP.
+#           This option may not be used under Linux.
 #    "--usedefault {devicefile}" to install as default
 #           (/EFI/BOOT/BOOTX64.EFI and similar) to the specified device
 #           (/dev/sdd1 or whatever) without registering with the NVRAM.
+#    "--ownhfs {devicefile}" to install to an HFS+ volume that's NOT currently
+#           an OS X boot volume.
 #    "--root {dir}" to specify installation using the specified directory
 #           as the system's root
 #    "--alldrivers" to install all drivers along with regular files
@@ -20,6 +22,7 @@
 #    "--shim {shimfile}" to install a shim.efi file for Secure Boot
 #    "--preloader" is synonymous with "--shim"
 #    "--localkeys" to re-sign x86-64 binaries with a locally-generated key
+#    "--keepname" to keep refind_x64.efi name as such even when using shim
 #    "--yes" to assume a "yes" response to all prompts
 #
 # The "esp" option is valid only on Mac OS X; it causes
 # to the current OS X boot partition. Under Linux, this script
 # installs to the ESP by default.
 #
-# This program is copyright (c) 2012 by Roderick W. Smith
+# This program is copyright (c) 2012-2015 by Roderick W. Smith
 # It is released under the terms of the GNU GPL, version 3,
 # a copy of which should be included in the file COPYING.txt.
 #
 # Revision history:
 #
+# 0.9.2   -- Added --keepname option.
+# 0.8.7   -- Better detection of Secure Boot mode & fixed errors when copying
+#            Shim & MokManager files over themselves; fixed bug that caused
+#            inappropriate installation to EFI/BOOT/bootx64.efi
+# 0.8.6   -- Fixed bugs that caused misidentification of ESP on disks with
+#            partition numbers over 10 on OS X and misidentification of mount
+#            point if already-mounted ESP had space in path.
+# 0.8.5   -- Refinement/cleanup of new OS X ESP-as-default policy
+# 0.8.4   -- OS X default changed to install to ESP under /EFI/BOOT
+# 0.7.9   -- Fixed bug that caused errors if dmraid utility not installed
+# 0.7.7   -- Fixed bug that created mangled refind_linux.conf file; added ability
+#            to locate and mount ESP on Linux, if it's not mounted
+# 0.7.6   -- Added --ownhfs {device-filename} option
 # 0.7.5   -- Fixed bug when installing to ESP on recent versions of OS X
 # 0.7.2   -- Fixed code that could be confused by use of autofs to mount the ESP
 # 0.7.0   -- Added support for the new Btrfs driver
@@ -71,6 +87,7 @@ TargetDir=/EFI/refind
 LocalKeysBase="refind_local"
 ShimSource="none"
 ShimType="none"
+KeepName=0
 TargetShim="default"
 TargetX64="refind_x64.efi"
 TargetIA32="refind_ia32.efi"
@@ -83,16 +100,20 @@ AlwaysYes=0
 #
 
 GetParams() {
-   InstallToEspOnMac=0
-   if [[ $OSName == "Linux" ]] ; then
-      # Install the driver required to read /boot, if it's available
-      InstallDrivers="boot"
-   else
-      InstallDrivers="none"
-   fi
+   InstallToEspOnMac=1
+   # Install the driver required to read Linux /boot, if it's available
+   # Note: Under OS X, this will be installed only if a Linux partition
+   # is detected, in which case the ext4fs driver will be installed.
+   InstallDrivers="boot"
    while [[ $# -gt 0 ]]; do
       case $1 in
-         --esp | --ESP) InstallToEspOnMac=1
+         --notesp) InstallToEspOnMac=0
+              ;;
+         --ownhfs) OwnHfs=1
+              InstallToEspOnMac=0
+              TargetPart="$2"
+              TargetDir=/System/Library/CoreServices
+              shift
               ;;
          --usedefault) TargetDir=/EFI/BOOT
               TargetPart="$2"
@@ -101,6 +122,7 @@ GetParams() {
               shift
               ;;
          --root) RootDir="$2"
+              InstallToEspOnMac=0
               shift
               ;;
          --localkeys) LocalKeys=1
@@ -109,33 +131,47 @@ GetParams() {
               ShimType=`basename $ShimSource`
               shift
               ;;
+         --keepname) KeepName=1
+              ;;
          --drivers | --alldrivers) InstallDrivers="all"
               ;;
          --nodrivers) InstallDrivers="none"
               ;;
          --yes) AlwaysYes=1
               ;;
-         * ) echo "Usage: $0 [--esp | --usedefault {device-file} | --root {directory} ]"
-             echo "                  [--nodrivers | --alldrivers] [--shim {shim-filename}]"
-             echo "                  [--localkeys] [--yes]"
+         * ) echo "Usage: $0 [--notesp | --usedefault {device-file} | --root {dir} |"
+             echo "                     --ownhfs {device-file} ] [--keepname]"
+             echo "                  [--nodrivers | --alldrivers]"
+             echo "                  [--localkeys] [--keepname] [--yes]"
              exit 1
       esac
       shift
    done
-
-   if [[ $InstallToEspOnMac == 1 && "$TargetDir" == '/EFI/BOOT' ]] ; then
-      echo "You may use --esp OR --usedefault, but not both! Aborting!"
+   if [[ "$InstallToEspOnMac" == 0 && "$RootDir" == '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
+      echo "You may use --notesp OR --usedefault, but not both! Aborting!"
       exit 1
    fi
    if [[ "$RootDir" != '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
-      echo "You may use --usedefault OR --root, but not both! Aborting!"
+      echo "You may use --root OR --usedefault, but not both! Aborting!"
       exit 1
    fi
-   if [[ "$RootDir" != '/' && $InstallToEspOnMac == 1 ]] ; then
-      echo "You may use --root OR --esp, but not both! Aborting!"
+   if [[ "$TargetDir" != '/System/Library/CoreServices' && "$OwnHfs" == '1' ]] ; then
+      echo "If you use --ownhfs, you may NOT use --usedefault! Aborting!"
+      exit 1
+   fi
+   if [[ "$KeepName" == 1 && "$ShimSource" == "none" ]] ; then
+      echo "The --keepname option is meaningful only in conjunction with --shim"
+      echo "or --preloader! Aborting!"
+      exit 1
+   fi
+   if [[ "$KeepName" == 1 && "$OSName" != "Linux" ]] ; then
+      echo "The --keepname option is valid only under Linux! Aborting!"
+      exit 1
+   fi
+   if [[ "$KeepName" == 1 && "$TargetDir" != "/EFI/BOOT" ]] ; then
+      echo "The --keepname option is incompatible with --usedefault! Aborting!"
       exit 1
    fi
-
    RLConfFile="$RootDir/boot/refind_linux.conf"
    EtcKeysDir="$RootDir/etc/refind.d/keys"
 } # GetParams()
@@ -184,6 +220,7 @@ CheckForFiles() {
       exit 1
    fi
 
+   echo "ShimSource is $ShimSource"
    if [[ "$ShimSource" != "none" ]] ; then
       if [[ -f "$ShimSource" ]] ; then
          if [[ $ShimType == "shimx64.efi" || $ShimType == "shim.efi" ]] ; then
@@ -208,15 +245,24 @@ CheckForFiles() {
 # Helper for CopyRefindFiles; copies shim files (including MokManager, if it's
 # available) to target.
 CopyShimFiles() {
-   cp -fb "$ShimSource" "$InstallDir/$TargetDir/$TargetShim"
-   if [[ $? != 0 ]] ; then
-      Problems=1
-   fi
-   if [[ -f "$MokManagerSource" ]] ; then
-      cp -fb "$MokManagerSource" "$InstallDir/$TargetDir/"
+   local inode1=`ls -i "$ShimSource" 2> /dev/null | cut -f 1 -d " "`
+   local inode2=`ls -i "$InstallDir/$TargetDir/$TargetShim" 2> /dev/null | cut -f 1 -d " "`
+   if [[ $inode1 != $inode2 ]] ; then
+      cp -fb "$ShimSource" "$InstallDir/$TargetDir/$TargetShim"
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
    fi
-   if [[ $? != 0 ]] ; then
-      Problems=1
+   inode1=`ls -i "$MokManagerSource" 2> /dev/null | cut -f 1 -d " "`
+   local TargetMMName=`basename $MokManagerSource`
+   inode2=`ls -i "$InstallDir/$TargetDir/$TargetMMName" 2> /dev/null | cut -f 1 -d " "`
+   if [[ $inode1 != $inode2 ]] ; then
+      if [[ -f "$MokManagerSource" ]] ; then
+         cp -fb "$MokManagerSource" "$InstallDir/$TargetDir/"
+      fi
+      if [[ $? != 0 ]] ; then
+         Problems=1
+      fi
    fi
 } # CopyShimFiles()
 
@@ -229,6 +275,150 @@ CopyKeys() {
    fi
 } # CopyKeys()
 
+# Set varaibles for installation in EFI/BOOT directory
+SetVarsForBoot() {
+   TargetDir="/EFI/BOOT"
+   if [[ $ShimSource == "none" ]] ; then
+      TargetX64="bootx64.efi"
+      TargetIA32="bootia32.efi"
+   else
+      if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" ]] ; then
+         TargetX64="grubx64.efi"
+      elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
+         TargetX64="loader.efi"
+      else
+         echo "Unknown shim/PreBootloader type: $ShimType"
+         echo "Aborting!"
+         exit 1
+      fi
+      TargetIA32="bootia32.efi"
+      TargetShim="bootx64.efi"
+   fi
+   if [[ $KeepName == 1 ]] ; then
+      echo "Installation is to /EFI/BOOT, which is incompatible with --keepname! Aborting!"
+      exit 1
+   fi
+} # SetVarsForBoot()
+
+# Set variables for installation in EFI/Microsoft/Boot directory
+SetVarsForMsBoot() {
+   TargetDir="/EFI/Microsoft/Boot"
+   if [[ $ShimSource == "none" ]] ; then
+      TargetX64="bootmgfw.efi"
+      TargetIA32="bootmgfw.efi"
+   else
+      if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" ]] ; then
+         TargetX64="grubx64.efi"
+      elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
+         TargetX64="loader.efi"
+      else
+         echo "Unknown shim/PreBootloader type: $ShimType"
+         echo "Aborting!"
+         exit 1
+      fi
+      TargetShim="bootmgfw.efi"
+   fi
+   if [[ $KeepName == 1 ]] ; then
+      echo "Installation is to /EFI/Microsoft/Boot, which is incompatible with --keepname!"
+      echo "Aborting!"
+      exit 1
+   fi
+} # SetVarsForMsBoot()
+
+# 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 && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      SetVarsForBoot
+      Upgrade=1
+   fi
+   if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      SetVarsForMsBoot
+      Upgrade=1
+   fi
+   if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then
+      TargetDir="/EFI/refind"
+      if [[ $ShimSource == "none" || $KeepName == 1 ]] ; then
+         TargetX64="refind_x64.efi"
+         TargetIA32="refind_ia32.efi"
+      fi
+      Upgrade=1
+   fi
+   if [[ $Upgrade == 1 ]] ; then
+      echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it."
+   fi
+
+   if [[ ! -d /sys/firmware/efi && ! $OSName == 'Darwin' && $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()
+
+# Determine (or guess) the filesystem used on the Linux /boot filesystem.
+# Store the result in the BootFS global variable.
+SetBootFS() {
+   local Blkid
+
+   Blkid=`which blkid 2> /dev/null`
+   BootFS=""
+   if [[ $OSName == 'Linux' && -x "$Blkid" ]] ; then
+      BootPart=`df /boot | grep dev | cut -f 1 -d " "`
+      BootFS=`$Blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
+   fi
+   if [[ $OSName == 'Darwin' ]] ; then
+      # 0FC63DAF-8483-4772-8E79-3D69D8477DE4 = Linux filesystem
+      # BC13C2FF-59E6-4262-A352-B275FD6F7172 = Freedesktop $boot partition
+      # 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 = Freedesktop Linux /home
+      # E6D6D379-F507-44C2-A23C-238F2A3DF928 = Linux LVM
+      # A19D880F-05FC-4D3B-A006-743F0F84911E = Linux RAID
+      # 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F = Linux swap
+      Temp=$(diskutil list | grep -i '0FC63DAF-8483-4772-8E79-3D69D8477DE4\|BC13C2FF-59E6-4262-A352-B275FD6F7172\|933AC7E1-2EB4-4F13-B844-0E14E2AEF915\|E6D6D379-F507-44C2-A23C-238F2A3DF928\|A19D880F-05FC-4D3B-A006-743F0F84911E\|0657FD6D-A4AB-43C4-84E5-0933C84B4F4F\|Linux')
+      BootFS=""
+      if [[ -n $Temp ]] ; then
+         echo "Found suspected Linux partition(s); installing ext4fs driver."
+         BootFS="ext4"
+      fi
+   fi
+} # SetBootFS()
+
 # Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1,
 # honoring the $InstallDrivers condition. Must be passed a suitable
 # architecture code (ia32 or x64).
@@ -237,9 +427,8 @@ CopyDrivers() {
       mkdir -p "$InstallDir/$TargetDir/drivers_$1"
       cp "$ThisDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
       cp "$RefindDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
-   elif [[ "$InstallDrivers" == "boot" && -x `which blkid` ]] ; then
-      BootPart=`df /boot | grep dev | cut -f 1 -d " "`
-      BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
+   elif [[ "$InstallDrivers" == "boot" ]] ; then
+      SetBootFS
       DriverType=""
       case $BootFS in
          ext2 | ext3) DriverType="ext2"
@@ -254,6 +443,8 @@ CopyDrivers() {
               ;;
          hfsplus) DriverType="hfs"
               ;;
+         ntfs) DriverType="ntfs"
+              ;;
          *) BootFS=""
       esac
       if [[ -n $BootFS ]] ; then
@@ -263,13 +454,13 @@ CopyDrivers() {
          cp "$RefindDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1"/ 2> /dev/null
       fi
    fi
-}
+} # CopyDrivers()
 
 # Copy tools (currently only gptsync, and that only on Macs) to the EFI/tools
 # directory on the ESP. Must be passed a suitable architecture code (ia32
 # or x64).
 CopyTools() {
-   mkdir -p $InstallDir/EFI/tools
+   mkdir -p "$InstallDir/EFI/tools"
    if [[ $OSName == 'Darwin' ]] ; then
       cp -f "$RefindDir/tools_$1/gptsync_$1.efi" "$InstallDir/EFI/tools/"
       if [[ -f "$InstallDir/EFI/tools/gptsync.efi" ]] ; then
@@ -299,7 +490,7 @@ CopyRefindFiles() {
       if [[ $InstallDrivers == "all" ]] ; then
          cp -r "$RefindDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
          cp -r "$ThisDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
-      elif [[ $Upgrade == 1 ]] ; then
+      elif [[ $Upgrade == 1 || $InstallToEspOnMac == 1 ]] ; then
          if [[ $Platform == 'EFI64' ]] ; then
             CopyDrivers x64
             CopyTools x64
@@ -309,6 +500,11 @@ CopyRefindFiles() {
          fi
       fi
       Refind=""
+      if [[ $Platform == 'EFI64' ]] ; then
+         Refind='bootx64.efi'
+      elif [[ $Platform == 'EFI32' ]] ; then
+         Refind='bootia32.efi'
+      fi
       CopyKeys
    elif [[ $Platform == 'EFI64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then
       cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64"
@@ -332,6 +528,9 @@ CopyRefindFiles() {
             cp "$ThisDir/keys/refind.crt" "$EtcKeysDir" 2> /dev/null
          fi
       fi
+      if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then
+         SetupMacHfs $TargetX64
+      fi
    elif [[ $Platform == 'EFI32' ]] ; then
       cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32"
       if [[ $? != 0 ]] ; then
@@ -340,6 +539,9 @@ CopyRefindFiles() {
       CopyDrivers ia32
       CopyTools ia32
       Refind="refind_ia32.efi"
+      if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then
+         SetupMacHfs $TargetIA32
+      fi
    else
       echo "Unknown platform! Aborting!"
       exit 1
@@ -381,12 +583,24 @@ CopyRefindFiles() {
    fi
 } # CopyRefindFiles()
 
-# Mount the partition the user specified with the --usedefault option
+# Mount the partition the user specified with the --usedefault or --ownhfs option
 MountDefaultTarget() {
    InstallDir=/tmp/refind_install
    mkdir -p "$InstallDir"
+   UnmountEsp=1
    if [[ $OSName == 'Darwin' ]] ; then
-      mount -t msdos "$TargetPart" "$InstallDir"
+      if [[ $OwnHfs == '1' ]] ; then
+         Temp=`diskutil info "$TargetPart" | grep "Mount Point"`
+         InstallDir=`echo $Temp | cut -f 3-30 -d ' '`
+         if [[ $InstallDir == '' ]] ; then
+            InstallDir=/tmp/refind_install
+            mount -t hfs "$TargetPart" "$InstallDir"
+         else
+            UnmountEsp=0
+         fi
+      else
+         mount -t msdos "$TargetPart" "$InstallDir"
+      fi
    elif [[ $OSName == 'Linux' ]] ; then
       mount -t vfat "$TargetPart" "$InstallDir"
    fi
@@ -395,7 +609,6 @@ MountDefaultTarget() {
       rmdir "$InstallDir"
       exit 1
    fi
-   UnmountEsp=1
 } # MountDefaultTarget()
 
 #
@@ -409,39 +622,92 @@ MountDefaultTarget() {
 MountOSXESP() {
    # Identify the ESP. Note: This returns the FIRST ESP found;
    # if the system has multiple disks, this could be wrong!
-   Temp=`diskutil list | grep " EFI "`
-   Esp=/dev/`echo $Temp | cut -f 5 -d ' '`
+   Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p")
+   if [ $Temp ]; then
+      Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1)
+      if [ -z $Temp ]; then
+         echo "Warning: root device doesn't have an EFI partition"
+      fi
+   else
+      echo "Warning: root device could not be found"
+   fi
+   if [ -z $Temp ]; then
+      Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p
+             q
+         }' )
+
+      if [ -z $Temp ]; then
+         echo "Could not find an EFI partition. Aborting!"
+         exit 1
+      fi
+   fi
+   Esp=/dev/`echo $Temp`
    # If the ESP is mounted, use its current mount point....
-   Temp=`df -P | grep "$Esp"`
-   InstallDir=`echo $Temp | cut -f 6 -d ' '`
+   Temp=`df -P | grep "$Esp "`
+   InstallDir=`echo $Temp | cut -f 6- -d ' '`
    if [[ "$InstallDir" == '' ]] ; then
       mkdir /Volumes/ESP &> /dev/null
       mount -t msdos "$Esp" /Volumes/ESP
+      # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is
+      # detected, mount it as such and set appropriate options.
       if [[ $? != 0 ]] ; then
-         echo "Unable to mount ESP! Aborting!\n"
-         exit 1
+         mount -t hfs "$Esp" /Volumes/Esp
+         OwnHfs=1
+         InstallToEspOnMac=0
+         if [[ $? != 0 ]] ; then
+            echo "Unable to mount ESP! Aborting!\n"
+            exit 1
+         fi
       fi
       UnmountEsp=1
       InstallDir="/Volumes/ESP"
    fi
 } # MountOSXESP()
 
+# Set up for booting from Mac HFS+ volume that boots rEFInd in MJG's way
+# (http://mjg59.dreamwidth.org/7468.html)
+# Must be passed the original rEFInd binary filename (without a path).
+SetupMacHfs() {
+   if [[ -s "$InstallDir/mach_kernel" ]] ; then
+      echo "Attempt to install rEFInd to a partition with a /mach_kernel file! Aborting!"
+      exit 1
+   fi
+   cp -n "$InstallDir/$TargetDir/boot.efi" "$InstallDir/$TargetDir/boot.efi-backup" &> /dev/null
+   ln -f "$InstallDir/$TargetDir/$1" "$InstallDir/$TargetDir/boot.efi"
+   touch "$InstallDir/mach_kernel"
+   rm "$InstallDir/$TargetDir/SystemVersion.plist" &> /dev/null
+   cat - << ENDOFHERE >> "$InstallDir/$TargetDir/SystemVersion.plist"
+<xml version="1.0" encoding="UTF-8"?>
+<plist version="1.0">
+<dict>
+        <key>ProductBuildVersion</key>
+        <string></string>
+        <key>ProductName</key>
+        <string>rEFInd</string>
+        <key>ProductVersion</key>
+        <string>0.9.2</string>
+</dict>
+</plist>
+ENDOFHERE
+} # SetupMacHfs()
+
 # Control the OS X installation.
 # Sets Problems=1 if problems found during the installation.
 InstallOnOSX() {
    echo "Installing rEFInd on OS X...."
-   if [[ "$TargetDir" == "/EFI/BOOT" ]] ; then
-      MountDefaultTarget
-   elif [[ "$InstallToEspOnMac" == "1" ]] ; then
+   if [[ "$InstallToEspOnMac" == "1" ]] ; then
       MountOSXESP
+   elif [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then
+      MountDefaultTarget
    else
       InstallDir="$RootDir/"
    fi
    echo "Installing rEFInd to the partition mounted at $InstallDir"
+   DetermineTargetDir
    Platform=`ioreg -l -p IODeviceTree | grep firmware-abi | cut -d "\"" -f 4`
    CopyRefindFiles
    if [[ $InstallToEspOnMac == "1" ]] ; then
-      bless --mount "$InstallDir" --setBoot --file "$InstallDir/$TargetDir/$Refind"
+      bless --mount "$InstallDir" --setBoot --file "$InstallDir/$TargetDir/$Refind" --shortform
    elif [[ "$TargetDir" != "/EFI/BOOT" ]] ; then
       bless --setBoot --folder "$InstallDir/$TargetDir" --file "$InstallDir/$TargetDir/$Refind"
    fi
@@ -477,20 +743,18 @@ InstallOnOSX() {
 # appropriate options haven't been set, warn the user and offer to abort.
 # If we're NOT in Secure Boot mode but the user HAS specified the --shim
 # or --localkeys option, warn the user and offer to abort.
-#
-# FIXME: Although I checked the presence (and lack thereof) of the
-# /sys/firmware/efi/vars/SecureBoot* files on my Secure Boot test system
-# before releasing this script, I've since found that they are at least
-# sometimes present when Secure Boot is absent. This means that the first
-# test can produce false alarms. A better test is highly desirable.
 CheckSecureBoot() {
-   VarFile=`ls -d /sys/firmware/efi/vars/SecureBoot* 2> /dev/null`
-   if [[ -n "$VarFile" && "$TargetDir" != '/EFI/BOOT' && "$ShimSource" == "none" ]] ; then
+   local IsSecureBoot
+   if [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then
+      IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'`
+   else
+      IsSecureBoot="0"
+   fi
+   if [[ $IsSecureBoot == "1" && "$TargetDir" != '/EFI/BOOT' && "$ShimSource" == "none" ]] ; then
       echo ""
-      echo "CAUTION: Your computer appears to support Secure Boot, but you haven't"
-      echo "specified a valid shim.efi file source. If you've disabled Secure Boot and"
-      echo "intend to leave it disabled, this is fine; but if Secure Boot is active, the"
-      echo "resulting installation won't boot. You can read more about this topic at"
+      echo "CAUTION: Your computer appears to be booted with Secure Boot, but you haven't"
+      echo "specified a valid shim.efi file source. Chances are you should re-run with"
+      echo "the --shim option. You can read more about this topic at"
       echo "http://www.rodsbooks.com/refind/secureboot.html."
       echo ""
       echo -n "Do you want to proceed with installation (Y/N)? "
@@ -502,7 +766,7 @@ CheckSecureBoot() {
       fi
    fi
 
-   if [[ "$ShimSource" != "none" && ! -n "$VarFile" ]] ; then
+   if [[ "$ShimSource" != "none" && ! $IsSecureBoot == "1" ]] ; then
       echo ""
       echo "You've specified installing using a shim.efi file, but your computer does not"
       echo "appear to be running in Secure Boot mode. Although installing in this way"
@@ -520,7 +784,7 @@ CheckSecureBoot() {
       fi
    fi
 
-   if [[ $LocalKeys != 0 && ! -n "$VarFile" ]] ; then
+   if [[ $LocalKeys != 0 && ! $IsSecureBoot == "1" ]] ; then
       echo ""
       echo "You've specified re-signing your rEFInd binaries with locally-generated keys,"
       echo "but your computer does not appear to be running in Secure Boot mode. The"
@@ -624,33 +888,80 @@ ReSignBinaries() {
    IFS=$SaveIFS
    RefindDir="$TempDir"
    DeleteRefindDir=1
-}
+} # ReSignBinaries()
+
+# Locate and mount an ESP, if possible, based on parted output.
+# Should be called only if /boot/efi is NOT an acceptable ESP.
+# Sets InstallDir to the mounted ESP's path ($RootDir/boot/efi)
+# and EspFilesystem the filesystem (always "vfat")
+FindLinuxESP() {
+   echo "The ESP doesn't seem to be mounted! Trying to find it...."
+   local Drive
+   local PartNum
+   local TableType
+   local DmStatus
+   local SkipIt
+   local Dmraid
+   for Drive in `ls /dev/[sh]d?` ; do
+      SkipIt=0
+      Dmraid=`which dmraid 2> /dev/null`
+      if [ -x "$Dmraid" ] ; then
+         DmStatus=`dmraid -r | grep $Drive`
+         if [ -n "$DmStatus" ] ; then
+            echo "$Drive seems to be part of a RAID array; skipping!"
+            SkipIt=1
+         fi
+      fi
+      TableType=`parted $Drive print -m -s 2>/dev/null | awk -F: '$1 == "'$Drive'" { print $6 }'`
+      if [[ $TableType == 'gpt' && $SkipIt == 0 ]] ; then # read only GPT disks that aren't part of dmraid array
+         PartNum=`LANG=C parted $Drive print -m -s 2>/dev/null | awk -F: '$7 ~ "(^boot| boot)" { print $1 }' | head -n 1`
+         if [ "$PartNum" -eq "$PartNum" ] 2> /dev/null ; then
+            InstallDir="$RootDir/boot/efi"
+            mkdir -p $InstallDir
+            mount $Drive$PartNum $InstallDir
+            EspFilesystem=`grep "$Drive$PartNum.*/boot/efi" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3`
+            if [[ $EspFilesystem != 'vfat' ]] ; then
+               umount $InstallDir
+            else
+               echo "Mounting ESP at $InstallDir"
+               break;
+            fi
+         fi # $PartNum -eq $PartNum
+      fi # TableType
+   done
+} # FindLinuxESP()
 
 # Identifies the ESP's location (/boot or /boot/efi, or these locations under
 # the directory specified by --root); aborts if the ESP isn't mounted at
 # either location.
 # Sets InstallDir to the ESP mount point.
-FindLinuxESP() {
+FindMountedESP() {
+   mount /boot &> /dev/null
+   mount /boot/efi &> /dev/null
    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 | uniq | grep -v autofs | cut -d " " -f 3`
+      EspFilesystem=`grep -w "$InstallDir" /etc/mtab | uniq | grep -v autofs | 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"
+      FindLinuxESP
+   fi
+   if [[ $EspFilesystem != 'vfat' ]] ; then
+      echo "$RootDir/$InstallDir 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
    echo "ESP was found at $InstallDir using $EspFilesystem"
-} # FindLinuxESP
+} # FindMountedESP
 
 # Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM.
 # If this fails, sets Problems=1
 AddBootEntry() {
-   InstallIt="0"
+   local PartNum
    Efibootmgr=`which efibootmgr 2> /dev/null`
    if [[ "$Efibootmgr" ]] ; then
       InstallDisk=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 1-8`
@@ -668,20 +979,20 @@ AddBootEntry() {
             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"
+         "$Efibootmgr" -b $ExistingEntryBootNum -B &> /dev/null
       fi
 
-      if [[ $InstallIt == "1" ]] ; then
-         echo "Installing it!"
+      echo "Installing it!"
+      if [[ "$KeepName" == 0 ]] ; then
          "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
-         if [[ $? != 0 ]] ; then
-            EfibootmgrProblems=1
-            Problems=1
-         fi
+      else
+         "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum \
+                       -u "$TargetShim $TargetX64" &> /dev/null
+      fi
+      if [[ $? != 0 ]] ; then
+         EfibootmgrProblems=1
+         Problems=1
       fi
 
    else # efibootmgr not found
@@ -715,130 +1026,31 @@ GenerateRefindLinuxConf() {
       StartOfDevname=`echo "$RootFS" | cut -b 1-7`
       if [[ "$StartOfDevname" == "/dev/sd" || "$StartOfDevName" == "/dev/hd" ]] ; then
          # Identify root filesystem by UUID rather than by device node, if possible
-         Uuid=`blkid -o export "$RootFS" 2> /dev/null | grep UUID=`
+         Uuid=`blkid -o export -s UUID "$RootFS" 2> /dev/null | grep UUID=`
          if [[ -n $Uuid ]] ; then
             RootFS="$Uuid"
          fi
       fi
       DefaultOptions="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
-      echo "\"Boot with standard options\" \"ro root=$RootFS $DefaultOptions \"" > $RLConfFile
-      echo "\"Boot to single-user mode\"   \"ro root=$RootFS $DefaultOptions single\"" >> $RLConfFile
-      echo "\"Boot with minimal options\"  \"ro root=$RootFS\"" >> $RLConfFile
-   fi
-}
-
-# Set varaibles for installation in EFI/BOOT directory
-SetVarsForBoot() {
-   TargetDir="/EFI/BOOT"
-   if [[ $ShimSource == "none" ]] ; then
-      TargetX64="bootx64.efi"
-      TargetIA32="bootia32.efi"
-   else
-      if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" ]] ; then
-         TargetX64="grubx64.efi"
-      elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
-         TargetX64="loader.efi"
-      else
-         echo "Unknown shim/PreBootloader type: $ShimType"
-         echo "Aborting!"
-         exit 1
-      fi
-      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
-      if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" ]] ; then
-         TargetX64="grubx64.efi"
-      elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
-         TargetX64="loader.efi"
-      else
-         echo "Unknown shim/PreBootloader type: $ShimType"
-         echo "Aborting!"
-         exit 1
-      fi
-      TargetShim="bootmgfw.efi"
+      echo "\"Boot with standard options\"        \"ro root=$RootFS $DefaultOptions \"" > $RLConfFile
+      echo "\"Boot to single-user mode\"          \"ro root=$RootFS $DefaultOptions single\"" >> $RLConfFile
+      echo "\"Boot with minimal options\"         \"ro root=$RootFS\"" >> $RLConfFile
    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() {
+   if [[ "$TargetDir" == "/System/Library/CoreServices" ]] ; then
+      echo "You may not use the --ownhfs option under Linux! Aborting!"
+      exit 1
+   fi
    echo "Installing rEFInd on Linux...."
    modprobe efivars &> /dev/null
    if [[ $TargetDir == "/EFI/BOOT" ]] ; then
       MountDefaultTarget
    else
-      FindLinuxESP
+      FindMountedESP
       DetermineTargetDir
    fi
    CpuType=`uname -m`
@@ -895,7 +1107,6 @@ InstallOnLinux() {
 # performs a few startup checks, and then calls functions to
 # install under OS X or Linux, depending on the detected platform.
 #
-
 OSName=`uname -s`
 GetParams "$@"
 ThisDir="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
@@ -926,6 +1137,10 @@ elif [[ $OSName == 'Linux' ]] ; then
    InstallOnLinux
 else
    echo "Running on unknown OS; aborting!"
+   if [[ "$InstallToEspOnMac" == 0 ]] ; then
+      echo "The --notesp option is not supported on Linux! Exiting!"
+      exit 1
+   fi
 fi
 
 if [[ $Problems ]] ; then
@@ -941,7 +1156,7 @@ else
    echo
 fi
 
-if [[ $UnmountEsp ]] ; then
+if [[ $UnmountEsp == '1' ]] ; then
    echo "Unmounting install dir"
    umount $InstallDir
 fi