diff -r 35a0ea276176 -r c0a522905faf bin/imager.check --- a/bin/imager.check Tue Aug 16 16:04:02 2011 +0200 +++ b/bin/imager.check Tue Aug 16 16:44:55 2011 +0200 @@ -7,20 +7,24 @@ use Hash::Util qw(lock_keys); use File::Find; use File::Temp; -use DB_File; +use Digest::MD5 qw(md5_hex); use File::Basename; use autodie qw(:all); use Cwd qw(abs_path); +use IO::Compress::Gzip qw(&gzip $GzipError Z_BEST_SPEED); +use IO::Uncompress::Gunzip qw(&gunzip $GunzipError); use Getopt::Long; +use constant CIPHER => "aes-128-cbc"; sub get_block_list; sub purge_unused; sub check_images; my %o = ( - yes => undef, - verbose => 1, - check => undef, + yes => undef, + verbose => 1, + checksum => undef, + pass => undef, ); lock_keys(%o); @@ -29,7 +33,8 @@ GetOptions( "y|yes!" => \$o{yes}, "v|verbose!" => \$o{verbose}, - "c|check" => \$o{check}, + "c|checksum" => \$o{checksum}, + "p|pass" => \$o{pass}, "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) }, "m|man" => sub { pod2usage( @@ -45,8 +50,8 @@ and @ARGV or pod2usage; my $dir = shift; - - while (1) { + + for (my $pass = 1 ; 1 ; ++$pass) { my %block = get_block_list($dir); verbose("# reading index files"); @@ -56,10 +61,11 @@ . (grep !/^\.idx$/ => keys(%block)) . " blocks"); - purge_unused($dir => %block); - check_images($dir => %block) and last; + my $subpass = 0; + purge_unused($pass => ++$subpass, $dir => %block); + check_images($pass => ++$subpass, $dir => %block) and last; - verbose("# STARTING OVER!"); + verbose("# STARTING OVER!"); } } @@ -93,11 +99,10 @@ } sub purge_unused { - my ($dir, %block) = @_; + my ($pass, $subpass, $dir, %block) = @_; my ($total, $done, $t0); - state $subpass = -1; - verbose("# pass 1.@{[++$subpass]} - checking for unused blocks"); + verbose("# pass $pass.$subpass - checking for unused blocks"); verbose("# estimating file count"); # calculate the number of files we expect @@ -120,7 +125,7 @@ return alarm 1 if not $done; my $speed = $done / (time - $t0 + 1); verbose sprintf - "# pass 1.$subpass done %5.1f%% | %25s (%*d of %d blocks)", + "# pass $pass.$subpass done %5.1f%% | %25s (%*d of %d blocks)", 100 * ($done / $total), scalar(localtime $t0 + $total / $speed), length($total) => $done, $total; @@ -182,21 +187,20 @@ } sub check_images { - my ($dir, %block) = @_; + my ($pass, $subpass, $dir, %block) = @_; my $total = grep { $_ ne "" } keys(%block); my $done = 0; my $t0 = time; - state $subpass = -1; - verbose("# pass 2.@{[++$subpass]} - checking image completeness"); + verbose("# pass $pass.$subpass - checking image completeness"); # progress local $SIG{ALRM} = sub { return alarm 1 if not $done; my $speed = $done / (time - $t0 + 1); verbose sprintf - "# pass 2.$subpass done %5.1f%% | %25s (%*d of %d blocks)", + "# pass $pass.$subpass done %5.1f%% | %25s (%*d of %d blocks)", 100 * $done / $total, scalar(localtime $t0 + $total / $speed), length($total) => $done, $total; @@ -210,14 +214,43 @@ next if $k eq ""; ++$done; - next - if -f "$dir/data/$k" - or -f "$dir/data/$k.gz" - or -f "$dir/data/$k.x" - or -f "$dir/data/$k.x.gz" - or -f "$dir/data/$k.gz.x"; - say "missing $k @$i"; + my ($file) = + grep { -f } + map { "$dir/data/$_" } ($k, "$k.gz", "$k.x", "$k.x.gz", "$k.gz.x"); + + if (not $file) { + say "missing $k @$i"; + @invalid{@$i} = (); + next; + } + + next if not $o{checksum}; + + # checking the checksum + my $buffer; + given ($file) { + when (/\.gz\.x$/) { + open( + my $fh => + "openssl @{[CIPHER]} -d -pass $o{pass} -in $file|"); + local $/ = undef; + gunzip($fh => \$buffer) or die $GunzipError; + } + when (/\.gz$/) { gunzip($file => \$buffer) or die $GunzipError } + when (/\.x$/) { + open( + my $fh => + "openssl @{[CIPHER]} -d -pass $o{pass} -in $file|"); + local $/ = undef; + $buffer = <$fh>; + } + default { open(my $fh => $file); local $/ = undef; $buffer = <$fh> } + } + + next if md5_hex($buffer) eq basename($file, qw(.gz .x .gz.x)); + say "wrong checksum for $file\n"; @invalid{@$i} = (); + } $SIG{ALRM}->(); alarm 0; @@ -268,6 +301,15 @@ =over +=item B<-c>|B<--checksum> + +Read all block files and check their checksum. (default: off) + +=item B<-p>|B<--pass> I + +In case you're using encrypted blocks, the param is passed to +Cs C<-pass> option. (default: unset) + =item B<-v>|B<-->[no]B Generate more output about what's going on. (default: on)