00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <unistd.h>
00019 #include <string.h>
00020 #include <errno.h>
00021 #include <getopt.h>
00022 #include <netinet/in.h>
00023 #include <arpa/inet.h>
00024 #include <netdb.h>
00025 #include <signal.h>
00026 #include <sys/types.h>
00027 #include <sys/socket.h>
00028 #include <sys/wait.h>
00029
00030 #include <iostream>
00031 #include <vector>
00032
00033 #include "config.h"
00034 #include "Debug.h"
00035 #include "Config.h"
00036 #include "NServer.h"
00037 #include "Logger.h"
00038 #include "setugid.h"
00039
00040 using namespace std;
00041
00042 #ifndef WITH_UNIQUE_PACKAGE_NAME
00043 #undef PACKAGE
00044 #define PACKAGE PACKAGE_UPDATENEWS
00045 #endif
00046
00047
00048
00049
00050
00051
00052 enum {
00053 F_PREFETCH_ACTIVE = 0x01,
00054 F_PREFETCH_GROUP = 0x02,
00055 F_PREFETCH_OVER = 0x04,
00056 F_PREFETCH_LOCKGROUP = 0x08
00057 };
00058
00059 Logger slog;
00060 const char *cmnd;
00061 Config Cfg;
00062 int opt_flags = 0;
00063 int opt_workers = 0;
00064 int Xsignal;
00065
00066 void catchsignal(int num)
00067 {
00068 Xsignal = num;
00069 slog.p(Logger::Warning) << "received signal " << num << "\n";
00070 #ifdef HAVE_SIGACTION
00071
00072 struct sigaction action;
00073 action.sa_handler = catchsignal;
00074 sigemptyset(&action.sa_mask);
00075 action.sa_flags = 0;
00076 sigaction(num, &action, NULL);
00077 #else
00078 signal(num, catchsignal);
00079 #endif
00080 }
00081
00082 void doprefetch(CServer * cs, const char *group)
00083 {
00084 Newsgroup *grp;
00085 try {
00086 slog.p(Logger::Info) << "prefetching " << group << "\n";
00087 grp = cs->getgroup(group);
00088 if (opt_flags & F_PREFETCH_GROUP)
00089 grp->
00090 prefetchGroup(opt_flags &
00091 F_PREFETCH_LOCKGROUP);
00092 else if (opt_flags & F_PREFETCH_OVER)
00093 grp->prefetchOverview();
00094 cs->freegroup(grp);
00095 }
00096 catch(...) {
00097 slog.
00098 p(Logger::
00099 Error) << "prefetching " << group << " failed\n";
00100 }
00101 }
00102
00103 int create_worker(CServer * cs, const char *group)
00104 {
00105 int c;
00106 switch (c = fork()) {
00107 case -1:
00108
00109 slog.
00110 p(Logger::
00111 Error) << "fork failed, using this process\n";
00112 doprefetch(cs, group);
00113 return 0;
00114 case 0:
00115
00116 doprefetch(cs, group);
00117 exit(0);
00118 default:
00119
00120 return 1;
00121 break;
00122 }
00123 }
00124
00125 void readgroups(const char *fn, vector < string > &groups)
00126 {
00127 ifstream ifs(fn);
00128 string group;
00129
00130 if (!ifs.good()) {
00131 return;
00132 }
00133
00134 for (; Xsignal < 0;) {
00135 nlreadline(ifs, group, 0);
00136 if (ifs.eof())
00137 break;
00138 if (group[0] == '!')
00139 continue;
00140 if (ifs.bad()) {
00141 slog.
00142 p(Logger::Error) << "cannot read from " << Cfg.
00143 PrefetchFile;
00144 break;
00145 }
00146 groups.push_back(group);
00147 }
00148 ifs.close();
00149 }
00150
00151 void update(void)
00152 {
00153 CServer cs(Cfg.SpoolDirectory, &(Cfg.srvrs));
00154 int wi = opt_workers ? 0 : -1;
00155
00156 cs.setttl(Cfg.ttl_list, Cfg.ttl_desc);
00157
00158 slog.p(Logger::Info) << "posting spooled articles\n";
00159 cs.postspooled();
00160 if (opt_flags & F_PREFETCH_ACTIVE) {
00161 slog.p(Logger::Debug) << "invalidate the ActiveDB (force update)\n";
00162 cs.invalidateActiveDB ();
00163 };
00164 slog.p(Logger::Info) << "prefetching active database\n";
00165 cs.active();
00166
00167 if (!(opt_flags & (F_PREFETCH_GROUP | F_PREFETCH_OVER)))
00168 return;
00169
00170
00171 vector < string > groups;
00172 vector < string >::iterator begin, end;
00173 readgroups(Cfg.PrefetchFile, groups);
00174
00175 for (begin = groups.begin(), end = groups.end();
00176 begin != end && Xsignal < 0; ++begin) {
00177 while (wi == opt_workers) {
00178
00179 int cstat;
00180 int cid;
00181 cid = wait(&cstat);
00182 if (WIFSIGNALED(cstat)) {
00183 slog.
00184 p(Logger::
00185 Error) <<
00186 "worker terminated unexpectedly\n";
00187 --wi;
00188 } else if (WIFEXITED(cstat)) {
00189 --wi;
00190 }
00191 }
00192 if (opt_workers == 0)
00193 doprefetch(&cs, begin->c_str());
00194 else
00195 wi += create_worker(&cs, begin->c_str());
00196 }
00197 }
00198
00199 #define USAGE \
00200 " -h, --help\n"\
00201 " Show summary of options.\n"\
00202 "\n"\
00203 " -v, --version\n"\
00204 " Show version of program.\n"\
00205 "\n"\
00206 " -c --configuration config-file\n"\
00207 "\n"\
00208 " -a --active\n"\
00209 "\n"\
00210 " -g --group\n"\
00211 " Prefetch articles.\n"\
00212 "\n"\
00213 " -o --over\n"\
00214 " Prefetch overview database.\n"\
00215 "\n"\
00216 " -l --lock-groups\n"\
00217 " Lock newsgroup, when prefetching.\n"\
00218 "\n"\
00219 " -w --workers\n"\
00220 " Prefetch # newsgroups at once.\n"\
00221
00222 int main(int argc, char **argv)
00223 {
00224 #ifndef WITH_SYSLOG
00225 char logfile[MAXPATHLEN];
00226 time_t t;
00227 pid_t p;
00228 #endif
00229 char conffile[MAXPATHLEN];
00230 int opt_config = 0, opt_flagsset = 0;
00231 int c, aerr = 0;
00232
00233 sprintf(conffile, "%s/newscache.conf", SYSCONFDIR);
00234
00235 cmnd = argv[0];
00236 while (1) {
00237 int option_index = 0;
00238 static struct option long_options[] = {
00239 {"version", 0, 0, 'v'},
00240 {"help", 0, 0, 'h'},
00241 {"active", 0, 0, 'a'},
00242 {"group", 0, 0, 'g'},
00243 {"over", 0, 0, 'o'},
00244 {"lock-group", 0, 0, 'l'},
00245 {"workers", 1, 0, 'w'},
00246 {"configuration", 1, 0, 'c'},
00247 {0, 0, 0, 0}
00248 };
00249
00250 c = getopt_long (argc, argv, "vhc:agolw:", long_options,
00251 &option_index);
00252
00253 if (c == -1)
00254 break;
00255
00256 switch (c) {
00257 case 'v':
00258 cout << PACKAGE << " " << VERSION << endl;
00259 exit (0);
00260 break;
00261
00262 case 'h':
00263 cout << "Usage: " << cmnd << endl;
00264 cout << USAGE << endl;
00265 exit (0);
00266 break;
00267
00268 case 'a':
00269 opt_flags |= F_PREFETCH_ACTIVE;
00270 opt_flagsset = 1;
00271 break;
00272
00273 case 'g':
00274 opt_flags |= F_PREFETCH_GROUP;
00275 opt_flagsset = 1;
00276 break;
00277
00278 case 'o':
00279 opt_flags |= F_PREFETCH_OVER;
00280 opt_flagsset = 1;
00281 break;
00282
00283 case 'l':
00284 opt_flags |= F_PREFETCH_LOCKGROUP;
00285 opt_flagsset = 1;
00286 break;
00287
00288 case 'c':
00289 strcpy (conffile, optarg);
00290 ++opt_config;
00291 break;
00292
00293 default:
00294 aerr = 1;
00295 break;
00296 }
00297
00298 }
00299 if (!opt_flagsset)
00300 opt_flags = F_PREFETCH_GROUP;
00301
00302 if (aerr || optind != argc) {
00303 cerr << "Usage: " << cmnd << " [options]\n" << USAGE;
00304 exit(1);
00305 }
00306
00307 try {
00308 Cfg.read(conffile);
00309 strcpy(nntp_hostname, Cfg.Hostname);
00310 }
00311 catch(IOError & io) {
00312 cerr << "unexpected EOF in " << conffile << "\n";
00313 exit(2);
00314 }
00315 catch(SyntaxError & se) {
00316 cerr << se._errtext << "\n";
00317 exit(2);
00318 }
00319
00320 for (unsigned int i = 0; i < Cfg.srvrs.entries.size(); i++) {
00321
00322 Cfg.srvrs.entries[i].flags &=
00323 ~(MPListEntry::F_OFFLINE | MPListEntry::F_SEMIOFFLINE);
00324
00325 Cfg.srvrs.entries[i].groupTimeout = 0;
00326 }
00327
00328
00329 Xsignal = -1;
00330 #ifdef HAVE_SIGACTION
00331 struct sigaction action;
00332
00333 action.sa_handler = catchsignal;
00334 sigemptyset(&action.sa_mask);
00335 action.sa_flags = 0;
00336 sigaction(SIGHUP, &action, NULL);
00337 sigaction(SIGINT, &action, NULL);
00338 sigaction(SIGPIPE, &action, NULL);
00339 sigaction(SIGTERM, &action, NULL);
00340
00341 sigaction(SIGALRM, &action, NULL);
00342 sigaction(SIGUSR1, &action, NULL);
00343 sigaction(SIGUSR2, &action, NULL);
00344 #else
00345 signal(SIGHUP, catchsignal);
00346 signal(SIGPIPE, catchsignal);
00347 signal(SIGINT, catchsignal);
00348 signal(SIGPIPE, catchsignal);
00349 signal(SIGTERM, catchsignal);
00350 signal(SIGALRM, catchsignal);
00351 signal(SIGUSR1, catchsignal);
00352 signal(SIGUSR2, catchsignal);
00353 #endif
00354
00355 #ifdef WITH_SYSLOG
00356 slog.open(PACKAGE, LOG_NDELAY | LOG_PID, LOG_NEWS);
00357 #else
00358 sprintf (logfile, "%s/newscache_updatenews.log", Cfg.LogDirectory);
00359 slog.open (logfile);
00360 #endif
00361
00362
00363
00364 if (getuid() == CONF_UIDROOT)
00365 setugid(Cfg.Username, Cfg.Groupname);
00366 update();
00367 return 0;
00368 }