You are not logged in.
I wrote following script snippet after spending +6h on the binutils 2.41 vs. perf bug I reported.
It would have instantly pointed me at right direction(s) and saved multiple hours of trouble shooting.
See updated version here
#!/bin/bash
# force C locale to get stable command output.
export LANG=C
function depcheck() {
readarray -t results < <(ldd $1 | grep 'not found')
if [[ ${#results[@]} -gt 0 ]]; then
echo "depcheck $1 failed:";
for dep in "${results[@]}"; do
# trim white space from the ldd line:
dep="${dep#"${dep%%[![:space:]]*}"}"
dep="${dep%"${dep##*[![:space:]]}"}"
echo "${dep}"
# try find who owns the missing library file:
libname="$(echo $dep | sed -re 's#(.*)\.so.*#\1.so#')"
echo "pacman -Qo /lib/${libname}*"
pacman -Qo /lib/${libname}*
done
fi
}
# test single binary:
if [[ -n $1 ]]; then
depcheck $1
exit
fi
# else test all of /bin
for fbin in $(find /bin/ -executable -type f); do
# test only ELF executables, not 100% fool proof
# and ldd may still complain on some files.
if head -c 4 $fbin | grep -qc 'ELF'; then
depcheck $fbin;
fi
done
No elevated privileges should be required to run above script.
What the script does is scan /bin for any ELF binaries (shebangs with +x should not count)
and pass them to ldd command and report any errors that ldd outputs.
If ldd shows any missing dynamic (.so) libraries for binary, it feeds these names to
pacman -Qo
to try see if these files are owned by any package.
My system does not "pass" the check and I found out that bunch things are broken at the moment:
depcheck /bin/sensord failed:
librrd.so.8 => not found
pacman -Qo /lib/librrd.so*
error: No package owns /lib/librrd.so*
depcheck /bin/mpeg2dec failed:
libSDL-1.2.so.0 => not found
pacman -Qo /lib/libSDL-1.2.so*
error: No package owns /lib/libSDL-1.2.so*
... list goes on ...
If binary is reported by this script that binary can't be run on your system.
If pacman reports "No package owns nnn" the shared library is likely totally missing from the system.
pkgfile might find package that provides this file.
In case of perf tool from linux-tools the result got interesting: "/usr/lib/libsframe.so is owned by binutils 2.41-1"
This result tells the package that owns perf binary is now broken: its dependency has changed in incompatible way, but pacman has upgraded the dependency regardless.
Likely only way to cleanly fix such situation is to re-build the (perf,linux-tools) package yourself and report it.
I'm kind of curious of what and how many things this script would report on other user systems?
Also I don't know if tool like this exists already, I'm just glad to drop this here.
Suggestions to improve the script are also welcome.
Last edited by JATothrim (2023-08-06 20:20:09)
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
There seems to be a lot of grepping, redirecting, then other parsing which could be simplified. I have a related script that just lists the dependencies for a given binary (regardless of whether they are "missing"):
#!/bin/sh
readelf -d $1 \
| sed -n 's|.*Shared library: \[\([^\]*\)\]|/usr/lib/\1|p' \
| pacman -F - | sed 's|^|/|;s| .*||' | pacman -Qqo - \
| sort -u
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
@JATothrim: Er?
not a dynamic executable
head: cannot open '/bin/mount.nfs' for reading: Permission denied
head: cannot open '/bin/cdda2wav' for reading: Permission denied
not a dynamic executable
not a dynamic executable
depcheck /bin/hdspconf failed:
libfltk.so.1.3 => not found
pacman -Qo /lib/libfltk.so*
error: No package owns /lib/libfltk.so*
depcheck /bin/sensord failed:
librrd.so.8 => not found
pacman -Qo /lib/librrd.so*
error: No package owns /lib/librrd.so*
head: cannot open '/bin/readcd' for reading: Permission denied
not a dynamic executable
depcheck /bin/hdspmixer failed:
libfltk.so.1.3 => not found
pacman -Qo /lib/libfltk.so*
error: No package owns /lib/libfltk.so*
not a dynamic executable
depcheck /bin/makemhr failed:
libmysofa.so.1 => not found
pacman -Qo /lib/libmysofa.so*
error: No package owns /lib/libmysofa.so*
head: cannot open '/bin/cdrecord' for reading: Permission denied
not a dynamic executable
not a dynamic executable
head: cannot open '/bin/rscsi' for reading: Permission denied
Last edited by yochananmarqos (2023-08-05 21:02:24)
Offline
There seems to be a lot of grepping, redirecting, then other parsing which could be simplified. I have a related script that just lists the dependencies for a given binary (regardless of whether they are "missing"):
#!/bin/sh readelf -d $1 \ | sed -n 's|.*Shared library: \[\([^\]*\)\]|/usr/lib/\1|p' \ | pacman -F - | sed 's|^|/|;s| .*||' | pacman -Qqo - \ | sort -u
Had to add "export LANG=C" and do pacman -Fy to run above...
I'm not too good on bash scripting and I assembled this thing in one evening.. I mostly do C++.
Idea was to find + detect what installed binaries can not run on the system and point to the potential culprit if any.
Last edited by JATothrim (2023-08-06 00:10:57)
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
@JATothrim: Er?
not a dynamic executable head: cannot open '/bin/mount.nfs' for reading: Permission denied head: cannot open '/bin/cdda2wav' for reading: Permission denied not a dynamic executable not a dynamic executable depcheck /bin/hdspconf failed: libfltk.so.1.3 => not found pacman -Qo /lib/libfltk.so* error: No package owns /lib/libfltk.so* depcheck /bin/sensord failed: librrd.so.8 => not found pacman -Qo /lib/librrd.so* error: No package owns /lib/librrd.so* head: cannot open '/bin/readcd' for reading: Permission denied not a dynamic executable depcheck /bin/hdspmixer failed: libfltk.so.1.3 => not found pacman -Qo /lib/libfltk.so* error: No package owns /lib/libfltk.so* not a dynamic executable depcheck /bin/makemhr failed: libmysofa.so.1 => not found pacman -Qo /lib/libmysofa.so* error: No package owns /lib/libmysofa.so* head: cannot open '/bin/cdrecord' for reading: Permission denied not a dynamic executable not a dynamic executable head: cannot open '/bin/rscsi' for reading: Permission denied
Thanks for test run: The hdspconf, sensord, hdspmixer, makemhr are likely unable to run if you try them.
the script just spews errors out on few of files though...
"not a dynamic executable" lines are ldd command complaining because my script fails to ignore these files.
"head: cannot open ..." lines are a bit weird: Do you have some files in /bin that have only execute bit but no read bit set? o__O
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
Listing all the package dependencies of program is a bit pointless
That's what you said your script was trying to do.
But if you really just want to detect programs with missing dynamic links that's much easier:
#!/bin/sh
ldd /bin/* 2>/dev/null | awk '
/^\// { exe = $1 }
/not found/ { list[exe] = list[exe] " " $1 }
END { for (key in list) print key list[key] }
'
Last edited by Trilby (2023-08-05 21:55:47)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
The hdspconf, sensord, hdspmixer, makemhr are likely unable to run if you try them.
Oh, I see. Those are all binaries of packages I do have installed, however I do not have the corresponding optional dependencies installed.
Offline
JATothrim wrote:Listing all the package dependencies of program is a bit pointless
That's what you said your script was trying to do.
Ah. excuse for my bad english.. *facepalm*
Your awk version is much better than mine doing the searching part.
Just do "pacman -F" for each of these missing dynamic links and that is it.
Those are all binaries of packages I do have installed, however I do not have the corresponding optional dependencies installed.
Oh, that may explain some of the cases.
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
There are versions here using "ldd" and "readelf -d". There is a slight difference. Using "ldd" does a recursive lookup, were "readelf -d" just looks for directly linked libraries, so you may get slightly different results.
Offline
There are versions here using "ldd" and "readelf -d". There is a slight difference. Using "ldd" does a recursive lookup, were "readelf -d" just looks for directly linked libraries, so you may get slightly different results.
Do you have some examples that do recursive lookup?
What I understand ldd is invoking the standard system linker and stopping before the program is run.
I think "readelf -d" is good for inspecting the directly linked dependencies, but it may miss stuff deeper the linking dependency chain.
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
Another difference I realized in hindsight is I'm not sure whether readelf reports missing libraries any differently than ones that are present. My first code block in this thread was what I use for a different purpose than yours: I use it on built binaries that I intend to package (my own version of namcap) to ensure I list all the needed dependencies in the PKGBUILD. For that use one would not want a recursive look-up (which is one of the main reasons I use readelf for that rather than ldd).
Last edited by Trilby (2023-08-06 14:01:43)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
I wrote upgraded version that does not use grep or ldd at all.
This is script is intended for users that have to troubleshoot why some installed binary fails with missing libraries.
The script may report false positives if it can't locate the library on the file system.
Please verify the reported binary/program fails to execute:
If the reported binary/program does run report an bug here.
depcheck: Recursively parse given binary/program dependency chain with "readelf -d" and awk.
If the script can't find a library file on the system it reports them with "pacman -F "
In "scan all mode" without arguments it processes all of /bin and this may take awhile...
Bugs fixed: strip off any hard coded path-names from libraries.
#!/bin/bash
# depcheck V2: find system binaries that are unable to run
# requires bash 4.3, find, readelf, awk, sort, pacman
# --Any NOTE(s) reported by this tool means an installed binary
# is missing optional dependency.
# Such binaries/programs cannot run until the dependency is installed.
# --Any WARN(s) reported by this tool means: an installed binary
# is missing dependency *and* the dependency is also installed.
# Such binaries/programs cannot run until the dependency is fixed.
# Fixing such dependency problem may be hard.
# You should also verify that the binary really does not execute: If it runs, please report an bug for this script.
# force C locale to get stable command output.
export LANG=C
export LC_ALL=C
checkpassed=0
function pacman_query() {
local -n _query=$1
readarray _query < <(pacman -F $2 | awk '
{ line[NR] = $0 }
/installed/ { wasinstalled = 1
line[NR] = $0 }
END { print wasinstalled
for (i in line)
print "==>" line[i]
}')
}
function checkissue() {
# display pacman -F result for $1
depname=$(basename "$(echo $1 | sed -re 's#(.*)\.so.*#\1.so#')" )
local pkginfo=()
pacman_query pkginfo "$depname"
if [[ "${pkginfo[0]}" =~ "1" ]]; then
echo "==>This dependency is currently installed via"
for info in "${pkginfo[@]:1}"; do
echo -ne "$info"
done
local baseprog=$(basename "$2")
pacman_query pkginfo "$baseprog"
echo "==>WARN: Following package may have an problem:"
for info in "${pkginfo[@]:1}"; do
echo -ne "$info"
done
checkpassed=1
return 1
else
echo "==>NOTE: This dependency may be installed via"
for info in "${pkginfo[@]:1}"; do
echo -ne "$info"
done
return 1
fi
}
function unique_arr() {
local -n arrayref=$1
readarray -td '' arrayref < <(printf '%s\0' "${arrayref[@]}" | sort -zus)
}
# accelerate recursive dependency chain checking:
# any library added here is ignored by depgraph.
passeddeps=('libc.so')
# build the recursive dependency graph with readelf -d and awk
# (avoid using ldd for security reasons)
function depgraph() {
# collect RPATH/RUNPATH and NEEDED from the binary
# awk filters out anything that is in skip array.
local skip=(${@:3} ${passeddeps[*]} )
echo -ne "\033[0Kprocessing...\r"
readarray -t depinfo < <(readelf -d $1 | awk -v fskip="${skip[*]// /:}" '
/RPATH/ { rpath = gensub(/.*\[(.+)\].*/, "\\1", "g", $0) }
/RUNPATH/ { rpath = gensub(/.*\[(.+)\].*/, "\\1", "g", $0) }
/NEEDED/ { list[NR] = gensub(/.*\[(.+)\].*/, "\\1", "g", $0) }
END { print rpath
for (i in list)
if (index(fskip, list[i]) == 0)
print list[i] } ' )
[[ $? != 0 ]] && return 0
local deps=("${depinfo[@]:1}")
# assemble array of unique library search paths
local rpath="${depinfo[0]}"
local inpaths="$2"
local paths=(${rpath//:/ } ${inpaths//:/ } /lib /usr/lib32)
unique_arr paths
#declare -p paths
#declare -p deps
for dep in ${deps[@]}; do
dep="$(basename $dep)"
local ok=0
for path in ${paths[@]}; do
if [[ -r "$path/$dep" ]]; then
ok=1
depgraph "$path/$dep" "${paths[*]// /:}" ${skip[*]} ${deps[*]}
break
fi
done
if [[ $ok == 0 ]]; then
# file likely not found on the system
echo "Unable to find [$dep] from the system. This library is needed to run [$1]"
checkissue $dep $1
fi
if [[ $? == 0 ]]; then
passeddeps+=("$dep")
fi
done
unique_arr passeddeps
return 0
}
# test single files from command line
cmdline=("$@")
if [[ -n "${cmdline[*]}" ]]; then
for fbin in ${cmdline[@]}; do
echo "depcheck $fbin"
depgraph "$fbin"
done
exit $checkpassed
fi
# else test all of /bin
for fbin in $(find /bin/ -readable -type f); do
depgraph $fbin 2>/dev/null
done
echo "${#passeddeps[@]} libraries checked total."
exit $checkpassed
The script output now looks like:
~$depcheck /bin/pvtkpython /bin/bpf_jit_disasm
depcheck /bin/pvtkpython
Unable to find [libmpi.so.40] from the system. This library is needed to run [/bin/pvtkpython]
==>NOTE: This dependency may be installed via
==>extra/intel-oneapi-basekit 2023.1.0.46401-3
==> opt/intel/oneapi/mpi/2021.9.0/lib/debug/libmpi.so
==> opt/intel/oneapi/mpi/2021.9.0/lib/release/libmpi.so
==>extra/openmpi 4.1.5-2
==> usr/lib/libmpi.so
depcheck /bin/bpf_jit_disasm
Unable to find [libsframe.so.0] from the system. This library is needed to run [/bin/bpf_jit_disasm]
==>This dependency is currently installed via
==>core/binutils 2.41-3 [installed: 2.41-1]
==> usr/lib/libsframe.so
==>WARN: Following package may have an problem:
==>extra/bpf 6.3-2 (linux-tools) [installed]
==> usr/bin/bpf_jit_disasm
Trickiest part was stuffing the bash "passeddeps" array into awk and recursively processing the dependency chain only once.
Another difference I realized in hindsight is I'm not sure whether readelf reports missing libraries any differently than ones that are present.
readelf -d reads the ELF file (i.e. binary or shared library) and dumps its contents out in human readable form.
The library name strings "readelf -d -> (NEEDED)" dumps are stored in the ELF file. readelf doesn't interpret these strings in anyway.
Last edited by JATothrim (2023-08-07 11:57:44)
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
I don't get it. mpv runs and the dependency is satisfied.
depcheck /usr/bin/mpv
Unable to find [/usr/lib/libmujs.so] from the system. This library is needed to run [/usr/bin/mpv]
==>This dependency is currently installed via
==>extra/mujs 1.3.3-1 [installed]
==> usr/lib/libmujs.so
==>WARN: Following package may have an problem:
==>extra/mpv 1:0.36.0-1 [installed]
==> usr/bin/mpv
==> usr/share/bash-completion/completions/mpv
Offline
I don't get it. mpv runs and the dependency is satisfied.
depcheck /usr/bin/mpv Unable to find [/usr/lib/libmujs.so] from the system. This library is needed to run [/usr/bin/mpv] ==>This dependency is currently installed via ==>extra/mujs 1.3.3-1 [installed] ==> usr/lib/libmujs.so ==>WARN: Following package may have an problem: ==>extra/mpv 1:0.36.0-1 [installed] ==> usr/bin/mpv ==> usr/share/bash-completion/completions/mpv
Thanks for testing.
This looks like a bug:
The library was reported as "[/usr/lib/libmujs.so]" this looks like an hard coded library filename.
It should read just "[libmujs.so]" as the combined "</lib>/</usr/lib/libmujs.so>" filename obviously can't be found...
@yochananmarqos: I fixed the bug. Can you test again?
Side note:
I'm not sure exactly what the dynamic linker search paths are and how it discovers them?
Currently only hard coded search paths are "/lib", "/usr/lib32" and extra library paths are discovered from
the RPATH and RUNPATH info of the binaries+libraries.
If the script misses any of them false positive reports are possible...
ldd would not have this problem, because it is the dynamic linker.
So If the binary actually does run, it is an bogus result.
Last edited by JATothrim (2023-08-07 12:11:59)
If it ain't broken yet, some time passes and I'm doomed to learn its secrets.
Now it is half broken but twice as fast than before.
Offline
I see. Now there's no output for mpv.
Offline