Every distribution has a package manager and a whole lot of work goes into maintaining packages and correctly resolving their dependencies. This is a descriptive kind of dependency tracking.
The other day I had the idea of using a more "evidence based" method. Given a linked binary, you can find out what libraries it uses with ldd
. (This, however, will not account for any dynamic linking that happens during runtime.) More interestingly, perhaps, given a running process, you can figure out which files it using to run. There is lsof
, and if not, /proc/pid/maps
has that information too.
Such a list of files can then be fed to the package manager to find the packages which own them.
For instance, which package owns init
(on an Ubuntu system)?
$ findpkgs 1
upstart
What's needed to run ls
(on a Gentoo system)?
$ findpkgs ls
sys-apps/acl
sys-apps/attr
sys-apps/coreutils
sys-libs/glibc
What about a Python application like iotop
?
$ findpkgs `pgrep iotop`
dev-lang/python
dev-libs/openssl
sys-libs/glibc
sys-libs/ncurses
sys-libs/zlib
The query-package-manager-for-owner-of-file tries to figure out which package manager is used on the system in this order:
- paludis
- qfile
- equery
- dpkg
- rpm
To be honest I'm not really sure how useful this is, I just put it together since I figured out it could be done. It *can* answer the question: which packages are required to run this application? (Or to be more precise: to achieve this specific runtime state of the application.) So if you write an app, send it to a friend and he can't make it run, you could use findpkgs
to get a list of them he needs to install (provided he's on the same distro and all that).
# Author: Martin Matusiak <numerodix@gmail.com>
# Licensed under the GNU Public License, version 3
#
# <desc> Find packages by binary or process pid </desc>
#
# <usage>
# source this file in bash, then run `findpkgs`
# </usage>
function _findpkgfor() {
local file="$1";shift;
if which paludis &>/dev/null; then
paludis -o "$file" 2>/dev/null | grep '::installed' \
| sed "s/::installed//g" | tr -d ' '
elif which qfile &>/dev/null; then
qfile "$file" 2>/dev/null | awk '{print $1}'
elif which equery &>/dev/null; then
equery belongs "$file" 2>/dev/null | awk '{print $1}'
elif which dpkg &>/dev/null; then
dpkg -S "$file" 2>/dev/null | awk '{print $1}' | tr -d ':'
elif which rpm &>/dev/null; then
rpm -qf "$file" 2>/dev/null | grep -v "not owned"
else
echo "No known package manager found"
fi
}
function findpkgs() {
local arg="$1";shift;
if [ ! "$arg" ]; then
echo "Usage: findpkgs [ pid | /path/to/binary ]"
return
fi
local pid=
local arg_new=
local bin=
if echo "$arg" | grep "^[0-9]*$" &>/dev/null; then
pid="$arg"
else
arg_new=$(which "$arg" 2>/dev/null)
[ "$arg_new" ] && arg="$arg_new"
if ! echo "$arg" | grep '^/' &>/dev/null; then
echo "Can't find absolute path (or not a binary) for: $arg" >&2
return
fi
arg=$(readlink -f "$arg")
if ! file "$arg" | grep 'ELF' &>/dev/null; then
echo "Not a binary: $arg" >&2
return
fi
bin="$arg"
fi
local fst=
local fst_new=
local files=
if [ "$pid" ]; then
fst=$(ps aux \
| sed "s/^[^ ]* *//g" \
| grep "^$pid " \
| awk '{print $10}' \
| tr -d ':')
fst_new=$(which "$fst" 2>/dev/null)
[ "$fst_new" ] && fst="$fst_new"
if ! echo "$fst" | grep '^/' &>/dev/null; then
echo "Can't find absolute path for: $fst" >&2
unset fst
fi
if $(which lsof &>/dev/null); then
files=$(lsof \
| sed "s/^[^ ]* *//g" \
| grep "^$pid " \
| awk '{print $8}' \
| grep '^/' \
| sort \
| uniq)
else
files=$(cat "/proc/$pid/maps" \
| awk '{print $6}' \
| grep '^/' \
| sort \
| uniq)
fi
files="$fst $files"
for file in `echo $files`; do
_findpkgfor "$file"
done | sort | uniq
elif [ "$bin" ]; then
files=$(ldd "$bin" \
| awk '{print $3}' \
| grep '^/' \
| sort \
| uniq)
files="$bin $files"
for file in `echo $files`; do
_findpkgfor "$file"
done | sort | uniq
fi
}
[...] use findpkgs as an example here. The function is defined in a separate file and the file is source’d. But [...]