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