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