/***************************** ** 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 0 #define MAX_LOG_FILES 2 // how we were called, from shell (i.e. standalone) or from httpd (as .cgi) #define IS_STANDALONE (getenv("GATEWAY_INTERFACE") == NULL) #define TO_MBYTES(inbytes) ((inbytes)/1048576.0f) int str2time(char *s); int parse_querystring(const char* s); typedef struct { time_t t; float in; float out; } mrtg; // global vars char* g_start = NULL; char* g_stop = NULL; char* g_logs[MAX_LOG_FILES]; int g_log_num = 0; char* g_log_path = NULL; char* g_script_name = NULL; // parses given string and stores values in global vars int parse_querystring(const char* s) { int n = 0; int i = 0; char* str = NULL; char* p = NULL; char ch, ch2, ch3, hex[8]; n = strlen(s)+1; str = (char *)malloc ((n+1) * sizeof(char)); *str = '\0'; str[n] = '\0'; str[n+1] = '\0'; for (i = 0; i < n; i++) { ch = s[i]; // fflush (stdout); if (s[i] == '+') ch = ' '; if (s[i] == '%') { ch2 = s[i+1]; ch3 = s[i+2]; i += 2; snprintf(hex, sizeof(hex), "%c%c", ch2, ch3); ch = strtol (hex, NULL, 16); if ((ch == 10) || (ch == 13)) ch = ' '; } snprintf(&str[strlen(str)], n-strlen(str), "%c", ch); } while (str) { p = str; //while (*p != '=' && *p != '&') { *p = tolower (*p); p++; } if ((char *)strstr(str, "start") == str) { g_start = p+1; p = (char *) strchr(g_start, '&'); } else if ((char *)strstr(str, "stop") == str) { g_stop = p+1; p = (char *) strchr(g_stop, '&'); } else if ((char *)strstr(str, "logs") == str) { g_logs[0] = p+1; p = (char *) strchr(g_logs[0], '&'); str = g_logs[0]; while ((str = strchr(str, ' ')) != NULL) { *str = '\0'; g_logs[g_log_num++] = str+1; } } else { printf("Parameter '%s' is wrong
\n", str); return -1; } if (p) { str = p+1; *p = '\0'; } else str = NULL; } 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 hostname[256]; time_t t1, t2; struct tm *zeit; float IN, OUT, ISUM=0.0f, OSUM=0.0f; FILE *fp; memset(g_logs, 0, sizeof(g_logs)*sizeof(char*)); printf(HTMLHEAD); // if we were called as cli, then action in the form below must be the same as we were called // set path to mrtg logs accordingly // ^^^ BLAH-BLAH-BLAH... if (IS_STANDALONE) { printf("WE ARE STANDALONE! :)\n"); g_log_path = MRTGLOGS_SHELL_PATH; g_script_name = argv[0]; gethostname(hostname, sizeof(hostname)); } else { printf("WE ARE HTTPD-called! :)\n"); g_log_path = MRTGLOGS_CGI_RELATIVE_PATH; strncpy(hostname, getenv("SERVER_NAME"), sizeof(hostname)); if ( (g_script_name=getenv("SCRIPT_NAME")) == NULL ) { g_script_name = getenv("REQUEST_URI"); if ( (str=strchr(g_script_name, '?')) != NULL ) *str = '\0'; } } if (argc >= 4) { // we are called from shell g_script_name = argv[0]; g_start = argv[1]; g_stop = argv[2]; 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; } g_logs[i-3] = argv[i]; } 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_FILENAME: %s
\n", getenv("SCRIPT_FILENAME")); printf("SCRIPT_NAME: %s
\n", getenv("SCRIPT_NAME")); printf("PATH_INFO: %s
\n", getenv("PATH_INFO")); printf("TERM: %s
\n", getenv("TERM")); printf("PATH_TRANSLATED: %s
\n", getenv("PATH_TRANSLATED")); //#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"); #endif str = getenv("QUERY_STRING"); if (!str) { printf("error: QUERY_STRING is not set
\n"); fflush(stdout); return -1; } if (parse_querystring(str) != 0) return -1; } else if (strcmp(reqmethod, "POST") == 0) { #if (DBG_LVL == 1) printf("REQUEST_METHOD: \"POST\"
\n"); #endif while (fgets(s, sizeof(s)-1, stdin)) { #if (DBG_LVL == 1) printf("line %d: %s\n", i, s); i++; #endif parse_querystring(s); } } else // otherwise method is possibly "HEAD" { printf("error: REQUEST_METHOD: \"%s\" is not supported
\n", reqmethod); fflush(stdout); return -1; } } if (!g_start || !g_stop || (g_log_num < 1) || (g_logs[0] == NULL)) { 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"); 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\n%s - Statistics from %s to %s for %s\n" "\n\n\ \n\ \n\ \n\ \n", hostname, 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); // print footer printf("mrtglog %s, copyleft 2000 by http://www.netpark.at
\n\ modified by Roman Vasiyarov aka Winex\n\ \n\n", 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)