#!/usr/bin/perl -w #use strict; use Getopt::Std; my %opts; my ($all,$files,$sizeopt,$perms,$provides) = (0,0,0,0,0); my ($oldrpms,$newrpms); #opts -a all -f files -s file size -p file perms -l dynamic linkages -r requires/provides -o old tree -n new tree getopts('afsplro:n:',\%opts); if(defined($opts{a})){ $all = 1; print "all\n";}; if(defined($opts{f})){ $files = 1; print "files\n"; }; if(defined($opts{s})){ $sizeopt = 1; print "size\n";}; if(defined($opts{p})){ $perms = 1; print "perms\n";}; if(defined($opts{l})){ $links = 1; print "links\n";}; if(defined($opts{r})){ $provides = 1; print "provides\n"; }; if(defined($opts{o})){ if (-d $opts{o}) { $oldrpms = $opts{o}; print "old $oldrpms\n"; }; }; if(defined($opts{n})){ if (-d $opts{n}) { $newrpms = $opts{n}; print "new $newrpms\n"; }; }; if(! ($all or $files or $sizeopt or $links or $perms or $provides)){ print "$0\nOptions:\n-a\tall\n-f\tfiles\n-s\tfile size\n-p\tfile perms\n-l\tdynamic linkages\n-r\trequires/provides\n-o\t old tree\n-n\t new tree\n"; exit; } #print %opts; #print "\n"; if ($ARGV[0]){ print "Unknown extra argument: "; foreach (@ARGV) { print "$_ "; } print "\n"; print "$0\nOptions:\n-a\tall\n-f\tfiles\n-s\tfile size\n-p\tfile perms\n-l\tdynamic linkages\n-r\trequires/provides\n-o\t old tree\n-n\t new tree\n"; exit; } #print @oldrpms."\n"; #print @newrpms."\n"; if(!$oldrpms or !$newrpms) { exit; } #Point these to a directory of RH and rebuilt (aka new) RPMS #$WB_RPMS = "/home/test/b8"; #$RH_RPMS = "/home/test/new"; #my $WB_RPMS = "/centos-3/build8/i386/RedHat/RPMS"; #my $RH_RPMS = "/centos-3/build6/i386/RedHat/RPMS"; # Size difference to trigger error, .1 = plus/minus 10% my $SizeError=.10; # Working directories # Careful where these point, they get a "rm -rf" cleaning! my $oldTMP="/tmp/old-$$"; my $newTMP="/tmp/new-$$"; my $rpm; opendir(DIR,$newrpms); my @allrpms= grep (/rpm$/, readdir(DIR) ); closedir(DIR); foreach $rpm (sort @allrpms){ my $rpmold=$rpm; my $rpmoldf=$rpm; if (! (-e "$oldrpms/$rpm") ) { #try without .centos.x my $fname = $rpm; $fname =~ s/centos\.[0-9]//; print $fname; if (! (-e "$oldrpms/$fname")) { print "\nNo equivalent original for $rpm \t trying glob\n"; $fname= $rpm; $fname =~ s/(.*)-.*-.*/$1-/; # print "fname is $fname\n"; my $found = 0; #print "trying $oldrpms/$fname*\n"; my @globmatch = glob("$oldrpms/$fname*"); while ($rpmold = shift @globmatch) { #while($rpmold = glob("$oldrpms/$fname*")){ my $try = $rpmold; # print "\nglob got $try\n "; $try =~ s/.*\///; $try =~ s/(.*)-.*-.*/$1-/; if($try eq $fname) { #this is the one $rpmoldf = $rpmold; $rpmoldf =~ s/.*\///; $found = 1; while($rpmold = glob("$oldrpms/$fname*")){}; last; } } if(!$found) { next; } } } if($rpm =~ /^kernel/) { next; } if($rpm eq $rpmoldf) { # only doing difficult ones # next; } else { print "$rpm >> $rpmoldf\n"; } if($all) { printf ("%-50s\t", $rpm); } $fileproblems=0; $libproblems=0; if ($all or $files or $sizeopt or $perms or $links){ # Initialize %allfiles=(); %oldhash=(); %newhash=(); system("rm -rf $oldTMP;mkdir $oldTMP"); system("rm -rf $newTMP;mkdir $newTMP"); # Extract RPMS system("cd $oldTMP/; rpm2cpio $oldrpms/$rpmoldf | cpio -id --no-absolute-filenames --quiet"); system("cd $newTMP/; rpm2cpio $newrpms/$rpm | cpio -id --no-absolute-filenames --quiet"); # Parse name/size info @oldnamesize=`cd $oldTMP/; find ./ -printf "%p:_:%s:_:%U:_:%G:_:%04m:_:\n"`; @newnamesize=`cd $newTMP/; find ./ -printf "%p:_:%s:_:%U:_:%G:_:%04m:_:\n"`; for ($i=0;$i<@oldnamesize;$i++){ ($file,$size,$uid,$gid,$perms)=split(/:_:/,$oldnamesize[$i]); #print "old: $file,$size,$uid,$gid,$perms\n"; $oldhash{"$file"}=$size; $olduid{"$file"}=$uid; $oldgid{"$file"}=$gid; $oldperms{"$file"}=$perms; $allfiles{"$file"}=1; } for ($i=0;$i<@newnamesize;$i++){ ($file,$size,$uid,$gid,$perms)=split(/:_:/,$newnamesize[$i]); #print "new: $file,$size,$uid,$gid,$perms\n"; $newhash{"$file"}=$size; $newuid{"$file"}=$uid; $newgid{"$file"}=$gid; $newperms{"$file"}=$perms; $allfiles{"$file"}=1; } if($all or $files or $sizeopt) { # Print and tag file errors if appropraite foreach $file (keys %allfiles){ if (!(exists $oldhash{"$file"})){ if(!$fileproblems){printf ("%-50s\t", $rpm);}; print "\n\tPackage contains extra file: $file"; $fileproblems=1; } elsif (!(exists $newhash{"$file"})){ if(!$fileproblems){printf ("%-50s\t", $rpm);}; print "\n\tPackage is missing file: $file"; $fileproblems=1; } else { if ($oldhash{"$file"}>0){ $ratio=($newhash{"$file"})/($oldhash{"$file"})} else{ $ratio=1-$newhash{"$file"}; # Negative ratios indicate filesize vs. zero in RedHat } if($sizeopt){ print "size: $sizeopt\n"; if (($ratio-1)*($ratio-1)>($SizeError*$SizeError)) { if(!$fileproblems){printf ("%-50s\t", $rpm);}; printf("\n\tSize Ratio: %3.2f on file:%s",$ratio,$file); $fileproblems=1; }; } } if($all or $perms) { if (!$fileproblems){ if($olduid{"$file"} ne $newuid{"$file"}) { printf ("%-50s\t", $rpm); printf("\n\tUid Diff $olduid{\"$file\"} : $newuid{\"$file\"} on $file"); $fileproblems=1; } if ($oldgid{"$file"} ne $newgid{"$file"}) { printf ("%-50s\t", $rpm); printf("\n\tGid Diff $oldgid{\"$file\"} : $newgid{\"$file\"} on $file"); $fileproblems=1; } if ($oldperms{"$file"} ne $newperms{"$file"}) { printf ("%-50s\t", $rpm); printf("\n\tPerms Diff $oldperms{\"$file\"} : $newperms{\"$file\"} on $file"); $fileproblems=1; } } } } } if($all or $links) { # Select executable files @oldexec=`cd $oldTMP/; find ./ -perm +111 -type f -print`; # Check library dependencies foreach $executable (@oldexec) { chop $executable; # Move on if no equivalent binary exists in rebuild if (! (-e "$newTMP/$executable") ) {next;} # Get shared libs @oldlibs=`ldd $oldTMP/$executable`; @newlibs=`ldd $newTMP/$executable`; # Clean up ldd output $oldlibline=join('',(sort @oldlibs)); $newlibline=join('',(sort @newlibs)); $oldlibline=~ s/=>(.*)(\n)/\n/g; $oldlibline=~ s/(\s+)/ /g; $newlibline=~ s/=>(.*)(\n)/\n/g; $newlibline=~ s/(\s+)/ /g; @oldlibs=split(/ /,$oldlibline); @newlibs=split(/ /,$newlibline); # Print and tag library errors foreach $lib (@oldlibs){ $searchpat=$lib; $searchpat =~ s/\+/\\\+/g; $searchpat =~ s/\./\\\./g; unless ($newlibline =~ (/$searchpat/)){ if(!$libproblems and !$fileproblems){printf ("%-50s\t", $rpm);}; print "\n\tMissing link in $executable:\t$lib";$libproblems=1; } } foreach $lib (@newlibs){ $searchpat=$lib; $searchpat =~ s/\+/\\\+/g; $searchpat =~ s/\./\\\./g; unless ($oldlibline =~ (/$searchpat/)){ if(!$libproblems and !$fileproblems){printf ("%-50s\t", $rpm);}; print "\n\tExtra link in $executable:\t$lib";$libproblems=1; } } } } } if($all or $provides) { # sort out provides and requires @oldrequires = `rpm -qp --requires $newrpms/$rpm`; @newrequires = `rpm -qp --requires $oldrpms/$rpmoldf`; while ($oldrequire = shift(@oldrequires)) { if($newrequire = shift(@newrequires)) { chomp($oldrequire); chomp($newrequire); # print "$oldrequire : $newrequire\n"; if ($oldrequire gt $newrequire) { # extra one in newrequire if(!$fileproblems and !$libproblems and !$fileproblems){printf ("%-50s\t", $rpm);}; print "\n\tExtra require $newrequire";$fileproblems=1; unshift(@oldrequires,$oldrequire); } elsif($oldrequire lt $newrequire) { # one missing in newrequire if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tMissing require $oldrequire";$fileproblems=1; unshift(@newrequires,$newrequire); } } else { # end of new array if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tMissing require $oldrequire";$fileproblems=1; } } if(shift(@newrequires)){ # extra in the new array if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tExtra require $newrequire";$fileproblems=1; } @oldprovides = `rpm -qp --provides $newrpms/$rpm`; @newprovides = `rpm -qp --provides $oldrpms/$rpmoldf`; while ($oldprovide = shift(@oldprovides)) { if($newprovide = shift(@newprovides)) { chomp($oldprovide); chomp($newprovide); # print "$oldprovide : $newprovide\n"; if ($oldprovide gt $newprovide) { # extra one in newprovide if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tExtra provide $newprovide";$fileproblems=1; unshift(@oldprovides,$oldprovide); } elsif($oldprovide lt $newprovide) { # one missing in newprovide if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tMissing provide $oldprovide";$fileproblems=1; unshift(@newprovides,$newprovide); } } else { # end of new array if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tMissing provide $oldprovide";$fileproblems=1; } } if(shift(@newprovides)){ # extra in the new array if(!$fileproblems and !$libproblems){printf ("%-50s\t", $rpm);}; print "\n\tExtra provide $newprovide";$fileproblems=1; } } if ($fileproblems || $libproblems) { print "\n";} else { if($all) { print "MATCH\n"; }; } }