zfsbootmenu/dracut/module-setup.sh

190 lines
5.6 KiB
Bash
Raw Normal View History

2019-07-19 05:44:35 +08:00
#!/bin/bash
# vim: softtabstop=2 shiftwidth=2 expandtab
2019-07-19 05:44:35 +08:00
check() {
# Do not include this module by default; it must be requested
2019-11-03 05:49:59 +08:00
return 255
2019-07-19 05:44:35 +08:00
}
depends() {
echo bash udev-rules
2019-11-03 05:49:59 +08:00
return 0
2019-07-19 05:44:35 +08:00
}
installkernel() {
local mod
# shellcheck disable=SC2154
for mod in "${zfsbootmenu_essential_modules[@]}"; do
if ! instmods -c "${mod}" ; then
dfatal "Required kernel module '${mod}' is missing, aborting image creation!"
exit 1
fi
done
# shellcheck disable=SC2154
for mod in "${zfsbootmenu_optional_modules[@]}"; do
instmods "${mod}"
done
2019-07-19 05:44:35 +08:00
}
install() {
: "${zfsbootmenu_module_root:=/usr/share/zfsbootmenu}"
: "${zfsbootmenu_hook_root:=/etc/zfsbootmenu/hooks}"
# shellcheck disable=SC1091
if ! source "${zfsbootmenu_module_root}/install-helpers.sh" ; then
dfatal "Unable to source ${zfsbootmenu_module_root}/install-helpers.sh"
exit 1
fi
# BUILDROOT is an initcpio-ism
# shellcheck disable=SC2154,2034
BUILDROOT="${initdir}"
# shellcheck disable=SC2034
ZBM_BUILDSTYLE="dracut"
local _rule _exec _ret
# shellcheck disable=SC2154
for _rule in "${zfsbootmenu_udev_rules[@]}"; do
if ! inst_rules "${_rule}"; then
dfatal "failed to install udev rule '${_rule}'"
exit 1
fi
done
# shellcheck disable=SC2154
for _exec in "${zfsbootmenu_essential_binaries[@]}"; do
if ! dracut_install "${_exec}"; then
dfatal "failed to install essential executable '${_exec}'"
exit 1
fi
done
# shellcheck disable=SC2154
for _exec in "${zfsbootmenu_optional_binaries[@]}"; do
if ! dracut_install "${_exec}"; then
dwarning "optional component '${_exec}' not found, omitting from image"
fi
done
# Add libgcc_s as appropriate
local _libgcc_s
if ! _libgcc_s="$( find_libgcc_s )"; then
dfatal "Unable to locate libgcc_s.so"
exit 1
2019-11-03 05:49:59 +08:00
fi
local _lib
while read -r _lib ; do
[ -n "${_lib}" ] || continue
if ! dracut_install "${_lib}"; then
dfatal "Failed to install '${_lib}'"
exit 1
fi
done <<< "${_libgcc_s}"
compat_dirs=( "/etc/zfs/compatibility.d" "/usr/share/zfs/compatibility.d/" )
for compat_dir in "${compat_dirs[@]}"; do
# shellcheck disable=2164
[ -d "${compat_dir}" ] && tar -cf - "${compat_dir}" | ( cd "${initdir}" ; tar xfp - )
done
_ret=0
# Install core ZFSBootMenu functionality
install_zbm_core || _ret=$?
# Install runtime hooks
install_zbm_hooks || _ret=$?
# Hooks necessary to initialize ZBM
inst_hook cmdline 95 "${zfsbootmenu_module_root}/pre-init/zfsbootmenu-parse-commandline.sh" || _ret=$?
inst_hook pre-mount 90 "${zfsbootmenu_module_root}/pre-init/zfsbootmenu-preinit.sh" || _ret=$?
# Hooks to force the dracut event loop to fire at least once
# Things like console configuration are done in optional event-loop hooks
# shellcheck disable=SC2154
inst_hook initqueue/settled 99 "${moddir}/zfsbootmenu-ready-set.sh" || _ret=$?
inst_hook initqueue/finished 99 "${moddir}/zfsbootmenu-ready-chk.sh" || _ret=$?
if [ ${_ret} -ne 0 ]; then
dfatal "Unable to install core ZFSBootMenu functions"
exit 1
fi
2019-07-19 05:44:35 +08:00
# Install online documentation if possible
install_zbm_docs
# Install an os-release, if one is available
install_zbm_osver
# optionally enable early Dracut profiling
if [ -n "${dracut_trace_enable}" ]; then
inst_hook cmdline 00 "${zfsbootmenu_module_root}/profiling/profiling-lib.sh"
fi
# vdev_id.conf and hostid files are host-specific
# and do not belong in public release images
if [ -z "${zfsbootmenu_release_build}" ]; then
if [ -e /etc/zfs/vdev_id.conf ]; then
inst /etc/zfs/vdev_id.conf
type mark_hostonly >/dev/null 2>&1 && mark_hostonly /etc/zfs/vdev_id.conf
Add support to discover and assume a hostid, as well as fix arguments passed to a BE (#147) A persistent problem with ZFS and now with ZFSBootMenu is getting spl.spl_hostid lined up on all pool imports. The contents of an initramfs and the kernel command line can influence this value, making it difficult to determine exactly where and how to change it to get a system to boot. To help combat this recurring issue, ZBM now accepts the following options to control importing behavior. * zbm.import_policy=strict: If no pools can be imported with the hostid embedded in the initramfs, or set via spl_hostid on the ZBM command line, drop to a recovery shell. * zbm.import_policy=hostid: If no pools can be imported with the hostid embedded in the initramfs, or set via spl_hostid on the ZBM command line, attempt to scrape the hostid used to import the pool defined in root=zfsbootmenu:POOL=<value> and import the pool. If that pool is missing or can't be imported, any other available pool is scraped for a hostid and attempted to be imported. * zbm.import_policy=force: YOLO mode, just force import a pool. Replaces `zbm.force_import'. Right now, when undefined, zbm.import_policy is set to strict. With this option available, ZBM can now in most cases import any pool - regardless of the hostid of the system that built the initramfs or the EFI executable. Next is to ensure that the boot environment imports the pool correctly. Some ZFS initramfs modules can use spl_hostid to write out /etc/hostid in the initramfs before loading SPL/ZFS modules. Others ... like Arch ... not only do not by default include /etc/hostid in the initramfs, they do not have any methods to line up spl_hostid on the kernel command line with /etc/hostid. However, spl.spl_hostid takes precedence over /etc/hostid, so we can simply set this on the kernel command line. To this end, we now: Suppress spl_hostid if it's part of the discovered command line for a boot environment Suppress spl.spl_hostid if it's part of the discovered command line for a boot environment Insert spl.spl_hostid=0x<hostid> on the command line for each boot environment. (when hostid is 0, insert spl_hostid=0x00000000, to help dracut. spl.spl_hostid=0 is a no-op). Since we know the hostid used to import a pool - either discovered in zfsbootmenu-parse-commandline.sh, or discovered when zbm.import_policy=hostid is set. Suppression / rewriting can be disabled via zbm.set_hostid=0 when booting ZBM. Co-authored-by: Zach Dykstra <dykstra.zachary@gmail.com> Co-authored-by: Andrew J. Hesford <ajh@sideband.org>
2021-02-26 08:29:10 +08:00
fi
# Try to synchronize hostid between host and ZFSBootMenu
#
# DEPRECATION NOTICE: on musl systems, zfs < 2.0 produced a bad hostid in
# dracut images. Unfortunately, this should be replicated for now to ensure
# those images are bootable. After some time, remove this version check.
ZVER="$( zfs version | head -n1 | sed 's/zfs-\(kmod-\)\?//' )"
if [ -n "${ZVER}" ] && printf '%s\n' "${ZVER}" "2.0" | sort -VCr; then
NEWZFS=yes
else
NEWZFS=""
fi
if [ -n "${NEWZFS}" ] && [ -e /etc/hostid ]; then
# With zfs >= 2.0, prefer the hostid file if it exists
inst /etc/hostid
elif HOSTID="$( hostid 2>/dev/null )"; then
# Fall back to `hostid` output when it is nonzero or with zfs < 2.0
if [ -z "${NEWZFS}" ]; then
# In zfs < 2.0, zgenhostid does not provide necessary behavior
echo -ne "\\x${HOSTID:6:2}\\x${HOSTID:4:2}\\x${HOSTID:2:2}\\x${HOSTID:0:2}" > "${initdir}/etc/hostid"
elif [ "${HOSTID}" != "00000000" ]; then
# In zfs >= 2.0, zgenhostid writes the output, but only with nonzero hostid
# shellcheck disable=SC2154
zgenhostid -o "${initdir}/etc/hostid" "${HOSTID}"
Add support to discover and assume a hostid, as well as fix arguments passed to a BE (#147) A persistent problem with ZFS and now with ZFSBootMenu is getting spl.spl_hostid lined up on all pool imports. The contents of an initramfs and the kernel command line can influence this value, making it difficult to determine exactly where and how to change it to get a system to boot. To help combat this recurring issue, ZBM now accepts the following options to control importing behavior. * zbm.import_policy=strict: If no pools can be imported with the hostid embedded in the initramfs, or set via spl_hostid on the ZBM command line, drop to a recovery shell. * zbm.import_policy=hostid: If no pools can be imported with the hostid embedded in the initramfs, or set via spl_hostid on the ZBM command line, attempt to scrape the hostid used to import the pool defined in root=zfsbootmenu:POOL=<value> and import the pool. If that pool is missing or can't be imported, any other available pool is scraped for a hostid and attempted to be imported. * zbm.import_policy=force: YOLO mode, just force import a pool. Replaces `zbm.force_import'. Right now, when undefined, zbm.import_policy is set to strict. With this option available, ZBM can now in most cases import any pool - regardless of the hostid of the system that built the initramfs or the EFI executable. Next is to ensure that the boot environment imports the pool correctly. Some ZFS initramfs modules can use spl_hostid to write out /etc/hostid in the initramfs before loading SPL/ZFS modules. Others ... like Arch ... not only do not by default include /etc/hostid in the initramfs, they do not have any methods to line up spl_hostid on the kernel command line with /etc/hostid. However, spl.spl_hostid takes precedence over /etc/hostid, so we can simply set this on the kernel command line. To this end, we now: Suppress spl_hostid if it's part of the discovered command line for a boot environment Suppress spl.spl_hostid if it's part of the discovered command line for a boot environment Insert spl.spl_hostid=0x<hostid> on the command line for each boot environment. (when hostid is 0, insert spl_hostid=0x00000000, to help dracut. spl.spl_hostid=0 is a no-op). Since we know the hostid used to import a pool - either discovered in zfsbootmenu-parse-commandline.sh, or discovered when zbm.import_policy=hostid is set. Suppression / rewriting can be disabled via zbm.set_hostid=0 when booting ZBM. Co-authored-by: Zach Dykstra <dykstra.zachary@gmail.com> Co-authored-by: Andrew J. Hesford <ajh@sideband.org>
2021-02-26 08:29:10 +08:00
fi
fi
fi
# shellcheck disable=SC2154
if [ -e "${initdir}/etc/hostid" ] && type mark_hostonly >/dev/null 2>&1; then
mark_hostonly /etc/hostid
fi
# Embed a kernel command line in the initramfs
# shellcheck disable=SC2154
if [ -n "${embedded_kcl}" ]; then
echo "export embedded_kcl=\"${embedded_kcl}\"" >> "${initdir}/etc/zfsbootmenu.conf"
fi
# Force rd.hostonly=0 in the KCL for releases, this will purge itself after 99base/init.sh runs
# shellcheck disable=SC2154
if [ -n "${zfsbootmenu_release_build}" ]; then
echo "rd.hostonly=0" > "${initdir}/etc/cmdline.d/hostonly.conf"
fi
create_zbm_conf
create_zbm_profiles
create_zbm_traceconf
if command -v setfont >/dev/null 2>&1; then
install_zbm_fonts && dracut_install setfont
fi
2019-07-19 05:44:35 +08:00
}