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

updatenews.cc

Go to the documentation of this file.
00001 /* updatenews.cc (c) 1996 by Thomas GSCHWIND 
00002  * -- prefetch a set of newsgroups
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 //Notes {
00048 // Config überarbeiten. Bei Syntaxfehler beenden. 
00049 // Switch ?-d? der nur Config einliest und ausgibt.
00050 //} Notes
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         /* Reinstall the signal handler */
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                 // failed
00109                 slog.
00110                     p(Logger::
00111                       Error) << "fork failed, using this process\n";
00112                 doprefetch(cs, group);
00113                 return 0;
00114         case 0:
00115                 // child
00116                 doprefetch(cs, group);
00117                 exit(0);
00118         default:
00119                 // parent
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         // read groups to prefetch
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                         // maximum workers spawned, wait until a worker exits
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                 // Switch off offline mode
00322                 Cfg.srvrs.entries[i].flags &=
00323                     ~(MPListEntry::F_OFFLINE | MPListEntry::F_SEMIOFFLINE);
00324                 // Set timeout to 0
00325                 Cfg.srvrs.entries[i].groupTimeout = 0;
00326         }
00327 
00328         // signal
00329         Xsignal = -1;
00330 #ifdef HAVE_SIGACTION
00331         struct sigaction action;
00332         // signals indicating to terminate NewsCache
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         // Check the queue in each server-directory and send it off to the 
00363         // news server
00364         if (getuid() == CONF_UIDROOT)
00365                 setugid(Cfg.Username, Cfg.Groupname);
00366         update();
00367         return 0;
00368 }

Generated on Fri Aug 20 10:58:08 2004 for NewsCache by doxygen 1.3.6-20040222