5 .
/usr
/share
/pve-kernel-helper
/scripts
/functions
7 _add_entry_to_list_file
() {
11 if [ -e "$file" ]; then
12 cp "$file" "$file.new"
14 echo "$entry" >> "$file.new"
15 sort -uo "$file.new" "$file.new"
16 mv "$file.new" "$file"
19 _remove_entry_from_list_file
() {
23 # guard against removing whole file by accident!
24 if [ -z "$entry" ]; then
25 echo "cannot remove empty entry from '$file'."
29 if [ -e "$file" ]; then
30 grep -vFx "$entry" "$file" > "$file.new" || true
31 mv "$file.new" "$file"
33 echo "'$file' does not exist.."
37 _get_partition_info
() {
38 if [ ! -e "$1" ]; then
39 warn
"E: '$1' does not exist!"
43 if [ ! -b "$bdev" ]; then
44 warn
"E: '$bdev' is not a block device!"
52 -o 'UUID,SIZE,FSTYPE,PARTTYPE,PKNAME,MOUNTPOINT' \
55 if [ -z "$bdev_info" ]; then
56 warn
"E: unable to get information about block device '$1'!"
60 count
=$
(echo "$bdev_info" |
grep -c '^')
61 if [ "$count" -ne '1' ]; then
63 warn
"E: block device '$1' has children!"
70 if [ -z "$PKNAME" ]; then
71 warn
"E: cannot determine parent device of '$1' - please provide a partition, not a full disk."
75 if [ -n "$SIZE" ] && [ "$SIZE" -lt 268435456 ]; then
76 warn
"E: '$1' is too small (<256M)."
80 if [ -n "$MOUNTPOINT" ]; then
81 warn
"E: '$1' is mounted on '$MOUNTPOINT' - exiting."
90 _get_partition_info
"$part"
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)"
99 part_basename
=$
(basename "$bdev")
100 if [ -z "$part_basename" ]; then
101 if [ "$part" != "$bdev" ]; then
102 symlinkmsg
=" -> '$bdev'"
104 warn
"E: unable to determine basename of '$part'$symlinkmsg"
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'"
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
121 echo "Formatting '$part' as vfat.."
122 mkfs.vfat
-F 32 "$part"
130 _get_partition_info
"$part"
132 if [ -z "$PARTTYPE" ] ||
[ "$PARTTYPE" != "$ESPTYPE" ]; then
133 warn
"E: '$part' has wrong partition type (!= $ESPTYPE)."
137 if [ -z "$FSTYPE" ] ||
[ "$FSTYPE" != 'vfat' ]; then
138 warn
"E: '$part' has wrong filesystem (!= vfat)."
142 if [ -z "$UUID" ]; then
143 warn
"E: '$part' has no UUID set, required for mounting."
147 esp_mp
="/var/tmp/espmounts/$UUID"
150 echo "Mounting '$part' on '$esp_mp'."
151 mount
-t vfat
"$part" "$esp_mp"
153 if [ -d /sys
/firmware
/efi
]; then
154 echo "Installing systemd-boot.."
155 mkdir
-p "$esp_mp/$PMX_ESP_DIR"
156 bootctl
--graceful --path "$esp_mp" install
158 echo "Configuring systemd-boot.."
159 echo "timeout 3" > "$esp_mp/$PMX_LOADER_CONF.tmp"
160 echo "default proxmox-*" >> "$esp_mp/$PMX_LOADER_CONF.tmp"
161 mv "$esp_mp/$PMX_LOADER_CONF.tmp" "$esp_mp/$PMX_LOADER_CONF"
163 echo "Installing grub i386-pc target.."
165 --boot-directory "$esp_mp" \
168 --bootloader-id='proxmox' \
171 echo "Unmounting '$part'."
174 echo "Adding '$part' to list of synced ESPs.."
175 _add_entry_to_list_file
"$ESP_LIST" "$UUID"
177 echo "Refreshing kernels and initrds.."
182 if [ ! -e "/dev/disk/by-uuid/" ]; then
183 warn
'E: /dev/disk/by-uuid does not exist, aborting!'
186 printf "Checking whether ESP '%s' exists.. " "$curr_uuid" # avoid newline
187 if [ -e "/dev/disk/by-uuid/$curr_uuid" ]; then
191 if [ -z "$dry_run" ] ||
[ "$dry_run" != '--dry-run' ]; then
192 _remove_entry_from_list_file
"$ESP_LIST" "$curr_uuid"
199 rm -f "$ESP_LIST".tmp
200 loop_esp_list _clean_impl
201 if [ "$?" -eq 2 ]; then
202 warn
"E: $ESP_LIST does not exist."
205 if [ -e "$ESP_LIST".tmp
]; then
206 mv "$ESP_LIST".tmp
"$ESP_LIST"
209 echo "Sorting and removing duplicate ESPs.."
210 sort -uo "$ESP_LIST".tmp
"$ESP_LIST"
211 mv "$ESP_LIST".tmp
"$ESP_LIST"
216 hookscripts
='proxmox-auto-removal zz-proxmox-boot'
218 if [ -n "$hook" ]; then
219 if echo "$hookscripts" |
grep -sqE "(^|[[:space:]]+)$hook([[:space:]]+|$)"; then
222 warn
"E: '$hook' is not a valid hook script name.";
227 for script in $hookscripts; do
228 scriptpath
="/etc/kernel/postinst.d/$script"
229 if [ -f "$scriptpath" ] && [ -x "$scriptpath" ]; then
230 echo "Running hook script '$script'.."
233 warn
"Hook script '$script' not found or not executable, skipping."
241 if [ -z "$ver" ]; then
242 warn
"E: <kernel-version> is mandatory"
247 if [ ! -e "/boot/vmlinuz-$ver" ]; then
248 warn
"E: no kernel image found in /boot for '$ver', not adding."
251 _add_entry_to_list_file
"$MANUAL_KERNEL_LIST" "$ver"
252 echo "Added kernel '$ver' to manual kernel list. Use the 'refresh' command to update the ESPs."
258 if [ -z "$ver" ]; then
259 warn
"E: <kernel-version> is mandatory"
264 if grep -sqFx "$ver" "$MANUAL_KERNEL_LIST"; then
265 _remove_entry_from_list_file
"$MANUAL_KERNEL_LIST" "$ver"
266 echo "Removed kernel '$ver' from manual kernel list. Use the 'refresh' command to update the ESPs."
268 echo "Kernel '$ver' not found in manual kernel list."
273 boot_kernels
="$(boot_kernel_list)"
275 if [ -e "$MANUAL_KERNEL_LIST" ]; then
276 manual_kernels
="$(cat "$MANUAL_KERNEL_LIST" || true)"
277 boot_kernels
="$(echo "$boot_kernels" | grep -Fxv -f "$MANUAL_KERNEL_LIST" || true)"
280 if [ -z "$manual_kernels" ]; then
281 manual_kernels
="None."
284 echo "Manually selected kernels:"
285 echo "$manual_kernels"
287 echo "Automatically selected kernels:"
290 pinned_kernel
="$(get_first_line "$PINNED_KERNEL_CONF")"
291 nextboot_kernel
="$(get_first_line "$NEXT_BOOT_PIN")"
292 if [ -n "$pinned_kernel" ]; then
294 echo "Pinned kernel:"
295 echo "${pinned_kernel}"
297 if [ -n "$nextboot_kernel" ]; then
299 echo "Kernel pinned on next-boot:"
300 echo "${nextboot_kernel}"
306 if [ -z "$subcmd" ]; then
307 warn
"USAGE: $0 <commands> [ARGS]"
310 if [ -z "$subcmd" ] ||
[ "$subcmd" = "format" ]; then
311 warn
" $0 format <partition> [--force]"
313 if [ -z "$subcmd" ] ||
[ "$subcmd" = "init" ]; then
314 warn
" $0 init <partition>"
316 if [ -z "$subcmd" ] ||
[ "$subcmd" = "clean" ]; then
317 warn
" $0 clean [--dry-run]"
319 if [ -z "$subcmd" ] ||
[ "$subcmd" = "refresh" ]; then
320 warn
" $0 refresh [--hook <name>]"
322 if [ -z "$subcmd" ] ||
[ "$subcmd" = "kernel" ]; then
323 warn
" $0 kernel <add|remove> <kernel-version>"
324 warn
" $0 kernel pin <kernel-version> [--next-boot]"
325 warn
" $0 kernel unpin [--next-boot]"
326 warn
" $0 kernel list"
328 if [ -z "$subcmd" ] ||
[ "$subcmd" = "status" ]; then
329 warn
" $0 status [--quiet]"
331 if [ -z "$subcmd" ] ||
[ "$subcmd" = "help" ]; then
337 echo "USAGE: $0 format <partition> [--force]"
339 echo " format <partition> as EFI system partition. Use --force to format even if <partition> is currently in use."
341 echo "USAGE: $0 init <partition>"
343 echo " initialize EFI system partition at <partition> for automatic synchronization of pve-kernels and their associated initrds."
345 echo "USAGE: $0 clean [--dry-run]"
347 echo " remove no longer existing EFI system partition UUIDs from $ESP_LIST. Use --dry-run to only print outdated entries instead of removing them."
349 echo "USAGE: $0 refresh [--hook <name>]"
351 echo " refresh all configured EFI system partitions. Use --hook to only run the specified hook, omit to run all."
353 echo "USAGE: $0 kernel <add|remove> <kernel-version>"
355 echo " add/remove pve-kernel with ABI <kernel-version> to list of synced kernels, in addition to automatically selected ones."
356 echo " NOTE: you need to manually run 'refresh' once you're finished with adding/removing kernels from the list"
358 echo "USAGE: $0 kernel pin <kernel-version> [--next-boot]"
360 echo " pin pve-kernel with ABI <kernel-version> as the default entry to be booted."
361 echo " with --next-boot sets <kernel-version> only for the next boot."
362 echo " NOTE: you need to manually run 'refresh' once you're finished with pinning kernels"
364 echo "USAGE: $0 kernel unpin [--next-boot]"
366 echo " unpin removes pinned and next-boot kernel settings."
367 echo " with --next-boot only removes the pin for the next boot."
369 echo "USAGE: $0 kernel list"
371 echo " list kernel versions currently selected for inclusion on ESPs."
373 echo "USAGE: $0 status [--quiet]"
375 echo " Print details about the ESPs configuration. Exits with 0 if any ESP is configured, else with 2."
380 if ! (echo "${curr_uuid}" |
grep -qE '[0-9a-fA-F]{4}-[0-9a-fA-F]{4}'); then
381 warn
"WARN: ${curr_uuid} read from ${ESP_LIST} does not look like a VFAT-UUID - skipping"
385 path
="/dev/disk/by-uuid/$curr_uuid"
386 if [ ! -e "${path}" ]; then
387 warn
"WARN: ${path} does not exist - clean '${ESP_LIST}'! - skipping"
391 mountpoint
="${MOUNTROOT}/${curr_uuid}"
392 mkdir
-p "${mountpoint}" || \
393 { warn
"creation of mountpoint ${mountpoint} failed - skipping"; return; }
394 mount
"${path}" "${mountpoint}" || \
395 { warn
"mount of ${path} failed - skipping"; return; }
398 if [ -f "${mountpoint}/$PMX_LOADER_CONF" ]; then
399 if [ ! -d "${mountpoint}/$PMX_ESP_DIR" ]; then
400 warn
"${path}/$PMX_ESP_DIR does not exist"
402 versions_uefi
=$
(ls -1 ${mountpoint}/$PMX_ESP_DIR |
awk '{printf (NR>1?", ":"") $0}')
403 result
="uefi (versions: ${versions_uefi})"
405 if [ -d "${mountpoint}/grub" ]; then
406 versions_grub
=$
(ls -1 ${mountpoint}/vmlinuz-
* |
awk '{ gsub(/.*\/vmlinuz-/, ""); printf (NR>1?", ":"") $0 }')
407 if [ -n "$result" ]; then
408 result
="${result}, grub (versions: ${versions_grub})"
410 result
="grub (versions: ${versions_grub})"
413 echo "$curr_uuid is configured with: $result"
414 umount
"${mountpoint}" || \
415 { warn
"umount of ${path} failed - failure"; exit 0; }
417 rmdir "${mountpoint}" || true
422 if [ ! -e "${ESP_LIST}" ]; then
423 if [ -z "$quiet" ]; then
424 warn
"E: $ESP_LIST does not exist."
428 if [ -z "$quiet" ]; then
429 if [ -d /sys
/firmware
/efi
]; then
430 echo "System currently booted with uefi"
432 echo "System currently booted with legacy bios"
434 loop_esp_list _status_detail
438 _ask_interactive_refresh
() {
441 if [ -t 0 ] && [ -t 1 ]; then # check if interactive
443 printf "Refresh the actual boot ESPs now? [yN] "
445 if [ "$do_refresh" != "${do_refresh#[Yy]}" ] ;then
448 echo "Skip auto-refresh, you can call it any time to enact boot changes."
451 echo "$msg. Use the 'refresh' command to update the ESPs."
459 if [ -z "$ver" ]; then
460 boot_kernels
="$(boot_kernel_list)"
461 warn
"E: <kernel-version> is mandatory"
463 warn
"Possible Proxmox kernel versions are:"
468 if [ -z "$pin_file" ]; then
469 pin_file
="$PINNED_KERNEL_CONF"
472 if [ ! -e "/boot/vmlinuz-$ver" ]; then
473 boot_kernels
="$(boot_kernel_list)"
474 warn
"E: no kernel image found in /boot for '$ver', not setting default."
476 warn
"Possible Proxmox kernel versions are:"
481 if [ -e "$pin_file" ]; then
482 old_pin
=$
(get_first_line
"${pin_file}")
483 if [ "$ver" != "$old_pin" ]; then
484 echo "Overriding previously pinned version '$old_pin' with '$ver'"
487 echo "$ver" > "$pin_file"
489 if [ -f "${ESP_LIST}" ]; then
490 _ask_interactive_refresh
"Set kernel '$ver' in $pin_file"
492 next_boot_ver
=$
(get_first_line
"${NEXT_BOOT_PIN}")
493 pin_ver
="${next_boot_ver:-$ver}"
494 echo "Setting '$pin_ver' as grub default entry and running update-grub."
495 set_grub_default
"$pin_ver"
501 last_pin
=$
(get_first_line
"${NEXT_BOOT_PIN}")
502 rm -f "$NEXT_BOOT_PIN"
503 echo "Removed $NEXT_BOOT_PIN."
505 old_pin
=$
(get_first_line
"${PINNED_KERNEL_CONF}")
506 last_pin
=${old_pin:-$last_pin}
507 rm -f "$PINNED_KERNEL_CONF"
508 echo "Removed $PINNED_KERNEL_CONF."
511 if [ -f "${ESP_LIST}" ]; then
512 if [ -n "$last_pin" ]; then
513 _ask_interactive_refresh
"Unpinned kernel '$last_pin'"
516 echo "Reset default grub entry and running update-grub."
517 pinned_kernel
=$
(get_first_line
"${PINNED_KERNEL_CONF}")
518 set_grub_default
"$pinned_kernel"
532 warn
"E: <partition> is mandatory."
541 reexec_in_mountns
"$@"
544 warn
"E: <partition> is mandatory."
559 if [ "$#" -eq 0 ]; then
561 elif [ "$#" -eq 2 ] && [ "$1" = "--hook" ]; then
572 warn
"E: subcommand is mandatory for 'kernel'."
592 if [ "$#" -eq 3 ] && [ "$3" = '--next-boot' ]; then
593 pin_kernel
"$2" "${NEXT_BOOT_PIN}"
594 elif [ "$#" -eq 2 ]; then
603 if [ "$#" -eq 2 ] && [ "$2" = '--next-boot' ]; then
605 elif [ "$#" -eq 1 ]; then
614 warn
"E: invalid 'kernel' subcommand '$cmd'."
622 if [ "$#" -eq 2 ] && [ "$2" = '--quiet' ]; then
625 elif [ "$#" -eq 1 ]; then
626 reexec_in_mountns
"$@"
641 warn
"Invalid/unknown command '$1'."