X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=perl%2FAmanda%2FChanger%2Fcompat.pm;h=4b0028b6a4d2d510f220518adeb0df7722c4a74e;hb=d74dc4d908fcbc1a4ef474edaf51e61ec90eab6b;hp=3a9693509cc6574397854e0fdf71b0e6207fafe4;hpb=2627875b7d18858bc1f9f7652811e4d8c15a23eb;p=debian%2Famanda diff --git a/perl/Amanda/Changer/compat.pm b/perl/Amanda/Changer/compat.pm index 3a96935..4b0028b 100644 --- a/perl/Amanda/Changer/compat.pm +++ b/perl/Amanda/Changer/compat.pm @@ -29,7 +29,7 @@ use File::Path; use Amanda::Paths; use Amanda::MainLoop qw( :GIOCondition ); use Amanda::Config qw( :getconf ); -use Amanda::Debug; +use Amanda::Debug qw( debug ); use Amanda::Device qw( :constants ); use Amanda::Changer; @@ -131,44 +131,53 @@ sub _manual_scan { my $self = shift; my %params = @_; my $nchecked = 0; - my $check_slot; + my ($run_success_cb, $run_fail_cb, $load_next); - # search manually, starting with "current". This is complicated, because - # it's an event-based loop. + # search manually, starting with "current" and proceeding through nslots-1 + # loads of "next" # TODO: support the case where nslots == -1 - $check_slot = sub { - my ($err, $res) = @_; - - TRYSLOT: { - # ignore "benign" errors - next TRYSLOT if $err; - - my $device = Amanda::Device->new($res->{'device_name'}); - next TRYSLOT unless $device; - next TRYSLOT if ($device->read_label() != $DEVICE_STATUS_SUCCESS); - next TRYSLOT unless ($device->volume_label() eq $params{'label'}); + $run_success_cb = sub { + my ($slot, $rest) = @_; + my $device = Amanda::Device->new($rest); + if ($device and $device->configure(1) + and $device->read_label() == $DEVICE_STATUS_SUCCESS + and $device->volume_label() eq $params{'label'}) { # we found the correct slot + my $res = Amanda::Changer::compat::Reservation->new($self, $slot, $rest); Amanda::MainLoop::call_later($params{'res_cb'}, undef, $res); return; } - # on to the next slot + $load_next->(); + }; + + $run_fail_cb = sub { + my ($exitval, $message) = @_; + + # don't continue scanning after a fatal error + if ($exitval > 1) { + Amanda::MainLoop::call_later($params{'res_cb'}, $message, undef); + return; + } + + $load_next->(); + }; + + $load_next = sub { + # if we've scanned all nslots, we haven't found the label. if (++$nchecked >= $self->{'nslots'}) { Amanda::MainLoop::call_later($params{'res_cb'}, "Volume '$params{label}' not found", undef); return; - } else { - # loop again with the next slot - $res->release(); # we know this completes immediately - $self->load(slot => "next", res_cb => $check_slot); - } + } + + $self->_run_tpchanger($run_success_cb, $run_fail_cb, "-slot", "next"); }; - # kick off the loop with the current slot - $self->load(slot => "current", res_cb => $check_slot); + $self->_run_tpchanger($run_success_cb, $run_fail_cb, "-slot", "current"); } sub info { @@ -211,13 +220,16 @@ sub _simple_op { my $op = shift; my %params = @_; + Amanda::Debug::debug("running simple op '$op'"); my $run_success_cb = sub { + Amanda::Debug::debug("simple op '$op' ok"); if (exists $params{'finished_cb'}) { $params{'finished_cb'}->(undef); } }; my $run_fail_cb = sub { my ($exitval, $message) = @_; + Amanda::Debug::debug("simple op '$op' failed: $message"); if (exists $params{'finished_cb'}) { $params{'finished_cb'}->($message); } @@ -240,6 +252,14 @@ sub clean { $self->_simple_op("clean", %params); } +sub eject { + my $self = shift; + my %params = @_; + + # note: parameter 'drive' is ignored + $self->_simple_op("eject", %params); +} + sub update { my $self = shift; my %params = @_; @@ -413,8 +433,13 @@ sub _run_tpchanger { # everything is finished -- process the results and invoke the callback chomp $child_output; - # handle fatal errors - if (!POSIX::WIFEXITED($child_exit_status) || POSIX::WEXITSTATUS($child_exit_status) > 1) { + # mark this object as no longer busy. This frees the + # object up to begin the next operation, which may happen + # during the invocation of the callback + $self->{'busy'} = 0; + + # handle unexpected exit status as a fatal error + if (!POSIX::WIFEXITED($child_exit_status) || POSIX::WEXITSTATUS($child_exit_status) > 2) { $failure_cb->(POSIX::WEXITSTATUS($child_exit_status), "Fatal error from changer script: ".$child_output); return; @@ -422,19 +447,20 @@ sub _run_tpchanger { # parse the child's output my @child_output = split '\n', $child_output; - $failure_cb->(2, "Malformed output from changer script -- no output") - if (@child_output < 1); - $failure_cb->(2, "Malformed output from changer script -- too many lines") - if (@child_output > 1); - $failure_cb->(2, "Malformed output from changer script: '$child_output[0]'") - if ($child_output[0] !~ /\s*([^\s]+)(?:\s+(.+))?/); + if (@child_output < 1) { + $failure_cb->(2, "Malformed output from changer script -- no output"); + return; + } + if (@child_output > 1) { + $failure_cb->(2, "Malformed output from changer script -- too many lines"); + return; + } + if ($child_output[0] !~ /\s*([^\s]+)(?:\s+(.+))?/) { + $failure_cb->(2, "Malformed output from changer script: '$child_output[0]'"); + return; + } my ($slot, $rest) = ($1, $2); - # mark this object as no longer busy. This frees the - # object up to begin the next operation, which may happen - # during the invocation of the callback - $self->{'busy'} = 0; - # let the callback take care of any further interpretation my $exitval = POSIX::WEXITSTATUS($child_exit_status); if ($exitval == 0) { @@ -481,6 +507,8 @@ package Amanda::Changer::compat::Reservation; use vars qw( @ISA ); @ISA = qw( Amanda::Changer::Reservation ); +use Amanda::Debug qw( :logging ); + sub new { my $class = shift; my ($chg, $slot, $device_name) = @_; @@ -502,7 +530,21 @@ sub do_release { my $self = shift; my %params = @_; - $self->{'chg'}->{'reserved'} = 0; + my $finished = sub { + my ($msg) = @_; + + $self->{'chg'}->{'reserved'} = 0; + + if (exists $params{'finished_cb'}) { + Amanda::MainLoop::call_later($params{'finished_cb'}, $msg); + } + }; + + if (exists $params{'eject'} && $params{'eject'}) { + $self->{'chg'}->eject(finished_cb => $finished); + } else { + $finished->(undef); + } } sub set_label {