⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 changer.pm

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 PM
字号:
# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.## This program is free software; you can redistribute it and/or modify it# under the terms of the GNU General Public License version 2 as published# by the Free Software Foundation.## 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 General Public License# for more details.## 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, 505 N Mathlida Ave, Suite 120# Sunnyvale, CA 94085, USA, or: http://www.zmanda.compackage Amanda::Changer;use Carp;use POSIX ();use Exporter;@ISA = qw( Exporter );@EXPORT_OK = qw(    reset clean eject label    query loadslot find scan);use Amanda::Paths;use Amanda::Util;use Amanda::Device qw( :constants );use Amanda::Config qw( :getconf );=head1 NAMEAmanda::Changer -- interface to changer scripts=head1 SYNOPSIS  use Amanda::Changer;  my ($error, $slot) = Amanda::Changer::reset();  my ($nslots, $curslot, $backwards, $searchable) = Amanda::Changer::query();  my ($tpslot, $tpdevice) = Amanda::Changer::find("TAPE018");  sub slot_callback {    my ($slot, $device, $error) = @_;    if (!$error) print "Slot $slot: $device\n";    return 0;  }  Amanda::Changer::scan(\&slot_callback);=head1 API STATUSStable=head1 FUNCTIONSAll of these functions return an array of values, beginning withC<$error>, and containing any other results appropriate to theoperation.The functions C<croak()> in the event of a serious error (problemsrunning the changer script, or an exit status of 2 or higher)."Benign" errors, corresponding to an exit status of 1 or a slot named"<error>", result in the return of a single-element array containingthe error message.  Error-handling for calls can be writtenC<$error> and C<$slot>.  The first is false unless a "benign"error, such as a positioning error, has occurred, in which case itcontains the message from the changer script, and the other resultsare undefined.  C<$slot> is the first word returned from the changerscript, and is usually a number, but occasionally a string such as"<none>".=over=item reset  my ($error, $slot) = reset();Resets the tape changer, if supported, by calling  $tpchanger -reset=item clean  my ($error, $slot) = clean();Triggers a cleaning cycle, if supported, by calling  $tpchanger -clean=item eject  my ($error, $slot) = eject();Ejects the tape in the current slot, if supported, by calling  $tpchanger -eject=item label  my ($error) = label($label);Inform the changer that the tape in the current slot is labeled C<$label>.  Calls  $tpchanger -label $label=item query  my ($error, $slot, $nslots, $backwards, $searchable) = query();Query the changer to determine the current slot (C<$slot>), thenumber of slots (C<$nslots>), whether it can move backward through tapes(C<$backwards>), and whether it is searchable (that is, has a barcodereader; C<$searchable>).  A changer which cannot move backward throughtapes is also known as a gravity feeder.This function runs  $tpchanger -info=item loadslot  my ($error, $slot, $device) = loadslot($desired_slot);Load the tape in the given slot, returning its slot and device.C<$desired_slot> can be a numeric slot number or one of the symbolicnames defined by the changer API, e.g., "next", "current", or "first".  $tpchanger -slot $slot=item find  my ($error, $tpslot, $tpdevice) = Amanda::Changer::find($label);Search the changer for a tape with the given label, returning withC<$tpslot = "<none>"> if the given label is not found.If the changer is searchable, this function calls  $tpchanger -search $labelOtherwise it scans all slots in order, beginning with the current slot,until it finds one with a label equal to C<$label> or exhausts allslots.  Note that it is considered a fatal error if the label is notfound.=item scan  my ($error) = Amanda::Changer::scan(\&slot_callback);Call C<slot_callback> for all slots, beginning with the current slot,until C<slot_callback> returns a nonzero value or all slots areexhausted.  C<slot_callback> gets three arguments: a slot number, adevice name for that slot, and a boolean value which is true if thechanger successfully loaded the slot.=cutsub reset {    my ($error, $slot, $rest) = run_tpchanger("-reset");    return ($error) if $error;    return (0, $slot);}sub clean {    my ($error, $slot, $rest) = run_tpchanger("-clean");    return ($error) if $error;    return (0, $slot);}sub eject {    my ($error, $slot, $rest) = run_tpchanger("-eject");    return ($error) if $error;    return (0, $slot);}sub label {    my ($label) = @_;    my ($error, $slot, $rest) = run_tpchanger("-label", $label);    return ($error) if $error;    return (0);}sub query {    my ($error, $slot, $rest) = run_tpchanger("-info");    return ($error) if $error;    # old, unsearchable changers don't return the third result, so it's optional in the regex    $rest =~ /(\d+) (\d+) ?(\d+)?/ or croak("Malformed response from changer -seek: $rest");    # return array: error, nslots, curslot, backwards, searchable    return (0, $slot, $1, $2, $3?1:0);}sub loadslot {    my ($desired_slot) = @_;    my ($error, $slot, $rest) = run_tpchanger("-slot", $desired_slot);    return ($error) if $error;    return (0, $slot, $rest);}sub find {    my ($label) = @_;    my ($error, $curslot, $nslots, $backwards, $searchable) = query();    return ($error) if $error;    if ($searchable) {        # search using the barcode reader, etc.        my ($error, $slot, $rest) = run_tpchanger("-search", $label);        return ($error) if $error;        return ($error, $slot, $rest);    } else {        # search manually, starting with "current"        my $slotstr = "current";        for (my $checked = 0; $checked < $nslots; $checked++) {            my ($error, $slot, $rest) = run_tpchanger("-slot", $slotstr);            $slotstr = "next";            # ignore "benign" errors            next if $error;            my $device = Amanda::Device->new($rest);            next if (!$device);            next if ($device->read_label() != $READ_LABEL_STATUS_SUCESS);            # we found it!            if ($device->{'volume_label'} eq $label) {                return (0, $slot, $rest);            }        }        croak("Label $label not found in any slot");    }}sub scan {    my ($slot_callback) = @_;    my ($error, $curslot, $nslots, $backwards, $searchable) = query();    return ($error) if $error;    my $slotstr = "current";    my $done = 0;    for (my $checked = 0; $checked < $nslots; $checked++) {        my ($error, $slot, $rest) = run_tpchanger("-slot", $slotstr);        $slotstr = "next";        if ($error) {            $done = $slot_callback->(undef, undef, $error);        } else {            $done = $slot_callback->($slot, $rest, 0);        }        last if $done;    }        return (0);}# Internal-use function to actually invoke a changer script and parse # its output.  If the script's exit status is neither 0 nor 1, or if an error# occurs running the script, then run_tpchanger croaks with the error message.## @params @args: command-line arguments to follow the name of the changer# @returns: array ($error, $slot, $rest), where $error is an error message if#       a benign error occurred, or 0 if no error occurredsub run_tpchanger {    my @args = @_;    # get the tape changer and extend it to a full path    my $tapechanger = getconf($CNF_TPCHANGER);    if ($tapechanger !~ qr(^/)) {        $tapechanger = "$amlibexecdir/$tapechanger";    }    my $pid = open(my $child, "-|");    if (!defined($pid)) {        croak("Can't fork to run changer script: $!");    }    if (!$pid) {        # child        # cd into the config dir, if one exists        # TODO: construct a "fake" config dir including any "-o" overrides        my $config_dir = Amanda::Config::get_config_dir();        if ($config_dir) {            if (!chdir($config_dir)) {                print "<error> Could not chdir to '$config_dir'\n";                exit(2);            }        }        %ENV = Amanda::Util::safe_env();        exec { $tapechanger } $tapechanger, @args or            print "<error> Could not exec $tapechanger: $!\n";        exit 2;    }    # parent    my @child_output = <$child>;    # close the child and get its exit status    my $child_exit = 0;    if (!close($child)) {        if ($!) {            croak("Error running changer script: $!");        } else {            $child_exit = $?;        }    }    # parse the response    croak("Malformed output from changer script -- no output")        if (@child_output < 1);    croak("Malformed output from changer script -- too many lines")        if (@child_output > 1);    croak("Malformed output from changer script: '$child_output[0]'")        if ($child_output[0] !~ /\s*([^\s]+)\s+(.+)?/);    my ($slot, $rest) = ($1, $2);    if ($child_exit == 0) {        return (0, $slot, $rest);    } elsif (POSIX::WIFEXITED($child_exit) && POSIX::WEXITSTATUS($child_exit) == 1) {        return ($rest); # non-fatal error    } else {        croak("Fatal error from changer script: $rest");    }}1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -