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