#!/usr/bin/perl
# $Id: cfmv,v 1.3 2000/09/07 18:10:20 dmetz Exp $
# $crtd:  by  Derald Metzger  on  990630 $
# $cmnt:  Does rpm -V with filtering
#           Copyright (C) 1998 - 2000 Derald Metzger
#   This may be freely redistributed under the terms of the GNU GPL.
# $

############# 000401-dam. Needs reviewed for cfm-1

#  Load perl modules
use File::Basename;

# Id/set vars
$base = basename($0);
$cnt_opt = "-ql";      # Count files of pkgs
$dst_fil = "";
$err_cnt = 0;
$fil_cnt = 0;
($hnam) = (`hostname` =~ /(\w+).*/);
$hashpr = "##";
@pkgs = ();
#re_vfy                # RE for verify ops
$sdate = `date +%y%m%d`; chop $sdate;  # short date yymmdd
$vfy_opt = "-V";       # verify option

$usage="
NAME
  cfmv - cfm verify
SYNOPSIS
  cfmv [-f dst_file] { . | pkg_name [...] }
DESCR
  Cfmv tests installed files to verify their integrity. It outputs a
  list of those files which have been altered in some unacceptable
  way. Cfmv generates the file discrepancy list using \`rpm -V' then
  filters the output. The filter may be taylored to remove test
  conditions for individual files by modifying the appropiate section
  of /etc/cfm/cfm.cf.  Basically things that are identified as legitimate
  changes should be filtered and the remaining changes will be
  reported as errors.
OPTIONS
  -f dst_file  destination filename.
  .            do all installed package files
  pkg_name     do the files of pkg pkg_name
ALSO
  See also cfm(8), cfmd(8), cfmds, cfmh(8), cfmhs, cfmdb(8), cfmsr(8),
  cfmv(8), cfmvs, rcsintro(1), doc/cfm*/*
AUTHORS
           Copyright (c) 1998 - 2000  Derald Metzger 
  This file is part of the cfm pkg (GPL).
";

# Get the opts.
while( $ARGV[0] =~ /^-/ ) {
    $_ = shift;
    /^-f(?:$|(\S+$))/ && do {
        ($1 && ($_ = $1)) || ($_ = shift);
        $dst_fil = $_;
        next;
    };
    die "\n### $0: Invalid option: $_ $usage";
}

# Get the pkg names
@ARGV || die "\n### $0: insufficient args $usage";
if( $ARGV[0] eq "." ) { $vfy_opt = "-Va"; $cnt_opt = "-qla"; }
else { @pkgs = @ARGV; }

# Get the file count and conditionally open output file
$fil_cnt = `rpm $cnt_opt @pkgs | wc -l`; chomp $fil_cnt;
$dst_fil && ( open(RPMVOUT, ">$dst_fil") || die "### Can't open $dst_fil");

# Read in the config file and build the RE for excluding err lines
$data_flg = 0;     # 0 for header, 1 & 2 for cfmh, 3 for rpmv
$re_vfy = 'm;^$';  # Start the str, empty line reject; semicolon is delimiter
open(CFMCF, "/etc/cfm/cfm.cf") || die "### Bad open /etc/cfm/cfm.cf";
while(<CFMCF>) {
    /^#- section/ && do { $data_flg++; next; };
    /^#|^$/ && next;
    ($data_flg == 3) && do { $re_vfy = "$re_vfy|$_"; };
}
close CFMCF;
$re_vfy = "$re_vfy;ox";  # compile once, ignore whitespace/comments

# Run rpm -V and filter the output
open(RPMVF, "nice rpm $vfy_opt @pkgs |") || die "### rpm -V failed";
while(<RPMVF>) {
    eval $re_vfy && next;  # Exclude matching lines
    m%^\.\.\.\.\.[U.]\.\.   /dev/(.d.|scd)%  # Console control of cdrom
		&& "`ls -l /dev/cdrom | cut -d/ -f5`" == $1 && next;
    $err_cnt++;
    $dst_fil && do { print RPMVOUT; next; };
    print;
}
close RPMVF;

# Add summary
$dst_fil && do { write RPMVOUT;	close RPMVOUT; };
!$dst_fil && write;

##################  subroutines and formats  ##################
format =
=========================================================================
@< @<<<<< @<<<<<<<<< cfmv report:  chkd @>>>>>> files,  found @>>>>> errs
$hashpr $sdate  $hnam                    $fil_cnt             $err_cnt
.
format RPMVOUT =
=========================================================================
@< @<<<<< @<<<<<<<<< cfmv report:  chkd @>>>>>> files,  found @>>>>> errs
$hashpr $sdate  $hnam                    $fil_cnt             $err_cnt
.
