/*
* LIB/STATS.C
*
* (c)Copyright 2000, Russell Vincent, All Rights Reserved. Refer to
* the COPYRIGHT file in the base directory of this distribution
* for specific rights granted.
*
*
* This file maintains access to shared stats structures for:
* outgoing feeds
*/
#include "defs.h"
#define FS_VERSION 1
Prototype FeedStats *FeedStatsFindSlot(char *hostname);
Prototype void LockFeedRegion(FeedStats *Stats, int locktype, int stype);
Prototype void FeedStatsClear(FILE *fo, char *hostname, int stype);
Prototype void FeedStatsDump(FILE *fo, char *hostname, int raw, int stype);
Prototype void FeedStatsSnapShot(FILE *fo, char *hostname, char *ext);
void dumpInStats(FILE *fo, char *hostname, FeedStats *fs, int raw);
void dumpInDetStats(FILE *fo, char *hostname, FeedStats *fs, int raw);
void dumpOutStats(FILE *fo, char *hostname, FeedStats *fs, int raw);
void dumpSpoolStats(FILE *fo, char *hostname, FeedStats *fs, int raw);
void dumpSpoolDetStats(FILE *fo, char *hostname, FeedStats *fs, int raw);
int FSSFd = -1;
int FRSFd = -1;
/**********************************************************************
* Outgoing feed stats routines
**********************************************************************/
/*
* FeedStatsFindSlot - locate a free area of a mmaped file that we use
* use to store some outgoing feed stats. The file will be created
* if it doesn't exist.
*/
FeedStats *
FeedStatsFindSlot(char *hostname)
{
FeedStats *Stats;
FeedStats fs;
int count;
int found;
if (FSSFd < 0) {
FSSFd = open(PatDbExpand(DFeedStatsPat), O_RDWR|O_CREAT, 0644);
if (FSSFd == -1) {
logit(LOG_ERR, "Unable to create feeder stats file: %s (%s)",
PatDbExpand(DFeedStatsPat), strerror(errno));
Stats = (FeedStats *)malloc(sizeof(FeedStats));
if (Stats == NULL) {
logit(LOG_CRIT, "Unable to alloc memory for stats struct");
exit(1);
}
bzero(Stats, sizeof(FeedStats));
return(Stats);
}
} else {
lseek(FSSFd, 0, 0);
}
hflock(FSSFd, 0, XLOCK_EX);
/*
* The first entry is a dummy entry
*/
if (read(FSSFd, &fs, sizeof(fs)) == 0) {
bzero(&fs, sizeof(fs));
strcpy(fs.hostname, "Outgoing Feeder Stats");
fs.SentStats.TimeStart = time(NULL);
fs.RecStats.TimeStart = time(NULL);
fs.SpoolStats.TimeStart = time(NULL);
fs.version = FS_VERSION;
write(FSSFd, &fs, sizeof(fs));
}
if (fs.version != FS_VERSION) {
logit(LOG_CRIT, "Feed stats db '%s' has wrong version - please delete",
PatDbExpand(DFeedStatsPat));
fprintf(stderr, "Feed stats db '%s' has wrong version - please delete\n",
PatDbExpand(DFeedStatsPat));
exit(1);
}
count = 1;
found = 0;
while (read(FSSFd, &fs, sizeof(fs)) > 0) {
if (strcmp(fs.hostname, hostname) == 0) {
found = 1;
break;
}
count++;
}
if (!found) {
bzero(&fs, sizeof(fs));
fs.region = count;
strcpy(fs.hostname, hostname);
lseek(FSSFd, count * sizeof(FeedStats), SEEK_SET);
write(FSSFd, &fs, sizeof(fs));
}
Stats = xmap(NULL, sizeof(FeedStats), PROT_READ|PROT_WRITE,
MAP_SHARED, FSSFd, count * sizeof(FeedStats));
hflock(FSSFd, 0, XLOCK_UN);
return(Stats);
}
/*
* LockFeedRegion - lock a region of the mmaped file so that we
* can safely update the values
*/
void
LockFeedRegion(FeedStats *Stats, int locktype, int stype)
{
if (Stats->region > 0) {
switch (stype) {
case FSTATS_IN:
case FSTATS_INDETAIL:
hflock(FSSFd, (int)&Stats->RecStats - (int)Stats, locktype);
break;
case FSTATS_OUT:
hflock(FSSFd, (int)&Stats->SentStats - (int)Stats, locktype);
break;
case FSTATS_SPOOL:
case FSTATS_SPOOLDETAIL:
hflock(FSSFd, (int)&Stats->SpoolStats - (int)Stats, locktype);
break;
}
}
}
/*
* FeedStatsClear - zero the stats
*/
void
FeedStatsClear(FILE *fo, char *hostname, int stype)
{
FeedStats *Stats;
FeedStats *fs;
struct stat st;
int count;
int cleared = 0;
FSSFd = open(PatDbExpand(DFeedStatsPat), O_RDWR, 0644);
if (FSSFd == -1) {
fprintf(fo, "Unable to open feeder stats file: %s (%s)\n",
PatDbExpand(DFeedStatsPat), strerror(errno));
return;
}
if (fstat(FSSFd, &st) != 0)
return;
fs = Stats = xmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, FSSFd, 0);
if (Stats == NULL) {
fprintf(fo, "Unable to mmap stats file: %s\n", strerror(errno));
return;
}
if (fs->version != FS_VERSION) {
fprintf(fo, "Feed stats db '%s' has wrong version - please delete\n",
PatDbExpand(DFeedStatsPat));
fflush(fo);
exit(1);
}
count = st.st_size / sizeof(FeedStats);
while (--count > 0) {
fs++;
if (hostname != NULL && strcmp(hostname, fs->hostname) != 0)
continue;
LockFeedRegion(fs, XLOCK_EX, stype);
switch(stype) {
case FSTATS_IN:
case FSTATS_INDETAIL:
if (fs->RecStats.TimeStart != 0) {
bzero(&fs->RecStats, sizeof(fs->RecStats));
fs->RecStats.TimeStart = time(NULL);
}
cleared++;
break;
case FSTATS_OUT:
if (fs->SentStats.TimeStart != 0) {
bzero(&fs->SentStats, sizeof(fs->SentStats));
fs->SentStats.TimeStart = time(NULL);
}
cleared++;
break;
case FSTATS_SPOOL:
case FSTATS_SPOOLDETAIL:
if (fs->SpoolStats.TimeStart != 0) {
bzero(&fs->SpoolStats, sizeof(fs->SpoolStats));
fs->SpoolStats.TimeStart = time(NULL);
}
cleared++;
break;
}
LockFeedRegion(fs, XLOCK_UN, stype);
}
xunmap(Stats, st.st_size);
close(FSSFd);
fprintf(fo, "Cleared %d records of type ", cleared);
switch (stype) {
case FSTATS_IN:
case FSTATS_INDETAIL:
printf("incoming\n");
break;
break;
case FSTATS_OUT:
printf("outgoing\n");
break;
case FSTATS_SPOOL:
case FSTATS_SPOOLDETAIL:
printf("spool\n");
break;
}
}
/*
* FeedStatsDump - print the feed stats
*/
void
FeedStatsDump(FILE *fo, char *hostname, int raw, int stype)
{
FeedStats *Stats;
FeedStats *fs;
struct stat st;
int count;
int totalonly = 0;
FeedStats ts;
int i;
if (hostname != NULL && strcmp(hostname, "TOTAL") == 0)
totalonly = 1;
FSSFd = open(PatDbExpand(DFeedStatsPat), O_RDONLY, 0644);
if (FSSFd == -1) {
fprintf(fo, "Unable to open feeder stats file: %s (%s)\n",
PatDbExpand(DFeedStatsPat), strerror(errno));
return;
}
if (fstat(FSSFd, &st) != 0)
return;
fs = Stats = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, FSSFd, 0);
if (Stats == NULL) {
fprintf(fo, "Unable to mmap stats file: %s\n", strerror(errno));
return;
}
if (fs->version != FS_VERSION) {
fprintf(fo, "Feed stats db '%s' has wrong version - please delete\n",
PatDbExpand(DFeedStatsPat));
fflush(fo);
exit(1);
}
count = st.st_size / sizeof(FeedStats);
bzero(&ts, sizeof(ts));
ts.RecStats.TimeStart = time(NULL);
ts.SentStats.TimeStart = time(NULL);
ts.SpoolStats.TimeStart = time(NULL);
while (--count > 0) {
fs++;
if (fs->hostname[0] == 0)
continue;
if (hostname != NULL && !totalonly &&
strcmp(hostname, fs->hostname) != 0)
continue;
if (fs->RecStats.TimeStart > 0 &&
fs->RecStats.TimeStart < ts.RecStats.TimeStart)
ts.RecStats.TimeStart = fs->RecStats.TimeStart;
ts.RecStats.ConnectCnt += fs->RecStats.ConnectCnt;
for (i = 0; i < STATS_NSLOTS; i++)
ts.RecStats.Stats[i] += fs->RecStats.Stats[i];
ts.RecStats.ReceivedBytes += fs->RecStats.ReceivedBytes;
ts.RecStats.AcceptedBytes += fs->RecStats.AcceptedBytes;
ts.RecStats.RejectedBytes += fs->RecStats.RejectedBytes;
if (fs->SentStats.TimeStart > 0 &&
fs->SentStats.TimeStart < ts.SentStats.TimeStart)
ts.SentStats.TimeStart = fs->SentStats.TimeStart;
ts.SentStats.ConnectCnt += fs->SentStats.ConnectCnt;
ts.SentStats.OfferedCnt += fs->SentStats.OfferedCnt;
ts.SentStats.AcceptedCnt += fs->SentStats.AcceptedCnt;
ts.SentStats.RefusedCnt += fs->SentStats.RefusedCnt;
ts.SentStats.RejectedCnt += fs->SentStats.RejectedCnt;
ts.SentStats.DeferredFailCnt += fs->SentStats.DeferredFailCnt;
ts.SentStats.AcceptedBytes += fs->SentStats.AcceptedBytes;
ts.SentStats.RejectedBytes += fs->SentStats.RejectedBytes;
if (fs->SpoolStats.TimeStart > 0 &&
fs->SpoolStats.TimeStart < ts.SpoolStats.TimeStart)
ts.SpoolStats.TimeStart = fs->SpoolStats.TimeStart;
ts.SpoolStats.ConnectCnt += fs->SpoolStats.ConnectCnt;
for (i = 0; i < STATS_S_NSLOTS; i++)
ts.SpoolStats.Arts[i] += fs->SpoolStats.Arts[i];
ts.SpoolStats.ArtsBytesSent += fs->SpoolStats.ArtsBytesSent;
if (!totalonly) {
switch (stype) {
case FSTATS_IN:
dumpInStats(fo, fs->hostname, fs, raw);
break;
case FSTATS_INDETAIL:
dumpInDetStats(fo, fs->hostname, fs, raw);
break;
case FSTATS_OUT:
dumpOutStats(fo, fs->hostname, fs, raw);
break;
case FSTATS_SPOOL:
dumpSpoolStats(fo, fs->hostname, fs, raw);
break;
case FSTATS_SPOOLDETAIL:
dumpSpoolDetStats(fo, fs->hostname, fs, raw);
break;
}
}
}
xunmap(Stats, st.st_size);
close(FSSFd);
switch (stype) {
case FSTATS_IN:
dumpInStats(fo, "TOTAL", &ts, raw);
break;
case FSTATS_INDETAIL:
dumpInDetStats(fo, "TOTAL", &ts, raw);
break;
case FSTATS_OUT:
dumpOutStats(fo, "TOTAL", &ts, raw);
break;
case FSTATS_SPOOL:
dumpSpoolStats(fo, "TOTAL", &ts, raw);
break;
case FSTATS_SPOOLDETAIL:
dumpSpoolDetStats(fo, "TOTAL", &ts, raw);
break;
}
}
void
dumpInStats(FILE *fo, char *hostname, FeedStats *fs, int raw)
{
if (fs->RecStats.TimeStart == 0)
return;
if (raw)
fprintf(fo, "INFEED %-20s secs=%u con=%u off=%u rec=%u acc=%u ref=%u rej=%u recbytes=%.0f accbytes=%.0f rejbytes=%.0f\n",
hostname,
time(NULL) - fs->RecStats.TimeStart,
fs->RecStats.ConnectCnt,
fs->RecStats.Stats[STATS_OFFERED],
fs->RecStats.Stats[STATS_RECEIVED],
fs->RecStats.Stats[STATS_ACCEPTED],
fs->RecStats.Stats[STATS_REFUSED],
fs->RecStats.Stats[STATS_REJECTED],
fs->RecStats.ReceivedBytes,
fs->RecStats.AcceptedBytes,
fs->RecStats.RejectedBytes
);
else
fprintf(fo, "INFEED %-20s secs=%u con=%u off=%u rec=%u acc=%u ref=%u rej=%u recbytes=%s accbytes=%s rejbytes=%s\n",
hostname,
time(NULL) - fs->RecStats.TimeStart,
fs->RecStats.ConnectCnt,
fs->RecStats.Stats[STATS_OFFERED],
fs->RecStats.Stats[STATS_RECEIVED],
fs->RecStats.Stats[STATS_ACCEPTED],
fs->RecStats.Stats[STATS_REFUSED],
fs->RecStats.Stats[STATS_REJECTED],
ftos(fs->RecStats.ReceivedBytes),
ftos(fs->RecStats.AcceptedBytes),
ftos(fs->RecStats.RejectedBytes)
);
}
void
dumpInDetStats(FILE *fo, char *hostname, FeedStats *fs, int raw)
{
if (fs->RecStats.TimeStart == 0)
return;
if (raw)
fprintf(fo, "INFEEDDETAIL %-20s secs=%u ihave=%d chk=%d takethis=%d rec=%d acc=%d ref=%d precom=%d postcom=%d his=%d badmsgid=%d rej=%d ctl=%d failsafe=%d misshdrs=%d tooold=%d grpfilt=%d intspamfilt=%d extspamfilt=%d incfilter=%d nospool=%d ioerr=%d notinactv=%d pathtab=%d ngtab=%d posdup=%d hdrerr=%d toosmall=%d incompl=%d nul=%d nobytes=%d proto=%d msgidmis=%d err=%d toobig=%d recbytes=%.0f accbytes=%.0f rejbytes=%.0f\n",
hostname,
time(NULL) - fs->RecStats.TimeStart,
fs->RecStats.Stats[STATS_IHAVE],
fs->RecStats.Stats[STATS_CHECK],
fs->RecStats.Stats[STATS_TAKETHIS],
fs->RecStats.Stats[STATS_RECEIVED],
fs->RecStats.Stats[STATS_ACCEPTED],
fs->RecStats.Stats[STATS_REFUSED],
fs->RecStats.Stats[STATS_REF_PRECOMMIT],
fs->RecStats.Stats[STATS_REF_POSTCOMMIT],
fs->RecStats.Stats[STATS_REF_HISTORY],
fs->RecStats.Stats[STATS_REF_BADMSGID],
fs->RecStats.Stats[STATS_REJECTED],
fs->RecStats.Stats[STATS_CONTROL],
fs->RecStats.Stats[STATS_REJ_FAILSAFE],
fs->RecStats.Stats[STATS_REJ_MISSHDRS],
fs->RecStats.Stats[STATS_REJ_TOOOLD],
fs->RecStats.Stats[STATS_REJ_GRPFILTER],
fs->RecStats.Stats[STATS_REJ_INTSPAMFILTER],
fs->RecStats.Stats[STATS_REJ_EXTSPAMFILTER],
fs->RecStats.Stats[STATS_REJ_INCFILTER],
fs->RecStats.Stats[STATS_REJ_NOSPOOL],
fs->RecStats.Stats[STATS_REJ_IOERROR],
fs->RecStats.Stats[STATS_REJ_NOTINACTV],
fs->RecStats.Stats[STATS_REJ_PATHTAB],
fs->RecStats.Stats[STATS_REJ_NGTAB],
fs->RecStats.Stats[STATS_REJ_POSDUP],
fs->RecStats.Stats[STATS_REJ_HDRERROR],
fs->RecStats.Stats[STATS_REJ_TOOSMALL],
fs->RecStats.Stats[STATS_REJ_ARTINCOMPL],
fs->RecStats.Stats[STATS_REJ_ARTNUL],
fs->RecStats.Stats[STATS_REJ_NOBYTES],
fs->RecStats.Stats[STATS_REJ_PROTOERR],
fs->RecStats.Stats[STATS_REJ_MSGIDMIS],
fs->RecStats.Stats[STATS_REJ_ERR],
fs->RecStats.Stats[STATS_REJ_TOOBIG],
fs->RecStats.ReceivedBytes,
fs->RecStats.AcceptedBytes,
fs->RecStats.RejectedBytes
);
else
fprintf(fo, "INFEEDDETAIL %-20s secs=%u ihave=%d chk=%d takethis=%d rec=%d acc=%d ref=%d precom=%d postcom=%d his=%d badmsgid=%d rej=%d ctl=%d failsafe=%d misshdrs=%d tooold=%d grpfilt=%d intspamfilt=%d extspamfilt=%d incfilter=%d nospool=%d ioerr=%d notinactv=%d pathtab=%d ngtab=%d posdup=%d hdrerr=%d toosmall=%d incompl=%d nul=%d nobytes=%d proto=%d msgidmis=%d err=%d toobig=%d recbytes=%s accbytes=%s rejbytes=%s\n",
hostname,
time(NULL) - fs->RecStats.TimeStart,
fs->RecStats.Stats[STATS_IHAVE],
fs->RecStats.Stats[STATS_CHECK],
fs->RecStats.Stats[STATS_TAKETHIS],
fs->RecStats.Stats[STATS_RECEIVED],
fs->RecStats.Stats[STATS_ACCEPTED],
fs->RecStats.Stats[STATS_REFUSED],
fs->RecStats.Stats[STATS_REF_PRECOMMIT],
fs->RecStats.Stats[STATS_REF_POSTCOMMIT],
fs->RecStats.Stats[STATS_REF_HISTORY],
fs->RecStats.Stats[STATS_REF_BADMSGID],
fs->RecStats.Stats[STATS_REJECTED],
fs->RecStats.Stats[STATS_CONTROL],
fs->RecStats.Stats[STATS_REJ_FAILSAFE],
fs->RecStats.Stats[STATS_REJ_MISSHDRS],
fs->RecStats.Stats[STATS_REJ_TOOOLD],
fs->RecStats.Stats[STATS_REJ_GRPFILTER],
fs->RecStats.Stats[STATS_REJ_INTSPAMFILTER],
fs->RecStats.Stats[STATS_REJ_EXTSPAMFILTER],
fs->RecStats.Stats[STATS_REJ_INCFILTER],
fs->RecStats.Stats[STATS_REJ_NOSPOOL],
fs->RecStats.Stats[STATS_REJ_IOERROR],
fs->RecStats.Stats[STATS_REJ_NOTINACTV],
fs->RecStats.Stats[STATS_REJ_PATHTAB],
fs->RecStats.Stats[STATS_REJ_NGTAB],
fs->RecStats.Stats[STATS_REJ_POSDUP],
fs->RecStats.Stats[STATS_REJ_HDRERROR],
fs->RecStats.Stats[STATS_REJ_TOOSMALL],
fs->RecStats.Stats[STATS_REJ_ARTINCOMPL],
fs->RecStats.Stats[STATS_REJ_ARTNUL],
fs->RecStats.Stats[STATS_REJ_NOBYTES],
fs->RecStats.Stats[STATS_REJ_PROTOERR],
fs->RecStats.Stats[STATS_REJ_MSGIDMIS],
fs->RecStats.Stats[STATS_REJ_ERR],
fs->RecStats.Stats[STATS_REJ_TOOBIG],
ftos(fs->RecStats.ReceivedBytes),
ftos(fs->RecStats.AcceptedBytes),
ftos(fs->RecStats.RejectedBytes)
);
}
void
dumpOutStats(FILE *fo, char *hostname, FeedStats *fs, int raw)
{
if (fs->SentStats.TimeStart == 0)
return;
if (raw)
fprintf(fo, "OUTFEED %-20s secs=%u con=%u off=%u acc=%u ref=%u rej=%u deffail=%u accbytes=%.0f rejbytes=%.0f\n",
hostname,
time(NULL) - fs->SentStats.TimeStart,
fs->SentStats.ConnectCnt,
fs->SentStats.OfferedCnt,
fs->SentStats.AcceptedCnt,
fs->SentStats.RefusedCnt,
fs->SentStats.RejectedCnt,
fs->SentStats.DeferredFailCnt,
fs->SentStats.AcceptedBytes,
fs->SentStats.RejectedBytes
);
else
fprintf(fo, "OUTFEED %-20s secs=%u con=%u off=%u acc=%u ref=%u rej=%u deffail=%u accbytes=%s rejbytes=%s\n",
hostname,
time(NULL) - fs->SentStats.TimeStart,
fs->SentStats.ConnectCnt,
fs->SentStats.OfferedCnt,
fs->SentStats.AcceptedCnt,
fs->SentStats.RefusedCnt,
fs->SentStats.RejectedCnt,
fs->SentStats.DeferredFailCnt,
ftos(fs->SentStats.AcceptedBytes),
ftos(fs->SentStats.RejectedBytes)
);
}
void
dumpSpoolStats(FILE *fo, char *hostname, FeedStats *fs, int raw)
{
if (fs->SpoolStats.TimeStart == 0)
return;
if (raw)
fprintf(fo, "SPOOL %-20s secs=%u con=%u stat=%u article=%u head=%u body=%u bytes=%.0f\n",
hostname,
time(NULL) - fs->SpoolStats.TimeStart,
fs->SpoolStats.ConnectCnt,
fs->SpoolStats.Arts[STATS_S_STAT],
fs->SpoolStats.Arts[STATS_S_ARTICLE],
fs->SpoolStats.Arts[STATS_S_HEAD],
fs->SpoolStats.Arts[STATS_S_BODY],
fs->SpoolStats.ArtsBytesSent
);
else
fprintf(fo, "SPOOL %-20s secs=%u con=%u stat=%u article=%u head=%u body=%u bytes=%s\n",
hostname,
time(NULL) - fs->SpoolStats.TimeStart,
fs->SpoolStats.ConnectCnt,
fs->SpoolStats.Arts[STATS_S_STAT],
fs->SpoolStats.Arts[STATS_S_ARTICLE],
fs->SpoolStats.Arts[STATS_S_HEAD],
fs->SpoolStats.Arts[STATS_S_BODY],
ftos(fs->SpoolStats.ArtsBytesSent)
);
}
void
dumpSpoolDetStats(FILE *fo, char *hostname, FeedStats *fs, int raw)
{
if (fs->SpoolStats.TimeStart == 0)
return;
if (raw)
fprintf(fo, "SPOOLDETAIL %-20s secs=%u con=%u stat=%u statmiss=%d statexp=%d staterr=%d article=%u articlemiss=%d articleexp=%d articleerr=%d head=%u headmiss=%d headexp=%d headerr=%d body=%u bodymiss=%d bodyexp=%d bodyerr=%d bytes=%.0f\n",
hostname,
time(NULL) - fs->SpoolStats.TimeStart,
fs->SpoolStats.ConnectCnt,
fs->SpoolStats.Arts[STATS_S_STAT],
fs->SpoolStats.Arts[STATS_S_STATMISS],
fs->SpoolStats.Arts[STATS_S_STATEXP],
fs->SpoolStats.Arts[STATS_S_STATERR],
fs->SpoolStats.Arts[STATS_S_ARTICLE],
fs->SpoolStats.Arts[STATS_S_ARTICLEMISS],
fs->SpoolStats.Arts[STATS_S_ARTICLEEXP],
fs->SpoolStats.Arts[STATS_S_ARTICLEERR],
fs->SpoolStats.Arts[STATS_S_HEAD],
fs->SpoolStats.Arts[STATS_S_HEADMISS],
fs->SpoolStats.Arts[STATS_S_HEADEXP],
fs->SpoolStats.Arts[STATS_S_HEADERR],
fs->SpoolStats.Arts[STATS_S_BODY],
fs->SpoolStats.Arts[STATS_S_BODYMISS],
fs->SpoolStats.Arts[STATS_S_BODYEXP],
fs->SpoolStats.Arts[STATS_S_BODYERR],
fs->SpoolStats.ArtsBytesSent
);
else
fprintf(fo, "SPOOLDETAIL %-20s secs=%u con=%u stat=%u statmiss=%d statexp=%d staterr=%d article=%u articlemiss=%d articleexp=%d articleerr=%d head=%u headmiss=%d headexp=%d headerr=%d body=%u bodymiss=%d bodyexp=%d bodyerr=%d bytes=%s\n",
hostname,
time(NULL) - fs->SpoolStats.TimeStart,
fs->SpoolStats.ConnectCnt,
fs->SpoolStats.Arts[STATS_S_STAT],
fs->SpoolStats.Arts[STATS_S_STATMISS],
fs->SpoolStats.Arts[STATS_S_STATEXP],
fs->SpoolStats.Arts[STATS_S_STATERR],
fs->SpoolStats.Arts[STATS_S_ARTICLE],
fs->SpoolStats.Arts[STATS_S_ARTICLEMISS],
fs->SpoolStats.Arts[STATS_S_ARTICLEEXP],
fs->SpoolStats.Arts[STATS_S_ARTICLEERR],
fs->SpoolStats.Arts[STATS_S_HEAD],
fs->SpoolStats.Arts[STATS_S_HEADMISS],
fs->SpoolStats.Arts[STATS_S_HEADEXP],
fs->SpoolStats.Arts[STATS_S_HEADERR],
fs->SpoolStats.Arts[STATS_S_BODY],
fs->SpoolStats.Arts[STATS_S_BODYMISS],
fs->SpoolStats.Arts[STATS_S_BODYEXP],
fs->SpoolStats.Arts[STATS_S_BODYERR],
ftos(fs->SpoolStats.ArtsBytesSent)
);
}
/*
* FeedStatsSnapShot - create a snapshot of the feedstats file
*/
void
FeedStatsSnapShot(FILE *fo, char *hostname, char *ext)
{
int oldf;
int newf;
char fnameout[PATH_MAX];
char timebuf[64];
FeedStats fs;
int count = 0;
int res = 1;
oldf = open(PatDbExpand(DFeedStatsPat), O_RDONLY);
if (oldf == -1) {
fprintf(fo, "Unable to open feeder stats file: %s (%s)\n",
PatDbExpand(DFeedStatsPat), strerror(errno));
return;
}
if (ext == NULL) {
struct tm *tp;
time_t t = time(NULL);
tp = localtime(&t);
strftime(timebuf, sizeof(timebuf), "%Y%m%d-%H%M%S", tp);
ext = timebuf;
}
snprintf(fnameout, sizeof(fnameout), "%s.%s",
PatDbExpand(DFeedStatsPat), ext);
newf = open(fnameout, O_WRONLY|O_CREAT, 0644);
if (newf == -1) {
fprintf(fo, "Unable to create snapshot feeder stats file: %s (%s)\n",
fnameout, strerror(errno));
return;
}
while (res > 0) {
hflock(oldf, count * sizeof(fs), XLOCK_EX);
res = read(oldf, &fs, sizeof(fs));
if (res == sizeof(fs) &&
(hostname == NULL || strcmp(fs.hostname, hostname) == 0)) {
if (write(newf, &fs, sizeof(fs)) != sizeof(fs)) {
fprintf(fo, "Error writing snapshot feeder stats file (%s)\n",
strerror(errno));
res = 0;
}
}
hflock(oldf, count * sizeof(fs), XLOCK_UN);
if (res == -1)
fprintf(fo, "Error reading feeder stats file (%s)\n",
strerror(errno));
if (res <= 0)
break;
count++;
}
close(oldf);
close(newf);
fprintf(fo, "%d records written to snapshot file %s\n", count, fnameout);
}
syntax highlighted by Code2HTML, v. 0.9.1