/***************************** ** woho's MRTG Logfile cgi ** *****************************/ /* 2007-09-01: v1.3: modified mrtglog-1.2 by Roman Vasiyarov aka Winex, rvasiyarov@gmail.com */ #define VERSION "1.3" #include "./mrtglog.h" #include #include #include #include #include #define DBG_LVL 1 #define MAX_LOG_FILES 64 #define MAX_PATH 256 #define TO_MBYTES(inbytes) ((inbytes)/1048576.0f) int str2time(char *s); int parse_querystring(const char* s); int gen_table_from_log(const char* sFile, int nStart, int nStop); typedef struct { time_t t; float in; float out; } mrtg; // global vars char g_start[32]; char g_stop[32]; char g_logs_tmp[MAX_PATH*MAX_LOG_FILES]; char g_logs[MAX_LOG_FILES][MAX_PATH]; int g_log_num = 0; char* g_log_path = MRTGLOGS_CGI_RELATIVE_PATH; char* g_script_name = NULL; clock_t tm1, tm2; float tmdiff = 0.0f; typedef struct { char* sName; char* sValue; } opt_entry; const opt_entry g_opt_table[] = { {"start", g_start}, {"stop", g_stop}, {"logs", g_logs_tmp} }; const g_opt_table_len = sizeof(g_opt_table) / sizeof(opt_entry); // parses given string and stores values in global vars int parse_querystring(const char* sQueryString) { int n = 0; int k = 0; int i = 0; char* str = NULL; char* s = NULL; char* p = NULL; char* q = NULL; char ch, ch2, ch3, hex[8]; int known = 0; n = strlen(sQueryString); str = (char *)malloc ((n+2) * sizeof(char)); str[n] = '\0'; str[n+1] = '\0'; p = str; for (i = 0; i < n; i++) { ch = sQueryString[i]; if (ch == '+') ch = ' '; else if (ch == '%') { // TODO: 20070906 winex: check here if % sign hasn't successors ch2 = sQueryString[i+1]; ch3 = sQueryString[i+2]; i += 2; snprintf(hex, sizeof(hex), "%c%c", ch2, ch3); ch = strtol (hex, NULL, 16); if ((ch == 10) || (ch == 13)) ch = ' '; } *p++ = ch; } n = p - str; p = str; while ((*p != '\0') && (*p != '=') && (*p != '&')) { s = p; while ((*s != '\0') && (*s != '=') && (*s != '&')) s++; if (*s == '=') { *s++ = '\0'; for (i = 0; i < g_opt_table_len; i++) { known = 0; if (strcmp(g_opt_table[i].sName, p) == 0) { known = 1; g_opt_table[i].sValue; if ((*s == '&') || (*s == '\0')) *(g_opt_table[i].sValue) = '\0'; else { q = s; while ((*q != '&') && (*q != '\0')) q++; // TODO: 20070906 winex: check (q-s) in range of [0,MAX_VALUE_LEN] strncpy(g_opt_table[i].sValue, s, q-s); g_opt_table[i].sValue[q-s] = '\0'; p = q; } break; } } if (!known) printf("Unknown parameter: %s
\n", p); } else p = s; p++; } //#if (DBG_LVL == 1) printf("start: %s
\nstop: %s
\nlogs: %s
\n", g_start, g_stop, g_logs_tmp); fflush(stdout); //#endif free(str); return 0; } /************************************/ int main(int argc, char *argv[]) { mrtg ar[3000]; int i, y, a1, a2, a3, a4 , a5, diff, newmon, oldmon=13, year; char s[128], *str, *ctmp; char *reqmethod = NULL; char *p = NULL; char *q = NULL; char hostname[256]; time_t t1, t2; struct tm *zeit; float IN, OUT, ISUM=0.0f, OSUM=0.0f; FILE *fp; tm1 = clock(); memset(g_start, '\0', sizeof(g_start)); memset(g_stop, '\0', sizeof(g_stop)); memset(g_logs_tmp, 0, sizeof(g_logs_tmp)*sizeof(char)); memset(g_logs, 0, sizeof(g_logs)*sizeof(char)); if (argc >= 4) { // we are called from shell printf(HTMLHEAD); g_log_path = MRTGLOGS_SHELL_PATH; //gethostname(hostname, sizeof(hostname)); strncpy(g_start, argv[1], sizeof(g_start)); strncpy(g_stop, argv[2], sizeof(g_stop)); for (i = 3; i < argc ; i++) { if (i >= MAX_LOG_FILES+3) { printf("warning: Possibly truncated list of files, see MAX_LOG_FILES variable which has value of %d\n", MAX_LOG_FILES); fflush(stdout); break; } strncpy((char*)&g_logs[i-3], argv[i], MAX_PATH); } g_log_num = i-3; #if (DBG_LVL == 1) for (i = 0; i < g_log_num; i++) printf("logs[%d]: %s\n", i, g_logs[i]); #endif } else if ( (reqmethod=(char*)getenv("REQUEST_METHOD")) != NULL ) { // don't print HTML header if we called from php script // in that php script, do // putenv("SCRIPT_NAME=".$_SERVER['SCRIPT_NAME']); // before calling this program if ( (str=getenv("SCRIPT_NAME")) == NULL ) printf(HTMLHEAD); else if (strstr(str, ".php") == NULL) printf(HTMLHEAD); #if (DBG_LVL == 1) printf("SCRIPT_NAME: %s
\n", getenv("SCRIPT_NAME")); #endif fflush(stdout); // we are called from httpd, test by what method if (strcmp(reqmethod, "GET") == 0) { #if (DBG_LVL == 1) printf("REQUEST_METHOD: GET
\n"); fflush(stdout); #endif str = getenv("QUERY_STRING"); if (!str) { printf("error: QUERY_STRING is not set
\n"); fflush(stdout); return -1; } if (parse_querystring(str) != 0) { fflush(stdout); return -1; } } else if (strcmp(reqmethod, "POST") == 0) { #if (DBG_LVL == 1) printf("REQUEST_METHOD: POST
\n"); fflush(stdout); #endif while (fgets(s, sizeof(s)-1, stdin)) { #if (DBG_LVL == 1) printf("line %d: %s
\n", i, s); i++; #endif fflush(stdout); parse_querystring(s); } } else // otherwise method is possibly "HEAD" { printf("error: REQUEST_METHOD: \"%s\" is not supported
\n", reqmethod); fflush(stdout); return -1; } } fflush(stdout); // parse g_logs_tmp into g_logs[], separated by spaces now // if it not empty i = 0; p = g_logs_tmp; if (*p != '\0') { q = g_logs[i]; while (*p != '\0') { if (*p == ' ') { p++; while ((*p != '\0') && (*p == ' ')) p++; if (*p == '\0') break; //*q = '\0'; i++; if (i >= MAX_LOG_FILES) { i--; break; } q = (char*)(g_logs[i]); } *q++ = *p++; } //*q = '\0'; if (p != g_logs_tmp) i++; g_log_num = i; } #if (DBG_LVL == 1) printf("g_log_num: %d
\n", g_log_num); if (g_log_num >= MAX_LOG_FILES) printf("warning: Possibly truncated list of log files, MAX_LOG_FILES: %d
\n", MAX_LOG_FILES); for (i = 0; i < g_log_num; i++) printf("g_logs[%d]: %s
\n", i, g_logs[i]); fflush(stdout); #endif if ((*g_start == '\0') || (*g_stop == '\0') || (g_log_num < 1) || (*g_logs[0] == '\0')) { printf("Usage: mrtglog START_DATE STOP_DATE LOGFILE [LOGFILE ...] #
\n" " ex: mrtglog 2007-08-01 2007-08-31 router0.log router1.log # will count all traffic in August 2007 for specified log files #
\n"); fflush(stdout); return -1; } i = y = IN = OUT = 0; t1 = str2time(g_start); t2 = str2time(g_stop); snprintf(s, sizeof(s), "%s%s", g_log_path, g_logs[0]); fp = fopen(s, "r"); if (!fp) { printf("error: can't open '%s'!
\n", s); return -1; } while (fgets(s, 100, fp)) { if (sscanf(s, "%d %d %d %d %d\n", &a1, &a2, &a3, &a4, &a5) == 5) { ar[y].t = a1; ar[y].in = a2; ar[y].out = a3; y++; } } fclose(fp); // we need to cut '.log' only for title, not changing log string itself strncpy(s, g_logs[0], sizeof(s)); // our cutted string is stored in s str = (char *)strrchr(s, '/'); if (str) *str++; else str = s; if (ctmp = (char *)strstr(str, ".log")) *ctmp = '\0'; printf("\n\nMRTGTotal: Statistics from %s to %s for %s\n" "\n\n\ \n\ \n\ \n\ \n", g_start, g_stop, s, s, g_start, g_stop); // sum data and output as table rows for (i = 0; i < y; i++) // trying to turn upside-down :) //for (i = y-2; i > 0; i--) { if ((t1 <= ar[i].t) && (ar[i].t <= t2)) { zeit = gmtime((const time_t *)&ar[i].t); newmon = zeit->tm_mon; if ((oldmon != 13 && newmon != oldmon) || i+1 == y) { if ((i+1) == y) { diff = ar[i].t - ar[i+1].t; IN = IN + ar[i].in * diff; OUT = OUT + ar[i].out * diff; } if ((IN == 0) && (OUT == 0)) break; ISUM += IN; OSUM += OUT; printf("\n", year+1900, oldmon+1, TO_MBYTES(IN), TO_MBYTES(OUT), TO_MBYTES(IN+OUT)); IN = OUT = 0; } if (i+1 < y) { oldmon = newmon; year = zeit->tm_year; diff = ar[i].t - ar[i+1].t; IN = IN + ar[i].in * diff; OUT = OUT + ar[i].out * diff; } } } /* // what is this??? if (IN != 0 || OUT != 0) { ISUM += IN; OSUM += OUT; printf("\n", year+1900,oldmon+1,TO_MBYTES(IN),TO_MBYTES(OUT),TO_MBYTES(IN+OUT)); } */ // print total sums printf("", TO_MBYTES(ISUM), TO_MBYTES(OSUM), TO_MBYTES(ISUM+OSUM)); // end table printf("

%s

\n\

Statistics from %s to %s

DATEINOUTTOTAL
%04i-%02i%.02f MB%.02f MB%.02f MB
%04i-%02i%.02f MB%.02f MB%.02f MB
TOTAL%.02f MB%.02f MB%.02f MB
\n"); /* printf("\n\ \n\ \n
TOTAL%.02f MB%.02f MB%.02f MB
\n
\n\ from \n\ to \n\ \n\ \n\
\n

%s

\n\ mrtglog %s, copyleft 2000 by http://www.netpark.at
\n\ modified by Roman Vasiyarov aka Winex\n\ \n\n", TO_MBYTES(ISUM), TO_MBYTES(OSUM), TO_MBYTES(ISUM+OSUM), ctmp, g_start, g_stop, g_logs[0], INFOTEXT, VERSION); */ /* // print form printf("\n\ \n
\n
\n\ from \n\ to \n\ \n\ \n\
\n

%s

\n", g_script_name, g_start, g_stop, g_logs[0], INFOTEXT); */ tm2 = clock(); tmdiff = (float)(tm2 - tm1) / CLOCKS_PER_SEC; // print footer printf("generated in %.02fs
\n\ mrtglog %s, copyleft 2000 by http://www.netpark.at
\n\ modified by Roman Vasiyarov aka Winex\n\ \n\n", tmdiff, VERSION); return 0; } /************************************/ // desc: converts ISO date YYYY-MM-DD[_HH[:MM[:SS]]] to int (time_t?) int str2time(char *s) { struct tm tim; int yyyy, mm, dd; if (sscanf(s, "%d-%d-%d", &yyyy, &mm, &dd) != 3) { printf("can't convert '%s' to date
\n", s); return -2; } if (yyyy < 100) yyyy += 2000; tim.tm_sec = tim.tm_min = tim.tm_hour = 0; tim.tm_mday = dd; tim.tm_mon = mm - 1; tim.tm_year = yyyy - 1900; return mktime(&tim); } // and in the end, the love you take, is equal to the love you make. (John Lennon)