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