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