LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (https://www.linuxquestions.org/questions/slackware-14/)
-   -   Grub 2.12 feedbacks (https://www.linuxquestions.org/questions/slackware-14/grub-2-12-feedbacks-4175732263/)

teoberi 01-03-2024 04:11 AM

Quote:

Originally Posted by Didier Spaier (Post 6473523)
To build the Slackware package I just ran the SlackBuild in /testing as is. Other than that, sources of the Slint package (only tested on 15.0).

Didier, I studied a bit your grub.SlackBuild from Slint and correlated with my attempts here I found this:
Code:

./configure --enable-stack-protector --with-platform=efi
Code:

cat config.log | grep TARGET_CFLAGS
Quote:

TARGET_CFLAGS='-std=gnu99 -fno-common -Os -m64 -Wall -W -Wshadow -Wpointer-arith -Wundef -Wchar-subscripts -Wcomment -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Wformat-extra-args -Wformat-security -Wformat-y2k -Wimplicit -Wimplicit-function-declaration -Wimplicit-int -Wmain -Wmissing-braces -Wmissing-format-attribute -Wmultichar -Wparentheses -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wswitch -Wtrigraphs -Wunknown-pragmas -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wwrite-strings -Wnested-externs -Wstrict-prototypes -g -Wredundant-decls -Wmissing-prototypes -Wmissing-declarations -Wextra -Wattributes -Wendif-labels -Winit-self -Wint-to-pointer-cast -Winvalid-pch -Wmissing-field-initializers -Wnonnull -Woverflow -Wvla -Wpointer-to-int-cast -Wstrict-aliasing -Wvariadic-macros -Wvolatile-register-var -Wpointer-sign -Wmissing-include-dirs -Wmissing-prototypes -Wmissing-declarations -Wformat=2 -freg-struct-return -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -Wa,-mx86-used-note=no -msoft-float -fno-omit-frame-pointer -fno-dwarf2-cfi-asm -mno-stack-arg-probe -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-ident -mcmodel=large -mno-red-zone -mstack-protector-guard=global -fstack-protector -Wtrampolines -Werror'
Code:

./configure --enable-stack-protector=strong --with-platform=efi
Code:

cat config.log | grep TARGET_CFLAGS
Quote:

TARGET_CFLAGS='-std=gnu99 -fno-common -Os -m64 -Wall -W -Wshadow -Wpointer-arith -Wundef -Wchar-subscripts -Wcomment -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Wformat-extra-args -Wformat-security -Wformat-y2k -Wimplicit -Wimplicit-function-declaration -Wimplicit-int -Wmain -Wmissing-braces -Wmissing-format-attribute -Wmultichar -Wparentheses -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wswitch -Wtrigraphs -Wunknown-pragmas -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wwrite-strings -Wnested-externs -Wstrict-prototypes -g -Wredundant-decls -Wmissing-prototypes -Wmissing-declarations -Wextra -Wattributes -Wendif-labels -Winit-self -Wint-to-pointer-cast -Winvalid-pch -Wmissing-field-initializers -Wnonnull -Woverflow -Wvla -Wpointer-to-int-cast -Wstrict-aliasing -Wvariadic-macros -Wvolatile-register-var -Wpointer-sign -Wmissing-include-dirs -Wmissing-prototypes -Wmissing-declarations -Wformat=2 -freg-struct-return -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -Wa,-mx86-used-note=no -msoft-float -fno-omit-frame-pointer -fno-dwarf2-cfi-asm -mno-stack-arg-probe -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-ident -mcmodel=large -mno-red-zone -mstack-protector-guard=global -fstack-protector-strong -Wtrampolines -Werror'
Code:

./configure --help | grep enable-stack-protector
Quote:

--enable-stack-protector
it doesn't seem too explicit to me.:)

marav 01-03-2024 05:22 AM

Quote:

Originally Posted by Didier Spaier (Post 6474309)
What can be wrong after the upgrade

Nobody here complain about not able to boot, login, or whatever else after a Slackware-current upgrade?

+
Quote:

Originally Posted by volkerdi (Post 6473441)
I'm not terribly surprised, since it won't even compile as released. There was no way it was going anywhere other than /testing... if it doesn't even build, what other bugs were included?

Anyway, from my point of view, if something is automated during an upgrade (via doinst.sh), the rollback (downgrade) must also be the same way. No matter the reason

During my grub test, I noticed that grub-mkconfig was reporting errors.
As I know how to do a chroot, I chose to reboot anyway
But, after noticing these errors, if I don't know how to deal with chroot, I could also have chosen to reinstall the previous version, which would have led to a non-bootable computer anyway

If the upgrade of a specific package is the culprit, the downgrade must be the first solution, not chroot

Side note:
It could be interesting to have something similar to arch-chroot on the ISO ;-)
Code:

mount $ROOT_PART /mnt
mount -t devtmpfs /dev /mnt/dev
mount -t devpts /dev/pts /mnt/dev/pts
mount -t sysfs /sys /mnt/sys
mount -t proc /proc /mnt/proc
chroot /mnt


volkerdi 01-03-2024 02:01 PM

Quote:

Originally Posted by marav (Post 6474321)
Anyway, from my point of view, if something is automated during an upgrade (via doinst.sh), the rollback (downgrade) must also be the same way. No matter the reason

You probably won't need to worry about that :)

Quote:

Side note:
It could be interesting to have something similar to arch-chroot on the ISO ;-)
Code:

mount $ROOT_PART /mnt
mount -t devtmpfs /dev /mnt/dev
mount -t devpts /dev/pts /mnt/dev/pts
mount -t sysfs /sys /mnt/sys
mount -t proc /proc /mnt/proc
chroot /mnt


Sort of like /sbin/mkbindmounts?

Didier Spaier 01-03-2024 02:49 PM

Quote:

Originally Posted by volkerdi (Post 6474404)
Sort of like /sbin/mkbindmounts?

Yes, but the script would need to ask the user which is the root partition and the options needed to mount it. For instance here and now that would be:
Code:

mount /dev/sda5 /mnt -o subvol=/@
that a script can't guess AFAIK. Also some more commands can be needed once in the chroot, like "mount /boot/efi" and "mount -t efivarfs none /sys/firmware/efi/efivars" before running grub-install in EFI mode.

volkerdi 01-03-2024 03:00 PM

Quote:

Originally Posted by Didier Spaier (Post 6474410)
Yes, but the script would need to ask the user which is the root partition and the options needed to mount it. For instance here and now that would be:
Code:

mount /dev/sda5 /mnt -o subvol=/@
that a script can't guess AFAIK. Also some more commands can be needed once in the chroot, like "mount /boot/efi" and "mount -t efivarfs none /sys/firmware/efi/efivars" before running grub-install in EFI mode.

In the case of the mkbindmounts script on the installer, *you* need to mount the partition on /mnt however that needs to be done. The script adds the usually-needed bind mounts for you. Then you can chroot into it. If you need to add other mounts (such as for /boot/efi) that's on you.

efivarfs is always mounted on EFI systems in -current now, so that shouldn't be an issue moving forward.

All done and exited from the chroot? Then you need umount -R /mnt to unmount everything.

marav 01-03-2024 03:15 PM

Quote:

Originally Posted by volkerdi (Post 6474404)
You probably won't need to worry about that :)

Please know that I'm rarely worried about your distribution, Monsieur :hattip:

kaott 01-03-2024 05:36 PM

So far 2.12 working well for me on both an MBR install and an UEFI install. However, both of these computers are basic setups: ext4 fs, early microcode enabled, and generic kernel using an initramfs.

I did reinstall via a grub-install on both systems.

I had to delete the .orig files to prevent double grub menu entries, but it looks like that is resolved in the 2nd build of it.

Daedra 01-13-2024 02:47 PM

Quote:

Originally Posted by marav (Post 6473580)
I also use it
I was looking for this line
Code:

linux=$(echo "$mylist" | version_sort -r | head -n 1)
Thanks ;-)

Today I needed to test something on Slackware 15.0 (32bit) and I got an error with the 09_slackware_linux script I tweaked to fix the deprecation warnings with 2.12. It works fine in 64bit, but was throwing errors in 32bit Slackware. Anyway I was annoyed enough where I went back and did a couple of things to the script, specifically the process_list function. Basically I wanted three things, get rid of the deprecated warnings with 2.12, fix the 32bit error, and prioritize the smp kernels first in the grub menu. With a little help from stackoverflow and chatGPT I got it working the way I want, but I thought I would post it here since even though I consider myself competent in bash I am no guru. I have zero ego on this so if you guys see something that is not right, could be done better, ugly, or just pain wrong please point it out so I can make the script better.
Code:

#! /bin/sh
set -e
# grub-mkconfig helper script.
# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
#
# GRUB is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GRUB is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
#
# Save this file in /etc/grub.d/09_slackware_linux

prefix="/usr"
exec_prefix="${prefix}"
datarootdir="${prefix}/share"

. "${datarootdir}/grub/grub-mkconfig_lib"

export TEXTDOMAIN=grub
export TEXTDOMAINDIR="${datarootdir}/locale"

CLASS="--class gnu-linux --class gnu --class os"

if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
  OS=GNU/Linux
else
  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
  CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]') ${CLASS}"
fi

# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
case ${GRUB_DEVICE} in
  /dev/loop/*|/dev/loop[0-9])
    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
  ;;
esac

if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then
  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
else
  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
fi

linux_entry ()
{
  os="$1"
  tag="$2"
  version="$3"
  recovery="$4"
  args="$5"
  if ${recovery} ; then
    title="$(gettext "%s, with Linux %s [%s] (recovery mode)")"
  else
    title="$(gettext "%s, with Linux %s [%s]")"
  fi
  printf "menuentry \"${title}\" ${CLASS} {\n" "${os}" "${version}" "${tag}"
  save_default_entry | sed -e "s/^/\t/"

  # Use ELILO's generic "efifb" when it's known to be available.
  # FIXME: We need an interface to select vesafb in case efifb can't be used.
  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
      if grep -qx "CONFIG_FB_EFI=y" /boot/config-${version} 2> /dev/null \
          && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-${version} 2> /dev/null; then
          cat << EOF
        set gfxpayload=keep
EOF
      fi
  else
          cat << EOF
        set gfxpayload=$GRUB_GFXPAYLOAD_LINUX
EOF
  fi

  if [ -z "${prepare_boot_cache}" ]; then
    prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
  fi
  printf '%s\n' "${prepare_boot_cache}"
  cat << EOF
        echo        $(printf "$(gettext "Loading Linux %s ...")" ${version})
        linux        ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
EOF
  if test -n "${initrd}" ; then
    cat << EOF
        echo        $(gettext "Loading initial ramdisk ...")
        initrd        ${rel_dirname}/${initrd}
EOF
  fi
  cat << EOF
}
EOF
}

process_list ()
{
    mylist="$1"
    tag="$2"
    initrd_allowed="$3"
   
    IFS=' ' read -r -a kernels <<< "$mylist"
   
    # Separate SMP and non-SMP kernels
    smp_kernels=()
    non_smp_kernels=()
   
    for kernel in "${kernels[@]}"; do
        basename=$(basename "$kernel")
        if [[ $basename == *"-smp"* ]]; then
            smp_kernels+=("$kernel")
        else
            non_smp_kernels+=("$kernel")
        fi
    done
   
    # Combine SMP kernels first, followed by non-SMP kernels
    sorted_kernels=("${smp_kernels[@]}" "${non_smp_kernels[@]}")
   
    for kernel in "${sorted_kernels[@]}"; do
        # Skip symbolic links
        if [ -L "$kernel" ]; then
            continue
        fi
       
        echo "Found linux image: $kernel" >&2
        basename=$(basename "$kernel")
        dirname=$(dirname "$kernel")
        rel_dirname=$(make_system_path_relative_to_its_root "$dirname")
        version=$(echo "$basename" | sed -e "s,^[^0-9]*-,,g")
        alt_version=$(echo "$version" | sed -e "s,\.old$,,g")
        linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
        initrd=
        if [ "x${initrd_allowed}" = "xtrue" ]; then
            for i in "initrd-${version}.gz" "initrd.gz" \
                "initrd.img-${version}" "initrd-${version}.img" \
                "initrd-${version}" "initrd.img-${alt_version}" \
                "initrd-${alt_version}.img" "initrd-${alt_version}"; do
                if test -e "${dirname}/${i}" ; then
                    initrd="$i"
                    break
                fi
            done
            if test -n "${initrd}" ; then
                echo "Found initrd image: ${dirname}/${initrd}" >&2
            else
                # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
                linux_root_device_thisversion=${GRUB_DEVICE}
            fi
        else
            # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
            linux_root_device_thisversion=${GRUB_DEVICE}
        fi

        linux_entry "${OS}" "${tag}" "${version}" false \
            "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
        if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
            linux_entry "${OS}" "${tag}" "${version}" true \
                "single ${GRUB_CMDLINE_LINUX}"
        fi
    done
}

prepare_boot_cache=

list=`for i in /boot/vmlinu[xz]-generic-* /vmlinu[xz]-generic-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`

process_list "${list}" "generic" "true"

list=`for i in /boot/vmlinu[xz]-custom-* /vmlinu[xz]-custom-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`
process_list "${list}" "custom" "true"

list=`for i in /boot/vmlinu[xz]-huge-* /vmlinu[xz]-huge-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`
process_list "${list}" "huge" "false"

EDIT: The only thing I am thinking I may have forgot is to priortize new kernels first if multiple kernels are installed. Working on that now...

Daedra 01-13-2024 03:34 PM

Ok last time I am going to spam the screen with the full code, but I added version_sort to sort the kernels with newest first.

Code:

#! /bin/sh
set -e
# grub-mkconfig helper script.
# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
#
# GRUB is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GRUB is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
#
# Save this file in /etc/grub.d/09_slackware_linux

prefix="/usr"
exec_prefix="${prefix}"
datarootdir="${prefix}/share"

. "${datarootdir}/grub/grub-mkconfig_lib"

export TEXTDOMAIN=grub
export TEXTDOMAINDIR="${datarootdir}/locale"

CLASS="--class gnu-linux --class gnu --class os"

if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
  OS=GNU/Linux
else
  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
  CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]') ${CLASS}"
fi

# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
case ${GRUB_DEVICE} in
  /dev/loop/*|/dev/loop[0-9])
    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
  ;;
esac

if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then
  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
else
  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
fi

linux_entry ()
{
  os="$1"
  tag="$2"
  version="$3"
  recovery="$4"
  args="$5"
  if ${recovery} ; then
    title="$(gettext "%s, with Linux %s [%s] (recovery mode)")"
  else
    title="$(gettext "%s, with Linux %s [%s]")"
  fi
  printf "menuentry "${title}" ${CLASS} {\n" "${os}" "${version}" "${tag}"
  save_default_entry | sed -e "s/^/\t/"

  # Use ELILO's generic "efifb" when it's known to be available.
  # FIXME: We need an interface to select vesafb in case efifb can't be used.
  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
      if grep -qx "CONFIG_FB_EFI=y" /boot/config-${version} 2> /dev/null \
          && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-${version} 2> /dev/null; then
          cat << EOF
        set gfxpayload=keep
EOF
      fi
  else
          cat << EOF
        set gfxpayload=$GRUB_GFXPAYLOAD_LINUX
EOF
  fi

  if [ -z "${prepare_boot_cache}" ]; then
    prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
  fi
  printf '%s\n' "${prepare_boot_cache}"
  cat << EOF
        echo        $(printf "$(gettext "Loading Linux %s ...")" ${version})
        linux        ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
EOF
  if test -n "${initrd}" ; then
    cat << EOF
        echo        $(gettext "Loading initial ramdisk ...")
        initrd        ${rel_dirname}/${initrd}
EOF
  fi
  cat << EOF
}
EOF
}

process_list ()
{
    mylist="$1"
    tag="$2"
    initrd_allowed="$3"

    # Version-sort the kernels
    sorted_kernels=$(echo "$mylist" | version_sort -r)

    # Separate smp and non-smp kernels
    smp_kernels=()
    non_smp_kernels=()

    IFS=' ' read -r -a kernels <<< "$sorted_kernels"

    for kernel in "${kernels[@]}"; do
        if [[ $kernel == *"smp"* ]]; then
            smp_kernels+=("$kernel")
        else
            non_smp_kernels+=("$kernel")
        fi
    done

    # Process smp kernels first
    for kernel in "${smp_kernels[@]}"; do
        process_kernel "$kernel" "$tag" "$initrd_allowed"
    done

    # Process non-smp kernels
    for kernel in "${non_smp_kernels[@]}"; do
        process_kernel "$kernel" "$tag" "$initrd_allowed"
    done
}

process_kernel ()
{
    kernel="$1"
    tag="$2"
    initrd_allowed="$3"

    # Skip symbolic links
    if [ -L "$kernel" ]; then
        return
    fi

    echo "Found linux image: $kernel" >&2
    basename=$(basename "$kernel")
    dirname=$(dirname "$kernel")
    rel_dirname=$(make_system_path_relative_to_its_root "$dirname")
    version=$(echo "$basename" | sed -e "s,^[^0-9]*-,,g")
    alt_version=$(echo "$version" | sed -e "s,\.old$,,g")
    linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
    initrd=
    if [ "x${initrd_allowed}" = "xtrue" ]; then
        for i in "initrd-${version}.gz" "initrd.gz" \
            "initrd.img-${version}" "initrd-${version}.img" \
            "initrd-${version}" "initrd.img-${alt_version}" \
            "initrd-${alt_version}.img" "initrd-${alt_version}"; do
            if test -e "${dirname}/${i}" ; then
                initrd="$i"
                break
            fi
        done
        if test -n "${initrd}" ; then
            echo "Found initrd image: ${dirname}/${initrd}" >&2
        else
            # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
            linux_root_device_thisversion=${GRUB_DEVICE}
        fi
    else
        # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
        linux_root_device_thisversion=${GRUB_DEVICE}
    fi

    linux_entry "${OS}" "${tag}" "${version}" false \
        "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
    if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
        linux_entry "${OS}" "${tag}" "${version}" true \
            "single ${GRUB_CMDLINE_LINUX}"
    fi
}


prepare_boot_cache=

list=`for i in /boot/vmlinu[xz]-generic-* /vmlinu[xz]-generic-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`

process_list "${list}" "generic" "true"

list=`for i in /boot/vmlinu[xz]-custom-* /vmlinu[xz]-custom-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`
process_list "${list}" "custom" "true"

list=`for i in /boot/vmlinu[xz]-huge-* /vmlinu[xz]-huge-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`
process_list "${list}" "huge" "false"


Didier Spaier 01-13-2024 03:55 PM

Quote:

Originally Posted by Daedra (Post 6476531)
Ok last time I am going to spam the screen with the full code, but I added version_sort to sort the kernels with newest first.

Code:

#! /bin/sh
set -e
# grub-mkconfig helper script.
# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
#
# GRUB is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GRUB is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
#
# Save this file in /etc/grub.d/09_slackware_linux

prefix="/usr"
exec_prefix="${prefix}"
datarootdir="${prefix}/share"

. "${datarootdir}/grub/grub-mkconfig_lib"

export TEXTDOMAIN=grub
export TEXTDOMAINDIR="${datarootdir}/locale"

CLASS="--class gnu-linux --class gnu --class os"

if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
  OS=GNU/Linux
else
  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
  CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]') ${CLASS}"
fi

# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
case ${GRUB_DEVICE} in
  /dev/loop/*|/dev/loop[0-9])
    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
  ;;
esac

if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then
  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
else
  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
fi

linux_entry ()
{
  os="$1"
  tag="$2"
  version="$3"
  recovery="$4"
  args="$5"
  if ${recovery} ; then
    title="$(gettext "%s, with Linux %s [%s] (recovery mode)")"
  else
    title="$(gettext "%s, with Linux %s [%s]")"
  fi
  printf "menuentry \"${title}\" ${CLASS} {\n" "${os}" "${version}" "${tag}"
  save_default_entry | sed -e "s/^/\t/"

  # Use ELILO's generic "efifb" when it's known to be available.
  # FIXME: We need an interface to select vesafb in case efifb can't be used.
  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
      if grep -qx "CONFIG_FB_EFI=y" /boot/config-${version} 2> /dev/null \
      && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-${version} 2> /dev/null; then
      cat << EOF
    set gfxpayload=keep
EOF
      fi
  else
      cat << EOF
    set gfxpayload=$GRUB_GFXPAYLOAD_LINUX
EOF
  fi

  if [ -z "${prepare_boot_cache}" ]; then
    prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
  fi
  printf '%s\n' "${prepare_boot_cache}"
  cat << EOF
    echo    $(printf "$(gettext "Loading Linux %s ...")" ${version})
    linux    ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
EOF
  if test -n "${initrd}" ; then
    cat << EOF
    echo    $(gettext "Loading initial ramdisk ...")
    initrd    ${rel_dirname}/${initrd}
EOF
  fi
  cat << EOF
}
EOF
}

process_list ()
{
    mylist="$1"
    tag="$2"
    initrd_allowed="$3"
   
    # Version-sort the kernels
    sorted_kernels=$(echo "$mylist" | version_sort -r)
   
    IFS=' ' read -r -a kernels <<< "$sorted_kernels"
   
    for kernel in "${kernels[@]}"; do
        # Skip symbolic links
        if [ -L "$kernel" ]; then
            continue
        fi
       
        echo "Found linux image: $kernel" >&2
        basename=$(basename "$kernel")
        dirname=$(dirname "$kernel")
        rel_dirname=$(make_system_path_relative_to_its_root "$dirname")
        version=$(echo "$basename" | sed -e "s,^[^0-9]*-,,g")
        alt_version=$(echo "$version" | sed -e "s,\.old$,,g")
        linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
        initrd=
        if [ "x${initrd_allowed}" = "xtrue" ]; then
            for i in "initrd-${version}.gz" "initrd.gz" \
                "initrd.img-${version}" "initrd-${version}.img" \
                "initrd-${version}" "initrd.img-${alt_version}" \
                "initrd-${alt_version}.img" "initrd-${alt_version}"; do
                if test -e "${dirname}/${i}" ; then
                    initrd="$i"
                    break
                fi
            done
            if test -n "${initrd}" ; then
                echo "Found initrd image: ${dirname}/${initrd}" >&2
            else
                # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
                linux_root_device_thisversion=${GRUB_DEVICE}
            fi
        else
            # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
            linux_root_device_thisversion=${GRUB_DEVICE}
        fi

        linux_entry "${OS}" "${tag}" "${version}" false \
            "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
        if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
            linux_entry "${OS}" "${tag}" "${version}" true \
                "single ${GRUB_CMDLINE_LINUX}"
        fi
    done
}

prepare_boot_cache=

list=`for i in /boot/vmlinu[xz]-generic-* /vmlinu[xz]-generic-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`

process_list "${list}" "generic" "true"

list=`for i in /boot/vmlinu[xz]-custom-* /vmlinu[xz]-custom-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`
process_list "${list}" "custom" "true"

list=`for i in /boot/vmlinu[xz]-huge-* /vmlinu[xz]-huge-* ; do
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
      done`
process_list "${list}" "huge" "false"


IMHO all files in /etc/grub.d should be POSIX compliant as run by grub-mkconfig which is itself a POSIX compliant script but this one has a few bashisms. Excerpts of the outing of "shellcheck 09_slackware_linux":
Code:

In 09_slackware_linux line 112:
    IFS=' ' read -r -a kernels <<< "$sorted_kernels"
                    ^-- SC2039: In POSIX sh, read -a is undefined.
                              ^-^ SC2039: In POSIX sh, here-strings are undefined.
In 09_slackware_linux line 114:
    for kernel in "${kernels[@]}"; do
                  ^-----------^ SC2039: In POSIX sh, array references are undefined.
In 09_slackware_linux line 161:
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
                                                    ^-- SC2039: In POSIX sh, echo flags are undefined.

In 09_slackware_linux line 167:
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
                                                    ^-- SC2039: In POSIX sh, echo flags are undefined.

In 09_slackware_linux line 172:
        if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
                                                    ^-- SC2039: In POSIX sh, echo flags are undefined.


Daedra 01-13-2024 04:07 PM

Thanks Didier, I will work on that.

EDIT: It also seems I forgot to add back logic to prioritize SMP kernels first in 32bit. But I am thinking why bother since that is going to be a thing of the past now that Pat has dropped the -smp label.

Daedra 01-13-2024 08:19 PM

Thanks again Didier, I went back and got the script POSIX compliant and tested it with 32/64 15.0 and current. It now works without errors or deprecation warnings. I think it is in a good place.

Code:

#! /bin/sh
set -e
# grub-mkconfig helper script.
# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
#
# GRUB is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GRUB is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
#
# Save this file in /etc/grub.d/09_slackware_linux

prefix="/usr"
exec_prefix="${prefix}"
datarootdir="${prefix}/share"

. "${datarootdir}/grub/grub-mkconfig_lib"

export TEXTDOMAIN=grub
export TEXTDOMAINDIR="${datarootdir}/locale"

CLASS="--class gnu-linux --class gnu --class os"

if [ "${GRUB_DISTRIBUTOR}" = "" ] ; then
  OS=GNU/Linux
else
  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
  CLASS="--class $(echo "${GRUB_DISTRIBUTOR}" | tr '[:upper:]' '[:lower:]') ${CLASS}"
fi

# loop-AES arranges things so that /dev/loop/X can be our root device, but
# the initrds that Linux uses don't like that.
case ${GRUB_DEVICE} in
  /dev/loop/*|/dev/loop[0-9])
    GRUB_DEVICE=$(losetup "${GRUB_DEVICE}" | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/")
  ;;
esac

if [ "${GRUB_DEVICE_UUID}" = "" ] || [ "${GRUB_DISABLE_LINUX_UUID}" = "true" ] \
    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then
  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
else
  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
fi

linux_entry ()
{
  os="$1"
  tag="$2"
  version="$3"
  recovery="$4"
  args="$5"
  if ${recovery} ; then
    title="$(gettext "%s, with Linux %s [%s] (recovery mode)")"
  else
    title="$(gettext "%s, with Linux %s [%s]")"
  fi
  printf "menuentry \"${title}\" ${CLASS} {\n" "${os}" "${version}" "${tag}"
  save_default_entry | sed -e "s/^/\t/"

  # Use ELILO's generic "efifb" when it's known to be available.
  # FIXME: We need an interface to select vesafb in case efifb can't be used.
  if [ "$GRUB_GFXPAYLOAD_LINUX" = "" ]; then
      if grep -qx "CONFIG_FB_EFI=y" /boot/config-"${version}" 2> /dev/null \
      && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-"${version}" 2> /dev/null; then
      cat << EOF
    set gfxpayload=keep
EOF
      fi
  else
      cat << EOF
    set gfxpayload=$GRUB_GFXPAYLOAD_LINUX
EOF
  fi

  if [ -z "${prepare_boot_cache}" ]; then
    prepare_boot_cache="$(prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | sed -e "s/^/\t/")"
  fi
  printf '%s\n' "${prepare_boot_cache}"
  cat << EOF
    echo    $(printf "$(gettext "Loading Linux %s ...")" "${version}")
    linux    ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
EOF
  if test -n "${initrd}" ; then
    cat << EOF
    echo    $(gettext "Loading initial ramdisk ...")
    initrd    ${rel_dirname}/${initrd}
EOF
  fi
  cat << EOF
}
EOF
}

process_list() {
    mylist="$1"
    tag="$2"
    initrd_allowed="$3"

    # Version-sort the kernels
    sorted_kernels=$(echo "$mylist" | version_sort -r)

    # Use portable command substitution
    kernels=$(echo "$sorted_kernels" | tr ' ' '\n')

    for kernel in $kernels; do
        # Skip symbolic links
        if [ -L "$kernel" ]; then
            continue
        fi

        printf "Found linux image: %s\n" "$kernel" >&2
        basename=$(basename "$kernel")
        dirname=$(dirname "$kernel")
        rel_dirname=$(make_system_path_relative_to_its_root "$dirname")
        version=$(echo "$basename" | sed -e "s,^[^0-9]*-,,g")
        alt_version=$(echo "$version" | sed -e "s,\.old$,,g")
        linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
        initrd=

        if [ "${initrd_allowed}" = "true" ]; then
            for i in "initrd-${version}.gz" "initrd.gz" \
                "initrd.img-${version}" "initrd-${version}.img" \
                "initrd-${version}" "initrd.img-${alt_version}" \
                "initrd-${alt_version}.img" "initrd-${alt_version}"; do
                if [ -e "${dirname}/${i}" ]; then
                    initrd="$i"
                    break
                fi
            done

            if [ -n "${initrd}" ]; then
                printf "Found initrd image: %s/%s\n" "${dirname}" "${initrd}" >&2
            else
                # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
                linux_root_device_thisversion=${GRUB_DEVICE}
            fi
        else
            # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
            linux_root_device_thisversion=${GRUB_DEVICE}
        fi

        linux_entry "${OS}" "${tag}" "${version}" false \
            "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"

        if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
            linux_entry "${OS}" "${tag}" "${version}" true \
                "single ${GRUB_CMDLINE_LINUX}"
        fi
    done
}

prepare_boot_cache=

list=$(for i in /boot/vmlinu[xz]-generic-* /vmlinu[xz]-generic-* ; do
        if grub_file_is_not_garbage "$i" ; then printf "%s " "$i"; fi
      done)

process_list "${list}" "generic" "true"

list=$(for i in /boot/vmlinu[xz]-custom-* /vmlinu[xz]-custom-* ; do
        if grub_file_is_not_garbage "$i" ; then printf "%s " "$i"; fi
      done)
process_list "${list}" "custom" "true"

list=$(for i in /boot/vmlinu[xz]-huge-* /vmlinu[xz]-huge-* ; do
        if grub_file_is_not_garbage "$i" ; then printf "%s " "$i"; fi
      done)
process_list "${list}" "huge" "false"


Didier Spaier 01-15-2024 05:28 PM

5 Attachment(s)
Quote:

Originally Posted by Daedra (Post 6476567)
Thanks again Didier, I went back and got the script POSIX compliant and tested it with 32/64 15.0 and current. It now works without errors or deprecation warnings. I think it is in a good place.

Well, I have tried it in a Slackware64-current in a Qemu VM, with lilo as boot loader.

<digression>As I had setup a gpt without efi, at first grub refused to work. No big deal, I shut down the system, did a "qemu-img resize +2G", restarted the VM, added a BIOSBoot partition, which made grub-mkconfig happy. Then I rebooted and got the grub menus grub-1.1.png (main) and grub-1.2.png (advanced options). I had kernel huge and generic 6.1.62.</digression>

After that I updated the system using slackpkg and ran geninitrd, not running grub-mkconfig at first. The grub menu did not change, but as the kernel 6.1.62 had been replaced by 6.6.11 as you can see in boot.txt which is the output "ls -1 /boot". As expected all the boot entries mentioning the kernel version were ineffective.

I rebooted, then ran grub-mkconfig again. This time of course all boot entries worked (see grub2.1 and grub2.2).

Opinion

Yes we have a safety net after a kernel upgrade with the symlinks in case the user:
  • uses slackpkg-upgrade to upgrade the kernel instead of just installing the new one
  • forget to run geninitrd
  • forget to run grub-mkconfig
This is a good thing as this forum is full of post like "I can't reboot" for one or several of these reasons.

But this is at the price of grub menus cluttered with redundant boot entries, of which not all are effective. Maybe acceptable for sighted users, but not nice for my blind "customers" ;)

Conclusion

I suggest to adapt Slackware to GRUB (instead of adapting GRUB to Slackware), doing what most other distributions do since a long time:
  • drop the huge kernels for good and provide only generic ones
  • build an initramfs for each new kernel
  • keep the running kernel when upgrading just in case
  • adopt a naming scheme handled by grub-mkconfig
  • build a new grub.cfg, possibly keeping the previous one as a backup.
All this being done automatically after a kernel upgrade, maybe after authorization by the user "Do you want to..."

chrisretusn 01-15-2024 11:09 PM

3 Attachment(s)
This is what I am using right now on all of my computers and vm's (VirtualBox). All are BIOS except for one VM that is EFI. I am using kernel-generic on all installs. For the -current installs, no initrd is used, for the my 14.2 and 15.0 installs an initrd is used. The BIOS installs have a BIOS Boot partition, of course the EFI install has an EFI partition.

I am including a screenshot of of my Slackware64-current VM. This is the 09_slackware section for that screenshot:
Code:

### BEGIN /etc/grub.d/09_slackware ###
menuentry 'Slackware-15.0+ with Generic Kernel  (6.1.66)' --class slackware_15_0_ --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-vmlinuz-advanced-generic-af779a17-fb23-47e6-ae5c-efcd75c188d7' {
        savedefault
        load_video
        set gfxpayload=800x600x32
        insmod gzio
        insmod part_gpt
        insmod ext2
        set root='hd0,gpt2'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2  af779a17-fb23-47e6-ae5c-efcd75c188d7
        else
          search --no-floppy --fs-uuid --set=root af779a17-fb23-47e6-ae5c-efcd75c188d7
        fi
        echo        'Loading Linux vmlinuz ...'
        linux        /boot/vmlinuz root=/dev/sda2 ro logo.nologo
}

### END /etc/grub.d/09_slackware ###

On this computer I have a "stock" kernel and a "last working" kernel installed. In /etc/grub.d/ I use an unmodified 00_header file and a custom 09_slackware file (a modified 10_linux). All other files are non executable except in the case of EFI, 25_bli and 30_uefi-firmware are executable.

This computer has two kernels installed, one is the latest (stock), the other is the last working backup (working). This is /etc/boot:
Code:

# ls -l /boot/vmlinuz*
lrwxrwxrwx 1 root root      22 Jan 11 21:46 /boot/vmlinuz -> vmlinuz-generic-6.6.11
lrwxrwxrwx 1 root root      22 Jan 11 21:46 /boot/vmlinuz-generic -> vmlinuz-generic-6.6.11
-rw-r--r-- 1 root root 12297792 Jan  6 03:11 /boot/vmlinuz-generic-6.6.10
-rw-r--r-- 1 root root 12309568 Jan 11 03:23 /boot/vmlinuz-generic-6.6.11
-rw-r--r-- 1 root root 12292928 Dec 21 03:49 /boot/vmlinuz-generic-6.6.8
-rw-r--r-- 1 root root 12291104 Jan  2 03:18 /boot/vmlinuz-generic-6.6.9
lrwxrwxrwx 1 root root      22 Jan 11 21:48 /boot/vmlinuz-generic-stock -> vmlinuz-generic-6.6.11
lrwxrwxrwx 1 root root      22 Jan 11 21:48 /boot/vmlinuz-generic-working -> vmlinuz-generic-6.6.10

As you may have notice above there are actually four kernels installed (need to fix that ;)). Only the two "stock" and "working" are picked up, if there were no "stock" or "working" symlink, then the kernel linked to vmlinuz is picked up.

This is the 09_slackware section of grub.cfg (I don't have a screenshot):
Code:

### BEGIN /etc/grub.d/09_slackware ###
menuentry 'Slackware-15.0+ with Generic Kernel [Working] (6.6.10)' --class slackware_15_0_ --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-working-advanced-generic-601df5bd-43a7-400e-834e-47045df436d0' {
        savedefault
        load_video
        set gfxpayload=1366x768x32
        insmod gzio
        insmod part_gpt
        insmod ext2
        set root='hd0,gpt1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1  601df5bd-43a7-400e-834e-47045df436d0
        else
          search --no-floppy --fs-uuid --set=root 601df5bd-43a7-400e-834e-47045df436d0
        fi
        echo        'Loading Linux working ...'
        linux        /boot/vmlinuz-generic-working root=/dev/sda1 ro nvidia-drm.modeset=1 logo.nologo
}
menuentry 'Slackware-15.0+ with Generic Kernel [Stock] (6.6.11)' --class slackware_15_0_ --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-stock-advanced-generic-601df5bd-43a7-400e-834e-47045df436d0' {
        savedefault
        load_video
        set gfxpayload=1366x768x32
        insmod gzio
        insmod part_gpt
        insmod ext2
        set root='hd0,gpt1'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1  601df5bd-43a7-400e-834e-47045df436d0
        else
          search --no-floppy --fs-uuid --set=root 601df5bd-43a7-400e-834e-47045df436d0
        fi
        echo        'Loading Linux stock ...'
        linux        /boot/vmlinuz-generic-stock root=/dev/sda1 ro nvidia-drm.modeset=1 logo.nologo
}

### END /etc/grub.d/09_slackware ###

I have attach my 09_slackware and /etc/default/grub. The kernel version is optional and grub-mkconfig has to be run to change it for a new kernel. If you don't want the kernel version included, then running grub-mkconfig is not necessary as the vmlinuz symlink is used or the "stock", "working" symlinks. For my "stock" and "working" setup, you do have to change the syslinks to match the kernel versions. With the standard install of Slackware running grub-mkconfig after a new kernel is not required. If you are using an initrd (of course that will have to be updated for the new kernel) there is an option in /etc/default/grub to enable it (by default disabled).

Edit: As an after thought I am adding the output of grub-mkconfig for this computer.
Code:

grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-generic-working
Found linux image: /boot/vmlinuz-generic-stock
Found linux image: /boot/vmlinuz
done


I have to give credit to marav and LuckyCyborg for give me the idea to come up with this. :hattip:

shipujin 01-16-2024 01:13 AM

Mark


All times are GMT -5. The time now is 10:51 AM.