"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\"> %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 " </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