Calctime.C
/* Program CalcTime
This program reads a Radius authentication file and writes to STDOUT
a list of users and their cumulative login times.
Additionally, it will perform the following options:
-i <path/file> input file. Mandatory!
-o <path/file> output file. If absent, output to STDOUT
-f Create user files and append to each user file each login
and logout.
-m <text> Extract records from source stream only if the text (usually month)
is found in the master records.
-q <text> Force End-of-File when it sees this pattern in a master record.
Created by Michael G. Gordon, February 1997.
*/
#undef __cplusplus
#define STDOUT 1
#define STDIN 0
#define STDERR 2
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAXPORTS 160
#define MAXUSERS 1500
#define LINESIZE 256 /* size of text lines for this program */
#define MAXUSERIDLENGTH 16
#define TRUE 1
#define FALSE 0
#define BUFFSIZE (16U*2048U) /* input or output buffer size */
#define long int // convert 16 bit dos specs to Linux
typedef enum {NOFLUSH, FLUSHAFTER, FLUSH};
typedef enum {NORECORDTYPE, START, STOP} Recordtypes;
typedef char userstring[MAXUSERIDLENGTH];
// DOS end-of-line
// char crlf[] = {13,10,0};
// UNIX end-of-line
char crlf[] = {10,0};
unsigned long portsused[MAXPORTS]; /* Here accumulate port logins */
// The users cumulative data array and pointers.
struct {
char user[MAXUSERIDLENGTH];
int logins; // 0=not logged in. 1=logged in, 2= logged in on two ports, etc.
long totalseconds;
time_t logontime; // Initial logon; hold until logout with no concurrent logins.
time_t startconcurrent; // time of concurrent login.
long totalconcurrent; // cumulative concurrency
} oneuser, allusers[MAXUSERS];
int numusers; /* variables for finding users in the array */
userstring ports[MAXPORTS]; // array to track who is on what port
int curport, numports;
char statusbyte;
char eoffound;
char db_flag; // if set, means to export for DB import (tab delimited)
char db_text[63]; // file path to store it.
int db_handle; // file handle for the database export file.
char f_flag; // means to make individual user data files
char o_flag; // means the output filename is specified
char h_flag; // means make histogram data
char s_flag; // means include START records.
char m_flag; // means to extract only for a defined [string], usually month.
char m_text[33];
char d_flag; // Means to delete records where datestring contains [d_text]
char d_text[33];
char q_flag;
char q_text[33];
char *months[14]={"???","Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec","???"};
// Histogram stuff
char histogramfilename[80];
int histogramhandle;
long sessiontimebins[40]; // Counts of sessions having n duration, where n varies from .1 hour to 7 days exponentially
long sessionhourbins[24]; // average session length ENDING this hour.
// analysis file variables
char ipaddress[16]; // from
char ipfirst[16]; // from Ascend-First-Dest = 207.201.65.10
int stopcode; // disconnection reason
long baudrate; //connection speed
int portid; // Port number for login, logout (validation check)
int presessiontime;
long bytes2user;
long bytesfmuser;
char datestring[LINESIZE]; // The text of the date/time
char timestring[LINESIZE]; // The text of the time (after fixup: hh:mm:ss)
int inhandle; /* which one are we using */
char filepath[128];
char outfilepath[128];
unsigned int bytesin; /* bytes in inbuffer */
unsigned int bytesout; /* bytes in out buffer */
unsigned buffersize; /* for search buffer and index */
unsigned long totalbytesread;
char onetab[] = {9,0};
char * inbuffer;
char * outbuffer;
char * outpointer;
char * lid;
char * nextbyte;
char morein; // flag that indicates NOT end of file
unsigned long bytecounter;
union {
char * c;
unsigned int *w;
long * l;
} parser;
typedef struct {
int codeindex;
char *codetext;
} codelisttype;
codelisttype codelist[] = {
{0,"No Reason"},
{1,"Not Applicable"},
{2,"Unknown"},
{3,"Call Disconnected"},
{4,"CLID Authentication Failed"},
{5,"CLID Radius Timeout"},
{10,"Modem never detected DCD"},
{11,"DCD detected but went inactive"},
{12,"Modem result codes parse fail"},
{20,"TermSrv - user quit"},
{21,"TermSrv - idle timeout"},
{22,"TermSrv - exit Telnet"},
{23,"TermSrv - no IP Addr"},
{24,"TermSrv - exit Raw TCP"},
{25,"TermSrv - login failed"},
{26,"TermSrv - Raw TCP disabled"},
{27,"TermSrv - CTRL-C during login"},
{28,"TermSrv - Destroyed"},
{29,"TermSrv - user closed VirtConn"},
{30,"TermSrv - VirtConn destroyed"},
{31,"TermSrv - exit Rlogin"},
{32,"TermSrv - bad Rlogin option"},
{33,"TermSrv - not enough resources"},
{35,"MPP - no NULL msg timeout"},
{40,"PPP - LCP Timeout"},
{41,"PPP - LCP Negotiation failed"},
{42,"PPP - PAP Auth failed"},
{43,"PPP - CHAP Auth failed"},
{44,"PPP - Remote Auth failed"},
{45,"PPP - Receive Terminate Req"},
{46,"PPP - Receive Close Event"},
{47,"PPP - No NCP's were open"},
{48,"PPP - MP bundle unknown"},
{49,"PPP - LCP close MP add fail"},
{50,"Session Table Full"},
{51,"Out of resources"},
{52,"Invalid IP Address"},
{53,"Hostname resolution failed"},
{54,"Bad/missing port number"},
{60,"Host Reset"},
{61,"Connection refused"},
{62,"Connection timeout"},
{63,"Connection Closed"},
{64,"Network unreachable"},
{65,"Host unreachable"},
{66,"Network admin unreachable"},
{67,"Host admin unreachable"},
{68,"Port unreachable"},
{100,"Session Timeout"},
{101,"Invalid incoming user"},
{102,"Disconnect due to callback"},
{120,"Protocol disabled/unsupported"},
{150,"Disconnect requested by RADIUS"},
{151,"Disconnect by Local Admin"},
{160,"V110 timeout/sync retry exceed"},
{170,"PPP Auth Timeout exceeded"},
{180,"User executed Do..Hangup"},
{185,"Remote End Hung Up"},
{190,"Resource has been Quiesced"},
{195,"MAX Call duration reached"}
};
int numcodes = sizeof(codelist) / sizeof(codelist[0]);
char * strupr(char * instring)
{
int i,alength;
alength = strlen(instring);
if (alength > 120)
return instring; // something went wrong.
for (i=0;i<alength;i++)
instring[i] = toupper(instring[i]);
return instring;
}
void comment(char * astring)
{
// write a comment to STDERR
write(STDERR,astring,strlen(astring));
write(STDERR,crlf,strlen(crlf));
}
char * reason(int mystopcode)
{
int i;
// printf("%d Number of codes. Requested code: %d\n",numcodes,stopcode);
// sleep(1);
for (i=0;i<numcodes;i++)
{
if (codelist[i].codeindex == mystopcode)
{
return(codelist[i].codetext);
}
}
return(codelist[0].codetext);
}
void fileproblem(char * description, char * afilename)
{
char textout[128];
sprintf(textout,"%s [%s] error number %d = %s \n", description, afilename, errno, sys_errlist[errno]) ;
write(2,textout,strlen(textout)); // write to STD ERR
}
char * makefilename(char * username)
{
static char afilename[MAXUSERIDLENGTH+16];
int i;
char ch;
memset(afilename,0,sizeof(afilename));
strcpy(afilename,"users/");
for (i=0;i<MAXUSERIDLENGTH && i<strlen(username);i++)
{
ch=username[i];
if (isalnum(ch))
afilename[i+6]=ch;
else
afilename[i+6]='_';
}
return afilename;
}
char getabyte(void)
{
char ch;
if (inhandle==0) // yes, we need to open the file.
{
inhandle=open(filepath,O_RDONLY,S_IREAD);
if (inhandle <0)
{
fileproblem("Problem opening input file:",filepath);
exit(1);
}
}
if ((bytesin==0) && (!eoffound))
{
bytesin=(unsigned int) read(inhandle,inbuffer,buffersize);
// Check for error and exit if so.
if ((bytesin & 0xffff) == 0xffff) // error
{
fileproblem("Problem reading input file:",filepath);
close(inhandle);
exit(1);
}
lid = inbuffer + bytesin; // calculate a lid, or stopper, or fence, address.
nextbyte = inbuffer; // reset the read pointer
totalbytesread += bytesin;
printf("requested: %u loaded: %u Total: %lu \n",buffersize,bytesin,totalbytesread);
// Check for end of file. This is detected by retrieving fewer bytes than asked for.
// In the case of the previous read obtaining exactly the number of bytes that exist,
// the next read will obtain zero bytes, and the one after that, an error.
if (bytesin == buffersize)
morein=TRUE;
else
{
morein=FALSE;
}
}
ch = *nextbyte;
nextbyte++;
bytesin --;
if ((bytesin==0) && (morein==0)) eoffound=TRUE; // signal end of file.
// At exit, the data byte returned is GOOD if eoffound is false, or if
// it just turned true (ie, don't ENTER this function with eoffound = true)
// keep count globally of bytes issued. If you want the byte address
// of the byte that is about to be issued, capture and keep a copy of
// bytecounter BEFORE calling this function.
bytecounter++;
return(ch);
}
char newgetabyte(void)
{
char ch;
if (inhandle==0) // yes, we need to open the file.
{
inhandle=open(filepath,O_RDONLY,S_IREAD);
if (inhandle <0)
{
fileproblem("Problem opening input file:",filepath);
exit(1);
}
}
if ((bytesin==0) && (!eoffound))
{
memset(inbuffer,0,buffersize);
bytesin=(unsigned int) read(inhandle,inbuffer,buffersize);
printf("requested: %ud loaded: %ud \n",buffersize,bytesin);
// Check for error and exit if so.
if ((bytesin & 0xffff) == 0xffff) // error
{
bytesin=0;
eoffound=TRUE;
}
lid = inbuffer + bytesin; // calculate a lid, or stopper, or fence, address.
nextbyte = inbuffer; // reset the read pointer
/* Curiously, the read requests are not being fulfilled completely; so the
anticipation of more data is not working! We'll just have to read data
until it complains.
*/
}
ch = *nextbyte;
nextbyte++;
bytesin --;
// if ((bytesin==0) && (morein==0)) eoffound=TRUE; // signal end of file.
// At exit, the data byte returned is GOOD if eoffound is false, or if
// it just turned true (ie, don't ENTER this function with eoffound = true)
// keep count globally of bytes issued. If you want the byte address
// of the byte that is about to be issued, capture and keep a copy of
// bytecounter BEFORE calling this function.
bytecounter++;
return(ch);
}
char * getaline(void)
{
int onepointer;
static char oneline[LINESIZE];
char ch;
char endline;
memset(oneline,0,sizeof(oneline));
onepointer=0;
endline=FALSE;
do
{
if (!eoffound)
{
ch = getabyte();
if ((ch==10) || (ch==13))
{
if (onepointer > 0) endline = TRUE;
}
else
{
oneline[onepointer++] = ch;
if (onepointer >= (LINESIZE-1)) onepointer = LINESIZE-2;
}
}
// getaline exits when it finds an END LINE character and is
// not a null-line, or, if end-of-file is reached.
} while ((!eoffound) && (!endline));
return (oneline);
}
int writetouser(int userhandle,char * filename, char * astring)
{
// Write string to open file identified by userhandle
int alength;
int result;
alength=strlen(astring);
result=write(userhandle,astring,alength);
if ((result != alength) || (result == -1))
fileproblem("Problem with writetouser on file ",filename);
}
int openuserfile(char * afilename)
{
// Common user file opener. If file does not exist, create it and fill it with
// some header information. Several functions may choose to record something to
// The user files and they may, or may not, exist.
int userhandle;
char isproblem;
char outline[128];
char textout[128];
isproblem=FALSE;
userhandle=0;
// Sloppy, but for now, here is where we put the customer blocks:
if (strcmp("users/broyer",afilename)==0) return (0); // requested by email to not receive this message.
if (strcmp("users/jadams",afilename)==0) return (0); // requested by email to not receive this message.
if (strcmp("users/spiricon",afilename)==0) return (0); // requested by email to not receive this message.
memset(outline,0,sizeof(outline));
// First, test for existence of file.
userhandle=open(afilename,O_RDONLY,0660);
if (userhandle >0)
{
// It exists. REopen with Append
close(userhandle);
userhandle=0;
userhandle=open(afilename,O_APPEND|O_WRONLY,0666);
// sprintf(textout,"%s %d Opened for Append",afilename,userhandle);
// comment(textout);
if (userhandle < 0)
{
fileproblem("Cannot append to existing file",afilename);
return (0);
}
}
else
{
userhandle=0;
isproblem=TRUE;
fileproblem("Problem opening a user file:",afilename);
comment(">>>Trying to create it...");
userhandle=creat(afilename,0666);
if (userhandle <0) // probably doesn't exist
{
fileproblem("Problem creating a user file:",afilename);
return (0);
}
else
{
writetouser(userhandle,afilename,"Dear Digital Planet Customer,\r\n");
writetouser(userhandle,afilename," Ths is your monthly utilization report. It is not a bill.\r\n");
writetouser(userhandle,afilename,"It simply shows when you logged onto the internet, and got off.\r\n");
writetouser(userhandle,afilename," Procedures for password changing, a more detailed explanation\r\n");
writetouser(userhandle,afilename,"of this report, and other help may be found on our web server:\r\n\r\n");
writetouser(userhandle,afilename,"http://www.digitalpla.net/support\r\n\r\n");
}
}
if (isproblem)
{
comment("Fixed!");
}
return (userhandle);
}
void recordastomp(char * username, int portid)
{
int userhandle;
int byteswritten;
long seekresult;
char afilename[MAXUSERIDLENGTH+16];
char outline[128];
if (f_flag ==0) return; // don't record a stomp if user files are turned off.
strcpy(afilename,makefilename(username));
userhandle=openuserfile(afilename);
if (f_flag && (userhandle >2))
{
sprintf(outline,"%s stomped; port %d in use by another user at %s\r\n",username,portid,datestring);
seekresult=lseek(userhandle,0,SEEK_END);
if (seekresult<0)
fileproblem("(recordastomp)Problem seeking end-of-file on a user file:",afilename);
else
{
byteswritten=write(userhandle,outline,strlen(outline));
if (byteswritten != strlen(outline))
fileproblem("(recordastomp)Problem writing to a user file:",afilename);
}
close(userhandle);
userhandle=0;
} // end of "if f_flag" to write individual user data files.
}
int getuser(char * username)
{
char founduser;
int testuser;
// searches for username in the user data array. Returns with index number.
// If user name not found, then it is added, and then returns with index number.
founduser = FALSE;
for (testuser=0;testuser<numusers;testuser++)
{
if (strcmp(allusers[testuser].user,username)==0)
{
founduser = TRUE;
break;
}
}
if (!founduser)
{
// name is not in the array. Just add it here.
strncpy(allusers[testuser].user,username,MAXUSERIDLENGTH-1);
if (numusers < MAXUSERS) numusers++;
}
return(testuser);
}
void storedb(char * username, unsigned long seconds, Recordtypes recordtype)
{
// warning, uses some globals.
// Prepares data for subsequent import into a database (tab delimited)
char outline[1000];
int byteswritten;
if ((recordtype == START) && s_flag)
{
sprintf(outline,"START\t%s\t%d\t%s %s\t%8.3f\t%s\t%s\t%s\t%ld\t%ld\t%ld\t%d\n",
username,
portid,
datestring,
timestring,
((double)0.0),
ipaddress,
ipfirst,
reason(stopcode),
baudrate,
bytes2user,
bytesfmuser,
presessiontime
);
byteswritten=write(db_handle,outline,strlen(outline));
}
if (recordtype == STOP)
{
sprintf(outline,"STOP\t%s\t%d\t%s %s\t%8.3f\t%s\t%s\t%s\t%ld\t%ld\t%ld\t%d\n",
username,
portid,
datestring,
timestring,
((double)seconds/3600.0),
ipaddress,
ipfirst,
reason(stopcode),
baudrate,
bytes2user,
bytesfmuser,
presessiontime
);
// printf("%s\n",outline);
byteswritten=write(db_handle,outline,strlen(outline));
if (byteswritten < 0)
{
fileproblem("Problem writing to database file",db_text);
exit (1);
}
// printf("%d \n",byteswritten);
// sleep(1);
}
}
void storedata(char * username, char * filename,
unsigned long seconds, time_t recordtime, Recordtypes recordtype)
{
// Input: ONE record to be stored.
// Output: Stores the record on a disk file
// Assumption: openfile will open user file, create and
// initilize if needed, and leave in append mode.
char outline[LINESIZE];
char temps[60];
int curuser,altuser; // Pointers within alluser array.
long concurrenttime; // Session concurrency computed from first concurrent login time.
long seekresult;
time_t checktime;
time_t timecharged;
int byteswritten;
int userhandle;
memset (outline,0,sizeof(outline));
checktime=timecharged=0;
concurrenttime =0;
curuser=getuser(username); // Get or add user to array and remember where it is.
// open file here for any type that needs it.
if ((f_flag) && ((recordtype==START) || (recordtype == STOP)) && (strlen(username)>0))
{
userhandle=openuserfile(filename);
if (userhandle <=2)
fileproblem("Open customer file failed",filename);
}
if (userhandle <=0) userhandle=0;
if (recordtype == STOP)
{
concurrenttime = 0;
ports[portid][0]=0;
// Serious problems occasionally with the Radius timestamps. Use
// The lesser of Radius timestamp or my own calculation.
checktime=recordtime - allusers[curuser].logontime;
if (((checktime > 0) && (checktime < seconds)) || (seconds == 0))
timecharged = checktime;
else
timecharged += seconds; // use lesser.
allusers[curuser].totalseconds += timecharged; // use lesser.
// the above uses the Radius time-stamp time.
// Log the user out.
if (allusers[curuser].logins >0) allusers[curuser].logins--;
// Now let us compute the concurrency time, if any.
// Any remaining logins?
if (allusers[curuser].logins>0)
{
// We have concurrency!
if ((allusers[curuser].startconcurrent) && (recordtime > 0))
concurrenttime = recordtime - allusers[curuser].startconcurrent;
// This is session concurrency. Add to accumulator and reset
// startconcurrent to present record time if logins is SILL >1
// or to zero if logins is 1 (end concurrent period).
allusers[curuser].totalconcurrent += concurrenttime;
if (allusers[curuser].logins >1)
allusers[curuser].startconcurrent = recordtime;
else
allusers[curuser].startconcurrent = 0; // stop concurrency
}
if (f_flag && (userhandle >2))
{
sprintf(outline," %s port %-3d STOP at %s, used %8.3f hours. Code: %s ",
username,portid,datestring,((double)timecharged/3600.0),reason(stopcode));
if (concurrenttime)
{
strcat(outline,"Concurrent: ");
sprintf(temps,"%8.3f",((double)concurrenttime/3600.0));
strcat(outline,temps);
}
strncat(outline,crlf,strlen(crlf));
//seekresult=lseek(userhandle,0,SEEK_END);
//if (seekresult<0)
//{
// printf("User handle: %d ",userhandle);
// fileproblem("Problem seeking end-of-file on a user file:",filename);
//}
//else
//{
byteswritten=write(userhandle,outline,strlen(outline));
if (byteswritten != strlen(outline))
fileproblem("Problem writing to a user file:",filename);
//}
} // end of "if f_flag" to write individual user data files.
}
// If the type of entry is "Start" we now have enough to write
// the individual user entry file, if enabled.
if (recordtype == START)
{
// Am I already on this port? (that is, did I get cut off and am
// I logging right back in?) IF so, it does not count toward concurrency.
if (ports[portid][0]!=0)
{
// OK, someone is already on this port. Who? Register a "stomped"
// message and count login if not present user; but if present user,
// and still marked logged in, then leave it just marked logged in.
if (strcmp(ports[portid],username)!=0)
{
// User was stomped.
printf("User %s stomped by user %s on port %d on %s\n",ports[portid],username,portid,datestring);
allusers[curuser].logins++; // add a login for THIS user
recordastomp(ports[portid],portid);
// We'd better fix up the info for the user that got stomped.
altuser=getuser(ports[portid]); // get array index for the stomped user
// Next, reduce the stomped user's login count.
if (allusers[altuser].logins > 0) allusers[altuser].logins--;
// Next, if the result of the reduction makes it zero, clean out
// Any residual memory of concurrency.
if (allusers[altuser].logins == 0)
{
allusers[altuser].logontime = 0;
allusers[altuser].startconcurrent = 0;
}
}
else
{
// must be same user stomping himself. Obviously cannot be concurrent.
if (allusers[curuser].logins==0)
{
allusers[curuser].logins++; // add a login if not marked logged in
}
}
}
else
{
// Free port, add a login to this user
allusers[curuser].logins++; // change state to logged in.
}
// In all cases, store the current user of this port.
memset(ports[portid],0,sizeof(ports[0]));
strncpy(ports[portid],username,sizeof(ports[0])-1);
if (allusers[curuser].logins >1) // do we have concurrency?
{
// Yes, we have concurrent login, remember the time it started.
if (recordtime)
allusers[curuser].startconcurrent = recordtime;
}
else
{
// First (nonconcurrent) logon.
if (recordtime)
allusers[curuser].logontime = recordtime;
}
if (f_flag && (userhandle >2))
{
// username start/stop port time date-time-text [Concurrency data]
sprintf(outline,"%s port %-3d START at %s. ",
username,portid,datestring);
// strcpy(outline,username);
// strcat(outline,onetab);
// strcat(outline,"Start");
// strcat(outline,onetab);
// itoa(portid,temps,10);
// strcat(outline,temps);
// strcat(outline,onetab);
// strcat(outline,datestring);
if (allusers[curuser].logins > 1)
{
strcat(outline,onetab);
strcat(outline,"Concurrent (Multi-port) Login detected");
}
strncat(outline,crlf,strlen(crlf));
//seekresult=lseek(userhandle,0,SEEK_END);
//if (seekresult<0)
// fileproblem("Problem seeking end-of-file on a user file:",filename);
//else
//{
byteswritten=write(userhandle,outline,strlen(outline));
if (byteswritten != strlen(outline))
fileproblem("Problem writing to a user file:",filename);
//}
} // end of if-f_flag
} // end of if-recordtype=START
if (userhandle>0)
{
close(userhandle);
userhandle=0;
}
}
void storetotals(void)
{
char outline[LINESIZE];
char filename[MAXUSERIDLENGTH+16];
int curuser; // Pointers within alluser array.
long seekresult;
int byteswritten;
int userhandle;
for (curuser=0;curuser<numusers;curuser++)
{
memset (outline,0,sizeof(outline));
memset (filename,0,sizeof(filename));
// open file here for any type that needs it.
strncpy(filename,makefilename(allusers[curuser].user),sizeof(filename)-1);
userhandle=openuserfile(filename);
if (userhandle <=2) userhandle=0;
if (userhandle)
{
// seekresult=lseek(userhandle,0,SEEK_END);
// if (seekresult<0)
// fileproblem("Problem seeking end-of-file on a user file:",filename);
// else
// {
sprintf(outline,"\r\nTotal Hours Used by %s: %4.3lf and concurrent usage of %4.3lf\r\n",
allusers[curuser].user,
(double)((double)allusers[curuser].totalseconds/3600.0),
(double)((double)allusers[curuser].totalconcurrent/3600.0));
byteswritten=write(userhandle,outline,strlen(outline));
if (byteswritten != strlen(outline))
fileproblem("Problem writing to a user file:",filename);
// }
close(userhandle);
userhandle=0;
}
}
}
void parsemessages(void)
{
/* description of the expected input (Radius Authorization Log) file
Wed Jul 23 18:17:27 1997
User-Name = "eyestorm"
NAS-Identifier = 208.23.23.150
NAS-Port = 20208
Acct-Status-Type = Stop
Acct-Delay-Time = 0
Acct-Session-Id = "238007122"
Acct-Authentic = RADIUS
Acct-Session-Time = 1757
Acct-Input-Octets = 30896
Acct-Output-Octets = 715465
Acct-Input-Packets = 1353
Acct-Output-Packets = 3658
Ascend-Disconnect-Cause = 11
Ascend-Connect-Progress = 65
Ascend-Data-Rate = 24000
Ascend-PreSession-Time = 25
Ascend-Pre-Input-Octets = 276
Ascend-Pre-Output-Octets = 289
Ascend-Pre-Input-Packets = 11
Ascend-Pre-Output-Packets = 10
Ascend-First-Dest = 207.201.65.10
Framed-Protocol = PPP
Framed-Address = 208.23.23.175
Wed Jul 23 18:18:26 1997
User-Name = "deanb"
NAS-Identifier = 208.23.23.150
NAS-Port = 20202
Acct-Status-Type = Start
Acct-Delay-Time = 0
Acct-Session-Id = "238007148"
Acct-Authentic = RADIUS
Framed-Protocol = PPP
Framed-Address = 208.23.23.153
-------------------------------------------------------------------- */
int i;
char ch;
char * beginuserid;
char * enduserid;
char * x; // generic char pointer
int namesize;
char oneline[LINESIZE];
// Current text record accumulators
char username[LINESIZE]; // The username
char filename[MAXUSERIDLENGTH+6]; // A fixed-up username with .USR suffixed
char temps[40];
unsigned long seconds; // time used converted to binary
time_t recordtime; // the binary time of this text record.
Recordtypes recordtype; // Tokenized record type
int result;
// Time stuff
struct tm time_check;
char atoken[4];
memset (oneline,0,sizeof(oneline));
memset (atoken,0,sizeof(atoken));
memset (username,0,sizeof(username));
memset (datestring,0,sizeof(datestring));
portid=0;
seconds=0;
recordtime=0;
stopcode=0;
memset(ipaddress,0,sizeof(ipaddress));
memset(ipfirst,0,sizeof(ipfirst));
recordtype=NORECORDTYPE;
do
{
if (eoffound) break;
strcpy(oneline,getaline());
// What kind of line is it?
strncpy(atoken,oneline,3); // copy just first three bytes.
if ((strcmp(atoken,"Mon")==0) ||
(strcmp(atoken,"Tue")==0) ||
(strcmp(atoken,"Wed")==0) ||
(strcmp(atoken,"Thu")==0) ||
(strcmp(atoken,"Fri")==0) ||
(strcmp(atoken,"Sat")==0) ||
(strcmp(atoken,"Sun")==0))
{ // we have a master record line. Parsing of previous record is complete,
// so do something with held data. If no data held, this is the first
// record, or prior record was not proper in some way. Use "Datestring"
// for existence flag.
if (datestring[0])
{ if (db_flag) storedb(username,seconds,recordtype);
storedata(username,filename,seconds,recordtime,recordtype);
}
recordtype = NORECORDTYPE;
memset(ipaddress,0,sizeof(ipaddress));
memset(ipfirst,0,sizeof(ipfirst));
memset (atoken,0,sizeof(atoken));
memset (username,0,sizeof(username));
memset (datestring,0,sizeof(datestring)); // also serves as record parse flag
stopcode = 0;
baudrate = 0;
presessiontime = 0;
bytes2user = 0;
bytesfmuser = 0;
portid=0;
seconds=0;
recordtime=0;
recordtype=NORECORDTYPE;
// The following is the quitter.
if (q_flag)
{
if (strstr(oneline,q_text))
{
eoffound = TRUE;
return; // leave this function immediately.
}
}
if (m_flag) // This is the selector
{
if (strstr(oneline,m_text))
strncpy(datestring,&oneline[4],sizeof(datestring)-1);
}
else
strncpy(datestring,&oneline[4],sizeof(datestring)-1);
if (d_flag) // Delete this record, reset logged in users
{
if (strstr(oneline,d_text))
{
memset(datestring,0,sizeof(datestring)); // make sure it doesn't write
memset(ports,0,sizeof(ports));
for (i=0;i<numusers;i++)
{
allusers[i].logins=0;
allusers[i].logontime=0;
allusers[i].startconcurrent=0;
}
}
}
// OK, shall we continue? Absent datestring means no.
if (strlen(datestring)==0) continue;
// convert datestring into binary seconds.
// int sscanf(const char *buffer, const char *format[, address, ...]);
// First, space out the colons so sscanf can grab the tokens
for (i=0;i<strlen(oneline);i++)
if (oneline[i]==':') oneline[i]=' ';
// now let sscanf grab and store date tokens. "Mon Nov 18 16 50 45 1996 "
memset(&time_check,0,sizeof(time_check));
recordtime=0;
result=sscanf(&oneline[4],"%3s %d %d %d %d %d",temps,&time_check.tm_mday,
&time_check.tm_hour,&time_check.tm_min,&time_check.tm_sec,&time_check.tm_year);
if (result != 6)
{
write(STDERR,"Problem in sscanf()",strlen("Problem in sscanf()"));
write(STDERR,crlf,strlen(crlf));
recordtime=0;
}
else
{
// Now convert the tokens to a binary time and store it in the temporary record.
if (strcmp(temps,"Jan")==0) time_check.tm_mon = 0;
else if (strcmp(temps,"Feb")==0) time_check.tm_mon = 1;
else if (strcmp(temps,"Mar")==0) time_check.tm_mon = 2;
else if (strcmp(temps,"Apr")==0) time_check.tm_mon = 3;
else if (strcmp(temps,"May")==0) time_check.tm_mon = 4;
else if (strcmp(temps,"Jun")==0) time_check.tm_mon = 5;
else if (strcmp(temps,"Jul")==0) time_check.tm_mon = 6;
else if (strcmp(temps,"Aug")==0) time_check.tm_mon = 7;
else if (strcmp(temps,"Sep")==0) time_check.tm_mon = 8;
else if (strcmp(temps,"Oct")==0) time_check.tm_mon = 9;
else if (strcmp(temps,"Nov")==0) time_check.tm_mon = 10;
else if (strcmp(temps,"Dec")==0) time_check.tm_mon = 11;
// Now reconstruct date string for export.
sprintf(datestring,"%02d/%02d/%4d",time_check.tm_mon+1,time_check.tm_mday,time_check.tm_year);
sprintf(timestring,"%d:%02d:%02d",time_check.tm_hour,time_check.tm_min,time_check.tm_sec);
time_check.tm_year -= 1900;
recordtime = mktime(&time_check);
if (recordtime == (time_t)(-1))
{
comment("Problem in mktime()");
recordtime=0;
}
}
}
else // perhaps we have a detail line?
{
if (((atoken[0]==' ') || (atoken[0]=='\t')) && (datestring[0] != 0)) // we have a detail line!
{
// what KIND of detail line do we have?
if (strstr(oneline,"Acct-Status-Type ="))
{
if (strstr(&oneline[11],"Start"))
recordtype = START;
else if (strstr(&oneline[11],"Stop"))
recordtype = STOP;
}
else if (x=strstr(oneline,"User-Name = "))
{
beginuserid = x + 13;
if (enduserid=strchr(beginuserid,'\"'))
{
// no suffix, just don't include the trailing quote.
namesize=enduserid-beginuserid;
if (namesize > MAXUSERIDLENGTH) namesize=MAXUSERIDLENGTH;
if (namesize < 0) namesize=1;
strncpy(username,beginuserid,namesize);
}
// Here create the filename for further usage.
strcpy(filename,makefilename(username));
}
else if (strstr(oneline,"Acct-Session-Time ="))
{
seconds = atol(&oneline[21]);
}
//===========
else if (strstr(oneline,"Framed-Address = "))
{
strncpy(ipaddress,&oneline[18],sizeof(ipaddress)-1);
}
else if (strstr(oneline,"Ascend-First-Dest ="))
{
strncpy(ipfirst,&oneline[21],sizeof(ipfirst)-1);
}
else if (strstr(oneline,"Ascend-Data-Rate ="))
{
baudrate = atol(&oneline[20]);
}
else if (strstr(oneline,"Ascend-Disconnect-Cause ="))
{
stopcode = atoi(&oneline[27]);
}
else if (strstr(oneline,"Acct-Output-Octets = "))
{
bytes2user = atol(&oneline[22]);
}
else if (strstr(oneline,"Acct-Input-Octets = "))
{
bytesfmuser = atol(&oneline[21]);
}
else if (strstr(oneline,"Ascend-PreSession-Time = "))
{
presessiontime = atoi(&oneline[26]);
}
//===========
else if (strstr(oneline,"NAS-Port ="))
{
portid = 0;
portid = atoi(&oneline[12]);
if ((portid >20100) && (portid <= 20124)) // T1 Line 1
portid = portid - 20100; // convert to ports 1-24
else
if ((portid >20200) && (portid <= 20224)) // T1 Line 2
portid = portid - 20200 + 24; // convert to ports 25-48
else
if ((portid >20300) && (portid <= 20324)) // T1 Line 2
portid = portid - 20300 + 48; // convert to ports 49-72
else
if ((portid >20400) && (portid <= 20424)) // T1 Line 2
portid = portid - 20400 + 72; // convert to ports 73-96
if (portid >= MAXPORTS) portid = 0;
}
} // end of "if we found a detail line"
} // end of "else not a master record"
} while (!eoffound);
// Might be the last record stuck in the buffers. Check variables and
// if they constitute a full record, write it.
if (datestring[0] && username[0] && (recordtype==START || recordtype==STOP))
{ if (db_flag) storedb(username,seconds,recordtype);
storedata(username,filename,seconds,recordtime,recordtype);
}
}
void oops(void)
{
comment("Usage: calctime -i inputpath/name [-f] [-s] [-m <matchstring>] [-d <matchstring>] ");
comment("-o Output File. If absent, STDOUT is assumed.");
comment("-f Create and append to user files (*.usr) time records for each.");
comment("-s Include START records (helps with concurrency problems) ");
comment("-h <file> Create Histogram file ");
comment("-m <text> Match master records, extract when dateline contains this string.");
comment("-q <text> Quit processing auth file when it sees this text on dateline. ");
comment("-d <text> Delete records containing this string (date) in dateline. ");
comment(" (Resets remembered logins) ");
comment("-db <file> DataBase Export, tab delimited, ");
comment("STDOUT Output is to Standard Output. ");
exit(1);
}
int main(int argc, char * argv[])
{
int i;
int outhandle;
int curuser;
int byteswritten;
char outline[256];
buffersize=BUFFSIZE;
inbuffer=(char *) malloc(buffersize);
if (inbuffer==NULL)
{
puts("Not enough memory for input buffer");
printf("Amount asked for %u bytes \n",buffersize);
exit(1);
}
memset(inbuffer,0,buffersize);
outbuffer=(char *) malloc(buffersize);
if (outbuffer==NULL)
{ puts("Not enough memory for output buffer");
printf("Amount asked for %u bytes \n",buffersize);
exit(1);
}
memset(outbuffer,0,buffersize);
bytesout=0;
outpointer=outbuffer;
m_flag=s_flag=f_flag=q_flag=o_flag=d_flag=db_flag=FALSE;
memset(m_text,0,sizeof(m_text));
memset(d_text,0,sizeof(d_text));
memset(q_text,0,sizeof(q_text));
memset(filepath,0,sizeof(filepath));
memset(outfilepath,0,sizeof(outfilepath));
memset(allusers,0,sizeof(allusers));
numusers=0;
memset(ports,0,sizeof(ports));
numports=curport=0;
// make a directory for the user files
mkdir("users",0770);
for (i=0;i<argc;i++)
{
if (strcmp(strupr(argv[i]),"-F")==0)
f_flag = TRUE;
else if (strcmp(strupr(argv[i]),"-S")==0)
{
s_flag = TRUE;
}
else if (strcmp(strupr(argv[i]),"-DB")==0)
{
db_flag = TRUE;
strncpy(db_text,argv[i+1],sizeof(db_text)-1);
i++;
}
else if (strcmp(strupr(argv[i]),"-M")==0)
{
m_flag = TRUE;
strncpy(m_text,argv[i+1],sizeof(m_text)-1);
i++;
}
else if (strcmp(strupr(argv[i]),"-H")==0)
{
h_flag = TRUE;
strncpy(histogramfilename,argv[i+1],sizeof(histogramfilename)-1);
i++;
}
else if (strcmp(strupr(argv[i]),"-D")==0)
{
d_flag = TRUE;
strncpy(d_text,argv[i+1],sizeof(d_text)-1);
printf("Deleting days: %s\n",d_text);
i++;
}
else if (strcmp(strupr(argv[i]),"-Q")==0)
{
q_flag = TRUE;
strncpy(q_text,argv[i+1],sizeof(q_text)-1);
i++;
}
else if (strcmp(strupr(argv[i]),"-I")==0)
{
strncpy(filepath,argv[i+1],sizeof(filepath)-1);
i++;
}
else if (strcmp(strupr(argv[i]),"-O")==0)
{
o_flag=TRUE;
strncpy(outfilepath,argv[i+1],sizeof(outfilepath)-1);
i++;
}
}
if (strlen(filepath)==0)
oops();
if (m_flag && (strlen(m_text)==0))
oops();
if (d_flag && (strlen(d_text)==0))
oops();
if (db_flag && (strlen(db_text)==0))
oops();
if (q_flag && (strlen(q_text)==0))
oops();
if (o_flag)
{
// Test writeability before wasting a lot of time.
outhandle=open(outfilepath,O_WRONLY|O_CREAT,0660);
if (outhandle<=0)
{
fileproblem("Problem creating the output file:",outfilepath);
write(STDERR,crlf,strlen(crlf));
exit(1);
}
close(outhandle);
outhandle=0;
}
if (db_flag)
{
db_handle=open(db_text,O_WRONLY|O_TRUNC|O_CREAT,0660);
if (db_handle<=0)
{
fileproblem("Problem creating the database file:",db_text);
write(STDERR,crlf,strlen(crlf));
exit(1);
}
}
// Output file is open if flag is true.
parsemessages();
if (db_handle) close(db_handle);
// Now write out the array
for (curuser=0;curuser<numusers;curuser++)
{
printf("%s\t%6.3lf\t%6.3lf\n",allusers[curuser].user,
(double)(allusers[curuser].totalseconds/3600.0),
(double)(allusers[curuser].totalconcurrent/3600.0));
}
// if f-flag, write out the total time to each customer file
if (f_flag) storetotals();
if (o_flag)
{
// outhandle=open(outfilepath,O_TRUNC|O_CREAT,0660);
outhandle=open(outfilepath,O_WRONLY|O_TRUNC|O_CREAT);
if (outhandle<=0)
{
fileproblem("Problem creating the output file:",outfilepath);
write(STDERR,crlf,strlen(crlf));
exit(1);
}
else
{
for (curuser=0;curuser<numusers;curuser++)
{
sprintf(outline,"%s\t%6.3lf\t%6.3lf\r\n",
allusers[curuser].user,
(double)(allusers[curuser].totalseconds/3600.0),
(double)(allusers[curuser].totalconcurrent/3600.0));
byteswritten=write(outhandle,outline,strlen(outline));
if (byteswritten < 0)
{
fileproblem("Problem writing the results file:",outfilepath);
exit(1);
}
}
close(outhandle);
}
}
return (0);
}