#!/usr/bin/perl

# Catch for sh/csh on systems without #! ability.
eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
	& eval 'exec /usr/bin/perl -S $0 $argv:q'
		if 0;

# rth-changer - 
#   A tape changer script for the Robotic Tape Handling system OEM'd
#   by Andataco (RTH-406) for use with Amanda, the Advanced Maryland
#   Network Disk Archiver.
#
#    Author: Erik Frederick 1/10/97
#            edf@tyrell.mc.duke.edu
#
# This changer script controls the HP c1553 tape drive via a
# Peripheral Vision Inc. SCSI control subsystem that interprets
# commands sent on the SCSI bus.  It may work with other tape drives
# containing the PVI board.
#
# Permission to freely use and distribute is granted.
#

require 5.001;

use Getopt::Long;

$pname = "rth-changer";

$prefix="/usr/local";
$prefix=$prefix;		# avoid warnings about possible typo
$exec_prefix="${prefix}";
$exec_prefix=$exec_prefix;	# ditto
$sbindir="${exec_prefix}/sbin";
$libexecdir="/usr/local/libexec/amanda";
if ("no" eq "yes") {
    $suf = "-2.4.5";
} else {
    $suf = "";
}

if (-x "$sbindir/ammt$SUF") {
	$MT="$sbindir/ammt$SUF";
	$MTF="-f";
} elsif (-x "/bin/mt") {
	$MT="/bin/mt";
	$MTF="-f";
} else {
	print "<none> $pname: mt program not found\n";
	exit(1);
}

$tapeDevice=`$sbindir/amgetconf$SUF tapedev`;

sub getCurrentTape {

  if (!sysopen(RTH, $tapeDevice, 2)) {
    print "$currentTape $pname: error in opening `$tapeDevice' for getting current tape: $!\n";
    exit(2);
  }
  if (syswrite(RTH, "Rd_ElS", 6) != 6) {
    print "$currentTape $pname: error in writing `Rd_ElS' to `$tapeDevice': $!\n";
    exit(2);
  }
  if (!close(RTH)) {
    print "$currentTape $pname: error in closing `$tapeDevice' for getting current tape: $!\n";
    exit(2);
  }

  if (!sysopen(RTH, $tapeDevice, 2)) {
    print "$currentTape $pname: error in opening `$tapeDevice' for getting current tape: $!\n";
    exit(2);
  }
  if (sysread(RTH, $status, 136) != 136) {
    print "$currentTape $pname: error in reading rth status.\n";
    exit(2);
  }
  if (!close(RTH)) {
    print "$currentTape $pname: error in closing `$tapeDevice' for getting current tape: $!\n";
    exit(2);
  }

  @statusBits=unpack("c*",$status);

  if( ($statusBits[18] == 0x1) || ($statusBits[18]== 0x9)) {
    return ($statusBits[27]-1);
  }

  return (0);
}


sub getTapeStatus {

  if (!sysopen(RTH, $tapeDevice, 2)) {
    print "$currentTape $pname: error in opening `$tapeDevice' for getting tape status: $!\n";
    exit(2);
  }
  if (syswrite(RTH, "Rd_ElS", 6) != 6) {
    print "$currentTape $pname: error in writing `Rd_ElS' to `$tapeDevice': $!\n";
    exit(2);
  }
  if (!close(RTH)) {
    print "$currentTape $pname: error in closing `$tapeDevice' for getting tpae status: $!\n";
    exit(2);
  }

  if (!sysopen(RTH, $tapeDevice, 2)) {
    print "$currentTape $pname: error in opening `$tapeDevice' for getting tape status: $!\n";
    exit(2);
  }
  if (sysread(RTH, $status, 136) != 136) {
    print "$currentTape $pname: error in reading rth status for tape $currentTape.\n";
    exit(2);
  }
  if (!close(RTH)) {
    print "$currentTape $pname: error in closing `$tapeDevice' for getting tape status: $!\n";
    exit(2);
  }

  @statusBits=unpack("c*",$status);

  $curTape=0;
  for($i=42;$i<187;$i+=16) {
    if($statusBits[$i] == 0x9) {
      $slots[$curTape] = 1;
    }
    else {
      $slots[$curTape] = 0;
    }
    $curTape++;
  }

  return (@slots);
}

sub rthLoad {
  my($tape) = @_;

  $command = sprintf "GeT%d", $tape;
  if (!sysopen(RTH, $tapeDevice, 2)) {
    print "$currentTape $pname: error in opening `$tapeDevice' for loading tape: $!\n";
    exit(2);
  }
  if (syswrite(RTH, $command, 4) != 4) {
    print "$currentTape $pname: error in loading tape by writing `$command' to `$tapeDevice': $!\n";
    exit(2);
  }
  if (!close (RTH)) {
    print "$currentTape $pname: error in closing `$tapeDevice' when trying to load tape: $!\n";
    exit(2);
  }
}

sub rthUnload {
  my($tape) = @_;

  $command = sprintf "PuT%d", $tape;
  if (!sysopen(RTH, $tapeDevice, 2)) {
    print "$currentTape $pname: error in opening `$tapeDevice' for unloading tape: $!\n";
    exit(2);
  }
  if (syswrite(RTH, $command, 4) != 4) {
    print "$currentTape $pname: error in unloading tape by writing `$command' to `$tapeDevice': $!\n";
    exit(2);
  }
  if (!close (RTH)) {
    print "$currentTape $pname: error in closing `$tapeDevice' when trying to unload tape: $!\n";
    exit(2);
  }
}

sub testTape {
  my($tape) = @_;

  @slots=getTapeStatus();

  if($currentTape == $tape) {
    return;
  }

  if($slots[$tape-1] == 0) {
    print "<none> $pname: no tape in slot requested\n";
    exit(1);
  }
  if($tape>6) {
    print $tape," $pname: requested a tape > 6\n";
    exit(2);
  }
  if($tape<1) {
    print $tape," $pname: requested a tape < 1\n";
    exit(2);
  }
  return;
}

sub changeTape {
  my($tape) = @_;

  if($tape==$currentTape) {
    return;
  }

  testTape($tape);

  if($currentTape==0) {
    rthLoad($tape);
    $currentTape=$tape;
    return;
  }
  else {
    rthUnload($currentTape);
    rthLoad($tape);
    $currentTape=$tape;
  }
}
    

$result = &GetOptions("slot=s", "info", "reset", "eject"); 

system($MT, 'rewind');

$nSlots=6;
$firstTape=1;
$lastTape=6;
$currentTape=getCurrentTape(); 

if($opt_slot) {
  if($opt_slot =~ /first/) {
    changeTape(1);
    print $currentTape, " ", $tapeDevice, "\n";
  }
  if($opt_slot =~ /last/) {
    changeTape(6);
    print $currentTape, " ", $tapeDevice, "\n";
  }
  if($opt_slot =~ /current/) {
    changeTape($currentTape);
    print $currentTape, " ", $tapeDevice, "\n";
  }
  if($opt_slot =~ /next/) {
    $tape=$currentTape+1;
    if ($tape>6) {
      $tape=1;
    }
    changeTape($tape);
    print $currentTape, " ", $tapeDevice,"\n";
  }
  if($opt_slot =~ /prev/) {
    $tape=$currentTape-1;
    if($tape<1) {
      $tape=6;
    }
    changeTape($tape);
    print $currentTape, " ", $tapeDevice,"\n";
  }
  if($opt_slot =~ /\d/) {
    changeTape($opt_slot);
    print $currentTape, " ", $tapeDevice,"\n";
  }
  if($opt_slot =~ /advance/) {
    $tape=$currentTape+1;
    if ($tape>6) {
      $tape=1;
    }
    if($currentTape) { 
      rthUnload($currentTape);
    }
    print $currentTape, " ", "/dev/null","\n";
  }

  exit 0;
}

if($opt_info) {
 
  print $currentTape, " 6 1\n";

  exit 0;
}

if($opt_reset) {
  changeTape(1);
  print $currentTape, " ",$tapeDevice,"\n";
  exit 0;
}

if($opt_eject) {
  if($currentTape) { 
    rthUnload($currentTape);
    print "0 ",$tapeDevice,"\n";
    exit 0;
  } 
  else {
    print "0 $pname: drive was not loaded\n";
    exit 1;
  }
}

print "$pname: No command was received.  Exiting.\n";
exit 1;
