Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

NewsCacheClean.cc File Reference

#include "config.h"
#include <string.h>
#include <getopt.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <algorithm>
#include "Debug.h"
#include "setugid.h"
#include "Config.h"
#include "Logger.h"
#include "NServer.h"

Go to the source code of this file.

Classes

class  Entry
struct  cache_statistic

Defines

#define PACKAGE   PACKAGE_NEWSCACHECLEAN
#define MAX(a, b)   (((a)>(b))?(a):(b))
#define FILE_ACCESS_TABLE_ENTRIES   100000
#define USAGE

Functions

bool sort_entries (const Entry *l, const Entry *r)
void clean (const char *cpath)
void remove_elements (long max_blocks, struct cache_statistic *pS)
int main (int argc, char **argv)

Variables

Logger slog
const char * cmnd
Config Cfg
vector< Entry * > pvector
long _blocks = 0


Define Documentation

#define FILE_ACCESS_TABLE_ENTRIES   100000
 

Definition at line 66 of file NewsCacheClean.cc.

#define MAX a,
 )     (((a)>(b))?(a):(b))
 

Definition at line 65 of file NewsCacheClean.cc.

#define PACKAGE   PACKAGE_NEWSCACHECLEAN
 

Definition at line 62 of file NewsCacheClean.cc.

#define USAGE
 

Value:

"       -h, --help\n"\
"              Show summary of options.\n"\
"\n"\
"       -v, --version\n"\
"              Show version of program.\n"\
"\n"\
"       -c --configuration config-file\n"\
"\n"\
"       -s --statistic\n"\
"              Show statistic informations.\n"\
"\n"\
"       -p --print-purgetable\n"\
"              Print the sorted purge table.\n"\
"\n"\
"       -t --try\n"\
"              Try, not really removing files.\n"\

Definition at line 321 of file NewsCacheClean.cc.


Function Documentation

void clean const char *  cpath  ) 
 

Definition at line 204 of file NewsCacheClean.cc.

References _blocks, Cfg, Logger::Error, NVNewsgroup::firstnbr(), NVNewsgroup::lastnbr(), MAX, NC_CATCH_ALL, Logger::p(), pvector, slog, Config::SpoolDirectory, and VERB.

Referenced by main().

00205 {
00206         VERB(slog.p(Logger::Debug) << "clean(" << cpath << ")\n");
00207         DIR *d;
00208         time_t dbatime;
00209         char buf[MAXPATHLEN];
00210 
00211         struct dirent *f;
00212         struct stat s;
00213 
00214         sprintf(buf, "%s/.db", cpath);
00215         // Exception Directories
00216         if (strcmp(buf, "./.artSpool") == 0)
00217                 return;
00218         if (strcmp(buf, "./.badArticles") == 0)
00219                 return;
00220         if (stat(buf, &s) == 0) {
00221                 dbatime = MAX(s.st_atime, s.st_mtime);
00222                 pvector.push_back( new Entry (buf, dbatime, s.st_blocks) );
00223                 _blocks += s.st_blocks;
00224                 --dbatime;
00225         } else {
00226                 dbatime = 0;
00227         }
00228 
00229         if ((d = opendir(cpath)) == NULL) {
00230                 slog.p(Logger::Error) << "cannot open " << cpath << "\n";
00231                 return;
00232         }
00233         while ((f = readdir(d)) != NULL) {
00234                 if (strcmp(f->d_name, ".") == 0)
00235                         continue;
00236                 if (strcmp(f->d_name, "..") == 0)
00237                         continue;
00238                 sprintf(buf, "%s/%s", cpath, f->d_name);
00239                 if (stat(buf, &s) == 0) {
00240                         if (S_ISDIR(s.st_mode))
00241                                 clean(buf);
00242                 } else {
00243                         slog.
00244                             p(Logger::
00245                               Error) << "cannot stat " << buf << "\n";
00246                 }
00247         }
00248         closedir(d);
00249 
00250         if ((d = opendir(cpath)) == NULL) {
00251                 slog.p(Logger::Error) << "cannot reopen " << cpath << "\n";
00252                 return;
00253         }
00254         // sanity check
00255         string ngname (cpath);
00256         // ./be/comp/os/unix -> be.comp.os.unix
00257         ngname.replace (0, 2, "");
00258         int i;
00259         while ((i=ngname.find ("/")) != -1) {
00260                 ngname[i] = '.';
00261         }
00262         NVNewsgroup *ng;
00263         OverviewFmt *fmt = new OverviewFmt ();
00264         int firstnr;
00265         int lastnr;
00266         try {
00267                 string dbname = cpath;
00268                 dbname += "/.db";
00269                 struct stat s;
00270                 if (stat (dbname.c_str(), &s) == 0) {
00271                         ng = new NVNewsgroup (fmt,
00272                                 (const char *) Cfg.SpoolDirectory,
00273                                 ngname.c_str());
00274                 } else {
00275                         ng = NULL;
00276                 }
00277         } catch (NoSuchGroupError e) {
00278                 ng = NULL;
00279         }
00280         // FIXME: what we are doing with bad database files?
00281         NC_CATCH_ALL ("Error, please report bug!");
00282         if (ng != NULL) {
00283                 firstnr = ng->firstnbr ();
00284                 lastnr = ng->lastnbr ();
00285                 delete ng;
00286         }
00287         string art;
00288         int nr;
00289         while ((f = readdir(d)) != NULL) {
00290                 sprintf(buf, "%s/%s", cpath, f->d_name);
00291                 if (stat(buf, &s) == 0) {
00292                         if (S_ISREG(s.st_mode) && dbatime != 0 &&
00293                             strncmp(f->d_name, ".art", 4) == 0) {
00294                                 time_t at = MAX(s.st_atime, s.st_mtime);
00295                                 if (dbatime <= at)
00296                                         at = dbatime;
00297                                 art = f->d_name;
00298                                 art.replace (0,4, "");
00299                                 if (sscanf (art.c_str(), "%d", &nr) != 1) {
00300                                         slog.p(Logger::Error) << "error "
00301                                                 << "parsing " << f->d_name;
00302                                 } else if ( ng == NULL | nr < firstnr || nr > lastnr) {
00303                                         at = 0;
00304                                 }
00305                                 pvector.push_back (new Entry(buf, at, 
00306                                         s.st_blocks) );
00307                                 _blocks += s.st_blocks;
00308                         }
00309                 } else {
00310                         slog.
00311                             p(Logger::
00312                               Error) << "cannot stat " << buf << "\n";
00313                 }
00314         }
00315         closedir(d);
00316         return;
00317 }

int main int  argc,
char **  argv
 

Definition at line 340 of file NewsCacheClean.cc.

References _blocks, Cfg, clean(), cmnd, CONF_UIDROOT, Config::Groupname, Config::LogDirectory, Config::NiceServer, Logger::open(), Logger::p(), PACKAGE, pvector, Config::read(), remove_elements(), setugid(), slog, sort_entries(), Config::SpoolDirectory, Config::SpoolSize, SYSCONFDIR, USAGE, Config::Username, and VERSION.

00341 {
00342 #ifndef WITH_SYSLOG
00343         char logfile[MAXPATHLEN];
00344         time_t t;
00345         pid_t p;
00346 #endif
00347         char conffile[MAXPATHLEN];
00348         int opt_config = 0;
00349         int c, aerr = 0;
00350         struct cache_statistic Stat;
00351         int nice;
00352         int stat=0;
00353         int try_flag = 0;
00354         char p_flag=0;
00355         vector<Entry *>::iterator begin, end;
00356 
00357         memset ((void *) &Stat, 0, sizeof (struct cache_statistic));
00358 
00359         sprintf(conffile, "%s/newscache.conf", SYSCONFDIR);
00360 
00361         cmnd = argv[0];
00362         while (1) {
00363                 int option_index = 0;
00364                 static struct option long_options[] = {
00365                         {"version", 0, 0, 'v'},
00366                         {"help", 0, 0, 'h'},
00367                         {"configuration", 1, 0, 'c'},
00368                         {"statistic", 0, 0, 's'},
00369                         {"try", 0, 0, 't'},
00370                         {"print-purgetable", 0, 0, 'p'},
00371                         {0, 0, 0, 0}
00372                 };
00373 
00374                 c = getopt_long (argc, argv, "vhc:stp", long_options,
00375                                 &option_index);
00376 
00377                 if (c == -1)
00378                         break;
00379 
00380                 switch (c) {
00381                         case 'v':
00382                                 cout << PACKAGE << " " << VERSION << endl;
00383                                 exit (0);
00384                                 break;
00385 
00386                         case 'h':
00387                                 cout << "Usage: " << cmnd << endl;
00388                                 cout << USAGE << endl;
00389                                 exit (0);
00390                                 break;
00391 
00392                         case 'c':
00393                                 strcpy (conffile, optarg);
00394                                 ++opt_config;
00395                                 break;
00396 
00397                         case 's':
00398                                 stat = 1;
00399                                 break;
00400 
00401                         case 't':
00402                                 try_flag = 1;
00403                                 break;
00404                         
00405                         case 'p':
00406                                 p_flag = 1;
00407                                 break;
00408 
00409                         default:
00410                                 aerr = 1;
00411                                 break;
00412                 }
00413         }
00414 
00415         if (aerr || optind != argc) {
00416                 cerr << "Usage: " << cmnd << " [options]\n" << USAGE;
00417                 exit(1);
00418         }
00419 
00420         try {
00421                 Cfg.read(conffile);
00422 //    strcpy(nntp_hostname,Cfg.Hostname);
00423         }
00424         catch(IOError & io) {
00425                 cerr << "unexpected EOF in " << conffile << "\n";
00426                 exit(2);
00427         }
00428         catch(SyntaxError & se) {
00429                 cerr << se._errtext << "\n";
00430                 exit(2);
00431         }
00432 
00433 #ifdef WITH_SYSLOG
00434         slog.open(PACKAGE, LOG_NDELAY | LOG_PID, LOG_NEWS);
00435 #else
00436         sprintf (logfile, "%s/newscache_newscacheclean.log", Cfg.LogDirectory);
00437         slog.open (logfile);
00438 #endif
00439         slog.p(Logger::Info) << "cleaning spool directory\n";
00440 
00441 
00442         /* set nice value for master server */
00443 #ifdef HAVE_SETPRIORITY
00444         errno = 0;
00445         nice = Cfg.NiceServer;
00446         nice += getpriority(PRIO_PROCESS, 0);
00447         if (nice == -1 && errno != 0) {
00448                 slog.
00449                     p(Logger::
00450                       Error) << "getpriority failed: " << strerror(errno)
00451                     << "\n";
00452         } else {
00453                 if (setpriority(PRIO_PROCESS, 0, nice) == -1)
00454                         slog.
00455                             p(Logger::
00456                               Error) << "setpriority failed: " <<
00457                             strerror(errno) << "\n";
00458         }
00459 #endif
00460 
00461         if (chdir(Cfg.SpoolDirectory) < 0) {
00462                 slog.
00463                     p(Logger::
00464                       Error) <<
00465                     "cannot change to spool directory -- exiting\n";
00466                 exit(1);
00467         }
00468         if (getuid() == CONF_UIDROOT)
00469                 setugid(Cfg.Username, Cfg.Groupname);
00470         clean(".");
00471         sort (pvector.begin(), pvector.end(), sort_entries);
00472         if (p_flag) {
00473                 cout << "---------------- Purge table ----------------" << endl;
00474                 for (begin=pvector.begin(), end=pvector.end();
00475                      begin != end; begin++) {
00476                         (*begin)->print (cout);
00477                 }
00478                 cout << "---------------- Purge table ----------------" << endl;
00479         }
00480         if (!try_flag) {
00481                 remove_elements(Cfg.SpoolSize * 2, &Stat);
00482         }
00483         if (stat) {
00484                 print_statistic(cout, &Stat);
00485         }
00486 
00487         slog.p(Logger::Info) << "|SpoolDirectory|="
00488             << (unsigned int) (_blocks / 2) << "K\n";
00489         return 0;
00490 }

void remove_elements long  max_blocks,
struct cache_statistic pS
 

Definition at line 143 of file NewsCacheClean.cc.

References _blocks, Logger::Error, Logger::p(), pvector, slog, cache_statistic::stArtCnt, cache_statistic::stArtSize, cache_statistic::stDbCnt, cache_statistic::stDbSize, cache_statistic::stOutArtCnt, cache_statistic::stOutArtSize, cache_statistic::stPurgedArtCnt, cache_statistic::stPurgedArtSize, cache_statistic::stPurgedDbCnt, cache_statistic::stPurgedDbSize, cache_statistic::stPurgedDirCnt, cache_statistic::stPurgedOutArtCnt, and cache_statistic::stPurgedOutArtSize.

Referenced by main().

00144 {
00145         int isDb;
00146         char cBuffer[MAXPATHLEN];
00147         vector<Entry *>::iterator begin, end;
00148 
00149         for (begin=pvector.begin(), end=pvector.end();
00150              begin != end; begin++) {
00151                 (*begin)->Path.length();
00152                 if (strcmp((*begin)->Path.c_str() + (*begin)->Path.length() - 3, ".db") == 0) {
00153                         isDb = 1;
00154                         pS->stDbCnt++;
00155                         pS->stDbSize += (*begin)->blocks;
00156                 } else {
00157                         isDb = 0;
00158                         if ((*begin)->atime != 0) {
00159                                 pS->stArtCnt++;
00160                                 pS->stArtSize += (*begin)->blocks;
00161                         } else {
00162                                 pS->stOutArtCnt++;
00163                                 pS->stOutArtSize += (*begin)->blocks;
00164                         }
00165                 }
00166                 if ((*begin)->atime != 0 && _blocks <= max_blocks)
00167                         continue;
00168                 if (unlink((*begin)->Path.c_str()) == 0) {
00169                         _blocks -= (*begin)->blocks;
00170                         if (!isDb) {
00171                                 if ((*begin)->atime != 0) {
00172                                         pS->stPurgedArtCnt++;
00173                                         pS->stPurgedArtSize += (*begin)->blocks;
00174                                 } else {
00175                                         pS->stPurgedOutArtCnt++;
00176                                         pS->stPurgedOutArtSize += (*begin)->blocks;
00177                                 }
00178                         } else {
00179                                 pS->stPurgedDbCnt++;
00180                                 pS->stPurgedDbSize += (*begin)->blocks;
00181                                 strcpy(cBuffer, (*begin)->Path.c_str());
00182                                 cBuffer[strlen(cBuffer) - 3] = '\0';
00183                                 if (rmdir(cBuffer) == 0) {
00184                                         pS->stPurgedDirCnt++;
00185                                 } else if (errno == ENOTEMPTY) {
00186                                         slog.p(Logger::Debug) 
00187                                                 << "Error rmdir "
00188                                                 << "(Directory not empty) "
00189                                                 << (*begin)->Path << "\n";
00190                                 } else {
00191                                         slog.p(Logger::Error) 
00192                                                 << "Error rmdir "
00193                                                 << (*begin)->Path << "\n";
00194                                 }
00195                         }
00196                 } else {
00197                         slog.
00198                             p(Logger::
00199                               Error) << "Error unlink " << (*begin)->Path << "\n";
00200                 }
00201         }
00202 }

bool sort_entries const Entry l,
const Entry r
 

Definition at line 134 of file NewsCacheClean.cc.

References Entry::atime.

Referenced by main().

00135 {
00136         if (l->atime < r->atime)
00137                 return 1;
00138         else
00139                 return 0;
00140 }


Variable Documentation

long _blocks = 0
 

Definition at line 110 of file NewsCacheClean.cc.

Referenced by clean(), main(), and remove_elements().

Config Cfg
 

Definition at line 70 of file NewsCacheClean.cc.

const char* cmnd
 

Definition at line 69 of file NewsCacheClean.cc.

vector<Entry*> pvector
 

Definition at line 87 of file NewsCacheClean.cc.

Referenced by clean(), main(), and remove_elements().

Logger slog
 

Definition at line 68 of file NewsCacheClean.cc.


Generated on Sun Oct 24 21:08:20 2004 for NewsCache by doxygen 1.3.6-20040222