btrbk: use global stderr (replace err); refeactor filter_stderr, add fatal_stderr

if fatal_stderr is set and returns true, the command exit code is set
to -1, resulting in run_cmd() returning undef.
pull/299/head
Axel Burri 2019-08-19 13:04:44 +02:00
parent 360c8918bb
commit 485bc3ab0c
1 changed files with 132 additions and 134 deletions

266
btrbk
View File

@ -285,7 +285,6 @@ my $quiet;
my @exclude_vf;
my $do_dumper;
my $show_progress = 0;
my $err = "";
my $output_format;
my $lockfile;
my $tlog_fh;
@ -294,6 +293,7 @@ my $current_transaction;
my @transaction_log;
my %config_override;
my @tm_now; # current localtime ( sec, min, hour, mday, mon, year, wday, yday, isdst )
my @stderr; # stderr of last run_cmd
my %warn_once;
my %kdf_vars;
my $kdf_session_key;
@ -687,16 +687,15 @@ sub run_cmd(@)
my @cmd_pipe_in = (ref($_[0]) eq "HASH") ? @_ : { @_ };
die unless(scalar(@cmd_pipe_in));
$err = "";
@stderr = ();
my $destructive = 0;
my $catch_stderr = 0;
my $exitcode_loglevel = "debug";
my $filter_stderr = undef;
my @cmd_pipe;
my @unsafe_cmd;
my $compressed = undef;
my $stream_options = $cmd_pipe_in[0]->{stream_options} // {};
my @filter_stderr;
my $fatal_stderr;
my $has_rsh;
$cmd_pipe_in[0]->{stream_source} = 1;
@ -706,10 +705,9 @@ sub run_cmd(@)
{
die if(defined($href->{cmd_text}));
$catch_stderr = 1 if($href->{catch_stderr});
$filter_stderr = $href->{filter_stderr} if($href->{filter_stderr}); # NOTE: last filter wins!
push @filter_stderr, ((ref($href->{filter_stderr}) eq "ARRAY") ? @{$href->{filter_stderr}} : $href->{filter_stderr}) if($href->{filter_stderr});
$fatal_stderr = $href->{fatal_stderr} if($href->{fatal_stderr});
$destructive = 1 unless($href->{non_destructive});
$exitcode_loglevel = $href->{exitcode_loglevel} if($href->{exitcode_loglevel});
$has_rsh = 1 if($href->{rsh});
if($href->{check_unsafe}) {
@ -819,15 +817,15 @@ sub run_cmd(@)
# execute command
my ($pid, $out_fh, $err_fh, @stdout, @stderr);
my ($pid, $out_fh, $err_fh, @stdout);
$err_fh = gensym;
if(eval_quiet { $pid = open3(undef, $out_fh, $err_fh, $cmd); }) {
chomp(@stdout = readline($out_fh));
chomp(@stderr = readline($err_fh));
waitpid($pid, 0);
if($loglevel >= 4) {
TRACE "[stdout] $_" foreach(@stdout);
TRACE "[stderr] $_" foreach(@stderr);
TRACE map("[stdout] $_", @stdout);
TRACE map("[stderr] $_", @stderr);
}
}
else {
@ -847,26 +845,22 @@ sub run_cmd(@)
}
my $exitcode = $? >> 8;
my @filtered_err;
if($filter_stderr) {
@filtered_err = map { &{$filter_stderr} ($exitcode) // () } @stderr;
# call hooks: fatal_stderr, filter_stderr
if(($exitcode == 0) && $fatal_stderr) {
$exitcode = -1 if(grep &{$fatal_stderr}(), @stderr);
}
elsif($has_rsh && ($exitcode == 255)) {
# SSH returns exit status 255 if an error occurred.
@filtered_err = map { { error => $_ } } @stderr;
$exitcode_loglevel = "error";
foreach my $filter_fn (@filter_stderr) {
@stderr = map { &{$filter_fn} ($exitcode); $_ // () } @stderr;
}
if($exitcode || (grep { $_->{fatal} } @filtered_err)) {
my $log_text = "Command execution failed (exitcode=$exitcode): `$cmd`";
$exitcode_loglevel = "error" if(scalar(@filtered_err));
if($exitcode_loglevel eq "error") { ERROR $log_text; }
elsif($exitcode_loglevel eq "warn") { WARN $log_text; }
else { DEBUG $log_text; }
foreach(@filtered_err) {
ERROR "... $_->{error}" if(defined($_->{error}));
WARN "... $_->{warn}" if(defined($_->{warn}));
DEBUG "... $_->{debug}" if(defined($_->{debug}));
unshift @stderr, "sh: $cmd";
if($exitcode) {
my @log_text = ("Command execution failed (exitcode=$exitcode): `$cmd`", map("... $_", @stderr));
if($has_rsh && ($exitcode == 255)) { # SSH returns exit status 255 if an error occurred.
ERROR @log_text;
} else {
DEBUG @log_text;
}
return undef;
}
@ -877,13 +871,25 @@ sub run_cmd(@)
}
sub _btrfs_filter_stderr
{
if(/^usage: / || /(unrecognized|invalid) option/) {
WARN_ONCE "Using unsupported btrfs-progs < v$BTRFS_PROGS_MIN";
}
# strip error prefix (we print our own)
# note that this also affects ssh_filter_btrbk.sh error strings
s/^ERROR: //;
}
sub btrfs_filesystem_show($)
{
my $vol = shift || die;
my $path = $vol->{PATH} // die;
return run_cmd( cmd => vinfo_cmd($vol, "btrfs filesystem show", { unsafe => $path } ),
rsh => vinfo_rsh($vol),
non_destructive => 1
non_destructive => 1,
filter_stderr => \&_btrfs_filter_stderr,
);
}
@ -894,7 +900,8 @@ sub btrfs_filesystem_df($)
my $path = $vol->{PATH} // die;
return run_cmd( cmd => vinfo_cmd($vol, "btrfs filesystem df", { unsafe => $path }),
rsh => vinfo_rsh($vol),
non_destructive => 1
non_destructive => 1,
filter_stderr => \&_btrfs_filter_stderr,
);
}
@ -905,8 +912,14 @@ sub btrfs_filesystem_usage($)
my $path = $vol->{PATH} // die;
my $ret = run_cmd( cmd => vinfo_cmd($vol, "btrfs filesystem usage", { unsafe => $path } ),
rsh => vinfo_rsh($vol),
non_destructive => 1
non_destructive => 1,
filter_stderr => \&_btrfs_filter_stderr,
);
unless(defined($ret)) {
ERROR "Failed to fetch btrfs filesystem usage for: $vol->{PRINT}", map("... $_", @stderr);
return undef;
}
return undef unless(defined($ret));
my %detail;
@ -978,21 +991,7 @@ sub btrfs_subvolume_show($;@)
my $ret = run_cmd(cmd => vinfo_cmd($vol, "btrfs subvolume show", @cmd_options, { unsafe => $path }),
rsh => vinfo_rsh($vol),
non_destructive => 1,
catch_stderr => 1, # hack for shell-based run_cmd()
filter_stderr => sub {
return undef unless($_[0]); # do nothing if exitcode=0
if(s/^ERROR: //) { # catch errors from btrfs-progs as well as ssh_filter_btrbk.sh
$err = $_;
return { error => $_, fatal => 1 } if(/^ssh_filter_btrbk.sh/); # "fatal" causes run_cmd to return undef
} elsif(/(unrecognized|invalid) option/) {
WARN_ONCE "$_ (maybe using unsupported btrfs-progs < v$BTRFS_PROGS_MIN " . ($vol->{HOST} ? "on host=$vol->{HOST} " : "") . "?)";
} else {
DEBUG "Unparsed error: $_";
$err ||= $_;
}
# soft fail: $err can be displayed as a user-friendly WARNING
return undef;
},
filter_stderr => \&_btrfs_filter_stderr,
);
return undef unless(defined($ret));
@ -1103,6 +1102,7 @@ sub btrfs_subvolume_list_readonly_flag($)
my $ret = run_cmd(cmd => vinfo_cmd($vol, "btrfs subvolume list", '-a', '-r', { unsafe => $path } ),
rsh => vinfo_rsh($vol),
non_destructive => 1,
filter_stderr => \&_btrfs_filter_stderr,
);
return undef unless(defined($ret));
@ -1135,6 +1135,7 @@ sub btrfs_subvolume_list($;@)
my $ret = run_cmd(cmd => vinfo_cmd($vol, "btrfs subvolume list", @filter_options, @display_options, { unsafe => $path } ),
rsh => vinfo_rsh($vol),
non_destructive => 1,
filter_stderr => \&_btrfs_filter_stderr,
);
return undef unless(defined($ret));
@ -1219,9 +1220,10 @@ sub btrfs_subvolume_find_new($$;$)
my $ret = run_cmd(cmd => vinfo_cmd($vol, "btrfs subvolume find-new", { unsafe => $path }, $lastgen ),
rsh => vinfo_rsh($vol),
non_destructive => 1,
filter_stderr => \&_btrfs_filter_stderr,
);
unless(defined($ret)) {
ERROR "Failed to fetch modified files for: $vol->{PRINT}";
ERROR "Failed to fetch modified files for: $vol->{PRINT}", map("... $_", @stderr);
return undef;
}
@ -1285,10 +1287,11 @@ sub btrfs_subvolume_snapshot($$)
);
my $ret = run_cmd(cmd => vinfo_cmd($svol, "btrfs subvolume snapshot", '-r', { unsafe => $src_path }, { unsafe => $target_path } ),
rsh => vinfo_rsh($svol),
filter_stderr => \&_btrfs_filter_stderr,
);
end_transaction("snapshot", defined($ret));
unless(defined($ret)) {
ERROR "Failed to create btrfs subvolume snapshot: $svol->{PRINT} -> $target_path";
ERROR "Failed to create snapshot: $svol->{PRINT} -> $target_path", map("... $_", @stderr);
return undef;
}
return $target_vol;
@ -1338,45 +1341,35 @@ sub btrfs_subvolume_delete($@)
}
$ret = run_cmd(cmd => ['rm', '-f', @cmd_target_paths ],
rsh => vinfo_rsh($targets->[0]),
catch_stderr => 1, # hack for shell-based run_cmd()
filter_stderr => sub {
# catch errors from "rm -f"
if(/^rm: cannot remove '($file_match)':/) {
my $catch = $1; # make sure $catch matches $vol->{PATH}
$catch =~ s/\.info$//;
$catch =~ s/\.split_[a-z][a-z]$//;
$err_catch{$catch} //= [];
push(@{$err_catch{$catch}}, $_);
return undef; # no error messages in run_cmd
}
else {
# show errors in run_cmd; force "Command execution failed" error message
return { error => $_, fatal => 1 };
}
},
);
unless(defined($ret)) {
foreach(@stderr) {
next unless(/^rm: cannot remove '($file_match)':/);
my $catch = $1; # make sure $catch matches $vol->{PATH}
$catch =~ s/\.info$//;
$catch =~ s/\.split_[a-z][a-z]$//;
$err_catch{$catch} //= [];
push(@{$err_catch{$catch}}, $_);
}
}
}
else {
my @cmd_target_paths = map { { unsafe => $_->{PATH} } } @$targets;
my $unparsed_errors;
my @options;
@options = ("--commit-$commit") if($commit);
$ret = run_cmd(cmd => vinfo_cmd($targets->[0], "btrfs subvolume delete", @options, @cmd_target_paths ),
rsh => vinfo_rsh($targets->[0]),
catch_stderr => 1, # hack for shell-based run_cmd()
filter_stderr => sub {
return undef unless(s/^ERROR: //); # strip ERROR prefix
if(/'($file_match)'/ || /: ($file_match)$/ || /($file_match):/) {
# NOTE: as of btrfs-progs-4.16, this does not catch anything
$err_catch{$1} //= [];
push(@{$err_catch{$1}}, $_);
} else {
$unparsed_errors = 1;
}
return undef; # no error messages in run_cmd
},
fatal_stderr => sub { m/^ERROR: /; }, # probably not needed, "btrfs sub delete" returns correct exit status
filter_stderr => \&_btrfs_filter_stderr,
);
$ret = undef if($unparsed_errors);
unless(defined($ret)) {
foreach(@stderr) {
next unless(/'($file_match)'/ || /: ($file_match)$/ || /($file_match):/);
# NOTE: as of btrfs-progs-4.16, this does not catch anything
$err_catch{$1} //= [];
push(@{$err_catch{$1}}, $_);
}
}
}
if(defined($ret)) {
@ -1388,7 +1381,7 @@ sub btrfs_subvolume_delete($@)
foreach my $check_target (@$targets) {
my $err_ary = $err_catch{$check_target->{PATH}};
if($err_ary) {
ERROR "Failed to delete subvolume \"$check_target->{PRINT}\": $_" foreach(@$err_ary);
ERROR map("Failed to delete subvolume \"$check_target->{PRINT}\": $_", @$err_ary);
$catch_count++;
}
else {
@ -1398,9 +1391,9 @@ sub btrfs_subvolume_delete($@)
@deleted = () if($catch_count != (scalar keys %err_catch));
}
unless(scalar(@deleted)) {
ERROR "Failed to match error messages from delete command, assuming nothing deleted:";
ERROR "... possibly not deleted subvolume: $_" foreach(map( { $_->{PRINT} } @$targets));
ERROR "... consider running 'btrbk prune -n'";
ERROR "Failed to match error messages from delete command, assuming nothing deleted", map("... $_", @stderr);
ERROR map("Possibly not deleted subvolume: $_->{PRINT}", @$targets);
ERROR "Consider running 'btrbk prune -n'";
}
}
@ -1426,10 +1419,11 @@ sub btrfs_qgroup_destroy($@)
vinfo_prefixed_keys("target", $vol));
my $ret = run_cmd(cmd => vinfo_cmd($vol, "btrfs qgroup destroy", $qgroup_id, { unsafe => $path }),
rsh => vinfo_rsh($vol),
filter_stderr => \&_btrfs_filter_stderr,
);
end_transaction($opts{type} // "qgroup_destroy", defined($ret));
unless(defined($ret)) {
ERROR "Failed to destroy qgroup \"$qgroup_id\" for subvolume: $vol->{PRINT}";
ERROR "Failed to destroy qgroup \"$qgroup_id\" for subvolume: $vol->{PRINT}", map("... $_", @stderr);
return undef;
}
return $vol;
@ -1472,21 +1466,14 @@ sub btrfs_send_receive($$;$$$)
rsh => vinfo_rsh($snapshot, disable_compression => $stream_options->{stream_compress}),
name => "btrfs send",
stream_options => $stream_options,
exitcode_loglevel => "error", # print error message if exitcode != 0
catch_stderr => 1, # hack for shell-based run_cmd()
filter_stderr => [ \&_btrfs_filter_stderr, sub { $_ = undef if(/^At subvol/) } ],
};
push @cmd_pipe, {
cmd => vinfo_cmd($target, "btrfs receive", @receive_options, { unsafe => $target_path . '/' } ),
rsh => vinfo_rsh($target, disable_compression => $stream_options->{stream_compress}),
name => "btrfs receive",
catch_stderr => 1, # hack for shell-based run_cmd()
filter_stderr => sub {
# NOTE: btrfs-progs < 4.11: if "btrfs send" fails, "btrfs receive" returns 0!
return { error => $_, fatal => 1 } if(s/^ERROR: //); # "fatal" causes run_cmd to return undef
return { warn => $_ } if(s/^WARNING: //);
return undef;
},
fatal_stderr => sub { m/^ERROR: /; }, # NOTE: btrfs-progs < 4.11: if "btrfs send" fails, "btrfs receive" returns 0!
};
my $send_receive_error = 0;
@ -1496,7 +1483,9 @@ sub btrfs_send_receive($$;$$$)
vinfo_prefixed_keys("parent", $parent),
);
my $ret = run_cmd(@cmd_pipe);
my @cmd_err;
unless(defined($ret)) {
@cmd_err = @stderr; # save for later
$send_receive_error = 1;
}
@ -1522,21 +1511,21 @@ sub btrfs_send_receive($$;$$$)
unless($send_receive_error) {
# plausibility checks on target detail
unless($detail->{readonly}) {
ERROR "[send/receive] target is not readonly: $vol_received->{PRINT}";
push @cmd_err, "target is not readonly: $vol_received->{PRINT}";
$send_receive_error = 1;
}
if($detail->{received_uuid} && ($detail->{received_uuid} eq '-')) {
# NOTE: received_uuid is not in @required_keys (needs btrfs-progs >= 4.1 (BTRFS_PROGS_MIN))
# so we only check it if it's really present
ERROR "[send/receive] received_uuid is not set on target: $vol_received->{PRINT}";
push @cmd_err, "received_uuid is not set on target: $vol_received->{PRINT}";
$send_receive_error = 1;
}
if($parent && ($detail->{parent_uuid} eq '-')) {
ERROR "[send/receive] parent_uuid is not set on target: $vol_received->{PRINT}";
push @cmd_err, "parent_uuid is not set on target: $vol_received->{PRINT}";
$send_receive_error = 1;
}
if((not $parent) && ($detail->{parent_uuid} ne '-')) {
ERROR "[send/receive] parent_uuid is set on target: $vol_received->{PRINT}";
push @cmd_err, "parent_uuid is set on target: $vol_received->{PRINT}";
$send_receive_error = 1;
}
}
@ -1545,7 +1534,7 @@ sub btrfs_send_receive($$;$$$)
$is_garbled = ((not $detail->{readonly}) && defined($detail->{received_uuid}) && ($detail->{received_uuid} eq '-'));
}
else {
$err = "" if($send_receive_error); # ignore $err if send/receive failed
push @cmd_err, "failed to check target subvolume: $vol_received->{PRINT}", @stderr;
$send_receive_error = 1;
}
}
@ -1554,7 +1543,7 @@ sub btrfs_send_receive($$;$$$)
if($send_receive_error) {
ERROR "Failed to send/receive subvolume: $snapshot->{PRINT} " . ($parent_path ? "[$parent_path]" : "") . " -> $vol_received->{PRINT}";
ERROR "... $err" if($err);
ERROR map("... $_", @cmd_err);
}
if($is_garbled) {
@ -1619,13 +1608,8 @@ sub btrfs_send_to_file($$$;$$)
rsh => vinfo_rsh($source, disable_compression => $stream_options->{stream_compress}),
name => "btrfs send",
stream_options => $stream_options,
exitcode_loglevel => "error", # print error message if exitcode != 0
catch_stderr => 1, # hack for shell-based run_cmd()
filter_stderr => sub {
return { error => $_, fatal => 1 } if(s/^ERROR: //); # "fatal" causes run_cmd to return undef
return { warn => $_ } if(s/^WARNING: //);
return undef;
},
filter_stderr => [ \&_btrfs_filter_stderr, sub { $_ = undef if(/^At subvol/) } ],
fatal_stderr => sub { m/^ERROR: /; },
};
if($compress) {
@ -1702,12 +1686,18 @@ sub btrfs_send_to_file($$$;$$)
DEBUG "Generating session key for: $vol_received->{PRINT}";
my $kdf_backend_name = $encrypt->{kdf_backend};
$kdf_backend_name =~ s/^.*\///;
my $key_target_text = $encrypt->{kdf_keygen_each} ? "\"$vol_received->{PRINT}\"" : "all raw backups";
print STDOUT "\nGenerate session key for " . ($encrypt->{kdf_keygen_each} ? "\"$vol_received->{PRINT}\"" : "all raw backups") . ":\n";
print STDOUT "\nGenerate session key for $key_target_text:\n";
my $kdf_values = run_cmd(cmd => [ $encrypt->{kdf_backend}, $encrypt->{kdf_keysize} ],
non_destructive => 1,
name => $kdf_backend_name
);
unless(defined($kdf_values)) {
ERROR "Failed to generate session key for $key_target_text", map("... $_", @stderr);
return undef;
}
return undef unless(defined($kdf_values));
foreach(@$kdf_values) {
chomp;
@ -1803,8 +1793,13 @@ sub btrfs_send_to_file($$$;$$)
my $ret;
$ret = system_write_raw_info($vol_received, \%raw_info);
my @cmd_err;
if(defined($ret)) {
$ret = run_cmd(@cmd_pipe);
@cmd_err = @stderr unless(defined($ret)); # save for later
}
else {
push @cmd_err, "failed to write raw .info file: $vol_received->{PATH}.info", @stderr;
}
if(defined($ret)) {
@ -1813,9 +1808,10 @@ sub btrfs_send_to_file($$$;$$)
# redirection as well as "dd" always creates the target file.
# Note that "split" does not create empty files.
my $test_postfix = ($split ? ".split_aa" : "");
DEBUG "Testing target data file (non-zero size)";
my $check_file = "${target_path}/${target_filename}${test_postfix}";
DEBUG "Testing target data file (non-zero size): $check_file";
$ret = run_cmd({
cmd => ['test', '-s', { unsafe => "${target_path}/${target_filename}${test_postfix}" } ],
cmd => ['test', '-s', { unsafe => $check_file } ],
rsh => vinfo_rsh($target),
name => "test",
});
@ -1824,10 +1820,14 @@ sub btrfs_send_to_file($$$;$$)
delete $raw_info{INCOMPLETE};
$ret = system_write_raw_info($vol_received, \%raw_info);
}
else {
push @cmd_err, "failed to check target file (not present or zero length): $check_file";
}
}
end_transaction("send-to-raw", defined($ret));
unless(defined($ret)) {
ERROR "Failed to send btrfs subvolume to raw file: $source->{PRINT} " . ($parent_path ? "[$parent_path]" : "") . " -> $vol_received->{PRINT}";
ERROR map("... $_", @cmd_err);
return undef;
}
return 1;
@ -1841,8 +1841,6 @@ sub system_list_mountinfo($)
my $ret = run_cmd(cmd => [ qw(cat), $file ],
rsh => vinfo_rsh($vol),
non_destructive => 1,
exitcode_loglevel => "error", # print error message if exitcode != 0
catch_stderr => 1, # hack for shell-based run_cmd()
);
return undef unless(defined($ret));
@ -5195,11 +5193,11 @@ MAIN:
# NOTE: ssh://{src,target} uses default config
my $src_vol = vinfo($src_url, $config);
unless(vinfo_init_root($src_vol)) { ERROR "Failed to fetch subvolume detail for '$src_vol->{PRINT}'" . ($err ? ": $err" : ""); exit 1; }
unless(vinfo_init_root($src_vol)) { ERROR "Failed to fetch subvolume detail for '$src_vol->{PRINT}'", map("... $_", @stderr); exit 1; }
if($src_vol->{node}{is_root}) { ERROR "Subvolume is btrfs root: $src_vol->{PRINT}"; exit 1; }
my $target_vol = vinfo($target_url, $config);
unless(vinfo_init_root($target_vol)) { ERROR "Failed to fetch subvolume detail for '$target_vol->{PRINT}'" . ($err ? ": $err" : ""); exit 1; }
unless(vinfo_init_root($target_vol)) { ERROR "Failed to fetch subvolume detail for '$target_vol->{PRINT}'", map("... $_", @stderr); exit 1; }
if($target_vol->{node}{is_root}) { ERROR "Subvolume is btrfs root: $target_vol->{PRINT}"; exit 1; }
unless(_is_same_fs_tree($src_vol->{node}, $target_vol->{node})) {
@ -5301,7 +5299,7 @@ MAIN:
$realpath_cache{$mnt->{mount_point}} = $mnt->{mount_point}; # we know those are real paths, prevents calling readlink in btrfs_mountpoint
my $vol = vinfo($mnt->{mount_point}, $config);
unless(vinfo_init_root($vol)) {
ERROR "Failed to fetch subvolume detail for: $vol->{PRINT}" . ($err ? ": $err" : "");
ERROR "Failed to fetch subvolume detail for: $vol->{PRINT}", map("... $_", @stderr);
exit 1;
}
@ -5381,12 +5379,12 @@ MAIN:
my $src_root = vinfo($src_url, $config);
unless(vinfo_init_root($src_root)) {
ERROR "Failed to fetch subvolume detail for '$src_root->{PRINT}'" . ($err ? ": $err" : "");
ERROR "Failed to fetch subvolume detail for '$src_root->{PRINT}'", map("... $_", @stderr);
exit 1;
}
my $archive_root = vinfo($archive_url, $config);
unless($archive_raw ? vinfo_init_raw_root($archive_root) : vinfo_init_root($archive_root)) {
ERROR "Failed to fetch " . ($archive_raw ? "raw target metadata" : "subvolume detail") . " for '$archive_root->{PRINT}'" . ($err ? ": $err" : "");
ERROR "Failed to fetch " . ($archive_raw ? "raw target metadata" : "subvolume detail") . " for '$archive_root->{PRINT}'", map("... $_", @stderr);
exit 1;
}
@ -5421,18 +5419,18 @@ MAIN:
my $sroot = vinfo($sroot_url, $config_sroot);
vinfo_assign_config($sroot);
unless(vinfo_init_root($sroot)) {
ABORTED($sroot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
WARN "Skipping archive source \"$sroot->{PRINT}\": " . ABORTED_TEXT($sroot);
ABORTED($sroot, "Failed to fetch subvolume detail");
WARN "Skipping archive source \"$sroot->{PRINT}\": " . ABORTED_TEXT($sroot), map("... $_", @stderr);
next;
}
my $droot = vinfo($droot_url, $config_droot);
vinfo_assign_config($droot);
unless($archive_raw ? vinfo_init_raw_root($droot) : vinfo_init_root($droot)) {
DEBUG "Failed to fetch " . ($archive_raw ? "raw target metadata" : "subvolume detail") . " for '$droot->{PRINT}'" . ($err ? ": $err" : "");
DEBUG "Failed to fetch " . ($archive_raw ? "raw target metadata" : "subvolume detail") . " for '$droot->{PRINT}'";
unless(system_mkdir($droot)) {
ABORTED($droot, "Failed to create directory: $droot->{PRINT}/");
WARN "Skipping archive target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot);
WARN "Skipping archive target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot), map("... $_", @stderr);
next;
}
$droot->{SUBDIR_CREATED} = 1;
@ -5445,8 +5443,8 @@ MAIN:
else {
# after directory is created, try to init again
unless($archive_raw ? vinfo_init_raw_root($droot) : vinfo_init_root($droot)) {
ABORTED($droot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
WARN "Skipping archive target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot);
ABORTED($droot, "Failed to fetch subvolume detail");
WARN "Skipping archive target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot), map("... $_", @stderr);
next;
}
}
@ -5616,8 +5614,8 @@ MAIN:
next unless(grep defined($_->{GLOB_CONTEXT}), @{$config_vol->{SUBSECTION}});
my $sroot = vinfo($config_vol->{url}, $config_vol);
unless(vinfo_init_root($sroot)) {
ABORTED($sroot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
WARN "Skipping volume \"$sroot->{PRINT}\": " . ABORTED_TEXT($sroot);
ABORTED($sroot, "Failed to fetch subvolume detail");
WARN "Skipping volume \"$sroot->{PRINT}\": " . ABORTED_TEXT($sroot), map("... $_", @stderr);
next;
}
@ -5953,15 +5951,15 @@ MAIN:
foreach my $sroot (vinfo_subsection($config, 'volume')) {
DEBUG "Initializing volume section: $sroot->{PRINT}";
unless(vinfo_init_root($sroot)) {
ABORTED($sroot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
WARN "Skipping volume \"$sroot->{PRINT}\": " . ABORTED_TEXT($sroot);
ABORTED($sroot, "Failed to fetch subvolume detail");
WARN "Skipping volume \"$sroot->{PRINT}\": " . ABORTED_TEXT($sroot), map("... $_", @stderr);
next;
}
foreach my $svol (vinfo_subsection($sroot, 'subvolume')) {
DEBUG "Initializing subvolume section: $svol->{PRINT}";
unless(vinfo_init_root($svol)) {
ABORTED($svol, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
WARN "Skipping subvolume \"$svol->{PRINT}\": " . ABORTED_TEXT($svol);
ABORTED($svol, "Failed to fetch subvolume detail");
WARN "Skipping subvolume \"$svol->{PRINT}\": " . ABORTED_TEXT($svol), map("... $_", @stderr);
next;
}
if((not $svol->{node}{uuid}) || ($svol->{node}{uuid} eq '-')) {
@ -5991,8 +5989,8 @@ MAIN:
my $snaproot = vinfo_snapshot_root($svol);
unless(vinfo_init_root($snaproot)) {
ABORTED($svol, "Failed to fetch subvolume detail for snapshot_dir" . ($err ? ": $err" : ""));
WARN "Skipping subvolume \"$svol->{PRINT}\": " . ABORTED_TEXT($svol);
ABORTED($svol, "Failed to fetch subvolume detail for snapshot_dir");
WARN "Skipping subvolume \"$svol->{PRINT}\": " . ABORTED_TEXT($svol), map("... $_", @stderr);
next;
}
unless(_is_same_fs_tree($snaproot->{node}, $svol->{node})) {
@ -6018,16 +6016,16 @@ MAIN:
if($target_type eq "send-receive")
{
unless(vinfo_init_root($droot)) {
ABORTED($droot, "Failed to fetch subvolume detail" . ($err ? ": $err" : ""));
WARN "Skipping target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot);
ABORTED($droot, "Failed to fetch subvolume detail");
WARN "Skipping target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot), map("... $_", @stderr);
next;
}
}
elsif($target_type eq "raw")
{
unless(vinfo_init_raw_root($droot)) {
ABORTED($droot, "Failed to fetch raw target metadata" . ($err ? ": $err" : ""));
WARN "Skipping target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot);
ABORTED($droot, "Failed to fetch raw target metadata");
WARN "Skipping target \"$droot->{PRINT}\": " . ABORTED_TEXT($droot), map("... $_", @stderr);
next;
}
}
@ -6077,7 +6075,7 @@ MAIN:
my $url = $subvol_args[0] || die;
my $vol = vinfo($url, $config);
unless(vinfo_init_root($vol)) {
ERROR "Failed to fetch subvolume detail for: $url" . ($err ? ": $err" : "");
ERROR "Failed to fetch subvolume detail for: $url", map("... $_", @stderr);
exit 1;
}
if($vol->{node}{is_root}) {