Advertisement
zebedeeboss

refind-install

Oct 18th, 2016
451
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 51.72 KB | None | 0 0
  1. #!/bin/bash
  2. #
  3. # Linux/MacOS X script to install rEFInd
  4. #
  5. # Usage:
  6. #
  7. # ./refind-install [options]
  8. #
  9. # options include:
  10. # "--notesp" to install to the OS X root filesystem rather than to the ESP.
  11. # This option may not be used under Linux.
  12. # "--usedefault {devicefile}" to install as default
  13. # (/EFI/BOOT/BOOTX64.EFI and similar) to the specified device
  14. # (/dev/sdd1 or whatever) without registering with the NVRAM.
  15. # "--ownhfs {devicefile}" to install to an HFS+ volume that's NOT currently
  16. # an OS X boot volume.
  17. # "--root {dir}" to specify installation using the specified directory
  18. # as the system's root
  19. # "--alldrivers" to install all drivers along with regular files
  20. # "--nodrivers" to suppress driver installation (default in Linux is
  21. # driver used on /boot; --nodrivers is OS X default)
  22. # "--shim {shimfile}" to install a shim.efi file for Secure Boot
  23. # "--preloader" is synonymous with "--shim"
  24. # "--localkeys" to re-sign x86-64 binaries with a locally-generated key
  25. # "--keepname" to keep refind_x64.efi name as such even when using shim
  26. # "--yes" to assume a "yes" response to all prompts
  27. #
  28. # The "esp" option is valid only on Mac OS X; it causes
  29. # installation to the EFI System Partition (ESP) rather than
  30. # to the current OS X boot partition. Under Linux, this script
  31. # installs to the ESP by default.
  32. #
  33. # This program is copyright (c) 2012-2015 by Roderick W. Smith
  34. #
  35. # This program is licensed under the terms of the GNU GPL, version 3,
  36. # or (at your option) any later version.
  37. # You should have received a copy of the GNU General Public License
  38. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  39.  
  40. # Revision history:
  41. #
  42. # 0.10.4 -- Improved handling of disks (other than /dev/[sh]d? disks).
  43. # 0.10.2 -- Improved Secure Boot detection in Linux, fixed --usedefault in OS X,
  44. # and fixed bug that could cause mountesp to be installed as a FILE
  45. # called /usr/local/bin in OS X.
  46. # 0.10.1 -- Improve extraction of default kernel options from /proc/cmdline.
  47. # Add support for AMD64 (aka AARCH64, aa64) platform. Added
  48. # warning when --alldrivers used without --usedefault.
  49. # 0.10.0 -- Enable running under OS X's recovery system & add warning about
  50. # SIP & brief instructions on how to deal with it if SIP is
  51. # detected to be enabled. Also change way refind_linux.conf default
  52. # options are found; use /proc/cmdline as base.
  53. # 0.9.2 -- Added --keepname option.
  54. # 0.8.7 -- Better detection of Secure Boot mode & fixed errors when copying
  55. # Shim & MokManager files over themselves; fixed bug that caused
  56. # inappropriate installation to EFI/BOOT/bootx64.efi
  57. # 0.8.6 -- Fixed bugs that caused misidentification of ESP on disks with
  58. # partition numbers over 10 on OS X and misidentification of mount
  59. # point if already-mounted ESP had space in path.
  60. # 0.8.5 -- Refinement/cleanup of new OS X ESP-as-default policy
  61. # 0.8.4 -- OS X default changed to install to ESP under /EFI/BOOT
  62. # 0.7.9 -- Fixed bug that caused errors if dmraid utility not installed
  63. # 0.7.7 -- Fixed bug that created mangled refind_linux.conf file; added ability
  64. # to locate and mount ESP on Linux, if it's not mounted
  65. # 0.7.6 -- Added --ownhfs {device-filename} option
  66. # 0.7.5 -- Fixed bug when installing to ESP on recent versions of OS X
  67. # 0.7.2 -- Fixed code that could be confused by use of autofs to mount the ESP
  68. # 0.7.0 -- Added support for the new Btrfs driver
  69. # 0.6.12 -- Added support for PreLoader as well as for shim
  70. # 0.6.11 -- Improvements in script's ability to handle directories with spaces
  71. # in their names
  72. # 0.6.9 -- Install gptsync on Macs
  73. # 0.6.8 -- Bug fix: ESP scan now uses "uniq".
  74. # 0.6.6 -- Bug fix: Upgrade drivers when installed to EFI/BOOT. Also enable
  75. # copying shim.efi and MokManager.efi over themselves.
  76. # 0.6.4 -- Copies ext2 driver rather than ext4 driver for ext2/3fs
  77. # 0.6.3 -- Support for detecting rEFInd in EFI/BOOT and EFI/Microsoft/Boot
  78. # directories & for installing to EFI/BOOT in BIOS mode
  79. # 0.6.2-1 -- Added --yes option & tweaked key-copying for use with RPM install script
  80. # 0.6.1 -- Added --root option; minor bug fixes
  81. # 0.6.0 -- Changed --drivers to --alldrivers and added --nodrivers option;
  82. # changed default driver installation behavior in Linux to install
  83. # the driver needed to read /boot (if available)
  84. # 0.5.1.2 -- Fixed bug that caused failure to generate refind_linux.conf file
  85. # 0.5.1.1 -- Fixed bug that caused script failure under OS X
  86. # 0.5.1 -- Added --shim & --localkeys options & create sample refind_linux.conf
  87. # in /boot
  88. # 0.5.0 -- Added --usedefault & --drivers options & changed "esp" option to "--esp"
  89. # 0.4.5 -- Fixed check for rEFItBlesser in OS X
  90. # 0.4.2 -- Added notice about BIOS-based OSes & made NVRAM changes in Linux smarter
  91. # 0.4.1 -- Added check for rEFItBlesser in OS X
  92. # 0.3.3.1 -- Fixed OS X 10.7 bug; also works as make target
  93. # 0.3.2.1 -- Check for presence of source files; aborts if not present
  94. # 0.3.2 -- Initial version
  95. #
  96. # Note: install.sh version numbers match those of the rEFInd package
  97. # with which they first appeared.
  98.  
  99. RootDir="/"
  100. TargetDir=/EFI/refind
  101. LocalKeysBase="refind_local"
  102. ShimSource="none"
  103. ShimType="none"
  104. KeepName=0
  105. TargetShim="default"
  106. TargetX64="bootx64.efi"
  107. TargetIA32="refind_ia32.efi"
  108. LocalKeys=0
  109. DeleteRefindDir=0
  110. AlwaysYes=0
  111.  
  112. #
  113. # Functions used by both OS X and Linux....
  114. #
  115.  
  116. GetParams() {
  117. InstallToEspOnMac=1
  118. # Install the driver required to read Linux /boot, if it's available
  119. # Note: Under OS X, this will be installed only if a Linux partition
  120. # is detected, in which case the ext4fs driver will be installed.
  121. InstallDrivers="boot"
  122. while [[ $# -gt 0 ]]; do
  123. case $1 in
  124. --notesp) InstallToEspOnMac=0
  125. ;;
  126. --ownhfs) OwnHfs=1
  127. InstallToEspOnMac=0
  128. TargetPart="$2"
  129. TargetDir=/System/Library/CoreServices
  130. shift
  131. ;;
  132. --usedefault) TargetDir=/EFI/BOOT
  133. TargetPart="$2"
  134. TargetX64="bootx64.efi"
  135. TargetIA32="bootia32.efi"
  136. shift
  137. ;;
  138. --root) RootDir="$2"
  139. InstallToEspOnMac=0
  140. shift
  141. ;;
  142. --localkeys) LocalKeys=1
  143. ;;
  144. --shim | --preloader) ShimSource="$2"
  145. ShimType=`basename $ShimSource`
  146. shift
  147. ;;
  148. --keepname) KeepName=1
  149. ;;
  150. --drivers | --alldrivers) InstallDrivers="all"
  151. ;;
  152. --nodrivers) InstallDrivers="none"
  153. ;;
  154. --yes) AlwaysYes=1
  155. ;;
  156. * ) echo "Usage: $0 [--notesp | --usedefault {device-file} | --root {dir} |"
  157. echo " --ownhfs {device-file} ] [--keepname]"
  158. echo " [--nodrivers | --alldrivers]"
  159. echo " [--localkeys] [--keepname] [--yes]"
  160. exit 1
  161. esac
  162. shift
  163. done
  164. if [[ "$InstallToEspOnMac" == 0 && "$RootDir" == '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
  165. echo "You may use --notesp OR --usedefault, but not both! Aborting!"
  166. exit 1
  167. fi
  168. if [[ "$RootDir" != '/' && "$TargetDir" == '/EFI/BOOT' ]] ; then
  169. echo "You may use --root OR --usedefault, but not both! Aborting!"
  170. exit 1
  171. fi
  172. if [[ "$TargetDir" != '/System/Library/CoreServices' && "$OwnHfs" == '1' ]] ; then
  173. echo "If you use --ownhfs, you may NOT use --usedefault! Aborting!"
  174. exit 1
  175. fi
  176. if [[ "$KeepName" == 1 && "$ShimSource" == "none" ]] ; then
  177. echo "The --keepname option is meaningful only in conjunction with --shim"
  178. echo "or --preloader! Aborting!"
  179. exit 1
  180. fi
  181. if [[ "$KeepName" == 1 && "$OSTYPE" != "linux" && "$OSTYPE" != "linux-gnu" ]] ; then
  182. echo "The --keepname option is valid only under Linux! Aborting!"
  183. exit 1
  184. fi
  185. if [[ "$KeepName" == 1 && "$TargetDir" == "/EFI/BOOT" ]] ; then
  186. echo "The --keepname option is incompatible with --usedefault! Aborting!"
  187. exit 1
  188. fi
  189. if [[ "$InstallDrivers" == "all" && "$TargetDir" != "/EFI/BOOT" ]] ; then
  190. echo "The --alldrivers option is meant for creating USB flash drives with (near-)"
  191. echo "universal boot support. Using it on a hard disk partition runs the risk of"
  192. echo "creating serious problems, up to and including rendering your computer"
  193. echo -n "unbootable. Are you SURE you want to proceed (Y/N)? "
  194. ReadYesNo
  195. if [[ "$YesNo" != "Y" && "$YesNo" != "y" ]] ; then
  196. echo "Aborting installation!"
  197. exit 0
  198. fi
  199. fi
  200. RLConfFile="$RootDir/boot/refind_linux.conf"
  201. EtcKeysDir="$RootDir/etc/refind.d/keys"
  202. } # GetParams()
  203.  
  204. # Get a yes/no response from the user and place it in the YesNo variable.
  205. # If the AlwaysYes variable is set to 1, skip the user input and set "Y"
  206. # in the YesNo variable.
  207. ReadYesNo() {
  208. if [[ $AlwaysYes == 1 ]] ; then
  209. YesNo="Y"
  210. echo "Y"
  211. else
  212. read YesNo
  213. fi
  214. }
  215.  
  216. # Determine what CPU type and EFI bit depth we're using.
  217. # Sets Platform global variable to lowercase EFI platform code (currently
  218. # "x64", "ia32", or "aa64") -- the same code used in filenames.
  219. DeterminePlatform() {
  220. local CpuType
  221. case "$OSTYPE" in
  222. darwin*)
  223. CpuType=`ioreg -l -p IODeviceTree | grep firmware-abi | cut -d "\"" -f 4`
  224. if [[ "$CpuType" == EFI32 ]] ; then
  225. Platform="ia32"
  226. else
  227. Platform="x64"
  228. fi
  229. ;;
  230. linux*)
  231. CpuType=`uname -m`
  232. case "$CpuType" in
  233. aarch64)
  234. Platform="aa64"
  235. ;;
  236. x86_64)
  237. Platform="x64"
  238. ;;
  239. i?86)
  240. Platform="ia32"
  241. # If we're in EFI mode, do some sanity checks, and alert the user or even
  242. # abort. Not in BIOS mode, though, since that could be used on an emergency
  243. # disc to try to recover a troubled Linux installation.
  244. if [[ -d /sys/firmware/efi ]] ; then
  245. if [[ "$ShimSource" != "none" && "$TargetDir" != "/BOOT/EFI" ]] ; then
  246. echo ""
  247. echo "CAUTION: shim does not currently supports 32-bit systems, so you should not"
  248. echo "use the --shim option to install on such systems. Aborting!"
  249. echo ""
  250. exit 1
  251. fi
  252. echo
  253. echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based"
  254. echo "computers are VERY RARE. If you've installed a 32-bit version of Linux"
  255. echo "on a 64-bit computer, you should manually install the 64-bit version of"
  256. echo "rEFInd. If you're positive you want to continue with this installation,"
  257. echo "answer 'Y' to the following question..."
  258. echo
  259. echo -n "Are you sure you want to continue (Y/N)? "
  260. ReadYesNo
  261. if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
  262. echo "OK; continuing with the installation..."
  263. else
  264. exit 0
  265. fi
  266. fi # In EFI mode
  267. ;;
  268. *)
  269. echo "Unknown CPU type '$CpuType'; aborting!"
  270. exit 1
  271. ;;
  272. esac # case "$CpuType"....
  273. ;;
  274. *)
  275. echo "Unknown OS; aborting!"
  276. exit 1
  277. ;;
  278. esac # case "$OSTYPE"....
  279. } # DeterminePlatform()
  280.  
  281. # Abort if the rEFInd files can't be found.
  282. # Also sets $ConfFile to point to the configuration file,
  283. # $IconsDir to point to the icons directory,
  284. # $ShimSource to the source of the shim.efi file (if necessary),
  285. # $ThisDir to point to the directory in which this script resides,
  286. # and $RefindDir to point to where the rEFInd binaries live
  287. CheckForFiles() {
  288. # Note: $ThisDir points to real (not symlinked) script home on Linux,
  289. # enabling creating a symlink in /usr/sbin (or wherever); but on OS X,
  290. # "readlink" doesn't do the same thing as under Linux, so the script
  291. # must not be a symlink under OS X.
  292. case "$OSTYPE" in
  293. darwin*)
  294. ThisDir="$( cd -P "${BASH_SOURCE%/*}" && pwd )"
  295. ;;
  296. linux*)
  297. ThisDir="$(dirname "$(readlink -f "$0")")"
  298. ;;
  299. esac
  300. RefindDir="$ThisDir/refind"
  301.  
  302. if [[ ! -f "$RefindDir/refind_$Platform.efi" ]] ; then
  303. echo "The rEFInd binary file is missing! Aborting installation!"
  304. exit 1
  305. fi
  306.  
  307. if [[ -f "$RefindDir/refind.conf-sample" ]] ; then
  308. ConfFile="$RefindDir/refind.conf-sample"
  309. elif [[ -f "$ThisDir/refind.conf-sample" ]] ; then
  310. ConfFile="$ThisDir/refind.conf-sample"
  311. else
  312. echo "The sample configuration file is missing! Aborting installation!"
  313. exit 1
  314. fi
  315.  
  316. if [[ -d "$RefindDir/icons" ]] ; then
  317. IconsDir="$RefindDir/icons"
  318. elif [[ -d "$ThisDir/icons" ]] ; then
  319. IconsDir="$ThisDir/icons"
  320. else
  321. echo "The icons directory is missing! Aborting installation!"
  322. exit 1
  323. fi
  324.  
  325. echo "ShimSource is $ShimSource"
  326. if [[ "$ShimSource" != "none" ]] ; then
  327. if [[ -f "$ShimSource" ]] ; then
  328. if [[ $ShimType == "shimx64.efi" || $ShimType == "shim.efi" ]] ; then
  329. TargetX64="grubx64.efi"
  330. TargetAARCH64="grubaa64.efi"
  331. MokManagerSource=`dirname "$ShimSource"`/MokManager.efi
  332. elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
  333. TargetX64="loader.efi"
  334. MokManagerSource=`dirname "$ShimSource"`/HashTool.efi
  335. else
  336. echo "Unknown shim/PreBootloader filename: $ShimType!"
  337. echo "Known filenames are shimx64.efi, shim.efi, and PreLoader.efi. Aborting!"
  338. exit 1
  339. fi
  340. else
  341. echo "The specified shim/PreBootloader file, $ShimSource, doesn't exist!"
  342. echo "Aborting installation!"
  343. exit 1
  344. fi
  345. fi
  346. } # CheckForFiles()
  347.  
  348. # Helper for CopyRefindFiles; copies shim files (including MokManager, if it's
  349. # available) to target.
  350. CopyShimFiles() {
  351. local inode1=`ls -i "$ShimSource" 2> /dev/null | cut -f 1 -d " "`
  352. local inode2=`ls -i "$InstallDir/$TargetDir/$TargetShim" 2> /dev/null | cut -f 1 -d " "`
  353. if [[ $inode1 != $inode2 ]] ; then
  354. cp -fb "$ShimSource" "$InstallDir/$TargetDir/$TargetShim"
  355. if [[ $? != 0 ]] ; then
  356. Problems=1
  357. fi
  358. fi
  359. inode1=`ls -i "$MokManagerSource" 2> /dev/null | cut -f 1 -d " "`
  360. local TargetMMName=`basename $MokManagerSource`
  361. inode2=`ls -i "$InstallDir/$TargetDir/$TargetMMName" 2> /dev/null | cut -f 1 -d " "`
  362. if [[ $inode1 != $inode2 ]] ; then
  363. if [[ -f "$MokManagerSource" ]] ; then
  364. cp -fb "$MokManagerSource" "$InstallDir/$TargetDir/"
  365. fi
  366. if [[ $? != 0 ]] ; then
  367. Problems=1
  368. fi
  369. fi
  370. } # CopyShimFiles()
  371.  
  372. # Copy the public keys to the installation medium
  373. CopyKeys() {
  374. if [[ $LocalKeys == 1 ]] ; then
  375. mkdir -p "$InstallDir/$TargetDir/keys/"
  376. cp "$EtcKeysDir/$LocalKeysBase.cer" "$InstallDir/$TargetDir/keys/"
  377. cp "$EtcKeysDir/$LocalKeysBase.crt" "$InstallDir/$TargetDir/keys/"
  378. fi
  379. } # CopyKeys()
  380.  
  381. # Set varaibles for installation in EFI/BOOT directory
  382. SetVarsForBoot() {
  383. TargetDir="/EFI/BOOT"
  384. if [[ $ShimSource == "none" ]] ; then
  385. TargetX64="bootx64.efi"
  386. TargetIA32="bootia32.efi"
  387. TargetAARCH64="bootaa64.efi"
  388. else
  389. if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType = "shimaa64.efi" ]] ; then
  390. TargetX64="grubx64.efi"
  391. TargetAARCH64="grubaa64.efi"
  392. elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
  393. TargetX64="loader.efi"
  394. else
  395. echo "Unknown shim/PreBootloader type: $ShimType"
  396. echo "Aborting!"
  397. exit 1
  398. fi
  399. TargetIA32="bootia32.efi"
  400. TargetShim="boot$Platform.efi"
  401. fi
  402. if [[ $KeepName == 1 ]] ; then
  403. echo "Installation is to /EFI/BOOT, which is incompatible with --keepname! Aborting!"
  404. exit 1
  405. fi
  406. } # SetVarsForBoot()
  407.  
  408. # Set variables for installation in EFI/Microsoft/Boot directory
  409. SetVarsForMsBoot() {
  410. TargetDir="/EFI/Microsoft/Boot"
  411. if [[ $ShimSource == "none" ]] ; then
  412. TargetX64="bootmgfw.efi"
  413. TargetIA32="bootmgfw.efi"
  414. TargetAARCH64="bootmgfw.efi"
  415. else
  416. if [[ $ShimType == "shim.efi" || $ShimType == "shimx64.efi" || $ShimType == "shimaa64.efi" ]] ; then
  417. TargetX64="grubx64.efi"
  418. TargetAARCH64="grubaa64.efi"
  419. elif [[ $ShimType == "preloader.efi" || $ShimType == "PreLoader.efi" ]] ; then
  420. TargetX64="loader.efi"
  421. else
  422. echo "Unknown shim/PreBootloader type: $ShimType"
  423. echo "Aborting!"
  424. exit 1
  425. fi
  426. TargetShim="bootmgfw.efi"
  427. fi
  428. if [[ $KeepName == 1 ]] ; then
  429. echo "Installation is to /EFI/Microsoft/Boot, which is incompatible with --keepname!"
  430. echo "Aborting!"
  431. exit 1
  432. fi
  433. } # SetVarsForMsBoot()
  434.  
  435. # TargetDir defaults to /EFI/refind; however, this function adjusts it as follows:
  436. # - If an existing refind.conf is available in /EFI/BOOT or /EFI/Microsoft/Boot,
  437. # install to that directory under the suitable name; but DO NOT do this if
  438. # refind.conf is also in /EFI/refind.
  439. # - If booted in BIOS mode and the ESP lacks any other EFI files, install to
  440. # /EFI/BOOT
  441. # - If booted in BIOS mode and there's no refind.conf file and there is a
  442. # /EFI/Microsoft/Boot/bootmgfw.efi file, move it down one level and
  443. # install under that name, "hijacking" the Windows boot loader filename
  444. DetermineTargetDir() {
  445. Upgrade=0
  446.  
  447. if [[ -f $InstallDir/EFI/BOOT/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then
  448. SetVarsForBoot
  449. Upgrade=1
  450. fi
  451. if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf && ! -f $InstallDir/EFI/refind/refind.conf ]] ; then
  452. SetVarsForMsBoot
  453. Upgrade=1
  454. fi
  455. if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then
  456. TargetDir="/EFI/refind"
  457. if [[ $ShimSource == "none" || $KeepName == 1 ]] ; then
  458. TargetX64="refind_x64.efi"
  459. TargetIA32="refind_ia32.efi"
  460. TargetAARCH64="refind_aa64.efi"
  461. fi
  462. Upgrade=1
  463. fi
  464. if [[ $Upgrade == 1 ]] ; then
  465. echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it."
  466. fi
  467.  
  468. if [[ ! -d /sys/firmware/efi && ! $OSTYPE == darwin* && $Upgrade == 0 ]] ; then # BIOS-mode
  469. FoundEfiFiles=`find "$InstallDir/EFI/BOOT" -name "*.efi" 2> /dev/null`
  470. FoundConfFiles=`find "$InstallDir" -name "refind\.conf" 2> /dev/null`
  471. if [[ ! -n "$FoundConfFiles" && -f "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" ]] ; then
  472. mv -n "$InstallDir/EFI/Microsoft/Boot/bootmgfw.efi" "$InstallDir/EFI/Microsoft" &> /dev/null
  473. SetVarsForMsBoot
  474. echo "Running in BIOS mode with a suspected Windows installation; moving boot loader"
  475. echo "files so as to install to $InstallDir$TargetDir."
  476. elif [[ ! -n "$FoundEfiFiles" ]] ; then # In BIOS mode and no default loader; install as default loader
  477. SetVarsForBoot
  478. echo "Running in BIOS mode with no existing default boot loader; installing to"
  479. echo $InstallDir$TargetDir
  480. else
  481. echo "Running in BIOS mode with an existing default boot loader; backing it up and"
  482. echo "installing rEFInd in its place."
  483. if [[ -d "$InstallDir/EFI/BOOT-rEFIndBackup" ]] ; then
  484. echo ""
  485. echo "Caution: An existing backup of a default boot loader exists! If the current"
  486. echo "default boot loader and the backup are different boot loaders, the current"
  487. echo "one will become inaccessible."
  488. echo ""
  489. echo -n "Do you want to proceed with installation (Y/N)? "
  490. ReadYesNo
  491. if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
  492. echo "OK; continuing with the installation..."
  493. else
  494. exit 0
  495. fi
  496. fi
  497. mv -n "$InstallDir/EFI/BOOT" "$InstallDir/EFI/BOOT-rEFIndBackup"
  498. SetVarsForBoot
  499. fi
  500. fi # BIOS-mode
  501. } # DetermineTargetDir()
  502.  
  503. # Determine (or guess) the filesystem used on the Linux /boot filesystem.
  504. # Store the result in the BootFS global variable.
  505. SetBootFS() {
  506. BootFS=""
  507. case "$OSTYPE" in
  508. linux*)
  509. if command -v blkid &>/dev/null; then
  510. BootPart=`df $RootDir/boot | grep dev | cut -f 1 -d " "`
  511. BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
  512. fi
  513. ;;
  514. darwin*)
  515. # 0FC63DAF-8483-4772-8E79-3D69D8477DE4 = Linux filesystem
  516. # BC13C2FF-59E6-4262-A352-B275FD6F7172 = Freedesktop $boot partition
  517. # 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 = Freedesktop Linux /home
  518. # E6D6D379-F507-44C2-A23C-238F2A3DF928 = Linux LVM
  519. # A19D880F-05FC-4D3B-A006-743F0F84911E = Linux RAID
  520. # 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F = Linux swap
  521. 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')
  522. BootFS=""
  523. if [[ -n $Temp ]] ; then
  524. echo "Found suspected Linux partition(s); installing ext4fs driver."
  525. BootFS="ext4"
  526. fi
  527. ;;
  528. esac
  529. } # SetBootFS()
  530.  
  531. # Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1,
  532. # honoring the $InstallDrivers condition. Must be passed a suitable
  533. # architecture code (ia32 or x64).
  534. CopyDrivers() {
  535. if [[ $InstallDrivers == "all" ]] ; then
  536. mkdir -p "$InstallDir/$TargetDir/drivers_$1"
  537. cp "$ThisDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
  538. cp "$RefindDir"/drivers_$1/*_$1.efi "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
  539. elif [[ "$InstallDrivers" == "boot" ]] ; then
  540. SetBootFS
  541. DriverType=""
  542. case $BootFS in
  543. ext2 | ext3) DriverType="ext2"
  544. # Could use ext4, but that can create unwanted entries from symbolic
  545. # links in / to /boot/vmlinuz if a separate /boot partition is used.
  546. ;;
  547. ext4) DriverType="ext4"
  548. ;;
  549. reiserfs) DriverType="reiserfs"
  550. ;;
  551. btrfs) DriverType="btrfs"
  552. ;;
  553. hfsplus) DriverType="hfs"
  554. ;;
  555. ntfs) DriverType="ntfs"
  556. ;;
  557. *) BootFS=""
  558. esac
  559. if [[ -n $BootFS ]] ; then
  560. echo "Installing driver for $BootFS (${DriverType}_$1.efi)"
  561. mkdir -p "$InstallDir/$TargetDir/drivers_$1"
  562. cp "$ThisDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1/" 2> /dev/null
  563. cp "$RefindDir/drivers_$1/${DriverType}_$1.efi" "$InstallDir/$TargetDir/drivers_$1"/ 2> /dev/null
  564. fi
  565. fi
  566. } # CopyDrivers()
  567.  
  568. # Copy tools (currently only gptsync, and that only on Macs) to the EFI/tools
  569. # directory on the ESP. Must be passed a suitable architecture code (ia32
  570. # or x64).
  571. CopyTools() {
  572. mkdir -p "$InstallDir/EFI/tools"
  573. if [[ $OSTYPE == darwin* ]] ; then
  574. cp -f "$RefindDir/tools_$1/gptsync_$1.efi" "$InstallDir/EFI/tools/"
  575. if [[ -f "$InstallDir/EFI/tools/gptsync.efi" ]] ; then
  576. mv "$InstallDir/EFI/tools/gptsync.efi" "$InstallDir/EFI/tools/gptsync.efi-disabled"
  577. echo "Found old gptsync.efi; disabling it by renaming it to gptsync.efi-disabled"
  578. fi
  579. fi
  580. } # CopyTools()
  581.  
  582. # Copy the rEFInd files to the ESP or OS X root partition.
  583. # Sets Problems=1 if any critical commands fail.
  584. CopyRefindFiles() {
  585. mkdir -p "$InstallDir/$TargetDir"
  586. if [[ "$TargetDir" == '/EFI/BOOT' ]] ; then
  587. cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32" 2> /dev/null
  588. if [[ $? != 0 ]] ; then
  589. echo "Note: IA32 (x86) binary not installed!"
  590. fi
  591. cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64" 2> /dev/null
  592. if [[ $? != 0 ]] ; then
  593. Problems=1
  594. fi
  595. cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64" 2> /dev/null
  596. if [[ $? != 0 && $Platform == "aa64" ]] ; then
  597. Problems=1
  598. fi
  599. if [[ "$ShimSource" != "none" ]] ; then
  600. TargetShim="bootx64.efi"
  601. CopyShimFiles
  602. fi
  603. if [[ $InstallDrivers == "all" ]] ; then
  604. cp -r "$RefindDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
  605. cp -r "$ThisDir"/drivers_* "$InstallDir/$TargetDir/" 2> /dev/null
  606. elif [[ $Upgrade == 1 || $InstallToEspOnMac == 1 ]] ; then
  607. CopyDrivers "$Platform"
  608. CopyTools "$Platform"
  609. fi
  610. Refind="boot$Platform.efi"
  611. CopyKeys
  612. elif [[ $Platform == 'x64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then
  613. cp "$RefindDir/refind_x64.efi" "$InstallDir/$TargetDir/$TargetX64"
  614. if [[ $? != 0 ]] ; then
  615. Problems=1
  616. fi
  617. CopyDrivers x64
  618. CopyTools x64
  619. Refind="refind_x64.efi"
  620. CopyKeys
  621. if [[ "$ShimSource" != "none" ]] ; then
  622. if [[ "$TargetShim" == "default" ]] ; then
  623. TargetShim=`basename "$ShimSource"`
  624. fi
  625. CopyShimFiles
  626. Refind="$TargetShim"
  627. if [[ $LocalKeys == 0 ]] ; then
  628. echo "Storing copies of rEFInd Secure Boot public keys in $EtcKeysDir"
  629. mkdir -p "$EtcKeysDir"
  630. cp "$ThisDir/keys/refind.cer" "$EtcKeysDir" 2> /dev/null
  631. cp "$ThisDir/keys/refind.crt" "$EtcKeysDir" 2> /dev/null
  632. fi
  633. fi
  634. if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then
  635. SetupMacHfs $TargetX64
  636. fi
  637. elif [[ $Platform == 'ia32' || $Platform == 'aa64' ]] ; then
  638. if [[ $Platform == 'ia32' ]] ; then
  639. cp "$RefindDir/refind_ia32.efi" "$InstallDir/$TargetDir/$TargetIA32"
  640. if [[ $? != 0 ]] ; then
  641. Problems=1
  642. fi
  643. else
  644. cp "$RefindDir/refind_aa64.efi" "$InstallDir/$TargetDir/$TargetAARCH64"
  645. if [[ $? != 0 ]] ; then
  646. Problems=1
  647. fi
  648. fi
  649. CopyDrivers $Platform
  650. CopyTools $Platform
  651. Refind="refind_$Platform.efi"
  652. if [[ "$TargetDir" == '/System/Library/CoreServices' ]] ; then
  653. SetupMacHfs $TargetIA32
  654. fi
  655. else
  656. echo "Unknown platform! Aborting!"
  657. exit 1
  658. fi
  659. echo "Copied rEFInd binary files"
  660. echo ""
  661. if [[ -d "$InstallDir/$TargetDir/icons" ]] ; then
  662. rm -rf "$InstallDir/$TargetDir/icons-backup" &> /dev/null
  663. mv -f "$InstallDir/$TargetDir/icons" "$InstallDir/$TargetDir/icons-backup"
  664. echo "Notice: Backed up existing icons directory as icons-backup."
  665. fi
  666. cp -r "$IconsDir" "$InstallDir/$TargetDir"
  667. if [[ $? != 0 ]] ; then
  668. Problems=1
  669. fi
  670. mkdir -p "$InstallDir/$TargetDir/keys"
  671. cp -rf "$ThisDir"/keys/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null
  672. cp -rf "$EtcKeysDir"/*.[cd]er "$InstallDir/$TargetDir/keys/" 2> /dev/null
  673. if [[ -f "$InstallDir/$TargetDir/refind.conf" ]] ; then
  674. echo "Existing refind.conf file found; copying sample file as refind.conf-sample"
  675. echo "to avoid overwriting your customizations."
  676. echo ""
  677. cp -f "$ConfFile" "$InstallDir/$TargetDir"
  678. if [[ $? != 0 ]] ; then
  679. Problems=1
  680. fi
  681. else
  682. echo "Copying sample configuration file as refind.conf; edit this file to configure"
  683. echo "rEFInd."
  684. echo ""
  685. cp -f "$ConfFile" "$InstallDir/$TargetDir/refind.conf"
  686. if [[ $? != 0 ]] ; then
  687. Problems=1
  688. fi
  689. fi
  690. if [[ $DeleteRefindDir == 1 ]] ; then
  691. echo "Deleting the temporary directory $RefindDir"
  692. rm -r "$RefindDir"
  693. fi
  694. } # CopyRefindFiles()
  695.  
  696. # Mount the partition the user specified with the --usedefault or --ownhfs option
  697. MountDefaultTarget() {
  698. InstallDir=/tmp/refind_install
  699. mkdir -p "$InstallDir"
  700. UnmountEsp=1
  701. if [[ $OSTYPE == darwin* ]] ; then
  702. if [[ $OwnHfs == '1' ]] ; then
  703. Temp=`diskutil info "$TargetPart" | grep "Mount Point"`
  704. InstallDir=`echo $Temp | cut -f 3-30 -d ' '`
  705. if [[ $InstallDir == '' ]] ; then
  706. InstallDir=/tmp/refind_install
  707. mount -t hfs "$TargetPart" "$InstallDir"
  708. else
  709. UnmountEsp=0
  710. fi
  711. else
  712. mount -t msdos "$TargetPart" "$InstallDir"
  713. fi
  714. elif [[ $OSTYPE == linux* ]] ; then
  715. mount -t vfat "$TargetPart" "$InstallDir"
  716. fi
  717. if [[ $? != 0 ]] ; then
  718. echo "Couldn't mount $TargetPart ! Aborting!"
  719. rmdir "$InstallDir"
  720. exit 1
  721. fi
  722. } # MountDefaultTarget()
  723.  
  724. #
  725. # A series of OS X support functions....
  726. #
  727.  
  728. # Mount the ESP at /Volumes/ESP or determine its current mount
  729. # point.
  730. # Sets InstallDir to the ESP mount point
  731. # Sets UnmountEsp if we mounted it
  732. MountOSXESP() {
  733. # Identify the ESP. Note: This returns the FIRST ESP found;
  734. # if the system has multiple disks, this could be wrong!
  735. Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p")
  736. if [ $Temp ]; then
  737. Temp=$(diskutil list | grep " EFI " | grep -o 'disk.*' | head -n 1)
  738. if [ -z $Temp ]; then
  739. echo "Warning: root device doesn't have an EFI partition"
  740. fi
  741. else
  742. echo "Warning: root device could not be found"
  743. fi
  744. if [ -z $Temp ]; then
  745. Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p
  746. q
  747. }' )
  748.  
  749. if [ -z $Temp ]; then
  750. echo "Could not find an EFI partition. Aborting!"
  751. exit 1
  752. fi
  753. fi
  754. Esp=/dev/`echo $Temp`
  755. # If the ESP is mounted, use its current mount point....
  756. Temp=`df -P | grep "$Esp "`
  757. InstallDir=`echo $Temp | cut -f 6- -d ' '`
  758. if [[ "$InstallDir" == '' ]] ; then
  759. mkdir /Volumes/ESP &> /dev/null
  760. mount -t msdos "$Esp" /Volumes/ESP
  761. # Some systems have HFS+ "ESPs." They shouldn't, but they do. If this is
  762. # detected, mount it as such and set appropriate options.
  763. if [[ $? != 0 ]] ; then
  764. mount -t hfs "$Esp" /Volumes/Esp
  765. OwnHfs=1
  766. InstallToEspOnMac=0
  767. if [[ $? != 0 ]] ; then
  768. echo "Unable to mount ESP! Aborting!\n"
  769. exit 1
  770. fi
  771. fi
  772. UnmountEsp=1
  773. InstallDir="/Volumes/ESP"
  774. fi
  775. } # MountOSXESP()
  776.  
  777. # Set up for booting from Mac HFS+ volume that boots rEFInd in MJG's way
  778. # (http://mjg59.dreamwidth.org/7468.html)
  779. # Must be passed the original rEFInd binary filename (without a path).
  780. SetupMacHfs() {
  781. if [[ -s "$InstallDir/mach_kernel" ]] ; then
  782. echo "Attempt to install rEFInd to a partition with a /mach_kernel file! Aborting!"
  783. exit 1
  784. fi
  785. cp -n "$InstallDir/$TargetDir/boot.efi" "$InstallDir/$TargetDir/boot.efi-backup" &> /dev/null
  786. ln -f "$InstallDir/$TargetDir/$1" "$InstallDir/$TargetDir/boot.efi"
  787. touch "$InstallDir/mach_kernel"
  788. rm "$InstallDir/$TargetDir/SystemVersion.plist" &> /dev/null
  789. cat - << ENDOFHERE >> "$InstallDir/$TargetDir/SystemVersion.plist"
  790. <xml version="1.0" encoding="UTF-8"?>
  791. <plist version="1.0">
  792. <dict>
  793. <key>ProductBuildVersion</key>
  794. <string></string>
  795. <key>ProductName</key>
  796. <string>rEFInd</string>
  797. <key>ProductVersion</key>
  798. <string>0.10.4</string>
  799. </dict>
  800. </plist>
  801. ENDOFHERE
  802. } # SetupMacHfs()
  803.  
  804. CheckForSIP() {
  805. if [[ -x "/usr/bin/csrutil" && -z "$TargetPart" ]] ; then
  806. local OKToInstall=`/usr/bin/csrutil status | \
  807. grep "Protection status: disabled\|enabled (Apple Internal)\|NVRAM Protections: disabled"`
  808. if [[ -z "$OKToInstall" ]] ; then
  809. echo
  810. echo "**** ALERT: SIP ENABLED! ****"
  811. echo
  812. if [[ "$Upgrade" == "1" ]] ; then
  813. echo "You are attempting to upgrade an existing installation, but it appears that"
  814. echo "System Integrity Protection (SIP) is enabled. If rEFInd is working now, then"
  815. echo "this is fine; you can upgrade your existing rEFInd. If rEFInd is not working,"
  816. echo "though, re-installing from this boot will not help. To re-enable rEFInd, you"
  817. echo "must re-install it from a Recovery system or from another OS. To enter the"
  818. echo "Recovery system and re-install rEFInd:"
  819. else
  820. echo "rEFInd cannot be installed because System Integrity Protection (SIP) seems"
  821. echo "to be enabled! You must install rEFInd from your Recovery installation or"
  822. echo "from another OS. To install from the Recovery system:"
  823. fi
  824. echo
  825. echo " 1. Reboot"
  826. echo " 2. Hold down Command+R as the chime sounds"
  827. echo " 3. When the OS has booted, select Utilities->Terminal"
  828. echo " 4. Change to this directory with the 'cd' command; it will probably be under"
  829. if [[ "`pwd | cut -b 1-8`" == "/Volumes" ]] ; then
  830. echo " `pwd`"
  831. else
  832. local RootName=`diskutil info -plist / | grep -A 1 VolumeName | grep string | cut -d \> -f 2 | cut -d \< -f 1`
  833. echo " /Volumes/$RootName`pwd`"
  834. fi
  835. echo " 5. Re-run this script."
  836. echo
  837. if [[ "$Upgrade" != "1" ]] ; then
  838. echo "If you believe SIP is NOT enabled, you may attempt an installation anyhow,"
  839. echo "but it may fail."
  840. echo
  841. fi
  842. echo "For more on this subject, see http://www.rodsbooks.com/refind/sip.html"
  843. echo
  844. echo -n "Do you want to attempt installation (Y/N)? "
  845. ReadYesNo
  846. if [[ $YesNo == "N" || $YesNo == "n" ]] ; then
  847. echo "Exiting!"
  848. exit
  849. fi
  850. fi # csrutil status suggests OK to install
  851. fi # csrutil exists
  852. } # CheckForSIP()
  853.  
  854. # Control the OS X installation.
  855. # Sets Problems=1 if problems found during the installation.
  856. InstallOnOSX() {
  857. echo "Installing rEFInd on OS X...."
  858. if [[ "$InstallToEspOnMac" == "1" && -z "$TargetPart" ]] ; then
  859. MountOSXESP
  860. elif [[ "$TargetDir" == "/EFI/BOOT" || "$OwnHfs" == '1' ]] ; then
  861. MountDefaultTarget
  862. else
  863. InstallDir="$RootDir/"
  864. fi
  865. echo "Installing rEFInd to the partition mounted at $InstallDir"
  866. DetermineTargetDir
  867. CheckForSIP
  868. CopyRefindFiles
  869. mkdir -p /usr/local/bin &> /dev/null
  870. cp "$ThisDir/mountesp" /usr/local/bin/ &> /dev/null
  871. if [[ $InstallToEspOnMac == "1" && -z "$TargetPart" ]] ; then
  872. bless --mount "$InstallDir" --setBoot --file "$InstallDir/$TargetDir/$Refind" --shortform
  873. elif [[ "$TargetDir" != "/EFI/BOOT" ]] ; then
  874. bless --setBoot --folder "$InstallDir/$TargetDir" --file "$InstallDir/$TargetDir/$Refind"
  875. fi
  876. if [[ $? != 0 ]] ; then
  877. Problems=1
  878. fi
  879. if [[ -f /Library/StartupItems/rEFItBlesser || -d /Library/StartupItems/rEFItBlesser ]] ; then
  880. echo
  881. echo "/Library/StartupItems/rEFItBlesser found!"
  882. echo "This program is part of rEFIt, and will cause rEFInd to fail to work after"
  883. echo -n "its first boot. Do you want to remove rEFItBlesser (Y/N)? "
  884. ReadYesNo
  885. if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
  886. echo "Deleting /Library/StartupItems/rEFItBlesser..."
  887. rm -r /Library/StartupItems/rEFItBlesser
  888. else
  889. echo "Not deleting rEFItBlesser."
  890. fi
  891. fi
  892. } # InstallOnOSX()
  893.  
  894.  
  895. #
  896. # Now a series of Linux support functions....
  897. #
  898.  
  899. # Check for evidence that we're running in Secure Boot mode. If so, and if
  900. # appropriate options haven't been set, warn the user and offer to abort.
  901. # If we're NOT in Secure Boot mode but the user HAS specified the --shim
  902. # or --localkeys option, warn the user and offer to abort.
  903. CheckSecureBoot() {
  904. IsSecureBoot="0"
  905. if [[ -f /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c ]] ; then
  906. IsSecureBoot=`od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c | awk '{print substr($0,length,1)}'`
  907. elif [[ -f /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data ]] ; then
  908. IsSecureBoot=`od -An -t u1 /sys/firmware/efi/vars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data | tr -d '[[:space:]]'`
  909. fi
  910. if [[ $IsSecureBoot == "1" && "$TargetDir" != '/EFI/BOOT' && "$ShimSource" == "none" ]] ; then
  911. echo ""
  912. echo "CAUTION: Your computer appears to be booted with Secure Boot, but you haven't"
  913. echo "specified a valid shim.efi file source. Chances are you should re-run with"
  914. echo "the --shim option. You can read more about this topic at"
  915. echo "http://www.rodsbooks.com/refind/secureboot.html."
  916. echo ""
  917. echo -n "Do you want to proceed with installation (Y/N)? "
  918. ReadYesNo
  919. if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
  920. echo "OK; continuing with the installation..."
  921. else
  922. exit 0
  923. fi
  924. fi
  925.  
  926. if [[ "$ShimSource" != "none" && ! $IsSecureBoot == "1" ]] ; then
  927. echo ""
  928. echo "You've specified installing using a shim.efi file, but your computer does not"
  929. echo "appear to be running in Secure Boot mode. Although installing in this way"
  930. echo "should work, it's unnecessarily complex. You may continue, but unless you"
  931. echo "plan to enable Secure Boot, you should consider stopping and omitting the"
  932. echo "--shim option. You can read more about this topic at"
  933. echo "http://www.rodsbooks.com/refind/secureboot.html."
  934. echo ""
  935. echo -n "Do you want to proceed with installation (Y/N)? "
  936. ReadYesNo
  937. if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
  938. echo "OK; continuing with the installation..."
  939. else
  940. exit 0
  941. fi
  942. fi
  943.  
  944. if [[ $LocalKeys != 0 && ! $IsSecureBoot == "1" ]] ; then
  945. echo ""
  946. echo "You've specified re-signing your rEFInd binaries with locally-generated keys,"
  947. echo "but your computer does not appear to be running in Secure Boot mode. The"
  948. echo "keys you generate will be useless unless you enable Secure Boot. You may"
  949. echo "proceed with this installation, but before you do so, you may want to read"
  950. echo "more about it at http://www.rodsbooks.com/refind/secureboot.html."
  951. echo ""
  952. echo -n "Do you want to proceed with installation (Y/N)? "
  953. ReadYesNo
  954. if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
  955. echo "OK; continuing with the installation..."
  956. else
  957. exit 0
  958. fi
  959. fi
  960.  
  961. } # CheckSecureBoot()
  962.  
  963. # Check for the presence of locally-generated keys from a previous installation in
  964. # $EtcKeysDir (/etc/refind.d/keys). If they're not present, generate them using
  965. # openssl.
  966. GenerateKeys() {
  967. PrivateKey="$EtcKeysDir/$LocalKeysBase.key"
  968. CertKey="$EtcKeysDir/$LocalKeysBase.crt"
  969. DerKey="$EtcKeysDir/$LocalKeysBase.cer"
  970. OpenSSL=`which openssl 2> /dev/null`
  971.  
  972. # Do the work only if one or more of the necessary keys is missing
  973. # TODO: Technically, we don't need the DerKey; but if it's missing and openssl
  974. # is also missing, this will fail. This could be improved.
  975. if [[ ! -f "$PrivateKey" || ! -f "$CertKey" || ! -f "$DerKey" ]] ; then
  976. echo "Generating a fresh set of local keys...."
  977. mkdir -p "$EtcKeysDir"
  978. chmod 0700 "$EtcKeysDir"
  979. if [[ ! -x "$OpenSSL" ]] ; then
  980. echo "Can't find openssl, which is required to create your private signing keys!"
  981. echo "Aborting!"
  982. exit 1
  983. fi
  984. if [[ -f "$PrivateKey" ]] ; then
  985. echo "Backing up existing $PrivateKey"
  986. cp -f "$PrivateKey" "$PrivateKey.backup" 2> /dev/null
  987. fi
  988. if [[ -f "$CertKey" ]] ; then
  989. echo "Backing up existing $CertKey"
  990. cp -f "$CertKey" "$CertKey.backup" 2> /dev/null
  991. fi
  992. if [[ -f "$DerKey" ]] ; then
  993. echo "Backing up existing $DerKey"
  994. cp -f "$DerKey" "$DerKey.backup" 2> /dev/null
  995. fi
  996. "$OpenSSL" req -new -x509 -newkey rsa:2048 -keyout "$PrivateKey" -out "$CertKey" \
  997. -nodes -days 3650 -subj "/CN=Locally-generated rEFInd key/"
  998. "$OpenSSL" x509 -in "$CertKey" -out "$DerKey" -outform DER
  999. chmod 0600 "$PrivateKey"
  1000. else
  1001. echo "Using existing local keys...."
  1002. fi
  1003. }
  1004.  
  1005. # Sign a single binary. Requires parameters:
  1006. # $1 = source file
  1007. # $2 = destination file
  1008. # Also assumes that the SBSign and various key variables are set appropriately.
  1009. # Aborts script on error
  1010. SignOneBinary() {
  1011. $SBSign --key "$PrivateKey" --cert "$CertKey" --output "$2" "$1" 2>&1 >/dev/null | \
  1012. grep -v "data remaining.*gaps between PE/COFF sections"
  1013. if [[ "${PIPESTATUS[0]}" != 0 ]] ; then
  1014. echo "Problem signing the binary $1! Aborting!"
  1015. exit 1
  1016. fi
  1017. }
  1018.  
  1019. # Re-sign the x86-64 binaries with a locally-generated key, First look for appropriate
  1020. # key files in $EtcKeysDir. If they're present, use them to re-sign the binaries. If
  1021. # not, try to generate new keys and store them in $EtcKeysDir.
  1022. ReSignBinaries() {
  1023. SBSign=`which sbsign 2> /dev/null`
  1024. echo "Found sbsign at $SBSign"
  1025. TempDir="/tmp/refind_local"
  1026. if [[ ! -x "$SBSign" ]] ; then
  1027. echo "Can't find sbsign, which is required to sign rEFInd with your own keys!"
  1028. echo "Aborting!"
  1029. exit 1
  1030. fi
  1031. GenerateKeys
  1032. mkdir -p "$TempDir/drivers_$Platform"
  1033. cp "$RefindDir/refind.conf-sample $TempDir" 2> /dev/null
  1034. cp "$ThisDir/refind.conf-sample $TempDir" 2> /dev/null
  1035. cp "$RefindDir/refind_ia32.efi $TempDir" 2> /dev/null
  1036. cp -a "$RefindDir/drivers_ia32 $TempDir" 2> /dev/null
  1037. cp -a "$ThisDir/drivers_ia32 $TempDir" 2> /dev/null
  1038. SignOneBinary "$RefindDir/refind_$Platform.efi" "$TempDir/refind_$Platform.efi"
  1039. SaveIFS=$IFS
  1040. IFS=$(echo -en "\n\b")
  1041. for Driver in `ls "$RefindDir"/drivers_$Platform/*.efi "$ThisDir"/drivers_$Platform/*.efi 2> /dev/null` ; do
  1042. TempName=`basename "$Driver"`
  1043. SignOneBinary "$Driver" "$TempDir/drivers_$Platform/$TempName"
  1044. done
  1045. IFS=$SaveIFS
  1046. RefindDir="$TempDir"
  1047. DeleteRefindDir=1
  1048. } # ReSignBinaries()
  1049.  
  1050. # Locate and mount an ESP, if possible, based on parted output.
  1051. # Should be called only if /boot/efi is NOT an acceptable ESP.
  1052. # Sets InstallDir to the mounted ESP's path ($RootDir/boot/efi)
  1053. # and EspFilesystem the filesystem (always "vfat")
  1054. FindLinuxESP() {
  1055. echo "The ESP doesn't seem to be mounted! Trying to find it...."
  1056. local Name
  1057. local Drive
  1058. local PartNum
  1059. local TableType
  1060. local DmStatus
  1061. local SkipIt
  1062. local Dmraid
  1063. for Name in `lsblk -r | grep disk | cut -f 1 -d " "` ; do
  1064. Drive="/dev/$Name"
  1065. SkipIt=0
  1066. Dmraid=`which dmraid 2> /dev/null`
  1067. if [ -x "$Dmraid" ] ; then
  1068. DmStatus=`dmraid -r | grep $Drive`
  1069. if [ -n "$DmStatus" ] ; then
  1070. echo "$Drive seems to be part of a RAID array; skipping!"
  1071. SkipIt=1
  1072. fi
  1073. fi
  1074. TableType=`parted $Drive print -m -s 2>/dev/null | awk -F: '$1 == "'$Drive'" { print $6 }'`
  1075. if [[ $TableType == 'gpt' && $SkipIt == 0 ]] ; then # read only GPT disks that aren't part of dmraid array
  1076. PartNum=`LANG=C parted $Drive print -m -s 2>/dev/null | awk -F: '$7 ~ "(^boot| boot)" { print $1 }' | head -n 1`
  1077. if [ "$PartNum" -eq "$PartNum" ] 2> /dev/null ; then
  1078. InstallDir="$RootDir/boot/efi"
  1079. mkdir -p $InstallDir
  1080. mount $Drive$PartNum $InstallDir
  1081. EspFilesystem=`grep "$Drive$PartNum.*/boot/efi" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3`
  1082. if [[ $EspFilesystem != 'vfat' ]] ; then
  1083. umount $InstallDir
  1084. else
  1085. echo "Mounting ESP at $InstallDir"
  1086. break;
  1087. fi
  1088. fi # $PartNum -eq $PartNum
  1089. fi # TableType
  1090. done
  1091. } # FindLinuxESP()
  1092.  
  1093. # Identifies the ESP's location (/boot or /boot/efi, or these locations under
  1094. # the directory specified by --root); aborts if the ESP isn't mounted at
  1095. # either location.
  1096. # Sets InstallDir to the ESP mount point.
  1097. FindMountedESP() {
  1098. mount /boot &> /dev/null
  1099. mount /boot/efi &> /dev/null
  1100. EspLine=`df "$RootDir/boot/efi" 2> /dev/null | grep boot/efi`
  1101. if [[ ! -n "$EspLine" ]] ; then
  1102. EspLine=`df "$RootDir"/boot | grep boot`
  1103. fi
  1104. InstallDir=`echo $EspLine | cut -d " " -f 6`
  1105.  
  1106. if [[ -n "$InstallDir" ]] ; then
  1107. EspFilesystem=`grep -w "$InstallDir" /etc/mtab | uniq | grep -v autofs | cut -d " " -f 3`
  1108. fi
  1109. if [[ $EspFilesystem != 'vfat' ]] ; then
  1110. FindLinuxESP
  1111. fi
  1112. if [[ $EspFilesystem != 'vfat' ]] ; then
  1113. echo "$RootDir/$InstallDir doesn't seem to be on a VFAT filesystem. The ESP must be"
  1114. echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!"
  1115. if [[ -d /sys/firmware/efi ]] ; then
  1116. exit 1
  1117. else
  1118. echo "The computer appears to be running in BIOS mode and has no ESP. You should"
  1119. echo "create an ESP, and ideally boot in EFI mode, before installing rEFInd."
  1120. exit 0
  1121. fi
  1122. fi
  1123. echo "ESP was found at $InstallDir using $EspFilesystem"
  1124. } # FindMountedESP
  1125.  
  1126. # Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM.
  1127. # If this fails, sets Problems=1
  1128. AddBootEntry() {
  1129. local PartNum
  1130. Efibootmgr=`which efibootmgr 2> /dev/null`
  1131. if [[ "$Efibootmgr" ]] ; then
  1132. InstallDisk=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 1-8`
  1133. PartNum=`grep "$InstallDir" /etc/mtab | cut -d " " -f 1 | cut -c 9-10`
  1134. EntryFilename="$TargetDir/$Refind"
  1135. EfiEntryFilename=`echo ${EntryFilename//\//\\\}`
  1136. EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g`
  1137. ExistingEntry=`"$Efibootmgr" -v | grep -i "$EfiEntryFilename2"`
  1138.  
  1139. if [[ "$ExistingEntry" ]] ; then
  1140. ExistingEntryBootNum=`echo "$ExistingEntry" | cut -c 5-8`
  1141. FirstBoot=`"$Efibootmgr" | grep BootOrder | cut -c 12-15`
  1142. if [[ "$ExistingEntryBootNum" != "$FirstBoot" ]] ; then
  1143. echo "An existing rEFInd boot entry exists, but isn't set as the default boot"
  1144. echo "manager. The boot order is being adjusted to make rEFInd the default boot"
  1145. echo "manager. If this is NOT what you want, you should use efibootmgr to"
  1146. echo "manually adjust your EFI's boot order."
  1147. fi
  1148. "$Efibootmgr" -b $ExistingEntryBootNum -B &> /dev/null
  1149. fi
  1150.  
  1151. echo "Installing it!"
  1152. if [[ "$KeepName" == 0 ]] ; then
  1153. "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
  1154. else
  1155. "$Efibootmgr" -c -l "$EfiEntryFilename" -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum \
  1156. -u "$TargetShim $TargetX64" &> /dev/null
  1157. fi
  1158. if [[ $? != 0 ]] ; then
  1159. EfibootmgrProblems=1
  1160. Problems=1
  1161. fi
  1162.  
  1163. else # efibootmgr not found
  1164. EfibootmgrProblems=1
  1165. Problems=1
  1166. fi
  1167.  
  1168. if [[ $EfibootmgrProblems ]] ; then
  1169. echo
  1170. echo "ALERT: There were problems running the efibootmgr program! You may need to"
  1171. echo "rename the $Refind binary to the default name (EFI/BOOT/bootx64.efi"
  1172. echo "on x86-64 systems, EFI/BOOT/bootia32.efi on x86 systems, or"
  1173. echo "EFI/BOOT/bootaa64.efi on ARM64 systems) to have it run!"
  1174. echo
  1175. else
  1176. echo "rEFInd has been set as the default boot manager."
  1177. fi
  1178. } # AddBootEntry()
  1179.  
  1180. # Create a minimal/sample refind_linux.conf file in /boot.
  1181. GenerateRefindLinuxConf() {
  1182. if [[ -f "$RLConfFile" ]] ; then
  1183. echo "Existing $RLConfFile found; not overwriting."
  1184. else
  1185. echo "Creating $RLConfFile; edit it to adjust kernel options."
  1186. RootFS=`df "$RootDir" | grep dev | cut -f 1 -d " "`
  1187. StartOfDevname=`echo "$RootFS" | cut -b 1-7`
  1188. if [[ "$StartOfDevname" == "/dev/sd" || "$StartOfDevName" == "/dev/hd" ]] ; then
  1189. # Identify root filesystem by UUID rather than by device node, if possible
  1190. Uuid=`blkid -o export -s UUID "$RootFS" 2> /dev/null | grep UUID=`
  1191. if [[ -n $Uuid ]] ; then
  1192. RootFS="$Uuid"
  1193. fi
  1194. fi
  1195. if [[ $RootDir == "/" ]] ; then
  1196. local FirstCmdlineOption=`cat /proc/cmdline | cut -d ' ' -f 1`
  1197. if [[ "$FirstCmdlineOption" =~ (vmlinuz|bzImage|kernel) ]] ; then
  1198. DefaultOptions=`cat /proc/cmdline | cut -d ' ' -f 2- | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'`
  1199. else
  1200. DefaultOptions=`cat /proc/cmdline | sed 's/\S*initrd=\S*//g' | sed 's/ *$//' | sed 's/^ *//'`
  1201. fi
  1202. else
  1203. if [[ -f "$RootDir/etc/default/grub" ]] ; then
  1204. # We want the default options used by the distribution, stored here....
  1205. source "$RootDir/etc/default/grub"
  1206. echo "Setting default boot options based on $RootDir/etc/default/grub"
  1207. fi
  1208. DefaultOptions="ro root=$RootFS $GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
  1209. fi
  1210. echo "\"Boot with standard options\" \"$DefaultOptions\"" > $RLConfFile
  1211. echo "\"Boot to single-user mode\" \"$DefaultOptions single\"" >> $RLConfFile
  1212. echo "\"Boot with minimal options\" \"ro root=$RootFS\"" >> $RLConfFile
  1213. fi
  1214. }
  1215.  
  1216. # Controls rEFInd installation under Linux.
  1217. # Sets Problems=1 if something goes wrong.
  1218. InstallOnLinux() {
  1219. if [[ "$TargetDir" == "/System/Library/CoreServices" ]] ; then
  1220. echo "You may not use the --ownhfs option under Linux! Aborting!"
  1221. exit 1
  1222. fi
  1223. echo "Installing rEFInd on Linux...."
  1224. modprobe efivars &> /dev/null
  1225. if [[ $TargetDir == "/EFI/BOOT" ]] ; then
  1226. MountDefaultTarget
  1227. else
  1228. FindMountedESP
  1229. DetermineTargetDir
  1230. fi
  1231.  
  1232. if [[ $LocalKeys == 1 ]] ; then
  1233. ReSignBinaries
  1234. fi
  1235.  
  1236. CheckSecureBoot
  1237. CopyRefindFiles
  1238. if [[ "$TargetDir" != "/EFI/BOOT" && "$TargetDir" != "/EFI/Microsoft/Boot" ]] ; then
  1239. AddBootEntry
  1240. GenerateRefindLinuxConf
  1241. fi
  1242. } # InstallOnLinux()
  1243.  
  1244. #
  1245. # The main part of the script. Sets a few environment variables,
  1246. # performs a few startup checks, and then calls functions to
  1247. # install under OS X or Linux, depending on the detected platform.
  1248. #
  1249. GetParams "$@"
  1250. if [[ $UID != 0 ]] ; then
  1251. echo "Not running as root; attempting to elevate privileges via sudo...."
  1252. sudo "$BASH_SOURCE" "$@"
  1253. if [[ $? != 0 ]] ; then
  1254. echo "This script must be run as root (or using sudo). Exiting!"
  1255. exit 1
  1256. else
  1257. exit 0
  1258. fi
  1259. fi
  1260. DeterminePlatform
  1261. CheckForFiles
  1262. case "$OSTYPE" in
  1263. darwin*)
  1264. if [[ "$ShimSource" != "none" ]] ; then
  1265. echo "The --shim option is not supported on OS X! Exiting!"
  1266. exit 1
  1267. fi
  1268. if [[ "$LocalKeys" != 0 ]] ; then
  1269. echo "The --localkeys option is not supported on OS X! Exiting!"
  1270. exit 1
  1271. fi
  1272. InstallOnOSX $1
  1273. ;;
  1274. linux*)
  1275. InstallOnLinux
  1276. ;;
  1277. *)
  1278. echo "Running on unknown OS; aborting!"
  1279. if [[ "$InstallToEspOnMac" == 0 ]] ; then
  1280. echo "The --notesp option is not supported on Linux! Exiting!"
  1281. exit 1
  1282. fi
  1283. esac
  1284.  
  1285. if [[ $Problems ]] ; then
  1286. echo
  1287. echo "ALERT:"
  1288. echo "Installation has completed, but problems were detected. Review the output for"
  1289. echo "error messages and take corrective measures as necessary. You may need to"
  1290. echo "re-run this script or install manually before rEFInd will work."
  1291. echo
  1292. else
  1293. echo
  1294. echo "Installation has completed successfully."
  1295. echo
  1296. fi
  1297.  
  1298. if [[ $UnmountEsp == '1' ]] ; then
  1299. echo "Unmounting install dir"
  1300. case "$OSTYPE" in
  1301. darwin*)
  1302. diskutil unmount $InstallDir
  1303. ;;
  1304. *)
  1305. umount $InstallDir
  1306. ;;
  1307. esac
  1308. fi
  1309.  
  1310. if [[ "$InstallDir" == /tmp/refind_install ]] ; then
  1311. # sleep 5
  1312. rmdir "$InstallDir"
  1313. fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement