]> git.proxmox.com Git - pve-kernel-meta.git/blame - bin/proxmox-boot-tool
proxmox-boot-tool: rename from pve-efiboot-tool
[pve-kernel-meta.git] / bin / proxmox-boot-tool
CommitLineData
b3d47d2d
SI
1#!/bin/sh
2
3set -e
4
5. /usr/share/pve-kernel-helper/scripts/functions
6
2955b2b7
FG
7_add_entry_to_list_file() {
8 file="$1"
9 entry="$2"
10
11 if [ -e "$file" ]; then
12 cp "$file" "$file.new"
13 fi
14 echo "$entry" >> "$file.new"
15 sort -uo "$file.new" "$file.new"
16 mv "$file.new" "$file"
17}
18
19_remove_entry_from_list_file() {
20 file="$1"
21 entry="$2"
22
23 # guard against removing whole file by accident!
24 if [ -z "$entry" ]; then
25 echo "cannot remove empty entry from '$file'."
26 return
27 fi
28
29 if [ -e "$file" ]; then
30 grep -vFx "$entry" "$file" > "$file.new" || true
31 mv "$file.new" "$file"
32 else
33 echo "'$file' does not exist.."
34 fi
35}
b3d47d2d
SI
36
37_get_partition_info() {
38 if [ ! -e "$1" ]; then
39 warn "E: '$1' does not exist!"
40 exit 1
41 fi
42 bdev=$(realpath "$1")
43 if [ ! -b "$bdev" ]; then
44 warn "E: '$bdev' is not a block device!"
45 exit 1
46 fi
47
48 bdev_info=$( \
49 lsblk \
50 --bytes \
51 --pairs \
52 -o 'UUID,SIZE,FSTYPE,PARTTYPE,PKNAME,MOUNTPOINT' \
53 "$bdev" \
54 )
55 if [ -z "$bdev_info" ]; then
56 warn "E: unable to get information about block device '$1'!"
57 exit 1
58 fi
59
60 count=$(echo "$bdev_info" | grep -c '^')
61 if [ "$count" -ne '1' ]; then
62 echo "$bdev_info"
63 warn "E: block device '$1' has children!"
64 exit 1
65 fi
66
67 echo "$bdev_info"
68 eval "$bdev_info"
69
70 if [ -z "$PKNAME" ]; then
71 warn "E: cannot determine parent device of '$1' - please provide a partition, not a full disk."
72 exit 1
73 fi
74
75 if [ -n "$SIZE" ] && [ "$SIZE" -lt 268435456 ]; then
76 warn "E: '$1' is too small (<256M)."
77 exit 1
78 fi
79
80 if [ -n "$MOUNTPOINT" ]; then
81 warn "E: '$1' is mounted on '$MOUNTPOINT' - exiting."
82 exit 1
83 fi
84}
85
86format() {
87 part="$1"
88 force="$2"
89
90 _get_partition_info "$part"
91
92 if [ -n "$FSTYPE" ]; then
93 if [ -z "$force" ] || [ "$force" != '--force' ]; then
94 warn "E: '$part' contains a filesystem ('$FSTYPE') - exiting (use --force to override)"
95 exit 1
96 fi
97 fi
98
5d733131 99 part_basename=$(basename "$bdev")
b3d47d2d 100 if [ -z "$part_basename" ]; then
78c0b9cb
AL
101 if [ $part != $bdev ]; then
102 symlinkmsg=" -> '$bdev'"
103 fi
104 warn "E: unable to determine basename of '$part'$symlinkmsg"
b3d47d2d
SI
105 exit 1
106 fi
107
108 part_num=$(cat /sys/block/"$PKNAME"/"$part_basename"/partition)
109 if [ -z "$part_num" ]; then
110 warn "E: unable to determine partition number of '$part'"
111 exit 1
112 fi
113
114 if [ -z "$PARTTYPE" ] || [ "$PARTTYPE" != "$ESPTYPE" ]; then
115 echo "Setting partition type of '$part' to '$ESPTYPE'.."
116 sgdisk "-t$part_num:$ESPTYPE" "/dev/$PKNAME"
117 echo "Calling 'udevadm settle'.."
118 udevadm settle --timeout=5
119 fi
120
121 echo "Formatting '$part' as vfat.."
122 mkfs.vfat -F 32 "$part"
123 echo "Done."
124 exit 0
125}
126
127init() {
128 part="$1"
129
130 _get_partition_info "$part"
131
132 if [ -z "$PARTTYPE" ] || [ "$PARTTYPE" != "$ESPTYPE" ]; then
133 warn "E: '$part' has wrong partition type (!= $ESPTYPE)."
134 exit 1
135 fi
136
137 if [ -z "$FSTYPE" ] || [ "$FSTYPE" != 'vfat' ]; then
138 warn "E: '$part' has wrong filesystem (!= vfat)."
139 exit 1
140 fi
141
142 if [ -z "$UUID" ]; then
143 warn "E: '$part' has no UUID set, required for mounting."
144 exit 1
145 fi
146
147 esp_mp="/var/tmp/espmounts/$UUID"
148
149 mkdir -p "$esp_mp"
150 echo "Mounting '$part' on '$esp_mp'."
151 mount -t vfat "$part" "$esp_mp"
152
153 echo "Installing systemd-boot.."
154 mkdir -p "$esp_mp/$PMX_ESP_DIR"
155 bootctl --path "$esp_mp" install
156
157 echo "Configuring systemd-boot.."
158 echo "timeout 3" > "$esp_mp/$PMX_LOADER_CONF.tmp"
159 echo "default proxmox-*" >> "$esp_mp/$PMX_LOADER_CONF.tmp"
160 mv "$esp_mp/$PMX_LOADER_CONF.tmp" "$esp_mp/$PMX_LOADER_CONF"
161 echo "Unmounting '$part'."
162 umount "$part"
163
164 echo "Adding '$part' to list of synced ESPs.."
2955b2b7 165 _add_entry_to_list_file "$ESP_LIST" "$UUID"
b3d47d2d
SI
166
167 echo "Refreshing kernels and initrds.."
168 refresh
169}
170
0956bd22
FG
171_clean_impl() {
172 if [ ! -e "/dev/disk/by-uuid/" ]; then
173 warn 'E: /dev/disk/by-uuid does not exist, aborting!'
174 exit 1
175 fi
176 echo -n "Checking whether ESP '$curr_uuid' exists.. "
177 if [ -e "/dev/disk/by-uuid/$curr_uuid" ]; then
178 echo "Found!"
179 else
180 echo "Not found!"
181 if [ -z "$dry_run" ] || [ "$dry_run" != '--dry-run' ]; then
182 _remove_entry_from_list_file "$ESP_LIST" "$curr_uuid"
183 fi
184 fi
185}
186
187clean() {
188 dry_run="$1"
189 rm -f "$ESP_LIST".tmp
190 loop_esp_list _clean_impl
191 if [ "$?" -eq 2 ]; then
192 warn "E: $ESP_LIST does not exist."
193 exit 1
194 fi
195 if [ -e "$ESP_LIST".tmp ]; then
196 mv "$ESP_LIST".tmp "$ESP_LIST"
197 fi
198}
199
b3d47d2d 200refresh() {
27d93251 201 hook=$1
b3c98062 202 hookscripts='proxmox-auto-removal zz-proxmox-boot'
27d93251
FG
203
204 if [ -n "$hook" ]; then
205 if echo "$hookscripts" | grep -sqE "(^|[[:space:]]+)$hook([[:space:]]+|$)"; then
206 hookscripts="$hook"
207 else
208 warn "E: '$hook' is not a valid hook script name.";
209 exit 1;
210 fi
6e829c9b
SR
211 fi
212
c2c22297 213 for script in $hookscripts; do
6e829c9b
SR
214 scriptpath="/etc/kernel/postinst.d/$script"
215 if [ -f "$scriptpath" ] && [ -x "$scriptpath" ]; then
216 echo "Running hook script '$script'.."
217 $scriptpath
218 else
219 warn "Hook script '$script' not found or not executable, skipping."
220 fi
c2c22297 221 done
b3d47d2d
SI
222}
223
427fba71
FG
224add_kernel() {
225 ver="$1"
226
227 if [ -z "$ver" ]; then
228 warn "E: <kernel-version> is mandatory"
229 warn ""
230 exit 1
231 fi
232
233 if [ ! -e "/boot/vmlinuz-$ver" ]; then
234 warn "E: no kernel image found in /boot for '$ver', not adding."
235 exit 1
236 fi
237 _add_entry_to_list_file "$MANUAL_KERNEL_LIST" "$ver"
d0519968 238 echo "Added kernel '$ver' to manual kernel list. Use the 'refresh' command to update the ESPs."
427fba71
FG
239}
240
241remove_kernel() {
242 ver="$1"
243
244 if [ -z "$ver" ]; then
245 warn "E: <kernel-version> is mandatory"
246 warn ""
247 exit 1
248 fi
249
250 if grep -sqFx "$ver" "$MANUAL_KERNEL_LIST"; then
251 _remove_entry_from_list_file "$MANUAL_KERNEL_LIST" "$ver"
d0519968 252 echo "Removed kernel '$ver' from manual kernel list. Use the 'refresh' command to update the ESPs."
427fba71
FG
253 else
254 echo "Kernel '$ver' not found in manual kernel list."
255 fi
256}
257
2d7389fb
FG
258list_kernels() {
259 boot_kernels="$(boot_kernel_list)"
260
261 if [ -e "$MANUAL_KERNEL_LIST" ]; then
6a3c4ace 262 manual_kernels="$(cat "$MANUAL_KERNEL_LIST" || true)"
4f11dd63 263 boot_kernels="$(echo "$boot_kernels" | grep -Fxv -f "$MANUAL_KERNEL_LIST" || true)"
2d7389fb
FG
264 fi
265
266 if [ -z "$manual_kernels" ]; then
267 manual_kernels="None."
268 fi
269
270 echo "Manually selected kernels:"
271 echo "$manual_kernels"
272 echo ""
273 echo "Automatically selected kernels:"
274 echo "$boot_kernels"
275}
276
b3d47d2d
SI
277usage() {
278 warn "USAGE: $0 <commands> [ARGS]"
279 warn ""
280 warn " $0 format <partition> [--force]"
281 warn " $0 init <partition>"
0956bd22 282 warn " $0 clean [--dry-run]"
6e829c9b 283 warn " $0 refresh [--hook <name>]"
992c689e
TL
284 warn " $0 kernel <add|remove> <kernel-version>"
285 warn " $0 kernel list"
0b99d576 286 warn " $0 help"
b3d47d2d
SI
287}
288
289help() {
290 echo "USAGE: $0 format <partition> [--force]"
291 echo ""
292 echo " format <partition> as EFI system partition. Use --force to format even if <partition> is currently in use."
293 echo ""
294 echo "USAGE: $0 init <partition>"
295 echo ""
296 echo " initialize EFI system partition at <partition> for automatic synchronization of pve-kernels and their associated initrds."
297 echo ""
0956bd22
FG
298 echo "USAGE: $0 clean [--dry-run]"
299 echo ""
300 echo " remove no longer existing EFI system partition UUIDs from $ESP_LIST. Use --dry-run to only print outdated entries instead of removing them."
301 echo ""
6e829c9b 302 echo "USAGE: $0 refresh [--hook <name>]"
b3d47d2d 303 echo ""
6e829c9b 304 echo " refresh all configured EFI system partitions. Use --hook to only run the specified hook, omit to run all."
b3d47d2d 305 echo ""
992c689e 306 echo "USAGE: $0 kernel <add|remove> <kernel-version>"
427fba71
FG
307 echo ""
308 echo " add/remove pve-kernel with ABI <kernel-version> to list of synced kernels, in addition to automatically selected ones."
d0519968 309 echo " NOTE: you need to manually run 'refresh' once you're finished with adding/removing kernels from the list"
427fba71 310 echo ""
992c689e 311 echo "USAGE: $0 kernel list"
2d7389fb
FG
312 echo ""
313 echo " list kernel versions currently selected for inclusion on ESPs."
314 echo ""
b3d47d2d
SI
315}
316
317if [ -z "$1" ]; then
318 usage
319 exit 0
320fi
321
322case "$1" in
323 'format')
324 shift
325 if [ -z "$1" ]; then
326 warn "E: <partition> is mandatory."
327 warn ""
328 usage
329 exit 1
330 fi
331 format "$@"
332 exit 0
333 ;;
334 'init')
420039cd 335 reexec_in_mountns "$@"
b3d47d2d
SI
336 shift
337 if [ -z "$1" ]; then
338 warn "E: <partition> is mandatory."
339 warn ""
340 usage
341 exit 1
342 fi
343 init "$@"
344 exit 0
345 ;;
0956bd22
FG
346 'clean')
347 shift
348 clean "$@"
349 exit 0
350 ;;
b3d47d2d
SI
351 'refresh')
352 shift
6e829c9b
SR
353 if [ "$#" -eq 0 ]; then
354 refresh
355 elif [ "$#" -eq 2 ] && [ "$1" = "--hook" ]; then
356 refresh "$2"
357 else
358 usage
359 exit 1
360 fi
b3d47d2d
SI
361 exit 0
362 ;;
992c689e 363 'kernel'|'kernels')
427fba71
FG
364 shift
365 if [ -z "$1" ]; then
992c689e 366 warn "E: subcommand is mandatory for 'kernel'."
427fba71
FG
367 warn ""
368 usage
369 exit 1
370 fi
371 cmd="$1"
372 case "$cmd" in
373 'add')
374 add_kernel "$2"
375 exit 0
376 ;;
377 'remove')
378 remove_kernel "$2"
379 exit 0
380 ;;
2d7389fb
FG
381 'list')
382 list_kernels
383 exit 0
384 ;;
427fba71 385 *)
992c689e 386 warn "E: invalid 'kernel' subcommand '$cmd'."
427fba71
FG
387 warn ""
388 usage
389 exit 1
390 ;;
391 esac
392 ;;
b3d47d2d
SI
393 'help')
394 shift
395 help
396 exit 0
397 ;;
398 *)
399 warn "Invalid/unknown command '$1'."
400 warn ""
401 usage
402 exit 1
403 ;;
404esac
405
406exit 1