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