APPENDIX P Logical Log Tape Validator for Online 5.x



#!/usr/bin/perl5
# informix 5.x logical log tape validator

#written after some very painful experiences with informix recovery

# This software is supplied without any warrenty whatsover
# If you find it useful use it otherwise dont blame me
#  J.Clutterbuck Siemens Business Services 11th June 1997

$usage="logtape_validate.pl [-v] ltapedev\n";

#check for optional -v (verbose) argument
if ( $ARGV[0] eq "-v" ) {
    $verbose=1;
    shift @ARGV;
} else {
    $verbose=0;
}
if ( $#ARGV != 0 ) {
    die $usage;
}

$LOGTAPE=$ARGV[0];

#get environment variables
$TBCONFIG=$ENV{'TBCONFIG'} || die "Cannot evaluate TBCONFIG environment variable\n";
$INFORMIXDIR=$ENV{'INFORMIXDIR'} || die "Cannot evaluate INFORMIXDIR environment variable\n";

#open TBCONFIG file
open(TBCONFIG,"<$INFORMIXDIR/etc/$TBCONFIG") || die "cannot open $INFORMIXDIR/etc/$TBCONFIG for reading\n";

#read and look for LOGSIZE & LTAPEBLK
print "Getting logical log tape details from $INFORMIXDIR/etc/$TBCONFIG\n";
while (<TBCONFIG>) {
    if ( /^LOGSIZE\s+([0-9]+)\s+/ ) {
	$LOGSIZE=$1;
    } elsif ( /^LTAPEBLK\s+([0-9]+)\s+/ ) {
	$LTAPEBLK=$1;
    }
}
close(TBCONFIG);
if ( ! $LOGSIZE || ! $LTAPEBLK ) {
    die "Cannot establish LOGSIZE or LTAPEBLK from $INFORMIXDIR/etc/$TBCONFIG\n";
}


#open the log file
open(LOGTAPE,"<$LOGTAPE") || die "Cannot open $LOGTAPE\n";

print "Reading tape: $LOGTAPE\n";

#read each line
$found=0;
$num=0;

$rec_bytes = $LTAPEBLK * 1024;				#number of bytes per tape record
$log_bytes = $LOGSIZE * 1024;				#number bytes per log file
$num_per_log = 1 + int(($log_bytes-1)/$rec_bytes);	#number of records per log

$got_err=0;
$found_hdr=0;
$curr_logno=0;
$first_logno=0;
$prev_logno=0;
$recno=0;
 nextlog:
    while(1) {
	#read all the records per log file
	$found_log=0;
	foreach $b ( 1 .. $num_per_log ) {
	    $numread=sysread(LOGTAPE,$logbuf,$rec_bytes);
	    ++$recno;
	    if ( $numread != $rec_bytes ) {
		if ( $found_hdr && $curr_logno ) {
		    print "ERROR $numread BYTES READ INSTEAD OF $rec_bytes IN RECORD $recno - END OF TAPE?\n" if $verbose;
		} else {
		    print "ERROR $numread BYTES READ INSTEAD OF $rec_bytes IN RECORD $recno - NOT A LOG FILE TAPE\n" if $verbose;
		    $got_err=1;
		}
		last nextlog;
	    }
	    #look at header(s) if first record per log file
	    if ( $b >= 1 ) {
		$hdr_offset=0;
	      testhdr:
		while(1) {
		    #unpack header from first 2048 bytes
		    $header=substr($logbuf,$hdr_offset,2048);
		    ($h1)=unpack "i4",$header;
		    #look for tape header
		    if ( $h1 == -1 ) {
			printf "TAPE HEADER (%d) record %4d offset %5d\n",$h1,$recno,$hdr_offset if $verbose;
			
			if ( ++$found_hdr > 1 || $hdr_offset || $recno != 1) {
			    print "*** ERROR - DUPLICATE OR NOT IN FIRST BLOCK ***\n"; $got_err=1;
			    last nextlog;
			}

		    } elsif ( $h1 == -4 ) {
			++$curr_logno;
			($log_number)=unpack "i4",substr($header,16,4);
			$message='';
			if ( $curr_logno == 1 && ! $found_hdr ) {
			    $message.="*** ERROR - NO TAPE HEADER ***"; $got_err=1;
			}
			if ( ++$found_log > 1 ) {
			    $message.="*** ERROR - LOG $found_log IN BLOCK ***"; $got_err=1;
			}
			#check for log sequence and remeber first/last
			if ( $prev_logno ) {
			    if ( $log_number != $prev_logno+1 ) {
				$message.="*** ERROR - BAD LOG SEQUENCE $prev_logno - $curr_logno ***"; $got_err=1;
			    }
			} elsif ( ! $first_logno ) {
			    $first_logno=$log_number;
			}
			$prev_logno=$log_number;

			printf "Log  Header (%d) record %4d offset %5d - LOGFILE: %6d  %s\n",$h1,$recno,$hdr_offset,$log_number,$message if $verbose;

		    } elsif ( $h1 > -10 && $h1 < 0 ) {
			printf "???? Header (%d) record %4d offset %5d\n",$h1,$recno,$hdr_offset if $verbose;

		    } else {
			last testhdr;
		    }

		    #look at next bit of block
		    $hdr_offset+= 2048;
		}
	    }
	}
    }    

close(LOGTAPE);

if ( $got_err ) {
    print "\n*** ERRORS FOUND *** - Tape contains logical logs: $first_logno - $prev_logno\n";
} else {
    print "\nNo Errors - Tape contains logical logs: $first_logno - $prev_logno\n";
}

#eof