diff --git a/dracut-functions.sh b/dracut-functions.sh index 4535871b60..c8aa10d4d5 100755 --- a/dracut-functions.sh +++ b/dracut-functions.sh @@ -1081,3 +1081,141 @@ pe_get_image_base() { [[ $? -eq 1 ]] && return 1 echo "$((16#$base_image))" } + +# get_dollar_boot +# $BOOT is the primary place to put boot menu entry resources into +# see https://uapi-group.org/specifications/specs/boot_loader_specification +get_dollar_boot() { + local _root_arg + local _esp + local _xbootldr + local _dollar_boot + + if type -P bootctl &> /dev/null; then + if [[ -n $dracutsysrootdir ]]; then + _root_arg=(--root "$dracutsysrootdir") + fi + # shellcheck disable=SC2155 disable=SC2068 + _esp=$(bootctl ${_root_arg[@]} -p 2> /dev/null) + # shellcheck disable=SC2155 disable=SC2068 + _xbootldr=$(bootctl ${_root_arg[@]} -x 2> /dev/null) + [[ $_xbootldr == "$_esp" ]] && unset _xbootldr + _dollar_boot=${_xbootldr:-$_esp} + elif [[ -z $dracutsysrootdir ]]; then + if mountpoint -q /efi && [[ -d /efi/EFI ]]; then + _esp="/efi" + elif mountpoint -q /boot/efi && [[ -d /boot/efi/EFI ]]; then + _esp="/boot/efi" + fi + _dollar_boot=${_esp:-/boot} + else + if [[ -d "$dracutsysrootdir"/efi/EFI ]]; then + _esp="$dracutsysrootdir/efi" + elif [[ -d "$dracutsysrootdir"/boot/EFI ]]; then + _esp="$dracutsysrootdir/boot" + elif [[ -d "$dracutsysrootdir"/boot/efi/EFI ]]; then + _esp="$dracutsysrootdir/boot/efi" + fi + _dollar_boot=${_esp} + fi + + echo -n "$_dollar_boot" +} + +# get_machine_id [<$BOOT>|no] +get_machine_id() { + local _dollar_boot + local _machine_id + + if [[ $1 != "no" ]]; then + _dollar_boot=${1:-$(get_dollar_boot)} + fi + + if [[ $_dollar_boot ]] && [[ -d "$_dollar_boot"/Default ]]; then + _machine_id="Default" + elif [[ -s /etc/machine-id ]]; then + read -r _machine_id < /etc/machine-id + [[ $_machine_id == "uninitialized" ]] && _machine_id="Default" + else + _machine_id="Default" + fi + + echo -n "$_machine_id" +} + +# get_default_initramfs_image [] [<$BOOT>|no] [|no] +get_default_initramfs_image() { + local _kver="$1" + local _dollar_boot + local _machine_id + local _image + + [[ $_kver ]] || _kver="$(uname -r)" + if [[ $2 != "no" ]]; then + _dollar_boot=${2:-$(get_dollar_boot)} + fi + if [[ $3 != "no" ]]; then + _machine_id=${3:-$(get_machine_id "$_dollar_boot")} + fi + + if [[ $_dollar_boot ]] && [[ $_machine_id ]] \ + && [[ -d "${_dollar_boot}"/loader/entries || -L "${_dollar_boot}"/loader/entries ]] \ + && [[ -d "${_dollar_boot}"/${_machine_id} || -L "${_dollar_boot}"/${_machine_id} ]]; then + _image="${_dollar_boot}/${_machine_id}/${_kver}/initrd" + elif [[ -f "$dracutsysrootdir"/lib/modules/${_kver}/initrd ]]; then + _image="$dracutsysrootdir/lib/modules/${_kver}/initrd" + elif [[ -f "$dracutsysrootdir"/lib/modules/${_kver}/initramfs.img ]]; then + _image="$dracutsysrootdir/lib/modules/${_kver}/initramfs.img" + else + _image="$dracutsysrootdir/boot/initramfs-${_kver}.img" + fi + + echo -n "$_image" +} + +# has_early_microcode +has_early_microcode() { + local _image="$1" + local _is_early + _is_early=$(cpio --extract --verbose --quiet --to-stdout -- 'early_cpio' < "$_image" 2> /dev/null) + # Debian mkinitramfs does not create the file 'early_cpio', so let's check if firmware files exist + [[ "$_is_early" ]] || _is_early=$(cpio --list --verbose --quiet --to-stdout -- 'kernel/*/microcode/*.bin' < "$_image" 2> /dev/null) + [[ "$_is_early" ]] && return 0 + return 1 +} + +# get_decompression_command +get_decompression_command() { + local _bin="$1" + local _cmd + + case $_bin in + $'\x1f\x8b'*) + _cmd="zcat --" + ;; + BZh*) + _cmd="bzcat --" + ;; + $'\x71\xc7'* | 070701) + _cmd="cat --" + ;; + $'\x02\x21'*) + _cmd="lz4 -d -c" + ;; + $'\x89'LZO$'\0'*) + _cmd="lzop -d -c" + ;; + $'\x28\xB5\x2F\xFD'*) + _cmd="zstd -d -c" + ;; + *) + if echo "test" | xz | xzcat --single-stream > /dev/null 2>&1; then + _cmd="xzcat --single-stream --" + else + _cmd="xzcat --" + fi + ;; + esac + + echo -n "$_cmd" +} diff --git a/dracut-initramfs-restore.sh b/dracut-initramfs-restore.sh index 995e13a0d5..f6f6990874 100755 --- a/dracut-initramfs-restore.sh +++ b/dracut-initramfs-restore.sh @@ -11,54 +11,65 @@ set -e # switching root to an incompletely unpacked initramfs trap 'echo "Received SIGTERM signal, ignoring!" >&2' TERM -KERNEL_VERSION="$(uname -r)" - [[ $dracutbasedir ]] || dracutbasedir=/usr/lib/dracut -SKIP="$dracutbasedir/skipcpio" -[[ -x $SKIP ]] || SKIP="cat" - -if [[ -d /efi/Default ]] || [[ -d /boot/Default ]] || [[ -d /boot/efi/Default ]]; then - MACHINE_ID="Default" -elif [[ -s /etc/machine-id ]]; then - read -r MACHINE_ID < /etc/machine-id - [[ $MACHINE_ID == "uninitialized" ]] && MACHINE_ID="Default" + +# shellcheck source=./dracut-functions.sh +. "$dracutbasedir"/dracut-functions.sh + +mount -o ro /boot &> /dev/null || true + +if [[ -f /sys/firmware/initrd ]]; then + IMG="/sys/firmware/initrd" else - MACHINE_ID="Default" + # shellcheck disable=SC2119 + IMG="$(get_default_initramfs_image)" + if [[ -z $IMG ]]; then + echo "No initramfs image found to restore!" >&2 + exit 1 + fi fi -mount -o ro /boot &> /dev/null || true +# check if initramfs image contains early microcode and skip it +read -r -N 6 bin < "$IMG" +case $bin in + $'\x71\xc7'* | 070701) + CAT="cat --" + if has_early_microcode "$IMG"; then + SKIP="$dracutbasedir/skipcpio" + if ! [[ -x $SKIP ]]; then + echo "'$SKIP' not found, cannot skip early microcode to extract $IMG" >&2 + exit 1 + fi + fi + ;; +esac -if [[ -d /efi/loader/entries || -L /efi/loader/entries ]] \ - && [[ -d /efi/$MACHINE_ID || -L /efi/$MACHINE_ID ]]; then - IMG="/efi/${MACHINE_ID}/${KERNEL_VERSION}/initrd" -elif [[ -d /boot/loader/entries || -L /boot/loader/entries ]] \ - && [[ -d /boot/$MACHINE_ID || -L /boot/$MACHINE_ID ]]; then - IMG="/boot/${MACHINE_ID}/${KERNEL_VERSION}/initrd" -elif [[ -d /boot/efi/loader/entries || -L /boot/efi/loader/entries ]] \ - && [[ -d /boot/efi/$MACHINE_ID || -L /boot/efi/$MACHINE_ID ]]; then - IMG="/boot/efi/$MACHINE_ID/$KERNEL_VERSION/initrd" -elif [[ -f /lib/modules/${KERNEL_VERSION}/initrd ]]; then - IMG="/lib/modules/${KERNEL_VERSION}/initrd" -elif [[ -f /boot/initramfs-${KERNEL_VERSION}.img ]]; then - IMG="/boot/initramfs-${KERNEL_VERSION}.img" -elif mountpoint -q /efi; then - IMG="/efi/$MACHINE_ID/$KERNEL_VERSION/initrd" -elif mountpoint -q /boot/efi; then - IMG="/boot/efi/$MACHINE_ID/$KERNEL_VERSION/initrd" +if [[ $SKIP ]]; then + bin="$($SKIP "$IMG" | { read -r -N 6 bin && echo "$bin"; })" else - echo "No initramfs image found to restore!" + read -r -N 6 bin < "$IMG" +fi + +# check if initramfs image is compressed +CAT=$(get_decompression_command "$bin") + +type "${CAT%% *}" > /dev/null 2>&1 || { + echo "'${CAT%% *}' not found, cannot unpack $IMG" >&2 exit 1 +} + +skipcpio() { + $SKIP "$@" | $ORIG_CAT +} + +if [[ $SKIP ]]; then + ORIG_CAT="$CAT" + CAT=skipcpio fi +# decompress and extract initramfs image cd /run/initramfs - -if (command -v zcat > /dev/null && $SKIP "$IMG" 2> /dev/null | zcat 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1) \ - || (command -v bzcat > /dev/null && $SKIP "$IMG" 2> /dev/null | bzcat 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1) \ - || (command -v xzcat > /dev/null && $SKIP "$IMG" 2> /dev/null | xzcat 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1) \ - || (command -v lz4 > /dev/null && $SKIP "$IMG" 2> /dev/null | lz4 -d -c 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1) \ - || (command -v lzop > /dev/null && $SKIP "$IMG" 2> /dev/null | lzop -d -c 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1) \ - || (command -v zstd > /dev/null && $SKIP "$IMG" 2> /dev/null | zstd -d -c 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1) \ - || ($SKIP "$IMG" 2> /dev/null | cpio -id --no-absolute-filenames --quiet > /dev/null 2>&1); then +if ($CAT "$IMG" | cpio -id --no-absolute-filenames --quiet > /dev/null); then rm -f -- .need_shutdown else # something failed, so we clean up diff --git a/dracut.sh b/dracut.sh index 3b292910f3..7cedf29d44 100755 --- a/dracut.sh +++ b/dracut.sh @@ -1092,83 +1092,6 @@ drivers_dir="${drivers_dir%"${drivers_dir##*[!/]}"}" [[ $sbat_l ]] && sbat="$sbat_l" [[ $machine_id_l ]] && machine_id="$machine_id_l" -if ! [[ $outfile ]]; then - if [[ $machine_id != "no" ]]; then - if [[ -d "$dracutsysrootdir"/efi/Default ]] \ - || [[ -d "$dracutsysrootdir"/boot/Default ]] \ - || [[ -d "$dracutsysrootdir"/boot/efi/Default ]]; then - MACHINE_ID="Default" - elif [[ -s "$dracutsysrootdir"/etc/machine-id ]]; then - read -r MACHINE_ID < "$dracutsysrootdir"/etc/machine-id - [[ $MACHINE_ID == "uninitialized" ]] && MACHINE_ID="Default" - else - MACHINE_ID="Default" - fi - fi - - if [[ $uefi == "yes" ]]; then - if [[ -n $uefi_secureboot_key && -z $uefi_secureboot_cert ]] || [[ -z $uefi_secureboot_key && -n $uefi_secureboot_cert ]]; then - printf "%s\n" "dracut[F]: Need 'uefi_secureboot_key' and 'uefi_secureboot_cert' both to be set." >&2 - exit 1 - fi - - if [[ -n $uefi_secureboot_key && -n $uefi_secureboot_cert ]] && ! command -v sbsign &> /dev/null; then - printf "%s\n" "dracut[F]: Need 'sbsign' to create a signed UEFI executable." >&2 - exit 1 - fi - - BUILD_ID=$(cat "$dracutsysrootdir"/etc/os-release "$dracutsysrootdir"/usr/lib/os-release \ - | while read -r line || [[ $line ]]; do - [[ $line =~ BUILD_ID\=* ]] && eval "$line" && echo "$BUILD_ID" && break - done) - if [[ -z $dracutsysrootdir ]]; then - if [[ -d /efi ]] && mountpoint -q /efi; then - efidir=/efi/EFI - else - efidir=/boot/EFI - if [[ -d /boot/efi/EFI ]]; then - efidir=/boot/efi/EFI - fi - fi - else - efidir=/boot/EFI - if [[ -d $dracutsysrootdir/boot/efi/EFI ]]; then - efidir=/boot/efi/EFI - fi - fi - mkdir -p "$dracutsysrootdir$efidir/Linux" - outfile="$dracutsysrootdir$efidir/Linux/linux-$kernel${MACHINE_ID:+-${MACHINE_ID}}${BUILD_ID:+-${BUILD_ID}}.efi" - else - if [[ -d "$dracutsysrootdir"/efi/loader/entries || -L "$dracutsysrootdir"/efi/loader/entries ]] \ - && [[ $MACHINE_ID ]] \ - && [[ -d "$dracutsysrootdir"/efi/${MACHINE_ID} || -L "$dracutsysrootdir"/efi/${MACHINE_ID} ]]; then - outfile="$dracutsysrootdir/efi/${MACHINE_ID}/${kernel}/initrd" - elif [[ -d "$dracutsysrootdir"/boot/loader/entries || -L "$dracutsysrootdir"/boot/loader/entries ]] \ - && [[ $MACHINE_ID ]] \ - && [[ -d "$dracutsysrootdir"/boot/${MACHINE_ID} || -L "$dracutsysrootdir"/boot/${MACHINE_ID} ]]; then - outfile="$dracutsysrootdir/boot/${MACHINE_ID}/${kernel}/initrd" - elif [[ -d "$dracutsysrootdir"/boot/efi/loader/entries || -L "$dracutsysrootdir"/boot/efi/loader/entries ]] \ - && [[ $MACHINE_ID ]] \ - && [[ -d "$dracutsysrootdir"/boot/efi/${MACHINE_ID} || -L "$dracutsysrootdir"/boot/efi/${MACHINE_ID} ]]; then - outfile="$dracutsysrootdir/boot/efi/${MACHINE_ID}/${kernel}/initrd" - elif [[ -f "$dracutsysrootdir"/lib/modules/${kernel}/initrd ]]; then - outfile="$dracutsysrootdir/lib/modules/${kernel}/initrd" - elif [[ -e $dracutsysrootdir/boot/vmlinuz-${kernel} ]]; then - outfile="$dracutsysrootdir/boot/initramfs-${kernel}.img" - elif [[ -z $dracutsysrootdir ]] \ - && [[ $MACHINE_ID ]] \ - && mountpoint -q /efi; then - outfile="/efi/${MACHINE_ID}/${kernel}/initrd" - elif [[ -z $dracutsysrootdir ]] \ - && [[ $MACHINE_ID ]] \ - && mountpoint -q /boot/efi; then - outfile="/boot/efi/${MACHINE_ID}/${kernel}/initrd" - else - outfile="$dracutsysrootdir/boot/initramfs-${kernel}.img" - fi - fi -fi - # eliminate IFS hackery when messing with fw_dir export DRACUT_FIRMWARE_PATH=${fw_dir// /:} fw_dir=${fw_dir//:/ } @@ -1313,6 +1236,42 @@ else exit 1 fi +if ! [[ $outfile ]]; then + DOLLAR_BOOT="$(get_dollar_boot)" + [[ $DOLLAR_BOOT ]] && ddebug "\$BOOT set to $DOLLAR_BOOT" + + if [[ $machine_id != "no" ]]; then + MACHINE_ID="$(get_machine_id "${DOLLAR_BOOT:-no}")" + fi + + if [[ $uefi == "yes" ]]; then + if ! [[ $DOLLAR_BOOT ]]; then + # shellcheck disable=SC2016 + dfatal '$BOOT (ESP and XBOOTLDR) partition not found.' + exit 1 + fi + + if [[ -n $uefi_secureboot_key && -z $uefi_secureboot_cert ]] || [[ -z $uefi_secureboot_key && -n $uefi_secureboot_cert ]]; then + dfatal "Need 'uefi_secureboot_key' and 'uefi_secureboot_cert' both to be set." + exit 1 + fi + + if [[ -n $uefi_secureboot_key && -n $uefi_secureboot_cert ]] && ! command -v sbsign &> /dev/null; then + dfatal "Need 'sbsign' to create a signed UEFI executable." + exit 1 + fi + + BUILD_ID=$(cat "$dracutsysrootdir"/etc/os-release "$dracutsysrootdir"/usr/lib/os-release \ + | while read -r line || [[ $line ]]; do + [[ $line =~ BUILD_ID\=* ]] && eval "$line" && echo "$BUILD_ID" && break + done) + mkdir -p "${DOLLAR_BOOT}/EFI/Linux" + outfile="${DOLLAR_BOOT}/EFI/Linux/linux-$kernel${MACHINE_ID:+-${MACHINE_ID}}${BUILD_ID:+-${BUILD_ID}}.efi" + else + outfile="$(get_default_initramfs_image "$kernel" "${DOLLAR_BOOT:-no}" "${MACHINE_ID:-no}")" + fi +fi + if [[ $persistent_policy == "mapper" ]]; then unset persistent_policy elif [[ -n $persistent_policy && ! -d "/dev/disk/${persistent_policy}" ]]; then diff --git a/lsinitrd.sh b/lsinitrd.sh index ada6cf516e..5fa481edb8 100755 --- a/lsinitrd.sh +++ b/lsinitrd.sh @@ -39,6 +39,9 @@ usage() { [[ $dracutbasedir ]] || dracutbasedir=/usr/lib/dracut +# shellcheck source=./dracut-functions.sh +. "$dracutbasedir"/dracut-functions.sh + sorted=0 modules=0 unset verbose @@ -108,43 +111,10 @@ if [[ $1 ]]; then usage exit 1 fi +elif [[ $KERNEL_VERSION == "$(uname -r)" ]] && [[ -f /sys/firmware/initrd ]]; then + image="/sys/firmware/initrd" else - if [[ -d /efi/Default ]] || [[ -d /boot/Default ]] || [[ -d /boot/efi/Default ]]; then - MACHINE_ID="Default" - elif [[ -s /etc/machine-id ]]; then - read -r MACHINE_ID < /etc/machine-id - [[ $MACHINE_ID == "uninitialized" ]] && MACHINE_ID="Default" - else - MACHINE_ID="Default" - fi - - if [[ -d /efi/loader/entries || -L /efi/loader/entries ]] \ - && [[ $MACHINE_ID ]] \ - && [[ -d /efi/${MACHINE_ID} || -L /efi/${MACHINE_ID} ]]; then - image="/efi/${MACHINE_ID}/${KERNEL_VERSION}/initrd" - elif [[ -d /boot/loader/entries || -L /boot/loader/entries ]] \ - && [[ $MACHINE_ID ]] \ - && [[ -d /boot/${MACHINE_ID} || -L /boot/${MACHINE_ID} ]]; then - image="/boot/${MACHINE_ID}/${KERNEL_VERSION}/initrd" - elif [[ -d /boot/efi/loader/entries || -L /boot/efi/loader/entries ]] \ - && [[ $MACHINE_ID ]] \ - && [[ -d /boot/efi/${MACHINE_ID} || -L /boot/efi/${MACHINE_ID} ]]; then - image="/boot/efi/${MACHINE_ID}/${KERNEL_VERSION}/initrd" - elif [[ -f /lib/modules/${KERNEL_VERSION}/initrd ]]; then - image="/lib/modules/${KERNEL_VERSION}/initrd" - elif [[ -f /lib/modules/${KERNEL_VERSION}/initramfs.img ]]; then - image="/lib/modules/${KERNEL_VERSION}/initramfs.img" - elif [[ -f /boot/initramfs-${KERNEL_VERSION}.img ]]; then - image="/boot/initramfs-${KERNEL_VERSION}.img" - elif [[ $MACHINE_ID ]] \ - && mountpoint -q /efi; then - image="/efi/${MACHINE_ID}/${KERNEL_VERSION}/initrd" - elif [[ $MACHINE_ID ]] \ - && mountpoint -q /boot/efi; then - image="/boot/efi/${MACHINE_ID}/${KERNEL_VERSION}/initrd" - else - image="" - fi + image="$(get_default_initramfs_image "$KERNEL_VERSION")" fi shift @@ -270,7 +240,7 @@ if ((${#filenames[@]} <= 0)) && [[ -z $unpack ]] && [[ -z $unpackearly ]]; then fi else echo -n "Image: $image: " - du -h "$image" | while read -r a _ || [ -n "$a" ]; do echo "$a"; done + du -bh "$image" | while read -r a _ || [ -n "$a" ]; do echo "$a"; done fi echo "========================================================================" @@ -280,10 +250,7 @@ read -r -N 6 bin < "$image" case $bin in $'\x71\xc7'* | 070701) CAT="cat --" - is_early=$(cpio --extract --verbose --quiet --to-stdout -- 'early_cpio' < "$image" 2> /dev/null) - # Debian mkinitramfs does not create the file 'early_cpio', so let's check if firmware files exist - [[ "$is_early" ]] || is_early=$(cpio --list --verbose --quiet --to-stdout -- 'kernel/*/microcode/*.bin' < "$image" 2> /dev/null) - if [[ "$is_early" ]]; then + if has_early_microcode "$image"; then if [[ -n $unpack ]]; then # should use --unpackearly for early CPIO : @@ -315,33 +282,8 @@ if [[ $SKIP ]]; then else read -r -N 6 bin < "$image" fi -case $bin in - $'\x1f\x8b'*) - CAT="zcat --" - ;; - BZh*) - CAT="bzcat --" - ;; - $'\x71\xc7'* | 070701) - CAT="cat --" - ;; - $'\x02\x21'*) - CAT="lz4 -d -c" - ;; - $'\x89'LZO$'\0'*) - CAT="lzop -d -c" - ;; - $'\x28\xB5\x2F\xFD'*) - CAT="zstd -d -c" - ;; - *) - if echo "test" | xz | xzcat --single-stream > /dev/null 2>&1; then - CAT="xzcat --single-stream --" - else - CAT="xzcat --" - fi - ;; -esac + +CAT=$(get_decompression_command "$bin") type "${CAT%% *}" > /dev/null 2>&1 || { echo "Need '${CAT%% *}' to unpack the initramfs." diff --git a/man/lsinitrd.1.asc b/man/lsinitrd.1.asc index 05f63e3a79..0a2f6b4622 100644 --- a/man/lsinitrd.1.asc +++ b/man/lsinitrd.1.asc @@ -17,8 +17,11 @@ SYNOPSIS DESCRIPTION ----------- -lsinitrd shows the contents of an initramfs image. if is omitted, then -lsinitrd uses the default image _/efi///initrd_, +lsinitrd shows the contents of an initramfs image. If is omitted and +__ is omitted or equal to the running kernel version, +then lsinitrd uses _/sys/firmware/initrd_ if it exists. Otherwise, if +is omitted, then lsinitrd uses the default image +_/efi///initrd_, _/boot///initrd_, _/boot/efi///initrd_, _/lib/modules//initrd_ or