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