#
# Copyright (c) 1990,1991,1992 The Ohio State University.
# All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that: (1) source distributions retain this entire copyright
# notice and comment, and (2) distributions including binaries display
# the following acknowledgement:  ``This product includes software
# developed by The Ohio State University and its contributors''
# in the documentation or other materials provided with the distribution
# and in all advertising materials mentioning features or use of this
# software. Neither the name of the University nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#

#
# Add a tape to the tape database, sticking a label on the tape in the process.
#
# Steve Romig, January 29, 1990.
# Converted to new DB stuff: July 2, 1990
#

require 'global.defs';
require 'local.defs';
require $yagrip_perl;
require $backuplib_perl;

$options = "ht:Ud:f:el:p:";
$usage = "usage: add-tape [-t tape[:tape]] [-f host:dev] [-U] [-e] 
  [-p prefix] [-l location] [-d debuglevel] [-h] 
    -t tape		specifies an explicit tape ID to use.  Use
			N:M to add a range of tapes.
    -f host:device	specifies the tape drive to use.
    -U			unsafe mode - don't check tape labels.
    -e                  don't eject the tape.
    -p prefix		prefix to use instead of [config-]type-
    -l location		home location for these tapes
    -d debuglevel	turns on debugging output.
    -h			display this message.\n";

    #
    # Make sure that we clean up after ourselves if someone wants to kill us.
    #
$SIG{'INT'} = 'handle_interrupts';
$SIG{'HUP'} = 'handle_interrupts';
$SIG{'TERM'} = 'handle_interrupts';
$SIG{'QUIT'} = 'handle_interrupts';

&read_config();

    #
    # Deal with arguments...
    #
die $usage if ! &getopt($options);
die $usage if $#ARGV != -1;
die $usage if defined($opt_h);

    #
    # Where's the tape...need this first to get the type of tape that 
    # we'll be dealing with.
    #
($drive_name, $tape_user, $tape_host, $tape_dev) = 
  &get_tape_name("", "", "");

$rsh = &make_rsh_cmd($tape_user, $tape_host);
print "tapehost $tape_host, dev $tape_dev\n" if $opt_d & $DEBUG_INFO;

if (! defined($tape_device{$drive_name})) {
    ($tape_type{$drive_name}, $tape_reads{$drive_name},
     $tape_writes{$drive_name}, $tape_status_ok{$drive_name}) =
       &get_tape_extra_info($drive_name);
}

if (defined($opt_l)) {
    $location = $opt_l;
    if (! defined($known_locations{$location})) {
	die "error (add-tape): $location isn't a known tape storage location.  See backup.config.\n";
    }
} else {
    $location = $tape_location{$drive_name};
}

if (defined($opt_p)) {
    $prefix = $opt_p;
} else {
    $prefix = "";
}

    #
    # Get the range of tape IDs that we are making.
    #
if (defined($opt_t)) {
    $n = ($tape_low, $tape_high) = split(/:/, $opt_t);
    die $usage if $n < 1 || $n > 2;
    $tape_high = $tape_low if $n == 1;

    foreach $num ($tape_low, $tape_high) {
	if ($num !~ m/[0-9]+/) {
	    die "error (add-tape): Invalid tape number '$num - must be an integer!\n";
	}
    }

    $tape_low += 0; $tape_high += 0;

    for ($tape_num = $tape_low; $tape_num <= $tape_high; $tape_num++) {
	#
	# Construct a proper tape ID from this number.
	#
	$tape_id = &make_tape_id_from_number($tape_type{$drive_name}, $tape_num, $prefix);

	&make_tape($tape_id);
    }
} else {
    &make_tape(&get_tape_id($tape_type{$drive_name}, $prefix));
}

exit(0);

sub make_tape {
    local($tape_id) = @_;

    &make_log_entry("add-tape, using tape number $tape_id");

    if (! &update_db($tape_db_file, $tape_db_file, $tape_id, "tape_db",
		     $DB_READ, *replace, *add, *result)) {
        print "warning: there's already a tape with ID $tape_id in the database.\n";
	$answer = &askdef("Do you really want to use this ID again", "no",
"Type 'no' if you do not want to use this tape ID number again.  If you 
are absolutely, positively certain that you want to re-use this tape ID
number, then type 'yes'.  Note that if that tape ID is already in use by 
another tape, and if that tape has a backup run on it, the next time 
'clean-db' runs that backup run will be deleted from the database.\n");
	return if $answer ne "y" && $answer ne "yes";
    }

    #
    # Tell the user how to label the tape...
    #
    print "This will be tape $tape_id\n";

  load_loop:
    {
	$| = 1;
	print "Load the tape and press return please.";
	<stdin>;
	$| = 0;

	if (! defined($opt_U)) {
	    if ($tape_status_ok{$drive_name}) {
		#
		# If this tape drive deals with 'mt status' correctly, then 
		# we should make sure that we are at file 0, block 0 before 
		# trying to read the tape label (avoid repositioning the tape 
		# in case its the wrong one!). 
		#
		if (&tape_position($rsh, $tape_dev, *file_number, *block_number)) {
		    print stderr "warning: cannot get tape position information\n";
		    print stderr "skipping to the next tape.\n";
		    redo load_loop;
		}

		if ($file_number ne "0" || $block_number != "0") {
		    print stderr "warning: tape position is wrong - this might be the wrong tape!\n";
		    print stderr "skipping to the next tape.\n";
		    redo load_loop;
		}
	    }

	    #
	    # Check the tape label if there is one
	    #
	    $cmd = "$rsh $dd_prog if=$tape_dev count=1 |";

	    print "system: $cmd\n" if $opt_d & $DEBUG_SYSTEM;

	    open(LABEL, $cmd) || do {
		print 
"warning: can't start dd to read the tape label.  
Are you sure that the tape is mounted?\n";
		redo load_loop;
	    };

	    chop($label = <LABEL>);
	    ($magic, $garbage, $number) = split(/[ \t\n]+/, $label);

	    close(LABEL);
	    
	    if ($magic eq $tape_magic) {
		print stderr "warning: it looks like this tape already has a label on it (id $number).\n";
		$answer = &askdef("Do you really want to relabel this tape", "no",
"Type 'no' if you do not want to relabel this tape.  If you are
absolutely, positively certain that you want to label this tape
despite the fact that it already has a label then type 'yes'.\n");
		redo load_loop if $answer ne "y" && $answer ne "yes";
	    }
	}
    }

    #
    # Write the tape label
    #
    if (&tape_put_label($rsh, $tape_dev, "$tape_magic T# $tape_id\n\n")) {
	print stderr "warning: couldn't write the tape label\n";
	return;
    }

    #
    # Update the database entry for that tape number...
    #
    if ($tape_host eq "") {
	$tape_host = $hostname;
    }
    
    #
    # Open the tape dbm file.
    #
    %replace = ();
    $replace{"uses"} = 0;
    $replace{"add_date"} = time;
    $replace{"used_date"} = time;
    $replace{"drive"} = $tape_host . ":" . $tape_dev;
    $replace{"flags"} = "free";
    $replace{"type"} = $tape_type{$drive_name};
    $replace{"format"} = $tape_writes{$drive_name};
    if ($location ne "") {
	$replace{"location"} = $location;
	$replace{"home"} = $location;
    }
    %add = ();
	
    &update_db($tape_db_file,
	       $tape_db_file,
	       $tape_id,
	       "tape_db",
	       $DB_CREATE,
	       *replace,
	       *add,
	       *result);

    #
    # eject the tape
    #
    if (! defined($opt_e)) {
        &tape_offload($rsh, $tape_dev);
    }
}

sub get_tape_id {
    local($type, $prefix) = @_;
    local($i, $id);

    #
    # open the database in question...
    #
    &open_db(*DB, $tape_db_file, $db_mode) ||
      &sigh("can't open the database $tape_db_file on $hostname in $0\n");

    for ($i = 1; 1; $i++) {
	$id = &make_tape_id_from_number($type, $i, $prefix);
	if (! &defined_db(*DB, $id)) {
	    &close_db(*DB, $tape_db_file);
	    return($id);
	}
    }

    &close_db(*DB, $tape_db_file);
}
