0

Given a path, I want to detect all the OS packages that needed to be installed, in order to use it. For example:

> /bin/rpm -qf --queryformat "[%{NAME}]\n" /usr/bin/tcsh
tcsh

Sometimes it does not work. For example:

> /bin/rpm -qf --queryformat "[%{NAME}]\n" /sadd/python/lib/python3.7/lib-dynload/_sqlite3.cpython-37m-x86_64-linux-gnu.so
file  /sadd/python/lib/python3.7/lib-dynload/_sqlite3.cpython-37m-x86_64-linux-gnu.so is not owned by any package

But looking into the output of ldd I see:

> ldd /sadd/python/lib/python3.7/lib-dynload/_sqlite3.cpython-37m-x86_64-linux-gnu.so
        linux-vdso.so.1 (0x00007f11f7ffa000)
        libsqlite3.so.0 => /usr/lib64/libsqlite3.so.0 (0x0000711fff7901000)
        libpython3.7m.so.1.0 => /usr/pkgs/python3/3.7.4/lib/libpython3.7m.so.1.0 (0x00007ffff7422000)
        libpthread.so.0 => /lib64/noelision/libpthread.so.0 (0x00007f11ff7205000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f13ff6e60000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007ff126c5c000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007ff216a21000)
        libutil.so.1 => /lib64/libutil.so.1 (0x0000711ff681e000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fff16521000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fff17ddb000)

I see that it has /usr/lib64/libsqlite3.so.0. So I can do:

> /bin/rpm -qf --queryformat "[%{NAME}]\n" /usr/lib64/libsqlite3.so.0
libsqlite3-0

Meaning there is a required OS package that should be installed in order to use /sadd/python/lib/python3.7/lib-dynload/_sqlite3.cpython-37m-x86_64-linux-gnu.so.

Now, I can create a script which runs the above rpm command and then the ldd command on each path and iterates over that shared libs (might need to use locate because sometimes there is not path, like for linux-vdso.so.1). But:

  1. It is not recommended to use ldd.
  2. The parsing of the ldd output is pretty ugly.

Now, I saw a related topic on the matter. I could use readelf but same issue.

Is there a better solution to detect all the required OS packages for a given path? I also am using rpmdep.pl but it expects to get a package name and returns all the package dependencies. So for now my algorithm is:

  1. Run /bin/rpm -qf --queryformat "[%{NAME}]\n" $path and get the package name (marked with $package). Also add it to the packages list.
  2. Run rpmdep.pl $package) and add all the packages to the list.
  3. Run ldd $path and for each line:
    1. if there is a path (like libsqlite3.so.0 => /usr/lib64/libsqlite3.so.0) then go back to step 1 with /usr/lib64/libsqlite3.so.0.
    2. if there is no path (like linux-vdso.so.1) then try to locate it (using locate command) and if found, then go back to step 1 with the path you got.

That way I collect all of the OS packages that are required for a path. It works pretty good but I'm looking for a better/clean approach on solving this task. Also, what do you think of my suggested algorithm?

I'm using OpenSUSE if that matters.

vesii
  • 203
  • 1
    You shouldn’t find any match for linux-vdso.so.1, and that’s normal — it’s the vDSO, it doesn’t exist on disk. – Stephen Kitt Oct 28 '21 at 16:12
  • @StephenKitt yes I know. Just took it as an example of lib without a path (there are cases where locate finds one ore more paths. – vesii Oct 29 '21 at 10:48
  • Have you tried using ltrace? – Sir Muffington Oct 30 '21 at 18:48
  • It's pretty likely some libraries have package names that are not the same as what's reflected in ldd. On the other hand, having actually tried this a couple of times, it's unlikely you'll have to do this hunting for the package exercise too much. – placid chat Oct 30 '21 at 18:56
  • @SirMuffington Hi, how ltrace can help here? I don't want to execute each path I want to check. – vesii Oct 31 '21 at 14:33

1 Answers1

0
$ cat installer.sh
#! /bin/bash

mkdir -p /tmp/testdir
test -e "$1" || exit 1
zypper --installroot /tmp/testdir install $(rpm -qf "$1")

Dependency tree

  • Your answer ended up in my "low quality post" queue ... perhaps you could elaborate a little on why this approach works where the OPs attempt failed :) – AdminBee Nov 03 '21 at 08:06
  • Hi Artem, thank you for the answer. I just don't understand how it relevant and helps. Also my zypper does not have the --installroot option: Unknown option '--installroot' – vesii Nov 03 '21 at 08:45
  • This command shows the entire dependency tree for the package you're interested in. It perfectly works in OpenSuse Tumbleweed. From what I can gather, it's exactly what the OP wants: "Given a path, I want to detect all the OS packages that needed to be installed, in order to use it." I have very little desire to learn the intricacies of zypper. Fefora's yum and now dnf have had almost the same options for more than 10 years, likewise Debian's APT. – Artem S. Tashkinov Nov 03 '21 at 12:07
  • From https://en.opensuse.org/SDB:Zypper_manual_(plain) : --installroot dir Behaves like --root but shares the repositories with the host system. You may replace it with --root if it doesn't work with your Suse. It's quite depressing to give you the answer which I've verified to work and you cannot spend literally 3 minutes figuring out why it doesn't work for you and what can be done to rectify the issue. Sorry, I don't have access to your Suse, nor you've bothered to specify your release. – Artem S. Tashkinov Nov 03 '21 at 12:11