Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Changer / single.pm
index 33bf2913501f02e13abae9ba53dee4799e0a2f6b..8417d02a0e5a0034544445f28d1c14dfecd42a57 100644 (file)
@@ -1,25 +1,27 @@
-# Copyright (c) 2005-2008 Zmanda, Inc.  All Rights Reserved.
+# Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
 #
-# This library is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License version 2.1 as
-# published by the Free Software Foundation.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
 #
-# This library is distributed in the hope that it will be useful, but
+# This program is distributed in the hope that it will be useful, but
 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-# License for more details.
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
 #
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 #
-# Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
-# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
+# Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
+# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
 
 package Amanda::Changer::single;
 
 use strict;
 use warnings;
+use Carp;
 use vars qw( @ISA );
 @ISA = qw( Amanda::Changer );
 
@@ -29,6 +31,7 @@ use Amanda::Config qw( :getconf );
 use Amanda::Debug;
 use Amanda::Changer;
 use Amanda::MainLoop;
+use Amanda::Device qw( :constants );
 
 =head1 NAME
 
@@ -42,20 +45,25 @@ into something similar to the old C<chg-manual>.
 Whatever you load, you get the volume in the drive.  The volume's either
 reserved or not.  All pretty straightforward.
 
-=head1 TODO
-
-Support notifying the user that a tape is required, and some kind of "OK,
-loaded" feedback mechanism -- perhaps a utility script of some sort, or an
-amtape subcommand?
+See the amanda-changers(7) manpage for usage information.
 
 =cut
 
 sub new {
     my $class = shift;
-    my ($cc, $tpchanger) = @_;
+    my ($config, $tpchanger) = @_;
     my ($device_name) = ($tpchanger =~ /chg-single:(.*)/);
 
+    # check that $device_name is an honest-to-goodness device
+    my $tmpdev = Amanda::Device->new($device_name);
+    if ($tmpdev->status() != $DEVICE_STATUS_SUCCESS) {
+       return Amanda::Changer->make_error("fatal", undef,
+           message => "chg-single: error opening device '$device_name': " .
+                       $tmpdev->error_or_status());
+    }
+
     my $self = {
+       config => $config,
        device_name => $device_name,
        reserved => 0,
     };
@@ -67,35 +75,74 @@ sub new {
 sub load {
     my $self = shift;
     my %params = @_;
+    $self->validate_params('load', \%params);
 
-    die "no res_cb supplied" unless (exists $params{'res_cb'});
+    return if $self->check_error($params{'res_cb'});
+
+    confess "no res_cb supplied" unless (exists $params{'res_cb'});
 
     if ($self->{'reserved'}) {
-       Amanda::MainLoop::call_later($params{'res_cb'},
-           "'{$self->{device_name}}' is already reserved", undef);
-    } else {
-       Amanda::MainLoop::call_later($params{'res_cb'},
-               undef, Amanda::Changer::single::Reservation->new($self));
+       return $self->make_error("failed", $params{'res_cb'},
+           reason => "volinuse",
+           message => "'$self->{device_name}' is already reserved");
+    }
+
+    if (keys %{$params{'except_slots'}} > 0) {
+       return $self->make_error("failed", $params{'res_cb'},
+               reason => "notfound",
+               message => "all slots have been loaded");
+    }
+
+    my $device = Amanda::Device->new($self->{'device_name'});
+    if ($device->status() != $DEVICE_STATUS_SUCCESS) {
+       return $self->make_error("fatal", $params{'res_cb'},
+           message => "error opening device '$self->{device_name}': " . $device->error_or_status());
+    }
+
+    if (my $msg = $self->{'config'}->configure_device($device)) {
+       # a failure to configure a device is fatal, since it's probably
+       # a user configuration error (and thus unlikely to work for the
+       # next device, either)
+       return $self->make_error("fatal", $params{'res_cb'},
+           message => $msg);
     }
+
+    my $res = Amanda::Changer::single::Reservation->new($self, $device);
+    $device->read_label();
+    $params{'res_cb'}->(undef, $res);
 }
 
-sub info {
+sub inventory {
     my $self = shift;
     my %params = @_;
+
+    my @inventory;
+    my $s = { slot => 0,
+             state => undef,
+             device_status => undef,
+             f_type => undef,
+             label => undef };
+    push @inventory, $s;
+
+    $params{'inventory_cb'}->(undef, \@inventory);
+}
+
+sub info_key {
+    my $self = shift;
+    my ($key, %params) = @_;
     my %results;
 
-    die "no info_cb supplied" unless (exists $params{'info_cb'});
-    die "no info supplied" unless (exists $params{'info'});
+    return if $self->check_error($params{'info_cb'});
 
-    for my $inf (@{$params{'info'}}) {
-        if ($inf eq 'num_slots') {
-            $results{$inf} = 1;
-        } else {
-            warn "Ignoring request for info key '$inf'";
-        }
+    if ($key eq 'num_slots') {
+       $results{$key} = 1;
+    } elsif ($key eq 'fast_search') {
+       # (asking the user for a specific label is faster than asking
+       # for each "slot" in a sequential scan, so search is "fast")
+       $results{$key} = 0;
     }
 
-    Amanda::MainLoop::call_later($params{'info_cb'}, undef, %results);
+    $params{'info_cb'}->(undef, %results) if $params{'info_cb'};
 }
 
 package Amanda::Changer::single::Reservation;
@@ -104,14 +151,14 @@ use vars qw( @ISA );
 
 sub new {
     my $class = shift;
-    my ($chg, $drive, $next_slot) = @_;
+    my ($chg, $device) = @_;
     my $self = Amanda::Changer::Reservation::new($class);
 
     $self->{'chg'} = $chg;
 
-    $self->{'device_name'} = $chg->{'device_name'};
+    $self->{'device'} = $device;
+
     $self->{'this_slot'} = '1';
-    $self->{'next_slot'} = '1';
     $chg->{'reserved'} = 1;
 
     return $self;
@@ -121,5 +168,14 @@ sub do_release {
     my $self = shift;
     my %params = @_;
 
+    $self->{'device'}->eject() if (exists $self->{'device'} and
+                                  exists $params{'eject'} and
+                                  $params{'eject'});
+
     $self->{'chg'}->{'reserved'} = 0;
+
+    # unref the device, for good measure
+    $self->{'device'} = undef;
+
+    $params{'finished_cb'}->(undef) if $params{'finished_cb'};
 }