Imported Upstream version 3.3.0
[debian/amanda] / server-src / amlabel.pl
index f9103b8cb1f0d06cbadf0d5257d8376dc60fdeb4..77a5115c49e4b61825d43203ba8032266f2fe066 100644 (file)
@@ -42,7 +42,8 @@ my $exit_status = 0;
 my %subcommands;
 
 sub usage {
-    print STDERR "Usage: amlabel [-f] [-o configoption]* <conf> <label> [slot <slot-number>]\n";
+    print STDERR "Usage: amlabel [--barcode <barcode>] [--meta <meta>] [--assign] [--version]\n"
+              . "               [-f] [-o configoption]* <conf> [<label>] [slot <slot-number>]\n";
     exit(1);
 }
 
@@ -50,27 +51,46 @@ Amanda::Util::setup_application("amlabel", "server", $CONTEXT_CMDLINE);
 
 my $config_overrides = new_config_overrides($#ARGV+1);
 my ($opt_force, $opt_config, $opt_slot, $opt_label);
+my ($opt_barcode, $opt_meta, $opt_assign);
 
 $opt_force = 0;
+$opt_barcode = undef;
+$opt_meta = undef;
+$opt_assign = undef;
 Getopt::Long::Configure(qw(bundling));
 GetOptions(
     'help|usage|?' => \&usage,
-    'o=s' => sub { add_config_override_opt($config_overrides, $_[1]); },
-    'f' => \$opt_force,
-    'version' => \&Amanda::Util::version_opt,
+    'o=s'        => sub { add_config_override_opt($config_overrides, $_[1]); },
+    'f'          => \$opt_force,
+    'barcode=s'  => \$opt_barcode,
+    'meta=s'     => \$opt_meta,
+    'assign'     => \$opt_assign,
+    'version'    => \&Amanda::Util::version_opt,
 ) or usage();
 
-if (@ARGV == 2) {
+if ($opt_assign && (!$opt_meta || !$opt_barcode)) {
+    print STDERR "--assign require --barcode or --meta\n";
+    usage();
+}
+
+usage() if @ARGV == 0;
+$opt_config = $ARGV[0];
+if (@ARGV == 1) {
+    $opt_slot = undef;
+    $opt_label = undef;
+} elsif (@ARGV == 2) {
     $opt_slot = undef;
+    $opt_label = $ARGV[1];
+} elsif (@ARGV == 3 and $ARGV[1] eq 'slot') {
+    $opt_slot = $ARGV[2];
+    $opt_label = undef;
 } elsif (@ARGV == 4 and $ARGV[2] eq 'slot') {
     $opt_slot = $ARGV[3];
+    $opt_label = $ARGV[1];
 } else {
     usage();
 }
 
-$opt_config = $ARGV[0];
-$opt_label = $ARGV[1];
-
 set_config_overrides($config_overrides);
 config_init($CONFIG_INIT_EXPLICIT_NAME, $opt_config);
 my ($cfgerr_level, @cfgerr_errors) = config_errors();
@@ -102,13 +122,18 @@ sub failure {
 
 sub main {
     my ($finished_cb) = @_;
+    my $gerr;
+    my $chg;
+    my $dev;
+    my $dev_ok;
 
     my $steps = define_steps
-       cb_ref => \$finished_cb;
+       cb_ref => \$finished_cb,
+       finalize => sub { $chg->quit() if defined $chg };
 
     step start => sub {
        my $labelstr = getconf($CNF_LABELSTR);
-       if ($opt_label !~ /$labelstr/) {
+       if (defined ($opt_label) && $opt_label !~ /$labelstr/) {
            return failure("Label '$opt_label' doesn't match labelstr '$labelstr'.", $finished_cb);
        }
 
@@ -117,7 +142,17 @@ sub main {
        if (!defined $tl) {
            return failure("Can't load tapelist file ($tlf)", $finished_cb);
        }
-       if (!$opt_force) {
+
+       $chg = Amanda::Changer->new(undef, tapelist => $tl);
+
+       return failure($chg, $finished_cb)
+           if $chg->isa("Amanda::Changer::Error");
+
+       if ($opt_assign) {
+           return $steps->{'assign'}->();
+       }
+
+       if (defined($opt_label) && !$opt_force) {
            if ($tl->lookup_tapelabel($opt_label)) {
                return failure("Label '$opt_label' already on a volume", $finished_cb);
            }
@@ -127,28 +162,48 @@ sub main {
     };
 
     step load => sub {
-       my $chg = Amanda::Changer->new();
-
-       return failure($chg, $finished_cb)
-           if $chg->isa("Amanda::Changer::Error");
-
        print "Reading label...\n";
        if ($opt_slot) {
            $chg->load(slot => $opt_slot, mode => "write",
-                   res_cb => $steps->{'loaded'});
+                      res_cb => $steps->{'loaded'});
+       } elsif ($opt_barcode) {
+           $chg->inventory(inventory_cb => $steps->{'inventory'});
        } else {
            $chg->load(relative_slot => "current", mode => "write",
-                   res_cb => $steps->{'loaded'});
+                      res_cb => $steps->{'loaded'});
        }
     };
 
+    step inventory => sub {
+       my ($err, $inv) = @_;
+
+       return failure($err, $finished_cb) if $err;
+
+       for my $sl (@$inv) {
+           if ($sl->{'barcode'} eq $opt_barcode) {
+               return $chg->load(slot => $sl->{'slot'}, mode => "write",
+                                 res_cb => $steps->{'loaded'});
+           }
+       }
+
+       return failure("No volume with barcode '$opt_barcode' available", $finished_cb);
+    };
+
     step loaded => sub {
        (my $err, $res) = @_;
 
        return failure($err, $finished_cb) if $err;
 
-       my $dev = $res->{'device'};
-       my $dev_ok = 1;
+       if (defined $opt_slot && defined $opt_barcode &&
+           $opt_barcode ne $res->{'barcode'}) {
+           if (defined $res->{'barcode'}) {
+               return failure("Volume in slot $opt_slot have barcode '$res->{'barcode'}, it is not '$opt_barcode'", $finished_cb);
+           } else {
+               return failure("Volume in slot $opt_slot have no barcode", $finished_cb);
+           }
+       }
+       $dev = $res->{'device'};
+       $dev_ok = 1;
        if ($dev->status & $DEVICE_STATUS_VOLUME_UNLABELED) {
            if (!$dev->volume_header or $dev->volume_header->{'type'} == $F_EMPTY) {
                print "Found an empty tape.\n";
@@ -189,10 +244,34 @@ sub main {
            }
        }
 
+       $res->get_meta_label(finished_cb => $steps->{'got_meta'});
+    };
+
+    step got_meta => sub {
+       my ($err, $meta) = @_;
+
+       if (defined $meta && defined $opt_meta && $meta ne $opt_meta) {
+           return failure();
+       }
+       $meta = $opt_meta if !defined $meta;
+       ($meta, my $merr) = $res->make_new_meta_label() if !defined $meta;
+       if (defined $merr) {
+           return failure($merr, $finished_cb);
+       }
+       $opt_meta = $meta;
+
+       my $label = $opt_label;
+       if (!defined($label)) {
+           ($label, my $lerr) = $res->make_new_tape_label(meta => $meta);
+           if (defined $lerr) {
+               return failure($lerr, $finished_cb);
+           }
+       }
+
        if ($dev_ok) {
-           print "Writing label '$opt_label'...\n";
+           print "Writing label '$label'...\n";
 
-           if (!$dev->start($ACCESS_WRITE, $opt_label, "X")) {
+           if (!$dev->start($ACCESS_WRITE, $label, "X")) {
                return failure("Error writing label: " . $dev->error_or_status(), $finished_cb);
            } elsif (!$dev->finish()) {
                return failure("Error finishing device: " . $dev->error_or_status(), $finished_cb);
@@ -205,9 +284,9 @@ sub main {
                        $finished_cb);
            } elsif (!$dev->volume_label) {
                return failure("No label found.", $finished_cb);
-           } elsif ($dev->volume_label ne $opt_label) {
+           } elsif ($dev->volume_label ne $label) {
                my $got = $dev->volume_label;
-               return failure("Read back a different label: got '$got', but expected '$opt_label'",
+               return failure("Read back a different label: got '$got', but expected '$label'",
                        $finished_cb);
            } elsif ($dev->volume_time ne "X") {
                my $got = $dev->volume_time;
@@ -217,33 +296,105 @@ sub main {
 
            # update the tapelist
            $tl->reload(1);
-           $tl->remove_tapelabel($opt_label);
-           $tl->add_tapelabel("0", $opt_label, undef, 1, undef, $res->{'barcode'});
+           $tl->remove_tapelabel($label);
+           $tl->add_tapelabel("0", $label, undef, 1, $meta, $res->{'barcode'});
            $tl->write();
 
            print "Success!\n";
 
            # notify the changer
-           $res->set_label(label => $opt_label, finished_cb => $steps->{'labeled'});
+           $res->set_label(label => $label, finished_cb => $steps->{'set_meta_label'});
        } else {
            return failure("Not writing label.", $finished_cb);
        }
     };
 
+    step set_meta_label => sub {
+       my ($gerr) = @_;
+
+       if ($opt_meta) {
+           return $res->set_meta_label(meta => $opt_meta,
+                                       finished_cb => $steps->{'labeled'});
+       } else {
+           return $steps->{'labeled'}->();
+       }
+    };
+
     step labeled => sub {
        my ($err) = @_;
-       return failure($err, $finished_cb) if $err;
+       $gerr = $err if !$gerr;
 
        $res->release(finished_cb => $steps->{'released'});
     };
 
     step released => sub {
        my ($err) = @_;
+       return failure($gerr, $finished_cb) if $gerr;
        return failure($err, $finished_cb) if $err;
 
        $finished_cb->();
     };
+
+    step assign => sub {
+       my $tle;
+       $tle = $tl->lookup_tapelabel($opt_label);
+       if (defined $tle) {
+           my $meta = $opt_meta;
+           if (defined $meta) {
+               if (defined($tle->{'meta'}) && $meta ne $tle->{'meta'} &&
+                   !$opt_force) {
+                   return failure("Can't change meta-label with --force, old meta-label is '$tle->{'meta'}'");
+               }
+           } else {
+               $meta = $tle->{'meta'};
+           }
+           my $barcode = $opt_barcode;
+           if (defined $barcode) {
+               if (defined($tle->{'barcode'}) &&
+                   $barcode ne $tle->{'barcode'} &&
+                   !$opt_force) {
+                   return failure("Can't change barcode with --force, old barcode is '$tle->{'barcode'}'");
+               }
+           } else {
+               $barcode = $tle->{'barcode'};
+           }
+
+           $tl->reload(1);
+           $tl->remove_tapelabel($opt_label);
+           $tl->add_tapelabel($tle->{'datestamp'}, $tle->{'label'},
+                              $tle->{'comment'}, $tle->{'reuse'}, $meta,
+                              $barcode);
+           $tl->write();
+       } else {
+           return failure("Label '$opt_label' is not in the tapelist file", $finished_cb);
+       }
+
+       $chg->inventory(inventory_cb => $steps->{'assign_inventory'});
+    };
+
+    step assign_inventory => sub {
+       my ($err, $inv) = @_;
+
+       if ($err) {
+           return $finished_cb->() if $err->notimpl;
+           return failure($err, $finished_cb);
+       }
+
+       for my $sl (@$inv) {
+           if (defined $sl->{'label'} && $sl->{'label'} eq $opt_label) {
+               return $chg->set_meta_label(meta => $opt_meta,
+                                           slot => $sl->{'slot'},
+                                           finished_cb => $steps->{'done'});
+           }
+       }
+       $finished_cb->();
+    };
+
+    step done => sub {
+       $finished_cb->();
+    }
 }
+
 main(\&Amanda::MainLoop::quit);
 Amanda::MainLoop::run();
 Amanda::Util::finish_application();