#!/bin/sh
# Package Checker
#
#
# This message presents a shell script which uses rpm to 
# check directories for what packages are installed and/or
# find "unpackaged" files.  
# 
# Why did I make it?  
# 
# Several reasons:
# 
# 1.  The SAG points out that there is no need to backup files that
# can be easily reinstalled from CD-ROMS or other media.  That
# sounds right to me.   But how do you know what you have installed?
# 
# rpm -qa will give you a listing of the entire system.  But often
# a problem arises because (a) a filesystem went south, or (b)
# you just did rpm * in /usr/bin, or other very local situations,
# where you want to only restore a part of your system.
# (Of course you can rpm -Va the entire system, but it is crude and slow
# to say the least. If you have recorded what is located in different
# directories, it should be easier to selectively rebuild them.).  
# 
# With this utility, you can make lists of what packages are
# stored in the directories that you are not backing up, so that
# you can have half a chance to try to reinstall without starting
# from scratch.
# 
# 2.  I have often wondered about "stray" files.   One that are
# not mentioned in packages.  They could be mine.  They could be
# from other sources (e.g., compiling rpms).  How to find them?
# (especially if one wants to package some of them up).
# This utility can do that.
# 
# 3.  Simple curiosity.  For example, what packages are installed
# under /usr/X11 directory tree.  This utility will tell you.
# 
# Are there other utilities like this?
# 
# As best as I can tell (i.e., from checking in http://www.rpm.org 
# from looking in the 442 pages of Maximum RPM (which does offer a 
# some good tricks, but not something like this), and a few random 
# searches of mailing lists, there does not appear to be anything 
# like this script that is publically available.
# 
# What does the output look like?
# 
# Here is a (default) sample from my COL 1.1 /bin
# 
# pkck /bin
# 
# *** Directory: /bin ***
# arch:                util-linux-2.5-21
# basename:            file /bin/basename is not owned by any package
# bash:                bash-1.14.7-2
# [ stuff deleted ]
# view:                vim-4.4-3
# vim:                 vim-4.4-3
# zcat:                gzip-1.2.4-4
# 
# There are switches to find only strays or make unique lists.  
# Here is an example of finding strays in my /bin 
# 
# pkck -s /bin
# 
# *** Directory: /bin ***
# file /bin/basename is not owned by any package
# file /bin/prep_use is not owned by any package
# file /bin/hilfe is not owned by any package
# file /bin/lisa is not owned by any package
# file /bin/lisa is not owned by any package
# file /bin/prep_use is not owned by any package
# file /bin/prep_use is not owned by any package
# file /bin/prep_use is not owned by any package
# file /bin/lisa is not owned by any package
# file /bin/lisa is not owned by any package
# 
# These examples only show one directory, but the script is recursive
# so if you enter:  pkck /usr  you will get the whole usr tree.
# 
# Here it is....I hope you will try it...just clip below the
# line and put it into an executable file (I call mine: pkck)
# ...and let me know what you think.
# 
# Cheers,
#   Seth
# ----------Clip here-----------------------------------------------------
#######################################################################
#
#			DESCRIPTION
#
#######################################################################

# A utility to automatically identify which rpm packages are
# installed in a directory and which files are not rpm-packaged

# Usage: pkck /directory [-s|-u|-U|-q|-o filename]

# Default Result from:  pkck /directory
# A list of all the files in the given directory (and
# its subdirectories), telling which package(s) it is found in
# as well as identifying files not in packages.

# Flags are optional.  
# -s will only identify "stray" (unpackaged) files by directory
# -u will give a unique listing of the packages used in a directory.
# -U will give a unique listing of the packages in directory and subdirectories.
# -q turns off the progress feedback
# -o filename allows you to specify where the output will go

#######################################################################
#
# License:  "VanityWare" := Public Domain + send me an email if you tried it.
#
#######################################################################
#
# ChangeLog:
#
# Version 1.0 
# 25 September 1997 Seth Chaiklin <seth@psy.aau.dk> 
#
#######################################################################
#
# BUGS || IMPROVEMENTS || MATTERS OF TASTE
#  1.  Could test for validity of supplied directories
#      As it is now, find will report the error, but process the
#      valid cases, so not a big problem.
#  2.  Does not test for overwriting output file (trivial to add)         
#  3.  If there are no files in a directory, then rpm complains
#       (trivial to add test if you want.)
#######################################################################

#  The "real" stuff starts here!

#######################################################################
#
#			CONFIGURATION
#

#####################################################################

#If you always want verbose, then any string will turn it on
VERBOSE=true		       # leave blank if you never want it

# Where to put the results 
#OUTPUTFILE=/dev/stderr        # sends to terminal
OUTPUTFILE=/tmp/pkck.$$        #Use absolute path!

RPM=/bin/rpm
LS=/bin/ls                    # color-ls won't do
PRINTF=/usr/bin/printf	      # found in sh-utils

############ SETUP ####################################################

# Start with default.  User can change with command line flags

type=default

# Get commandline flags

while getopts qsuUo:? flag ; do
   case $flag in
	q ) unset VERBOSE ;;
 	s ) type=stray ;;
 	u ) type=unique ;;
 	U ) type=Unique ;;
 	o ) if [ `echo $OPTARG | cut -c1 ` = / ] ; then
 	     	OUTPUTFILE="$OPTARG"
 	     else
 	   	OUTPUTFILE=`pwd`/$OPTARG
 	     fi
 	;;
 	* )  echo -e "\nUsage: $0 [options] directory directory...\n"
 		echo -e "Options:"
 		echo -e "\t[-o filename]   -- define filename for output "
 		echo -e "\t[-q]	-- turn off feedback"
 		echo -e "\t[-s]	-- find unpackaged files"
 		echo -e "\t[-u]	-- find packaged files by directory"
 		echo -e "\t[-U]	-- find packaged files across directories\n"
 	esac
	done

# Get directories to process
 
shift $(($OPTIND-1))
 
# A small sanity check -- need to have a start directory

if [   -z "$*"  ] ; then
	echo "No starting root directory given...aborting." 
 	exit 1
fi
 
 # Empty out the output file
>$OUTPUTFILE		

function dirchg {
     [ $VERBOSE ] && echo Changing to directory $1 ... 	#cosmetic
     echo -e "\n*** Directory: $i ***" >>$OUTPUTFILE 	#cosmetic
     cd $1						
}
 
############ PROCESSING ####################################################

case $type in 
# List files not found in packages (i.e., strays)
  stray )
   for i in `find $* -type d -mount` ; do 
    dirchg $i
    $RPM -qf `$LS -A` >/dev/null 2>>  $OUTPUTFILE 
   done
;;

#List found packages WITH directory info
  unique )
   for i in `find $* -type d -mount` ; do 
    dirchg $i
    $LS -d1 $i/* 2>/dev/null | $RPM -qF  2>/dev/null |sort|uniq >>  $OUTPUTFILE
   done
;;

#List found packages WITHOUT directory info
   Unique )
    [ $VERBOSE ] && echo Making list of unique packages...	#cosmetic
    echo -e "*** Unique packages in $* and subdirectories ***" >> $OUTPUTFILE
    for i in `find $* -type d -mount` ; do 
      [ $VERBOSE ] && echo Changing to directory $i ... >/dev/stderr
      $LS -d1 $i/* 2>/dev/null | $RPM -qF 2>/dev/null
    done | sort | uniq >> $OUTPUTFILE
;;

# DEFAULT
# Full listing of all files found and 
# their package or non-package status
*)
    for i in `find $* -type d -mount` ; do 
	dirchg $i
 	for j in `$LS -A` ; do
		$PRINTF %-21s $j: >>  $OUTPUTFILE 2>&1
 	$RPM -qf $j >>  $OUTPUTFILE 2>&1
 	done
      done
esac
