/* SRG - Squid Report Generator Copyright 2003 University of Waikato This file is part of SRG. SRG is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SRG is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SRG; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "srg.h" #include "Report.h" #include "UserReport.h" #include "prototypes.h" #include #include /* Local Prototype */ UserReport* findUser(char * user); /* Program Information */ char *progname; config_info srg; /* Constant Strings */ char *GROUPBY_NAMES[4] = {"Not Grouped", "User", "IP Address", "Subnet"}; char *FILTERBY_NAMES[4] = {"Not Filtered", "User", "IP Address", "Subnet"}; char *month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; /* Global Data Structures */ list groups; UserReport* stats; Resolver *dnscache; /* Version information */ char *cvsid = "$Id: main.cc,v 1.69 2004/09/25 12:46:54 mattgbrown Exp $"; char *version = "1.1"; /* Get this show on the road */ int main(int argc, char **argv) { progname = strrchr(argv[0], '/'); if (progname == NULL) progname = argv[0]; else progname++; /* Configure srg */ do_configuration(argc, argv); /* Ensure Base Directory Exists */ if (mkdir(srg.outputDir, 0755) == -1) { if (errno != EEXIST) { fprintf(stderr, "%s: Error creating base output " "directory: %s\n", argv[0], srg.outputDir); exit(1); } } /* Make sure the style sheet is present if using default */ if (srg.defaultcss) { init_stylesheet(srg.outputDir, CSS_NAME); } /* Likewise for javascript */ if (srg.usejs) { init_javascript(srg.outputDir); } /* Create a new DNS resolving library */ dnscache = new Resolver(false); /* Initialise ip2user mappings */ init_ip2user(); if (srg.verbose) fprintf(stdout, "Configuration Completed... Beginning " "Analysation\n"); /* If we are not grouping then just create a default group */ if (srg.groupBy == BY_NONE) { stats = new UserReport("All"); stats->singleUserMode = true; } /* Process the logfile */ process_log(); if (srg.verbose) fprintf(stdout, "Finished processing log file: %s, creating " "reports.\n", srg.accessLog); /* Create the datename for the report */ char *datename = generate_datename(srg.startTime, srg.endTime); /* Create the base directory for the report */ char *basename = NULL; asprintf(&basename, "%s/%s", srg.outputDir, datename); if (mkdir(basename, 0755) == -1 && errno != EEXIST) { fprintf(stderr, "Error (%s) creating directory: %s\n", strerror(errno), basename); exit(1); } /* Call the actual reports to output themselves */ if (srg.groupBy > 0) generate_reports(datename); else stats->generate_report(datename); free(datename); free(basename); /* Delete old reports */ if (srg.maxreportage > 0) cull_oldreports(srg.maxreportage); /* Make index for all dates */ make_date_index(); /* Must be grouped for email report */ assert(srg.groupBy>=0 && srg.groupBy<=BY_MAX); if (srg.emailreport && srg.groupBy>0) { generate_email_report(); } /* Get rid of our dns cache */ delete dnscache; /* Get rid of our groups */ list::const_iterator iter; for (iter=groups.begin(); iter != groups.end(); iter++) { delete (*iter); } if (srg.groupBy == BY_NONE) delete stats; return 0; } void generate_email_report(void) { char *start = strdup(ctime(&srg.startTime)); char *sp = strchr(start, '\n'); *sp = '\0'; char *end = strdup(ctime(&srg.endTime)); char *ep = strchr(end, '\n'); *ep = '\0'; fprintf(stdout, "SRG - Squid Traffic Report for %s to %s\n\n", start, end); assert(srg.filter.by>=BY_NONE && srg.filter.by<=BY_MAX); if (srg.filter.by) { fprintf(stdout, "%-20s%-15s\n", "Filtered By:", FILTERBY_NAMES[srg.filter.by]); if (srg.filter.by == BY_USER) { fprintf(stdout, "%-20s%-15s\n", "Filter Criteria:", srg.filter.user); } else if (srg.filter.by == BY_IP) { fprintf(stdout, "%-20s%-15s\n", "Filter Criteria:", inet_ntoa(srg.filter.address)); } else if (srg.filter.by == BY_SUBNET) { fprintf(stdout, "%-20s%-15s/%s\n", "Filter Criteria:", inet_ntoa(srg.filter.network), inet_ntoa(srg.filter.netmask)); } } groups.sort(LessByBytesMissed()); list::const_iterator iter; unsigned long long ttraffic=0; unsigned long long ftraffic=0; int ngroups=0; char *t1=NULL, *t2=NULL; /* Get the total traffic from all groups */ for (iter=groups.begin(); iter != groups.end(); iter++) { summary_info sitestats = (*iter)->getStats(); if (srg.hideDeniedOnly > 0 && sitestats.deniedHits == sitestats.connects) { // Nothing } else { ttraffic += sitestats.bytesTransferred; ftraffic += sitestats.bytesMissed; ngroups++; } } fprintf(stdout, "%-15s%-15s\n", "Grouped By:", GROUPBY_NAMES[srg.groupBy]); fprintf(stdout, "%-15s%-15i\n", "No Groups:", ngroups); fprintf(stdout, "\n%-47sTraffic Used\n", ""); fprintf(stdout, "%-35s%15s %15s\n\n", "Group Name", "External (kB)", "Total (kB)"); /* Now write out the actual groups */ for (iter=groups.begin(); iter != groups.end(); iter++) { summary_info sitestats = (*iter)->getStats(); if (srg.hideDeniedOnly > 0 && sitestats.deniedHits == sitestats.connects) { // Nothing } else { t1 = FormatOutput(sitestats.bytesMissed/1024); t2 = FormatOutput(sitestats.bytesTransferred/1024); fprintf(stdout, "%-35s%15s %15s\n", (*iter)->getName(), t1, t2); free(t1); free(t2); } } t1 = FormatOutput(ftraffic/1024); t2 = FormatOutput(ttraffic/1024); fprintf(stdout, "\n%-35s%15s %15s\n", "Total Traffic",t1,t2); free(t1); free(t2); free(start); free(end); sp=NULL; ep=NULL; } void process_log(void) { Line *iLine = new Line(srg.accessLog); int linesT=0; int linesP=0; log_line line; line.request = new url_request; char *a = NULL; if (iLine->getError()) { fprintf(stderr,"ERROR: Can not open '%s': %s\n", srg.accessLog, strerror(iLine->getError())); exit(1); } while(iLine->getError()==0 && !iLine->eof()) { a = iLine->getline(); if (parse_line(a, &line)) { if (srg.startTime < 1) srg.startTime = line.timestamp; linesP += process_line(&line); /* Free Memory */ freeURL(line.request); free(line.resultCode); free(line.requestMethod); free(line.user); free(line.hierarchyData); free(line.contentType); } linesT++; free(a); } delete line.request; delete iLine; if (srg.endTime < 1) { srg.endTime = line.timestamp; } assert(srg.startTime > 0); assert(srg.endTime > 0); } int parse_line(char * line, log_line *lineOut) { char * parts[10]; unsigned int pos=0; unsigned int i=0; char *lineIn = strdup(line); char *start = lineIn; while (lineIn[i] != '\0') { if (lineIn[i]!=' ') { i++; continue; } lineIn[i]='\0'; parts[pos] = start; if (pos==0) { int timestamp = atoi(parts[pos]); /* Check if we are filtering by time */ if (srg.startTime > 0 && srg.endTime > 0) { /* Check if this line is required */ if (timestamp < srg.startTime || timestamp > srg.endTime) { /* Don't process */ goto errexit; } } } pos++; /* Eat Whitespace */ i++; while (lineIn[i] == ' ') i++; if (pos > 9) { if (srg.verbose) fprintf(stderr, "Extra whitespace in URL, " "ignoring line: %s\n", line); goto errexit; } start = &lineIn[i]; i++; } if (pos != 9) { if (srg.verbose) fprintf(stderr, "Premature end of line: %s\n", line); goto errexit; } parts[pos] = start; /* Transfer into the structure */ lineOut->timestamp = atoi(parts[0]); lineOut->elapsedTime = atoi(parts[1]); if (inet_aton(parts[2], &lineOut->clientAddress) == 0) { /* Possibly a hostname in the log... resolve it */ if (dnscache->get_ip(parts[2], &lineOut->clientAddress)!=0) { /* Or perhaps it's just faulty... */ if (srg.verbose) fprintf(stderr, "Unable to resolve client " "address: %s (ignoring line)\n", parts[2]); goto errexit; } } lineOut->resultCode = strdup(parts[3]); lineOut->size = atoi(parts[4]); lineOut->requestMethod = strdup(parts[5]); if (parseURL(parts[6], lineOut->request)!=0) { /* Invalid request */ if (srg.verbose) fprintf(stderr, "Unable to parse request URL: %s " "(ignoring line)\n", parts[6]); goto errexit2; } lineOut->user = strdup(parts[7]); lineOut->hierarchyData = strdup(parts[8]); lineOut->contentType = strdup(parts[9]); /* Free the rest */ free(lineIn); return true; /* Execution comes here when an error is found */ errexit2: /* Free strdup'd lines */ free(lineOut->resultCode); free(lineOut->requestMethod); freeURL(lineOut->request); errexit: /* Free the rest */ free(lineIn); return false; } void print_line(const log_line *line) { time_t tstamp = line->timestamp; struct tm * tmtstamp = localtime(&tstamp); fprintf(stderr, "Time:\t\t\t%s", asctime(tmtstamp)); fprintf(stderr, "Time Elapsed:\t\t%i\n", line->elapsedTime); fprintf(stderr, "Client Address:\t\t%s\n", inet_ntoa(line->clientAddress)); fprintf(stderr, "LogTag/HTTPCode:\t%s\n", line->resultCode); fprintf(stderr, "Size:\t\t\t%lli\n", line->size); fprintf(stderr, "RequestMethod:\t\t%s\n", line->requestMethod); char *URL = asprintURL(line->request); fprintf(stderr, "URL:\t\t\t%s\n", URL); free(URL); fprintf(stderr, "User:\t\t\t%s\n", line->user); fprintf(stderr, "HierarchyData/Hostname:\t%s\n", line->hierarchyData); fprintf(stderr, "ContentType:\t\t%s\n", line->contentType); } int process_line(const log_line *line) { char *group=NULL; bool ipuser=false; // See if this line matches the filter (if any) if (srg.filter.by > BY_NONE) { switch(srg.filter.by) { case BY_USER: if (strcasecmp(line->user, srg.filter.user)!=0) return 0; // Don't do any further processing break; case BY_IP: if (line->clientAddress.s_addr != srg.filter.address.s_addr) return 0; // Don't do any further processing break; case BY_SUBNET: if (!isInSubnet(line->clientAddress, srg.filter.network, srg.filter.netmask)) return 0; // Don't do any further processing break; } } // Grouping? if (srg.groupBy <= 0) { // Process the line stats->process_line(line); return 1; } // Work out what group this line belongs in (if any) if (srg.groupBy == BY_USER) { if (strcasecmp(line->user, "-")!=0) { group = strdup(line->user); } else { if (srg.ip2user) { /* Convert ip address to username */ ipuser = !ip2username(line->clientAddress, &group); } else { ipuser = true; group = strdup(inet_ntoa(line->clientAddress)); } } } else if (srg.groupBy == BY_IP) { group = strdup(inet_ntoa(line->clientAddress)); } else if (srg.groupBy == BY_SUBNET) { in_addr network; getNetworkAddress(line->clientAddress, srg.groupByNetmask, &network); group = strdup(inet_ntoa(network)); } if (srg.debug) fprintf(stderr, "Initial Group: %s\n", group); if (srg.lookupHosts && ipuser) { char *tgroup = dnscache->get_name(line->clientAddress); if (tgroup) { free(group); group = strdup(tgroup); } } if (srg.debug) fprintf(stderr, "Final Group: %s\n", group); UserReport *theUser = (UserReport *)findUser(group); if (theUser==NULL) { if (srg.debug) fprintf(stderr, "Group not found - creating %s\n", group); // The user does not exist. Create it. theUser = new UserReport(group); groups.push_back(theUser); if (srg.debug) fprintf(stderr, "Group List size=%i\n", groups.size()); } // Process the line theUser->process_line(line); free(group); group = NULL; return 1; } UserReport *findUser(char * user) { list::const_iterator iter; // Iterate through list and compare each element. for (iter=groups.begin(); iter != groups.end(); iter++) { if(strcasecmp((*iter)->getName(), user)==0) return (UserReport *)(*iter); } return NULL; } void generate_reports(const char *basedir) { FILE *outfile = NULL; char *t = NULL; char *filename = NULL; char *basepath = NULL; list::const_iterator iter; /* Open the report file */ asprintf(&filename, "%s/%s/%s", srg.outputDir, basedir, srg.indexfname); outfile = fopen(filename, "w"); if(outfile==NULL) { fprintf(stderr, "Error opening output file: %s\n", filename); exit(1); } free(filename); /* Header & Title */ html_header(outfile, "../"); fprintf(outfile, "\n", version, HOME_URL); /* Generic Report Information */ fprintf(outfile, ""); fprintf(outfile, "\n", localtime(&srg.endTime)->tm_mday, month_names[localtime(&srg.endTime)->tm_mon], localtime(&srg.endTime)->tm_year+1900); if (srg.groupBy>0) { fprintf(outfile, "\n", GROUPBY_NAMES[srg.groupBy]); } if (srg.filter.by>0) { fprintf(outfile, "\n", FILTERBY_NAMES[srg.filter.by]); switch (srg.filter.by) { case BY_USER: t = strdup(srg.filter.user); break; case BY_IP: t = strdup(inet_ntoa(srg.filter.address)); break; case BY_SUBNET: asprintf(&t, "%s/%s", inet_ntoa(srg.filter.network), inet_ntoa(srg.filter.netmask)); } fprintf(outfile, "", t); free(t); t = NULL; } fprintf(outfile, "
Period: %d %s %d", localtime(&srg.startTime)->tm_mday, month_names[localtime(&srg.startTime)->tm_mon], localtime(&srg.startTime)->tm_year+1900); fprintf(outfile, " - %d %s %d
Grouped By:" "%s
Filtered By:" "%s
Filter Criteria:" "%s
\n"); /* Notices Row */ fprintf(outfile, "
" " 
\n"); /* Main Report Contents */ fprintf(outfile, "" ""); if (srg.showtimes) fprintf(outfile, ""); if (srg.showrates) fprintf(outfile, ""); fprintf(outfile, "\n"); /* Initialise Authentication */ if (srg.usephp && srg.authenticate) fprintf(outfile, "\t\n"); /* Sort the Output */ groups.sort(LessByBytesTransferred()); /* Initialise the Summary Stats Structure */ summary_info as; as.connects = 0; as.bytesTransferred = 0; as.hits = 0; as.misses = 0; as.bytesHit = 0; as.bytesMissed = 0; as.timeSpent = 0; as.deniedHits = 0; float asfhits = 0; float asfmisses = 0; /* Collect Statistics */ for (iter=groups.begin(); iter != groups.end(); iter++) { summary_info tss = (*iter)->getStats(); if ((tss.deniedHits==tss.connects) && srg.hideDeniedOnly) continue; /* Skip this group */ as.connects += tss.connects; as.bytesTransferred += tss.bytesTransferred; as.timeSpent += tss.timeSpent; //as.hits += tss.hits; as.bytesHit += tss.bytesHit; //as.misses += tss.misses; as.bytesMissed += tss.bytesMissed; } /* Output Report */ int rows=0; for (iter=groups.begin(); iter != groups.end(); iter++) { /* Get report statistics and name */ summary_info ss = (*iter)->getStats(); char *md5name = md5this((*iter)->getName()); char *groupdir = NULL; asprintf(&groupdir, "%s/%s", basedir, md5name); if ((ss.deniedHits==ss.connects) && srg.hideDeniedOnly) continue; /* Skip this group */ /* Generate the report for this group */ (*iter)->generate_report(basedir); /* Authentication */ if (srg.usephp && srg.authenticate) fprintf(outfile, "\t" "\n\t", (*iter)->getName()); /* Calculate group statistics */ float percentin=0; float percentout=0; float timespent=0; float bytespercent=0; int total = ss.hits+ss.misses; if (total == 0) { percentin = -1; percentout = -1; } else { percentin = ((float)ss.hits/(float)total)*100; percentout = ((float)ss.misses/(float)total)*100; asfhits += percentin; asfmisses += percentout; } if (srg.debug) { fprintf(stderr, "percentin=(%lld/%d)*100=%f\n", ss.hits, total, percentin); fprintf(stderr, "percentout=(%lld/%d)*100=%f\n", ss.misses, total, percentout); } if (as.timeSpent == 0) { timespent = 100; } else { timespent=((float)ss.timeSpent/(float)as.timeSpent)*100; } if (as.bytesTransferred == 0) { bytespercent = 100; } else { bytespercent = ((float)ss.bytesTransferred / (float)as.bytesTransferred)*100; } if (srg.debug) { fprintf(stderr, "bytespercent=(%lld/%lld)*100=%f\n", ss.bytesTransferred, as.bytesTransferred, bytespercent); } /* Highlight ever other row */ if ((rows%2)==0) t = " class=\"highlightRow\""; else t = ""; fprintf(outfile, "", t); /* Group Name and link to report */ fprintf(outfile, "", md5name, srg.indexfname, (*iter)->getName()); /* Number of requests */ t = FormatOutput(ss.connects); fprintf(outfile, "", t); free(t); /* Bytes Transferred */ t = FormatOutput(ss.bytesTransferred); fprintf(outfile, "", t); free(t); /* % of Total Bytes */ fprintf(outfile, "", bytespercent); if (percentin == -1) { fprintf(outfile, ""); } else { fprintf(outfile, "", percentin, percentout); } /* Time Spent */ if (srg.showtimes) { fprintf(outfile, "", timespent); t = FormatOutput((int)ss.timeSpent); fprintf(outfile, "", t); free(t); } /* Transfer Rate */ if (srg.showrates) { if (ss.timeSpent == 0) fprintf(outfile, ""); else { fprintf(outfile, "", ((float)ss.bytesTransferred/ (float)ss.timeSpent)); } } /* End Row */ fprintf(outfile, "\n"); if (srg.usephp && srg.authenticate) fprintf(outfile, "\t\t\n"); rows++; free(md5name); free(groupdir); } /* How many columns are in the table */ int cols=6; if (srg.showtimes) cols+=2; if (srg.showrates) cols+=2; /* Handle to reports output case */ if (srg.usephp && srg.authenticate) fprintf(outfile, "\t\";\n" "\t\treport_error(\"There are no reports " "available for the selected time period.\"" ");\n\t} else "); /* Calculate total percent in and out of cache */ float percentin=0; float percentout=0; if (asfhits+asfmisses == 0 && rows != 0) percentin = percentout = -1; else { percentin = (float)asfhits/(float)rows; percentout = (float)asfmisses/(float)rows; } /* Output Totals */ if (srg.usephp && srg.authenticate) fprintf(outfile, " if ($authenticatedrows==%d) {?>\n", rows); fprintf(outfile, ""); t = FormatOutput(as.connects); fprintf(outfile, "", t); free(t); t = FormatOutput(as.bytesTransferred); fprintf(outfile, "", t); free(t); if (percentin == -1) fprintf(outfile, ""); else fprintf(outfile, "", percentin, percentout); if (srg.showtimes) { t = FormatOutput(as.timeSpent); fprintf(outfile, "", t); free(t); } if (srg.showrates) { if (as.timeSpent == 0) { fprintf(outfile, ""); } else { t = FormatOutput(as.bytesTransferred/as.timeSpent); fprintf(outfile, "", t); free(t); } } fprintf(outfile, "\n\n\t"); if (srg.usephp && srg.authenticate) fprintf(outfile, "\n\t\n"); fprintf(outfile, "
GROUPREQUESTSBYTES" "BYTES%%IN-CACHE-OUTTIME%%TIME(ms)RATE (kb/s)
%s" "%s%s%.2f%%--%.2f%%%.2f%%%2.2f%%%s-" "" "%2.0f%%
Totals:%s%s100%%--100%%%.2f%%" "%.2f%%100%%%s-%s

"); /* Link back to the index */ fprintf(outfile, "\n\t
" "Back to dates page
\n", srg.indexfname); if (srg.usephp && srg.authenticate) { fprintf(outfile, ""); } /* Finish off the HTML */ html_footer(outfile, "../"); fclose(outfile); /* Remove the entire directory if there were no groups */ if (rows==0) { asprintf(&basepath, "%s/%s", srg.outputDir, basedir); recurse_unlink(basepath); free(basepath); } } void make_date_index() { DIR *dirp; struct dirent *direntp; char *file_name; char *filename; FILE *outfile; /* Open the output file */ asprintf(&filename, "%s/%s", srg.outputDir, srg.indexfname); outfile = fopen(filename, "w"); if(outfile==NULL) { fprintf(stderr, "Error opening output file: %s\n", filename); exit(1); } free(filename); /* Generate the headers */ html_header(outfile, ""); fprintf(outfile, "\n", version, HOME_URL); fprintf(outfile, "
"); fprintf(outfile, ""); //go through output dir and make lines for each directory list folders; dirp = opendir(srg.outputDir); if (dirp == NULL) { fprintf(stderr, "Error opening %s to generate date index: " "%s\n", srg.outputDir, strerror(errno)); exit(1); } while ((direntp = readdir(dirp)) != NULL) { /* Skip dot files */ if (direntp->d_name[0] == '.') continue; /* Check directory has a valid name, if not skip it! */ if (strlen(direntp->d_name) != 19) continue; /* Build Absolute Path */ asprintf(&file_name, "%s/%s", srg.outputDir, direntp->d_name); /* Retrieve filetype */ struct stat buf; if (stat(file_name, &buf) != 0) { fprintf(stderr, "Failed to stat file %s : %s\n", file_name, strerror(errno )); exit(1); } if ((buf.st_mode & S_IFMT) == S_IFDIR) { /* It's a directory */ char *tmp = strdup(direntp->d_name); folders.push_back(tmp); } free(file_name); } if (closedir( dirp ) == -1) { fprintf(stderr, "Error closing dir %s : %s \n", srg.outputDir,strerror(errno)); exit(1); } /* Display the list of directories */ folders.sort(&compare_datename); list::reverse_iterator iter; long long linecount = 0; for (iter=folders.rbegin(); iter!=folders.rend(); iter++) { fprintf(outfile, "", (*iter), srg.indexfname, (*iter)); linecount++; } if (linecount == 0) { fprintf(outfile, ""); } fprintf(outfile, "\n\n\t
Select a time period to " "view reports for
%s
No reports found" "


"); if (srg.phpheader && srg.authenticate) { fprintf(outfile, ""); } for (iter=folders.rbegin(); iter!=folders.rend(); iter++) { free(*iter); } /* Finish off the HTML */ html_footer(outfile, ""); fclose(outfile); } void cull_oldreports(int maxage) { DIR *dirp; struct dirent *direntp; char *file_name=NULL; time_t curr; tm local; tm folder; memset(&folder, 0, sizeof(folder)); time(&curr); // get current time_t value local=*(localtime(&curr)); // dereference and assign if (srg.debug) { fprintf(stderr, "Culling reports over %d days (%d seconds) " "old\n", maxage, maxage*24*60*60); } dirp = opendir( srg.outputDir ); if (dirp == NULL) { fprintf(stderr, "Error opening directory %s to cull reports: " "%s\n", srg.outputDir, strerror(errno)); exit(1); } while ( (direntp = readdir( dirp )) != NULL ) { if (direntp == NULL) { fprintf(stderr, "Error reading directory entry %s " "for culling: %s \n", srg.outputDir, strerror(errno)); exit(1); } // skip the ./ and ../ files if (direntp->d_name[0] == '.') continue; /* Check directory has a valid name, if not skip it! */ if (strlen(direntp->d_name) != 19) { continue; } // build the full path asprintf(&file_name, "%s/%s", srg.outputDir, direntp->d_name); char *dirname = direntp->d_name; struct stat buf; // Find file's type if (stat(file_name, &buf) != 0) { fprintf(stderr, "Failed to stat file %s - " "%s\n", file_name, strerror(errno)); exit(1); free(file_name); } /* Skip regular files */ if ((buf.st_mode & S_IFMT) != S_IFDIR) { free(file_name); continue; } if (srg.debug) { fprintf(stderr, "Inspecting %s\n", file_name); } /* Get date of directory */ char *year, *month_name, *day; year = strdup(dirname+10); year[4] = '\0'; month_name = strdup(dirname+14); month_name[3] = '\0'; day = strdup(dirname+17); int monthnum; monthnum=getMonthByName(month_name); if (srg.debug) { fprintf(stderr, "\tExtracted %s %s (%d) %s\n", day, month_name, monthnum, year); } /* Place in to structure */ folder.tm_mday = atoi(day); folder.tm_mon = monthnum; folder.tm_year = atoi(year)-1900; /* Clean Up */ free(year); free(month_name); free(day); time_t foldertimet = mktime(&folder); if (foldertimet == (time_t)(-1)) { fprintf(stderr, "Could not mktime for %d %d %d.\n", folder.tm_mday, folder.tm_mon, folder.tm_year); free(file_name); exit(1); } time_t now = time(0); int seconds = (int)difftime(foldertimet, now); if (srg.debug) { fprintf(stderr, "\t%d seconds old\n", seconds); } if (seconds < (0-(maxage*24*60*60))) { if (srg.debug) { fprintf(stderr, "\tRemoving\n"); } recurse_unlink(file_name); } free(file_name); } if (closedir( dirp ) == -1) { fprintf(stderr, "Error closing dir %s - %s \n", srg.outputDir, strerror(errno)); exit(1); } } void recurse_unlink(const char *dirname) { DIR *dirp; struct dirent *direntp; char file_name[256]; dirp = opendir( dirname ); if (dirp == NULL) { fprintf(stderr, "Error opening %s for removal: %s\n", dirname, strerror(errno)); exit(1); } while ( (direntp = readdir( dirp )) != NULL ) { if (direntp == NULL) { fprintf(stderr, "Error opening entry %s for removal:" " %s \n", dirname, strerror(errno)); exit(1); } if (direntp->d_name[0] == '.') continue; strcpy (file_name,dirname); strcat (file_name,"/"); strcat (file_name,direntp->d_name); struct stat buf; if (stat(file_name, &buf) == 0) { /* Recursively call ourselves for directories */ if ((buf.st_mode & S_IFMT) == S_IFDIR) { recurse_unlink(file_name); } else { if (srg.debug) fprintf(stderr, "Deleting file: %s\n", file_name); if (unlink(file_name) == -1) { fprintf(stderr, "Error: Could not " "delete %s - %s\n", file_name, strerror(errno)); exit(1); } } } else { fprintf(stderr, "Error: Failed to stat file %s " "- %s\n",file_name, strerror(errno)); exit(1); } } if (closedir( dirp ) == -1) { fprintf(stderr, "Error closing dir %s - %s \n", dirname, strerror(errno)); exit(1); } if (rmdir(dirname) == -1) { fprintf(stderr, "Error removing dir %s - %s \n", dirname, strerror(errno)); exit(1); } }