btrbk: improved error handling

pull/30/head
Axel Burri 2014-12-19 13:31:31 +01:00
parent 8930c0a87f
commit 299edde0d7
1 changed files with 69 additions and 34 deletions

103
btrbk
View File

@ -109,7 +109,10 @@ sub run_cmd($;$)
$ret = `$cmd`; $ret = `$cmd`;
chomp($ret); chomp($ret);
TRACE "command output:\n$ret"; TRACE "command output:\n$ret";
die("command execution failed: \"$cmd\"") if($?); if($?) {
WARN "command execution failed (exitcode=$?): \"$cmd\"";
return undef;
}
} }
return $ret; return $ret;
} }
@ -147,36 +150,39 @@ sub btr_subvolume_detail($)
{ {
my $vol = shift; my $vol = shift;
my $ret = run_cmd("/sbin/btrfs subvolume show $vol 2>/dev/null", 1); my $ret = run_cmd("/sbin/btrfs subvolume show $vol 2>/dev/null", 1);
if($ret eq "$vol is btrfs root") { if($ret)
TRACE "btr_detail: found btrfs root: $vol"; {
return { id => 5, is_root => 1 }; if($ret eq "$vol is btrfs root") {
} TRACE "btr_detail: found btrfs root: $vol";
elsif($ret =~ /^$vol/) { return { id => 5, is_root => 1 };
TRACE "btr_detail: found btrfs subvolume: $vol"; }
my %trans = ( elsif($ret =~ /^$vol/) {
name => "Name", TRACE "btr_detail: found btrfs subvolume: $vol";
uuid => "uuid", my %trans = (
parent_uuid => "Parent uuid", name => "Name",
creation_time => "Creation time", uuid => "uuid",
id => "Object ID", parent_uuid => "Parent uuid",
gen => "Generation \\(Gen\\)", creation_time => "Creation time",
cgen => "Gen at creation", id => "Object ID",
parent_id => "Parent", gen => "Generation \\(Gen\\)",
top_level => "Top Level", cgen => "Gen at creation",
flags => "Flags", parent_id => "Parent",
); top_level => "Top Level",
my %detail; flags => "Flags",
foreach (keys %trans) { );
if($ret =~ /^\s+$trans{$_}:\s+(.*)$/m) { my %detail;
$detail{$_} = $1; foreach (keys %trans) {
} else { if($ret =~ /^\s+$trans{$_}:\s+(.*)$/m) {
WARN "Failed to parse subvolume detail \"$trans{$_}\": $ret"; $detail{$_} = $1;
} } else {
WARN "Failed to parse subvolume detail \"$trans{$_}\": $ret";
}
}
TRACE "btr_detail for $vol: " . Dumper \%detail;
return \%detail;
} }
TRACE "btr_detail for $vol: " . Dumper \%detail;
return \%detail;
} }
ERROR "Failed to fetch subvolume detail for: $vol"; WARN "Failed to fetch subvolume detail for: $vol";
return undef; return undef;
} }
@ -254,6 +260,10 @@ sub btr_subvolume_list($;@)
my $filter_option = "-a"; my $filter_option = "-a";
$filter_option = "-o" if($opts{subvol_only}); $filter_option = "-o" if($opts{subvol_only});
my $ret = run_cmd("/sbin/btrfs subvolume list $filter_option -c -u -q -R $vol", 1); my $ret = run_cmd("/sbin/btrfs subvolume list $filter_option -c -u -q -R $vol", 1);
unless($ret) {
WARN "Failed to fetch btrfs subvolume list for: $vol";
return undef;
}
my @nodes; my @nodes;
foreach (split(/\n/, $ret)) foreach (split(/\n/, $ret))
{ {
@ -275,7 +285,7 @@ sub btr_subvolume_list($;@)
}; };
# $node{parent_uuid} = undef if($node{parent_uuid} eq '-'); # $node{parent_uuid} = undef if($node{parent_uuid} eq '-');
} }
return @nodes; return \@nodes;
} }
sub btr_subvolume_find_new($$) sub btr_subvolume_find_new($$)
@ -283,6 +293,8 @@ sub btr_subvolume_find_new($$)
my $vol = shift; my $vol = shift;
my $lastgen = shift; my $lastgen = shift;
my $ret = run_cmd("/sbin/btrfs subvolume find-new $vol $lastgen"); my $ret = run_cmd("/sbin/btrfs subvolume find-new $vol $lastgen");
ERROR "Failed to fetch modified files for: $vol" unless(defined($ret));
return $ret;
} }
@ -291,7 +303,9 @@ sub btr_tree($)
my $vol = shift; my $vol = shift;
my %tree; my %tree;
my %id; my %id;
foreach my $node (btr_subvolume_list($vol, subvol_only => 0)) my $subvol_list = btr_subvolume_list($vol, subvol_only => 0);
return undef unless(ref($subvol_list) eq "ARRAY");
foreach my $node (@$subvol_list)
{ {
TRACE "btr_tree: processing subvolid=$node->{id}"; TRACE "btr_tree: processing subvolid=$node->{id}";
@ -327,9 +341,16 @@ sub btr_subtree($)
{ {
my $vol = shift; my $vol = shift;
my $detail = btr_subvolume_detail($vol); my $detail = btr_subvolume_detail($vol);
unless($detail) {
WARN "Failed to build btrfs subtree for volume: $vol";
return undef;
}
my $volname = $detail->{name} || ""; my $volname = $detail->{name} || "";
my %tree; my %tree;
foreach my $node (btr_subvolume_list($vol, subvol_only => 1)) my $subvol_list = btr_subvolume_list($vol, subvol_only => 1);
return undef unless(ref($subvol_list) eq "ARRAY");
foreach my $node (@$subvol_list)
{ {
TRACE "btr_subtree: processing subvolid=$node->{id}"; TRACE "btr_subtree: processing subvolid=$node->{id}";
@ -359,6 +380,7 @@ sub btr_subtree($)
} }
# returns $dst, or undef on error
sub btrfs_snapshot($$) sub btrfs_snapshot($$)
{ {
my $src = shift; my $src = shift;
@ -367,7 +389,9 @@ sub btrfs_snapshot($$)
DEBUG "[btrfs] source: $src"; DEBUG "[btrfs] source: $src";
DEBUG "[btrfs] dest : $dst"; DEBUG "[btrfs] dest : $dst";
INFO ">>> $dst"; INFO ">>> $dst";
run_cmd("/sbin/btrfs subvolume snapshot -r $src $dst"); my $ret = run_cmd("/sbin/btrfs subvolume snapshot -r $src $dst");
ERROR "Failed to create btrfs subvolume snapshot: $src -> $dst" unless(defined($ret));
return defined($ret) ? $dst : undef;
} }
@ -397,6 +421,10 @@ sub btrfs_send_receive($$;$$)
$receive_option = "-v -v" if($parent && $changelog); $receive_option = "-v -v" if($parent && $changelog);
my $cmd = "/sbin/btrfs send $parent_option $src | /sbin/btrfs receive $receive_option $dst/ 2>&1"; my $cmd = "/sbin/btrfs send $parent_option $src | /sbin/btrfs receive $receive_option $dst/ 2>&1";
my $ret = run_cmd($cmd); my $ret = run_cmd($cmd);
unless(defined($ret)) {
ERROR "Failed to send/receive btrfs subvolume: $src " . ($parent ? "[$parent]" : "") . " -> $dst";
return undef;
}
if($changelog && (not $dryrun)) if($changelog && (not $dryrun))
{ {
INFO "Writing btrfs-diff changelog: $changelog"; INFO "Writing btrfs-diff changelog: $changelog";
@ -412,6 +440,7 @@ sub btrfs_send_receive($$;$$)
WARN "Failed to open changelog file: $!"; WARN "Failed to open changelog file: $!";
} }
} }
return 1;
} }
@ -558,6 +587,8 @@ MAIN:
if($target_diff) { if($target_diff) {
my $target_detail = btr_subvolume_detail($target_diff); my $target_detail = btr_subvolume_detail($target_diff);
exit 1 unless($target_detail);
$target = $uuid_info{$target_detail->{uuid}}; $target = $uuid_info{$target_detail->{uuid}};
# check if given parent is really a parent # check if given parent is really a parent
my $cur = $node; my $cur = $node;
@ -575,6 +606,7 @@ MAIN:
# dump files, sorted and unique # dump files, sorted and unique
my $ret = btr_subvolume_find_new($vol, $lastgen); my $ret = btr_subvolume_find_new($vol, $lastgen);
exit 1 unless(defined($ret));
my %files; my %files;
foreach (split(/\n/, $ret)) { foreach (split(/\n/, $ret)) {
/\S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ (\S+)/; /\S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ \S+ (\S+)/;
@ -717,7 +749,10 @@ MAIN:
DEBUG "***"; DEBUG "***";
INFO "Creating subvolume snapshot for: $sroot/$svol"; INFO "Creating subvolume snapshot for: $sroot/$svol";
btrfs_snapshot("$sroot/$svol", $snapshot); unless(btrfs_snapshot("$sroot/$svol", $snapshot)) {
WARN "Failed to create snapshot, aborting job: $sroot/$svol";
$job->{ABORTED} = 1;
}
$snapshot_cache{"$sroot/$svol"} = { name => $snapshot_name, $snapshot_cache{"$sroot/$svol"} = { name => $snapshot_name,
file => $snapshot }; file => $snapshot };
} }