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