]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - lastlog.c
Update the man page
[thirdparty/sarg.git] / lastlog.c
index bdf42585c69207f077cb4ca90d943beab66b0f05..0ff25aa2c1b2a8435f8ca0c5b9482b414cf4709e 100644 (file)
--- a/lastlog.c
+++ b/lastlog.c
@@ -1,10 +1,11 @@
 /*
- * AUTHOR: Pedro Lineu Orso                         pedro.orso@gmail.com
- *                                                            1998, 2008
  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
+ *                                                            1998, 2015
  *
  * SARG donations:
  *      please look at http://sarg.sourceforge.net/donations.php
+ * Support:
+ *     http://sourceforge.net/projects/sarg/forums/forum/363374
  * ---------------------------------------------------------------------
  *
  *  This program is free software; you can redistribute it and/or modify
 #include "include/conf.h"
 #include "include/defs.h"
 
+struct DirEntry
+{
+       struct DirEntry *Next;
+       time_t Time;
+       char *Name;
+};
+
+static void DeleteDirList(struct DirEntry *List)
+{
+       struct DirEntry *Next;
+
+       while (List)
+       {
+               Next=List->Next;
+               if (List->Name) free(List->Name);
+               free(List);
+               List=Next;
+       }
+}
+
+static struct DirEntry *AppendDirEntry(struct DirEntry *List,time_t CreationTime,const char *Name,int NameLen)
+{
+       struct DirEntry *entry;
+       struct DirEntry *prev;
+       struct DirEntry *ptr;
+
+       entry=malloc(sizeof(*entry));
+       if (!entry) {
+               debuga(__FILE__,__LINE__,_("Not enough memory to store a report to purge\n"));
+               DeleteDirList(List);
+               return(NULL);
+       }
+       entry->Name=malloc((NameLen+1)*sizeof(char));
+       if (!entry->Name) {
+               free(entry);
+               debuga(__FILE__,__LINE__,_("Not enough memory to store a report to purge\n"));
+               DeleteDirList(List);
+               return(NULL);
+       }
+       entry->Time=CreationTime;
+       strcpy(entry->Name,Name);
+
+       // store most recent file first
+       prev=NULL;
+       for (ptr=List ; ptr ; ptr=ptr->Next)
+       {
+               if (ptr->Time>CreationTime) break;
+               prev=ptr;
+       }
+       entry->Next=ptr;
+       if (prev)
+               prev->Next=entry;
+       else
+               List=entry;
+
+       return(List);
+}
+
+static struct DirEntry *BuildDirDateList(struct DirEntry *List,char *Path,int PathSize,int RootPos,int Length,int Level)
+{
+       DIR *dirp;
+       struct dirent *direntp;
+       struct stat statb;
+       int name_len;
+
+       if ((dirp = opendir(Path)) == NULL) {
+               debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),Path,strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       while ((direntp = readdir( dirp )) != NULL )
+       {
+               name_len=strlen(direntp->d_name);
+               if (RootPos+name_len+1>=PathSize) {
+                       debuga(__FILE__,__LINE__,_("Directory entry \"%s%s\" too long to purge the old reports\n"),Path,direntp->d_name);
+                       exit(EXIT_FAILURE);
+               }
+               strcpy(Path+Length,direntp->d_name);
+               if (stat(Path,&statb) == -1) {
+                       debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),Path,strerror(errno));
+                       continue;
+               }
+               if (!S_ISDIR(statb.st_mode)) continue;
+               if (Level==0)
+               {
+                       if (IsTreeMonthFileName(direntp->d_name))
+                       {
+                               Path[Length+name_len]='/';
+                               Path[Length+name_len+1]='\0';
+                               List=BuildDirDateList(List,Path,PathSize,RootPos,Length+name_len+1,1);
+                               if (!List)
+                               {
+                                       debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                                       break;
+                               }
+                       }
+               }
+               else if (Level==1)
+               {
+                       if (IsTreeDayFileName(direntp->d_name))
+                       {
+                               List=AppendDirEntry(List,statb.st_mtime,Path+RootPos,Length-RootPos+name_len);
+                               if (!List)
+                               {
+                                       debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       closedir(dirp);
+       return(List);
+}
+
+static struct DirEntry *BuildDirList(const char *Path)
+{
+       DIR *dirp;
+       struct dirent *direntp;
+       struct stat statb;
+       char warea[MAXLEN];
+       int name_pos;
+       int name_len;
+       struct DirEntry *List=NULL;
+
+       name_pos=strlen(Path);
+       if (name_pos>=sizeof(warea)) {
+               debuga(__FILE__,__LINE__,_("The directory name \"%s\" containing the old reports to purge is too long\n"),Path);
+               exit(EXIT_FAILURE);
+       }
+       strcpy(warea,Path);
+       if ((dirp = opendir(outdir)) == NULL) {
+               debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),outdir,strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       while ((direntp = readdir( dirp )) != NULL )
+       {
+               name_len=strlen(direntp->d_name);
+               if (name_pos+name_len+1>=sizeof(warea)) {
+                       debuga(__FILE__,__LINE__,_("Directory entry \"%s%s\" too long to purge the old reports\n"),Path,direntp->d_name);
+                       exit(EXIT_FAILURE);
+               }
+               strcpy(warea+name_pos,direntp->d_name);
+               if (stat(warea,&statb) == -1) {
+                       debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),warea,strerror(errno));
+                       continue;
+               }
+               if (!S_ISDIR(statb.st_mode)) continue;
+               if (IsTreeFileDirName(direntp->d_name))
+               {
+                       List=AppendDirEntry(List,statb.st_mtime,direntp->d_name,name_len);
+                       if (!List)
+                       {
+                               debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                               break;
+                       }
+               }
+               else if (IsTreeYearFileName(direntp->d_name))
+               {
+                       warea[name_pos+name_len]='/';
+                       warea[name_pos+name_len+1]='\0';
+                       List=BuildDirDateList(List,warea,sizeof(warea),name_pos,name_pos+name_len+1,0);
+                       if (!List)
+                       {
+                               debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                               break;
+                       }
+               }
+       }
+
+       closedir(dirp);
+       return(List);
+}
+
+static void DeleteEmptyDirs(char *Path,int PathSize,int BasePos)
+{
+       char *Dir;
+       DIR *dirp;
+       struct dirent *direntp;
+       bool index;
+
+       while ((Dir=strrchr(Path,'/'))!=NULL)
+       {
+               if (Dir-Path<=BasePos) break;
+               *Dir='\0';
+               if ((dirp = opendir(Path)) == NULL) {
+                       debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),Path,strerror(errno));
+                       return;
+               }
+               index=false;
+               while ((direntp = readdir( dirp )) != NULL )
+               {
+                       if (direntp->d_name[0]=='.' && (direntp->d_name[1]=='\0' || (direntp->d_name[1]=='.' && direntp->d_name[2]=='\0'))) continue;
+                       if (!strcmp(direntp->d_name,INDEX_HTML_FILE))
+                       {
+                               index=true;
+                               continue;
+                       }
+                       break;
+               }
+               closedir(dirp);
+               if (direntp!=NULL) {
+                       // at least one file exists in the directory, don't delete the directory
+                       break;
+               }
+               if (debug)
+                       debuga(__FILE__,__LINE__,_("Deleting empty directory \"%s\"\n"),Path);
+               if (index) {
+                       if (strlen(Path)+strlen(INDEX_HTML_FILE)+2>=PathSize) {
+                               debuga(__FILE__,__LINE__,_("Buffer too small to delete index file \"%s/%s\""),Path,INDEX_HTML_FILE);
+                               exit(EXIT_FAILURE);
+                       }
+                       strcat(Path,"/"INDEX_HTML_FILE);
+                       if (unlink(Path)==-1) {
+                               debuga(__FILE__,__LINE__,_("Failed to delete \"%s\": %s\n"),Path,strerror(errno));
+                               exit(EXIT_FAILURE);
+                       }
+                       *Dir='\0';
+               }
+               if (rmdir(Path)) {
+                       debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),Path,strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+       }
+       //! \todo Rebuild the surviving index file
+}
+
 void mklastlog(const char *outdir)
 {
+       char warea[MAXLEN];
+       int name_pos;
+       int  ftot=0;
+       struct DirEntry *List;
+       struct DirEntry *ptr;
+
+       if(LastLog <= 0)
+               return;
+
+       List=BuildDirList(outdir);
+       if (!List) return;
+
+       for (ptr=List ; ptr ; ptr=ptr->Next) ftot++;
+       if (debug)
+               debuga(__FILE__,__LINE__,ngettext("%d report directory found\n","%d report directories found\n",ftot),ftot);
+
+       if(ftot<=LastLog) {
+               DeleteDirList(List);
+               if (debug) {
+                       debuga(__FILE__,__LINE__,ngettext("No old reports to delete as only %d report currently exists\n",
+                                               "No old reports to delete as only %d reports currently exist\n",ftot),ftot);
+               }
+               return;
+       }
+
+       ftot-=LastLog;
+       if (debug)
+               debuga(__FILE__,__LINE__,ngettext("%d old report to delete\n","%d old reports to delete\n",ftot),ftot);
+
+       name_pos=strlen(outdir);
+       if (name_pos>=sizeof(warea)) {
+               DeleteDirList(List);
+               debuga(__FILE__,__LINE__,_("The directory name \"%s\" containing the old reports to purge is too long\n"),outdir);
+               exit(EXIT_FAILURE);
+       }
+       strcpy(warea,outdir);
+       for (ptr=List ; ptr && ftot>0 ; ptr=ptr->Next)
+       {
+               if(debug)
+                       debuga(__FILE__,__LINE__,_("Removing old report file %s\n"),ptr->Name);
+               if (name_pos+strlen(ptr->Name)+1>=sizeof(warea)) {
+                       DeleteDirList(List);
+                       debuga(__FILE__,__LINE__,_("Path too long: "));
+                       debuga_more("%s%s\n",outdir,ptr->Name);
+                       exit(EXIT_FAILURE);
+               }
+               strcpy(warea+name_pos,ptr->Name);
+               unlinkdir(warea,0);
+               DeleteEmptyDirs(warea,sizeof(warea),name_pos);
+               ftot--;
+       }
 
-   FILE *fp_in, *fp_ou;
-   DIR *dirp;
-   struct dirent *direntp;
-   char temp[MAXLEN];
-   char warea[MAXLEN];
-   char ftime[128];
-   int  ftot=0;
-   time_t t;
-   struct tm *local;
-   struct stat statb;
-   int cstatus;
-
-   if(strcmp(LastLog,"0") == 0)
-      return;
-
-   sprintf(temp,"%slastlog1",outdir);
-   if((fp_ou=fopen(temp,"w"))==NULL) {
-     fprintf(stderr, "SARG: (lastlog) %s: %s\n",text[9],temp);        
-     exit(1);
-   }
-
-   dirp = opendir(outdir);
-   while ((direntp = readdir( dirp )) != NULL ){
-      if(strstr(direntp->d_name,"-") == 0)
-         continue;
-
-      sprintf(warea,"%s%s",outdir,direntp->d_name);
-      stat(warea,&statb);
-      t=statb.st_ctime;
-      local = localtime(&t);
-      strftime(ftime, 127, "%Y%m%d%H%M%S", local);
-      fprintf(fp_ou,"%s %s\n",ftime,direntp->d_name);
-      ftot++;
-   }
-
-   (void)rewinddir( dirp );
-   (void)closedir( dirp );
-   fclose(fp_ou);
-   
-   sprintf(buf,"sort -n -k 1,1 -o '%slastlog' '%s'",outdir,temp);
-   cstatus=system(buf);
-   if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-      fprintf(stderr, "SARG: sort command return status %d\n",WEXITSTATUS(cstatus));
-      fprintf(stderr, "SARG: sort command: %s\n",buf);
-      exit(1);
-   }
-
-   unlink(temp);
-
-   if(ftot<=atoi(LastLog)) {
-      sprintf(temp,"%slastlog",outdir);
-      if(access(temp, R_OK) == 0)
-         unlink(temp);
-      return;
-   }
-
-   ftot-=atoi(LastLog);
-
-   sprintf(temp,"%slastlog",outdir);
-   if((fp_in=fopen(temp,"r"))==NULL) {
-     fprintf(stderr, "SARG: (lastlog) %s: %s\n",text[9],temp);        
-     exit(1);
-   }
-
-   while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
-      if (getword(warea,sizeof(warea),buf,' ')<0) {
-         printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",temp);
-         exit(1);
-      }
-      buf[strlen(buf)-1]='\0';
-     
-      if(ftot) {
-         if(debug)
-            debuga("%s: %s",text[81],buf);
-//         sprintf(temp,"%s%s",outdir,buf);
-         sprintf(temp,"rm -r %s%s",outdir,buf);
-         system(temp);
-         unlink(temp);
-         ftot--;
-      }
-   }
-
-   fclose(fp_in);
-   sprintf(temp,"%slastlog",outdir);
-   unlink(temp);
-   return;
+       DeleteDirList(List);
+       return;
 }