/********************************************************
* File: crashstats.c
* Created at Sun Jan 28 22:10:33 MSK 2001 by raorn // raorn@binec.ru
* CrashStats - statistics generation utility
* $Id: crashstats.c,v 1.17 2002/01/10 02:04:09 raorn Exp $
*******************************************************/
#include <machine/defs.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#elif HAVE_SYS_TIME
# include <sys/time.h>
#else
# include <time.h>
#endif
#include <signal.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#else
# include <shared/getopt.h>
#endif
#include <shared/jblist.h>
#include <shared/node4d.h>
uchar verstr[] = "CrashStats/" PLATFORM_NAME " " VERSION;
#define STATS_IDENTIFIER "CST3"
struct DiskAreaStats {
uchar Tagname[80];
struct Node4D Aka;
uchar Group;
uchar fill_to_make_even; /* Just ignore this one */
ulong TotalTexts;
ushort Last8Days[8];
ulong Dupes;
time_t FirstTime;
time_t LastTime;
};
struct DiskNodeStats {
struct Node4D Node;
ulong GotNetmails;
ulong GotNetmailBytes;
ulong SentNetmails;
ulong SentNetmailBytes;
ulong GotEchomails;
ulong GotEchomailBytes;
ulong SentEchomails;
ulong SentEchomailBytes;
ulong Dupes;
time_t FirstTime;
};
struct StatsNode {
struct StatsNode *Next;
uchar Tagname[80];
ulong Average;
ulong Total;
ulong Dupes;
time_t FirstTime;
time_t LastTime;
ushort Last8Days[8];
};
struct NodeStatsNode {
struct NodeStatsNode *Next;
struct Node4D Node;
ulong GotNetmails;
ulong GotNetmailBytes;
ulong SentNetmails;
ulong SentNetmailBytes;
ulong GotEchomails;
ulong GotEchomailBytes;
ulong SentEchomails;
ulong SentEchomailBytes;
ulong Dupes;
ulong Days;
time_t FirstTime;
};
#define SHOWVER 128
#define NOAREAS 129
#define NONODES 130
bool diskfull;
int CompareAlpha(const void *a1, const void *a2)
{
struct StatsNode **s1, **s2;
s1 = (struct StatsNode **) a1;
s2 = (struct StatsNode **) a2;
return (stricmp((*s1)->Tagname, (*s2)->Tagname));
}
int CompareTotal(const void *a1, const void *a2)
{
struct StatsNode **s1, **s2;
s1 = (struct StatsNode **) a1;
s2 = (struct StatsNode **) a2;
if ((*s1)->Total < (*s2)->Total)
return (1);
if ((*s1)->Total > (*s2)->Total)
return (-1);
return (0);
}
int CompareDupes(const void *a1, const void *a2)
{
struct StatsNode **s1, **s2;
s1 = (struct StatsNode **) a1;
s2 = (struct StatsNode **) a2;
if ((*s1)->Dupes < (*s2)->Dupes)
return (1);
if ((*s1)->Dupes > (*s2)->Dupes)
return (-1);
return (0);
}
int CompareMsgsDay(const void *a1, const void *a2)
{
struct StatsNode **s1, **s2;
s1 = (struct StatsNode **) a1;
s2 = (struct StatsNode **) a2;
if ((*s1)->Average < (*s2)->Average)
return (1);
if ((*s1)->Average > (*s2)->Average)
return (-1);
return (0);
}
int CompareFirstTime(const void *a1, const void *a2)
{
struct StatsNode **s1, **s2;
s1 = (struct StatsNode **) a1;
s2 = (struct StatsNode **) a2;
if ((*s1)->FirstTime < (*s2)->FirstTime)
return (1);
if ((*s1)->FirstTime > (*s2)->FirstTime)
return (-1);
return (0);
}
int CompareLastTime(const void *a1, const void *a2)
{
struct StatsNode **s1, **s2;
s1 = (struct StatsNode **) a1;
s2 = (struct StatsNode **) a2;
if ((*s1)->LastTime < (*s2)->LastTime)
return (1);
if ((*s1)->LastTime > (*s2)->LastTime)
return (-1);
return (0);
}
bool Sort(struct jbList * list, uchar sortmode)
{
ulong nc;
struct StatsNode *sn, **buf, **work;
nc = 0;
for (sn = (struct StatsNode *) list->First; sn; sn = sn->Next)
nc++;
if (nc == 0)
return (TRUE); /* Nothing to sort */
if (!(buf = (struct StatsNode **) malloc(nc * sizeof(struct StatsNode *))))
return (FALSE);
work = buf;
for (sn = (struct StatsNode *) list->First; sn; sn = sn->Next)
*work++ = sn;
switch (sortmode) {
case 'a':
qsort(buf, nc, 4, CompareAlpha);
break;
case 't':
qsort(buf, nc, 4, CompareTotal);
break;
case 'm':
qsort(buf, nc, 4, CompareMsgsDay);
break;
case 'd':
qsort(buf, nc, 4, CompareFirstTime);
break;
case 'l':
qsort(buf, nc, 4, CompareLastTime);
break;
case 'u':
qsort(buf, nc, 4, CompareDupes);
break;
}
jbNewList(list);
for (work = buf; nc--;)
jbAddNode(list, (struct jbNode *) *work++);
free(buf);
return (TRUE);
}
int CompareNodes(const void *a1, const void *a2)
{
struct NodeStatsNode **s1, **s2;
s1 = (struct NodeStatsNode **) a1;
s2 = (struct NodeStatsNode **) a2;
return (Compare4D(&(*s1)->Node, &(*s2)->Node));
}
bool SortNodes(struct jbList * list)
{
struct NodeStatsNode *sn, **buf, **work;
ulong nc;
nc = 0;
for (sn = (struct NodeStatsNode *) list->First; sn; sn = sn->Next)
nc++;
if (nc == 0)
return (TRUE); /* Nothing to sort */
if (!(buf = (struct NodeStatsNode **) malloc(nc * sizeof(struct NodeStatsNode *))))
return (FALSE);
work = buf;
for (sn = (struct NodeStatsNode *) list->First; sn; sn = sn->Next)
*work++ = sn;
qsort(buf, nc, 4, CompareNodes);
jbNewList(list);
for (work = buf; nc--;)
jbAddNode(list, (struct jbNode *) *work++);
free(buf);
return (TRUE);
}
char *unit(long i)
{
static char buf[40];
if ((i > 10000000) || (i < -10000000))
snprintf(buf, 40, "%ld MB", i / (1024 * 1024));
else if ((i > 10000) || (i < -10000))
snprintf(buf, 40, "%ld KB", i / 1024);
else
snprintf(buf, 40, "%ld bytes", i);
return buf;
}
bool CheckFlags(uchar group, uchar * node)
{
int c;
for (c = 0; c < strlen(node); c++) {
if (toupper(group) == toupper(node[c]))
return (TRUE);
}
return (FALSE);
}
ulong CalculateAverage(ushort * last8array, ulong total, ulong daystatswritten, time_t firstday)
{
ushort days, c;
ulong sum;
if (daystatswritten == 0 || firstday == 0)
return (0);
days = daystatswritten - firstday;
if (days > 7)
days = 7;
sum = 0;
for (c = 1; c < days + 1; c++)
sum += last8array[c];
if (days == 0)
days = 1;
if (sum == 0 && total != 0) {
days = daystatswritten - firstday;
if (days == 0)
days = 1;
return (total / days);
}
return (sum / days);
}
bool ctrlc;
RETSIGTYPE breakfunc(int x)
{
ctrlc = TRUE;
}
int main(int argc, char **argv)
{
FILE *fh;
ulong total, areas, totaldupes;
time_t firsttime, t;
ulong DayStatsWritten;
uchar buf[200], date[30], date2[30];
struct DiskAreaStats dastat;
struct DiskNodeStats dnstat;
struct StatsNode *sn;
struct NodeStatsNode *nsn;
struct jbList StatsList;
struct jbList NodesList;
ulong c, num, tot;
ushort total8days[8];
uchar sortmode = 'a', *groups = NULL;
int lastseven = 0, noareas = 0, nonodes = 0;
struct tm *tp;
uchar *monthnames[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec", "???"
};
static struct option lopts[] = {
{"help", 0, NULL, 'h'},
{"sort", required_argument, NULL, 's'},
{"groups", required_argument, NULL, 'g'},
{"last7", 0, NULL, '7'},
{"no-areas", 0, NULL, NOAREAS},
{"no-nodes", 0, NULL, NONODES},
{"version", 0, NULL, SHOWVER},
{0, 0, 0, 0}
};
static uchar optstr[] = "+hs:g:7an";
static uchar helpstr[] =
"Usage: crashstats [OPTION]... FILE\n"
"Display CrashEcho statistics.\n"
"\n"
" -h, --help display this help and exit\n"
" -s, --sort=MODE specifies the sort mode:\n"
" a - sort alphabetically\n"
" t - sort by total number of messages\n"
" m - sort by msgs/day\n"
" d - sort by first time messages were imported\n"
" l - sort by last time messages were imported\n"
" u - sort by number of dupes\n"
" -g, --groups=GROUPS areas in the specified GROUPS are included\n"
" -7, --last7 displays detailed information about the flow of\n"
" messages in areas for the last seven days\n"
" --no-areas hide area statistics\n"
" --no-nodes hide node statistics\n"
" --version print version number and exit\n\n";
int ch, lopt_index;
signal(SIGINT, breakfunc);
while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){
switch(ch){
case 'h':
case '?':
default:
fprintf(stderr, helpstr);
exit(EXIT_OK);
/* Not reached */
case SHOWVER:
fprintf(stderr, "%s\n", verstr);
exit(EXIT_OK);
/* Not reached */
case 's':
sortmode = tolower(optarg[0]);
break;
case 'g':
groups = optarg;
break;
case '7':
lastseven = 1;
break;
case NOAREAS:
noareas = 1;
break;
case NONODES:
nonodes = 1;
break;
}
}
argc -= optind;
argv += optind;
if(argc != 1){
fprintf(stderr, helpstr);
exit(EXIT_ERROR);
}
if (!strchr("amtdlu", sortmode)) {
fprintf(stderr, "Unknown sort mode %c\n", sortmode);
exit(EXIT_ERROR);
}
if (noareas && nonodes) {
fprintf(stderr, "Nothing to do\n");
exit(EXIT_ERROR);
}
if (!(fh = fopen(argv[0], "rb"))) {
fprintf(stderr, "Error opening %s\n", (char *) argv[0]);
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(EXIT_ERROR);
}
fread(buf, 4, 1, fh);
buf[4] = 0;
if (strcmp(buf, STATS_IDENTIFIER) != 0) {
fprintf(stderr, "Unknown format of stats file\n");
fclose(fh);
exit(EXIT_ERROR);
}
fread(&DayStatsWritten, sizeof(ulong), 1, fh);
total = 0;
totaldupes = 0;
firsttime = 0;
areas = 0;
for (c = 0; c < 8; c++)
total8days[c] = 0;
jbNewList(&StatsList);
jbNewList(&NodesList);
fread(&num, sizeof(ulong), 1, fh);
c = 0;
if (!noareas) {
while (c < num && fread(&dastat, 1, sizeof(struct DiskAreaStats), fh) == sizeof(struct DiskAreaStats)) {
if (!groups || CheckFlags(dastat.Group, groups)) {
if (!(sn = malloc(sizeof(struct StatsNode)))) {
fprintf(stderr, "Out of memory\n");
jbFreeList(&StatsList);
fclose(fh);
exit(EXIT_ERROR);
}
jbAddNode(&StatsList, (struct jbNode *) sn);
strcpy(sn->Tagname, dastat.Tagname);
sn->Dupes = dastat.Dupes;
sn->Total = dastat.TotalTexts;
sn->FirstTime = dastat.FirstTime;
sn->LastTime = dastat.LastTime;
memcpy(&sn->Last8Days[0], &dastat.Last8Days[0], 8 * sizeof(ushort));
sn->Average = CalculateAverage(&dastat.Last8Days[0], dastat.TotalTexts, DayStatsWritten, sn->FirstTime / (24 * 60 * 60));
}
if (dastat.FirstTime != 0)
if (firsttime == 0 || firsttime > dastat.FirstTime)
firsttime = dastat.FirstTime;
c++;
}
} else {
while (c < num && fread(&dastat, 1, sizeof(struct DiskAreaStats), fh) == sizeof(struct DiskAreaStats))
c++;
}
fread(&num, sizeof(ulong), 1, fh);
c = 0;
if (!nonodes) {
while (c < num && fread(&dnstat, 1, sizeof(struct DiskNodeStats), fh) == sizeof(struct DiskNodeStats)) {
if (!(nsn = malloc(sizeof(struct NodeStatsNode)))) {
fprintf(stderr, "Out of memory\n");
jbFreeList(&NodesList);
jbFreeList(&StatsList);
fclose(fh);
exit(EXIT_ERROR);
}
jbAddNode(&NodesList, (struct jbNode *) nsn);
Copy4D(&nsn->Node, &dnstat.Node);
nsn->GotNetmails = dnstat.GotNetmails;
nsn->GotNetmailBytes = dnstat.GotNetmailBytes;
nsn->SentNetmails = dnstat.SentNetmails;
nsn->SentNetmailBytes = dnstat.SentNetmailBytes;
nsn->GotEchomails = dnstat.GotEchomails;
nsn->GotEchomailBytes = dnstat.GotEchomailBytes;
nsn->SentEchomails = dnstat.SentEchomails;
nsn->SentEchomailBytes = dnstat.SentEchomailBytes;
nsn->Dupes = dnstat.Dupes;
nsn->Days = DayStatsWritten - dnstat.FirstTime % (24 * 60 * 60);
if (nsn->Days == 0)
nsn->Days = 1;
nsn->FirstTime = dnstat.FirstTime;
if (dnstat.FirstTime != 0)
if (firsttime == 0 || firsttime > dnstat.FirstTime)
firsttime = dnstat.FirstTime;
c++;
}
} else {
while (c < num && fread(&dnstat, 1, sizeof(struct DiskNodeStats), fh) == sizeof(struct DiskNodeStats))
c++;
}
fclose(fh);
t = (time_t) DayStatsWritten *24 * 60 * 60;
tp = localtime(&firsttime);
snprintf(date, 30, "%02d-%s-%02d", tp->tm_mday, monthnames[tp->tm_mon], tp->tm_year % 100);
tp = localtime(&t);
snprintf(date2, 30, "%02d-%s-%02d", tp->tm_mday, monthnames[tp->tm_mon], tp->tm_year % 100);
printf("\nStatistics from %s to %s\n", date, date2);
if (!ctrlc && !noareas) {
Sort(&StatsList, 'a');
Sort(&StatsList, sortmode);
printf("\n");
if (lastseven) {
printf("Area ");
for (c = 7; c > 0; c--) {
t = (DayStatsWritten - c) * 24 * 60 * 60;
tp = localtime(&t);
printf(" %02d", tp->tm_mday);
}
printf(" Total\n============================================================================\n");
if (!ctrlc) {
for (sn = (struct StatsNode *) StatsList.First; sn && !ctrlc; sn = sn->Next) {
tot = 0;
for (c = 7; c > 0; c--)
tot += sn->Last8Days[c];
printf("%-33.33s %4d %4d %4d %4d %4d %4d %4d : %5ld\n", sn->Tagname,
sn->Last8Days[7], sn->Last8Days[6], sn->Last8Days[5],
sn->Last8Days[4], sn->Last8Days[3], sn->Last8Days[2],
sn->Last8Days[1], tot);
for (c = 7; c > 0; c--)
total8days[c] += sn->Last8Days[c];
areas++;
}
if (!ctrlc) {
tot = 0;
for (c = 7; c > 0; c--)
tot += total8days[c];
printf("=============================================================================\n");
snprintf(buf, 200, "Totally in all %lu areas", areas);
printf("%-33.33s %4d %4d %4d %4d %4d %4d %4d : %5ld\n", buf,
total8days[7], total8days[6], total8days[5], total8days[4],
total8days[3], total8days[2], total8days[1], tot);
}
}
} else {
printf("Area First Last Msgs Msgs/day Dupes\n");
printf("============================================================================\n");
if (!ctrlc) {
for (sn = (struct StatsNode *) StatsList.First; sn && !ctrlc; sn = sn->Next) {
if (sn->LastTime == 0) {
strcpy(date2, " <Never> ");
} else {
tp = localtime(&sn->LastTime);
snprintf(date2, 30, "%02d-%s-%02d", tp->tm_mday, monthnames[tp->tm_mon], tp->tm_year % 100);
}
if (sn->FirstTime == 0) {
strcpy(date, " <Never> ");
} else {
tp = localtime(&sn->FirstTime);
snprintf(date, 30, "%02d-%s-%02d", tp->tm_mday, monthnames[tp->tm_mon], tp->tm_year % 100);
}
for (c = 0; c < 8; c++)
total8days[c] += sn->Last8Days[c];
total += sn->Total;
totaldupes += sn->Dupes;
areas++;
printf("%-30.30s %-9.9s %-9.9s %7ld %7ld %7ld\n", sn->Tagname, date, date2, sn->Total, sn->Average, sn->Dupes);
}
}
if (!ctrlc) {
printf("============================================================================\n");
snprintf(buf, 200, "Totally in all %lu areas", areas);
printf("%-42s %7ld %7ld %7ld\n", buf, total, CalculateAverage(&total8days[0], total, DayStatsWritten, firsttime / (24 * 60 * 60)), totaldupes);
}
}
}
if (!ctrlc && !nonodes) {
SortNodes(&NodesList);
printf("\n");
printf("Nodes statistics\n");
printf("================\n");
for (nsn = (struct NodeStatsNode *) NodesList.First; nsn && !ctrlc; nsn = nsn->Next) {
if (nsn->FirstTime == 0) {
strcpy(date, "<Never>");
} else {
tp = localtime(&nsn->FirstTime);
snprintf(date, 30, "%02d-%s-%02d", tp->tm_mday, monthnames[tp->tm_mon], tp->tm_year % 100);
}
snprintf(buf, 200, "%u:%u/%u.%u", nsn->Node.Zone, nsn->Node.Net, nsn->Node.Node, nsn->Node.Point);
printf("%-30.40s Statistics since: %s\n\n", buf, date);
printf(" Sent netmails: %lu/%s\n", nsn->SentNetmails, unit(nsn->SentNetmailBytes));
printf(" Received netmails: %lu/%s\n", nsn->GotNetmails, unit(nsn->GotNetmailBytes));
printf(" Sent echomails: %lu/%s\n", nsn->SentEchomails, unit(nsn->SentEchomailBytes));
printf(" Received echomails: %lu/%s\n", nsn->GotEchomails, unit(nsn->GotEchomailBytes));
printf(" Dupes: %lu\n", nsn->Dupes);
printf("\n");
}
}
if (ctrlc) {
printf("*** Break\n");
} else {
printf("\n");
}
jbFreeList(&StatsList);
jbFreeList(&NodesList);
exit(EXIT_OK);
}
syntax highlighted by Code2HTML, v. 0.9.1