#!/bin/sh
#
# chkpgkhealth
# check package content for installed packages
# does check for existence of files and md5 checksum
# Author: Volker Werth <volker@vwsoft.com>
# License: take it or leave it - use on your own risk
#

# tuneables:
_CHKQUIET=N
_CHKVERB=N
_CHKMVERB=N
_CHKMD5=Y
_CHKUID=Y


check_pkg()
{
# if "$pfile" contains a string which contains an asterisk, be sure to
# expect sh bombing error messages - not quite sure how to deal with these
# strings; there are a few packages with asterisk in it's filenames
PKGPATH=${1}

if [ ! -d "${PKGPATH}" ] ; then
  return
fi
if [ ! -f ${PKGPATH}/'+CONTENTS' ] ; then
  if [ ${_CHKQUIET} != Y ] ; then
    echo "${PKGPATH}: no +CONTENTS file"
  fi
  return
fi

ppkg=""
ppath=""
pfile=""
pmd5=""
ptold=N

cat ${PKGPATH}/'+CONTENTS' | while `read line`
do
  case ${line} in
    "@cwd "*)
	set ${line}
	if [ -n "${2}" ] ; then
	  ppath=${2}
	fi
	;;
    "@comment MD5"*)
	if [ -f "${ppath}/${pfile}" -a ${_CHKMD5} = Y ] ; then
	  oIFS=${IFS}
	  IFS=" :"
	  set ${line}
	  IFS=${oIFS}
	  pmd5=${3}
	  if [ -L "${ppath}/${pfile}" ] ; then
	    cmd5=`readlink -n "${ppath}/${pfile}" | md5 -q`
	  else
	    if [ -r "${ppath}/${pfile}" ] ; then
	      cmd5=`md5 -q "${ppath}/${pfile}"`
	    else
	      cmd5="ENOPERM"
	    fi
	  fi
	  if [ "${pmd5}" != "${cmd5}" ] ; then
		if [ ${ptold} != Y ] ; then
		  # in quiet mode, tell pkg name
		  echo "port: ${ppkg}"
		  ptold=Y
		fi
		if [ "${_CHKVERB}" = N ] ; then
		  if [ "${cmd5}" = "ENOPERM" ] ; then
		    echo " ERRPERM ${pfile}"
		  else
		    echo " ERRMD5 ${pfile}"
		  fi
		else
		  echo " ERRMD5 ${pfile} ${pmd5} ${cmd5}"
		fi
	  fi
	fi
	;;
    "@name "*)
	set ${line}
	ppkg=${2}
	if [ ${_CHKQUIET} = N ] ; then
	  echo "port: ${ppkg}"
	  ptold=Y
	fi
	;;
    [a-zA-Z0-9]*)
	pfile="${line}"
	if [ "${_CHKMVERB}" = Y ] ; then
	  echo " file: ${ppath}/${pfile}"
	fi
	if [ ! -e "${ppath}/${pfile}" ] ; then
		if [ ${ptold} != Y ] ; then
		  # in quiet mode, tell pkg name
		  echo "port: ${ppkg}"
		  ptold=Y
		fi
		echo " ERRNOFILE ${ppath}/${pfile}"
	fi
	;;
  esac

done
}

while getopts "qmvfhu" PAR
do
  case ${PAR} in
    q)	_CHKQUIET=Y ;;
    m)	_CHKMD5=N ;;
    v)	if [ ${_CHKVERB} = Y ] ; then
	  _CHKMVERB=Y
	fi
	_CHKVERB=Y ;;
    u)	_CHKUID=N ;;
    h|?)
	echo " ${0} -[qmvfh]"
	echo "    where"
	echo "   -q	be quiet (suppress some noisy output)"
	echo "		ie, do not display package names while scanning"
	echo "   -m	DO NOT do (time consuming) md5 checksum validation" 
	echo "   -v	be verbose"
	echo "		display md5 sums for failing md5's"
	echo "   -vv	be more verbose"
	echo "		display all file names while checking"
	echo "   -u	run without being root (expect file permission errors)"
	echo "   -h	help (this screen)"
	exit 0
	;;
    *)	echo "wrong option" ; exit 1 ;;
  esac
done

if [ ${_CHKQUIET} != Y ] ; then
  echo "--- ${0} ---"
  echo "- checking package health..."
fi

if [ `id -u` -ne 0 ] ; then
  if [ ${_CHKUID} != N ] ; then
    # oops, we're just a regular user
    # if not running as root, we will most likely get 
    # file permission errors while scanning for files and md5's
    echo "${0} needs to run as root"
    echo "if you know what you're doing, use '-u' parameter"
    exit 1
  else
    if [ ${_CHKQUIET} != Y ] ; then
      echo "- not UID root - expect file permission errors"
    fi
  fi
fi

# this may bomb with "argument list too long" some day...
for p in /var/db/pkg/*
do
  check_pkg ${p}
done

