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 }
Download this code: findpkgs.sh

[...] use findpkgs as an example here. The function is defined in a separate file and the file is source’d. But [...]