#!/bin/bash
# missing_libs.sh
# created and copyrighted: 26 Feb 11
#
# author: Evsiz (evsiz@this-voice.org)
# The author releases this file under the GNU GPL
# license. See GNU's COPYING file for specifics.

# This script is a reduction/fork of Sasha Alexandr's orphans.sh. I have
# reduced the script from a four-phase monster to a mere one-phase system
# hog. (The original would mount my old box and hump it for two and a half
# hours.) If something doesn't work, don't bother Sasha about this script.
# Use the email above and bother me.

# Original license:
# Author: Sasha Alexandr <crawlingwithsnakes at hush dot com>
# Created: March 2010
# This script is provided with ABSOLUTELY NO WARRANTY in the hope
# that you will find it useful and/or entertaining.
# While the script does not change your system in any way
# the author takes no responsibility for how you use it, or how you
# might use the results produced by it. Use at own risk.
# You may modify or redistribute this program as you like.

version () {
 VERSION='Version 14Apr11'
 echo "$VERSION"
}


check_permissions () {
# Check permissions (are we root?)
if [ "$(id -u)" != '0' ]; then
  echo "Please su to root or use sudo to run this script. Exiting now."
  exit 1
fi
}


setup () {

 LDCONFIG=$(which ldconfig)

# put the results in this file 
 RESULT=missing_libs.`date +%d%b%y-%H%M%S`

# create fresh output file:
 echo
 echo "## missing_libs.sh for Slackware - $(version)"| tee "$RESULT"
 echo "## Executed: $(date)" | tee -a "$RESULT"
 echo "## Results will be logged to: $RESULT"
 echo "## ##########################################" >> "$RESULT"

 if [ "$SKIP" != "true" ]; then
    echo "## Updating slocate database ..."
    updatedb
 else
    echo "## Skipping the update of slocate database"
 fi   

 echo -n "## Creating lib database "
 LIB64DIRS=$( find / -type d -name 'lib64' 2>/dev/null | sed \
  -e '/^\/boot\/initrd-tree\/.*$/d' \
  -e '/^\/mnt\|tmp\|media\/.*$/d' \
  -e '/^\/usr\/src\/.*$/d' \
  -e '/^\/usr\/source\/.*$/d' )
 printf "."

 LIB32DIRS=$( find / -type d -name 'lib' 2>/dev/null | sed \
  -e '/^\/boot\/initrd-tree\/.*$/d' \
  -e '/^\/mnt\|tmp\|media\/.*$/d' \
  -e '/^\/usr\/src\/.*$/d' \
  -e '/^\/usr\/source\/.*$/d' \
  -e '/^\/usr\/libexec\/.*$/d' \
  -e '/^\/usr\/doc\/.*$/d' \
  -e '/^\/lib\/modules\/.*$/d' \
  -e '/^\/var\/cache\/.*$/d' \
  -e '/\/lib64\/.*$/d' )
 printf "."

 LIBEXECDIRS=$( find / -type d -name 'libexec' 2>/dev/null )
echo "."

 BINDIRS=$( find / -type d -name 'bin' -or -name 'sbin' 2>/dev/null | sed \
  -e '/^\/mnt\|tmp\|media\/.*$/d' \
  -e '/^\/usr\/src\/.*$/d' \
  -e '/^\/boot\/initrd-tree\/.*$/d' \
  -e '/^\/usr\/source\/.*$/d' )

}

count_packages () {
 echo -n "## Counting installed packages: " 
 NUMPKGS=`ls -1 /var/log/packages | wc -l`
 echo "$NUMPKGS" 
}

dependency () {
# Checks for missing dependencies of installed binaries and other libs on the system.
# The --full mode checks every lib & bin dir it can find on the system
# instead of just the /bin dirs. Might be overkill - you decide.
echo "## Checking for missing dependencies of installed libs/binaries." 

DIRCOUNT=$((1)); ITEMINCR=$((0))
ALLDIRS="$BINDIRS
$LIB64DIRS
$LIB32DIRS
$LIBEXECDIRS"
NUMDIRS=$(echo "$ALLDIRS" | wc -l)

echo "$ALLDIRS" | while read DIR; do
  if [ "$DIR" ] && [ -d "$DIR" ]; then
    ITEMCOUNT=$(find "$DIR" -type f | sort | uniq | wc -l)
    LASTFILE=""
    for FILE in $(find "$DIR" -type f | sort | uniq); do

      ITEMINCR=$((ITEMINCR+1))

      # visual progress display:
      DIRPROGRESS="$DIRCOUNT/$NUMDIRS"; ITEMPROGRESS="$((ITEMINCR*100/ITEMCOUNT))"
      printf %b "\r## Path: $DIRPROGRESS  Done: $ITEMPROGRESS%  "

      if [ -x $FILE ]; then
        DEPS=$(ldd "$FILE" 2>/dev/null | grep 'not found' | sort | uniq | awk '{print $1}')
        for i in $DEPS; do
          found=`locate $i`
          if [ "$found" == "" ]; then
            if [ "$FILE" != "$LASTFILE" ]; then
              echo "Missing dependencies for: $FILE" >> "$RESULT"
              LASTFILE=$FILE
            fi
            echo "$i" >> "$RESULT"
          fi 
        done
      fi
      
   done
  fi
  DIRCOUNT=$((DIRCOUNT+1)); ITEMINCR=$((0))
done

printf %b "\r## Paths: $NUMDIRS/$NUMDIRS  Done.          \n"

}

summary () {
  echo "
## SUMMARY: missing libs
" >> $RESULT
  SMRY=`cat $RESULT | awk '$0 !~ /^M|^#/ { print }' | sort | uniq`
  for s in $SMRY; do
    echo $s >> $RESULT
  done
}


help () {
cat << END

 # USAGE: missing_libs.sh [option]

 -h|-?|--help ( shows this help info you are reading right now )
 -v|--version ( show which version of this script you have )
              ( identify missing library files for installed pkgs )
 -s           ( identify missing library files but skip updatedb)

END
}

# script entry point:
LANG=C
export LANG
LC_ALL=C
export LC_ALL

case "$1" in

 --version|-v) version && exit 0 ;;

 --help|-h|-\?) help && exit 0 ;;

 *)
    if [ "$1" == "-s" ]; then
    	SKIP="true"
    fi	
    check_permissions
    setup
    count_packages
    dependency
    summary
 ;;

esac
