1 |
dpavlin |
1 |
#!/usr/bin/perl |
2 |
|
|
|
3 |
|
|
use warnings; |
4 |
|
|
use strict; |
5 |
|
|
|
6 |
|
|
use File::Slurp; |
7 |
|
|
use File::Path; |
8 |
|
|
use Getopt::Long; |
9 |
|
|
|
10 |
|
|
my $dev = '/dev/sdb2'; |
11 |
|
|
my $mnt = '/mnt/42'; |
12 |
|
|
|
13 |
|
|
my ( $rollback, $commit ); |
14 |
|
|
|
15 |
|
|
GetOptions( |
16 |
|
|
'rollback!' => \$rollback, |
17 |
|
|
'commit!' => \$commit, |
18 |
|
|
) or die "unknown options: $!"; |
19 |
|
|
|
20 |
dpavlin |
2 |
map { mkdir $_ unless -e $_ } map { "$mnt/$_" } ( 'log', 'fs' ); |
21 |
dpavlin |
1 |
|
22 |
dpavlin |
2 |
my $path = shift @ARGV || die "usage: $0 /path/to/file\n"; |
23 |
dpavlin |
1 |
|
24 |
|
|
my ($dir,$file) = ($1,$2) if $path =~ m{^(?:(.+)/)?([^/]+)}; |
25 |
|
|
|
26 |
|
|
my $seq; |
27 |
|
|
my $opos = 0; |
28 |
|
|
|
29 |
|
|
if ( -e "$mnt/last" ) { |
30 |
|
|
my $log = read_file("$mnt/last"); |
31 |
|
|
$seq = readlink("$mnt/last"); |
32 |
|
|
$seq =~ s{^.+/(\d+)$}{$1} || die "can't parse sequence: $seq"; |
33 |
|
|
$seq++; |
34 |
|
|
$opos = $1 if $log =~ m{opos:\s+(\d+\.\d[k])}; |
35 |
|
|
die "can't decode opos" unless $opos; |
36 |
|
|
warn "# seq: $seq start: $opos\n"; |
37 |
|
|
|
38 |
|
|
} else { |
39 |
dpavlin |
2 |
$seq = $#{ glob("$mnt/log/*") } + 1; |
40 |
dpavlin |
1 |
warn "# $mnt/last not found, recover seq: $seq\n"; |
41 |
|
|
} |
42 |
|
|
|
43 |
|
|
|
44 |
|
|
my $log = "$mnt/log/$seq"; |
45 |
|
|
|
46 |
|
|
if ( -e $log ) { |
47 |
|
|
print "ERROR $log exists!\n",read_file($log); |
48 |
|
|
if ( $rollback ) { |
49 |
|
|
unlink $log || die "can't rollback $log: $!"; |
50 |
|
|
die "RECOVERY removed $log\n"; |
51 |
|
|
} elsif ( $commit ) { |
52 |
|
|
unlink "$mnt/last" || die "can't remove $mnt/last: $!"; |
53 |
|
|
symlink $log,"$mnt/last" || die "can't commit $log: $!"; |
54 |
|
|
die "ERROR: can't update $mnt/last -> $log" unless $log eq readlink "$mnt/last"; |
55 |
|
|
die "RECOVERY updated $mnt/last -> $log\n"; |
56 |
|
|
} else { |
57 |
|
|
die "$log exists, re-run with --commit or --rollback"; |
58 |
|
|
} |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
my $fs = "$mnt/fs/$dir"; |
62 |
dpavlin |
2 |
mkpath $fs unless -e $fs; |
63 |
dpavlin |
1 |
|
64 |
|
|
$fs .= '/' . $file; |
65 |
|
|
|
66 |
dpavlin |
2 |
die "$fs exists!" if -e $fs; |
67 |
|
|
|
68 |
|
|
my $cmd = "dd_rescue -l $log -S $opos $path $dev"; |
69 |
|
|
print "+ $cmd\n"; |
70 |
|
|
system($cmd) == 0 or warn "# exit code: $?"; |
71 |
|
|
|
72 |
|
|
unlink("$mnt/last") && symlink($log,"$mnt/last") || die "can't commit log $log -> $mnt/last"; |
73 |
|
|
|
74 |
|
|
symlink($log,$fs) || die "can't create $fs: $!"; |
75 |
|
|
|
76 |
|
|
print "OK $fs -> $log\n"; |