-
Notifications
You must be signed in to change notification settings - Fork 1
/
uefi-mkconfig
executable file
·301 lines (237 loc) · 10.8 KB
/
uefi-mkconfig
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
298
299
300
301
#!/usr/bin/env bash
die() {
echo -e " ${NOCOLOR-\e[1;31m*\e[0m }${*}" >&2
exit 1
}
einfo() {
echo -e " ${NOCOLOR-\e[1;32m*\e[0m }${*}" >&2
}
ewarn() {
echo -e " ${NOCOLOR-\e[1;33m*\e[0m }${*}" >&2
}
check_if_uefi_entry_exists () {
local IFS=$'\n'
local efi_file_path_check
efi_file_path_check="${efi_file_path//\//\\}"
for entry in $(efibootmgr -u); do
# Added last case because while testing this script I found that sometimes, firmware uppercases the path and reverts backslash to forward slash
if [[ "$entry" == *"$partition_partuuid"* ]]; then
if [[ "$entry" == *"(${efi_file_path_check}"* ]] || [[ "$entry" == *"(${efi_file_path_check^^}"* ]]; then
# Get Hex number of a entry
uefi_entry_hex="${entry:4:4}"
return 0
# Added for handling shim entries
elif [[ "$entry" == *"(.${efi_file_path_check}"* ]] || [[ "$entry" == *"(.${efi_file_path_check^^}"* ]]; then
# Get Hex number of a entry
uefi_entry_hex="${entry:4:4}"
return 0
fi
fi
done
return 1
}
add_uefi_entries () (
for efi_file in $partition_efis; do
# Skip this kernel if ignore file is found
if [[ -f "$efi_file.ignore" ]]; then
ewarn "Ignoring \"$efi_file\" from partition \"$partition\"."
continue
fi
# Prepare path which will be inserted into efibootmgr
local efi_file_path
efi_file_path="${efi_file//$partition_mount}"
# Add entry if it doesn't exist
if ! check_if_uefi_entry_exists; then
# Find first free hex address larger than or equal to 0100 for new UEFI boot entry
local bootnum
bootnum=256 # 256 is decimal value of 0100
while [[ "$(efibootmgr -u)" == *"Boot$(printf %04X $bootnum)"* ]]; do
bootnum=$((bootnum + 1))
# Die if script exceeds managed range 0100-0200
if [[ $bootnum -gt 512 ]]; then
die "All IDs, within managed range by uefi-mkconfig, are full!"
fi
done
# Convert chosen entry ID into hex
bootnum="$(printf %04X $bootnum)"
# Get kernel version
## Remove everything before /
local kernel_version
kernel_version="${efi_file_path//*\//}"
## Remove everything before first - to remove any prefixes
kernel_version="${kernel_version/${kernel_version%%-*}-/}"
## Remove .efi suffix if it exists
if [[ "$kernel_version" == *".efi"* ]]; then
kernel_version="${kernel_version/\.${kernel_version##*.}}"
fi
# Create label for UEFI eintry
local partition_label
local entry_label
partition_label="$(lsblk "/dev/$partition" -lno PARTLABEL)"
if [[ -n ${partition_label} ]]; then
entry_label="$kernel_version-$partition_label"
else
entry_label="$kernel_version"
fi
# Create path to initramfs
local initramfs_image
initramfs_image="${efi_file_path/${efi_file_path##*/}}initramfs-$kernel_version.img"
## Add .old suffix to initramfs in case we are handling kernel with -old suffix
[[ "$efi_file_path" == *"-old."* ]] && initramfs_image="${initramfs_image/-old}.old"
# If shim is present in directory, presume it's used for every kernel in said directory
local shim
local adding_kernel_commands
shim="$(find "$partition_mount""${efi_file_path/${efi_file_path##*/}/}" -maxdepth 1 -iname "*shim*.efi")"
if [[ -n "$shim" ]]; then
shim="${shim%%.efi*}.efi"
adding_kernel_commands="${efi_file_path//\//\\} ${kernel_commands}"
ewarn "Creating UEFI entry \"$bootnum\" for \"$partition_mount$efi_file_path\" using shim \"$shim\" found on \"$partition\"..."
efi_file_path="${efi_file_path/${efi_file_path##*/}/}${shim/*\//}"
else
adding_kernel_commands="${kernel_commands}"
ewarn "Creating UEFI entry \"$bootnum\" for \"$partition_mount$efi_file_path\" found on \"$partition\"..."
fi
# Check if microcode image exists
## microcode image can be ignored the same way as kernel image via .ignore suffix
local microcode_path
microcode_path="${efi_file_path/${efi_file_path##*/}}"
if [[ -f "${partition_mount}${microcode_path}amd-uc.img" ]] && [[ ! -f "${partition_mount}${microcode_path}amd-uc.img.ignore" ]]; then
adding_kernel_commands="${adding_kernel_commands} initrd=${microcode_path//\//\\}amd-uc.img"
fi
if [[ -f "${partition_mount}${microcode_path}intel-uc.img" ]] && [[ ! -f "${partition_mount}${microcode_path}intel-uc.img.ignore" ]]; then
adding_kernel_commands="${adding_kernel_commands} initrd=${microcode_path//\//\\}intel-uc.img"
fi
# Check if corresponding initramfs exists
if [[ -f "$partition_mount$initramfs_image" ]]; then
adding_kernel_commands="${adding_kernel_commands} initrd=${initramfs_image//\//\\}"
else
ewarn "No initramfs found for \"$partition_mount$efi_file_path\"."
fi
# Add new entry
efibootmgr --create -b "$bootnum" --disk /dev/"$partition" --label "$entry_label" --loader "${efi_file_path//\//\\}"\
-u "$adding_kernel_commands" &>/dev/null || die "Failed to add UEFI entry for \"$efi_file_path\""
else
einfo "Existing UEFI Entry \"$uefi_entry_hex\" for \"$partition_mount$efi_file_path\" from partition \"$partition\" has been found."
fi
done
)
remove_uefi_entries () {
local IFS=$'\n'
for entry in $(efibootmgr -u | grep "$partition_partuuid"); do
# Get Hex number of a entry
local uefi_entry_hex
uefi_entry_hex="${entry:4:4}"
# Check if the entry is within range managed by uefi-mkconfig
if [[ $((16#$uefi_entry_hex)) -gt 255 ]] && [[ $((16#$uefi_entry_hex)) -lt 513 ]]; then
local entry_efi_path
local entry_kernel_commands
# Create path to efi file
## Decide if entry is shim entry or not
if [[ "$entry" == *"File("*"shim"*")"* ]] || [[ "$entry" == *"File("*"SHIM"*")"* ]]; then
### Remove everything after and included with last character )
entry_efi_path="${entry##*(\.}"
### Remove everything after and included with last space
entry_efi_path="${entry_efi_path%%\ *}"
### Prepare Entry kernel commands in case of shim booting
entry_kernel_commands=${entry##*\.efi}
entry_kernel_commands=${entry_kernel_commands//)*}
entry_kernel_commands=${entry_kernel_commands/#\ }
else
### Remove everything before first mention of string File(
entry_efi_path="${entry/${entry%%File(*}File\(/}"
### Remove everything after first ) character
entry_efi_path="${entry_efi_path%%)*}"
### Prepare Entry kernel commands
entry_kernel_commands=${entry/#*\.efi)}
fi
# Remove initramfs entry from the kernel commands
entry_kernel_commands=${entry_kernel_commands// initrd*}
# Check if efi file exists and if this entry in in managed range
if [ ! -f "$partition_mount${entry_efi_path//\\/\/}" ] || [ -f "$partition_mount${entry_efi_path//\\/\/}.ignore" ]; then
# Delete entry
ewarn "Deleting UEFI entry \"$uefi_entry_hex\"! Its EFI file \"$partition_mount${entry_efi_path//\\/\/}\" wasn't found."
efibootmgr -q -B -b "$uefi_entry_hex" || die "Failed to delete entry \"$uefi_entry_hex\""
# Delete entry if kernel commands are not the same as in config file. Don't do this if kernel commands are taken from /proc/cmdline
elif [[ "$kernel_commands" != "$entry_kernel_commands" ]] && [[ -z $proc_kernel_commands ]]; then
# Delete entry for regeneration
ewarn "Deleting UEFI entry \"$uefi_entry_hex\" for regeneration! Kernel commads in configuration differ from the ones in this entry."
efibootmgr -q -B -b "$uefi_entry_hex" || die "Failed to delete entry \"$uefi_entry_hex\""
fi
fi
done
}
main () {
efi_parttype="c12a7328-f81f-11d2-ba4b-00a0c93ec93b"
mounted_efi_partitions=$(lsblk -lo NAME,MOUNTPOINTS,PARTTYPE | grep "$efi_parttype" | grep "/" | cut -d' ' -f1 | sort -r)
proc_kernel_commands=
valid_kernel_commands=
kernel_prefixes="vmlinuz vmlinux- kernel- bzImage zImage"
einfo "Running uefi-mkconfig..."
[[ ${EUID} -eq 0 ]] || die "Please run uefi-mkconfig as root!"
[[ -n ${mounted_efi_partitions} ]] || die "No mounted efi partitions!"
[[ -n "$(command -v efibootmgr)" ]] || die "efibootmgr dependency not found!"
# Load kernel commands from config files
if [[ -n "${INSTALLKERNEL_CONF_ROOT}" ]]; then
if [[ -f "${INSTALLKERNEL_CONF_ROOT}/uefi-mkconfig" ]]; then
kernel_commands="$(tr -s "${IFS}" ' ' <"${KERNEL_INSTALL_CONF_ROOT}/uefi-mkconfig")"
fi
elif [[ -f /etc/default/uefi-mkconfig ]]; then
kernel_commands="$(tr -s "${IFS}" ' ' </etc/default/uefi-mkconfig)"
einfo "Using kernel commands from \"/etc/default/uefi-mkconfig\""
elif [[ -f /etc/kernel/uefi-mkconfig ]]; then
kernel_commands="$(tr -s "${IFS}" ' ' </etc/kernel/uefi-mkconfig)"
einfo "Using kernel commands from \"/etc/kernel/uefi-mkconfig\""
elif [[ -f /usr/lib/kernel/uefi-mkconfig ]]; then
kernel_commands="$(tr -s "${IFS}" ' ' </usr/lib/kernel/uefi-mkconfig)"
einfo "Using kernel commands from \"/usr/lib/kernel/uefi-mkconfig\""
else
kernel_commands="$(tr -s "${IFS}" '\n' </proc/cmdline | grep -ve '^BOOT_IMAGE=' -e '^initrd=' | tr '\n' ' ')"
proc_kernel_commands=1
ewarn "Warning, using kernel commands from \"/proc/cmdline\"!"
fi
# Get kernel prefix from os-release
if [[ -f /etc/os-release ]]; then
. /etc/os-release
kernel_prefixes="${kernel_prefixes} ${ID}-"
elif [[ -f /usr/lib/os-release ]]; then
. /usr/lib/os-release
kernel_prefixes="${kernel_prefixes} ${ID}-"
fi
# Get kernel prefix from entry-token
if [[ -f /etc/kernel/entry-token ]]; then
kernel_prefixes="${kernel_prefixes} $(head -n1 /etc/kernel/entry-token)-"
elif [[ -f /usr/lib/kernel/entry-token ]]; then
kernel_prefixes="${kernel_prefixes} $(head -n1 /usr/lib/kernel/entry-token)-"
fi
# Verify kernel commands
for check_config in $kernel_commands; do
# Strip initrd=* from config file
[[ "$check_config" != *"initrd="* ]] && strip_kernel_commands="$strip_kernel_commands $check_config"
# Verify if "root=" is present
[[ "$check_config" == "root="* ]] && valid_kernel_commands=1
done
kernel_commands="$strip_kernel_commands"
[[ -z $valid_kernel_commands ]] && ewarn "Warning, kernel command \"root=\" is missing from loaded configuration!"
for partition in $mounted_efi_partitions; do
# Find partition uuid
partition_partuuid=$(lsblk "/dev/$partition" -lno PARTUUID)
# Find where disk is mounted
# Head at the end deals with cases where this partition is mounted in multiple places
partition_mount=$(lsblk /dev/"$partition" -lno MOUNTPOINTS | head -n 1)
# Find all .efi files on this partition
for prefix in $kernel_prefixes; do
find_results="$(find "$partition_mount" -name "$prefix*.efi" -printf "%f\n")"
[[ -n "$find_results" ]] && kernel_images+="$find_results "
done
kernel_images="$(sort -uV <<< "$kernel_images")"
# Add path back to the kernel image
for kernel_image in $kernel_images; do
partition_efis+="$(find "$partition_mount" -name "$kernel_image") "
done
# Remove invalid entries
remove_uefi_entries
# Add missiong efi entries for efi files that exist
add_uefi_entries
done
}
main