#! /usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 1997,2019 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # sccsid = "@(#)59 1.33 src/rsct/pgs/cmds/hagsreap.pl, gsdaemon, rsct_rady, rady2035a 11/12/15 16:45:09" ####################################################################### # hagsreap - cleanup hags core and log files # # hagsreap DaemonName Partition (Erase|(P|p)[rint]) [ SizeLimit [ NodeNumber [ LogDir [ CoreDir ] ] ] ] # # DaemonName and Partition are required, and specify which daemon to clean up after. # SizeLimit defaults to 5 MB, and is the cap in bytes. # If NodeNumber is not specified, use HA_DOMAIN_TYPE to determine how to get it. # LogDir defaults to /var/ha/log, and is the directory where the log files are kept and cleaned up. # CoreDir defaults to LogDir if it's specified, # or /var/ha/run/hags.Partition otherwise # # exit value is the number of (core and log) files removed # (note that therefore the "error" return value is 0!) ####################################################################### print "$0 input arguments: ", join(' ',@ARGV), "\n"; unshift(@INC, '/opt/rsct/bin'); ($dir,$progname) = $0 =~ /(.*\/)?(.*)/; # get basename of $0 sub Usage { warn "Usage: $progname [ -d DefaultLogName ] DaemonName Partition (Erase|(P|p)[rint]) [ SizeLimit [ NodeNumber [ LogDir [ CoreDir ] ] ] ]\n"; exit -1; } # Avoid getopts, to remove dependencies on Perl libraries... #if ( 1 != &Getopts( "d:" ) ) { # &Usage; #} #$DefaultLogName = $opt_d; if ("-d" eq @ARGV[0]) { shift @ARGV; $DefaultLogName = shift @ARGV; } # # set locale to "C" so that "ls" output should be locale-free $ENV{'LC_ALL'} = "C"; ($Daemon_Name, $Partition, $EraseOrPrint, $SizeLimit, $Node_Number, $LogDir, $CoreDir) = @ARGV; $EraseTheFiles = 0; # Operational flag for Erase/Print parameter if ("" eq $EraseOrPrint) { warn "Not enough arguments"; &Usage; } else { if ("Erase" eq $EraseOrPrint) { #OK! $EraseTheFiles = 1; } else { if ($EraseOrPrint =~ /^[Pp](.*)/) { $rest = $1; if ( ("" ne $rest) && (index("rint", $rest) != $[) ) { warn "Print flag invalid"; &Usage; } } else { warn "Erase|Print flag invalid"; &Usage; } } } if ("" eq $SizeLimit) { $SizeLimit = 5 * 1024 * 1024; # 5 MB default size limit } else { if ($SizeLimit !~ /^[0-9]+$/) { warn "SizeLimit must be numeric"; &Usage; } } $domainType = $ENV{'HA_DOMAIN_TYPE'}; if ("" eq $Node_Number) { if (!defined( $ENV{'HA_DOMAIN_TYPE'} )) { die "Node number not given, and HA_DOMAIN_TYPE not set. Exit.\n"; } else { $domainType = $ENV{'HA_DOMAIN_TYPE'}; if ($domainType eq "HAES") { if (!defined( $ENV{'HB_SERVER_SOCKET'} ) ) { $ENV{'HB_SERVER_SOCKET'} = "/var/ha/soc/topsvcs/server_socket"; } $Node_Number=`hats_node_number -d $Partition`; while (0 != $?) { sleep(2); $Node_Number=`hats_node_number -d $Partition`; } } elsif($domainType eq "CLUSTER") { if(!defined($ENV{'HB_SERVER_SOCKET'})) { warn "HB_SERVER_SOCKET is not defined"; &Usage; } $Node_Number=`hats_node_number -d $Partition`; while (0 != $?) { sleep(2); $Node_Number=`hats_node_number -d $Partition`; } } else { $Node_Number=`/usr/lpp/ssp/install/bin/node_number`; } chop($Node_Number); } } if ($Node_Number !~ /^[0-9]+$/) { warn "NodeNumber must be numeric"; &Usage; } if ("" eq $LogDir) { if($domainType eq "CLUSTER") { warn "LogDir is not provided"; &Usage; } $LogDir = "/var/ha/log"; $CoreDir = "/var/ha/run/$Daemon_Name.$Partition"; } if ("" eq $CoreDir) { if($domainType eq "CLUSTER") { warn "CoreDir is not provided"; &Usage; } $CoreDir = $LogDir; } $flag = (1 == $EraseTheFiles) ? "Erase" : "Print"; print "$progname parsed arguments: $Daemon_Name $Partition $flag $SizeLimit $Node_Number $LogDir $CoreDir\n"; sub piperc { local($rc) = (256 <= $_[0]) ? $_[0]/256 : $_[0]; local($cmd) = $_[1]; local($line) = $_[2]; if ( 0 != $rc ) { warn "\n$!\n"; warn "$0: $cmd at line $line failed: rc = $rc.\n"; exit 0; } } sub removeDanglingSymbolicLinks { my $directory = $_[0]; open(SYMLINKS, "find $directory -type l -ls |") or return; while () { # find symbolic links, capturing the link in $1 # and the link target in $2 /^.* (.*) -> (.*)$/; # if the link target doesn't exist, remove the link if (! -e "$directory/$2") { warn "removing symbolic link $1 because link target $directory/$2 doesn't exist\n"; unlink "$1"; } } } $NaN = 65535; # Not a Number # Get all core and log files # Determine and save their Incarnation Number, name and size $cmd = "ls -lL $CoreDir |"; if ( ! open(FILES, $cmd ) ) { $rc = $! + 0; warn "\n$!\n"; } if (0 == $Node_Number) { $Daemon_Name = "$Daemon_Name.$Partition"; } #process core files $lastModifiedTime = 0; while() { ($perms, $links, $owner, $group, $size, $month, $day, $time, $name) = split(' '); $name =~ s/.*\///o; # get basename of file name; strip off /s and dirname if( ("" ne $name) && ($name =~ "core") ){ @a = stat("$CoreDir/$name"); $modifiedTime = $a[9]; if( $lastModifiedTime < $modifiedTime ){ if($lastModifiedTime > 0){ unlink "$CoreDir/$lastCoreFile"; } $lastModifiedTime = $modifiedTime; $lastCoreFile=$name; $CoreSavedFileName = $name; } elsif( $modifiedTime < $lastModifiedTime ){ unlink "$CoreDir/$name"; } } } close FILES; # this causes a wait on pipe child process, with $? set to its rc &piperc( $?, $cmd, __LINE__ ); # remove dangling symbolic links so ls -lL cannot fail # because of them, because piperc() after this step will # exit on such a failure, resulting in subsequent steps # being skipped (also, dangling symbolic links serve no # useful purpose) removeDanglingSymbolicLinks $LogDir; # collect log files $cmd = "ls -lL $LogDir |"; # print "$cmd\n"; if ( ! open(FILES, $cmd ) ) { $rc = $! + 0; warn "\n$!\n"; } # defect 145926: for HACMP case it will have grpsvcs_ prefix for the file name $TRACEFILEPREFIX = "trace"; if ($domainType eq "HAES") { $TRACEFILEPREFIX = "${Daemon_Name}_trace"; } elsif($domainType eq "PSSP") { # considering PSSP & partition name $TRACEFILEPREFIX="${Daemon_Name}_${Partition}_trace"; } if ( $Daemon_Name =~ /hagsglsm/ ) { if($domainType eq "CLUSTER") { if (defined( $ENV{'CLUSTERNAME'} )) { $ClusterName = $ENV{'CLUSTERNAME'}; } else { $ClusterName = $Partition; } $LogPattern = "$Daemon_Name"."_$Node_Number"."_([0-9]+)\\.$ClusterName"; $LongLogPattern = "$Daemon_Name"."_$Node_Number"."_([0-9]+)\\.$ClusterName\.long"; $BadLogPattern = "$Daemon_Name"."_([0-9]+)"."_([0-9]+)\\.$ClusterName"; $BadLogPattern = "$Daemon_Name"."_([0-9]+)"."_([0-9]+)".bak; } else { $LogPattern = "$Daemon_Name"."_$Node_Number"."_([0-9]+)\\.$Partition"; $LongLogPattern = "$Daemon_Name"."_$Node_Number"."_([0-9]+)\\.$Partition\.long"; $BadLogPattern = "$Daemon_Name"."_([0-9]+)"."_([0-9]+)\\.$Partition"; $BadLogPattern = "$Daemon_Name"."_([0-9]+)"."_([0-9]+)".bak; } } else { $SpoolLogPattern = "$TRACEFILEPREFIX".".([0-9]+)".".sp"; $SpoolLongLogPattern = "$TRACEFILEPREFIX"."\\.summary".".([0-9]+)".".sp"; $BadLogPattern = "$Daemon_Name"."_([0-9]+)"."_([0-9]+)".bak; } #If there is a symbolic link unlink it. $TRACEFILEPREFIX_SUMMARY = "$TRACEFILEPREFIX".".summary"; #Since for HACMP,SP and rpdomain cases the symbolic link file names #are all the same: trace and trace.summary $symbolicFile = "$LogDir"."/trace"; $symbolicFileSummary = "$LogDir"."/trace.summary"; unlink("$symbolicFile") if -l $symbolicFile; unlink("$symbolicFileSummary") if -l $symbolicFileSummary; #If there is a core file rename it as core.0 $Core0 = "core.0"; if( "" ne $CoreSavedFileName ){ if( $CoreSavedFileName ne "core.0" ){ rename("$CoreDir/$CoreSavedFileName","$CoreDir/$Core0"); } } # No matter if there is a core file copy the current trace files # to .last trace files. # If there is a core file then copy the current trace files as .0 trace files. use File::Copy; while() { ($perms, $links, $owner, $group, $size, $month, $day, $time, $name) = split(' '); $name =~ s/.*\///o; # get basename of file name; strip off /s and dirname $SavedLogFile0 = "$name".".0"; $SavedLogFileLast = "$name".".last"; if ( ($name =~ /^$TRACEFILEPREFIX(\.bak)?$/o) && ($NaN > $1) ) { system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFileLast"); if( "" ne $CoreSavedFileName ){ if( $CoreSavedFileName ne "core.0" ){ system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFile0"); } } } elsif ( ($name =~ /^$TRACEFILEPREFIX_SUMMARY(\.bak)?$/o) && ($NaN > $1) ) { system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFileLast"); if( "" ne $CoreSavedFileName ){ if( $CoreSavedFileName ne "core.0" ){ system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFile0"); } } } elsif ( ($name =~ /^$SpoolLogPattern(\.bak)?$/o) && ($NaN > $1) ) { system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFileLast"); if( "" ne $CoreSavedFileName ){ if( $CoreSavedFileName ne "core.0" ){ system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFile0"); } } } elsif ( ($name =~ /^$SpoolLongLogPattern(\.bak)?$/o) && ($NaN > $1) ) { system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFileLast"); if( "" ne $CoreSavedFileName ){ if( $CoreSavedFileName ne "core.0" ){ system("cp","-p","$LogDir/$name","$LogDir/$SavedLogFile0"); } } } # end of if } #end of while( ) $preSaveIncar = $NaN; $saveIncar = $NaN; $afterIncar = $NaN; $saveLogIncar = $NaN; $numberOfSaveIncar = 0; $preTime = 0; $afterTime = 0; $count = 0; #Since need to read the FILES again here open it again. if ( ! open(FILES, $cmd ) ) { $rc = $! + 0; warn "\n$!\n"; } #rewind FILES seek( FILES,0,SEEK_SET); if ( $Daemon_Name =~ /hagsglsm/ ) { while() { ($perms, $links, $owner, $group, $size, $month, $day, $time, $name) = split(' '); $name =~ s/.*\///o; # get basename of file name; strip off /s and dirname if ( ($name =~ /^$LogPattern(\.bak)?$/o) && ($NaN > $1) ) { $incarnationNumber = $1; $bak = $2; if ("" eq $bak) { # a regular log file # print "$name, $incarnationNumber\n"; $LogFileName{$incarnationNumber} = $name; $LogFileSize{$incarnationNumber} = $size; @a = stat("$LogDir/$LogFileName{$incarnationNumber}"); $modifiedTime = $a[9]; $LogFileTime{$incarnationNumber} = $modifiedTime; # find the incarnation number to save if( $count == 0 ){ if( $modifiedTime ==$lastModifiedTime ){ $saveLogIncar = $incarnationNumber; $numberOfSaveIncar = 1; } else { $preSaveIncar = $incarnationNumber; $preTime = $LogFileTime{$incarnationNumber}; } } elsif( $count == 1 ){ if( $modifiedTime ==$lastModifiedTime ){ $saveLogIncar = $incarnationNumber; $numberOfSaveIncar = 1; } else { $saveIncar = $incarnationNumber; $saveTime = $LogFileTime{$incarnationNumber}; } } elsif( $count == 2 ){ if( $modifiedTime ==$lastModifiedTime ){ $saveLogIncar = $incarnationNumber; $numberOfSaveIncar = 1; } else { $afterSaveIncar = $incarnationNumber; $afterTime = $LogFileTime{$incarnationNumber}; } } else{ if( $modifiedTime ==$lastModifiedTime ){ $saveLogIncar = $incarnationNumber; $numberOfSaveIncar = 1; } elsif( $preTime < $lastModifiedTime && $afterTime > $lastModifiedTime){ $saveLogIncar = $saveIncar; $numberOfSaveIncar = 3; } else { if($numberOfSaveIncar == 0 ){ $preSaveIncar = $saveIncar; $saveIncar = $afterSaveIncar; $afterSaveIncar = $incarnationNumber; $preTime = $saveTime; $saveTime = $afterTime; $afterTime = $LogFileTime{$incarnationNumber}; } } } if( $modifiedTime ==$lastModifiedTime ){ $saveLogIncar = $incarnationNumber; $numberOfSaveIncar = 1; } elsif( $preTime < $lastModifiedTime && $afterTime > $lastModifiedTime){ $saveLogIncar = $saveIncar; $numberOfSaveIncar = 3; } $count++; } else { # a log.bak file # print "$name, $incarnationNumber\n"; $BakFileName{$incarnationNumber} = $name; $BakFileSize{$incarnationNumber} = $size; } } elsif ( ($name =~ /^$LongLogPattern(\.bak)?$/o) && ($NaN > $1) ) { $incarnationNumber = $1; $bak = $2; if ("" eq $bak) { # a regular long log file # print "$name, $incarnationNumber\n"; $LongLogFileName{$incarnationNumber} = $name; $LogFileSize{$incarnationNumber} = $size; } else { # a long log.bak file # print "$name, $incarnationNumber\n"; $LongBakFileName{$incarnationNumber} = $name; $BakFileSize{$incarnationNumber} = $size; } } elsif (($name =~ /^$BadLogPattern(\.bak)?$/o) && ($NaN > $1) ) { # A common situation we have seen is that a mksysb contains log # and core files from a node. When this is installed on a new # node, the node_number value does not match the current node # number, and hagsreap does not erase these files, and they just # sit taking up space in /var/ha/. Therefore, we assume the # first two tests will find the log & core files for THIS node, # we only get to these latter tests for files that follow the # hags pattern, but do NOT match on node number. Try to catch # those here, and simply erase them. print "Bad log file line $. Will erase it: $LogDir/$name, $_"; #$cmd = "rm -f $LogDir/$name"; #system($cmd); unlink( "$LogDir/$name" ); } else { # print "Bad FILES line $.: $name, $_"; next; } } close FILES; # this causes a wait on pipe child process, with $? set to its rc &piperc( $?, $cmd, __LINE__ ); } print "saveLogIncar=$saveLogIncar\n"; if( $saveLogIncar != $NaN ){ $CoreFileName{$saveLogIncar} = $CoreSavedFileName; } print "CoreFileName{$saveLogIncar}=$CoreFileName{$saveLogIncar}\n"; if ("" ne $DefaultLogName) { # get dirname of file name; strip off /s and dirname ($DefaultLogDir) = $DefaultLogName =~ /(.*)\/[^\/]+$/; print "\$DefaultLogDir=$DefaultLogDir\n"; $cmd = "ls -lL ${DefaultLogName}* |"; # print "$cmd\n"; if ( ! open(FILES, $cmd ) ) { $rc = $! + 0; warn "\n$!\n"; } while() { ($perms, $links, $owner, $group, $size, $month, $day, $time, $name) = split(' '); if ( ($name =~ /^$DefaultLogName.${Node_Number}_([0-9]+)$/o) && ($NaN > $1) ) { $incarnationNumber = $1; # print "$name, $incarnationNumber\n"; $name =~ s/.*\///o; # get basename of file name; strip off /s and dirname $DefLFileName{$incarnationNumber} = $name; $DefLFileSize{$incarnationNumber} = $size; } elsif ( $name ne $DefaultLogName ) { print "Bad FILE line $. Will erase it: $name, $_"; #$cmd = "rm -f $name"; #system($cmd); unlink( "$name" ); next; } } close FILES; # this causes a wait on pipe child process, with $? set to its rc &piperc( $?, $cmd, __LINE__ ); } # foreach $incar (keys(%CoreFileName)) { # print "$CoreFileName{$incar}, $incar, $CoreFileSize{$incar}\n"; # } # There are three things to potentially save for each incarnation number: # 1. the log # 2. the core file # 3. the log.bak file, or backup log, if it has wrapped # The order listed in the priority order # Our approach: # 1. Establish the weight or priority of each incarnation number. # The weight of each incarnation number is it's position in the # sorted list, except that the priority of incarnation numbers # with core files is raised. # 2. Sort the incarnation numbers by weight. # 3. Save the files from the top incarnation numbers that fit under the SizeLimit. # Save an incarnation number and it's weight for subsequent sorting by weight sub AddRecord { local ($incar) = $_[0]; local ($weight) = $_[1]; local ($record) = "$weight $incar"; # printf "AddRecord: %9.2f %10d\n", split(' ',$record); push(@Files, $record); } # taken from SequenceNum.[Ch]. $NaN = 65535; # Not a Number $kHalfSequence = 32767; # note we've insured that all Incarnation Numbers are < $NaN sub ByIncarnationNumber { if ($a == $b) { return 0; } # equal # if ($NaN == $a) { return 1; } # a > b # if ($NaN == $b) { return -1; } # a < b local($c) = ($a + $NaN -1 - $b) % $NaN; return ($kHalfSequence > $c) ? -1 : 1; } # Establish incarnation number weights by sorting by incarnation number, # and adjusting the weights of those with core files. $factor = 65537./137623.; # two primes, $factor =~ 1/2.1. 65537 = smallest prime > $NaN # I do this so that no two incarnation numbers should ever have the same weight $NumIncars = 0; # number of incarnation numbers seen $LastIncarSeen = $NaN; # beyond the valid range $LargestIncar = 0; $LargestCoreIncar = 0; if( $Daemon_Name=~/glsm/ ){ $NumIncarToKeep = 2; } else { $NumIncarToKeep = 3; } print "NumIncarToKeep=$NumIncarToKeep\n"; foreach $incarnationNumber (sort ByIncarnationNumber (keys(%CoreFileName), keys(%LogFileName), keys(%BakFileName), keys(%LongLogFileName), keys(%LongBakFileName), keys(%DefLFileName))) { if ($LastIncarSeen == $incarnationNumber) { next; # skip duplicate incarnation numbers } if( $LargestIncar < $incarnationNumber ){ $LargestIncar = $incarnationNumber; } # new incarnation number $LastIncarSeen = $incarnationNumber; $weight = $NumIncars++; # it's sorted order if( $NumIncars <= $NumIncarToKeep ){ $weight *= $factor; } if( $numberOfSaveIncar == 1){ if ( defined($CoreFileName{$incarnationNumber}) ) { # this incar has a core file; adjust weight $weight *= $factor; } } elsif ( $numberOfSaveIncar == 3 ){ if($incarnationNumber == $saveLogIncar-1 || $incarnationNumber == $saveLogIncar || $incarnationNumber == $saveLogIncar+1 ){ $weight *= $factor; } } &AddRecord( $incarnationNumber, $weight ); } print "largest incar = $LargestIncar\n"; # foreach $record (@Files) { # printf "%9.2f %10d %-s\n", split(' ',$record); # } # OK, now that we have the weights, sort by it! sub ByWeight { local($aweight, $arest, $bweight, $brest); ($aweight, $arest) = split(' ', $a); ($bweight, $brest) = split(' ', $b); $aweight <=> $bweight; } print "SizeLimit = $SizeLimit\n"; $CumSize = 0; $NumTrash = 0; $NumKeep = 0; $n = 0; # If we are under SizeLimit and the next incarnation number has a core file, # keep the core file and both logs, even if we exceed SizeLimit. # Otherwise, only keep a log if doing so will keep us under SizeLimit. print "numberOfSaveIncar=$numberOfSaveIncar\n"; sub ProcessFile { local ($name, $size, $HasaCoreFile, $dir, $incarNum) = @_; $n++; if ( 0 == $NumTrash ) { if( $LargestIncar - $incarNum >= $NumIncarToKeep){ if( HasaCoreFile ){ if($numberOfSaveIncar == 1 ){ if($incarNum != $saveLogIncar){ $NumTrash = 1; $BytesKept = $CumSize; } } elsif($numberOfSaveIncar == 3){ if($incarNum != $saveLogIncar-1 && $incarNum != $saveLogIncar && $incarNum != $saveLogIncar+1 ){ $NumTrash = 1; $BytesKept = $CumSize; } } else { $NumTrash = 1; $BytesKept = $CumSize; } }#end if hascorefile } else { $NumKeep++; }#end of if incardiff>numtokeep } else { if($numberOfSaveIncar == 1 ){ if($incarNum != $saveLogIncar){ $NumTrash = 1; $BytesKept = $CumSize; } } elsif($numberOfSaveIncar == 3){ if($incarNum != $saveLogIncar-1 && $incarNum != $saveLogIncar && $incarNum != $saveLogIncar+1 ){ $NumTrash = 1; $BytesKept = $CumSize; } } else { $NumTrash = 1; $BytesKept = $CumSize; } } $CumSize += $size; printf "%5d %10d %8.3f %9.2f %10d %-s\n", $n, $CumSize, $CumSize/1024./1024., $weight, $size, $name; if ( 0 < $NumTrash ) { # trash 'em! # I could save all names and issue one command # The one command line may exceed shell limits # So, do'em one at a time; shouldn't be a big deal. #$cmd = "rm -f $dir/$name"; print "unlink $dir/$name\n"; if (1 == $EraseTheFiles) { unlink "$dir/$name"; } } } printf "%5s %10s %8s %9s %10s %s\n", "n", "CumSize", "MB", "weight", "size", "name"; # Sort the incarnation numbers ordered by weight (priority), and # keep those that fit under SizeLimit, and erase (trash) the rest, # depending on the Erase|Print parameter. foreach $record (sort ByWeight @Files) { ($weight, $incar) = split(' ',$record); local($HasaCoreFile) = defined($CoreFileName{$incar}); if (defined($LogFileName{$incar}) ) { &ProcessFile( $LogFileName{$incar}, $LogFileSize{$incar}, $HasaCoreFile, $LogDir, $incar ); } if (defined($LongLogFileName{$incar}) ) { &ProcessFile( $LongLogFileName{$incar}, $LogFileSize{$incar}, $HasaCoreFile, $LogDir, $incar ); } if (defined($BakFileName{$incar}) ) { &ProcessFile( $BakFileName{$incar}, $BakFileSize{$incar}, $HasaCoreFile, $LogDir, $incar ); } if (defined($LongBakFileName{$incar}) ) { &ProcessFile( $LongBakFileName{$incar}, $BakFileSize{$incar}, $HasaCoreFile, $LogDir, $incar ); } if (defined($DefLFileName{$incar}) ) { &ProcessFile( $DefLFileName{$incar}, $DefLFileSize{$incar}, $HasaCoreFile, $DefaultLogDir, $incar ); } } # Print out some stats on what we did if (0 == $NumTrash) { $BytesKept = $CumSize; } $BytesTrashed = $CumSize - $BytesKept; $MBtrashed = $BytesTrashed/1024./1024.; printf "Keep %d logs, %d bytes, %.3f MB; Trash %d logs, %d bytes, %.3f MB.\n", $NumKeep, $BytesKept, $BytesKept/1024./1024., $NumTrash, $BytesTrashed, $MBtrashed; $tlogs = $NumKeep + $NumTrash; $tbytes = $BytesKept + $BytesTrashed; printf "%d total logs, %d total bytes, %.3f total MB.\n", $tlogs, $tbytes, $tbytes/1024./1024.; # $rc = int($NumTrash*256 + $MBtrashed); # $rc = int($NumKeep*256*256 + $NumTrash*256 + $MBtrashed + .5); # $rc = int($NumKeep*256*256 + $NumTrash*256 + $MBtrashed + .5); $rc = $NumTrash; printf "keep %d, trash %d, %d MB. rc = %d, 0x%x\n", $NumKeep, $NumTrash, ($MBtrashed + .5), $rc, $rc; exit $rc;