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