/* * 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); }