Skip to content

Commit

Permalink
dracut, initcpio: make libgcc_s search universal
Browse files Browse the repository at this point in the history
Closes: #427.

Update zfsbootmenu-core.sh

Update mkinitcpio.conf

Update zfsbootmenu-core.sh

Update docs/man/zfsbootmenu.7.rst

Co-authored-by: Andrew J. Hesford <[email protected]>

Update docs/man/zfsbootmenu.7.rst

Co-authored-by: Andrew J. Hesford <[email protected]>
  • Loading branch information
2 people authored and bob committed Jul 22, 2023
1 parent ae519b4 commit bdbfdc8
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 24 deletions.
9 changes: 8 additions & 1 deletion docs/man/dist/man7/zfsbootmenu.7
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<executable\-list>\fP values in the dracut configuration should be specified as a single, space\-separated string; in the mkinitcpio configuration, each \fB<executable\-list>\fP value must be specified as a Bash array like the standard mkinitcpio arguments.
Expand Down
13 changes: 13 additions & 0 deletions docs/man/zfsbootmenu.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,15 @@ 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.

<<<<<<< HEAD
=======
**zfsbootmenu_load_key=<executable-list>**

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 **<executable-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.

>>>>>>> f2ddbec (Update docs/man/zfsbootmenu.7.rst)
**zfsbootmenu_teardown=<executable-list>**

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 **<executable-list>** that exists and is executable will be installed.
Expand Down Expand Up @@ -261,6 +270,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
Expand Down
31 changes: 13 additions & 18 deletions dracut/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}\//}"
Expand Down
8 changes: 4 additions & 4 deletions etc/zfsbootmenu/mkinitcpio.conf
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,14 @@ 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_load_key' hooks are run immediately before attempting to load an
# encryption key and unlocked a locked filesystem. Each hook is called with a
# single argument: the name of an encryption root that should be unlocked.
#
#zfsbootmenu_early_setup=()
#zfsbootmenu_setup=()
#zfsbootmenu_load_key=()
Expand Down
16 changes: 16 additions & 0 deletions initcpio/install/zfsbootmenu
Original file line number Diff line number Diff line change
Expand Up @@ -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}/"}"
Expand Down
70 changes: 70 additions & 0 deletions zfsbootmenu/install-helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion zfsbootmenu/lib/zfsbootmenu-core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1679,7 +1679,7 @@ load_key() {
zinfo "Processing hook: ${_hook}"
[ -x "${_hook}" ] || continue
if ! "${_hook}" "${encroot}"; then
zwarn "load-key hook failed for '${encroot}', aborting load attempt"
zwarn "load-key hook '${_hook}' failed for '${encroot}', aborting load attempt"
return 1
fi
done
Expand Down

0 comments on commit bdbfdc8

Please sign in to comment.