"Fossies" - the Fresh Open Source Software Archive

Member "srg-1.3.6/src/main.cc" (5 Aug 2009, 31720 Bytes) of package /linux/privat/old/srg-1.3.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2     SRG - Squid Report Generator
    3     Copyright 2005 University of Waikato
    4 
    5     This file is part of SRG.
    6 
    7     SRG is free software; you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation; either version 2 of the License, or
   10     (at your option) any later version.
   11 
   12     SRG is distributed in the hope that it will be useful,
   13     but WITHOUT ANY WARRANTY; without even the implied warranty of
   14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15     GNU General Public License for more details.
   16 
   17     You should have received a copy of the GNU General Public License
   18     along with SRG; if not, write to the Free Software
   19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   20 
   21 */
   22 
   23 #include "srg.h"
   24 #include "Report.h"
   25 #include "UserReport.h"
   26 #include "prototypes.h"
   27 #include <dirent.h>
   28 #include <regex.h>
   29     
   30 /* Local Prototype */
   31 UserReport* findUser(char * user);
   32 
   33 /* Program Information */
   34 char *progname;
   35 config_info srg;
   36 
   37 /* Constant Strings */
   38 char *GROUPBY_NAMES[4] = {"Not Grouped", "User", "IP Address", "Subnet"};
   39 char *FILTERBY_NAMES[4] = {"Not Filtered", "User", "IP Address", "Subnet"};
   40 char *month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", 
   41             "Sep", "Oct", "Nov", "Dec"};
   42 
   43 /* Global Data Structures */
   44 list<UserReport*> groups;
   45 UserReport* stats;
   46 Resolver *dnscache;
   47 
   48 /* Version information 
   49  *
   50  * Major.Minor.Revision
   51  *
   52  * Even minor versions are "stable" releases
   53  * Odd minor versions are "development" releases
   54  * 
   55  * Version should be set in configure.ac
   56  *
   57  */
   58 char *cvsid = "$Id: main.cc 244 2008-01-19 21:09:55Z matt $";
   59 char *version = PACKAGE_VERSION;
   60 
   61 /* Get this show on the road */
   62 int main(int argc, char **argv) {
   63 
   64     progname = strrchr(argv[0], '/');
   65     if (progname == NULL)
   66         progname = argv[0];
   67     else
   68         progname++;
   69             
   70     /* Configure srg */
   71     do_configuration(argc, argv);
   72     
   73     /* Check output environment */
   74     check_environment();
   75         
   76     /* Create a new DNS resolving library */
   77     dnscache = new Resolver(false);
   78         
   79     /* Initialise ip2user mappings */
   80     init_ip2user();
   81 
   82     /* Initialise destination site filtering */
   83     init_sitefilter();
   84 
   85     if (srg.verbose) {
   86         fprintf(stderr, "Configuration Completed.\n");
   87         fprintf(stderr, "Beginning Analysation...\n");
   88     }
   89 
   90     /* If we are not grouping then just create a default group */
   91     if (srg.groupBy == BY_NONE) {
   92         stats = new UserReport("All");
   93         stats->singleUserMode = true;
   94     }
   95 
   96     /* Process the logfile(s) */
   97     process_logs();
   98         
   99     if (srg.verbose)
  100         fprintf(stderr, "Beginning Report Generation...\n");
  101     
  102     /* Create the datename for the report */
  103     char *datename = generate_datename(srg.startTime, srg.endTime);
  104         
  105     /* Create the base directory for the report */
  106     char *basename = NULL;
  107     asprintf(&basename, "%s/%s", srg.outputDir, datename);
  108     if (mkdir(basename, 0755) == -1 && errno != EEXIST) {
  109         fprintf(stderr, "Error (%s) creating directory: %s\n",
  110                 strerror(errno), basename);
  111         exit(1);
  112     }
  113 
  114     /* Call the actual reports to output themselves */
  115     if (srg.groupBy > 0)
  116         generate_reports(datename);
  117     else
  118         stats->generate_report(datename);
  119     free(datename);
  120     free(basename);
  121                 
  122     /* Delete old reports */
  123     if (srg.maxreportage > 0)
  124         cull_oldreports(srg.maxreportage);
  125 
  126     /* Make index for all dates */
  127     make_date_index();
  128     
  129     if (srg.verbose)
  130         fprintf(stderr, "Report Generation Completed.\n");
  131     
  132     /* Must be grouped for email report */
  133     assert(srg.groupBy>=0 && srg.groupBy<=BY_MAX);
  134     if (srg.emailreport && srg.groupBy>0) {
  135             generate_email_report();
  136     }
  137     
  138     /* Get rid of our dns cache */
  139     delete dnscache;
  140     /* Get rid of our groups */
  141     list<UserReport*>::const_iterator iter;
  142     for (iter=groups.begin(); iter != groups.end(); iter++) {
  143         delete (*iter);
  144     }
  145     if (srg.groupBy == BY_NONE)
  146         delete stats;
  147 
  148     return 0;
  149 
  150 }
  151 
  152 void generate_email_report(void)
  153 {
  154 
  155     char *start = strdup(ctime(&srg.startTime));
  156     char *sp = strchr(start, '\n');
  157     *sp = '\0';
  158     char *end = strdup(ctime(&srg.endTime));
  159     char *ep = strchr(end, '\n');
  160     *ep = '\0';
  161 
  162     groups.sort(LessByBytesMissed<UserReport>());
  163     list<UserReport*>::const_iterator iter;
  164     unsigned long long ttraffic=0;
  165     unsigned long long ftraffic=0;
  166     int ngroups=0;
  167     char *t1=NULL, *t2=NULL;
  168 
  169     /* Get the total traffic from all groups */ 
  170     for (iter=groups.begin(); iter != groups.end(); iter++) {
  171         summary_info sitestats = (*iter)->getStats();
  172         if (srg.hideDeniedOnly > 0 && sitestats.deniedHits 
  173                 == sitestats.connects) {
  174             // Nothing
  175         } else {
  176             ttraffic += sitestats.bytesTransferred;
  177             ftraffic += sitestats.bytesMissed;
  178             ngroups++;
  179         }       
  180     }
  181     fprintf(stdout, "SRG - Squid Traffic Report\n\n");
  182     fprintf(stdout, "%-20s%s\n", "Period Start:", start);
  183     fprintf(stdout, "%-20s%s\n", "Period End:", end);    
  184     fprintf(stdout, "%-20s%-15s\n", "Grouped By:", GROUPBY_NAMES[srg.groupBy]);
  185     fprintf(stdout, "%-20s%-15i\n", "No Groups:", ngroups);
  186 
  187     assert(srg.filter.by>=BY_NONE && srg.filter.by<=BY_MAX);
  188     if (srg.filter.by) {
  189         fprintf(stdout, "%-20s%-15s\n", "Filtered By:", 
  190                 FILTERBY_NAMES[srg.filter.by]);
  191         if (srg.filter.by == BY_USER) {
  192             fprintf(stdout, "%-20s%-15s\n", "Filter Criteria:", 
  193                     srg.filter.user);
  194         } else if (srg.filter.by == BY_IP) {
  195             fprintf(stdout, "%-20s%-15s\n", "Filter Criteria:",
  196                     inet_ntoa(srg.filter.address));
  197         } else if (srg.filter.by == BY_SUBNET) {
  198             fprintf(stdout, "%-20s%s/", "Filter Criteria:",
  199                     inet_ntoa(srg.filter.network));
  200             fprintf(stdout, "%s\n", inet_ntoa(srg.filter.netmask));
  201         }
  202     }
  203 
  204     fprintf(stdout, "\n%-47sTraffic Used\n", "");
  205     fprintf(stdout, "%-35s%15s  %15s\n\n", "Group Name", "External (kB)", 
  206             "Total (kB)");
  207     
  208     /* Now write out the actual groups */
  209     for (iter=groups.begin(); iter != groups.end(); iter++) {
  210         summary_info sitestats = (*iter)->getStats();
  211         if (srg.hideDeniedOnly > 0 && sitestats.deniedHits 
  212                 == sitestats.connects) {
  213             // Nothing
  214         } else {
  215             t1 = FormatOutput(sitestats.bytesMissed/1024);
  216             t2 = FormatOutput(sitestats.bytesTransferred/1024);
  217             fprintf(stdout, "%-35s%15s  %15s\n",
  218                     (*iter)->getName(), t1, t2);
  219             free(t1);
  220             free(t2);
  221         }
  222     }
  223 
  224     t1 = FormatOutput(ftraffic/1024);
  225     t2 = FormatOutput(ttraffic/1024);
  226     fprintf(stdout, "\n%-35s%15s  %15s\n", "Total Traffic",t1,t2);
  227     free(t1);
  228     free(t2);
  229 
  230     fprintf(stdout, "\nReport generated by SRG %s\n", version);
  231 
  232     free(start);
  233     free(end);
  234     sp=NULL;
  235     ep=NULL;
  236 
  237 }
  238 
  239 void process_logs(void)
  240 {
  241 
  242     char *next = NULL;
  243     char *work = NULL;
  244     char *orig = NULL;
  245     int linesP = 0;
  246     
  247     /* Allocate space for working string and copy log filename(s) into it */
  248     orig = (char *)malloc(strlen(srg.accessLog)+1);
  249     work = orig;
  250     if (work == NULL) {
  251         fprintf(stderr, "ERROR: Out of Memory in process_logs!\n");
  252         exit(1);
  253     }
  254     sprintf(&work[0], "%s", srg.accessLog);
  255     
  256     /* Extract all the filenames and process one at a time */
  257     while ((next = break_string(work, ' ')) != NULL) {
  258         linesP += process_log(work);
  259         work = next;
  260     }
  261     linesP += process_log(work);
  262 
  263     if (srg.verbose) {
  264         fprintf(stderr, "Finished analysing logfiles\n");
  265     }
  266     
  267     /* exit if no lines were processed */
  268     if (linesP == 0) {
  269         fprintf(stderr, "No logfile lines found to process!\n");
  270         exit(1);
  271     }
  272 
  273     /* Ensure start & end times are set */
  274     if (srg.startTime == (time_t)-1)
  275         srg.startTime = srg.minTime;
  276     if (srg.endTime == (time_t)-1)
  277         srg.endTime = srg.maxTime;
  278     assert(srg.startTime > 0);
  279     assert(srg.endTime > 0);
  280     assert(srg.endTime >= srg.startTime);
  281 
  282     if (srg.verbose) {
  283         fprintf(stderr, "Analysed Time Range: %d -> %d\n", srg.startTime,
  284                 srg.endTime);
  285     }
  286     
  287     /* Free allocated memory */
  288     free(orig);
  289     
  290 }
  291 
  292 int process_log(const char *filename)
  293 {
  294     
  295     Line *iLine = NULL;
  296     int linesT=0;
  297     int linesP=0;
  298     log_line line;
  299     line.request = new url_request;
  300     char *a = NULL;
  301     time_t start = (time_t)-1;
  302     time_t end = (time_t)-1;
  303     
  304     if (srg.verbose) {
  305         fprintf(stderr, "Analysing logfile: %s\n", filename);
  306     }
  307     
  308     /* Open the file */
  309     iLine = new Line(filename);
  310     if (iLine->getError()) {
  311         fprintf(stderr,"ERROR: Can not open '%s': %s\n", filename,
  312                 strerror(iLine->getError()));
  313         exit(1);
  314     }
  315 
  316     /* Loop through the lines and process them */
  317     while(iLine->getError()==0 && !iLine->eof()) {
  318         a = iLine->getline();
  319 
  320         if (parse_line(a, &line)) {
  321 
  322             /* Keep track of first / last request time */
  323             if (start==-1 || line.timestamp<start)
  324                 start = line.timestamp;
  325             if (end==-1 || line.timestamp>end)
  326                 end = line.timestamp;
  327             
  328             linesP += process_line(&line);
  329 
  330             /* Free Memory */
  331             freeURL(line.request);
  332             free(line.resultCode);
  333             free(line.requestMethod);
  334             free(line.user);
  335             free(line.hierarchyData);
  336             free(line.contentType);
  337         }
  338 
  339         linesT++;
  340         free(a);
  341     }
  342     delete line.request;
  343     delete iLine;
  344 
  345     /* Generate statistics regarding the file */
  346     if (srg.verbose) {
  347         fprintf(stderr, "%s: %d/%d lines analysed\n", filename, linesP, 
  348                 linesT);
  349         fprintf(stderr, "%s: time: %d -> %d\n", filename, start, end);
  350     }
  351     
  352     /* Only proceed if lines were processed! */
  353     if (linesP==0)
  354         return 0;
  355     
  356     /* Sanity */
  357     assert(start>0);
  358     assert(end>0);
  359     assert(end >= start);
  360     
  361     /* Update global variables */
  362     if (srg.minTime == -1 || start < srg.minTime)
  363         srg.minTime = start;
  364     if (srg.maxTime == -1 || end > srg.maxTime)
  365         srg.maxTime = end;
  366     
  367     return linesP;
  368     
  369 }
  370 
  371 int parse_line(char * line, log_line *lineOut)
  372 {
  373 
  374     char * parts[10];
  375     unsigned int pos=0;
  376     unsigned int i=0;
  377     char *lineIn = strdup(line);
  378     char *start = lineIn;
  379     static int longlineMsg = 0;
  380         
  381     while (lineIn[i] != '\0') {
  382         if (lineIn[i]!=' ') {
  383             i++;
  384             continue;
  385         }
  386         lineIn[i]='\0';
  387         parts[pos] = start;
  388         if (pos==0) {
  389             int timestamp = atoi(parts[pos]);
  390             /* Check if we are filtering by time */
  391             if (srg.startTime > 0 && srg.endTime > 0) {
  392                 /* Check if this line is required */
  393                 if (timestamp < srg.startTime || timestamp > srg.endTime) {
  394                     /* Don't process */
  395                     goto errexit;
  396                 }
  397             }
  398         }
  399         pos++;
  400         /* Eat Whitespace */
  401         i++;
  402         while (lineIn[i] == ' ') i++;           
  403         if (pos > 9) {
  404             if (srg.verbose && !longlineMsg) {
  405                 fprintf(stderr, "Ignoring extra fields after content "
  406                         "type. (this message is only printed once)\n");
  407                 longlineMsg = 1;
  408             }
  409             break;
  410         }
  411         start = &lineIn[i];                
  412         i++;
  413     }
  414     if (pos < 9) {
  415         if (srg.verbose) {
  416             fprintf(stderr, "Premature end of line: %s\n", line);
  417         }
  418         goto errexit;
  419     } else {
  420         parts[pos] = start;
  421     }
  422 
  423     /* Transfer into the structure */
  424     lineOut->timestamp = atoi(parts[0]);
  425     lineOut->elapsedTime = atoi(parts[1]);
  426     if (inet_aton(parts[2], &lineOut->clientAddress) == 0) {
  427         /* Possibly a hostname in the log... resolve it */  
  428         if (dnscache->get_ip(parts[2], &lineOut->clientAddress)!=0) {
  429             /* Or perhaps it's just faulty... */
  430             if (srg.verbose)
  431                 fprintf(stderr, "Unable to resolve client "
  432                         "address: %s (ignoring line)\n", 
  433                         parts[2]);
  434             goto errexit;
  435         }   
  436     }
  437     lineOut->resultCode = strdup(parts[3]);
  438     lineOut->size = atoi(parts[4]);
  439     lineOut->requestMethod = strdup(parts[5]);
  440     if (parseURL(parts[6], lineOut->request)!=0) {
  441         /* Invalid request */
  442         if (srg.verbose) 
  443             fprintf(stderr, "Unable to parse request URL: %s " 
  444                     "(ignoring line)\n", parts[6]);
  445         goto errexit2;
  446     }
  447     lineOut->user = strdup(parts[7]);
  448     lineOut->hierarchyData = strdup(parts[8]);
  449     lineOut->contentType = strdup(parts[9]);
  450 
  451     /* Free the rest */
  452     free(lineIn);   
  453     return true;
  454 
  455     /* Execution comes here when an error is found */
  456 errexit2:
  457     /* Free strdup'd lines */
  458     free(lineOut->resultCode);
  459     free(lineOut->requestMethod);
  460     freeURL(lineOut->request);
  461 errexit:
  462     /* Free the rest */
  463     free(lineIn);
  464     return false;
  465 
  466 }
  467 
  468 void print_line(const log_line *line)
  469 {
  470     
  471     time_t tstamp = line->timestamp;
  472     struct tm * tmtstamp = localtime(&tstamp);
  473     
  474     fprintf(stderr, "Time:\t\t\t%s", asctime(tmtstamp));
  475     fprintf(stderr, "Time Elapsed:\t\t%i\n", line->elapsedTime);
  476     fprintf(stderr, "Client Address:\t\t%s\n", 
  477             inet_ntoa(line->clientAddress));
  478     fprintf(stderr, "LogTag/HTTPCode:\t%s\n", line->resultCode);
  479     fprintf(stderr, "Size:\t\t\t%lli\n", line->size);
  480     fprintf(stderr, "RequestMethod:\t\t%s\n", line->requestMethod);
  481     char *URL = asprintURL(line->request);
  482     fprintf(stderr, "URL:\t\t\t%s\n", URL);
  483     free(URL);
  484     fprintf(stderr, "User:\t\t\t%s\n", line->user);
  485     fprintf(stderr, "HierarchyData/Hostname:\t%s\n",
  486             line->hierarchyData);
  487     fprintf(stderr, "ContentType:\t\t%s\n", line->contentType);
  488     
  489 }
  490 
  491 int process_line(const log_line *line)
  492 {
  493     
  494     char *group=NULL;
  495     bool ipuser=false;
  496     
  497     /* See if this line matches the filter (if any) */
  498     if (srg.filter.by > BY_NONE) {
  499         switch(srg.filter.by) {
  500         case BY_USER:
  501             if (strcasecmp(line->user, srg.filter.user)!=0)
  502                 return 0; // Don't do any further processing
  503             break;
  504         case BY_IP:
  505             if (line->clientAddress.s_addr != srg.filter.address.s_addr)
  506                 return 0; // Don't do any further processing
  507             break;
  508         case BY_SUBNET:
  509             if (!isInSubnet(line->clientAddress, 
  510                         srg.filter.network, srg.filter.netmask))
  511                 return 0; // Don't do any further processing
  512             break;
  513         }
  514     }
  515 
  516     /* If site destination filter is in effect check the line */
  517     if (srg.sitefilter) {
  518         if (destination_is_excluded(line->request->site)) {
  519             return 0; // Don't do any further processing
  520         }
  521     }
  522 
  523     /* Grouping? */
  524     if (srg.groupBy <= 0) {
  525         /* Process the line */
  526         stats->process_line(line);
  527         return 1;
  528     }
  529 
  530     /* Work out what group this line belongs in (if any) */
  531     if (srg.groupBy == BY_USER) {
  532         if (strcasecmp(line->user, "-")!=0) {
  533             group = strdup(line->user);
  534         } else {                
  535             if (srg.ip2user) {
  536                 /* Convert ip address to username */
  537                 ipuser = !ip2username(line->clientAddress, &group);
  538             } else {
  539                 ipuser = true;
  540                 group = strdup(inet_ntoa(line->clientAddress));
  541             }
  542         }
  543     } else if (srg.groupBy == BY_IP) {
  544         group = strdup(inet_ntoa(line->clientAddress));
  545     } else if (srg.groupBy == BY_SUBNET) {
  546         in_addr network;
  547         getNetworkAddress(line->clientAddress, srg.groupByNetmask,
  548                 &network);
  549         group = strdup(inet_ntoa(network));             
  550     }
  551 
  552     if (srg.debug)
  553         fprintf(stderr, "Initial Group: %s\n", group);
  554 
  555     if (srg.lookupHosts && ipuser) {
  556         char *tgroup = dnscache->get_name(line->clientAddress);
  557         if (tgroup) {
  558             free(group);
  559             group = strdup(tgroup);
  560         }           
  561     }
  562 
  563     if (srg.debug)
  564         fprintf(stderr, "Final Group: %s\n", group);
  565 
  566     UserReport *theUser = (UserReport *)findUser(group);
  567     if (theUser==NULL) {
  568         if (srg.debug)
  569             fprintf(stderr, "Group not found - creating %s\n", group);
  570         /* The user does not exist. Create it. */
  571         theUser = new UserReport(group);
  572         groups.push_back(theUser);            
  573         if (srg.debug)
  574             fprintf(stderr, "Group List size=%i\n", groups.size());
  575     }
  576 
  577     /* Process the line */
  578     theUser->process_line(line);
  579 
  580     free(group);
  581     group = NULL;
  582 
  583     return 1;
  584 
  585 }
  586 
  587 UserReport *findUser(char * user) {
  588 
  589     list<UserReport*>::const_iterator iter;
  590 
  591     /* Iterate through list and compare each element. */
  592     for (iter=groups.begin(); iter != groups.end(); iter++) {
  593         if(strcasecmp((*iter)->getName(), user)==0)
  594         return (UserReport *)(*iter);
  595     }
  596 
  597     return NULL;
  598 
  599 }
  600 
  601 void generate_reports(const char *basedir) {
  602 
  603     FILE *outfile = NULL;
  604     char *t = NULL;
  605     char *filename = NULL;
  606     char *basepath = NULL;
  607 
  608     list<UserReport*>::const_iterator iter;
  609 
  610     /* Open the report file */
  611     asprintf(&filename, "%s/%s/%s", srg.outputDir, basedir, srg.indexfname);
  612 
  613     outfile = fopen(filename, "w");
  614     if(outfile==NULL) {
  615         fprintf(stderr, "Error opening output file: %s\n", 
  616                 filename);
  617         exit(1);
  618     }
  619     free(filename);
  620 
  621     /* Header & Title */
  622     html_header(outfile, "../");
  623 
  624     fprintf(outfile, "<!-- SRG %s (%s) Generated Report -->\n", 
  625         version, HOME_URL);
  626 
  627     /* Generic Report Information */
  628     fprintf(outfile, "<table cellpadding=2 cellspacing=2 align=\""
  629             "center\">");
  630     fprintf(outfile, "<tr><td class=\"cellText\">Period:</td><td "
  631             "class=\"cellText\">&nbsp;%d %s %d",
  632             localtime(&srg.startTime)->tm_mday, 
  633             month_names[localtime(&srg.startTime)->tm_mon], 
  634             localtime(&srg.startTime)->tm_year+1900);
  635     fprintf(outfile, " - %d %s %d</td></tr>\n",
  636             localtime(&srg.endTime)->tm_mday, 
  637             month_names[localtime(&srg.endTime)->tm_mon], 
  638             localtime(&srg.endTime)->tm_year+1900);
  639     if (srg.groupBy>0) {
  640         fprintf(outfile, "<tr><td class=\"cellText\">Grouped By:"
  641                 "</td><td class=\"cellNum\">%s</td></tr>\n",
  642                 GROUPBY_NAMES[srg.groupBy]);
  643     }
  644     if (srg.filter.by>0) {
  645         fprintf(outfile, "<tr><td class=\"cellText\">Filtered By:"
  646                 "</td><td class=\"cellNum\">%s</td></tr>\n",
  647                 FILTERBY_NAMES[srg.filter.by]);
  648         switch (srg.filter.by) {
  649         case BY_USER:
  650             t = strdup(srg.filter.user);
  651             break;
  652         case BY_IP:
  653             t = strdup(inet_ntoa(srg.filter.address));
  654             break;
  655         case BY_SUBNET:
  656             asprintf(&t, "%s/%s", 
  657                     inet_ntoa(srg.filter.network),
  658                     inet_ntoa(srg.filter.netmask));
  659         }
  660         fprintf(outfile, "<tr><td class=\"cellText\">Filter Criteria:"
  661                 "</td><td class=\"cellNum\">%s</td></tr>\n", t);
  662         free(t);
  663         t = NULL;
  664     }
  665     fprintf(outfile, "</table>\n");
  666 
  667     /* Notices Row */
  668     fprintf(outfile, "<div align=\"center\" id=\"srg-message\">"
  669             "&nbsp;</div>\n");
  670 
  671     /* Main Report Contents */
  672     fprintf(outfile, "<table cellpadding=4 cellspacing=0 "
  673             "align=\"center\" id=\"srgtable\">"
  674             "<thead><tr><th>GROUP</th><th>REQUESTS</th><th>BYTES</th><th>"
  675             "BYTES%%</th><th>HIT</th><th>MISS</th>");
  676     if (srg.showtimes)
  677         fprintf(outfile, "<th>TIME%%</th><th>TIME(ms)</th>");
  678     if (srg.showrates)
  679         fprintf(outfile, "<th>RATE (kb/s)</th>");
  680     fprintf(outfile, "</tr></thead>\n");
  681 
  682     /* Sort the Output */
  683     groups.sort(LessByBytesTransferred<UserReport>());
  684 
  685     /* Initialise the Summary Stats Structure */
  686     summary_info as;    
  687     as.connects = 0;
  688     as.bytesTransferred = 0;
  689     as.hits = 0;
  690     as.misses = 0;
  691     as.bytesHit = 0;
  692     as.bytesMissed = 0;
  693     as.timeSpent = 0;
  694     as.deniedHits = 0;
  695 
  696     /* Collect Statistics */
  697     for (iter=groups.begin(); iter != groups.end(); iter++) {
  698         summary_info tss = (*iter)->getStats();
  699         /* Skip groups with less than the minimum number of connections or
  700          * whose connections were all denied */
  701         if (srg.minimumConnects>0 && tss.connects<srg.minimumConnects) {
  702             if (srg.verbose) {
  703                 fprintf(stdout, "Skipping group %s (not enough requests)!\n", 
  704                         (*iter)->getName());
  705             }
  706             continue;
  707         }
  708         if ((tss.deniedHits==tss.connects) && srg.hideDeniedOnly) {
  709             if (srg.verbose) {
  710                 fprintf(stdout, "Skipping group %s (only denied requests)!\n", 
  711                         (*iter)->getName());
  712             }            
  713             continue;
  714         }
  715         as.connects += tss.connects;
  716         as.bytesTransferred += tss.bytesTransferred;
  717         as.timeSpent += tss.timeSpent;
  718         //as.hits += tss.hits;
  719         as.bytesHit += tss.bytesHit;
  720         //as.misses += tss.misses;
  721         as.bytesMissed += tss.bytesMissed;      
  722     }
  723     
  724     /* Output Totals */
  725     if (srg.authenticate) {
  726         fprintf(outfile, "<?php if (can_view(\"srg-totals\")) {?>\n");
  727     }
  728     
  729     fprintf(outfile, "<tfoot><tr><th class=\"cellText\">Totals:</th>");
  730     t = FormatOutput(as.connects);
  731     fprintf(outfile, "<th class=\"cellNum\">%s</th>", t);
  732     free(t);
  733     t = FormatOutput(as.bytesTransferred);
  734     fprintf(outfile, "<th class=\"cellNum\">%s</th>", t);
  735     free(t);
  736     if (as.bytesTransferred>0) {
  737         /* Calculate total percent in/out of cache */
  738         float percentin=0;
  739         float percentout=0;
  740         percentin = ((float)as.bytesHit/(float)as.bytesTransferred)*100.0;
  741         percentout = ((float)as.bytesMissed/(float)as.bytesTransferred)*100.0;
  742         fprintf(outfile, "<th class=\"cellNum\">100%%</th><th class=\""
  743                 "cellNum\">%.2f%%</th><th class=\"cellNum\">"
  744                 "%.2f%%</th>", percentin, percentout);  
  745     } else {
  746         fprintf(outfile, "<th class=\"cellNum\">100%%</th><th class=\""
  747                 "cellNum\">0.00%</th><th class=\"cellNum\">0.00%</th>");
  748     }
  749     if (srg.showtimes) {
  750         t = FormatOutput(as.timeSpent);
  751         fprintf(outfile, "<th class=\"cellNum\">100%%</th><th class=\""
  752                 "cellNum\">%s</th>", t);
  753         free(t);
  754     }
  755     if (srg.showrates) {
  756         if (as.timeSpent == 0) {
  757             fprintf(outfile, "<th class=\"cellNum\">-</th>");
  758         } else {
  759             t = FormatOutput(as.bytesTransferred/as.timeSpent);
  760             fprintf(outfile, "<th class=\"cellNum\">%s</th>", t);
  761             free(t);
  762         }
  763     }
  764     fprintf(outfile, "</tr></tfoot>\n\n\t");
  765 
  766     if (srg.authenticate)
  767         fprintf(outfile, "\n\t<?php } ?>\n");
  768 
  769     /* Initialise Authenticated Rows Count */
  770     if (srg.authenticate)
  771         fprintf(outfile, "\t<?php $authenticatedrows = 0;?>\n");
  772 
  773     /* Output Report */
  774     int rows=0;
  775     for (iter=groups.begin(); iter != groups.end(); iter++) {
  776         /* Get report statistics and name */
  777         summary_info ss = (*iter)->getStats();
  778         char *md5name = md5this((*iter)->getName());
  779         char *groupdir = NULL;
  780         asprintf(&groupdir, "%s/%s", basedir, md5name); 
  781         
  782         /* Skip groups with less than the minimum number of connections or
  783          * whose connections were all denied */
  784         if (srg.minimumConnects>0 && ss.connects<srg.minimumConnects)
  785             continue;
  786         if ((ss.deniedHits==ss.connects) && srg.hideDeniedOnly)
  787             continue;
  788         
  789         /* Generate the report for this group */
  790         (*iter)->generate_report(basedir);
  791         
  792         /* Authentication */
  793         if (srg.authenticate)
  794             fprintf(outfile,  "\t<?php if (can_view(\"%s\")) {?>"
  795                     "\n\t", (*iter)->getName());
  796         
  797         /* Calculate group statistics */        
  798         float percentin=0;
  799         float percentout=0;
  800         float timespent=0;
  801         float bytespercent=0;
  802         int total = ss.hits+ss.misses;
  803         if (ss.bytesTransferred>0 && ss.connects>0) {
  804             percentin = ((float)ss.bytesHit/(float)ss.bytesTransferred)*100.0;
  805             percentout = ((float)ss.bytesMissed/
  806                     (float)ss.bytesTransferred)*100.0;
  807         } else {
  808             percentin = 0;
  809             percentout = 0;
  810         }
  811         if (srg.debug) {
  812             fprintf(stderr, "percentin=(%lld/%lld)*100=%2.2f\n", ss.bytesHit, 
  813                     ss.bytesTransferred, percentin);
  814             fprintf(stderr, "percentout=(%lld/%lld)*100=%2.2f\n", 
  815                     ss.bytesMissed, ss.bytesTransferred, percentout);
  816         }
  817         if (as.timeSpent == 0) {
  818             timespent = 100;
  819         } else {
  820             timespent=((float)ss.timeSpent/(float)as.timeSpent)*100;
  821         }
  822         if (as.bytesTransferred == 0) {
  823             bytespercent = 100;
  824         } else {
  825             bytespercent = ((float)ss.bytesTransferred /
  826                     (float)as.bytesTransferred)*100;
  827         }
  828         if (srg.debug) {
  829             fprintf(stderr, "bytespercent=(%lld/%lld)*100=%f\n", 
  830                     ss.bytesTransferred, as.bytesTransferred, 
  831                     bytespercent);
  832         }
  833         /* Highlight ever other row */
  834         if ((rows%2)==0)
  835             t = " class=\"highlightRow\"";
  836         else
  837             t = "";
  838         fprintf(outfile, "<tr%s>", t);  
  839         
  840         /* Group Name and link to report */
  841         fprintf(outfile, "<td class=\"bodyText\"><a href=\"%s/%s\">%s"
  842                 "</a></td>", md5name, srg.indexfname, 
  843                 (*iter)->getName());
  844         /* Number of requests */
  845         t = FormatOutput(ss.connects);
  846         fprintf(outfile, "<td class=\"cellNum\">%s</td>", t);
  847         free(t);
  848         /* Bytes Transferred */
  849         t = FormatOutput(ss.bytesTransferred);
  850         fprintf(outfile, "<td class=\"cellNum\">%s</td>", t);
  851         free(t);
  852         /* % of Total Bytes */
  853         fprintf(outfile, "<td class=\"cellNum\">%.2f%%</td>",
  854                 bytespercent);
  855         if (percentin == -1) {
  856             fprintf(outfile, "<td class=\"cellNum\">-</td><td "
  857                     "class=\"cellNum\">-</td>");
  858         } else {
  859             fprintf(outfile, "<td class=\"cellNum\">%.2f%%</td><td "
  860                     "class=\"cellNum\">%.2f%%</td>", 
  861                     percentin, percentout);
  862         }
  863         /* Time Spent */
  864         if (srg.showtimes) {
  865             fprintf(outfile, "<td class=\"cellNum\">%2.2f%%</td>",
  866                     timespent);
  867             t = FormatOutput((int)ss.timeSpent);
  868             fprintf(outfile, "<td class=\"cellNum\">%s</td>", t);
  869             free(t);
  870         }
  871         /* Transfer Rate */
  872         if (srg.showrates) {
  873             if (ss.timeSpent == 0)
  874                 fprintf(outfile, "<td class=\"cellNum\">-"
  875                         "</td>");
  876             else {
  877                 fprintf(outfile, "<td class=\"cellNum\">%.2f</td>",
  878                         ((float)ss.bytesTransferred/(float)ss.timeSpent));
  879             }
  880         }
  881         /* End Row */
  882         fprintf(outfile, "</tr>\n");
  883         if (srg.authenticate)
  884             fprintf(outfile, "\t\t<?php $authenticatedrows++;\n\t}"
  885                     "?>\n");
  886         rows++;
  887         free(md5name);
  888         free(groupdir);
  889     }
  890     fprintf(outfile, "\t</table><br>\n");
  891     
  892     /* Handle no reports output case */
  893     if (srg.authenticate) {
  894         fprintf(outfile, "\t<?php if ($authenticatedrows == 0) {\n"
  895                 "\t\treport_error(\"There are no reports "
  896                 "available for the selected time period.\""
  897                 ");\n\t}\n\t?>\n");
  898     }
  899 
  900     /* Link back to the index */
  901     fprintf(outfile, "\t<div align=\"center\"><a href=\"../%s\">"
  902             "Back</a> to dates page</div>\n", srg.indexfname);
  903     
  904     if (srg.authenticate) {
  905         fprintf(outfile, "<?php } else {\n report_error(\"Could "
  906                 "not authenticate user\");\n}?>");
  907     }
  908     
  909     /* Finish off the HTML */
  910     html_footer(outfile, "../");
  911     fclose(outfile);
  912 
  913     /* Remove the entire directory if there were no groups */
  914     if (rows==0) {
  915         asprintf(&basepath, "%s/%s", srg.outputDir, basedir);
  916         if (srg.verbose) {
  917             fprintf(stdout, "Removing %s. No groups found in report!\n", 
  918                     basepath);
  919         }
  920         recurse_unlink(basepath);
  921         free(basepath);
  922     }
  923 
  924 }
  925 
  926 void make_date_index() {
  927     
  928     DIR *dirp;
  929     struct dirent *direntp;
  930     char *file_name;
  931     char *filename;
  932     FILE *outfile;
  933 
  934     /* Open the output file */
  935     asprintf(&filename, "%s/%s", srg.outputDir, srg.indexfname);
  936     outfile = fopen(filename, "w");
  937     if(outfile==NULL) {
  938         fprintf(stderr, "Error opening output file: %s\n", 
  939                 filename);
  940         exit(1);
  941     }
  942     free(filename);
  943 
  944     /* Generate the headers */
  945     html_header(outfile, "");
  946 
  947     fprintf(outfile, "<!-- SRG %s (%s) Generated Date Index -->\n", 
  948         version, HOME_URL);
  949 
  950     fprintf(outfile, "<center><table cellpadding=4 cellspacing=0>");
  951     fprintf(outfile, "<tr><th>Select a time period to "
  952         "view reports for:</th></tr>\n");
  953 
  954     /* go through output dir and make lines for each directory */
  955     list<char *> folders;
  956 
  957     dirp = opendir(srg.outputDir);
  958     if (dirp == NULL) {
  959         fprintf(stderr, "Error opening %s to generate date index: "
  960                         "%s\n", srg.outputDir, strerror(errno));
  961         exit(1);
  962     }
  963     while ((direntp = readdir(dirp)) != NULL) {
  964 
  965         /* Skip dot files */
  966         if (direntp->d_name[0] == '.')
  967             continue;
  968 
  969         /* Check directory has a valid name, if not skip it! */
  970         if (strlen(direntp->d_name) != 19)
  971             continue;
  972 
  973         /* Build Absolute Path */
  974         asprintf(&file_name, "%s/%s", srg.outputDir, direntp->d_name);
  975 
  976         /* Retrieve filetype */
  977         struct stat buf;
  978         if (stat(file_name, &buf) != 0) {
  979             fprintf(stderr, "Failed to stat file %s : %s\n",
  980                     file_name, strerror(errno ));
  981             exit(1);
  982         }
  983         if ((buf.st_mode & S_IFMT) == S_IFDIR) {
  984             /* It's a directory */
  985             char *tmp = strdup(direntp->d_name);
  986             folders.push_back(tmp);
  987         }
  988         free(file_name);
  989     }
  990 
  991     if (closedir( dirp ) == -1) {
  992           fprintf(stderr, "Error closing dir %s : %s \n", 
  993             srg.outputDir,strerror(errno));
  994           exit(1);
  995     }
  996 
  997     /* Display the list of directories */
  998     folders.sort(&compare_datename);
  999     list<char *>::reverse_iterator iter;
 1000     long long linecount = 0;
 1001 
 1002     for (iter=folders.rbegin(); iter!=folders.rend(); iter++) {
 1003         fprintf(outfile, "<tr");
 1004         if (linecount % 2 == 0) {
 1005             fprintf(outfile, " class=highlightRow");
 1006         }
 1007         fprintf(outfile, "><td class=cellText align=center><a href=\""
 1008             "%s/%s\">%s</a></td></tr>\n", (*iter), srg.indexfname,
 1009             (*iter));
 1010         linecount++;        
 1011     }
 1012 
 1013     if (linecount == 0) {
 1014         fprintf(outfile, "<tr><td class=cellHeader>No reports found"
 1015                 "</td></tr>");
 1016     }
 1017     fprintf(outfile, "\n\n\t</table></center><br><br>");
 1018 
 1019     if (srg.authenticate) {
 1020         fprintf(outfile, "<?php } else {\n report_error(\"Could not "
 1021                 "authenticate user\");\n}?>");
 1022     }
 1023 
 1024     for (iter=folders.rbegin(); iter!=folders.rend(); iter++) {
 1025         free(*iter);
 1026     }
 1027     
 1028     /* Finish off the HTML */
 1029     html_footer(outfile, "");
 1030     fclose(outfile);
 1031 
 1032 }
 1033 
 1034 void cull_oldreports(int maxage) {
 1035     
 1036     DIR *dirp;
 1037     struct dirent *direntp;
 1038     char *file_name=NULL;
 1039     time_t curr;
 1040     tm local;
 1041     tm folder;
 1042     
 1043     memset(&folder, 0, sizeof(folder));
 1044     time(&curr); // get current time_t value
 1045     local=*(localtime(&curr)); // dereference and assign
 1046 
 1047     if (srg.debug) {
 1048         fprintf(stderr, "Culling reports over %d days (%d seconds) "
 1049                 "old\n", maxage, maxage*24*60*60);
 1050     }
 1051 
 1052     dirp = opendir( srg.outputDir );
 1053     if (dirp == NULL) {
 1054         fprintf(stderr, "Error opening directory %s to cull reports: "
 1055                 "%s\n", srg.outputDir, strerror(errno));
 1056         exit(1);
 1057     }
 1058 
 1059     while ( (direntp = readdir( dirp )) != NULL ) {
 1060         if (direntp == NULL) {
 1061             fprintf(stderr, "Error reading directory entry %s "
 1062                     "for culling: %s \n", srg.outputDir,
 1063                     strerror(errno));
 1064             exit(1);
 1065         }
 1066 
 1067         /* skip the ./ and ../ files */
 1068         if (direntp->d_name[0] == '.')
 1069             continue;
 1070         
 1071         /* Check directory has a valid name, if not skip it! */
 1072         if (strlen(direntp->d_name) != 19)
 1073             continue;
 1074         
 1075         /* build the full path */
 1076         asprintf(&file_name, "%s/%s", srg.outputDir, direntp->d_name);
 1077 
 1078         char *dirname = direntp->d_name;
 1079         struct stat buf;
 1080 
 1081         /* Find file's type */
 1082         if (stat(file_name, &buf) != 0) {
 1083             fprintf(stderr, "Failed to stat file %s - "
 1084                     "%s\n", file_name, strerror(errno));
 1085             exit(1);
 1086             free(file_name);
 1087         }
 1088 
 1089         /* Skip regular files */        
 1090         if ((buf.st_mode & S_IFMT) != S_IFDIR) {
 1091             free(file_name);
 1092             continue;
 1093         }
 1094         
 1095         if (srg.debug) {
 1096             fprintf(stderr, "Inspecting %s\n", file_name);
 1097         }
 1098 
 1099         /* Get date of directory */
 1100         char *year, *month_name, *day;
 1101         year = strdup(dirname+10);
 1102         year[4] = '\0';
 1103         month_name = strdup(dirname+14);
 1104         month_name[3] = '\0';
 1105         day = strdup(dirname+17);
 1106         int monthnum;
 1107         monthnum=getMonthByName(month_name);
 1108         if (srg.debug) {
 1109             fprintf(stderr, "\tExtracted %s %s (%d) %s\n", day,
 1110                     month_name, monthnum, year);
 1111         }
 1112         /* Place in to structure */
 1113         folder.tm_mday = atoi(day);
 1114         folder.tm_mon = monthnum;
 1115         folder.tm_year = atoi(year)-1900;
 1116         /* Clean Up */
 1117         free(year);
 1118         free(month_name);
 1119         free(day);
 1120         time_t foldertimet = mktime(&folder);
 1121         if (foldertimet == (time_t)(-1)) {
 1122             fprintf(stderr, "Could not mktime for %d %d %d.\n",
 1123                     folder.tm_mday, folder.tm_mon, folder.tm_year);
 1124             free(file_name);
 1125             exit(1);
 1126         }
 1127         time_t now = time(0);
 1128         int seconds = (int)difftime(foldertimet, now);
 1129         if (srg.debug) {
 1130             fprintf(stderr, "\t%d seconds old\n",  seconds);
 1131         }
 1132         if (seconds < (0-(maxage*24*60*60))) {
 1133             if (srg.debug) {
 1134                 fprintf(stderr, "\tRemoving\n");
 1135             }
 1136             recurse_unlink(file_name);
 1137         }
 1138 
 1139         free(file_name);            
 1140     }
 1141 
 1142     if (closedir( dirp ) == -1) {
 1143         fprintf(stderr, "Error closing dir %s - %s \n", srg.outputDir,
 1144                 strerror(errno));
 1145         exit(1);
 1146     }
 1147     
 1148 }
 1149 
 1150 void recurse_unlink(const char *dirname) {
 1151 
 1152     DIR *dirp;
 1153     struct dirent *direntp;
 1154     char file_name[256];
 1155 
 1156     dirp = opendir( dirname );
 1157     if (dirp == NULL) {
 1158         fprintf(stderr, "Error opening %s for removal: %s\n", dirname,
 1159                 strerror(errno));
 1160         exit(1);
 1161     }
 1162     while ( (direntp = readdir( dirp )) != NULL ) {
 1163         if (direntp == NULL) {
 1164             fprintf(stderr, "Error opening entry %s for removal:"
 1165                     " %s \n", dirname, 
 1166                 strerror(errno));
 1167                 exit(1);
 1168         }
 1169 
 1170         if (direntp->d_name[0] == '.')
 1171             continue;
 1172         
 1173         strcpy (file_name,dirname);
 1174         strcat (file_name,"/");
 1175         strcat (file_name,direntp->d_name);
 1176 
 1177         struct stat buf;
 1178 
 1179         if (stat(file_name, &buf) == 0) {
 1180             /* Recursively call ourselves for directories */
 1181             if ((buf.st_mode & S_IFMT) == S_IFDIR) {
 1182                 recurse_unlink(file_name);
 1183             } else {
 1184                 if (srg.debug)
 1185                     fprintf(stderr, "Deleting file: %s\n",
 1186                             file_name);
 1187                 if (unlink(file_name) == -1) {
 1188                     fprintf(stderr, "Error: Could not "
 1189                             "delete %s - %s\n", file_name,
 1190                             strerror(errno));
 1191                     exit(1);
 1192                 }
 1193             }
 1194         } else {
 1195             fprintf(stderr, "Error: Failed to stat file %s "
 1196                     "- %s\n",file_name, strerror(errno));
 1197             exit(1);
 1198         }
 1199     }
 1200 
 1201     if (closedir( dirp ) == -1) {
 1202         fprintf(stderr, "Error closing dir %s - %s \n", dirname, 
 1203                 strerror(errno));
 1204         exit(1);
 1205     }
 1206     if (rmdir(dirname) == -1) {
 1207         fprintf(stderr, "Error removing dir %s - %s \n", dirname, 
 1208                 strerror(errno));
 1209         exit(1);
 1210     }
 1211     
 1212 }
 1213 
 1214 // vim: ts=4 sw=4 sts=4 et