#!/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