#!/usr/bin/perl

#
# COPYRIGHT    2000
# THE REGENTS OF THE UNIVERSITY OF MICHIGAN
# ALL RIGHTS RESERVED
#
# Permission is granted to use, copy, create derivative works
# and redistribute this software and such derivative works
# for any purpose, so long as the name of The University of
# Michigan is not used in any advertising or publicity
# pertaining to the use of distribution of this software
# without specific, written prior authorization.  If the
# above copyright notice or any other identification of the
# University of Michigan is included in any copy of any
# portion of this software, then the disclaimer below must
# also be included.
#
# THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
# FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
# PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY O
# MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
# WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
# REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
# FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
# CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
# OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
# IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGES.
#

use strict;
use Getopt::Long;

#=======================================================================#
#
# This script emulates enough "chio" functionality using the 'mover'
# program from Gerd Knorr's distribution to allow vault operation.
# see http://www.bytesex.org for the mover user-level program and
# required kernel patch 
#
#=======================================================================#

my %opts;
my $opts;
my $debug = 0;
my $chio_device;
my $chio_cmd;
my $mover_cmd = "mover";

#########################################################################
#############  M A I N   E X E C U T I O N   P O I N T  #################
#########################################################################

process_arguments();

exit;

#########################################################################
#############           S U B R O U T I N E S           #################
#########################################################################

sub process_arguments {
	my $i;
	my $numargs = $#ARGV + 1;
	if ($debug > 0) {
		print "$0: entered with $numargs parms: ";
		for ($i = 0; $i <= $#ARGV; $i++) {
			print "$ARGV[$i] "
		}
		print "\n";
	}
	
	if ($ARGV[0] eq "-f") {
		shift @ARGV;
		$chio_device = shift @ARGV;
		print "Got device name $chio_device\n" if ($debug > 0 );
	}

	$chio_cmd = shift @ARGV;
	print "Got command $chio_cmd\n" if ($debug > 0);

	for ($chio_cmd) {
	  /move/ and do {
		handle_move_cmd();
		last;
	  };
	  /status/ and do {
		handle_status_cmd();
		last;
	  };
	  /exchange/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /return/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /position/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /params/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /getpicker/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /setpicker/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /ielem/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  /voltag/ and do {
		print "Sorry, the $chio_cmd command is not implemented\n";
		exit(1);
		last;
	  };
	  die "$0: unimplemented command '$chio_cmd'\n";
	}
}

sub chio_to_mover_type {
	my ($chio_t) = @_;
	my $mover_t;

	for ($chio_t) {
	  /drive/	and do { $mover_t = "d"; last; };
	  /slot/	and do { $mover_t = "s"; last; };
	  /portal/	and do { $mover_t = "e"; last; };
	  /picker/	and do { $mover_t = "t"; last; };
	  die "invalid chio type '$chio_t' in chio_to_mover_type\n";
	}
	return $mover_t;
}

sub check_system_rc {
        my ($description, $rc, $dbg, @args) = @_;

        if ( $rc == 0) {
                print $description, " completed successfully!\n" if ($dbg);
                return 0;
        }
        elsif ( $rc == 0xff00 )  {
                print $description, " failed: !$\n";
                return 1;
        }
        elsif ( $rc > 0x80 ) {
                $rc >>= 8;
                print $description, " returned with status $rc\n";
                return 1;
        }
        else {
                my $coredump = 0;
                if ( $rc & 0x80 ) {
                        $rc &= ~0x80;
                        $coredump = 1;
                }
                printf $description, " ended from signal %d (%s a core dump)\n",
                        $rc, $coredump ? "with" : "without";
                return 1;
        }
}

sub handle_move_cmd {
	my $rc;
	if ($#ARGV < 3) {
		print "Missing parameter for $chio_cmd\n";
		exit;
	}
	if ($#ARGV >= 4) {
		print "Ignoring extra move parameters: ";
		for (my $i = 4; $i <= $#ARGV; $i++) { print "'$ARGV[$i]' "; }
		print "\n";
	}

	my ($from_t, $from_u, $to_t, $to_u) = @ARGV;
	print "moving from $from_t $from_u to $to_t $to_u\n" if ($debug > 0);

	$from_t = chio_to_mover_type($from_t);
	$to_t = chio_to_mover_type($to_t);

	my $from = $from_t . $from_u;
	my $to = $to_t . $to_u;
	$rc = system($mover_cmd, "mv", $from, $to);
	die "$0: mover command failed!" if (check_system_rc("mover", $rc, 0));
}

sub handle_status_cmd {
	my $specific_type = "";
	my @mover_output;
	my @chio_output;
	my $i;

	if ($#ARGV >= 0) {
		$specific_type = shift @ARGV;	
		print "Doing status for type $specific_type\n" if ($debug > 0);
	}
	@mover_output = `$mover_cmd`;
	print "After mover, #mover_output is $#mover_output\n" if ($debug > 0);
	die "$0: mover command failed!" if ($#mover_output < 0);
	print "The mover output was:\n***\n@mover_output***\n" if ($debug > 0);
	translate_mover_to_chio(\@mover_output, \@chio_output, $specific_type);
	print "The chio  output is:\n***\n@chio_output***\n" if ($debug > 0);
	for ($i = 0; $i < scalar(@chio_output); $i++) {
		print @chio_output[$i];
	}
}

sub translate_mover_to_chio {
	my ($mref, $cref, $type) = @_;
	my ($i, $j);
	my $mover_line;
	my $chio_line;
	my $current_type = "";
	my $skip;

	$j = 0;
	while ($mover_line = shift @$mref) {
		# the mover output has header lines for each type
		chomp($mover_line);
		$skip = 0;
		for ($mover_line) {
		  /st=/			and do { $skip = 1; last; };
		  /medium transport/	and do { $current_type = "picker"; 
						 $skip = 1;
						 last; };
		  /storage/		and do { $current_type = "slot";
						 $skip = 1;
						 last; };
		  /import\/export/	and do { $current_type = "portal";
						 $skip = 1;
						 last; };
		  /data transfer/	and do { $current_type = "drive";
						 $skip = 1;
						 last; };
		}
		if ($skip != 1) {
			if ($type eq "" or $type eq $current_type) {
				$chio_line = translate_mover_to_chio_line($mover_line, $current_type);
				$$cref[$j] = $chio_line;
				$j++;
			}
		}
	}
}

sub translate_mover_to_chio_line {
	my ($mover_line, $type) = @_;
	my ($rawflags, $flags, $contents, $unit);
	my ($chio_line);

	$flags = ""; $contents = ""; $unit = "";
	$chio_line = "";

	# There are three variations on the mover output lines
	print "tm2c: mover_line: '$mover_line'\n" if ($debug > 0);
	if ($mover_line =~ m/(.*):(.*)tag: (.*)/) {
		($unit, $rawflags, $contents) = ($1, $2, $3); 
	} elsif ($mover_line =~ m/(.*):(.*)/) {
		($unit, $rawflags) = ($1, $2);
	} elsif ($mover_line =~ m/(.*):/) {
		$unit = $1;
	}


	# Clean up the unit field (remove all spaces)
	$unit =~ s/ //g;

	# Create the flags field
	for ($rawflags) {
	  /inenab/	and do	{ $flags .= "INENAB,"; };
	  /exenab/	and do	{ $flags .= "EXENAB,"; };
	  /except/	and do	{ $flags .= "EXCEPT,"; };
	  /access/	and do	{ $flags .= "ACCESS,"; };
	  /full/	and do	{ $flags .= "FULL,"; };
	}
	chop($flags) if ($flags ne "");
	print "final flags is '$flags'\n" if ($debug > 0);

	# Clean up the contents field (remove quotes and spaces)
	$contents =~ s/[ ']//g;

	# Create the correct chio line from the various pieces
	$chio_line = "$type $unit:";
	$chio_line .= " <$flags>" if ($flags ne "");
	$chio_line .= " voltag: <$contents:0>\n";

	print "tm2c: chio_line: '$chio_line'" if ($debug > 0);
	return $chio_line;
}

#------------------------------------------------------------------------
# Parse input options.
#------------------------------------------------------------------------
sub save_this_for_some_reason {
	GetOptions( \%opts,     "debug:i",
                        "db_file:s",
                        "db_mysql:s",
                        "changer=s",
                        "drive=s",
                        "drivenum=i",
                        );

	if ( exists $opts{debug} ) {
		if ( $opts{debug} == 0 ) { $debug = 1; }
		else { $debug = $opts{debug} }
	}
	else { $debug = 0 }
}
