chksha1.pl will run under any UNIX.
Check integrity of commands on your command $PATH.
Usage: chksha1 [--check] [--sha1sum]
Initialize
% chksha1 > foo ; chksha1 original format
% chksha1 --sha1sum > foo ; sha1sum compatible format
Check Integrity
% chksha1 --check < foo ; chksha1 original format
% sha1sum -c < foo ; check by sha1sum command
- [2000/07/15] Open this page and start distribution.
Author: Hironobu SUZUKI
Contact E-mail address: hironobu @ h2np . net
Source Code:
#!/usr/bin/perl
#
# $Id: chksha1.pl,v 1.1 2005/11/24 07:50:28 hironobu Exp hironobu $
# Hironobu SUZUKI < hironobu @ h2np -dot- net >
# ChecK file SHA1 On the PATH.
# GPL General Public License 2
#
# Check integrity of commands on your command $PATH.
#
# Usage: chksha1 [--check] [--sha1sum]
#
# Initialize
# % chksha1 > foo ; chksha1 original format
# % chksha1 --sha1sum > foo ; sha1sum format
# Check Integrity
# % chksha1 --check < foo ; chksha1 original format
# % sha1sum -c < foo ; sha1sum format
#
# Help
# % sha1sum --help ; show help
require 'stat.pl';
use Digest::SHA1;
# Init Vars
$sha1sumcompatible="NO";
$checkflag="NO";
$output=STDOUT;
@checkdata="";
$dateofcheckdata="";
%hcheckdata=();
@currentdata="";
%hcurrentdata=();
$dateofcurrentdata="";
$printbuf="";
%dirnamehash=(); # dir name hash table
$MAXDEPTH=3;
##MAIN
get_option(@ARGV);
if ( $checkflag eq "YES" ) {
readCheckData();
}
onPathFiles();
if ( $checkflag eq "YES" ) {
compareTwoHashData();
}
###
#
# Subroutines
#
sub onPathFiles {
$p=$ENV{'PATH'};
@a=split(':',$p);
makeCheckSha1(@a);
if ( $sha1sumcompatible eq "NO" ) {
$str= "Date: ".scalar localtime()."\n";
printVal($str);
}
}
sub makeCheckSha1 {
foreach $i (@_) {
makeCheckDateFromFile($i,0);
}
}
sub makeCheckDateFromFile{
my ($fname,$depth)=@_;
my $i="";
my @f="";
if ( $depth > $MAXDEPTH ) {
return ;
}
if ( -d $fname ) {
if ( alreadyReadDirCheck($fname) < 1 ) {
# already read this directory (or NOT directory)
return "";
}
if ($fname ne "." and $fname ne ".." ) {
chdir($fname);
}
if ($fname ne "..") {
opendir (D,$fname) || return;
}
else {
return;
}
@f=readdir(D);
foreach $i (@f) {
if ($i eq "." or $i eq ".." ) {
next;
}
$flp=$fname."/".$i;
makeCheckDateFromFile($flp,$depth+1);
}
}
else {
if ( -x $fname ) {
fileStatAndSha1($fname);
}
}
}
sub fileStatAndSha1 {
my($fname)=@_;
my $str="";
my(@st) = stat($fname);
open(F,$fname) || return "";
my $sha1 = new Digest::SHA1;
$sha1->reset();
$sha1->addfile(F);
$str=$sha1->hexdigest();
close(F);
if ( $sha1sumcompatible eq "NO" ) {
printVal(@st[$ST_INO].":");
printVal(@st[$ST_SIZE].":");
printVal(@st[$ST_MODE].":");
printVal(@st[$ST_UID].":");
printVal(@st[$ST_GID].":");
printVal(@st[$ST_MTIME]." ");
}
printVal("$str $fname\n");
}
sub printVal {
my ($stval,$hashval,$filepath);
if ( $checkflag eq "YES" ) {
$printbuf=$printbuf."@_";
if ( $printbuf =~/\n/) {
if ( $printbuf =~ /^Date:/ ) {
$dateofcurrentdata=$printbuf;
chop $dateofcurrentdata;
}
else {
($stval,$hashval,$filepath)=split('\s+',$printbuf);
$hcurrentdata{$filepath}=$printbuf;
}
$printbuf="";
}
return;
}
print $output "@_";
}
sub get_option {
my @largs=@_;
my $larg="";
foreach $larg (@largs) {
if ( $larg =~ /--check/ ) {
$checkflag="YES";
$checkfile=STDIN;
}
elsif ( $larg =~ /--sha1sum/ ) {
$sha1sumcompatible="YES";
}
elsif ( $larg =~ /--help/ ) {
print "Check integrity of commands on your command \$PATH\n";
print " Usage: chksha1 [--check] [--sha1sum]\n";
print " Initialize\n";
print "\t% chksha1 > foo ; chksha1 original format\n";
print "\t% chksha1 --sha1sum > foo ; sha1sum compatible format\n";
print " Check Integrity\n";
print "\t% chksha1 --check < foo ; chksha1 original format\n";
print "\t% sha1sum -c < foo ; sha1sum compatible format\n";
exit(0);
}
}
}
sub readCheckData() {
my($stval,$hashval,$filepath);
while(<$checkfile>) {
chop;
if ( $_ =~ /^Date:/ ) {
$dateofcheckdata=$_;
last;
}
else {
($stval,$hashval,$filepath)=split('\s+',$_);
$hcheckdata{$filepath}=$_;
}
}
close($checkfile);
}
sub compareTwoHashData
{
#
# Del current entry first;
#
my $k=""; # filepath
my $l=""; # check data content
my $c=""; # current data content
my ($stval,$hashval,$filepath);
my ($oldstval,$oldhashval,$oldfilepath);
my ($inode,$fsize,$mode,$uid,$gid,$mtime);
my @keyentries;
# Debug print
$dateofcheckdata;
print " Old Data:\t$dateofcheckdata\n";
print "Current Data:\t$dateofcurrentdata\n";
@keyentries = keys %hcheckdata;
foreach $k (@keyentries) {
$l=$hcheckdata{$k};
$c=$hcurrentdata{$k};
($stval,$hashval,$filepath)=split('\s+',$c);
($oldstval,$oldhashval,$oldfilepath)=split('\s+',$l);
if ( ($l ne "" && $c ne "" ) &&
($stval ne $oldstval || $hashval ne $oldhashval)) {
# miss much
print "\nUnmatched: $filepath\n";
print " Hash(current): $hashval\n";
print " Hash (old): $oldhashval\n";
print " Stat(current): $stval\n";
print " Stat (old): $oldstval\n";
}
if ( $c ne "" ) {
$hcheckdata{$k}=""; # file was deleted and couldn't be found.
}
if ( $l ne "" ) {
$hcurrentdata{$k}=""; # file was found in current data.
}
}
# dump undeleted entry
@keyentries = keys %hcheckdata;
foreach $k (@keyentries) {
$l=$hcheckdata{$k};
if ( $l ne "") {
($oldstval,$oldhashval,$oldfilepath)=split('\s+',$l);
($inode,$fsize,$mode,$uid,$gid,$mtime)=split(':',$stval);
print "\nDeleted: $oldfilepath\n";
print " Hash: $oldhashval\n";
print " Stat: $inode $mode $uid $gid $mtime\n";
}
}
@keyentries = keys %hcurrentdata;
foreach $k (@keyentries) {
$c=$hcurrentdata{$k};
if ( $c ne "") {
($stval,$hashval,$filepath)=split('\s+',$c);
($inode,$mode,$uid,$gid,$mtime)=split(':',$stval);
print "\nCreated: $filepath\n";
print " Date: ".scalar localtime($mtime)."\n";
print " Hash: $hashval\n";
print " Stat: $inode $mode $uid $gid $mtime\n";
}
}
}
sub alreadyReadDirCheck
{
my($dirname)=@_;
my($dev,$inode);
if ( -d $dirname ) {
($dev,$inode)=stat($dirname);
if ( $dirnamehash{$inode} eq "" ) {
$dirnamehash{$inode}="yes";
return 1; # not read yet.
}
else {
return 0; # already read;
}
}
else {
return -1; # NOT directory
}
}