diff --git a/docs/guides/fedora/_include/zbm-install-deps.rst b/docs/guides/fedora/_include/zbm-install-deps.rst index c4b9a697a..5f1dbe9c8 100644 --- a/docs/guides/fedora/_include/zbm-install-deps.rst +++ b/docs/guides/fedora/_include/zbm-install-deps.rst @@ -3,6 +3,7 @@ Install all packages required to build a ZFSBootMenu image on Fedora: .. code-block:: bash dnf install -y \ + systemd-boot-unsigned \ perl-YAML-PP \ perl-Sort-Versions \ perl-boolean \ diff --git a/docs/guides/fedora/_include/zfs-config.rst b/docs/guides/fedora/_include/zfs-config.rst index 70dbeda6b..1dd8cabd3 100644 --- a/docs/guides/fedora/_include/zfs-config.rst +++ b/docs/guides/fedora/_include/zfs-config.rst @@ -39,6 +39,6 @@ Install required packages dnf install -y https://dl.fedoraproject.org/pub/fedora/linux/releases/${VERSION_ID}/Everything/x86_64/os/Packages/k/kernel-devel-$(uname -r).rpm dnf --releasever=${VERSION_ID} install -y \ - https://zfsonlinux.org/fedora/zfs-release-2-2$(rpm --eval "%{dist}").noarch.rpm + https://zfsonlinux.org/fedora/zfs-release-2-3$(rpm --eval "%{dist}").noarch.rpm dnf install -y zfs zfs-dracut diff --git a/docs/guides/fedora/uefi.rst b/docs/guides/fedora/uefi.rst index 7d4426b97..ed7257219 100644 --- a/docs/guides/fedora/uefi.rst +++ b/docs/guides/fedora/uefi.rst @@ -1,4 +1,4 @@ -Workstation 37 UEFI +Workstation 38 UEFI =================== .. |distribution| replace:: fedora @@ -16,7 +16,7 @@ It assumes the following: * Your system is x86_64 * You're mildly comfortable with ZFS, EFI and discovering system facts on your own (``lsblk``, ``dmesg``, ``gdisk``, ...) -Download `Fedora Workstation Live `_ +Download `Fedora Workstation Live `_ , write it to a USB drive and boot your system in EFI mode. .. include:: ../_include/efi-boot-check.rst diff --git a/docs/guides/general/container-building.rst b/docs/guides/general/container-building.rst index 254438d28..ebdf04a7c 100644 --- a/docs/guides/general/container-building.rst +++ b/docs/guides/general/container-building.rst @@ -139,14 +139,16 @@ ZFSBootMenu supports :ref:`custom hooks ` in three stages: any pools. 2. ``setup`` hooks run after pools are imported, right before ZFSBootMenu will either boot a default environment or present a menu. -3. ``teardown`` hooks run immediately before ZFSBootMenu will ``kexec`` the kernel for the selected environment. +3. ``load_key`` hooks run immediately before attempting to load a key for a locked filesystem. Each hook is called with the name of the encryption root to be unlocked as its sole argument. +4. ``teardown`` hooks run immediately before ZFSBootMenu will ``kexec`` the kernel for the selected environment. When ``zbm-builder.sh`` runs, it will identify custom hooks as executable files in the respective subdirectories of its build directory: 1. ``hooks.early_setup.d`` 2. ``hooks.setup.d`` -3. ``hooks.teardown.d`` +3. ``hooks.load_key.d`` +4. ``hooks.teardown.d`` For each hook directory that contains at least one executable file, ``zbm-builder.sh`` will write custom configuration snippets for ``dracut`` and ``mkinitcpio`` that will include these files in the output images. diff --git a/docs/man/dist/man7/zfsbootmenu.7 b/docs/man/dist/man7/zfsbootmenu.7 index ab3bbc164..0766eff47 100644 --- a/docs/man/dist/man7/zfsbootmenu.7 +++ b/docs/man/dist/man7/zfsbootmenu.7 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "ZFSBOOTMENU" "7" "2023-05-21" "" "ZFSBootMenu" +.TH "ZFSBOOTMENU" "7" "2023-07-17" "" "ZFSBootMenu" .SH NAME zfsbootmenu \- System Integration .SH SYNOPSIS @@ -436,6 +436,13 @@ kexec \-\-unload should be sufficient to return to the main menu. Likewise, the hook may construct and execute its own \fIkexec\fP command to alter boot\-time parameters. This may be useful, for example, to allow ZFSBootMenu to select a boot environment and then restructure the boot process to launch a Xen kernel with the selected environment configured as dom0. .UNINDENT .UNINDENT +.sp +\fBzfsbootmenu_skip_gcc_s=yes\fP +.INDENT 0.0 +.INDENT 3.5 +The ZFSBootMenu module attempts to detect and install a copy of the library \fBlibgcc_s.so\fP in its initramfs image on glibc systems. Because several executables may have latent dependencies on this library via a \fBdlopen\fP call in glibc itself, a failure to detect and install the library will cause initramfs generation to fail. If the host system has no dependencies on \fBlibgcc_s.so\fP, set \fBzfsbootmenu_skip_gcc_s=yes\fP to avoid this failure. Alternatively, if \fBlibgcc_s.so\fP is present in an undetected location, set this option and configure Dracut to explicitly install the library. +.UNINDENT +.UNINDENT .SH OPTIONS FOR MKINITCPIO .sp The \fBdracut\fP options specified above may also be specified in a mkinitcpio configuration file when \fBgenerate\-zbm\fP is configured to create images using \fBmkinitcpio\fP\&. However, whereas the \fB\fP values in the dracut configuration should be specified as a single, space\-separated string; in the mkinitcpio configuration, each \fB\fP value must be specified as a Bash array like the standard mkinitcpio arguments. diff --git a/docs/man/zfsbootmenu.7.rst b/docs/man/zfsbootmenu.7.rst index 0b89d83d3..92da0808b 100644 --- a/docs/man/zfsbootmenu.7.rst +++ b/docs/man/zfsbootmenu.7.rst @@ -233,6 +233,12 @@ In addition to standard dracut configuration options, the ZFSBootMenu dracut mod Any installed hooks are run right before the ZFSBootMenu menu will be presented; ZFS pools will generally have been imported and the default boot environment will be available in the *BOOTFS* environment variable. Hooks will not be run if the countdown timer expires (or was set to zero) and the default boot environment is automatically selected. **Note:** The hooks may be run multiple times if the menu is invoked multiple times, e.g., by dropping to an emergency shell and then returning to the menu. If a script should only run once, the script is responsible for keeping track of this. +**zfsbootmenu_load_key=** + + An optional variable specifying a space-separated list of paths to load-key hooks that will be installed in the ZFSBootMenu initramfs. Any path in the list **** that exists and is executable will be installed. + + Any installed hooks are run immediately before ZFSBootMenu menu attempts to load a key for the encryption root of a locked filesystem. Each hook will be run with the name of the encryption root as its sole argument. If any hook exits with a non-zero return code, the load attempt will be aborted and the encryption root will not be unlocked. Hooks can be used to prepare keys needed to unlock the encryption root or may even attempt to unlock the root directly; a filesystem that is unlocked after the hooks have run will be considered to have had its keys successfully loaded. **Note:** The hooks may be run multiple times if keys for a given encryption root need to be loaded multiple times, e.g., by triggering a re-import of the pool. If a script should only run once, the script is responsible for keeping track of this. + **zfsbootmenu_teardown=** An optional variable specifying a space-separated list of paths to teardown hooks that will be installed in the ZFSBootMenu initramfs. Any path in the list **** that exists and is executable will be installed. @@ -261,6 +267,10 @@ In addition to standard dracut configuration options, the ZFSBootMenu dracut mod should be sufficient to return to the main menu. Likewise, the hook may construct and execute its own *kexec* command to alter boot-time parameters. This may be useful, for example, to allow ZFSBootMenu to select a boot environment and then restructure the boot process to launch a Xen kernel with the selected environment configured as dom0. +**zfsbootmenu_skip_gcc_s=yes** + + The ZFSBootMenu module attempts to detect and install a copy of the library **libgcc_s.so** in its initramfs image on glibc systems. Because several executables may have latent dependencies on this library via a **dlopen** call in glibc itself, a failure to detect and install the library will cause initramfs generation to fail. If the host system has no dependencies on **libgcc_s.so**, set **zfsbootmenu_skip_gcc_s=yes** to avoid this failure. Alternatively, if **libgcc_s.so** is present in an undetected location, set this option and configure Dracut to explicitly install the library. + .. _zbm-mkinitcpio-options: Options for mkinitcpio diff --git a/dracut/module-setup.sh b/dracut/module-setup.sh index 853f4c7e4..d09d50dff 100644 --- a/dracut/module-setup.sh +++ b/dracut/module-setup.sh @@ -68,27 +68,22 @@ install() { fi done - # Workaround for zfsonlinux/zfs#4749 by ensuring libgcc_s.so(.1) is included - _ret=0 - # If zpool requires libgcc_s.so*, dracut will track and include it - if ! ldd "$( command -v zpool )" | grep -qF 'libgcc_s.so'; then - # On systems with gcc-config (Gentoo, Funtoo, etc.), use it to find libgcc_s - if command -v gcc-config >/dev/null 2>&1; then - dracut_install "/usr/lib/gcc/$(s=$(gcc-config -c); echo "${s%-*}/${s##*-}")/libgcc_s.so.1" - _ret=$? - # Otherwise, use dracut's library installation function to find the right one - elif ! inst_libdir_file "libgcc_s.so*"; then - # If all else fails, just try looking for some gcc arch directory - dracut_install /usr/lib/gcc/*/*/libgcc_s.so* - _ret=$? - fi - fi - - if [ ${_ret} -ne 0 ]; then - dfatal "Unable to install libgcc_s.so" + # Add libgcc_s as appropriate + local _libgcc_s + if ! _libgcc_s="$( find_libgcc_s )"; then + dfatal "Unable to locate libgcc_s.so" exit 1 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}" + # shellcheck disable=SC2154 while read -r doc ; do relative="${doc//${zfsbootmenu_module_root}\//}" @@ -113,7 +108,7 @@ install() { inst_simple "${_libexec}" "/libexec/$( basename "${_libexec}" )" || _ret=$? done - # User-facing utilities, useful for running in a recover shell + # User-facing utilities, useful for running in a recovery shell for _bin in "${zfsbootmenu_module_root}"/bin/*; do inst_simple "${_bin}" "/bin/$( basename "${_bin}" )" || _ret=$? done @@ -156,6 +151,18 @@ install() { done fi + # Install "load_key" hooks + # shellcheck disable=SC2154 + if [ -n "${zfsbootmenu_load_key}" ]; then + for _exec in ${zfsbootmenu_load_key}; do + if [ -x "${_exec}" ]; then + inst_simple "${_exec}" "/libexec/load_key.d/$(basename "${_exec}")" || _ret=$? + else + dwarning "load_key script (${_exec}) missing or not executable; cannot install" + fi + done + fi + # Install "teardown" hooks # shellcheck disable=SC2154 if [ -n "${zfsbootmenu_teardown}" ]; then diff --git a/etc/zbm-builder/mkinitcpio.conf b/etc/zbm-builder/mkinitcpio.conf index 6a6447a8c..71a9b35e6 100644 --- a/etc/zbm-builder/mkinitcpio.conf +++ b/etc/zbm-builder/mkinitcpio.conf @@ -28,6 +28,7 @@ HOOKS=(base udev autodetect modconf block filesystems keyboard) # # hooks.early_setup.d # hooks.setup.d +# hooks.load_key.d # hooks.teardown.d # # of the same build directory. Support for mkinitcpio.conf.d mimics similar diff --git a/etc/zfsbootmenu/mkinitcpio.conf b/etc/zfsbootmenu/mkinitcpio.conf index 30a232727..60e79de13 100644 --- a/etc/zfsbootmenu/mkinitcpio.conf +++ b/etc/zfsbootmenu/mkinitcpio.conf @@ -75,7 +75,7 @@ HOOKS=(base udev autodetect modconf block filesystems keyboard zfsbootmenu) # tested and may break some (non-essential) ZFSBootMenu features. #zfsbootmenu_miser="no" -# zfsbootmenu_early_setup, zfsbootmenu_setup, zfsbootmenu_teardown +# zfsbootmenu_early_setup, zfsbootmenu_setup, zfsbootmenu_load_key, zfsbootmenu_teardown # ZFSBootMenu supports user-provided hooks that may be run at various points in # the boot process. Set each of these variables to an array of executable files # that should be installed as user hooks in the provided image. Files that are @@ -90,10 +90,15 @@ HOOKS=(base udev autodetect modconf block filesystems keyboard zfsbootmenu) # 'zfsbootmenu_setup' hooks are run after pools are imported and right before # the menu is presented. # +# 'zfsbootmenu_load_key' hooks are run immediately before attempting to load an +# encryption key and unlock a locked filesystem. Each hook is called with a +# single argument: the name of an encryption root that should be unlocked. +# # 'zfsbootmenu_teardown' hooks are run immediately before a chosen boot # environment is about to be launched. Any writable ZFS pools will have been # exported, but read-only pools will generally still be available. # #zfsbootmenu_early_setup=() #zfsbootmenu_setup=() +#zfsbootmenu_load_key=() #zfsbootmenu_teardown=() diff --git a/etc/zfsbootmenu/recovery.conf.d/recovery.conf b/etc/zfsbootmenu/recovery.conf.d/recovery.conf index c372c8c65..e83c7953b 100644 --- a/etc/zfsbootmenu/recovery.conf.d/recovery.conf +++ b/etc/zfsbootmenu/recovery.conf.d/recovery.conf @@ -1,5 +1,5 @@ # Disk manipulation -install_optional_items+=" /bin/gdisk /bin/parted /bin/wipefs /bin/kpartx " +install_optional_items+=" /bin/gdisk /bin/parted /bin/wipefs /bin/kpartx /bin/sgdisk" # Filesystem creation install_optional_items+=" /bin/mkfs.vfat /bin/mkfs.ext4 " @@ -13,3 +13,6 @@ install_optional_items+=" /bin/cryptsetup " # Networking install_optional_items+=" /bin/ip /bin/curl /bin/dhclient /sbin/dhclient-script /bin/ssh " add_dracutmodules+=" kernel-network-modules qemu-net " + +# SSL bundle for cURL +install_optional_items+=" /etc/ssl/certs/ca-certificates.crt " diff --git a/etc/zfsbootmenu/release.conf.d/common.conf b/etc/zfsbootmenu/release.conf.d/common.conf index 43520551a..f943bf6bb 100644 --- a/etc/zfsbootmenu/release.conf.d/common.conf +++ b/etc/zfsbootmenu/release.conf.d/common.conf @@ -1,6 +1,9 @@ zfsbootmenu_teardown+=" /zbm/contrib/xhci-teardown.sh " zfsbootmenu_early_setup+=" /zbm/contrib/10-console-init.sh /zbm/contrib/20-console-autosize.sh " +# zbm-kcl +install_optional_items+=" /zbm/bin/zbm-kcl " + install_optional_items+=" /etc/zbm-commit-hash " omit_dracutmodules+=" crypt-ssh nfs lunmask " diff --git a/initcpio/install/zfsbootmenu b/initcpio/install/zfsbootmenu index 8dbe3b758..f2de626d4 100644 --- a/initcpio/install/zfsbootmenu +++ b/initcpio/install/zfsbootmenu @@ -138,6 +138,22 @@ build() { # Binaries required for ZBM operation add_zbm_binaries + # Add libgcc_s as appropriate + local _libgcc_s + if ! _libgcc_s="$( find_libgcc_s )"; then + error "unable to locate libgcc_s.so" + exit 1 + fi + + local _lib + while read -r _lib ; do + [ -n "${_lib}" ] || continue + if ! add_binary "${_lib}"; then + error "Failed to install '${_lib}'" + exit 1 + fi + done <<< "${_libgcc_s}" + # On-line documentation while read -r doc; do relative="${doc#"${zfsbootmenu_module_root}/"}" @@ -178,6 +194,12 @@ build() { add_file "${_file}" "/libexec/setup.d/${_file##*/}" done + # shellcheck disable=SC2154 + for _file in "${zfsbootmenu_load_key[@]}"; do + [ -x "${_file}" ] || continue + add_file "${_file}" "/libexec/load_key.d/${_file##*/}" + done + # shellcheck disable=SC2154 for _file in "${zfsbootmenu_teardown[@]}"; do [ -x "${_file}" ] || continue diff --git a/releng/rst2help.sh b/releng/rst2help.sh index 5adc66945..8f239fb9a 100755 --- a/releng/rst2help.sh +++ b/releng/rst2help.sh @@ -6,7 +6,7 @@ set -e td="zfsbootmenu/help-files" for size in 52 92 132 ; do rm "${td}/${size}"/* >/dev/null 2>&1 || /bin/true - for doc in docs/online/*.rst docs/man/zfsbootmenu.7.rst; do + for doc in docs/online/*.rst docs/man/zfsbootmenu.7.rst docs/man/zbm-kcl.8.rst; do [ -d "${td}/${size}" ] || mkdir -p "${td}/${size}" file="$( basename -s .rst "${doc}" ).ansi" echo "Converting ${doc} for ${size} columns" diff --git a/zbm-builder.sh b/zbm-builder.sh index d954de831..27b06f7d6 100755 --- a/zbm-builder.sh +++ b/zbm-builder.sh @@ -239,7 +239,7 @@ if ! [ -r "${BUILD_DIRECTORY}"/config.yaml ]; then fi # Try to include ZBM hooks in the images by default -for stage in early_setup setup teardown; do +for stage in early_setup setup load_key teardown; do [ -d "${BUILD_DIRECTORY}/hooks.${stage}.d" ] || continue # Only executable hooks are added to the image diff --git a/zfsbootmenu/help-files/132/zbm-kcl.8.ansi b/zfsbootmenu/help-files/132/zbm-kcl.8.ansi new file mode 100644 index 000000000..957c41ce5 --- /dev/null +++ b/zfsbootmenu/help-files/132/zbm-kcl.8.ansi @@ -0,0 +1,106 @@ +zbm-kcl + + SYNOPSIS + + zbm-kcl [OPTION]... [FILESYSTEM|EFI_EXECUTABLE] + + DESCRIPTION + + The zbm-kcl utility allows review and manipulation of the org.zfsbootmenu:commandline property on ZFS filesystems or the + .cmdline section encoded within ZFSBootMenu EFI executables. ZFSBootMenu reads the property org.zfsbootmenu:commandline, as + set or inherited on each environment that it recognizes, to set the command line for the kernel that it boots. The + ZFSBootMenu EFI executable reads its own .cmdline section to parse options that control the behavior of ZFSBootMenu itself. + + The final argument is treated as a ZFS filesystem as long as one exists with the specified name. If a matching filesystem cannot + be found, the argument is treated as an EFI executable. To force zbm-kcl to treat the final argument as a relative path to + an EFI executable even when a ZFS filesystem exists with the same name, prefix the path with ./. + + When neither a filesystem nor an EFI executable is specified, zbm-kcl will attempt to determine the root filesystem and operate + on that. + + If an EFI executable of - is specified, stdin will be read as an EFI executable. + + With no options specified, zbm-kcl will print the current value of org.zfsbootmenu:commandline of the selected filesystem or the + .cmdline section of the named EFI executable and exit. + + OPTIONS + + -a argument + + Append the value of argument to the kernel command line. The value of argument can be a simple variable name for Boolean + arguments or may take the form var=value to provide a non-Boolean value. Multiple command-line arguments may be + accumulated into a single argument. If the value of any variable value contains spaces, it should be surrounded by + double quotes. In that case, surround the entire argument in single quotes to ensure that the double quotes are recorded + in the property: + + zbm-kcl -a 'variable="some argument with spaces"' + + This argument may be repeated any number of times. + + -r argument + + Remove argument from the kernel command line. The value of argument can be a simple variable name, in which case all arguments + of the form argument or argument= will be stripped. Alternatively, a specific argument may be selected + by specifying argument=. + + This argument may be repeated any number of times. + + Note + + All removal options are processed before any append options are processed, making it possible to replace an existing + argument by combining removal and append options into a single invocation of zbm-kcl. + + -e + + Open the contents of the command-line in an interactive editor. If the environment defines $EDITOR, that will be used; + otherwise, vi will be used by default. After making changes as desired, overwrite the (temporary) file that was opened + and quit the editor. The contents of the saved file will be written by zbm-kcl as the new command line. + + -d + + Delete the command-line property. + + For a ZFS filesystem, this is accomplished by calling + + zfs inherit org.zfsbootmenu:commandline + + to allow the boot environment to inherit any command-line property that may be defined by some parent. + + For a ZFSBootMenu EFI executable, the .cmdline section will be stripped. + + -o destination + + Save the modified command line to destination rather than back to the original source. When the source is a ZFS filesystem, + the destination must also be a valid ZFS filesystem. When the source is an EFI executable, the destination will be + treated as a file; a special EFI destination of - will cause the file to be written to stdout. + + EXAMPLES + + Change the loglevel value on the currently booted environment by removing any existing value from the command line and appending + the desired argument: + + zbm-kcl -a loglevel=7 -r loglevel + + Delete the entire command line from the zroot/ROOT/void boot environment, allowing it to inherit a command line set at zroot or + zroot/ROOT if either of these defines a value: + + zbm-kcl -d zroot/ROOT/void + + Allow interactive editing of the command line on the zroot/ROOT filesystem, but save the resulting changes to zroot/ROOT/void + rather than back to zroot/ROOT: + + zbm-kcl -e -o zroot/ROOT/void zroot/ROOT + + Review the current command line embedded in the EFI file /boot/efi/EFI/zfsbootmenu/zfsbootmenu.EFI: + + zbm-kcl /boot/efi/EFI/zfsbootmenu/zfsbootmenu.EFI + + Fetch the official ZFSBootMenu release EFI executable, customizing the menu timeout and saving the result to + zfsbootmenu-custom.EFI: + + curl -L https://get.zfsbootmenu.org/efi | \ + zbm-kcl -a zbm.timeout=15 -r zbm.timeout -o zfsbootmenu-slow.EFI - + + SEE ALSO + + zfsbootmenu(7) diff --git a/zfsbootmenu/help-files/52/zbm-kcl.8.ansi b/zfsbootmenu/help-files/52/zbm-kcl.8.ansi new file mode 100644 index 000000000..6ae3edb31 --- /dev/null +++ b/zfsbootmenu/help-files/52/zbm-kcl.8.ansi @@ -0,0 +1,171 @@ +zbm-kcl + + SYNOPSIS + + zbm-kcl [OPTION]... [FILESYSTEM|EFI_EXECUTABLE] + + DESCRIPTION + + The zbm-kcl utility allows review and + manipulation of the org.zfsbootmenu:com- + mandline property on ZFS filesystems or the + .cmdline section encoded within ZFSBootMenu + EFI executables. ZFSBootMenu reads the + property org.zfsbootmenu:commandline, as set + or inherited on each environment that it + recognizes, to set the command line for the + kernel that it boots. The ZFSBootMenu EFI + executable reads its own .cmdline section to + parse options that control the behavior of + ZFSBootMenu itself. + + The final argument is treated as a ZFS + filesystem as long as one exists with the + specified name. If a matching filesystem + cannot be found, the argument is treated as + an EFI executable. To force zbm-kcl to treat + the final argument as a relative path to an + EFI executable even when a ZFS filesystem + exists with the same name, prefix the path + with ./. + + When neither a filesystem nor an EFI executable + is specified, zbm-kcl will attempt to + determine the root filesystem and operate on + that. + + If an EFI executable of - is specified, stdin + will be read as an EFI executable. + + With no options specified, zbm-kcl will print + the current value of + org.zfsbootmenu:commandline of the selected + filesystem or the .cmdline section of the + named EFI executable and exit. + + OPTIONS + + -a argument + + Append the value of argument to the kernel + command line. The value of argument can + be a simple variable name for Boolean + arguments or may take the form var=value + to provide a non-Boolean value. Multiple + command-line arguments may be + accumulated into a single argument. If + the value of any variable value contains + spaces, it should be surrounded by + double quotes. In that case, surround + the entire argument in single quotes to + ensure that the double quotes are + recorded in the property: + + zbm-kcl -a 'variable="some argument with spaces"' + + This argument may be repeated any number of + times. + + -r argument + + Remove argument from the kernel command line. + The value of argument can be a simple + variable name, in which case all + arguments of the form argument or + argument= will be + stripped. Alternatively, a specific + argument may be selected by specifying + argument=. + + This argument may be repeated any number of + times. + + Note + + All removal options are processed before any + append options are processed, making + it possible to replace an existing + argument by combining removal and + append options into a single + invocation of zbm-kcl. + + -e + + Open the contents of the command-line in an + interactive editor. If the environment + defines $EDITOR, that will be used; + otherwise, vi will be used by default. + After making changes as desired, + overwrite the (temporary) file that was + opened and quit the editor. The contents + of the saved file will be written by + zbm-kcl as the new command line. + + -d + + Delete the command-line property. + + For a ZFS filesystem, this is accomplished by + calling + + zfs inherit org.zfsbootmenu:commandline + + to allow the boot environment to inherit any + command-line property that may be + defined by some parent. + + For a ZFSBootMenu EFI executable, the .cmdline + section will be stripped. + + -o destination + + Save the modified command line to destination + rather than back to the original source. + When the source is a ZFS filesystem, the + destination must also be a valid ZFS + filesystem. When the source is an EFI + executable, the destination will be + treated as a file; a special EFI + destination of - will cause the file to + be written to stdout. + + EXAMPLES + + Change the loglevel value on the currently + booted environment by removing any existing + value from the command line and appending + the desired argument: + + zbm-kcl -a loglevel=7 -r loglevel + + Delete the entire command line from the + zroot/ROOT/void boot environment, allowing + it to inherit a command line set at zroot or + zroot/ROOT if either of these defines a + value: + + zbm-kcl -d zroot/ROOT/void + + Allow interactive editing of the command line on + the zroot/ROOT filesystem, but save the + resulting changes to zroot/ROOT/void rather + than back to zroot/ROOT: + + zbm-kcl -e -o zroot/ROOT/void zroot/ROOT + + Review the current command line embedded in the + EFI file /boot/efi/EFI/zfsbootmenu/zfsb- + ootmenu.EFI: + + zbm-kcl /boot/efi/EFI/zfsbootmenu/zfsbootmenu.EFI + + Fetch the official ZFSBootMenu release EFI + executable, customizing the menu timeout and + saving the result to zfsbootmenu-custom.EFI: + + curl -L https://get.zfsbootmenu.org/efi | \ + zbm-kcl -a zbm.timeout=15 -r zbm.timeout -o zfsbootmenu-slow.EFI - + + SEE ALSO + + zfsbootmenu(7) diff --git a/zfsbootmenu/help-files/92/zbm-kcl.8.ansi b/zfsbootmenu/help-files/92/zbm-kcl.8.ansi new file mode 100644 index 000000000..186d26953 --- /dev/null +++ b/zfsbootmenu/help-files/92/zbm-kcl.8.ansi @@ -0,0 +1,122 @@ +zbm-kcl + + SYNOPSIS + + zbm-kcl [OPTION]... [FILESYSTEM|EFI_EXECUTABLE] + + DESCRIPTION + + The zbm-kcl utility allows review and manipulation of the org.zfsbootmenu:commandline + property on ZFS filesystems or the .cmdline section encoded within ZFSBootMenu EFI + executables. ZFSBootMenu reads the property org.zfsbootmenu:commandline, as set or + inherited on each environment that it recognizes, to set the command line for the + kernel that it boots. The ZFSBootMenu EFI executable reads its own .cmdline section + to parse options that control the behavior of ZFSBootMenu itself. + + The final argument is treated as a ZFS filesystem as long as one exists with the + specified name. If a matching filesystem cannot be found, the argument is treated as + an EFI executable. To force zbm-kcl to treat the final argument as a relative path + to an EFI executable even when a ZFS filesystem exists with the same name, prefix + the path with ./. + + When neither a filesystem nor an EFI executable is specified, zbm-kcl will attempt to + determine the root filesystem and operate on that. + + If an EFI executable of - is specified, stdin will be read as an EFI executable. + + With no options specified, zbm-kcl will print the current value of + org.zfsbootmenu:commandline of the selected filesystem or the .cmdline section of + the named EFI executable and exit. + + OPTIONS + + -a argument + + Append the value of argument to the kernel command line. The value of argument can be + a simple variable name for Boolean arguments or may take the form var=value to + provide a non-Boolean value. Multiple command-line arguments may be accumulated + into a single argument. If the value of any variable value contains spaces, it + should be surrounded by double quotes. In that case, surround the entire + argument in single quotes to ensure that the double quotes are recorded in the + property: + + zbm-kcl -a 'variable="some argument with spaces"' + + This argument may be repeated any number of times. + + -r argument + + Remove argument from the kernel command line. The value of argument can be a simple + variable name, in which case all arguments of the form argument or + argument= will be stripped. Alternatively, a specific argument + may be selected by specifying argument=. + + This argument may be repeated any number of times. + + Note + + All removal options are processed before any append options are processed, making it + possible to replace an existing argument by combining removal and append + options into a single invocation of zbm-kcl. + + -e + + Open the contents of the command-line in an interactive editor. If the environment + defines $EDITOR, that will be used; otherwise, vi will be used by default. After + making changes as desired, overwrite the (temporary) file that was opened and + quit the editor. The contents of the saved file will be written by zbm-kcl as + the new command line. + + -d + + Delete the command-line property. + + For a ZFS filesystem, this is accomplished by calling + + zfs inherit org.zfsbootmenu:commandline + + to allow the boot environment to inherit any command-line property that may be defined + by some parent. + + For a ZFSBootMenu EFI executable, the .cmdline section will be stripped. + + -o destination + + Save the modified command line to destination rather than back to the original source. + When the source is a ZFS filesystem, the destination must also be a valid ZFS + filesystem. When the source is an EFI executable, the destination will be + treated as a file; a special EFI destination of - will cause the file to be + written to stdout. + + EXAMPLES + + Change the loglevel value on the currently booted environment by removing any existing + value from the command line and appending the desired argument: + + zbm-kcl -a loglevel=7 -r loglevel + + Delete the entire command line from the zroot/ROOT/void boot environment, allowing it to + inherit a command line set at zroot or zroot/ROOT if either of these defines a + value: + + zbm-kcl -d zroot/ROOT/void + + Allow interactive editing of the command line on the zroot/ROOT filesystem, but save the + resulting changes to zroot/ROOT/void rather than back to zroot/ROOT: + + zbm-kcl -e -o zroot/ROOT/void zroot/ROOT + + Review the current command line embedded in the EFI file + /boot/efi/EFI/zfsbootmenu/zfsbootmenu.EFI: + + zbm-kcl /boot/efi/EFI/zfsbootmenu/zfsbootmenu.EFI + + Fetch the official ZFSBootMenu release EFI executable, customizing the menu timeout and + saving the result to zfsbootmenu-custom.EFI: + + curl -L https://get.zfsbootmenu.org/efi | \ + zbm-kcl -a zbm.timeout=15 -r zbm.timeout -o zfsbootmenu-slow.EFI - + + SEE ALSO + + zfsbootmenu(7) diff --git a/zfsbootmenu/install-helpers.sh b/zfsbootmenu/install-helpers.sh index 7ac4a72b9..200439ed5 100644 --- a/zfsbootmenu/install-helpers.sh +++ b/zfsbootmenu/install-helpers.sh @@ -118,7 +118,7 @@ create_zbm_profiles() { # Create shell profiles for ZBM cat > "${BUILDROOT}/etc/profile" <<-EOF - export PATH=/usr/sbin:/usr/bin:/sbin:/bin + export PATH=/zbm/bin:/usr/sbin:/usr/bin:/sbin:/bin export TERM=linux export HOME=/root EOF @@ -184,3 +184,73 @@ create_zbm_traceconf() { export zfsbootmenu_trace_baud=${zfsbootmenu_trace_baud} EOF } + +find_libgcc_s() { + local f libdirs libbase ldir zlibs matched + + # Skip detection if desired + # shellcheck disable=SC2154 + case "${zfsbootmenu_skip_gcc_s,,}" in + yes|on|1) return 0 ;; + esac + + # This is only required on glibc systems due to a dlopen in pthread_cancel + # https://github.com/openzfs/zfs/commit/24554082bd93cb90400c4cb751275debda229009 + ldconfig -p 2>/dev/null | grep -qF 'libc.so.6' || return 0 + + # Build a list of libraries linked by zpool + zlibs="$( ldd "$( command -v zpool 2>/dev/null )" )" || zlibs= + + # If zpool links libgcc_s overtly, there is no need for further action + if grep -qF 'libgcc_s.so' <<< "${zlibs}"; then + return 0 + fi + + # Query gcc-config for a current runtime profile if possible + if command -v gcc-config >/dev/null 2>&1; then + local gver + if gver="$( gcc-config -c )"; then + for f in "/usr/lib/gcc/${gver%-*}/${gver##*-}"/libgcc_s.so*; do + [ -e "${f}" ] || continue + echo "${f}" + matched="yes" + done + [ -n "${matched}" ] && return 0 + fi + fi + + # Try walking library paths to find libgcc_s + + # Search the system cache (adapted from dracut) + libdirs="$( ldconfig -pN 2>/dev/null \ + | grep -E -v '/(lib|lib64|usr/lib|usr/lib64)/[^/]*$' \ + | sed -n 's,.* => \(.*\)/.*,\1,p' | sort | uniq )" || libdirs="" + + # Search zpool dependencies to figure out system libdirs + if [[ "${zlibs}" == */lib64/* ]]; then + libbase="lib64" + else + libbase="lib" + fi + + # Look in all possible system library directories + libdirs="/${libbase} /usr/${libbase} ${libdirs}" + for ldir in ${libdirs}; do + for f in "${ldir}"/libgcc_s.so*; do + [ -e "${f}" ] || continue + echo "${f}" + matched="yes" + done + done + [ -n "${matched}" ] && return 0 + + # As a final fallback, just try to grab *any* libgcc_s from GCC + for f in /usr/lib/gcc/*/*/libgcc_s.so*; do + [ -f "${f}" ] || continue + echo "${f}" + matched="yes" + done + + [ -n "${matched}" ] && return 0 + return 1 +} diff --git a/zfsbootmenu/lib/zfsbootmenu-core.sh b/zfsbootmenu/lib/zfsbootmenu-core.sh index 71a96c4c7..bf56fea84 100755 --- a/zfsbootmenu/lib/zfsbootmenu-core.sh +++ b/zfsbootmenu/lib/zfsbootmenu-core.sh @@ -1659,7 +1659,7 @@ cache_key() { # NOTE: this function should *not* be called from a subshell load_key() { - local fs encroot key keypath keyformat keylocation keysource + local fs encroot key keypath keyformat keylocation keysource _hook fs="${1}" if [ -z "${fs}" ]; then @@ -1673,6 +1673,19 @@ load_key() { return 0 fi + # Run early load_key hooks, if they exist + if [ -d /libexec/load_key.d ]; then + for _hook in /libexec/load_key.d/*; do + zinfo "Processing hook: ${_hook}" + [ -x "${_hook}" ] || continue + if ! "${_hook}" "${encroot}"; then + zwarn "load-key hook '${_hook}' failed for '${encroot}', aborting load attempt" + return 1 + fi + done + unset _hook + fi + # Default to 0 when unset [ -n "${CLEAR_SCREEN}" ] || CLEAR_SCREEN=0 [ -n "${NO_CACHE}" ] || NO_CACHE=0