Skip to content

Commit 56cbbe8

Browse files
committed
dracut, initcpio: make libgcc_s search universal
Closes: #427.
1 parent deefabd commit 56cbbe8

File tree

5 files changed

+111
-19
lines changed

5 files changed

+111
-19
lines changed

docs/man/dist/man7/zfsbootmenu.7

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
2727
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
2828
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
2929
..
30-
.TH "ZFSBOOTMENU" "7" "2023-05-21" "" "ZFSBootMenu"
30+
.TH "ZFSBOOTMENU" "7" "2023-07-17" "" "ZFSBootMenu"
3131
.SH NAME
3232
zfsbootmenu \- System Integration
3333
.SH SYNOPSIS
@@ -436,6 +436,13 @@ kexec \-\-unload
436436
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.
437437
.UNINDENT
438438
.UNINDENT
439+
.sp
440+
\fBzfsbootmenu_skip_gcc_s=yes\fP
441+
.INDENT 0.0
442+
.INDENT 3.5
443+
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.
444+
.UNINDENT
445+
.UNINDENT
439446
.SH OPTIONS FOR MKINITCPIO
440447
.sp
441448
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.

docs/man/zfsbootmenu.7.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,10 @@ In addition to standard dracut configuration options, the ZFSBootMenu dracut mod
261261
262262
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.
263263

264+
**zfsbootmenu_skip_gcc_s=yes**
265+
266+
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.
267+
264268
.. _zbm-mkinitcpio-options:
265269

266270
Options for mkinitcpio

dracut/module-setup.sh

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,27 +68,22 @@ install() {
6868
fi
6969
done
7070

71-
# Workaround for zfsonlinux/zfs#4749 by ensuring libgcc_s.so(.1) is included
72-
_ret=0
73-
# If zpool requires libgcc_s.so*, dracut will track and include it
74-
if ! ldd "$( command -v zpool )" | grep -qF 'libgcc_s.so'; then
75-
# On systems with gcc-config (Gentoo, Funtoo, etc.), use it to find libgcc_s
76-
if command -v gcc-config >/dev/null 2>&1; then
77-
dracut_install "/usr/lib/gcc/$(s=$(gcc-config -c); echo "${s%-*}/${s##*-}")/libgcc_s.so.1"
78-
_ret=$?
79-
# Otherwise, use dracut's library installation function to find the right one
80-
elif ! inst_libdir_file "libgcc_s.so*"; then
81-
# If all else fails, just try looking for some gcc arch directory
82-
dracut_install /usr/lib/gcc/*/*/libgcc_s.so*
83-
_ret=$?
84-
fi
85-
fi
86-
87-
if [ ${_ret} -ne 0 ]; then
88-
dfatal "Unable to install libgcc_s.so"
71+
# Add libgcc_s as appropriate
72+
local _libgcc_s
73+
if ! _libgcc_s="$( find_libgcc_s )"; then
74+
dfatal "Unable to locate libgcc_s.so"
8975
exit 1
9076
fi
9177

78+
local _lib
79+
while read -r _lib ; do
80+
[ -n "${_lib}" ] || continue
81+
if ! dracut_install "${_lib}"; then
82+
dfatal "Failed to install '${_lib}'"
83+
exit 1
84+
fi
85+
done <<< "${_libgcc_s}"
86+
9287
# shellcheck disable=SC2154
9388
while read -r doc ; do
9489
relative="${doc//${zfsbootmenu_module_root}\//}"

initcpio/install/zfsbootmenu

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ build() {
138138
# Binaries required for ZBM operation
139139
add_zbm_binaries
140140

141+
# Add libgcc_s as appropriate
142+
local _libgcc_s
143+
if ! _libgcc_s="$( find_libgcc_s )"; then
144+
error "unable to locate libgcc_s.so"
145+
exit 1
146+
fi
147+
148+
local _lib
149+
while read -r _lib ; do
150+
[ -n "${_lib}" ] || continue
151+
if ! add_binary "${_lib}"; then
152+
error "Failed to install '${_lib}'"
153+
exit 1
154+
fi
155+
done <<< "${_libgcc_s}"
156+
141157
# On-line documentation
142158
while read -r doc; do
143159
relative="${doc#"${zfsbootmenu_module_root}/"}"

zfsbootmenu/install-helpers.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,73 @@ create_zbm_traceconf() {
184184
export zfsbootmenu_trace_baud=${zfsbootmenu_trace_baud}
185185
EOF
186186
}
187+
188+
find_libgcc_s() {
189+
local f libdirs libbase ldir zlibs matched
190+
191+
# Skip detection if desired
192+
# shellcheck disable=SC2154
193+
case "${zfsbootmenu_skip_gcc_s,,}" in
194+
yes|on|1) return 0 ;;
195+
esac
196+
197+
# This is only required on glibc systems due to a dlopen in pthread_cancel
198+
# https://github.com/openzfs/zfs/commit/24554082bd93cb90400c4cb751275debda229009
199+
ldconfig -p 2>/dev/null | grep -qF 'libc.so.6' || return 0
200+
201+
# Build a list of libraries linked by zpool
202+
zlibs="$( ldd "$( command -v zpool 2>/dev/null )" )" || zlibs=
203+
204+
# If zpool links libgcc_s overtly, there is no need for further action
205+
if grep -qF 'libgcc_s.so' <<< "${zlibs}"; then
206+
return 0
207+
fi
208+
209+
# Query gcc-config for a current runtime profile if possible
210+
if command -v gcc-config >/dev/null 2>&1; then
211+
local gver
212+
if gver="$( gcc-config -c )"; then
213+
for f in "/usr/lib/gcc/${gver%-*}/${gver##*-}"/libgcc_s.so*; do
214+
[ -e "${f}" ] || continue
215+
echo "${f}"
216+
matched="yes"
217+
done
218+
[ -n "${matched}" ] && return 0
219+
fi
220+
fi
221+
222+
# Try walking library paths to find libgcc_s
223+
224+
# Search the system cache (adapted from dracut)
225+
libdirs="$( ldconfig -pN 2>/dev/null \
226+
| grep -E -v '/(lib|lib64|usr/lib|usr/lib64)/[^/]*$' \
227+
| sed -n 's,.* => \(.*\)/.*,\1,p' | sort | uniq )" || libdirs=""
228+
229+
# Search zpool dependencies to figure out system libdirs
230+
if [[ "${zlibs}" == */lib64/* ]]; then
231+
libbase="lib64"
232+
else
233+
libbase="lib"
234+
fi
235+
236+
# Look in all possible system library directories
237+
libdirs="/${libbase} /usr/${libbase} ${libdirs}"
238+
for ldir in ${libdirs}; do
239+
for f in "${ldir}"/libgcc_s.so*; do
240+
[ -e "${f}" ] || continue
241+
echo "${f}"
242+
matched="yes"
243+
done
244+
done
245+
[ -n "${matched}" ] && return 0
246+
247+
# As a final fallback, just try to grab *any* libgcc_s from GCC
248+
for f in /usr/lib/gcc/*/*/libgcc_s.so*; do
249+
[ -f "${f}" ] || continue
250+
echo "${f}"
251+
matched="yes"
252+
done
253+
254+
[ -n "${matched}" ] && return 0
255+
return 1
256+
}

0 commit comments

Comments
 (0)