Skip to content

Commit

Permalink
Deprecate KCL in /etc/default/{zfsbootmenu,grub}
Browse files Browse the repository at this point in the history
ZBM will complain when reading kernel command-line parameters from
/etc/default/{zfsbootmenu,grub} within a BE rather than from the ZFS
property org.zfsbootmenu:commandline. By default, the contents of these
files will be migrated to a ZFS property on the BE after the warning is
shown. This will happen once for each BE that provides a configuration
file and no property. The file /etc/default/zfsbootmenu will be removed
from the BE if that was the source for the KCL; /etc/default/grub is
never removed.

By pressing Esc, the user can ignore the deprecation warning without
attempting to migrate the KCL configuration. This allows ZBM to operate
as before. When the warning is ignored, ZBM will export an environment
variable and write to /etc/zfsbootmenu.conf in the initramfs to suppress
subsequent warnings until the next reboot.

Co-authored-by: Andrew J. Hesford <ajh@sideband.org>
Co-authored-by: Zach Dykstra <dykstra.zachary@gmail.com>
  • Loading branch information
ahesford and zdykstra committed Sep 10, 2021
1 parent c2a1bee commit 29a1049
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 34 deletions.
109 changes: 76 additions & 33 deletions 90zfsbootmenu/zfsbootmenu-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1041,10 +1041,13 @@ find_be_kernels() {
done
done
done

done

# No further need for the mount
umount "${mnt}"

defaults="$( select_kernel "${fs}" )"

# shellcheck disable=SC2034
IFS=' ' read -r def_fs def_kernel def_initramfs <<<"${defaults}"

Expand All @@ -1053,19 +1056,16 @@ find_be_kernels() {
# If no default kernel is found, there are no kernels; leave the BE
# directory in the same state it would be in had no /boot existed
if [ -z "${def_kernel}" ]; then
umount "${mnt}"
zdebug "no default kernel found for ${fs}"
rm -f "${kernel_records}" "${def_kernel_file}"
return 1
fi
zdebug "default kernel set to ${def_kernel}"

zdebug "default kernel set to ${def_kernel}"
echo "${def_kernel##*/}" > "${def_kernel_file}"

# Pre-load cmdline arguments, possibly from files on the mount
preload_be_cmdline "${fs}" "${mnt}"

umount "${mnt}"
# Pre-load cmdline arguments, possibly from files in the environment
preload_be_cmdline "${fs}"
return 0
}

Expand Down Expand Up @@ -1242,50 +1242,93 @@ read_kcl_prop() {
}

# arg1: ZFS filesystem
# arg2: path for a mounted filesystem
# prints: nothing
# returns: 0 on success

preload_be_cmdline() {
local zfsbe_mnt zfsbe_fs zfsbe_args args_file

zfsbe_fs="${1}"
if [ -z "${zfsbe_fs}" ]; then
zerror "zfsbe_fs is undefined"
return 1
fi
zdebug "zfsbe_fs set to ${zfsbe_fs}"
local fs mnt args args_file deprecated need_rw zsout

zfsbe_mnt="${2}"
if [ -z "${zfsbe_mnt}" ]; then
zerror "zfsbe_mnt is undefined"
fs="${1}"
if [ -z "${fs}" ]; then
zerror "fs is undefined"
return 1
fi
zdebug "zfsbe_mnt set to ${zfsbe_mnt}"
zdebug "fs set to ${fs}"

args_file="${BASE}/${zfsbe_fs}/cmdline"
args_file="${BASE}/${fs}/cmdline"

if zfsbe_args="$( read_kcl_prop "${zfsbe_fs}" )" && [ -n "${zfsbe_args}" ]; then
if args="$( read_kcl_prop "${fs}" )" && [ -n "${args}" ]; then
zdebug "using org.zfsbootmenu:commandline"
echo "${zfsbe_args}" > "${args_file}"
return
echo "${args}" > "${args_file}"
return 0
fi

if [ -n "${zfsbe_mnt}" ] && [ -r "${zfsbe_mnt}/etc/default/zfsbootmenu" ]; then
zdebug "using ${zfsbe_mnt}/etc/default/zfsbootmenu"
head -1 "${zfsbe_mnt}/etc/default/zfsbootmenu" | tr -d '\n' > "${args_file}"
return
# Mount R/O to check for config files
if ! mnt="$( mount_zfs "${fs}" )"; then
zerror "unable to mount ${fs}"
return 1
fi

if [ -n "${zfsbe_mnt}" ] && [ -r "${zfsbe_mnt}/etc/default/grub" ]; then
zdebug "using ${zfsbe_mnt}/etc/default/grub"
if [ -r "${mnt}/etc/default/zfsbootmenu" ]; then
zdebug "using ${mnt}/etc/default/zfsbootmenu"
head -1 "${mnt}/etc/default/zfsbootmenu" | tr -d '\n' > "${args_file}"
deprecated="/etc/default/zfsbootmenu"
elif [ -r "${mnt}/etc/default/grub" ]; then
zdebug "using ${mnt}/etc/default/grub"
echo "$(
# shellcheck disable=SC1090,SC1091
. "${zfsbe_mnt}/etc/default/grub" ;
. "${mnt}/etc/default/grub" ;
echo "${GRUB_CMDLINE_LINUX_DEFAULT}"
)" > "${args_file}"
return
deprecated="/etc/default/grub"
fi

# Always unmount, pool must be writable to perform migration
umount "${mnt}" || return 1

if [ "${deprecated}" = "/etc/default/zfsbootmenu" ]; then
# Need an R/W mount to remove deprecated config
need_rw="yes"
elif [ -z "${deprecated}" ] || [ -n "${zbm_ignore_kcl_deprecation}" ]; then
# Nothing is deprecated, so there is nothing to do
return 0
fi

# It is not an error if user declines automatic migration
if ! color=green delay=60 prompt="Will attempt migration in %0.2d seconds" \
timed_prompt "Using KCL from ${deprecated} on ${fs}" \
"This behavior is DEPRECATED and will be removed soon" "" \
"KCL should be migrated to an org.zfsbootmenu:commandline property" "" \
"[RETURN] to migrate" "[ESCAPE] to ignore "; then
# Suppress repeated messages
export zbm_ignore_kcl_deprecation=1
echo 'export zbm_ignore_kcl_deprecation="1"' >> /etc/zfsbootmenu.conf
return 0
fi

zdebug "migrating ${deprecated} to org.zfsbootmenu:commandline"

# Pool must be writable to set property and remove config
set_rw_pool "${fs%%/*}" || return 1
CLEAR_SCREEN=1 load_key "${fs}"

if ! mnt="$( allow_rw="${need_rw}" mount_zfs "${fs}" )"; then
zerror "unable to mount ${fs}"
return 1
fi

read -r args < "${args_file}"

if ! zsout="$( zfs set org.zfsbootmenu:commandline="${args}" "${fs}" 2>&1 )"; then
zerror "Unable to migrate ${deprecated} to org.zfsbootmenu:commandline: ${zsout}"
elif [ "${deprecated}" = "/etc/default/zfsbootmenu" ] ; then
zdebug "removing ${deprecated} from ${fs}"
rm "${mnt}${deprecated}" >/dev/null 2>&1
else
zdebug "not removing ${deprecated} from ${fs}"
fi

umount "${mnt}"
}

# arg1: key(and associated value) to suppress from KCL
Expand Down Expand Up @@ -1560,7 +1603,7 @@ timed_prompt() {

[ $# -gt 0 ] || return
[ -n "${delay}" ] || delay="30"
[ -n "${prompt}" ] || prompt="Press [RETURN] or wait %0.2d seconds to continue"
[ -n "${prompt}" ] || prompt="Press [RETURN] or wait %0.${#delay}d seconds to continue"

[ "${delay}" -eq 0 ] && return

Expand Down
3 changes: 2 additions & 1 deletion 90zfsbootmenu/zfsbootmenu-preinit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mkdir -p "${BASE}"

# shellcheck disable=SC2154
cat >> "/etc/zfsbootmenu.conf" <<EOF
# Added by zfsbootmenu-preinit.sh
# BEGIN additions by zfsbootmenu-preinit.sh
export BASE="/zfsbootmenu"
export endian="${endian}"
export spl_hostid="${spl_hostid}"
Expand All @@ -37,6 +37,7 @@ export zbm_sort="${zbm_sort}"
export zbm_set_hostid="${zbm_set_hostid}"
export zbm_import_delay="${zbm_import_delay}"
export control_term="${control_term}"
# END additions by zfsbootmenu-preinit.sh
EOF

getcmdline > "${BASE}/zbm.cmdline"
Expand Down

0 comments on commit 29a1049

Please sign in to comment.