#! /usr/local/bin/perl -w
# $Id: viz.pl,v 1.1.1.1 2002/09/06 18:18:09 travcom Exp $
# (c) Travcom 2002

use strict;
use integer; 

viz("/etc/utmp", 0); # SunOS
viz("/usr/adm/wtmp", 1); # SunOS
viz("/var/run/utmp", 0); # NetBSD
viz("/var/log/wtmp", 1); # NetBSD
viz("/var/log/wtmp.0", 1); # NetBSD

sub viz() {
    my($fn, $wtmp) = @_;
    # warn and give up if we can't read this file
    if (!-e $fn) {
	warn "$fn not found: $!\n";
	return;
    }
    # stat the file (possibly a symlink)
    my($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
       $atime, $mtime, $ctime, $blksize, $blocks) = lstat($fn);
    # if we're on a BSD system,
    if (defined($blocks) and defined($blksize)) {
	# check for sparse files (holes);
	# a bug in the way zap does sign-extension leaves these.
	# HINT: file offsets are quad_t's!
	# The problem here is that PERLs stat returns longs for file size
	# so $size alone can't tell us how big the file is.
	# ask ls how big the file is:
	my $len = `ls -l $fn | awk -- '{ print \$5; }'`;
	chomp($len);
	if ($blocks * $blksize < $len) {
	    print("You've probably been zapped by a script-kiddie.\n",
		  "There are $blocks $blksize-byte blocks but ",
		  "$len bytes in the file $fn\n");
	}
	if ($len != $size) {
	    print("You've probably been zapped by a script-kiddie.\n",
		  "Your file should be $size bytes long,\n",
		  "instead it is $len bytes long and has a hole in it.\n",
		  "I won't bother to show you from the hole onward.\n");
	}
    }
    open(UTMP, '<' . $fn) or die "could not open $fn for read: $!\n";
    print "$fn:\n";
    my ($recno,$offset) = (0,0);
LOOP:
    while (read(UTMP, $_, 36)) {
	++$recno;
	$offset = $recno * 36;
	# null entries are expected in utmp but not wtmp
	if ($wtmp and $_ eq "\0" x 36) {
	    print "zap detected at offset $offset!\n";
        } else {
	    my($line, $name, $host, $time) = unpack("a8 a8 a16 L", $_);
	    print "record=$recno line=$line name=$name host=$host time=" .
		localtime($time) . "\n";
	}
	# print "$recno $offset $size\n";
	if ($offset >= $size) {
	    last LOOP;
	}
    }
    close(UTMP);
}

exit 0;
