]> code.delx.au - refind/blob - mvrefind
More documentation of copyrights and licenses.
[refind] / mvrefind
1 #!/bin/bash
2 #
3 # Linux script to move an existing rEFInd installation from one directory to
4 # another
5 #
6 # copyright (c) 2013-2015 by Roderick W. Smith
7 #
8 # This program is licensed under the terms of the GNU GPL, version 3,
9 # or (at your option) any later version.
10 # You should have received a copy of the GNU General Public License
11 # along with this program. If not, see <http://www.gnu.org/licenses/>.
12
13 # Usage:
14 #
15 # ./mvrefind /path/to/source /path/to/destination
16 #
17 # Typically used to "hijack" or "unhijack" a Windows boot loader location or
18 # to help convert a rEFInd installation made in BIOS mode to one that works
19 # in EFI mode.
20 #
21 # Revision history:
22 #
23 # 0.10.1 -- Generalized to support ARM64 (aka AARCH64, aa64)
24 # 0.10.0 -- Renamed from mvrefind.sh to mvrefind
25 # 0.6.3 -- Initial release
26 #
27 # Note: mvrefind version numbers match those of the rEFInd package
28 # with which they first appeared.
29
30 RootDir="/"
31 SourceShim="shim.efi"
32 TargetShim=$SourceShim
33 SourceDir=`readlink -f ${1}`
34 TargetDir=`readlink -f ${2}`
35
36 # Identifies the ESP's location (/boot or /boot/efi); aborts if the ESP isn't
37 # mounted at either location. Also splits the ESP location from SourceDir and
38 # TargetDir, leaving them intact but creating new EspSourceDir and EspTargetDir
39 # variables containing only the ESP components thereof. These new variables
40 # are also converted to all-lowercase and any trailing slash is stripped, to
41 # assist in comparisons. (This is reasonable because FAT is case-insensitive.)
42 # Sets InstallDir to the ESP mount point.
43 FindLinuxESP() {
44 EspLine=`df $RootDir/boot/efi 2> /dev/null | grep boot/efi`
45 if [[ ! -n $EspLine ]] ; then
46 EspLine=`df $RootDir/boot | grep boot`
47 fi
48 InstallDir=`echo $EspLine | cut -d " " -f 6`
49 if [[ -n $InstallDir ]] ; then
50 EspFilesystem=`grep $InstallDir /etc/mtab | cut -d " " -f 3`
51 fi
52 if [[ $EspFilesystem != 'vfat' ]] ; then
53 echo "$RootDir/boot/efi doesn't seem to be on a VFAT filesystem. The ESP must be"
54 echo "mounted at $RootDir/boot or $RootDir/boot/efi and it must be VFAT! Aborting!"
55 exit 1
56 fi
57
58 # Sanity check on source & target....
59 EspPathLength=`expr length $InstallDir`
60 Temp=`echo $SourceDir | cut -c 1-$EspPathLength`
61 if [[ $Temp != $InstallDir ]] ; then
62 echo "$SourceDir isn't on the ESP ($InstallDir)! Aborting!"
63 exit 1
64 fi
65 Temp=`echo $TargetDir | cut -c 1-$EspPathLength`
66 if [[ $Temp != $InstallDir ]] ; then
67 echo "$TargetDir isn't on the ESP ($InstallDir)! Aborting!"
68 exit 1
69 fi
70
71 # Temporarily replace "/" in pathnames with ",", so as to enable sed to
72 # work on them
73 TempInstallDir=`echo $InstallDir | tr '/' ','`
74 Temp=`echo $SourceDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'`
75 EspSourceDir=`dirname $Temp`/`basename $Temp`
76 Temp=`echo $TargetDir | tr '/' ',' | sed s/${TempInstallDir}//g | tr ',' '/' | tr '[A-Z]' '[a-z]'`
77 EspTargetDir=`dirname $Temp`/`basename $Temp`
78 if [[ $EspSourceDir == $EspTargetDir ]] ; then
79 echo "$SourceDir is the same as $TargetDir! Aborting!"
80 exit 1
81 fi
82 } # FindLinuxESP
83
84 DeterminePlatform() {
85 CpuType=`uname -m`
86 case "$CpuType" in
87 aarch64)
88 Platform="aa64"
89 ;;
90 x86_64)
91 Platform="x64"
92 ;;
93 i?86)
94 Platform="ia32"
95 ;;
96 *)
97 echo "Unsupported CPU type; aborting!"
98 exit 1
99 esac
100 Source="refind_$Platform.efi"
101 Target=$Source
102 }
103
104 # Adjust filename variables appropriately for their locations and detected
105 # presence (or lack thereof) of shim installation
106 AdjustFilenames() {
107 if [[ -f $SourceDir/grub$Platform.efi ]] ; then
108 Source="grub$Platform.efi"
109 Target=$Source
110 if [[ $EspSourceDir == "/efi/boot" ]] ; then
111 SourceShim="boot$Platform.efi"
112 elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then
113 SourceShim="bootmgfw.efi"
114 fi
115 else
116 SourceShim="none"
117 TargetShim="none"
118 if [[ $EspSourceDir == "/efi/boot" ]] ; then
119 Source="boot$Platform.efi"
120 elif [[ $EspSourceDir == "/efi/microsoft/boot" ]] ; then
121 Source="bootmgfw.efi"
122 fi
123 fi
124
125 if [[ $EspTargetDir == "/efi/boot" ]] ; then
126 if [[ $TargetShim == "none" ]] ; then
127 Target="boot$Platform.efi"
128 else
129 TargetShim="boot$Platform.efi"
130 fi
131 elif [[ $EspTargetDir == "/efi/microsoft/boot" ]] ; then
132 if [[ $TargetShim == "none" ]] ; then
133 Target="bootmgfw.efi"
134 else
135 TargetShim="bootmgfw.efi"
136 fi
137 fi
138 } # AdjustFilenames()
139
140 # Checks for the presence of necessary files, including both boot loaders
141 # and support utilities (efibootmgr, etc.)
142 CheckForFiles() {
143 if [[ (! -f $SourceDir/$Source) ||
144 ($SourceShim != "none" && ! -f $SourceDir/SourceShim) ||
145 ! -f $SourceDir/refind.conf ]] ; then
146 echo "There doesn't seem to be a rEFInd installation at $SourceDir!"
147 echo "Aborting!"
148 exit 1
149 fi
150 if [[ $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then
151 Efibootmgr=`which efibootmgr 2> /dev/null`
152 if [[ ! -f $Efibootmgr ]] ; then
153 echo "Moving to a non-default directory requires a working efibootmgr utility, but"
154 echo "one can't be found! Aborting!"
155 exit 1
156 elif [[ ! -d "/sys/firmware/efi" ]] ; then
157 echo "Moving to a non-default directory requires a boot into EFI mode, but we seem"
158 echo "to be running in BIOS mode. (Perhaps typing 'modprobe efivars' will fix this."
159 echo "Aborting!"
160 fi
161 fi
162 } # CheckForFiles()
163
164 # Do final checks & then move the files!
165 MoveFiles() {
166 ExistingFiles=`find $TargetDir -name "*.efi" 2> /dev/null`
167 if [[ -n $ExistingFiles && $EspTargetDir != "/efi/boot" && $EspTargetDir != "/efi/microsoft/boot" ]] ; then
168 echo "$TargetDir isn't empty! Aborting!"
169 exit 1
170 fi
171
172 if [[ $EspTargetDir == "/efi/boot" && -d $TargetDir ]] ; then
173 if [[ -d $InstallDir/EFI/BOOT-rEFIndBackup ]] ; then
174 echo ""
175 echo "Caution: An existing backup of a default boot loader exists! If the current"
176 echo "default boot loader and the backup are different boot loaders, the current"
177 echo "one will become inaccessible."
178 echo ""
179 echo -n "Do you want to proceed with moving (Y/N)? "
180 read YesNo
181 if [[ $YesNo == "Y" || $YesNo == "y" ]] ; then
182 echo "OK; continuing with the move..."
183 else
184 exit 0
185 fi
186 else
187 mv $TargetDir $InstallDir/EFI/BOOT-refindBackup &> /dev/null
188 fi
189 fi
190
191 if [[ $EspTargetDir == "/efi/microsoft/boot" && -d $TargetDir ]] ; then
192 mv -n $EspTargetDir/bootmgfw.efi $InstallDir/EFI/Microsoft/
193 fi
194
195 mkdir -p $TargetDir
196 mv $SourceDir/icons $TargetDir/ 2> /dev/null
197 mv $SourceDir/icons-backup $TargetDir/ 2> /dev/null
198 mv $SourceDir/drivers_* $TargetDir/ 2> /dev/null
199 mv $SourceDir/keys $TargetDir 2> /dev/null
200 mv $SourceDir/$Source $TargetDir/$Target 2> /dev/null
201 mv $SourceDir/$SourceShim $TargetDir/$TargetShim 2> /dev/null
202 mv $SourceDir/refind.conf* $TargetDir/ 2> /dev/null
203 rmdir $SourceDir 2> /dev/null
204 } # MoveFiles()
205
206 # Clean up after moving files -- mainly restoring old backed-up files, if present
207 PostMoveCleanup() {
208 if [[ $EfiSourceDir == "/efi/boot" && -d $InstallDir/EFI/BOOT-rEFIndBackup && ! -d $SourceDir ]] ; then
209 mv $InstallDir/EFI/BOOT-rEFIndBackup $SourceDir 2> /dev/null
210 fi
211 if [[ $EfiSourceDir == "/efi/microsoft/boot" && -f $InstallDir/EFI/Microsoft/bootmgfw.efi ]] ; then
212 mv -n $InstallDir/EFI/Microsoft/bootmgfw.efi $SourceDir/bootmgfw.efi
213 fi
214 } # PostMoveCleanup()
215
216 # If necessary, create a new NVRAM entry for the new location
217 AddNvramEntry() {
218 InstallIt="0"
219 Efibootmgr=`which efibootmgr 2> /dev/null`
220 InstallDisk=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 1-8`
221 PartNum=`grep $InstallDir /etc/mtab | cut -d " " -f 1 | cut -c 9-10`
222
223 if [[ $TargetShim != "none" ]] ; then
224 EntryFilename=$EspTargetDir/$TargetShim
225 else
226 EntryFilename=$EspTargetDir/$Target
227 fi # if/else
228
229 EfiEntryFilename=`echo ${EntryFilename//\//\\\}`
230 EfiEntryFilename2=`echo ${EfiEntryFilename} | sed s/\\\\\\\\/\\\\\\\\\\\\\\\\/g`
231 ExistingEntry=`$Efibootmgr -v | grep -i $EfiEntryFilename2`
232
233 if [[ $ExistingEntry ]] ; then
234 ExistingEntryBootNum=`echo $ExistingEntry | cut -c 5-8`
235 FirstBoot=`$Efibootmgr | grep BootOrder | cut -c 12-15`
236 if [[ $ExistingEntryBootNum != $FirstBoot ]] ; then
237 $Efibootmgr -b $ExistingEntryBootNum -B &> /dev/null
238 InstallIt="1"
239 fi
240 else
241 InstallIt="1"
242 fi
243
244 if [[ $InstallIt == "1" ]] ; then
245 if [[ $EfiTargetDir == "/efi/microsoft/boot" ]] ; then
246 # Name it the way some firmware expects -- see http://mjg59.dreamwidth.org/20187.html
247 $Efibootmgr -c -l $EfiEntryFilename -L "Windows Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
248 else
249 $Efibootmgr -c -l $EfiEntryFilename -L "rEFInd Boot Manager" -d $InstallDisk -p $PartNum &> /dev/null
250 fi
251 if [[ $? != 0 ]] ; then
252 EfibootmgrProblems=1
253 fi
254 fi
255
256 if [[ $EfibootmgrProblems ]] ; then
257 echo
258 echo "ALERT: There were problems running the efibootmgr program! Your moved rEFInd"
259 echo "might not run!"
260 echo
261 fi
262 } # AddNvramEntry
263
264 #
265 # Main body of script
266 #
267
268 if [[ $# != 2 ]] ; then
269 echo "Usage: $0 {source-directory} {target-directory}"
270 exit 1
271 fi
272 if [[ `whoami` != "root" ]] ; then
273 echo "Not running as root! Aborting!"
274 exit 1
275 fi
276
277 FindLinuxESP
278 DeterminePlatform
279 AdjustFilenames
280 CheckForFiles
281 MoveFiles
282 PostMoveCleanup
283 AddNvramEntry