#!/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"; }