2019-07-19 05:44:35 +08:00
|
|
|
#!/bin/bash
|
2020-08-11 09:45:09 +08:00
|
|
|
# vim: softtabstop=2 shiftwidth=2 expandtab
|
2019-07-19 05:44:35 +08:00
|
|
|
|
|
|
|
check() {
|
2020-08-22 11:32:17 +08:00
|
|
|
# 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() {
|
2022-10-29 21:40:10 +08:00
|
|
|
echo bash udev-rules
|
2019-11-03 05:49:59 +08:00
|
|
|
return 0
|
2019-07-19 05:44:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
installkernel() {
|
2020-06-20 06:06:55 +08:00
|
|
|
local mod
|
|
|
|
|
2022-01-25 02:21:46 +08:00
|
|
|
# shellcheck disable=SC2154
|
|
|
|
for mod in "${zfsbootmenu_essential_modules[@]}"; do
|
2020-06-20 06:06:55 +08:00
|
|
|
if ! instmods -c "${mod}" ; then
|
|
|
|
dfatal "Required kernel module '${mod}' is missing, aborting image creation!"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
2022-01-25 02:21:46 +08:00
|
|
|
# shellcheck disable=SC2154
|
|
|
|
for mod in "${zfsbootmenu_optional_modules[@]}"; do
|
2020-06-20 06:06:55 +08:00
|
|
|
instmods "${mod}"
|
|
|
|
done
|
2019-07-19 05:44:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
install() {
|
2022-01-23 00:34:39 +08:00
|
|
|
: "${zfsbootmenu_module_root:=/usr/share/zfsbootmenu}"
|
2023-09-12 23:33:40 +08:00
|
|
|
: "${zfsbootmenu_hook_root:=/etc/zfsbootmenu/hooks}"
|
2022-01-23 00:34:39 +08:00
|
|
|
|
|
|
|
# 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}"
|
2023-06-20 00:27:58 +08:00
|
|
|
|
2022-01-23 00:34:39 +08:00
|
|
|
# shellcheck disable=SC2034
|
2023-06-20 00:27:58 +08:00
|
|
|
ZBM_BUILDSTYLE="dracut"
|
2022-01-23 00:34:39 +08:00
|
|
|
|
2020-08-22 11:32:17 +08:00
|
|
|
local _rule _exec _ret
|
|
|
|
|
2022-01-25 02:21:46 +08:00
|
|
|
# shellcheck disable=SC2154
|
|
|
|
for _rule in "${zfsbootmenu_udev_rules[@]}"; do
|
2020-08-22 11:32:17 +08:00
|
|
|
if ! inst_rules "${_rule}"; then
|
|
|
|
dfatal "failed to install udev rule '${_rule}'"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
2022-01-23 00:34:39 +08:00
|
|
|
# shellcheck disable=SC2154
|
|
|
|
for _exec in "${zfsbootmenu_essential_binaries[@]}"; do
|
2020-08-22 11:32:17 +08:00
|
|
|
if ! dracut_install "${_exec}"; then
|
|
|
|
dfatal "failed to install essential executable '${_exec}'"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
2022-01-25 02:21:46 +08:00
|
|
|
# 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
|
2020-08-22 11:32:17 +08:00
|
|
|
|
2023-06-29 03:53:06 +08:00
|
|
|
# Add libgcc_s as appropriate
|
|
|
|
local _libgcc_s
|
|
|
|
if ! _libgcc_s="$( find_libgcc_s )"; then
|
|
|
|
dfatal "Unable to locate libgcc_s.so"
|
2020-08-22 11:32:17 +08:00
|
|
|
exit 1
|
2019-11-03 05:49:59 +08:00
|
|
|
fi
|
2020-06-18 20:18:39 +08:00
|
|
|
|
2023-06-29 03:53:06 +08:00
|
|
|
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}"
|
|
|
|
|
2022-12-15 02:47:01 +08:00
|
|
|
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
|
2021-12-29 09:00:49 +08:00
|
|
|
|
2023-06-20 00:27:58 +08:00
|
|
|
_ret=0
|
2021-12-29 09:00:49 +08:00
|
|
|
|
2023-06-20 00:27:58 +08:00
|
|
|
# Install core ZFSBootMenu functionality
|
|
|
|
install_zbm_core || _ret=$?
|
2021-12-29 09:00:49 +08:00
|
|
|
|
2023-06-20 00:27:58 +08:00
|
|
|
# Install runtime hooks
|
|
|
|
install_zbm_hooks || _ret=$?
|
2021-12-29 09:00:49 +08:00
|
|
|
|
|
|
|
# Hooks necessary to initialize ZBM
|
2023-06-20 00:27:58 +08:00
|
|
|
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=$?
|
2021-12-29 09:00:49 +08:00
|
|
|
|
|
|
|
# Hooks to force the dracut event loop to fire at least once
|
|
|
|
# Things like console configuration are done in optional event-loop hooks
|
2020-12-07 15:08:48 +08:00
|
|
|
# shellcheck disable=SC2154
|
2023-06-20 00:27:58 +08:00
|
|
|
inst_hook initqueue/settled 99 "${moddir}/zfsbootmenu-ready-set.sh" || _ret=$?
|
|
|
|
inst_hook initqueue/finished 99 "${moddir}/zfsbootmenu-ready-chk.sh" || _ret=$?
|
2020-12-07 15:08:48 +08:00
|
|
|
|
2020-08-22 11:32:17 +08:00
|
|
|
if [ ${_ret} -ne 0 ]; then
|
|
|
|
dfatal "Unable to install core ZFSBootMenu functions"
|
|
|
|
exit 1
|
|
|
|
fi
|
2019-07-19 05:44:35 +08:00
|
|
|
|
2023-06-20 00:27:58 +08:00
|
|
|
# Install online documentation if possible
|
|
|
|
install_zbm_docs
|
|
|
|
|
2023-11-09 00:48:47 +08:00
|
|
|
# Install an os-release, if one is available
|
|
|
|
install_zbm_osver
|
|
|
|
|
2023-06-20 00:27:58 +08:00
|
|
|
# optionally enable early Dracut profiling
|
|
|
|
if [ -n "${dracut_trace_enable}" ]; then
|
|
|
|
inst_hook cmdline 00 "${zfsbootmenu_module_root}/profiling/profiling-lib.sh"
|
|
|
|
fi
|
|
|
|
|
2022-11-28 22:40:56 +08:00
|
|
|
# vdev_id.conf and hostid files are host-specific
|
2021-07-02 12:12:53 +08:00
|
|
|
# and do not belong in public release images
|
2023-09-13 09:05:43 +08:00
|
|
|
if [ -z "${zfsbootmenu_release_build}" ]; then
|
2021-07-02 12:12:53 +08:00
|
|
|
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
|
|
|
|
|
2021-07-02 12:12:53 +08:00
|
|
|
# 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
|
2022-12-15 05:29:30 +08:00
|
|
|
echo -ne "\\x${HOSTID:6:2}\\x${HOSTID:4:2}\\x${HOSTID:2:2}\\x${HOSTID:0:2}" > "${initdir}/etc/hostid"
|
2021-07-02 12:12:53 +08:00
|
|
|
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
|
2020-11-18 04:40:22 +08:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
if [ -e "${initdir}/etc/hostid" ] && type mark_hostonly >/dev/null 2>&1; then
|
|
|
|
mark_hostonly /etc/hostid
|
2020-11-12 03:06:08 +08:00
|
|
|
fi
|
2021-03-07 02:31:09 +08:00
|
|
|
|
2021-03-16 09:21:40 +08:00
|
|
|
# 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
|
2023-09-13 09:05:43 +08:00
|
|
|
if [ -n "${zfsbootmenu_release_build}" ]; then
|
2021-03-16 09:21:40 +08:00
|
|
|
echo "rd.hostonly=0" > "${initdir}/etc/cmdline.d/hostonly.conf"
|
|
|
|
fi
|
2021-04-17 07:53:45 +08:00
|
|
|
|
2022-01-23 00:34:39 +08:00
|
|
|
create_zbm_conf
|
|
|
|
create_zbm_profiles
|
|
|
|
create_zbm_traceconf
|
2023-09-13 10:18:39 +08:00
|
|
|
|
|
|
|
if command -v setfont >/dev/null 2>&1; then
|
|
|
|
install_zbm_fonts && dracut_install setfont
|
|
|
|
fi
|
2019-07-19 05:44:35 +08:00
|
|
|
}
|