Announcement

Collapse
No announcement yet.

Systemd-boot / Grub

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [CONFIGURATION] Systemd-boot / Grub

    Hi all i created a script that will allow you to use the Systemd-Boot loader even with SecureBoot enabled.
    I have also cross-posted a link to here in @github: systemd/issues/16457.

    Explanation of what this script does:
    • Automatically generate a boot-entry called "Linux Secure-Bootloader" for your UEFI-Bios boot menu.
      And Automatically update (as needed) the Shim, MokManager and Systemd-boot used to boot your system in the ESP, see installUEFIbootEntry().
    • When ever you install a new kernel, or install/update any software/drivers that causes the ramdisk to be regenarated, the script will automatically update the ones used in the ESP partition to boot your OS.
      These files are in a separate 'kubuntu' vendor-dir in the ESP and does not interfere with those that your distro installs.
    • Automatically generate boot entries (as needed) in Systemd-boot's boot menu that you can choose from:
      1. The latest kernel and ramdisk.
        This entry is generated with a boot-try counter of 3 to detect boot failures, see getLoaderVars().
      2. The latest kernel and previous ramdisk.
      3. The old kernel and old ramdisk.
    • Automatically adds the kernel commandline options used from current boot, including the current swap partition to resume from.
      At moment it also always adds "intel_iommu=on", see getCmdLineOptions() if you don't want or modify this behaviour.

    Warning: First boot/After each update of Systemd-boot you need to either:
    • Enroll the hash of <ESP>/EFI/systemd/grubx64.efi using the MokManager that will come-up after boot.
    • OR automatically sign <ESP>/EFI/systemd/grubx64.efi with an accepted key for your SecureBoot system (eg. in db, KEK or MokList).
      You can't use /var/lib/shim-signed/mok/MOK.key to sign it because it is only valid for kernel-drivers...

    (Maybe i will automate this step later on)

    Current latest version is: zz-update-systemd-boot.txt (Remove extension and make executable)
    Code:
    #!/usr/bin/env bash
    # This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
    # https://creativecommons.org/licenses/by-sa/4.0/
    #
    # @version    2020.07.26
    # @author     ©TriMoon™ <https://gitlab.com/TriMoon>
    # @copyright  (C) 2020+ {@link https://gitlab.com/TriMoon|©TriMoon™}
    # @license    CC-BY-SA-4.0
    #
    # To install this script execute with 'installme' as argument.
    # Manual test after installing can be done by using `update-initramfs -u`
    #
    # shellcheck disable=SC2046
    if test $(id -u) -ne 0; then
    	printf "%s\n" \
    		"Need ROOT, aborting !"
    	exit 1
    fi
    
    # Global variables used in this script...
    declare -i \
    	bTestFlags \
    	BootTries \
    	versionFound \
    	latestFound \
    	prevFound \
    	oldFound
    declare -a \
    	KERNEL_CMDLINE
    declare \
    	ESP \
    	MACHINE_ID \
    	SWAP_PAR_UUID \
    	ROOT_PAR_UUID \
    	KERNEL \
    	KERNEL_LATEST \
    	VERSION_KERNEL_LATEST \
    	KERNEL_OLD \
    	VERSION_KERNEL_OLD \
    	RAMDISK \
    	RAMDISK_LATEST \
    	VERSION_RAMDISK_LATEST \
    	RAMDISK_OLD \
    	VERSION_RAMDISK_OLD \
    	LOADERID \
    	VERSION \
    	loader_entries \
    	loader_conf \
    	log_name \
    	log_func_name \
    	log_header_start \
    	log_header_end \
    	log_func_start \
    	log_func_end \
    	log_header \
    	log_func
    
    # shellcheck disable=SC2034
    source /etc/os-release
    
    # Install this script
    function installScript(){
    	local -a \
    		opts \
    		extradirs
    	local \
    		mainDest
    
    	log_func_name="Install"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	printf "%b %b: %s\n" \
    		"${log_header}" \
    		"${log_func}" \
    		"Installing helper..."
    
    	extradirs=(
    		# One for the kernel's postrm
    		/etc/kernel/postrm.d
    		# Another for the initramfs's post-update
    		/etc/initramfs/post-update.d
    	)
    	opts=(
    		--verbose
    		--parents
    	)
    	# Not always available by default...
    	mkdir "${opts[@]}" \
    		/etc/initramfs/post-update.d
    
    	# Install a fresh script in main place if needed.
    	mainDest="/etc/kernel/postinst.d/zz-update-systemd-boot"
    	if test ! -f "$mainDest" \
    		|| ! diff "$0" "$mainDest" >/dev/null
    		then
    		# copy into place
    		opts=(
    			--verbose
    			--archive
    		)
    		cp "${opts[@]}" "$0" "$mainDest"
    		# Set access permissions
    		opts=(
    			--modify
    			"u::rwx,g::rx,o::r,g:adm:rwx"
    		)
    		setfacl "${opts[@]}" "$mainDest"
    
    		# Remove the symlinks, if any, to reflect timestamp on new ones.
    		for d in "${extradirs[@]}"; do
    			rm --force "$d/zz-update-systemd-boot"
    		done
    	fi
    
    	# Link the other needed scripts to the main one.
    	opts=(
    		--verbose
    		--symbolic
    		--force
    	)
    	for d in "${extradirs[@]}"; do
    		if test ! -L "$d/zz-update-systemd-boot"; then
    			ln "${opts[@]}" \
    				"$mainDest" \
    				"$d/zz-update-systemd-boot"
    		fi
    	done
    
    	# opts=(
    	# 	-l
    	# 	--all
    	# 	"--color=auto"
    	# )
    	# for d in /etc/kernel/postinst.d "${extradirs[@]}"; do
    	# 	ls "${opts[@]}" "$d/zz-update-systemd-boot"
    	# done
    }
    
    function checkNeededBins(){
    	local -i missingBins
    	local -a neededBins
    	local Bin
    
    	log_func_name="check needed bins"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	printf "%b %b: %s\n" \
    		"${log_header}" \
    		"${log_func}" \
    		"Check needed bins..."
    
    	# Check for needed binaries for functionality.
    	neededBins=(
    		# pkg: coreutils
    		"/bin/cp"
    		"/bin/mv"
    		"/bin/rm"
    		"/usr/bin/head"
    		"/usr/bin/mktemp"
    		"/usr/bin/readlink"
    		"/usr/bin/test"
    		"/usr/bin/touch"
    		# pkg: sed
    		"/bin/sed"
    		# pkg: grep
    		"/bin/grep"
    		# pkg: libc-bin
    		#	To create the BOOTX64.CSV
    		"/usr/bin/iconv"
    		# pkg: mount
    		#	To determine swap partition.
    		"/sbin/swapon"
    		# pkg: util-linux
    		#	To get UUID of root and swap partitions
    		"/bin/lsblk"
    		# pkg: systemd
    		#	To determine root partition
    		"/bin/systemctl"
    		#	Systemd-boot
    		"/usr/lib/systemd/boot/efi/systemd-bootx64.efi"
    		# pkg: shim
    		#	MokManager
    		"/usr/lib/shim/mmx64.efi"
    		#	Unsigned-Shim loader
    		"/usr/lib/shim/shimx64.efi"
    		# pkg: shim-signed
    		#	Signed-Shim loader
    		#	This package is optional because you can sign your own,
    		#	but if you DO sign your own then place it here:
    		# "/usr/lib/shim/shimx64.efi.signed"
    		# pkg: efibootmgr
    		#	For EFI-boot entries
    		"/bin/efibootmgr"
    		# pkg: systemd
    		#	For determining ESP
    		"/usr/bin/bootctl"
    		# pkg: gcc
    		#	To determine machine architecture
    		"/usr/bin/cc"
    		# pkg: diffutils
    		#	To determine differences of binary files
    		"/usr/bin/cmp"
    	)
    	missingBins=0
    	for Bin in "${neededBins[@]}"; do
    		if test ! -f "$Bin"; then
    			missingBins=$((missingBins+1))
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"'$Bin' missing !"
    		fi
    	done
    	if test $missingBins -gt 0; then
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Missing $missingBins needed binaries, aborting !"
    		exit 1
    	else
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"All ok"
    	fi
    }
    
    # Grab current Machine ID.
    function getMachineID(){
    	MACHINE_ID=$(</etc/machine-id)
    }
    
    # Grab the UUID of the root partition.
    function getRootUUID(){
    	local ROOT_PAR
    
    	# ROOT_PAR=$(\
    	# 	df -l --output=source / \
    	# 	| tail -n +2\
    	# )
    
    	# Ask systemd for the device of the root partition.
    	ROOT_PAR=$(\
    		systemctl status -- -.mount \
    		| sed -En "/What:/ {s|^.*\s(.*)$|\1|; p}"\
    	)
    	# get the UUID of the ROOT_PAR
    	ROOT_PAR_UUID=$(\
    		lsblk \
    			--fs \
    			--noheadings \
    			--output UUID \
    			"$ROOT_PAR" \
    	)
    }
    
    # Grab the UUID of the resume partition.
    function getResumeUUID(){
    	local SWAP_PAR
    
    	# Ask swapon for the first swap partition.
    	# FIXME: We should check that its a partition !
    	SWAP_PAR=$(\
    		swapon \
    			--noheadings \
    			--show=NAME \
    		| head --lines=1\
    	)
    	# Grab the UUID of the SWAP_PAR
    	SWAP_PAR_UUID=$(\
    		lsblk \
    			--fs \
    			--noheadings \
    			--output=UUID \
    			"$SWAP_PAR"\
    	)
    }
    
    # Grab current ESP prtition.
    function getESP(){
    	# Ask bootctl for the esp path.
    	ESP=$(\
    		bootctl --print-esp-path\
    	)
    }
    
    # Grab the command line options for the kernel.
    function getCmdLineOptions(){
    	KERNEL_CMDLINE=()
    	# Iterate over the current command line options provided to the kernel.
    	for arg in $(</proc/cmdline); do
    		case $arg in
    			# Grub uses this, loader entries define it differently...
    			BOOT_IMAGE=*)	;&
    			# We set this
    			resume==*)		;&
    			# We set this
    			root=*)			;&
    			# We override this
    			intel_iommu=*)	;&
    			# Just a dummy to be stepped-into by above.
    			--non-existing-option--)
    				# We skip
    				continue ;;
    			# Add rest
    			*)
    				KERNEL_CMDLINE+=( "$arg" )
    		esac
    	done
    	# We override and always add these
    	# Comment out if not wanted...
    	KERNEL_CMDLINE+=( "intel_iommu=on" )
    	# echo "${KERNEL_CMDLINE[@]}"
    }
    
    # Grab the subdir to be used for the loader entries
    # This function needs these variables defined before calling:
    #	ESP
    function getLoaderVars(){
    	local d
    
    	loader_entries="/loader/entries"
    	BootTries=3
    
    	log_func_name="Loader Vars"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	# ID is populated from /etc/os-release
    	# These tests are just a few ideas at moment.
    	case "${ID,,}" in
    		"ubuntu")
    			# Below only works when already in a GUI,
    			#	thats why we fix it below for now...
    			if test\
    				"$DESKTOP_SESSION" = "plasma" \
    				-a "$XDG_SESSION_DESKTOP" = "KDE" \
    				-a "$XDG_CURRENT_DESKTOP" = "KDE"
    			then
    				LOADERID=kubuntu
    			fi
    			LOADERID=kubuntu
    			;;
    	esac
    	if test -z "$LOADERID"; then
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Could not compose a loaderID, aborting !"
    		exit 1
    	fi
    
    	# Full path to the loader entry config file(s) without extension,
    	#	so that we can append to it as needed.
    	loader_conf="${ESP}${loader_entries}/${LOADERID}"
    
    	# Create the needed directories when absent.
    	for d in "${ESP}${loader_entries}" "${ESP}/${LOADERID}"; do
    		test ! -d "$d" && mkdir --verbose "$d"
    	done
    }
    
    # Fill the kernel and ramdisk variables.
    # This function needs these variables defined before calling:
    #	KERNEL
    #	RAMDISK
    function getKernelAndRamdiskVars(){
    	### Find the Real filename and versions of:
    	# Latest kernel
    	KERNEL_LATEST=$(readlink --canonicalize-existing "/boot/${KERNEL}")
    	if test -n "$KERNEL_LATEST"; then
    		VERSION_KERNEL_LATEST="${KERNEL_LATEST#*-}"
    		VERSION_KERNEL_LATEST="${VERSION_KERNEL_LATEST%-*}"
    	fi
    	# Latest ramdisk
    	RAMDISK_LATEST=$(readlink --canonicalize-existing "/boot/${RAMDISK}")
    	if test -n "$RAMDISK_LATEST"; then
    		VERSION_RAMDISK_LATEST="${RAMDISK_LATEST#*-}"
    		VERSION_RAMDISK_LATEST="${VERSION_RAMDISK_LATEST%-*}"
    	fi
    	# Old kernel
    	KERNEL_OLD=$(readlink --canonicalize-existing "/boot/${KERNEL}.old")
    	if test -n "$KERNEL_OLD"; then
    		VERSION_KERNEL_OLD="${KERNEL_OLD#*-}"
    		VERSION_KERNEL_OLD="${VERSION_KERNEL_OLD%-*}"
    	fi
    	# Old ramdisk
    	RAMDISK_OLD=$(readlink --canonicalize-existing "/boot/${RAMDISK}.old")
    	if test -n "$RAMDISK_OLD"; then
    		VERSION_RAMDISK_OLD="${RAMDISK_OLD#*-}"
    		VERSION_RAMDISK_OLD="${VERSION_RAMDISK_OLD%-*}"
    	fi
    	# echo "$VERSION_KERNEL_LATEST"
    	# echo "$VERSION_RAMDISK_LATEST"
    	# echo "$VERSION_KERNEL_OLD"
    	# echo "$VERSION_RAMDISK_OLD"
    	# exit 123
    }
    
    # This function needs these variables defined before calling:
    #	ESP
    function installUEFIbootEntry(){
    	local -a \
    		opts \
    		bootEntries
    	local -i \
    		needToCreateEntry
    	local \
    		destDir \
    		entryLabel \
    		vendor \
    		shimLib \
    		bootEntry \
    		bootEntryLabel
    
    	vendor="systemd"
    	entryLabel="Linux Secure-Bootloader"
    	destDir="${ESP}/EFI/$vendor"
    
    	log_func_name="UEFI bootEntry"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	printf "%b %b: %s\n" \
    		"${log_header}" \
    		"${log_func}" \
    		"Preparing..."
    
    	# Create the destination dir if non-existant.
    	test ! -d "${destDir}" && mkdir -v "${destDir}"
    
    	opts=(
    		--verbose
    		# Does NOT work because of ESP-FS's timestamp precision
    		# --update
    		--archive
    		"--no-preserve=ownership"
    	)
    	shimLib="/usr/lib/shim"
    
    	# Copy the Signed-Shim loader.
    	if test -f "${shimLib}/shimx64.efi.signed"; then
    		# Preventing un-needed writes.
    		if ! cmp "${shimLib}/shimx64.efi.signed" \
    				"${destDir}/shimx64.efi" \
    				>/dev/null
    			then
    			cp "${opts[@]}" \
    				"${shimLib}/shimx64.efi.signed" \
    				"${destDir}/shimx64.efi"
    		fi
    	# Else copy the Unsigned-Shim loader.
    	elif test -f "${shimLib}/shimx64.efi"; then
    		# Preventing un-needed writes.
    		if ! cmp "${shimLib}/shimx64.efi" \
    				"${destDir}/shimx64.efi" \
    				>/dev/null
    			then
    			cp "${opts[@]}" \
    				"${shimLib}/shimx64.efi" \
    				"${destDir}"
    		fi
    	else
    		# This should NEVER happen,
    		#	because we already tested in checkNeededBins()
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Unable to find a Shim binary, aborting !"
    		exit 1
    	fi
    	# Copy the Shim loader's mokManager.
    	# Preventing un-needed writes.
    	if ! cmp "${shimLib}/mmx64.efi" \
    		"${destDir}/mmx64.efi" \
    		>/dev/null
    		then
    		cp "${opts[@]}" \
    			"${shimLib}/mmx64.efi" \
    			"${destDir}"
    	fi
    
    	# Copy the Systemd-boot loader.
    	# Preventing un-needed writes.
    	if ! cmp "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
    		"${destDir}/grubx64.efi" \
    		>/dev/null
    		then
    		cp "${opts[@]}" \
    			"/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
    			"${destDir}/grubx64.efi"
    	fi
    
    	# Create the 'BOOTX64.CSV' file
    	printf "%s,%s,%s,%s\n" \
    		"shimx64.efi" \
    		"$entryLabel" \
    		"" \
    		"This is the SecureBoot entry for Systemd-Boot" \
    	| iconv -t UCS-2 --output="${destDir}/BOOTX64.CSV"
    
    	# Grab EFI-bootloader entries we are interested in.
    	mapfile -t bootEntries < <(
    		efibootmgr --verbose \
    		| grep --ignore-case --regexp="\\\\$vendor\\\\" \
    		| sed -E 's|^Boot([[:digit:]]+).*|\1|'
    	)
    
    	# Check if we need to create a fresh UEFI bootEntry.
    	needToCreateEntry=1
    	if test "${#bootEntries[@]}" -gt 0; then
    		for bootEntry in "${bootEntries[@]}"; do
    			bootEntryLabel=$(
    				efibootmgr \
    				| sed -En "/^Boot$bootEntry/ {s|Boot$bootEntry(\*)?\s+(.*)|\2|; p}"
    			)
    			case "$bootEntryLabel" in
    				"Linux Bootloader")
    					printf "%b %b: %s\n" \
    						"${log_header}" \
    						"${log_func}" \
    						"Found default systemd-boot entry"
    					# Just informational.
    					;;
    				"$entryLabel")
    					printf "%b %b: %s\n" \
    						"${log_header}" \
    						"${log_func}" \
    						"UEFI SecureBoot entry already exists..."
    					needToCreateEntry=0
    					# efibootmgr -B -b "$bootEntry" >/dev/null
    					;;
    				*)
    					# We should normally not end here...
    					printf "%b %b: %s\n" \
    						"${log_header}" \
    						"${log_func}" \
    						"Found extra entry $bootEntry = '$bootEntryLabel'"
    			esac
    		done
    	fi
    	if test "${needToCreateEntry}" -eq 1; then
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Creating UEFI SecureBoot entry..."
    		efibootmgr \
    			--create \
    			--label "$entryLabel" \
    			--loader "/EFI/systemd/shimx64.efi" \
    			>/dev/null
    	fi
    }
    
    # Outputs a loader entry config
    # $1 = (latest|old|prev)
    # $2 = version
    # $3 = Kernel filename (without path)
    # $4 = Ramdisk filename (without path)
    function createLoaderEntry(){
    	local -i \
    		fieldWidth
    	local -a \
    		contents \
    		loader_options
    	local \
    		txtLine \
    		EFI_ARCH
    
    	fieldWidth=12
    	contents=()
    
    	# Taken from shim's Makefile
    	EFI_ARCH=$(
    		cc -dumpmachine \
    		| cut -f1 -d- \
    		| sed \
    			-e 's,aarch64,aa64,' \
    			-e 's,arm.*,arm,' \
    			-e 's,i[3456789]86,ia32,' \
    			-e 's,x86_64,x64,' \
    	)
    	# Header
    	printf -v txtLine "# %s/%s_" \
    		"${loader_entries}"	"${LOADERID}"
    	# Don't add $1 for latest
    	test "$1" != "latest" && txtLine+="$1"
    	contents+=( "${txtLine}.conf" )
    
    	# Title (Captialized first char)
    	printf -v txtLine "%-*s %s" $fieldWidth \
    		"title"			"${LOADERID^} ${VERSION}"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Version
    	printf -v txtLine "%-*s %s" $fieldWidth \
    		"version"		"$2"
    	# Not needed anymore because non-prev versions don't need it,
    	#	and prev-version adds it self while transforming...
    	# # Don't add $1 for old.
    	# test "$1" != "old" && txtLine+="-$1"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Machine ID
    	printf -v txtLine "%-*s %s" $fieldWidth \
    		"machine-id"	"$MACHINE_ID"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Architecture
    	printf -v txtLine "%-*s %s" $fieldWidth \
    		"architecture"	"$EFI_ARCH"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Kernel
    	printf -v txtLine "%-*s %s" $fieldWidth \
    		"linux"			"/${LOADERID}/$3"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Ramdisk
    	printf -v txtLine "%-*s %s" $fieldWidth \
    		"initrd"		"/${LOADERID}/$4"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Options
    	loader_options=()
    	# TODO: Resume is restricted when in SecureBoot, but how to resume in that case?
    	# Always add the resume partion.
    	loader_options+=( "resume=UUID=$SWAP_PAR_UUID" )
    	# Add the resume partion when SecureBoot is NOT enabled
    	# # test $(mokutil --sb-state >/dev/null) && \
    	# # 	loader_options+=( "resume=UUID=$SWAP_PAR_UUID" )
    	# test "SecureBoot enabled" != $(mokutil --sb-state) && \
    	# 	loader_options+=( "resume=UUID=$SWAP_PAR_UUID" )
    	# Add root partition to use
    	test -n "$ROOT_PAR_UUID" && \
    		loader_options+=( "root=UUID=$ROOT_PAR_UUID" )
    	# Add the remaining options
    	loader_options+=( "${KERNEL_CMDLINE[@]}" )
    	printf -v txtLine "%-*s%s" $fieldWidth \
    		"options" \
    		"$(\
    			printf " %s" \
    				"${loader_options[@]}" \
    		)"
    	# Add to total output.
    	contents+=( "${txtLine}" )
    
    	# Output the total output.
    	printf "%s\n" "${contents[@]}"
    }
    
    # Old-kernel-logic
    function oldKernelLogic(){
    	local -a cp_opts
    
    	log_func_name="Old Logic"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	bTestFlags=0
    	# Can't use -nt/-ot because of timestamp precision diffs of FS's...
    	# The tests: (Binary flags)
    	#	0001 = Old kernel does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	if test ! -f "${ESP}/${LOADERID}/${KERNEL}.old" \
    		|| ! cmp "${KERNEL_OLD}" "${ESP}/${LOADERID}/${KERNEL}.old" >/dev/null
    		then
    		bTestFlags=$((bTestFlags | 2#0001))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Old kernel is not in ESP or has changed"
    	fi
    	#	0010 = Old ramdisk does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	if test ! -f "${ESP}/${LOADERID}/${RAMDISK}.old" \
    		|| ! cmp "${RAMDISK_OLD}" "${ESP}/${LOADERID}/${RAMDISK}.old" >/dev/null
    		then
    		bTestFlags=$((bTestFlags | 2#0010))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Old ramdisk is not in ESP or has changed"
    	fi
    	#	0100 = Prev kernel exists in ESP.
    	if test -f "${ESP}/${LOADERID}/${RAMDISK}.prev"; then
    		bTestFlags=$((bTestFlags | 2#0100))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Prev kernel exists in ESP"
    	fi
    	#	1000 = Prev ramdisk exists in ESP.
    	if test -f "${ESP}/${LOADERID}/${RAMDISK}.prev"; then
    		bTestFlags=$((bTestFlags | 2#1000))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Prev ramdisk exists in ESP"
    	fi
    
    	# We need to create an old entry when: (All true)
    	#	Versions of old kernel/ramdisk are same.
    	#	Versions of old/latest of kernel&ramdisk are DIFFERENT.
    	#	Versions of all kernels&ramdisks are non-empty.
    	if test \
    		"$VERSION_KERNEL_OLD" = "$VERSION_RAMDISK_OLD" \
    		-a "$VERSION_KERNEL_OLD" != "$VERSION_KERNEL_LATEST" \
    		-a "$VERSION_RAMDISK_OLD" != "$VERSION_RAMDISK_LATEST" \
    		-a -n "$VERSION_KERNEL_OLD" \
    		-a -n "$VERSION_RAMDISK_OLD" \
    		-a -n "$VERSION_KERNEL_LATEST" \
    		-a -n "$VERSION_RAMDISK_LATEST"
    	then
    		# Create an old-entry from a prev-entry when: (All true)
    		#	prevFound set.
    		#	0001 = Old kernel does NOT exist in ESP.
    		#			or DIFFERS from the one in ESP.
    		#	0010 = Old ramdisk does NOT exist in ESP.
    		#			or DIFFERS from the one in ESP.
    		#	0100 = Prev kernel exists in ESP.
    		#	1000 = Prev ramdisk exists in ESP.
    		if test \
    			$((versionFound & prevFound)) -gt 0 \
    			-a $((bTestFlags ^ 2#1111)) -eq 0
    			then
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Creating old-entry from prev-entry..."
    
    			# Rename the kernel/ramdisk in ESP.
    			mv \
    				--verbose \
    				"${ESP}/${LOADERID}/${KERNEL}" \
    				"${ESP}/${LOADERID}/${KERNEL}.old"
    			mv \
    				--verbose \
    				"${ESP}/${LOADERID}/${RAMDISK}.prev" \
    				"${ESP}/${LOADERID}/${RAMDISK}.old"
    
    			# Adjust the loader entry-config appropriately into an old version.
    			#	Change the comment at top to reflect new filename.
    			#	Remove our extension from the version (not needed anymore)
    			#	Change the kernel used.
    			#	Change the ramdisk used.
    			# (Don't use -i so we can preserve timestamp...)
    			sed -E \
    				-e "s|(^#.*)_prev.conf|\1_old.conf|" \
    				-e "s|(^version.*)_prev|\1|" \
    				-e "s|(^linux.*)${KERNEL}|\1${KERNEL}.old|" \
    				-e "s|(^initrd.*)${RAMDISK}.prev|\1${RAMDISK}.old|" \
    				"${loader_conf}_prev.conf" \
    				>"${loader_conf}_old.conf"
    
    			# Update timestamp of config to that of the ramdisk.
    			touch \
    				--reference="${ESP}/${LOADERID}/${RAMDISK}.old" \
    				"${loader_conf}_old.conf"
    
    			# Remove the loader entry-config for prev,
    			#	it will be re-created as needed...
    			rm \
    				--verbose \
    				--force \
    				"${loader_conf}_prev.conf"
    		# Generate a FRESH old-entry when: (Any one true)
    		#	! prevFound set.
    		#	0001 = Old kernel does NOT exist in ESP.
    		#			or DIFFERS from the one in ESP.
    		#	0010 = Old ramdisk does NOT exist in ESP.
    		#			or DIFFERS from the one in ESP.
    		#	! 0100 = Prev kernel exists in ESP.
    		#	! 1000 = Prev ramdisk exists in ESP.
    		elif test \
    			$((versionFound & prevFound)) -eq 0 \
    			-a $((bTestFlags ^ 2#0011)) -eq 0
    			then
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Generating fresh old-entry..."
    			# Copy the old kernel and it's ramdisk.
    			cp_opts=(
    				--verbose
    				--update
    				--archive
    				"--no-preserve=ownership"
    			)
    			cp "${cp_opts[@]}" \
    				"${KERNEL_OLD}" \
    				"${ESP}/${LOADERID}/${KERNEL}.old"
    			cp "${cp_opts[@]}" \
    				"${RAMDISK_OLD}" \
    				"${ESP}/${LOADERID}/${RAMDISK}.old"
    
    			# Create the loader entry-config.
    			createLoaderEntry \
    				"old" \
    				"$VERSION_KERNEL_OLD" \
    				"${KERNEL}.old" \
    				"${RAMDISK}.old" \
    				>"${loader_conf}_old.conf"
    
    			# Update timestamp of config to that of the ramdisk.
    			touch \
    				--reference="${ESP}/${LOADERID}/${RAMDISK}.old" \
    				"${loader_conf}_old.conf"
    		else
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Nothing to be done..."
    		fi
    	else
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Skip..."
    	fi
    }
    
    # Prev-kernel-logic
    function prevKernelLogic(){
    	local -a cp_opts
    
    	log_func_name="Previous Logic"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	bTestFlags=0
    	# Can't use -nt/-ot because of timestamp precision diffs of FS's...
    	# The tests: (Binary flags)
    	#	00001 = Latest kernel did NOT boot succesfully (yet)
    	#		This will prevent creating a prev loader-entry from latest-entry
    	#		when it has a boot-try extension, either fresh or failed.
    	if test ! -f "${loader_conf}_.conf"; then
    		bTestFlags=$((bTestFlags | 2#00001))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Latest kernel did NOT boot succesfully (yet)"
    	# Only test rest when successully booted at least once.
    	else
    		#	00010 = Versions of latest kernel/ramdisk are SAME.
    		if test "$VERSION_KERNEL_LATEST" = "$VERSION_RAMDISK_LATEST"; then
    			bTestFlags=$((bTestFlags | 2#00010))
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Versions of latest kernel/ramdisk are same"
    		fi
    		#	00100 = The Latest ramdisk in ESP does exist.
    		#			AND DIFFERS from the latest ramdisk.
    		#		This only happens when ramdisk is updated...
    		if test -f "${ESP}/${LOADERID}/${RAMDISK}" \
    			&&	! cmp "${RAMDISK_LATEST}" "${ESP}/${LOADERID}/${RAMDISK}" >/dev/null
    			then
    			bTestFlags=$((bTestFlags | 2#00100))
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Latest ramdisk is in ESP and has changed"
    		fi
    		#	01000 = Prev ramdisk in ESP does NOT exist.
    		#			OR DIFFERS from the latest ramdisk.
    		#		This will prevent updating the Prev ramdisk in ESP
    		#		with the latest ramdisk in ESP when re-run...
    		if test ! -f "${ESP}/${LOADERID}/${RAMDISK}.prev" \
    			||	! cmp "${RAMDISK_LATEST}" "${ESP}/${LOADERID}/${RAMDISK}.prev" >/dev/null
    			then
    			bTestFlags=$((bTestFlags | 2#01000))
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Prev ramdisk is not in ESP or has changed"
    		fi
    		#	10000 = Versions of latest kernel and old ramdisk are SAME.
    		#		I once noticed this, not sure if it was a glitch...
    		if test "$VERSION_KERNEL_LATEST" = "$VERSION_RAMDISK_OLD"; then
    			bTestFlags=$((bTestFlags | 2#10000))
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Versions of latest kernel and old ramdisk are same"
    		fi
    	fi
    
    	# We need to create a prev entry when: (All true)
    	#	! 00001 = Latest kernel did NOT boot succesfully (yet)
    	#		This will prevent creating a prev loader-entry from latest-entry
    	#		when it has a boot-try extension, either fresh or failed.
    	#	00010 = Versions of latest kernel/ramdisk are SAME.
    	#	00100 = The Latest ramdisk in ESP does exist.
    	#			AND DIFFERS from the latest ramdisk.
    	#		This only happens when ramdisk is updated...
    	#	01000 = Prev ramdisk in ESP does NOT exist.
    	#			OR DIFFERS from the latest ramdisk.
    	#		This will prevent updating the Prev ramdisk in ESP
    	#		with the latest ramdisk in ESP when re-run...
    	if test $(((bTestFlags & 2#01111) ^ 2#01110)) -eq 0; then
    		# We need to UPDATE the prev ramdisk only when: (All true)
    		#	latestFound set.
    		#	prevFound set.
    		if test \
    			$((versionFound & latestFound)) -gt 0 \
    			-a $((versionFound & prevFound)) -gt 0
    			then
    			# Only update the prev ramdisk.
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Updateing prev-entry ramdisk..."
    
    			# Rename the ramdisk in ESP.
    			mv \
    				--verbose \
    				"${ESP}/${LOADERID}/${RAMDISK}" \
    				"${ESP}/${LOADERID}/${RAMDISK}.prev"
    
    			# Update timestamp of config to that of the ramdisk.
    			touch \
    				--reference="${ESP}/${LOADERID}/${RAMDISK}.prev" \
    				"${loader_conf}_prev.conf"
    
    			# Remove the loader entry-config for latest kernel,
    			#	it will be re-created fresh...
    			rm \
    				--verbose \
    				--force \
    				"${loader_conf}_.conf"
    		# We need to create a FRESH prev entry from latest-entry when: (All true)
    		#	latestFound set.
    		#	! prevFound set.
    		elif test \
    			$((versionFound & latestFound)) -gt 0 \
    			-a $((versionFound & prevFound)) -eq 0
    			then
    			# Create a fresh Prev loader entry-config.
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Creating prev-entry from latest-entry..."
    
    			# Rename the ramdisk in ESP.
    			mv \
    				--verbose \
    				"${ESP}/${LOADERID}/${RAMDISK}" \
    				"${ESP}/${LOADERID}/${RAMDISK}.prev"
    
    			# Adjust the loader entry-config appropriately into a prev version.
    			#	Change the comment at top to reflect new filename.
    			#	Change the version.
    			#	Change the ramdisk used.
    			# (Don't use -i so we can preserve timestamp...)
    			sed -E \
    				-e "s|(^#.*)_.conf|\1_prev.conf|" \
    				-e "s|(^version.*)|\1-prev|" \
    				-e "s|(^initrd.*)${RAMDISK}|\1${RAMDISK}.prev|" \
    				"${loader_conf}_.conf" \
    				>"${loader_conf}_prev.conf"
    
    			# Update timestamp of config to that of the ramdisk.
    			touch \
    				--reference="${ESP}/${LOADERID}/${RAMDISK}.prev" \
    				"${loader_conf}_prev.conf"
    
    			# Remove the loader entry-config for latest kernel,
    			#	it will be re-created as needed...
    			rm \
    				--verbose \
    				--force \
    				"${loader_conf}_.conf"
    		else
    			printf "%b %b: %s\n" \
    				"${log_header}" \
    				"${log_func}" \
    				"Nothing to be done..."
    		fi
    	else
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Skip..."
    	fi
    }
    
    # Latest-kernel-logic
    function latestKernelLogic(){
    	local -a cp_opts
    
    	log_func_name="Latest Logic"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	bTestFlags=0
    	# Can't use -nt/-ot because of timestamp precision diffs of FS's...
    	# The tests: (Binary flags)
    	#	00001 = Versions of latest kernel/ramdisk are same.
    	if test "$VERSION_KERNEL_LATEST" = "$VERSION_RAMDISK_LATEST"; then
    		bTestFlags=$((bTestFlags | 2#00001))
    	fi
    	#	00010 = Versions of latest kernel/ramdisk are non-empty.
    	if test -n "$VERSION_KERNEL_LATEST" -a -n "$VERSION_RAMDISK_LATEST"; then
    		bTestFlags=$((bTestFlags | 2#00010))
    	fi
    	#	00100 = Latest ramdisk does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	if test ! -f "${ESP}/${LOADERID}/${RAMDISK}" \
    		||	! cmp "${RAMDISK_LATEST}" "${ESP}/${LOADERID}/${RAMDISK}" >/dev/null
    		then
    		bTestFlags=$((bTestFlags | 2#00100))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Latest ramdisk is not in ESP or has changed"
    	fi
    	#	01000 = Latest kernel does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	if test ! -f "${ESP}/${LOADERID}/${KERNEL}" \
    		||	! cmp "${KERNEL_LATEST}" "${ESP}/${LOADERID}/${KERNEL}" >/dev/null
    		then
    		bTestFlags=$((bTestFlags | 2#01000))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Latest kernel is not in ESP or has changed"
    	fi
    	#	10000 = Loader entry-config for latest kernel NOT found.
    	if test ! -f "${loader_conf}_.conf" -a ! -f "${loader_conf}_+"*.conf; then
    		bTestFlags=$((bTestFlags | 2#10000))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Loader entry-config for latest kernel NOT found"
    	fi
    
    	# Generate a fresh latest-entry when: (All true)
    	#	00001 = Versions of latest kernel/ramdisk are same.
    	#	00010 = Versions of latest kernel/ramdisk are non-empty.
    	#	00100 = Latest ramdisk does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	#	Don't check for kernel here because only ramdisk might have been
    	#		updated, and it will be checked inside while copying.
    	if test $(((bTestFlags & 2#00111) ^ 2#00111)) -eq 0; then
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Generating fresh latest-entry..."
    		# Copy the latest kernel and it's ramdisk.
    		cp_opts=(
    			--verbose
    			--archive
    			"--no-preserve=ownership"
    		)
    		cp "${cp_opts[@]}" \
    			"${RAMDISK_LATEST}" \
    			"${ESP}/${LOADERID}/${RAMDISK}"
    		# Only copy latest kernel when it was different or non-existant in ESP.
    		# This will prevent un-needed writes.
    		#	01000 = Latest kernel does NOT exist in ESP.
    		#			or DIFFERS from the one in ESP.
    		if test $(((bTestFlags & 2#01000) ^ 2#01000)) -eq 0; then
    			cp "${cp_opts[@]}" \
    				"${KERNEL_LATEST}" \
    				"${ESP}/${LOADERID}/${KERNEL}"
    		fi
    
    		# Create the loader entry-config.
    		createLoaderEntry \
    			"latest" \
    			"$VERSION_KERNEL_LATEST" \
    			"${KERNEL}" \
    			"${RAMDISK}" \
    			>"${loader_conf}_+${BootTries}.conf"
    
    		# Update timestamp of config to that of the ramdisk.
    		touch \
    			--reference="${ESP}/${LOADERID}/${RAMDISK}" \
    			"${loader_conf}_+${BootTries}.conf"
    	# Re-generate a fresh latest-entry when: (All true)
    	#	00001 = Versions of latest kernel/ramdisk are same.
    	#	00010 = Versions of latest kernel/ramdisk are non-empty.
    	#	! 00100 = Latest ramdisk does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	#	! 01000 = Latest kernel does NOT exist in ESP.
    	#			or DIFFERS from the one in ESP.
    	#	10000 = Loader entry-config for latest kernel NOT found.
    	elif test $(((bTestFlags & 2#11111) ^ 2#10011)) -eq 0; then
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Re-generating fresh latest-entry..."
    
    		# Create the loader entry-config.
    		createLoaderEntry \
    			"latest" \
    			"$VERSION_KERNEL_LATEST" \
    			"${KERNEL}" \
    			"${RAMDISK}" \
    			>"${loader_conf}_+${BootTries}.conf"
    
    		# Update timestamp of config to that of the ramdisk.
    		touch \
    			--reference="${ESP}/${LOADERID}/${RAMDISK}" \
    			"${loader_conf}_+${BootTries}.conf"
    	else
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Nothing to be done..."
    	fi
    }
    
    # Loader-configs-logic
    function loaderConfigsLogic(){
    	log_func_name="Loader Configs"
    	log_func="${log_func_start}${log_func_name}${log_func_end}"
    
    	if test ! -d "${ESP}/EFI/systemd"; then
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"systemd-boot is not installed, skipping !"
    		exit 0
    	fi
    
    	latestFound=$((2#0001))
    	prevFound=$((2#0010))
    	oldFound=$((2#0100))
    
    	# Don't chain these, they need to be checked individualy for later logic...
    
    	# Set oldFound when: (All true)
    	#		Loader entry-config for old exist.
    	#		Old kernel EXIST in ESP already.
    	#		Old ramdisk EXIST in ESP already.
    	if test \
    		-f "${loader_conf}_old.conf" \
    		-a -f "${ESP}/${LOADERID}/${KERNEL}.old" \
    		-a -f "${ESP}/${LOADERID}/${RAMDISK}.old"
    		then
    		versionFound=$((versionFound | oldFound))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Valid entry for OLD found"
    	# else
    	# 	printf "%b %b: %s\n" \
    	# 		"${log_header}" \
    	# 		"${log_func}" \
    	# 		"NO valid entry for OLD found"
    	fi
    
    	# Set prevFound when: (All true)
    	#		Loader entry-config for prev exist.
    	#		Latest kernel EXIST in ESP already.
    	#		Prev ramdisk EXIST in ESP already.
    	#		(Will be result of Prev-kernel-logic below)
    	if test \
    		-f "${loader_conf}_prev.conf" \
    		-a -f "${ESP}/${LOADERID}/${KERNEL}" \
    		-a -f "${ESP}/${LOADERID}/${RAMDISK}.prev"
    		then
    		versionFound=$((versionFound | prevFound))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Valid entry for PREVIOUS found"
    	# else
    	# 	printf "%b %b: %s\n" \
    	# 		"${log_header}" \
    	# 		"${log_func}" \
    	# 		"NO valid entry for PREVIOUS found"
    	fi
    
    	# ONLY check for successfully booted configs.
    	# eg: no boot-try extensions see: systemd-boot(7)#BOOT COUNTING
    	# Set latestFound when: (All true)
    	#		Loader entry-config for latest exist.
    	#		Latest kernel/ramdisk EXIST in ESP already.
    	#		(Will be result of Latest-kernel-logic below)
    	if test \
    		-f "${loader_conf}_.conf" \
    		-a -f "${ESP}/${LOADERID}/${KERNEL}" \
    		-a -f "${ESP}/${LOADERID}/${RAMDISK}"
    	then
    		versionFound=$((versionFound | latestFound))
    		printf "%b %b: %s\n" \
    			"${log_header}" \
    			"${log_func}" \
    			"Valid entry for LATEST found"
    	# else
    	# 	printf "%b %b: %s\n" \
    	# 		"${log_header}" \
    	# 		"${log_func}" \
    	# 		"NO valid entry for LATEST found"
    	fi
    
    	oldKernelLogic
    	prevKernelLogic
    	latestKernelLogic
    }
    
    KERNEL="vmlinuz"
    RAMDISK="initrd.img"
    log_name="systemd-boot"
    log_header_start="\e[2m"
    log_header_end="\e[0m"
    log_func_start="(\e[32m"
    log_func_end="\e[0m)"
    log_header="${log_header_start}${log_name}${log_header_end}"
    
    bTestFlags=0
    BootTries=0
    versionFound=0
    latestFound=0
    prevFound=0
    oldFound=0
    
    case "$1" in
    	installme)
    		printf "%b: %s\n" \
    			"${log_header}" \
    			"Requested install of helper"
    		checkNeededBins
    		installScript
    		;;
    	installBoot)
    		printf "%b: %s\n" \
    			"${log_header}" \
    			"Requested install Boot loader-entry"
    		checkNeededBins
    		getESP
    		installUEFIbootEntry
    		;;
    	*)
    		checkNeededBins
    		getESP
    		getMachineID
    		getRootUUID
    		getResumeUUID
    		getCmdLineOptions
    		getLoaderVars
    		getKernelAndRamdiskVars
    		loaderConfigsLogic
    		installUEFIbootEntry
    esac
    Hope it is useful to the community,
    Maybe Kubuntu devs can use this in it's distro

    Output from my current running system:
    • Code:
      > bootctl | xsel -ib
      System:
          Firmware: UEFI 2.40 (American Megatrends 5.11)
       Secure Boot: enabled
        Setup Mode: user
      
      Current Boot Loader:
           Product: systemd-boot 245.4-4ubuntu3.2
          Features: ✓ Boot counting
                    ✓ Menu timeout control
                    ✓ One-shot menu timeout control
                    ✓ Default entry control
                    ✓ One-shot entry control
                    ✓ Support for XBOOTLDR partition
                    ✓ Support for passing random seed to OS
                    ✓ Boot loader sets ESP partition information
               ESP: /dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c
              File: └─/EFI/SYSTEMD/SHIMX64.EFI
      
      Random Seed:
      Passed to OS: no
      System Token: set
            Exists: yes
      
      Available Boot Loaders on ESP:
               ESP: /boot/efi (/dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c)
              File: └─/EFI/systemd/systemd-bootx64.efi (systemd-boot 245.4-4ubuntu3.1)
              File: └─/EFI/systemd/shimx64.efi
              File: └─/EFI/systemd/mmx64.efi
              File: └─/EFI/systemd/grubx64.efi (systemd-boot 245.4-4ubuntu3.2)
              File: └─/EFI/BOOT/BOOTX64.EFI
      
      Boot Loaders Listed in EFI Variables:
             Title: Linux Secure-Bootloader
                ID: 0x0000
            Status: active, boot-order
         Partition: /dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c
              File: └─/EFI/SYSTEMD/SHIMX64.EFI
      
             Title: ubuntu
                ID: 0x0002
            Status: inactive, boot-order
         Partition: /dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c
              File: └─/EFI/UBUNTU/SHIMX64.EFI
      
             Title: UEFI OS
                ID: 0x0004
            Status: inactive, boot-order
         Partition: /dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c
              File: └─/EFI/BOOT/BOOTX64.EFI
      
             Title: ubuntu
                ID: 0x0005
            Status: inactive, boot-order
         Partition: /dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c
              File: └─/EFI/UBUNTU/GRUBX64.EFI
      
      Boot Loader Entries:
             $BOOT: /boot/efi (/dev/disk/by-partuuid/07aa2f88-2546-4101-95d4-59e76a04f93c)
      
      Default Boot Loader Entry:
             title: Kubuntu 20.04.1 LTS (Focal Fossa)
                id: kubuntu_.conf
            source: /boot/efi/loader/entries/kubuntu_.conf
           version: 5.4.0-42
        machine-id: 80479e7d268341ec858db9de810df978
      architecture: x64
             linux: /kubuntu/vmlinuz
            initrd: /kubuntu/initrd.img
           options: resume=UUID=734867ce-811d-4fb3-ac4c-44a61fb1fca9 root=UUID=deb6ca8a-f40e-44c8-aa8d-db16d41219a9 ro quiet splash vt.handoff=7 intel_iommu=on
    • Code:
      > bootctl list | xsel -ib
      Boot Loader Entries:
         title: EFI Tools
            id: efitools-keytool.conf
        source: /boot/efi/loader/entries/efitools-keytool.conf
       version: KeyTool
      
         title: Kubuntu Grub-loader
            id: grub-kubuntu.conf
        source: /boot/efi/loader/entries/grub-kubuntu.conf
       version: Grub
      
         title: Kubuntu 20.04 LTS (Focal Fossa) (5.4.0-40)
            id: kubuntu_old.conf
        source: /boot/efi/loader/entries/kubuntu_old.conf
       version: 5.4.0-40
      machine-id: 80479e7d268341ec858db9de810df978
      architecture: x64
         linux: /kubuntu/vmlinuz.old
        initrd: /kubuntu/initrd.img.old
       options: resume=UUID=734867ce-811d-4fb3-ac4c-44a61fb1fca9 root=UUID=deb6ca8a-f40e-44c8-aa8d-db16d41219a9 ro quiet splash vt.handoff=7 intel_iommu=on
      
         title: Kubuntu 20.04 LTS (Focal Fossa) (5.4.0-42-prev)
            id: kubuntu_prev.conf
        source: /boot/efi/loader/entries/kubuntu_prev.conf
       version: 5.4.0-42-prev
      machine-id: 80479e7d268341ec858db9de810df978
      architecture: x64
         linux: /kubuntu/vmlinuz
        initrd: /kubuntu/initrd.img.prev
       options: resume=UUID=734867ce-811d-4fb3-ac4c-44a61fb1fca9 root=UUID=deb6ca8a-f40e-44c8-aa8d-db16d41219a9 ro quiet splash vt.handoff=7 intel_iommu=on
      
         title: Kubuntu 20.04.1 LTS (Focal Fossa) (default)
            id: kubuntu_.conf
        source: /boot/efi/loader/entries/kubuntu_.conf
       version: 5.4.0-42
      machine-id: 80479e7d268341ec858db9de810df978
      architecture: x64
         linux: /kubuntu/vmlinuz
        initrd: /kubuntu/initrd.img
       options: resume=UUID=734867ce-811d-4fb3-ac4c-44a61fb1fca9 root=UUID=deb6ca8a-f40e-44c8-aa8d-db16d41219a9 ro quiet splash vt.handoff=7 intel_iommu=on
      
         title: EFI Default Loader
            id: auto-efi-default
        source: /sys/firmware/efi/efivars/LoaderEntries-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
      
         title: Reboot Into Firmware Interface
            id: auto-reboot-to-firmware-setup
        source: /sys/firmware/efi/efivars/LoaderEntries-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
    Last edited by ©TriMoon™; Jul 27, 2020, 02:37 AM. Reason: Update with info from bootctl of my running system
    Well thats all for now, 3M

    #2
    Originally posted by ©TriMoon™ View Post
    Hope it is useful to the community,
    Maybe Kubuntu devs can use this in it's distro
    Unfortunately, Kubuntu uses what Ubuntu uses, so in this case it will be a bit unlikely at the moment.


    Be prepared for the anti-systemd element here to chime in shortly

    Comment


      #3
      Originally posted by claydoh View Post
      Unfortunately, Kubuntu uses what Ubuntu uses, so in this case it will be a bit unlikely at the moment.

      Be prepared for the anti-systemd element here to chime in shortly
      If so then WHY is systemd installed as DEFAULT in *ubuntu systems?
      I use this while doing a fresh install from the Live-DVD image.

      This script just makes it easy to transition to systemd-boot from grub...
      Well thats all for now, 3M

      Comment


        #4
        I don't see Ubuntu moving to using the systemd-boot component as the default boot mechanism at the moment, though if course it is not terribly hard for someone to use it on their own.
        Does any distro use this by default?

        Comment


          #5
          Originally posted by claydoh View Post
          I don't see Ubuntu moving to using the systemd-boot component as the default boot mechanism at the moment, though if course it is not terribly hard for someone to use it on their own.
          Does any distro use this by default?
          Not that i'm aware of, that said:
          If *ubuntu wants to stay leader in the market they should not wait for other distros to take the first step right?
          Most Linux distros already install systemd as System-Manager instead of SysV/etc, and Systemd-boot is part of the default systemd install.
          The next logical step is replacing grub with Systemd-boot for x64 UEFI installs...
          Well thats all for now, 3M

          Comment


            #6
            Sure, but then a distro that supports both Legacy and EFI installs will need to rewrite and/or do some significant mods to their installers to add and support both types of booting methods. I just don't see Ubuntu doing this any time soon, is all.
            I have zero opinion on the topic myself.

            Comment


              #7
              Ubuntu already does what you say by using grub-efi
              Plus it's hilarious to say that you don't have any opinion on the topic itself while trying to give so many arguments against it
              Be brave young padawah, it won't blow-up in your face
              Well thats all for now, 3M

              Comment


                #8
                No, I am simply giving reasons why I do not see Ubuntu doing this in the near future, with their fairly ancient, sometimes unreliable installer that they seldom update in any significant manner as one example as to why.
                When the more bleeding edge distros implement this, work things out, and thereby highlighting the pros and cons, then you may see more mainstream distros taking it on.

                And yes, I do have zero opinion, as I have not used systemd-boot. I cannot say if it is good, crap, or just another alternative, at this time.


                Be brave young padawah
                Heh, Last thing I am called is young.
                Last edited by claydoh; Jul 26, 2020, 12:12 PM.

                Comment


                  #9
                  Pop OS uses systemd bootloader for EFI installs. I played around with it a little. It's a lot cleaner and simpler than grub. Had a hell of time trying to get it to boot from btrfs subvolume.

                  Comment


                    #10
                    Originally posted by mr_raider View Post
                    Had a hell of time trying to get it to boot from btrfs subvolume.
                    I'm sure that was not related to Systemd-boot but more an issue with your kernel/ramdisk
                    Because Systemd-boot only uses the ESP filesystem which is a FAT32/VFAT partition by definition...
                    (It can also use a xbootldr partition but i have never used that)
                    Last edited by ©TriMoon™; Jul 27, 2020, 01:33 AM.
                    Well thats all for now, 3M

                    Comment


                      #11
                      Just updated the OP to give more info and explanation
                      Well thats all for now, 3M

                      Comment


                        #12
                        Just today found that systemd-boot only boots .efi images, so no iso booting; a show stopper for me. To boot an iso I could boot grub from systemd-boot, but then I might as well just use grub.
                        Regards, John Little

                        Comment


                          #13
                          How do you boot an iso with grub?

                          Sent from my HD1905 using Tapatalk

                          Comment


                            #14
                            Originally posted by mr_raider View Post
                            How do you boot an iso with grub?
                            See this thread on KFN, or Grub2 ISOBootExamples. It's the method that the ventoy and multibootusb projects use.

                            tl;dr, an example with a drive labelled foo, kubuntu-20.04-desktop-amd64.iso in a directory called iso:
                            Code:
                            menuentry 'Kubuntu iso' {
                            search --no-floppy --set=root --label "foo"
                            set isofile="/iso/kubuntu-20.04-desktop-amd64.iso"
                            rmmod tpm
                            loopback loop ($root)$isofile
                            linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile noprompt noeject
                            initrd (loop)/casper/initrd
                            }
                            (The "rmmod tpm" is a workaround for a bug in the grub shipped with 20.04.) Note the linux and initrd lines vary for different distros.
                            Last edited by jlittle; Aug 01, 2020, 04:31 PM. Reason: grammar
                            Regards, John Little

                            Comment

                            Working...
                            X