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