Dependency Discovery

From SlackWiki
Jump to: navigation, search

Introduction

"Slackware users typically prefer their method of manual dependency resolution, citing the level of system control it grants them." - as the ArchWiki says. This total control over the system is one of the main strength of the Slackware distribution.

If the administrator of the system knows every package on the system and ensures their every dependencies, then the system is stable, well usable. If the administrator installs a new, (until now) unknown application, then he/she needs to discover its dependencies via the attached README or documentations, or from starting the application (if something is not installed on the system, then the application won't start).

Dependency resolution at package installation

The dependency resolution can be performed at package installation, if we use a third party package manager, see Third_Party_Package_Managers. This is very easy, but we should use that third party package manager and maybe we don't want to do it just for a simple package installation. We would like a more Slackware like solution.

Dependency discovery as a separate task

We can discover the dependencies of our system in separate task using the 'ldd' command. This is not third party application, it is the part of our system.

We can scan the binaries in our PATH:

#!/bin/bash

ECHO=/usr/bin/echo
SED=/usr/bin/sed
FILE=/usr/bin/file
CUT=/usr/bin/cut
LDD=/usr/bin/ldd
GREP=/usr/bin/grep
AWK=/usr/bin/awk

for p in `$ECHO $PATH | $SED 's/:/ /g'`
do
    for f in $p/*
    do
        if [ 'ELF' == `$FILE -b $f | $CUT -d' ' -f1` ]; then
            if $LDD $f | $GREP -q 'not found'; then
                $ECHO "$f"
                $LDD $f | $GREP 'not found' | $AWK '{print "Not found:", $1}'
            fi
        fi
    done
done

Or, we can print the missing package names instead of the missing library names, so we have to install only the given packages mentioned by this script (I used the concatenated MANIFEST file of 'slackpkg' on Slackware64, this file list is more friendlier for scripting):

#!/bin/bash
# This is the concatenated MANIFEST file of slackpkg on Slackware64
MANIFEST=/var/lib/slackpkg/slackware64-filelist.gz

# Do not trust in any command in PATH, shell builtins, etc.
ECHO=/usr/bin/echo
PRINTF=/usr/bin/printf
CUT=/usr/bin/cut
SORT=/usr/bin/sort
GREP=/usr/bin/grep
ZGREP=/usr/bin/zgrep
SED=/usr/bin/sed
AWK=/usr/bin/awk
FILE=/usr/bin/file
LDD=/usr/bin/ldd
NULL=/dev/null

# Check all directories in PATH
for directory in `$ECHO $PATH | $SED 's/:/ /g'`
do
    # Check all binaries in PATH directories
    for binary in $directory/*
    do
        # If it is true ELF binary
        if [ 'ELF' == `$FILE -b $binary | $CUT -d' ' -f1` ]; then
            # Show the progress by printing of actual filename on standard error
            $PRINTF "%-70s\r" $binary >&2
            # Check the missing shared library dependencies
            $LDD $binary 2>$NULL | $GREP 'not found' | $AWK '{print $1}' | while read missing_lib
            do
                # Print the package name of the missing library
                $ZGREP $missing_lib $MANIFEST | $AWK '{print $1}'
            done
        fi
    done
    # Clear the progress info
    $PRINTF "%-80s\r" "" >&2
# Ignore the duplicated package names
done | $SORT -u

If we would like to scan the binaries of the PATH and the shared libraries of our system, then we need a deeper directory discovery:

#!/bin/bash                                                             

# This is the concatenated MANIFEST file of slackpkg on Slackware64
MANIFEST=/var/lib/slackpkg/slackware64-filelist.gz

# Do not trust in any command in PATH, shell builtins, etc.
SYSPATH=$PATH
PATH=/bin:/usr/bin:/usr/sbin
ECHO=/usr/bin/echo
PRINTF=/usr/bin/printf

# Check all directories in PATH and ld.so.conf
# If it is true ELF binary
find `$ECHO $SYSPATH | sed 's/:/ /g'` \
     `sed 's/\(\/.*\/.*\)\/.*/\1/' /etc/ld.so.conf | sort -u` \
     -perm -100 -a -type f \
     -exec sh -c 'filename="{}"; /usr/bin/echo -n "." >&2; \
                  [ "ELF" = `file -b $filename | cut -d" " -f1` ] && \
                  ldd $filename 2>/dev/null | fgrep "not found" \
                      | cut -d" " -f1' \; | while read missing_lib
do
    # Print the missing library and its package name
    $ECHO $missing_lib ": `zgrep $missing_lib $MANIFEST | cut -d" " -f1`"
done | sort -u

This small script will browse huge amount of directories and will scan a lot of ELF binaries, so it can run for a long time. There are more effective ways of the dependency discovery, this is only a very simple solution for a natural system administrator need. It demonstrates that a Slackware user does not need a package manager with dependency resolution, but even so can have a stable, well configured system.