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