--- 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<pass>
+
+In case you're using encrypted blocks, the param is passed to
+C<openssl>s C<-pass> option. (default: unset)
+
=item B<-v>|B<-->[no]B<verbose>
Generate more output about what's going on. (default: on)