Imported Upstream version 2.6.1p1
[debian/amanda] / perl / Amanda / Changer / compat.pm
index 3a9693509cc6574397854e0fdf71b0e6207fafe4..4b0028b6a4d2d510f220518adeb0df7722c4a74e 100644 (file)
@@ -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 {