]> code.delx.au - refind/blob - install.sh
Improvements to installation script.
[refind] / install.sh
1 #!/bin/bash
2 #
3 # Linux/MacOS X script to install rEFInd
4 #
5 # Usage:
6 #
7 # ./install.sh [options]
8 #
9 # options include:
10 # "--esp" to install to the ESP rather than to the system's root
11 # filesystem. This is the default on 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 # "--alldrivers" to install all drivers along with regular files
16 # "--nodrivers" to suppress driver installation (default in Linux is
17 # driver used on /boot; --nodrivers is OS X default)
18 # "--shim {shimfile}" to install a shim.efi file for Secure Boot
19 # "--localkeys" to re-sign x86-64 binaries with a locally-generated key
20 #
21 # The "esp" option is valid only on Mac OS X; it causes
22 # installation to the EFI System Partition (ESP) rather than
23 # to the current OS X boot partition. Under Linux, this script
24 # installs to the ESP by default.
25 #
26 # This program is copyright (c) 2012 by Roderick W. Smith
27 # It is released under the terms of the GNU GPL, version 3,
28 # a copy of which should be included in the file COPYING.txt.
29 #
30 # Revision history:
31 #
32 # 0.6.3 -- Support for detecting rEFInd in EFI/BOOT and EFI/Microsoft/Boot
33 # directories & for installing to EFI/BOOT in BIOS mode
34 # 0.6.2-1 -- Added --yes option & tweaked key-copying for use with RPM install script
35 # 0.6.1 -- Added --root option; minor bug fixes
36 # 0.6.0 -- Changed --drivers to --alldrivers and added --nodrivers option;
37 # changed default driver installation behavior in Linux to install
38 # the driver needed to read /boot (if available)
39 # 0.5.1.2 -- Fixed bug that caused failure to generate refind_linux.conf file
40 # 0.5.1.1 -- Fixed bug that caused script failure under OS X
41 # 0.5.1 -- Added --shim & --localkeys options & create sample refind_linux.conf
42 # in /boot
43 # 0.5.0 -- Added --usedefault & --drivers options & changed "esp" option to "--esp"
44 # 0.4.5 -- Fixed check for rEFItBlesser in OS X
45 # 0.4.2 -- Added notice about BIOS-based OSes & made NVRAM changes in Linux smarter
46 # 0.4.1 -- Added check for rEFItBlesser in OS X
47 # 0.3.3.1 -- Fixed OS X 10.7 bug; also works as make target
48 # 0.3.2.1 -- Check for presence of source files; aborts if not present
49 # 0.3.2 -- Initial version
50 #
51 # Note: install.sh version numbers match those of the rEFInd package
52 # with which they first appeared.
53
54 RootDir="/"
55 TargetDir=/EFI/refind
56 LocalKeysBase="refind_local"
57 ShimSource="none"
58 TargetShim="default"
59 TargetX64="refind_x64.efi"
60 TargetIA32="refind_ia32.efi"
61 LocalKeys=0
62 DeleteRefindDir=0
63 AlwaysYes=0
64
65 #
66 # Functions used by both OS X and Linux....
67 #
68
69 GetParams() {
70 InstallToEspOnMac=0
71 if [[ $OSName == "Linux" ]] ; then
72 # Install the driver required to read /boot, if it's available
73 InstallDrivers="boot"
74 else
75 InstallDrivers="none"
76 fi
77 while [[ $# -gt 0 ]]; do
78 case $1 in
79 --esp | --ESP) InstallToEspOnMac=1
80 ;;
81 --usedefault) TargetDir=/EFI/BOOT
82 TargetPart=$2
83 TargetX64="bootx64.efi"
84 TargetIA32="bootia32.efi"
85 shift
86 ;;
87 --root) RootDir=$2
88 shift
89 ;;
90 --localkeys) LocalKeys=1
91 ;;
92 --shim) ShimSource=$2
93 shift
94 ;;
95 --drivers | --alldrivers) InstallDrivers="all"
96 ;;
97 --nodrivers) InstallDrivers="none"
98 ;;
99 --yes) AlwaysYes=1
100 ;;
101 * ) echo "Usage: $0 [--esp | --usedefault {device-file} | --root {directory} ]"
102 echo " [--nodrivers | --alldrivers] [--shim {shim-filename}]"
103 echo " [--localkeys] [--yes]"
104 exit 1
105 esac
106 shift
107 done
108
109 if [[ $InstallToEspOnMac == 1 && $TargetDir == '/EFI/BOOT' ]] ; then
110 echo "You may use --esp OR --usedefault, but not both! Aborting!"
111 exit 1
112 fi
113 if [[ $RootDir != '/' && $TargetDir == '/EFI/BOOT' ]] ; then
114 echo "You may use --usedefault OR --root, but not both! Aborting!"
115 exit 1
116 fi
117 if [[ $RootDir != '/' && $InstallToEspOnMac == 1 ]] ; then
118 echo "You may use --root OR --esp, but not both! Aborting!"
119 exit 1
120 fi
121
122 RLConfFile="$RootDir/boot/refind_linux.conf"
123 EtcKeysDir="$RootDir/etc/refind.d/keys"
124 } # GetParams()
125
126 # Get a yes/no response from the user and place it in the YesNo variable.
127 # If the AlwaysYes variable is set to 1, skip the user input and set "Y"
128 # in the YesNo variable.
129 ReadYesNo() {
130 if [[ $AlwaysYes == 1 ]] ; then
131 YesNo="Y"
132 echo "Y"
133 else
134 read YesNo
135 fi
136 }
137
138 # Abort if the rEFInd files can't be found.
139 # Also sets $ConfFile to point to the configuration file,
140 # $IconsDir to point to the icons directory, and
141 # $ShimSource to the source of the shim.efi file (if necessary).
142 CheckForFiles() {
143 # Note: This check is satisfied if EITHER the 32- or the 64-bit version
144 # is found, even on the wrong platform. This is because the platform
145 # hasn't yet been determined. This could obviously be improved, but it
146 # would mean restructuring lots more code....
147 if [[ ! -f $RefindDir/refind_ia32.efi && ! -f $RefindDir/refind_x64.efi ]] ; then
148 echo "The rEFInd binary file is missing! Aborting installation!"
149 exit 1
150 fi
151
152 if [[ -f $RefindDir/refind.conf-sample ]] ; then
153 ConfFile=$RefindDir/refind.conf-sample
154 elif [[ -f $ThisDir/refind.conf-sample ]] ; then
155 ConfFile=$ThisDir/refind.conf-sample
156 else
157 echo "The sample configuration file is missing! Aborting installation!"
158 exit 1
159 fi
160
161 if [[ -d $RefindDir/icons ]] ; then
162 IconsDir=$RefindDir/icons
163 elif [[ -d $ThisDir/icons ]] ; then
164 IconsDir=$ThisDir/icons
165 else
166 echo "The icons directory is missing! Aborting installation!"
167 exit 1
168 fi
169
170 if [[ $ShimSource != "none" ]] ; then
171 if [[ -f $ShimSource ]] ; then
172 TargetX64="grubx64.efi"
173 MokManagerSource=`dirname $ShimSource`/MokManager.efi
174 else
175 echo "The specified shim file, $ShimSource, doesn't exist!"
176 echo "Aborting installation!"
177 exit 1
178 fi
179 fi
180 } # CheckForFiles()
181
182 # Helper for CopyRefindFiles; copies shim files (including MokManager, if it's
183 # available) to target.
184 CopyShimFiles() {
185 cp $ShimSource $InstallDir/$TargetDir/$TargetShim
186 if [[ $? != 0 ]] ; then
187 Problems=1
188 fi
189 if [[ -f $MokManagerSource ]] ; then
190 cp $MokManagerSource $InstallDir/$TargetDir/
191 fi
192 if [[ $? != 0 ]] ; then
193 Problems=1
194 fi
195 } # CopyShimFiles()
196
197 # Copy the public keys to the installation medium
198 CopyKeys() {
199 if [[ $LocalKeys == 1 ]] ; then
200 mkdir -p $InstallDir/$TargetDir/keys/
201 cp $EtcKeysDir/$LocalKeysBase.cer $InstallDir/$TargetDir/keys/
202 cp $EtcKeysDir/$LocalKeysBase.crt $InstallDir/$TargetDir/keys/
203 # else
204 # cp $ThisDir/refind.cer $InstallDir/$TargetDir/keys/
205 # cp $ThisDir/refind.crt $InstallDir/$TargetDir/keys/
206 fi
207 } # CopyKeys()
208
209 # Copy drivers from $RefindDir/drivers_$1 to $InstallDir/$TargetDir/drivers_$1,
210 # honoring the $InstallDrivers condition. Must be passed a suitable
211 # architecture code (ia32 or x64).
212 CopyDrivers() {
213 if [[ $InstallDrivers == "all" ]] ; then
214 mkdir -p $InstallDir/$TargetDir/drivers_$1
215 cp $RefindDir/drivers_$1/*_$1.efi $InstallDir/$TargetDir/drivers_$1/ 2> /dev/null
216 cp $ThisDir/drivers_$1/*_$1.efi $InstallDir/$TargetDir/drivers_$1/ 2> /dev/null
217 elif [[ $InstallDrivers == "boot" && -x `which blkid` ]] ; then
218 BootPart=`df /boot | grep dev | cut -f 1 -d " "`
219 BootFS=`blkid -o export $BootPart 2> /dev/null | grep TYPE= | cut -f 2 -d =`
220 DriverType=""
221 case $BootFS in
222 ext2 | ext3 | ext4) DriverType="ext4"
223 ;;
224 reiserfs) DriverType="reiserfs"
225 ;;
226 hfsplus) DriverType="hfs"
227 ;;
228 *) BootFS=""
229 esac
230 if [[ -n $BootFS ]] ; then
231 echo "Installing driver for $BootFS (${DriverType}_$1.efi)"
232 mkdir -p $InstallDir/$TargetDir/drivers_$1
233 cp $RefindDir/drivers_$1/${DriverType}_$1.efi $InstallDir/$TargetDir/drivers_$1/ 2> /dev/null
234 cp $ThisDir/drivers_$1/${DriverType}_$1.efi $InstallDir/$TargetDir/drivers_$1/ 2> /dev/null
235 fi
236 fi
237 }
238
239 # Copy the rEFInd files to the ESP or OS X root partition.
240 # Sets Problems=1 if any critical commands fail.
241 CopyRefindFiles() {
242 mkdir -p $InstallDir/$TargetDir
243 if [[ $TargetDir == '/EFI/BOOT' ]] ; then
244 cp $RefindDir/refind_ia32.efi $InstallDir/$TargetDir/$TargetIA32 2> /dev/null
245 if [[ $? != 0 ]] ; then
246 echo "Note: IA32 (x86) binary not installed!"
247 fi
248 cp $RefindDir/refind_x64.efi $InstallDir/$TargetDir/$TargetX64 2> /dev/null
249 if [[ $? != 0 ]] ; then
250 Problems=1
251 fi
252 if [[ $ShimSource != "none" ]] ; then
253 TargetShim="bootx64.efi"
254 CopyShimFiles
255 fi
256 if [[ $InstallDrivers == "all" ]] ; then
257 cp -r $RefindDir/drivers_* $InstallDir/$TargetDir/ 2> /dev/null
258 cp -r $ThisDir/drivers_* $InstallDir/$TargetDir/ 2> /dev/null
259 fi
260 Refind=""
261 CopyKeys
262 elif [[ $Platform == 'EFI64' || $TargetDir == "/EFI/Microsoft/Boot" ]] ; then
263 cp $RefindDir/refind_x64.efi $InstallDir/$TargetDir/$TargetX64
264 if [[ $? != 0 ]] ; then
265 Problems=1
266 fi
267 CopyDrivers x64
268 Refind="refind_x64.efi"
269 CopyKeys
270 if [[ $ShimSource != "none" ]] ; then
271 if [[ $TargetShim == "default" ]] ; then
272 TargetShim=`basename $ShimSource`
273 fi
274 CopyShimFiles
275 Refind=$TargetShim
276 if [[ $LocalKeys == 0 ]] ; then
277 echo "Storing copies of rEFInd Secure Boot public keys in $EtcKeysDir"
278 mkdir -p $EtcKeysDir
279 cp $ThisDir/keys/refind.cer $EtcKeysDir 2> /dev/null
280 cp $ThisDir/keys/refind.crt $EtcKeysDir 2> /dev/null
281 fi
282 fi
283 elif [[ $Platform == 'EFI32' ]] ; then
284 cp $RefindDir/refind_ia32.efi $InstallDir/$TargetDir/$TargetIA32
285 if [[ $? != 0 ]] ; then
286 Problems=1
287 fi
288 CopyDrivers ia32
289 Refind="refind_ia32.efi"
290 else
291 echo "Unknown platform! Aborting!"
292 exit 1
293 fi
294 echo "Copied rEFInd binary files"
295 echo ""
296 if [[ -d $InstallDir/$TargetDir/icons ]] ; then
297 rm -rf $InstallDir/$TargetDir/icons-backup &> /dev/null
298 mv -f $InstallDir/$TargetDir/icons $InstallDir/$TargetDir/icons-backup
299 echo "Notice: Backed up existing icons directory as icons-backup."
300 fi
301 cp -r $IconsDir $InstallDir/$TargetDir
302 if [[ $? != 0 ]] ; then
303 Problems=1
304 fi
305 mkdir -p $InstallDir/$TargetDir/keys
306 cp -rf $ThisDir/keys/*.[cd]er $InstallDir/$TargetDir/keys/ 2> /dev/null
307 cp -rf $EtcKeysDir/*.[cd]er $InstallDir/$TargetDir/keys/ 2> /dev/null
308 if [[ -f $InstallDir/$TargetDir/refind.conf ]] ; then
309 echo "Existing refind.conf file found; copying sample file as refind.conf-sample"
310 echo "to avoid overwriting your customizations."
311 echo ""
312 cp -f $ConfFile $InstallDir/$TargetDir
313 if [[ $? != 0 ]] ; then
314 Problems=1
315 fi
316 else
317 echo "Copying sample configuration file as refind.conf; edit this file to configure"
318 echo "rEFInd."
319 echo ""
320 cp -f $ConfFile $InstallDir/$TargetDir/refind.conf
321 if [[ $? != 0 ]] ; then
322 Problems=1
323 fi
324 fi
325 if [[ $DeleteRefindDir == 1 ]] ; then
326 echo "Deleting the temporary directory $RefindDir"
327 rm -r $RefindDir
328 fi
329 } # CopyRefindFiles()
330
331 # Mount the partition the user specified with the --usedefault option
332 MountDefaultTarget() {
333 InstallDir=/tmp/refind_install
334 mkdir -p $InstallDir
335 if [[ $OSName == 'Darwin' ]] ; then
336 mount -t msdos $TargetPart $InstallDir
337 elif [[ $OSName == 'Linux' ]] ; then
338 mount -t vfat $TargetPart $InstallDir
339 fi
340 if [[ $? != 0 ]] ; then
341 echo "Couldn't mount $TargetPart ! Aborting!"
342 rmdir $InstallDir
343 exit 1
344 fi
345 UnmountEsp=1
346 } # MountDefaultTarget()
347
348 #
349 # A series of OS X support functions....
350 #
351
352 # Mount the ESP at /Volumes/ESP or determine its current mount
353 # point.
354 # Sets InstallDir to the ESP mount point
355 # Sets UnmountEsp if we mounted it
356 MountOSXESP() {
357 # Identify the ESP. Note: This returns the FIRST ESP found;
358 # if the system has multiple disks, this could be wrong!
359 Temp=`diskutil list | grep " EFI "`
360 Esp=/dev/`echo $Temp | cut -f 5 -d ' '`
361 # If the ESP is mounted, use its current mount point....
362 Temp=`df | grep $Esp`
363 InstallDir=`echo $Temp | cut -f 6 -d ' '`
364 if [[ $InstallDir == '' ]] ; then
365 mkdir /Volumes/ESP &> /dev/null
366 mount -t msdos $Esp /Volumes/ESP
367 if [[ $? != 0 ]] ; then
368 echo "Unable to mount ESP! Aborting!\n"
369 exit 1
370 fi
371 UnmountEsp=1
372 InstallDir="/Volumes/ESP"
373 fi
374 } # MountOSXESP()
375
376 # Control the OS X installation.
377 # Sets Problems=1 if problems found during the installation.
378 InstallOnOSX() {
379 echo "Installing rEFInd on OS X...."
380 if [[ $TargetDir == "/EFI/BOOT" ]] ; then
381 MountDefaultTarget
382 elif [[ $InstallToEspOnMac == "1" ]] ; then
383 MountOSXESP
384 else
385 InstallDir="$RootDir/"
386 fi
387 echo "Installing rEFInd to the partition mounted at '$InstallDir'"
388 Platform=`ioreg -l -p IODeviceTree | grep firmware-abi | cut -d "\"" -f 4`
389 CopyRefindFiles
390 if [[ $InstallToEspOnMac == "1" ]] ; then
391 bless --mount $InstallDir --setBoot --file $InstallDir/$TargetDir/$Refind
392 elif [[ $TargetDir != "/EFI/BOOT" ]] ; then
393 bless --setBoot --folder $InstallDir/$TargetDir --file $InstallDir/$TargetDir/$Refind
394 fi
395 if [[ $? != 0 ]] ; then
396 Problems=1
397 fi
398 if [[ -f /Library/StartupItems/rEFItBlesser || -d /Library/StartupItems/rEFItBlesser ]] ; then
399 echo
400 echo "/Library/StartupItems/rEFItBlesser found!"
401 echo "This program is part of rEFIt, and will cause rEFInd to fail to work after"
402 echo -n "its first boot. Do you want to remove rEFItBlesser (Y/N)? "
403 ReadYesNo
404 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
405 echo "Deleting /Library/StartupItems/rEFItBlesser..."
406 rm -r /Library/StartupItems/rEFItBlesser
407 else
408 echo "Not deleting rEFItBlesser."
409 fi
410 fi
411 echo
412 echo "WARNING: If you have an Advanced Format disk, *DO NOT* attempt to check the"
413 echo "bless status with 'bless --info', since this is known to cause disk corruption"
414 echo "on some systems!!"
415 echo
416 } # InstallOnOSX()
417
418
419 #
420 # Now a series of Linux support functions....
421 #
422
423 # Check for evidence that we're running in Secure Boot mode. If so, and if
424 # appropriate options haven't been set, warn the user and offer to abort.
425 # If we're NOT in Secure Boot mode but the user HAS specified the --shim
426 # or --localkeys option, warn the user and offer to abort.
427 #
428 # FIXME: Although I checked the presence (and lack thereof) of the
429 # /sys/firmware/efi/vars/SecureBoot* files on my Secure Boot test system
430 # before releasing this script, I've since found that they are at least
431 # sometimes present when Secure Boot is absent. This means that the first
432 # test can produce false alarms. A better test is highly desirable.
433 CheckSecureBoot() {
434 VarFile=`ls -d /sys/firmware/efi/vars/SecureBoot* 2> /dev/null`
435 if [[ -n $VarFile && $TargetDir != '/EFI/BOOT' && $ShimSource == "none" ]] ; then
436 echo ""
437 echo "CAUTION: Your computer appears to support Secure Boot, but you haven't"
438 echo "specified a valid shim.efi file source. If you've disabled Secure Boot and"
439 echo "intend to leave it disabled, this is fine; but if Secure Boot is active, the"
440 echo "resulting installation won't boot. You can read more about this topic at"
441 echo "http://www.rodsbooks.com/refind/secureboot.html."
442 echo ""
443 echo -n "Do you want to proceed with installation (Y/N)? "
444 ReadYesNo
445 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
446 echo "OK; continuing with the installation..."
447 else
448 exit 0
449 fi
450 fi
451
452 if [[ $ShimSource != "none" && ! -n $VarFile ]] ; then
453 echo ""
454 echo "You've specified installing using a shim.efi file, but your computer does not"
455 echo "appear to be running in Secure Boot mode. Although installing in this way"
456 echo "should work, it's unnecessarily complex. You may continue, but unless you"
457 echo "plan to enable Secure Boot, you should consider stopping and omitting the"
458 echo "--shim option. You can read more about this topic at"
459 echo "http://www.rodsbooks.com/refind/secureboot.html."
460 echo ""
461 echo -n "Do you want to proceed with installation (Y/N)? "
462 ReadYesNo
463 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
464 echo "OK; continuing with the installation..."
465 else
466 exit 0
467 fi
468 fi
469
470 if [[ $LocalKeys != 0 && ! -n $VarFile ]] ; then
471 echo ""
472 echo "You've specified re-signing your rEFInd binaries with locally-generated keys,"
473 echo "but your computer does not appear to be running in Secure Boot mode. The"
474 echo "keys you generate will be useless unless you enable Secure Boot. You may"
475 echo "proceed with this installation, but before you do so, you may want to read"
476 echo "more about it at http://www.rodsbooks.com/refind/secureboot.html."
477 echo ""
478 echo -n "Do you want to proceed with installation (Y/N)? "
479 ReadYesNo
480 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
481 echo "OK; continuing with the installation..."
482 else
483 exit 0
484 fi
485 fi
486
487 } # CheckSecureBoot()
488
489 # Check for the presence of locally-generated keys from a previous installation in
490 # $EtcKeysDir (/etc/refind.d/keys). If they're not present, generate them using
491 # openssl.
492 GenerateKeys() {
493 PrivateKey=$EtcKeysDir/$LocalKeysBase.key
494 CertKey=$EtcKeysDir/$LocalKeysBase.crt
495 DerKey=$EtcKeysDir/$LocalKeysBase.cer
496 OpenSSL=`which openssl 2> /dev/null`
497
498 # Do the work only if one or more of the necessary keys is missing
499 # TODO: Technically, we don't need the DerKey; but if it's missing and openssl
500 # is also missing, this will fail. This could be improved.
501 if [[ ! -f $PrivateKey || ! -f $CertKey || ! -f $DerKey ]] ; then
502 echo "Generating a fresh set of local keys...."
503 mkdir -p $EtcKeysDir
504 chmod 0700 $EtcKeysDir
505 if [[ ! -x $OpenSSL ]] ; then
506 echo "Can't find openssl, which is required to create your private signing keys!"
507 echo "Aborting!"
508 exit 1
509 fi
510 if [[ -f $PrivateKey ]] ; then
511 echo "Backing up existing $PrivateKey"
512 cp -f $PrivateKey $PrivateKey.backup 2> /dev/null
513 fi
514 if [[ -f $CertKey ]] ; then
515 echo "Backing up existing $CertKey"
516 cp -f $CertKey $CertKey.backup 2> /dev/null
517 fi
518 if [[ -f $DerKey ]] ; then
519 echo "Backing up existing $DerKey"
520 cp -f $DerKey $DerKey.backup 2> /dev/null
521 fi
522 $OpenSSL req -new -x509 -newkey rsa:2048 -keyout $PrivateKey -out $CertKey \
523 -nodes -days 3650 -subj "/CN=Locally-generated rEFInd key/"
524 $OpenSSL x509 -in $CertKey -out $DerKey -outform DER
525 chmod 0600 $PrivateKey
526 else
527 echo "Using existing local keys...."
528 fi
529 }
530
531 # Sign a single binary. Requires parameters:
532 # $1 = source file
533 # $2 = destination file
534 # Also assumes that the SBSign, PESign, UseSBSign, UsePESign, and various key variables are set
535 # appropriately.
536 # Aborts script on error
537 SignOneBinary() {
538 $SBSign --key $PrivateKey --cert $CertKey --output $2 $1
539 if [[ $? != 0 ]] ; then
540 echo "Problem signing the binary $1! Aborting!"
541 exit 1
542 fi
543 }
544
545 # Re-sign the x86-64 binaries with a locally-generated key, First look for appropriate
546 # key files in $EtcKeysDir. If they're present, use them to re-sign the binaries. If
547 # not, try to generate new keys and store them in $EtcKeysDir.
548 ReSignBinaries() {
549 SBSign=`which sbsign 2> /dev/null`
550 echo "Found sbsign at $SBSign"
551 TempDir="/tmp/refind_local"
552 if [[ ! -x $SBSign ]] ; then
553 echo "Can't find sbsign, which is required to sign rEFInd with your own keys!"
554 echo "Aborting!"
555 exit 1
556 fi
557 GenerateKeys
558 mkdir -p $TempDir/drivers_x64
559 cp $RefindDir/refind.conf-sample $TempDir 2> /dev/null
560 cp $ThisDir/refind.conf-sample $TempDir 2> /dev/null
561 cp $RefindDir/refind_ia32.efi $TempDir 2> /dev/null
562 cp -a $RefindDir/drivers_ia32 $TempDir 2> /dev/null
563 cp -a $ThisDir/drivers_ia32 $TempDir 2> /dev/null
564 SignOneBinary $RefindDir/refind_x64.efi $TempDir/refind_x64.efi
565 for Driver in `ls $RefindDir/drivers_x64/*.efi $ThisDir/drivers_x64/*.efi 2> /dev/null` ; do
566 TempName=`basename $Driver`
567 SignOneBinary $Driver $TempDir/drivers_x64/$TempName
568 done
569 RefindDir=$TempDir
570 DeleteRefindDir=1
571 }
572
573 # Identifies the ESP's location (/boot or /boot/efi, or these locations under
574 # the directory specified by --root); aborts if the ESP isn't mounted at
575 # either location.
576 # Sets InstallDir to the ESP mount point.
577 FindLinuxESP() {
578 EspLine=`df $RootDir/boot/efi 2> /dev/null | grep boot/efi`
579 if [[ ! -n $EspLine ]] ; then
580 EspLine=`df $RootDir/boot | grep boot`
581 fi
582 InstallDir=`echo $EspLine | cut -d " " -f 6`
583 if [[ -n $InstallDir ]] ; then
584 EspFilesystem=`grep $InstallDir /etc/mtab | cut -d " " -f 3`
585 fi
586 if [[ $EspFilesystem != 'vfat' ]] ; then
587 echo "$RootDir/boot/efi doesn't seem to be on a VFAT filesystem. The ESP must be"
588 echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!"
589 exit 1
590 fi
591 echo "ESP was found at $InstallDir using $EspFilesystem"
592 } # FindLinuxESP
593
594 # Uses efibootmgr to add an entry for rEFInd to the EFI's NVRAM.
595 # If this fails, sets Problems=1
596 AddBootEntry() {
597 InstallIt="0"
598 Efibootmgr=`which efibootmgr 2> /dev/null`
599 if [[ $Efibootmgr ]] ; then
600 InstallDisk=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 1-8`
601 PartNum=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 9-10`
602 EntryFilename=$TargetDir/$Refind
603 EfiEntryFilename=`echo ${EntryFilename//\//\\\}`
604 EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g`
605 ExistingEntry=`$Efibootmgr -v | grep $EfiEntryFilename2`
606
607 if [[ $ExistingEntry ]] ; then
608 ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8`
609 FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15`
610 if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then
611 echo "An existing rEFInd boot entry exists, but isn't set as the default boot"
612 echo "manager. The boot order is being adjusted to make rEFInd the default boot"
613 echo "manager. If this is NOT what you want, you should use efibootmgr to"
614 echo "manually adjust your EFI's boot order."
615 $Efibootmgr -b $ExistingEntryBootNum -B &> /dev/null
616 InstallIt="1"
617 fi
618 else
619 InstallIt="1"
620 fi
621
622 if [[ $InstallIt == "1" ]] ; then
623 echo "Installing it!"
624 $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
625 if [[ $? != 0 ]] ; then
626 EfibootmgrProblems=1
627 Problems=1
628 fi
629 fi
630
631 else
632 EfibootmgrProblems=1
633 Problems=1
634 fi
635
636 if [[ $EfibootmgrProblems ]] ; then
637 echo
638 echo "ALERT: There were problems running the efibootmgr program! You may need to"
639 echo "rename the $Refind binary to the default name (EFI/boot/bootx64.efi"
640 echo "on x86-64 systems or EFI/boot/bootia32.efi on x86 systems) to have it run!"
641 echo
642 fi
643 } # AddBootEntry()
644
645 # Create a minimal/sample refind_linux.conf file in /boot.
646 GenerateRefindLinuxConf() {
647 if [[ -f $RLConfFile ]] ; then
648 echo "Existing $RLConfFile found; not overwriting."
649 else
650 if [[ -f "$RootDir/etc/default/grub" ]] ; then
651 # We want the default options used by the distribution, stored here....
652 source "$RootDir/etc/default/grub"
653 fi
654 RootFS=`df $RootDir | grep dev | cut -f 1 -d " "`
655 StartOfDevname=`echo $RootFS | cut -b 1-7`
656 if [[ $StartOfDevname == "/dev/sd" || $StartOfDevName == "/dev/hd" ]] ; then
657 # Identify root filesystem by UUID rather than by device node, if possible
658 Uuid=`blkid -o export $RootFS 2> /dev/null | grep UUID=`
659 if [[ -n $Uuid ]] ; then
660 RootFS=$Uuid
661 fi
662 fi
663 DefaultOptions="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
664 echo "\"Boot with standard options\" \"ro root=$RootFS $DefaultOptions \"" > $RLConfFile
665 echo "\"Boot to single-user mode\" \"ro root=$RootFS $DefaultOptions single\"" >> $RLConfFile
666 echo "\"Boot with minimal options\" \"ro root=$RootFS\"" >> $RLConfFile
667 fi
668 }
669
670 # Set varaibles for installation in EFI/BOOT directory
671 SetVarsForBoot() {
672 TargetDir="/EFI/BOOT"
673 if [[ $ShimSource == "none" ]] ; then
674 TargetX64="bootx64.efi"
675 TargetIA32="bootia32.efi"
676 else
677 TargetX64="grubx64.efi"
678 TargetIA32="bootia32.efi"
679 TargetShim="bootx64.efi"
680 fi
681 } # SetFilenamesForBoot()
682
683 # Set variables for installation in EFI/Microsoft/Boot directory
684 SetVarsForMsBoot() {
685 TargetDir="/EFI/Microsoft/Boot"
686 if [[ $ShimSource == "none" ]] ; then
687 TargetX64="bootmgfw.efi"
688 else
689 TargetX64="grubx64.efi"
690 TargetShim="bootmgfw.efi"
691 fi
692 }
693
694 # TargetDir defaults to /EFI/refind; however, this function adjusts it as follows:
695 # - If an existing refind.conf is available in /EFI/BOOT or /EFI/Microsoft/Boot,
696 # install to that directory under the suitable name; but DO NOT do this if
697 # refind.conf is also in /EFI/refind.
698 # - If booted in BIOS mode and the ESP lacks any other EFI files, install to
699 # /EFI/BOOT
700 # - If booted in BIOS mode and there's no refind.conf file and there is a
701 # /EFI/Microsoft/Boot/bootmgfw.efi file, move it down one level and
702 # install under that name, "hijacking" the Windows boot loader filename
703 DetermineTargetDir() {
704 Upgrade=0
705
706 if [[ -f $InstallDir/EFI/BOOT/refind.conf ]] ; then
707 SetVarsForBoot
708 Upgrade=1
709 fi
710 if [[ -f $InstallDir/EFI/Microsoft/Boot/refind.conf ]] ; then
711 SetVarsForMsBoot
712 Upgrade=1
713 fi
714 if [[ -f $InstallDir/EFI/refind/refind.conf ]] ; then
715 TargetDir="/EFI/refind"
716 Upgrade=1
717 fi
718 if [[ $Upgrade == 1 ]] ; then
719 echo "Found rEFInd installation in $InstallDir$TargetDir; upgrading it."
720 fi
721
722 if [[ ! -d /sys/firmware/efi && $Upgrade == 0 ]] ; then # BIOS-mode
723 FoundEfiFiles=`find $InstallDir/EFI/BOOT -name "*.efi" 2> /dev/null`
724 FoundConfFiles=`find $InstallDir -name "refind\.conf" 2> /dev/null`
725 if [[ ! -n $FoundConfFiles && -f $InstallDir/EFI/Microsoft/Boot/bootmgfw.efi ]] ; then
726 mv -n $InstallDir/EFI/Microsoft/Boot/bootmgfw.efi $InstallDir/EFI/Microsoft &> /dev/null
727 SetVarsForMsBoot
728 echo "Running in BIOS mode with a suspected Windows installation; moving boot loader"
729 echo "files so as to install to $InstallDir$TargetDir."
730 elif [[ ! -n $FoundEfiFiles ]] ; then # In BIOS mode and no default loader; install as default loader
731 SetVarsForBoot
732 echo "Running in BIOS mode with no existing default boot loader; installing to"
733 echo $InstallDir$TargetDir
734 else
735 echo "Running in BIOS mode with an existing default boot loader; backing it up and"
736 echo "installing rEFInd in its place."
737 if [[ -d $InstallDir/EFI/BOOT-rEFIndBackup ]] ; then
738 echo ""
739 echo "Caution: An existing backup of a default boot loader exists! If the current"
740 echo "default boot loader and the backup are different boot loaders, the current"
741 echo "one will become inaccessible."
742 echo ""
743 echo -n "Do you want to proceed with installation (Y/N)? "
744 ReadYesNo
745 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
746 echo "OK; continuing with the installation..."
747 else
748 exit 0
749 fi
750 fi
751 mv -n $InstallDir/EFI/BOOT $InstallDir/EFI/BOOT-rEFIndBackup
752 SetVarsForBoot
753 fi
754 fi # BIOS-mode
755 } # DetermineTargetDir()
756
757 # Controls rEFInd installation under Linux.
758 # Sets Problems=1 if something goes wrong.
759 InstallOnLinux() {
760 echo "Installing rEFInd on Linux...."
761 modprobe efivars &> /dev/null
762 if [[ $TargetDir == "/EFI/BOOT" ]] ; then
763 MountDefaultTarget
764 else
765 FindLinuxESP
766 DetermineTargetDir
767 fi
768 CpuType=`uname -m`
769 if [[ $CpuType == 'x86_64' ]] ; then
770 Platform="EFI64"
771 elif [[ ($CpuType == 'i386' || $CpuType == 'i486' || $CpuType == 'i586' || $CpuType == 'i686') ]] ; then
772 Platform="EFI32"
773 # If we're in EFI mode, do some sanity checks, and alert the user or even
774 # abort. Not in BIOS mode, though, since that could be used on an emergency
775 # disc to try to recover a troubled Linux installation.
776 if [[ -d /sys/firmware/efi ]] ; then
777 if [[ $ShimSource != "none" && $TargetDir != "/BOOT/EFI" ]] ; then
778 echo ""
779 echo "CAUTION: Neither rEFInd nor shim currently supports 32-bit systems, so you"
780 echo "should not use the --shim option to install on such systems. Aborting!"
781 echo ""
782 exit 1
783 fi
784 echo
785 echo "CAUTION: This Linux installation uses a 32-bit kernel. 32-bit EFI-based"
786 echo "computers are VERY RARE. If you've installed a 32-bit version of Linux"
787 echo "on a 64-bit computer, you should manually install the 64-bit version of"
788 echo "rEFInd. If you're installing on a Mac, you should do so from OS X. If"
789 echo "you're positive you want to continue with this installation, answer 'Y'"
790 echo "to the following question..."
791 echo
792 echo -n "Are you sure you want to continue (Y/N)? "
793 ReadYesNo
794 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
795 echo "OK; continuing with the installation..."
796 else
797 exit 0
798 fi
799 fi # in EFI mode
800 else
801 echo "Unknown CPU type '$CpuType'; aborting!"
802 exit 1
803 fi
804
805 if [[ $LocalKeys == 1 ]] ; then
806 ReSignBinaries
807 fi
808
809 CheckSecureBoot
810 CopyRefindFiles
811 if [[ $TargetDir != "/EFI/BOOT" && $TargetDir != "/EFI/Microsoft/Boot" ]] ; then
812 AddBootEntry
813 GenerateRefindLinuxConf
814 fi
815 } # InstallOnLinux()
816
817 #
818 # The main part of the script. Sets a few environment variables,
819 # performs a few startup checks, and then calls functions to
820 # install under OS X or Linux, depending on the detected platform.
821 #
822
823 OSName=`uname -s`
824 GetParams $@
825 ThisDir="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
826 RefindDir="$ThisDir/refind"
827 ThisScript="$ThisDir/`basename $0`"
828 if [[ `whoami` != "root" ]] ; then
829 echo "Not running as root; attempting to elevate privileges via sudo...."
830 sudo $ThisScript "$@"
831 if [[ $? != 0 ]] ; then
832 echo "This script must be run as root (or using sudo). Exiting!"
833 exit 1
834 else
835 exit 0
836 fi
837 fi
838 CheckForFiles
839 if [[ $OSName == 'Darwin' ]] ; then
840 if [[ $ShimSource != "none" ]] ; then
841 echo "The --shim option is not supported on OS X! Exiting!"
842 exit 1
843 fi
844 if [[ $LocalKeys != 0 ]] ; then
845 echo "The --localkeys option is not supported on OS X! Exiting!"
846 exit 1
847 fi
848 InstallOnOSX $1
849 elif [[ $OSName == 'Linux' ]] ; then
850 InstallOnLinux
851 else
852 echo "Running on unknown OS; aborting!"
853 fi
854
855 if [[ $Problems ]] ; then
856 echo
857 echo "ALERT:"
858 echo "Installation has completed, but problems were detected. Review the output for"
859 echo "error messages and take corrective measures as necessary. You may need to"
860 echo "re-run this script or install manually before rEFInd will work."
861 echo
862 else
863 echo
864 echo "Installation has completed successfully."
865 echo
866 fi
867
868 if [[ $UnmountEsp ]] ; then
869 echo "Unmounting install dir"
870 umount $InstallDir
871 fi
872
873 if [[ $InstallDir == /tmp/refind_install ]] ; then
874 # sleep 5
875 rmdir $InstallDir
876 fi