/***************************************************************************** * * $Id$ * Purpose ...............: Keep track of server status * ***************************************************************************** * Copyright (C) 1997-2007 * * Michiel Broek FIDO: 2:280/2802 * Beekmansbos 10 * 1971 BV IJmuiden * the Netherlands * * This file is part of MBSE BBS. * * This BBS is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * MB BBS is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MB BBS; see the file COPYING. If not, write to the Free * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *****************************************************************************/ #include "../config.h" #include "../lib/mbselib.h" #include "taskstat.h" #include "callstat.h" #include "outstat.h" #include "taskibc.h" #include "taskutil.h" /* * Semafores */ int s_scanout = FALSE; int s_mailout = FALSE; int s_mailin = FALSE; int s_reqindex = FALSE; int s_index = FALSE; int s_msglink = FALSE; int s_newnews = FALSE; int s_bbsopen = FALSE; int s_do_inet = FALSE; int tosswait = TOSSWAIT_TIME; extern int UPSalarm; extern int UPSdown; extern int ptimer; extern int rescan; extern struct taskrec TCFG; extern int internet; extern int ZMH; typedef struct { int tot_clt; /* Total client connects */ int peak_clt; /* Peak simultaneous tot_cltes */ int s_error; /* Syntax errors from clients */ int c_error; /* Comms errors from clients */ } cl_stat; typedef struct { int start; /* Start date/time */ int laststart; /* Last start date/time */ int daily; /* Last daily update */ int startups; /* Total starts */ int clients; /* Connected clients */ cl_stat total; /* Total statistics */ cl_stat today; /* Todays statistics */ unsigned open : 1; /* Is BBS open */ unsigned int sequence; /* Sequencer counter */ unsigned int mkbrcvd; /* MIB mailer Kbytes received */ unsigned int mkbsent; /* MIB mailer Kbytes sent */ unsigned int msessin; /* MIB mailer inbound sessions */ unsigned int msessout; /* MIB mailer outbound sessions */ unsigned int msesssecure; /* MIB mailer secure sessions */ unsigned int msessunsec; /* MIB mailer unsecure sessions */ unsigned int msessbad; /* MIB mailer bad sessions */ unsigned int mftsc; /* MIB mailer FTSC sessions */ unsigned int myoohoo; /* MIB mailer YooHoo sessions */ unsigned int memsi; /* MIB mailer EMSI sessions */ unsigned int mbinkp; /* MIB mailer Binkp sessions */ unsigned int mfreqs; /* MIB mailer file requests */ unsigned int tmsgsin; /* MIB tosser messages in */ unsigned int tmsgsout; /* MIB tosser messages out */ unsigned int tmsgsbad; /* MIB tosser messages bad */ unsigned int tmsgsdupe; /* MIB tosser messages dupe */ unsigned int tnetin; /* MIB tosser netmail in */ unsigned int tnetout; /* MIB tosser netmail out */ unsigned int tnetbad; /* MIB tosser netmail bad */ unsigned int temailin; /* MIB tosser email in */ unsigned int temailout; /* MIB tosser email out */ unsigned int temailbad; /* MIB tosser email bad */ unsigned int techoin; /* MIB tosser echomail in */ unsigned int techoout; /* MIB tosser echomail out */ unsigned int techobad; /* MIB tosser echomail bad */ unsigned int techodupe; /* MIB tosser echomail dupe */ unsigned int tnewsin; /* MIB tosser news in */ unsigned int tnewsout; /* MIB tosser news out */ unsigned int tnewsbad; /* MIB tosser news bad */ unsigned int tnewsdupe; /* MIB tosser news dupe */ unsigned int tfilesin; /* MIB tosser files in */ unsigned int tfilesout; /* MIB tosser files out */ unsigned int tfilesbad; /* MIB tosser bad files */ unsigned int tfilesdupe; /* MIB tosser dupe files */ unsigned int tfilesmagic; /* MIB tosser files magics */ unsigned int tfileshatched; /* MIB tosser files hatched */ } status_r; static char stat_fn[PATH_MAX]; /* Statusfile name */ static status_r status; /* Status data */ extern double Load; /* System Load */ extern int Processing; /* Is system running */ /************************************************************************ * * Initialize the statusfile, create it if necesary. */ void status_init() { size_t cnt; int stat_fd; snprintf(stat_fn, PATH_MAX, "%s/var/status.mbsed", getenv("MBSE_ROOT")); /* * First check if this is the very first time we start the show. * If so, we generate an empty status file with only the start * date in it. */ memset((char *)&status, 0, sizeof(status_r)); stat_fd = open(stat_fn, O_RDWR); if (stat_fd == -1) { status.start = (int)time(NULL); status.daily = (int)time(NULL); status.sequence = (unsigned int)time(NULL); stat_fd = open(stat_fn, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); cnt = write(stat_fd, &status, sizeof(status_r)); Syslog('+', "New statusfile created"); lseek(stat_fd, 0, SEEK_SET); } cnt = read(stat_fd, &status, sizeof(status_r)); if ((cnt != sizeof(status_r)) && (cnt < 50)) { printf("Error reading status file\n"); exit(MBERR_INIT_ERROR); } status.startups++; status.laststart = (int)time(NULL); status.clients = 1; /* We are a client ourself */ s_bbsopen = status.open; lseek(stat_fd, 0, SEEK_SET); cnt = write(stat_fd, &status, sizeof(status_r)); if (cnt != sizeof(status_r)) { Syslog('?', "$Error rewrite status file\n"); exit(MBERR_INIT_ERROR); } close(stat_fd); } /* * Writeback the updated status record. */ void status_write(void); void status_write(void) { int d, stat_fd, yday; struct tm ttm; time_t temp; temp = time(NULL); localtime_r(&temp, &ttm); yday = ttm.tm_yday; temp = (time_t)status.daily; localtime_r(&temp, &ttm); /* * If we passed to the next day, zero the today counters */ if (yday != ttm.tm_yday) { Syslog('+', "Last days statistics:"); Syslog('+', "Total clients : %lu", status.today.tot_clt); Syslog('+', "Peak clients : %lu", status.today.peak_clt); Syslog('+', "Syntax errors : %lu", status.today.s_error); Syslog('+', "Comms errors : %lu", status.today.c_error); memset((char *)&status.today, 0, sizeof(cl_stat)); status.daily = time(NULL); Syslog('+', "Zeroed todays status counters"); } if ((stat_fd = open(stat_fn, O_RDWR)) == -1) { Syslog('?', "$Error open statusfile %s", stat_fn); return; } if ((d = lseek(stat_fd, 0, SEEK_SET)) != 0) { Syslog('?', "$Error seeking in statusfile"); return; } d = write(stat_fd, &status, sizeof(status_r)); if (d != sizeof(status_r)) Syslog('?', "$Error writing statusfile, only %d bytes", d); /* * CLose the statusfile */ if (close(stat_fd) != 0) Syslog('?', "$Error closing statusfile"); } /************************************************************************* * * Various actions on the statusfile. */ /* * Check for Zone Mail Hour, return TRUE if it is. */ int get_zmh() { struct tm l_date; char sstime[6]; time_t Now; Now = time(NULL); gmtime_r(&Now, &l_date); snprintf(sstime, 6, "%02d:%02d", l_date.tm_hour, l_date.tm_min); if ((strncmp(sstime, TCFG.zmh_start, 5) >= 0) && (strncmp(sstime, TCFG.zmh_end, 5) < 0)) { if (!ZMH) { CreateSema((char *)"zmh"); Syslog('!', "Start of Zone Mail Hour"); ZMH = TRUE; } } else { if (ZMH) { RemoveSema((char *)"zmh"); Syslog('!', "End of Zone Mail Hour"); ZMH = FALSE; } } return ZMH; } void stat_inc_clients() { status.clients++; status.total.tot_clt++; status.today.tot_clt++; if (status.clients >= status.total.peak_clt) status.total.peak_clt = status.clients; if (status.clients >= status.today.peak_clt) status.today.peak_clt = status.clients; status_write(); } void stat_dec_clients() { status.clients--; status_write(); } void stat_set_open(int op) { if (op) { if (!s_bbsopen) { Syslog('!', "The bbs is open"); sem_set((char *)"scanout", TRUE); } } else { if (s_bbsopen) { Syslog('!', "The bbs is closed"); } } s_bbsopen = status.open = op; status_write(); } void stat_inc_serr() { status.total.s_error++; status.today.s_error++; status_write(); } void stat_inc_cerr() { status.total.c_error++; status.today.c_error++; status_write(); } void stat_status_r(char *buf) { int i, srvcnt = 0, chncnt = 0, usrcnt = 0; for (i = 0; i < MAXIBC_SRV; i++) if (strlen(srv_list[i].server)) srvcnt++; for (i = 0; i < MAXIBC_CHN; i++) if (strlen(chn_list[i].server)) chncnt++; for (i = 0; i < MAXIBC_USR; i++) if (strlen(usr_list[i].server)) usrcnt++; snprintf(buf, SS_BUFSIZE, "100:23,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%2.2f,%u,%d,%d,%d;", status.start, status.laststart, status.daily, status.startups, status.clients, status.total.tot_clt, status.total.peak_clt, status.total.s_error, status.total.c_error, status.today.tot_clt, status.today.peak_clt, status.today.s_error, status.today.c_error, status.open, get_zmh(), internet, s_do_inet, Processing, Load, status.sequence, srvcnt, chncnt, usrcnt); return; } /* * Return open status: * 0 = open. * 1 = closed. * 2 = Zone Mail Hour. */ int stat_bbs_stat() { if (!status.open) return 1; if (get_zmh()) return 2; return 0; } /* * Get next sequence number */ void getseq_r(char *buf) { status.sequence++; status_write(); snprintf(buf, 80, "100:1,%u;", status.sequence); return; } unsigned int gettoken(void) { status.sequence++; status_write(); return status.sequence; } int sem_set(char *sem, int value) { if (!strcmp(sem, "scanout")) { s_scanout = value; if (value) rescan = TRUE; } else if (!strcmp(sem, "mailout")) { s_mailout = value; } else if (!strcmp(sem, "mailin")) { s_mailin = value; if (value) tosswait = TOSSWAIT_TIME; } else if (!strcmp(sem, "mbindex")) { s_index = value; } else if (!strcmp(sem, "newnews")) { s_newnews = value; } else if (!strcmp(sem, "msglink")) { s_msglink = value; } else if (!strcmp(sem, "reqindex")) { s_reqindex = value; } else if (!strcmp(sem, "do_inet")) { s_do_inet = value; } else { return FALSE; } ptimer = PAUSETIME; return TRUE; } void sem_status_r(char *data, char *buf) { char *cnt, *sem; int value; snprintf(buf, 40, "200:1,16;"); cnt = strtok(data, ","); sem = strtok(NULL, ";"); if (!strcmp(sem, "scanout")) { value = s_scanout; } else if (!strcmp(sem, "mailout")) { value = s_mailout; } else if (!strcmp(sem, "mailin")) { value = s_mailin; } else if (!strcmp(sem, "mbindex")) { value = s_index; } else if (!strcmp(sem, "newnews")) { value = s_newnews; } else if (!strcmp(sem, "msglink")) { value = s_msglink; } else if (!strcmp(sem, "reqindex")) { value = s_reqindex; } else if (!strcmp(sem, "upsalarm")) { value = UPSalarm; } else if (!strcmp(sem, "upsdown")) { value = UPSdown; } else if (!strcmp(sem, "do_inet")) { value = s_do_inet; } else { Syslog('s', "sem_status(%s) buf=%s", sem, buf); return; } snprintf(buf, 40, "100:1,%s;", value ? "1":"0"); return; } void sem_create_r(char *data, char *buf) { char *sem; strtok(data, ","); sem = xstrcpy(strtok(NULL, ";")); if (sem_set(sem, TRUE)) snprintf(buf, 40, "100:0;"); else snprintf(buf, 40, "200:1,16;"); free(sem); return; } void sem_remove_r(char *data, char *buf) { char *sem; strtok(data, ","); sem = xstrcpy(strtok(NULL, ";")); if (sem_set(sem, FALSE)) snprintf(buf, 40, "100:0;"); else snprintf(buf, 40, "200:1,16;"); free(sem); return; } void mib_set_mailer(char *data) { unsigned int kbrcvd, kbsent, direction, state, type, freqs; Syslog('m', "MIB set mailer %s", data); strtok(data, ","); kbrcvd = atoi(strtok(NULL, ",")); kbsent = atoi(strtok(NULL, ",")); direction = atoi(strtok(NULL, ",")); state = atoi(strtok(NULL, ",")); type = atoi(strtok(NULL, ",")); freqs = atoi(strtok(NULL, ";")); status.mkbrcvd += kbrcvd; status.mkbsent += kbsent; if (direction) status.msessout++; else status.msessin++; switch (state) { case 0: status.msesssecure++; break; case 1: status.msessunsec++; break; case 2: status.msessbad++; break; } switch (type) { case 1: status.mftsc++; break; case 2: status.myoohoo++; break; case 3: status.memsi++; break; case 4: status.mbinkp++; break; } status.mfreqs += freqs; Syslog('m', "MIB mailer: rcvd=%d sent=%d in=%d out=%d sec=%d unsec=%d bad=%d ftsc=%d yoohoo=%d emsi=%d binkp=%d freq=%d", status.mkbrcvd, status.mkbsent, status.msessin, status.msessout, status.msesssecure, status.msessunsec, status.msessbad, status.mftsc, status.myoohoo, status.memsi, status.mbinkp, status.mfreqs); status_write(); } void mib_set_netmail(char *data) { unsigned int in, out, bad; Syslog('m', "MIB set netmail %s", data); strtok(data, ","); in = atoi(strtok(NULL, ",")); out = atoi(strtok(NULL, ",")); bad = atoi(strtok(NULL, ";")); status.tmsgsin += in; status.tnetin += in; status.tmsgsout += out; status.tnetout += out; status.tmsgsbad += bad; status.tnetbad += bad; Syslog('m', "MIB netmail: in=%d out=%d bad=%d in=%d out=%d bad=%d", status.tmsgsin, status.tmsgsout, status.tmsgsbad, status.tnetin, status.tnetout, status.tnetbad); status_write(); } void mib_set_email(char *data) { unsigned int in, out, bad; Syslog('m', "MIB set email %s", data); strtok(data, ","); in = atoi(strtok(NULL, ",")); out = atoi(strtok(NULL, ",")); bad = atoi(strtok(NULL, ";")); status.tmsgsin += in; status.temailin += in; status.tmsgsout += out; status.temailout += out; status.tmsgsbad += bad; status.temailbad += bad; Syslog('m', "MIB netmail: in=%d out=%d bad=%d in=%d out=%d bad=%d", status.tmsgsin, status.tmsgsout, status.tmsgsbad, status.temailin, status.temailout, status.temailbad); status_write(); } void mib_set_news(char *data) { unsigned int in, out, bad, dupe; Syslog('m', "MIB set news %s", data); strtok(data, ","); in = atoi(strtok(NULL, ",")); out = atoi(strtok(NULL, ",")); bad = atoi(strtok(NULL, ",")); dupe = atoi(strtok(NULL, ";")); status.tmsgsin += in; status.tnewsin += in; status.tmsgsout += out; status.tnewsout += out; status.tmsgsbad += bad; status.tnewsbad += bad; status.tmsgsdupe += dupe; status.tnewsdupe += dupe; Syslog('m', "MIB news: in=%d out=%d bad=%d dupe=%d in=%d out=%d bad=%d dupe=%d", status.tmsgsin, status.tmsgsout, status.tmsgsbad, status.tmsgsdupe, status.tnewsin, status.tnewsout, status.tnewsbad, status.tnewsdupe); status_write(); } void mib_set_echo(char *data) { unsigned int in, out, bad, dupe; Syslog('m', "MIB set echo %s", data); strtok(data, ","); in = atoi(strtok(NULL, ",")); out = atoi(strtok(NULL, ",")); bad = atoi(strtok(NULL, ",")); dupe = atoi(strtok(NULL, ";")); status.tmsgsin += in; status.techoin += in; status.tmsgsout += out; status.techoout += out; status.tmsgsbad += bad; status.techobad += bad; status.tmsgsdupe += dupe; status.techodupe += dupe; Syslog('m', "MIB echo: in=%d out=%d bad=%d dupe=%d in=%d out=%d bad=%d dupe=%d", status.tmsgsin, status.tmsgsout, status.tmsgsbad, status.tmsgsdupe, status.techoin, status.techoout, status.techobad, status.techodupe); status_write(); } void mib_set_files(char *data) { unsigned int in, out, bad, dupe, magics, hatched; Syslog('m', "MIB set files %s", data); strtok(data, ","); in = atoi(strtok(NULL, ",")); out = atoi(strtok(NULL, ",")); bad = atoi(strtok(NULL, ",")); dupe = atoi(strtok(NULL, ",")); magics = atoi(strtok(NULL, ",")); hatched = atoi(strtok(NULL, ";")); status.tfilesin += in; status.tfilesout += out; status.tfilesbad += bad; status.tfilesdupe += dupe; status.tfilesmagic += magics; status.tfileshatched += hatched; Syslog('m', "MIB files: in=%d out=%d bad=%d dupe=%d magic=%d hatch=%d", status.tfilesin, status.tfilesout, status.tfilesbad, status.tfilesdupe, status.tfilesmagic, status.tfileshatched); status_write(); }