#!/usr/local/bin/perl5
$|=1;
### university required copyright stuff
##
## Accheck v1.1
## Mark Notarus, notarus@uiuc.edu
## University of Illinois Computing and Communication Services
##
## Copyright (c) 1998 by Mark Notarus,
## and the University of Illinois Board of Trustees.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
##
## 1. Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
##
## 2. Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in the
## documentation and/or other materials provided with the distribution.
##
## 3. All advertising materials mentioning features or use of this
## software must display the following ack
##
## THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS "AS IS"
## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
## PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES
## OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
## OF SUCH DAMAGE.
##
###
### This program parses a Tacacs+ accounting log in useful ways.
###
###
### -usage prints options
### *** for other options, see the usage subroutine at the bottom ***
###
### Note that on a server reload, all "open" sessions in this program's
### history are closed, and printed out.
### This means that all information thus printed (end time, elapsed time, etc)
### is calculated, and therefore not 100% reliable!
###
### Also, please note that we assume that filenames are 80 char or less.
### V1.1, 5/14/98 notarus
###############################################
###### ######
###### ######
###### Variables & requires ######
###### ######
###### ######
###############################################
require "ctime.pl";
require 5; # we'll use the perlv5 getoptions stuff.
use Getopt::Long;
use Time::Local;
###############################################
###### ######
###### ######
###### Customizing for your site! ######
###### ######
###### ######
###############################################
###
### Where are our accounting files stored?
### Note that this NEEDS the trailing /
$FILEPATH="/areas/termserv/logs/accounting/";
###
### What's the prefix we tag on each file (eg, ACCOUNTING.Sep.25.gz)
$FILEPREFIX="ACCOUNTING";
### What is the program that builds our index for us if the index is
### out of date? (disabled, 6/18/98, annoying users)
### (since it's disabled, this MUST run as a cron job!! )
$REBUILDINDEX="/areas/termserv/logs/accounting/bin/buildindex.pl";
### Where is the index file which will tell us which files encompass
### what times?
$INDEXFILE="/areas/termserv/logs/accounting/.index";
###############################################
###### ######
###### ######
###### End Site Customization ######
###### ######
###### ######
###############################################
### %tr is an associative array for "thisrecord"
### %CT is an associative array for CT
### and holds a mapping between the keynames & where the values are in %tr
### %session{'server:task'} is a record for a session
### that this particular session has made (shell sessions, mostly)
### This template is here so we can store data about connections that began
### but haven't ended.
$SESSIONTMPL="a10 a32 a9 a12 a20 a30 a10 a20 l";
# $tr{$CT{'netid'}},$tr{$CT{'server'}},$tr{$CT{'tty'}},$tr{$CT{'callerid'}},$tr{$CT{'service'}},$tr{$CT{'cmd'}},$tr{$CT{'protocol'}},$tr{$CT{'addr'}},$tr{$CT{'start_time'}}
### Session X counter
$sessionNumber=0;
####
####
#### Months
%months=(
Jan => 0, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6,
Feb => 1, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11,
jan => 0, mar => 2, apr => 3, may => 4, jun => 5, jul => 6,
feb => 1, aug => 7, sep => 8, oct => 9, nov => 10, dec => 11,
);
####
####
#### Pre-stuff the keys for %CT (COMMANDTYPE, a hash from keyname to # of the entry
#### as stored in %tr
####
#### IMPORTANT: WARNING:
#### the first few entries (the ones that have no key=val pairs!!) MUST BE
#### stuffed in the following list!!!)
####
#### We stuff the rest (even though they are listed as key=val) because
#### it neatly lets me set a warning message about new values appearing in
#### the accounting data.
%CT=(
date => 0, server => 1, netid => 2 , tty =>3 , contype => 4,
type => 5, callerid => 6, task_id => 7, start_time => 8, service => 9,
cmd => 10, protocol => 11, addr => 12, elapsed_time => 13, paks_out => 14,
paks_in => 15, bytes_out => 16, bytes_in => 17, protocol => 18,
timezone => 19, 'cmd-arg' => 20, 'disc-cause' => 21, 'disc-cause-ext' => 22,
'pre-bytes-in' => 23, 'pre-bytes-out' => 24, 'pre-paks-in' => 25,
'pre-paks-out' => 26, 'pre-session-time' => 27, 'data-rate' => 28,
'event' => 29, 'reason' => 30, 'nas-rx-speed' => 31, 'nas-tx-speed' => 32,
);
####
#### $commandsinuse is a counter that tells us what's the next free mapping in
#### %CT -- needed as we build the dynamic array of key/val pairs.
@TEMP=keys %CT;
$commandsinuse=$#TEMP+1;
undef @TEMP;
###
### Discconect cause codes.
###
@disccause=("Unassigned","User Request","Lost Carrier","Lost Service","Idle Timeout",
"Session Timeout","Admin Reset","Admin Reboot","Port Error","NAS Error",
"NAS Request","NAS Reboot","Port Unneeded","Port Preempted","Port Suspended",
"Service Unavailable","User Error","Host Request");
undef $disccause[0]; # don't want that nasty 0 value.
###
### Disc-cause-ext codes.
###
$discext[1002]="Unknown";
$discext[1004]="CLID Authentication Fail";
$discext[1010]="No Carrier";
$discext[1011]="Lost Carrier";
$discext[1012]="No Modem Result Codes";
$discext[1020]="User Request";
$discext[1021]="Idle Timeout";
$discext[1022]="Exited Telnet";
$discext[1023]="Peer has No IPADDR";
$discext[1024]="Lost Service";
$discext[1025]="Password Failure";
$discext[1026]="TCP Disabled";
$discext[1027]="Control-C Detected";
$discext[1028]="Host Request";
$discext[1040]="LCP Neg Timeout";
$discext[1041]="LCP Neg Failed";
$discext[1042]="PAP Auth Failed";
$discext[1043]="CHAP Auth Failed";
$discext[1044]="Remote Auth Failed";
$discext[1045]="Received Terminate";
$discext[1046]="Upper Layer Req";
$discext[1100]="Session Timeout";
$discext[1101]="Fail Security";
$discext[1102]="Callback";
$discext[1120]="Service Unavailable";
###
### setup our command line options for getoptions
%optctl=("netid=s" => \$PARSENETID,
"usage" => \$USAGE,
"server=s" => \$PARSESERVER,
"tty=s" => \$PARSETTY,
"ip=s" => \$PARSEIP,
"debug" => \$DEBUG,
"printall" => \$PRINTALL,
"nowarn" => \$NOWARN,
"start=s" => \$STARTTIME,
"end=s" => \$ENDTIME,
"file=s" => \$FILE,
"help" => \$HELP
);
#### Months
%months=(
Jan => 0, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6,
Feb => 1, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11,
jan => 0, mar => 2, apr => 3, may => 4, jun => 5, jul => 6,
feb => 1, aug => 7, sep => 8, oct => 9, nov => 10, dec => 11,
);
###############################################
###### ######
###### ######
###### Main program starts here. ######
###### ######
###### ######
###############################################
&GetOptions(%optctl);
if ($USAGE || $HELP){
&Usage;
exit;
}
if ($PARSENETID eq ""){
$netid=shift(@ARGV);
$PARSENETID=$netid;
}
else{
$netid=$PARSENETID;
}
if ($STARTTIME eq "" && $FILE eq "" && $ENDTIME eq ""){
# default to examining yesterday's files.
$DEFAULTSTARTTIME=time;
$DEFAULTSTARTTIME=$DEFAULTSTARTTIME-(60*60*24);
local($sec,$min,$hour,$mday,$mon,$year,@chaff)=localtime($DEFAULTSTARTTIME);
$mon++;
$STARTTIME="$mon/$mday";
undef $DEFAULTSTARTTIME;
}
if ($PARSEIP){
if ($PARSEIP=~/^[a-z]/){
# oops, named entry. convert to numbers
# is there a "."? if so, strip it and everything else.
local($theIP)=split(/\./,$PARSEIP);
$theIP="$theIP.slip.uiuc.edu";
local($name,$aliases,$addrtype,$length,@addrs)=gethostbyname $theIP;
if (!defined $name){
print "Error: gethostbyname failed for $PARSEIP\n";
die;
}
$PARSEIP=join(".",unpack('C4',$addrs[0]));
}
}
if ($FILE ne ""){
&ProcessFile($FILE);
exit;
}
if ($STARTTIME || $ENDTIME){
if ($STARTTIME){
$startepoch=&ConvertToEpoch($STARTTIME);
}
if ($ENDTIME){
$endepoch=&ConvertToEpoch($ENDTIME);
}
# &UpdateIndex; # if needed.
&BuildListOfFiles($startepoch,$endepoch);
# debug
@FILELIST = sort keys %filelist;
while($nextstart=shift @FILELIST){
($debugend,$thefilename)=unpack("lA80",$filelist{$nextstart});
$thefilename=~s/\s+//;
&ProcessFile("$FILEPATH$thefilename");
}
exit;
}
print "Falling through to usage.\n";
### if we get here, there was neither a timestamp or a filename specified.
### Keel over, die, and print usage.
&Usage;
exit;
###############################################
###### ######
###### ######
###### Main program ends here. ######
###### ######
###### ######
###############################################
sub ProcessFile{
local($thefile)=@_;
### DEBUG-- kill.
print "Processing the file: $thefile\n";
$gzipped=&IsGzipped($thefile);
if ($gzipped){
open (INPUT,"gunzip -c $thefile |");
}
else{
open (INPUT,"<$thefile");
}
while(){
chop;
next if $_ eq "";
$line=$_;
&processLine($line);
}
close INPUT;
}
sub processLine{
local($line)=@_;
undef %tr;
@contents=split('\t+',$line);
$tr{$CT{'date'}}=shift(@contents);
$tr{$CT{'server'}}=shift(@contents);
$tr{$CT{'netid'}}=shift(@contents);
$tr{$CT{'tty'}}=shift(@contents);
$tr{$CT{'contype'}}=shift(@contents);
$tr{$CT{'type'}}=shift(@contents);
#ok.
#now, what's left to do depends on type, type, and what's in contents.
if ( $tr{$CT{'contype'}}=~/^{10}[0-9]/ ){
($tr{$CT{'callerid'}},$chaff)=split('/',$tr{$CT{'contype'}});
}
# process all the "key=value" pairs on the line. Fit them into the %tr array
# using the hash in %CT
while ($entry=shift(@contents)){
($keycommand,$keyval)=split('=',$entry);
if (!$CT{$keycommand}){
$commandsinuse++; # increment the command index.
print "Warning: New keyvalue $keycommand noted. Use -printall to display values\n" if !$NOWARN;
$CT{$keycommand}=$commandsinuse;
}
$tr{$CT{$keycommand}}=$keyval;
}
# at this point and time (4/17/98), the "contype" field is always one
# of two things: Caller ID info, or the string "async"
# check for this first; this is the only contype record which is not type
# (callerid) or asynch
# and it has a "start" or "stop" entry in the record type ($tr{$CT{'type'}}) field
if ($tr{$CT{'contype'}} eq "unknown"){
# system accounting record.
if ($reason eq "shutdown"){
# right now, we can ignore this.
# it means the system shutdown gracefully, and doesn't need to be
# worried about-- the NAS already sent stop records for
# everything.....right?
}
elsif ($reason eq "reload"){
# ok, now just check our lists to make sure everything has been cleared.
($wday,$mon,$day,$hms,$year,@other)=split(/\s+/,$tr{$CT{'date'}});
($hour,$min,$sec)=split(/:/,$hms);
$endtime=timelocal($sec,$min,$hour,$day,$months{$mon},$year);
@OPENLIST = sort keys %session;
foreach (@OPENLIST){
$thekey=$_;
local($a,$b)=split(/:/,$thekey);
if ($a eq $tr{$CT{'server'}}){
($tr{$CT{'netid'}},$chaff,$tr{$CT{'tty'}},$tr{$CT{'callerid'}},$tr{$CT{'service'}},$tr{$CT{'cmd'}},$tr{$CT{'protocol'}},$tr{$CT{'addr'}},$tr{$CT{'start_time'}})=unpack($SESSIONTMPL,$session{$thekey});
$tr{$CT{'elapsed_time'}}=$endtime-$tr{$CT{'start_time'}};
$tr{$CT{'task_id'}}=$b;
# printrecord will delete the session, too.
$NOTE="Warning: Session was terminated by server shutdown";
&printrecord;
}
}
undef $NOTE;
}
}
elsif ($tr{$CT{'type'}} eq "start"){
# store that info!
# since it's a start, this SHOULD be unique.
# storing start time because it's needed for a crash "cleanup"
if ($tr{$CT{'service'}} eq "connection"){
# store this in the %connections array, not the sessions array!
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.="\t\tCommand line: $tr{$CT{'cmd'}}\n\t\tConnected by: $tr{$CT{'protocol'}} $tr{$CT{'addr'}}\n";
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.="\t\tBegun at: ";
$chaff=&ctime($tr{$CT{'start_time'}});
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.=$chaff;
}
else{
$session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"}=pack($SESSIONTMPL,$tr{$CT{'netid'}},$tr{$CT{'server'}},$tr{$CT{'tty'}},$tr{$CT{'callerid'}},$tr{$CT{'service'}},$tr{$CT{'cmd'}},"","",$tr{$CT{'start_time'}});
}
}
elsif($tr{$CT{'type'}} eq "stop"){
if ($tr{$CT{'service'}} eq "ppp"){
# ending a ppp session.
&printrecord;
}
elsif ($tr{$CT{'service'}} eq "connection"){
# telnet or rlogin session from the shell.
#note the end of the session
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.="\t\tEnded at: ";
$chaff=&ctime($tr{$CT{'start_time'}} + $tr{$CT{'elapsed_time'}});
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.=$chaff;
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.="\t\tBytes in: $tr{$CT{'bytes_in'}}\t\tBytes out: $tr{$CT{'bytes_out'}}\n" if defined $tr{$CT{'bytes_in'}};
$connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"}.="\t\tPackets in: $tr{$CT{'paks_in'}}\t\tPackets out: $tr{$CT{'paks_out'}}\n" if defined $tr{$CT{'paks_in'}};
}
elsif($tr{$CT{'service'}} eq "shell"){
&printrecord;
}
elsif($tr{$CT{'service'}} eq "slip"){
&printrecord;
}
# others-- slip, others?
else{
"Warning: Stop record for service $tr{$CT{'service'}} not handled\n" if !$NOWARN;
}
}
elsif ($tr{$CT{'type'}} eq "update"){
# more information being handed to us.
# get any existing info
undef($PROTEMP,$ADDRTEMP);
($tr{$CT{'netid'}},$tr{$CT{'server'}},$tr{$CT{'tty'}},$tr{$CT{'callerid'}},$tr{$CT{'service'}},$tr{$CT{'cmd'}},$PROTEMP,$ADDRTEMP,$TIMETEMP)=unpack($SESSIONTMPL,$session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"});
# put in the new info.
$session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"}=pack($SESSIONTMPL,$tr{$CT{'netid'}},$tr{$CT{'server'}},$tr{$CT{'tty'}},$tr{$CT{'callerid'}},$tr{$CT{'service'}},$tr{$CT{'cmd'}},$tr{$CT{'protocol'}},$tr{$CT{'addr'}},$tr{$CT{'start_time'}});
}
else{
print "This type $tr{$CT{'type'}} not supported.\n";
# apparently nothing falls into here.
}
}
sub present {
local($scanfor,@scanin)=@_;
for($i=0;$i<$#scanin;$i++){
if ($scanin[$i]=~/$scanfor/){
return $scanin[$i];
}
}
return ""; # false/null string
}
sub printrecord {
# first, should we print this?
if ($PARSENETID && $PARSENETID ne $tr{$CT{'netid'}}){
delete $session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"};
delete $connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"};
return;
}
if ($PARSESERVER && $PARSESERVER ne $tr{$CT{'server'}}){
delete $session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"};
delete $connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"};
return;
}
if ($PARSESERVER && $PARSETTY && grep !/$PARSETTY/, $tr{$CT{'tty'}}){
delete $session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"};
delete $connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"};
return;
}
if ($PARSEIP && $PARSEIP ne $tr{$CT{'addr'}}){
delete $session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"};
delete $connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"};
return;
}
# ok, if we got here, it's time to clean out the strings
$tr{$CT{'netid'}}=~s/\0//g;
$tr{$CT{'server'}}=~s/\0//g;$tr{$CT{'tty'}}=~s/\0//g;$tr{$CT{'callerid'}}=~s/\0//g;$tr{$CT{'start_time'}}=~s/\0//g;
$tr{$CT{'elapsed_time'}}=~s/\0//g;$tr{$CT{'service'}}=~s/\0//g;$tr{$CT{'addr'}}=~s/\0//g;$tr{$CT{'cmd'}}=~s/\0//g;
$tr{$CT{'bytes_out'}}=~s/\0//g; $tr{$CT{'bytes_in'}}=~s/\0//g;$tr{$CT{'paks_in'}}=~s/\0//g;$tr{$CT{'paks_out'}}=~s/\0//g;
$sessionNumber++;
print "Session $sessionNumber\n";
print "\tNetid: $tr{$CT{'netid'}}\n";
print "\tLocation: $tr{$CT{'server'}} $tr{$CT{'tty'}}\n";
print "\tCaller ID: ";
if ($tr{$CT{'callerid'}}){
print "$tr{$CT{'callerid'}}\n";
}
else{
print "not available\n";
}
print "\tSession start: ";
print &ctime($tr{$CT{'start_time'}});
print "\tSession end: ";
print &ctime($tr{$CT{'start_time'}}+$tr{$CT{'elapsed_time'}});
print "\tSession length: $tr{$CT{'elapsed_time'}}\n";
print "\tService: $tr{$CT{'service'}}\n";
if ($connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"} ne "" ){
print $connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"};
}
if ($tr{$CT{'service'}} eq "ppp"){
print "\t\tIP Address: $tr{$CT{'addr'}}\n";
}
if ($tr{$CT{'service'}} eq "slip"){
print "\t\tIP Address: $tr{$CT{'addr'}}\n";
print "\t\tCommand line: $tr{$CT{'cmd'}}\n";
}
# valid for any service where this is defined
print "\t\tBytes in: $tr{$CT{'bytes_in'}}\t\tBytes out: $tr{$CT{'bytes_out'}}\n" if defined $tr{$CT{'bytes_in'}};
print "\t\tPackets in: $tr{$CT{'paks_in'}}\t\tPackets out: $tr{$CT{'paks_out'}}\n" if defined $tr{$CT{'paks_in'}};
if ($NOTE){
print "\t$NOTE";
}
# serious collisions can occur unless we nix this
# connection entry.
# besides, it's just good style not to waste ram.
delete $session{"$tr{$CT{'server'}}:$tr{$CT{'task_id'}}"};
delete $connections{"$tr{$CT{'netid'}}:$tr{$CT{'server'}}:$tr{$CT{'tty'}}"};
if (defined $tr{$CT{'disc-cause'}}){
print "\tDisconnect cause: $tr{$CT{'disc-cause'}}-$disccause[$tr{$CT{'disc-cause'}}]\n";
print "\tDisconnect exten: $tr{$CT{'disc-cause-ext'}}-$discext[$tr{$CT{'disc-cause-ext'}}]\n";
}
if($PRINTALL){
# ok, this is NOT the best way to handle this.
# print things we haven't printed before. Interesting to see what new
# features have been added to accounting logs, or other new stuff
@keylist=keys %CT;
$PRINTTOP=0;
while ($theKey=shift @keylist){
next if $theKey eq "netid";
next if $theKey eq "date";
next if $theKey eq "server";
next if $theKey eq "tty";
next if $theKey eq "contype";
next if $theKey eq "type";
next if $theKey eq "callerid";
next if $theKey eq "task_id";
next if $theKey eq "start_time";
next if $theKey eq "service";
next if $theKey eq "cmd";
next if $theKey eq "addr";
next if $theKey eq "elapsed_time";
next if $theKey eq "paks_out";
next if $theKey eq "paks_in";
next if $theKey eq "bytes_out";
next if $theKey eq "bytes_in";
next if $theKey eq "protocol";
next if $theKey eq "timezone";
next if $theKey eq "disc-cause";
next if $theKey eq "disc-cause-ext";
if (!$PRINTTOP++){
print "\tUnhandled extra information:\n";
}
if ($tr{$CT{$theKey}}eq ""){
print "\t\t$theKey=0\n";
}
else{
print "\t\t$theKey=$tr{$CT{$theKey}}\n";
}
}
}
print "\n\n";
}
sub IsGzipped{
local($THEFILE)=@_;
### Use /bin/file to see if this is a gzipped file.
open (FILECHECK,"/bin/file $THEFILE |");
while(){
return 1 if /gzip/;
}
### Silly check for any host who's /bin/file is too old to recognize gzip
if ($THEFILE =~/\.gz$/){
return 1;
}
return 0;
}
sub UpdateIndex {
# simple function.
# Check the timestamp on the index. If it's more than 24 hours out of date,
# patch it.
local($MYHOST)=`hostname`;
if ($MYHOST ne "minaret.cso.uiuc.edu"){
return;
}
if (!-e $INDEXFILE){
print "Rebuilding index file. Please wait...";
system($REBUILDINDEX);
print "Done.\n";
return;
}
local ($dev,$inode,$mode,$link,$uid,$gid,$rdev,$size,$atime,$mtime,@chaff)=stat($INDEXFILE);
if (time-$mtime>86400){
print "Rebuilding index file. Please wait...";
system($REBUILDINDEX);
print "Done.\n";
return;
}
}
###
### Input: begin time, end time, in epoch
### Fills %filelist with a list of files that fit those parameters.
### Provide no input, and we'll go through everything we can find
sub BuildListOfFiles{
local($startat,$endat)=@_;
local($starttime,$endtime,$filename,$prettystart,$prettyend);
#remember: $FilePath should include the trailing /
print "Building list...";
if ($startat eq ""){
$startat=0; # yes, I _KNOW_...
}
if ($endat eq ""){
$endat = time; # now
}
open (INDEX,"<$INDEXFILE");
while(){
$line=$_;
next if /^#/;
($starttime,$endtime,$filename,$prettystart,$prettyend)=split(/\t/,$line);
# print "Comparing file: $filename\n";
if (&IsInTimeFrame($startat,$endat,$starttime,$endtime)){
# include in array. Index by start time.
$filelist{$starttime}=pack("lA80",$endtime,$filename);
next;
}
}
print "Done.\n";
}
###
### Take in begin and end times, in epochs
### Also take in start & end times of the file to compare
### If there is an overlap, return 1
### Otherwise, return 0.
###
sub IsInTimeFrame{
local($startepoch,$endepoch,$startcompare,$endcompare)=@_;
# three cases: Smack dab in the middle of the time frame
# print "Comparing start: $startcompare >= $startepoch\n";
# print "Comparing end : $endcompare <= $endepoch\n";
if ($startcompare >=$startepoch && $endcompare<=$endepoch){
# print "Accepted\n\n";
return 1;
}
if ($startcompare <$startepoch && $endcompare<=$endepoch && $endcompare>=$startepoch){
# overlaps start time
# but does not end BEFORE the start
# print "Accepted\n\n";
return 1;
}
if ($startcompare >=$startepoch && $endcompare<$endepoch && $endcompare>=$startepoch ){
# overlaps end time
# print "Accepted\n\n";
return 1;
}
# print "Rejected\n\n";
return 0;
}
###
###
### This function takes a string input any order of mm/dd/year
### and hour:min:sec
### sec & year is optional. Exclude one and it assumes today.
### We return the epoch time requested.
sub ConvertToEpoch{
local($input)=@_;
local($chaffone,$chafftwo)=split(/\s+/,$input);
if ($chaffone=~/:/){
$hms=$chaffone;
}
if ($chaffone=~/\//){
$mdy=$chaffone;
}
if ($chafftwo=~/:/){
$hms=$chafftwo;
}
if ($chafftwo=~/\//){
$mdy=$chafftwo;
}
($mon,$day,$year)=split(/\//,$mdy);
($hour,$min,$sec)=split(/:/,$hms);
if ($year eq ""){
# get today & plug in where needed.
($blah,$blah,$blah,$blah,$blah,$year,@chaff)=localtime;
}
if ($mon eq ""){
# get today & plug in where needed.
($blah,$blah,$blah,$blah,$mon,$blah,@chaff)=localtime;
}
else{
$mon--;
}
if ($day eq ""){
# get today & plug in where needed.
($blah,$blah,$blah,$day,$blah,$blah,@chaff)=localtime;
}
else{
# $day--;
}
$hour=0 if $hour eq "";
$min=0 if $hour eq "";
$sec=0 if $hour eq "";
return timelocal($sec,$min,$hour,$day,$mon,$year);
}
###############################################
###### ######
###### ######
###### Usage. Leave this at the bottom-- ######
###### It's easier to find. ######
###### ######
###### ######
###############################################
sub Usage{
print "Usage: accheck \n";
print "Options:\n";
print "\t-file explicitly scan this file.\n";
print "\t-usage prints this message\n";
print "\t-netid= only print records for this netid\n";
print "\t-ip= only prints when the user was assigned this ip address\n";
print "\t-server= only print records on a particular term server\n";
print "\t-tty= only print records for a particular tty\n";
print "\t (ignored unless server is set.)\n";
print "\t-printall show values for records we don't handle yet\n";
print "\t-nowarn silently ignore options we don't handle\n";
print "\t-start mm/dd/yy start time/date\n";
print "\t-end mm/dd/yy end time/date\n";
print "\nNo options at all will just scan yesterday's info.\n";
}