"Fossies" - the Fresh Open Source Software Archive

Member "leafnode-1.12.0/xoverutil.c" (25 Mar 2017, 16629 Bytes) of package /linux/misc/leafnode-1.12.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xoverutil.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.11.11_vs_1.11.12.

    1 /*
    2 libutil -- handling xover records
    3 
    4 Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995
    5 Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47
    6 22646949.
    7 Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>
    8 and Randolf Skerka <Randolf.Skerka@gmx.de>.
    9 Copyright of the modifications 1997.
   10 Modified by Kent Robotti <robotti@erols.com>. Copyright of the
   11 modifications 1998.
   12 Modified by Markus Enzenberger <enz@cip.physik.uni-muenchen.de>.
   13 Copyright of the modifications 1998.
   14 Modified by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
   15 Copyright of the modifications 1998, 1999.
   16 Modified by Ralf Wildenhues <ralf.wildenhues@gmx.de>
   17 Copyright of the modifications 2002.
   18 Modified by Matthias Andree <matthias.andree@gmx.de>
   19 Copyright of the modifications 2000 - 2005, 2007.
   20 
   21 See file COPYING for restrictions on the use of this software.
   22 */
   23 
   24 #include "leafnode.h"
   25 #include <fcntl.h>
   26 #include <sys/param.h>
   27 #include <sys/socket.h>
   28 #include <netinet/in.h>
   29 #include <ctype.h>
   30 #include <errno.h>
   31 #include <limits.h>
   32 #include <stdlib.h>
   33 #include <netdb.h>
   34 #include <signal.h>
   35 #include <stdio.h>
   36 #include <string.h>
   37 #include <syslog.h>
   38 #include <sys/types.h>
   39 #include <sys/stat.h>
   40 #include <unistd.h>
   41 #include "system.h"
   42 #include "strlcpy.h"
   43 #include "ln_log.h"
   44 
   45 static void
   46 tabstospaces(char *t)
   47 {
   48     while (*t) {
   49     if (*t == '\t')
   50         *t = ' ';
   51     t++;
   52     }
   53 
   54 }
   55 
   56 static /*@null@*/ /*@only@*/
   57 char *getxoverline(const char *filename, const char **e /** error message is stored here */)
   58 {
   59     char *l;
   60     const char *em;
   61     char *result;
   62     FILE *f;
   63 
   64     result = NULL;
   65     *e = NULL;
   66     debug = 0;
   67     if ((f = fopen(filename, "r"))) {
   68     char *from, *subject, *date, *msgid, *references, *lines, *xref;
   69     unsigned long bytes, linecount;
   70     char **h;
   71     int body;
   72 
   73     from = subject = date = msgid = references = xref = lines = NULL;
   74     bytes = linecount = 0;
   75     h = NULL;
   76     body = 0;
   77 
   78     while (!feof(f) && ((l = getaline(f)) != NULL)) {
   79         tabstospaces(l);
   80         linecount++;
   81         bytes += strlen(l) + 2; /* normalize CR LF -> add 2 per line */
   82         if (body || !l) {
   83         /* do nothing */
   84         } else if (!body && !*l) {
   85         linecount = 0;
   86         body = 1;
   87         } else if (*l && isspace((unsigned char)*l)) {
   88         /* cater for folded headers */
   89         if (h) {
   90             (*h) = critrealloc(*h, strlen(*h) + strlen(l) + 1,
   91                        "extending header");
   92             strcat(*h, l);  /* RATS: ignore */
   93         }
   94         } else if (!from && !strncasecmp("From:", l, 5)) {
   95         l += 5;
   96         SKIPLWS(l);
   97         if (*l) {
   98             from = critstrdup(l, "getxoverline");
   99             h = &from;
  100         }
  101         } else if (!subject && !strncasecmp("Subject:", l, 8)) {
  102         l += 8;
  103         SKIPLWS(l);
  104         if (*l) {
  105             subject = critstrdup(l, "getxoverline");
  106             h = &subject;
  107         }
  108         } else if (!date && !strncasecmp("Date:", l, 5)) {
  109         l += 5;
  110         SKIPLWS(l);
  111         if (*l) {
  112             date = critstrdup(l, "getxoverline");
  113             h = &date;
  114         }
  115         } else if (!msgid && !strncasecmp("Message-ID:", l, 11)) {
  116         l += 11;
  117         SKIPLWS(l);
  118         if (*l) {
  119             msgid = critstrdup(l, "getxoverline");
  120             h = &msgid;
  121         }
  122         } else if (!references && !strncasecmp("References:", l, 11)) {
  123         l += 11;
  124         SKIPLWS(l);
  125         if (*l) {
  126             references = critstrdup(l, "getxoverline");
  127             h = &references;
  128         }
  129         } else if (!lines && !strncasecmp("Lines:", l, 6)) {
  130         l += 6;
  131         SKIPLWS(l);
  132         if (*l) {
  133             lines = critstrdup(l, "getxoverline");
  134             h = &lines;
  135         }
  136         } else if (!xref && !strncasecmp("Xref:", l, 5)) {
  137         l += 5;
  138         SKIPLWS(l);
  139         if (*l) {
  140             xref = critstrdup(l, "getxoverline");
  141             h = &xref;
  142         }
  143         } else {
  144         h = NULL;
  145         }
  146     }
  147     if (from != NULL && date != NULL && subject != NULL &&
  148         msgid != NULL && bytes) {
  149         result = critmalloc(strlen(filename) + strlen(subject) + strlen(from) +
  150                 strlen(date) + strlen(msgid) +
  151                 (references ? strlen(references) : 0) +
  152                 100 + (xref ? strlen(xref) : 0),
  153                 "computing overview line");
  154         sprintf(result, "%s\t%s\t%s\t%s\t%s\t%s\t%lu\t%lu", /* RATS: ignore */
  155             filename, subject, from, date, msgid,
  156             references ? references : "",
  157             bytes, lines ? strtoul(lines, NULL, 10) : linecount);
  158         if (xref) {
  159         strcat(result, "\tXref: "); /* RATS: ignore */
  160         strcat(result, xref);   /* RATS: ignore */
  161         }
  162     } else {
  163         if (from == NULL)
  164         *e = "missing From: header";
  165         else if (date == NULL)
  166         *e = "missing Date: header";
  167         else if (subject == NULL)
  168         *e = "missing Subject: header";
  169         else if (msgid == NULL)
  170         *e = "missing Message-ID: header";
  171         else if (bytes == 0)
  172         *e = "article has 0 bytes";
  173     }
  174     (void)fclose(f);
  175     if (from)
  176         free(from);
  177     if (date)
  178         free(date);
  179     if (subject)
  180         free(subject);
  181     if (msgid)
  182         free(msgid);
  183     if (references)
  184         free(references);
  185     if (lines)
  186         free(lines);
  187     if (xref)
  188         free(xref);
  189     } else {
  190     ln_log(LNLOG_SERR, LNLOG_CARTICLE,
  191         "error: getxoverline: cannot open %s: %m", filename);
  192     }
  193     debug = debugmode;
  194     if (result && !legalxoverline(result, &em)) {
  195     *e = em;
  196     free(result);
  197     result = NULL;
  198     }
  199     return result;
  200 }
  201 
  202 /*
  203  * return 1 if xover is a legal overview line, 0 else
  204  */
  205 int
  206 legalxoverline(const char *xover, const char **e)
  207 {
  208     const char *p;
  209     const char *q;
  210 
  211     if (!xover)
  212     return 0;
  213 
  214     /* anything that isn't tab, printable ascii, or latin-* -> kill */
  215 
  216     p = xover;
  217     while (*p) {
  218     int c = (unsigned char)*p++;
  219 
  220     if ((c != '\t' && c < ' ') || (c > 126 && c < 160)) {
  221         *e = "non-printable characters in headers (relaxed check allows for iso-8859*)";
  222         return 0;
  223     }
  224     }
  225 
  226     p = xover;
  227     q = strchr(p, '\t');
  228     if (!q) {
  229     *e = "missing Subject: header";
  230     return 0;
  231     }
  232 
  233     /* article number */
  234 
  235     while (p != q) {
  236     if (!isdigit((unsigned char)*p)) {
  237         *e = "article number contains non-digit characters";
  238         return 0;
  239     }
  240     p++;
  241     }
  242 
  243     p = q + 1;
  244     q = strchr(p, '\t');
  245     if (!q) {
  246     *e = "missing From: header";
  247     return 0;
  248     }
  249 
  250     /* subject: no limitations */
  251 
  252     p = q + 1;
  253     q = strchr(p, '\t');
  254     if (!q) {
  255     *e = "missing Date: header";
  256     return 0;
  257     }
  258 
  259     /* from: no limitations */
  260 
  261     p = q + 1;
  262     q = strchr(p, '\t');
  263     if (!q) {
  264     *e = "missing Message-ID: header";
  265     return 0;
  266     }
  267 
  268     /* date: no limitations */
  269 
  270     p = q + 1;
  271     q = strchr(p, '\t');
  272     if (!q) {
  273     *e = "missing References: or Bytes: header";
  274     return 0;
  275     }
  276 
  277     /* message-id: <*@*> */
  278 
  279     if (*p != '<') {
  280     *e = "Message-ID: does not start with \"<\"";
  281     return 0;
  282     }
  283     while (p != q && *p != '@' && *p != '>' && *p != ' ')
  284     p++;
  285     if (*p != '@') {
  286     *e = "Message-ID: does not contain @";
  287     return 0;
  288     }
  289     while (p != q && *p != '>' && *p != ' ')
  290     p++;
  291     if (*p != '>') {
  292     *e = "Message-ID: does not end with \">\"";
  293     return 0;
  294     }
  295     if (++p != q) {
  296     *e = "Message-ID: does not end with \">\"";
  297     return 0;
  298     }
  299 
  300     p = q + 1;
  301     q = strchr(p, '\t');
  302     if (!q) {
  303     *e = "missing Bytes: header";
  304     return 0;
  305     }
  306 
  307     /* references: a series of <*@*> separated by space */
  308 
  309 #if 0
  310     while (p != q) {
  311     /* reference validation - users don't like it */
  312     if (*p != '<') {
  313         *e = "References: does not start with \"<\"";
  314         return 0;
  315     }
  316     while (p != q && *p != '@' && *p != '>' && *p != ' ')
  317         p++;
  318     if (*p != '@') {
  319         *e = "References: does not contain @";
  320         return 0;
  321     }
  322     while (p != q && *p != '>' && *p != ' ')
  323         p++;
  324     if (*p++ != '>') {
  325         *e = "References: does not end with \">\"";
  326         return 0;
  327     }
  328     while (p != q && *p == ' ')
  329         p++;
  330     }
  331 #endif
  332 
  333     p = q + 1;
  334     q = strchr(p, '\t');
  335     if (!q) {
  336     *e = "missing Lines: header";
  337     return 0;
  338     }
  339 
  340     /* byte count */
  341 
  342     while (p != q) {
  343     if (!isdigit((unsigned char)*p)) {
  344         *e = "non-digit character in Bytes: header";
  345         return 0;
  346     }
  347     p++;
  348     }
  349 
  350     p = q + 1;
  351     q = strchr(p, '\t');
  352 
  353     /* line count */
  354 
  355     while (p && *p && p != q) {
  356     if (!isdigit((unsigned char)*p)) {
  357         *e = "non-digit character in Lines: header";
  358         return 0;
  359     }
  360     p++;
  361     }
  362 
  363     if (!q) {
  364     *e = "missing Xref: entry";
  365     return 0;
  366     }
  367 
  368     {
  369     p = q + 1;
  370 
  371     /* xref */
  372     if (0 != strncasecmp(p, "Xref:", 5)) {
  373         *e = "Xref header is missing or lacks Xref: tag";
  374         return 0;
  375     }
  376     }
  377 
  378     return 1;
  379 }
  380 
  381 static void killcwd(void) {
  382     char *t = NULL;
  383     size_t s_t;
  384 
  385     if (agetcwd(&t, &s_t)) {
  386     if (chdir(spooldir)) {
  387         ln_log(LNLOG_SERR, LNLOG_CTOP, "error: cannot chdir(%s): %m", spooldir);
  388     }
  389     if (rmdir(t) && errno != ENOTEMPTY && errno != EEXIST) {
  390         ln_log(LNLOG_SERR, LNLOG_CTOP, "error: cannot rmdir(%s): %m", t);
  391     }
  392     free(t);
  393     }
  394 }
  395 
  396 void freexover(void) {
  397     unsigned long art;
  398 
  399     if (xoverinfo) {
  400     for (art = xfirst; art <= xlast; art++) {
  401         if (xoverinfo[art - xfirst].text) {
  402         free(xoverinfo[art - xfirst].text);
  403         xoverinfo[art - xfirst].text = NULL;
  404         }
  405     }
  406     free(xoverinfo);
  407     xoverinfo = NULL;
  408     }
  409 
  410 }
  411 
  412 /* utility routine to pull the xover info into memory
  413    returns 0 if there's some error, non-zero else */
  414 int
  415 getxover(void)
  416 {
  417     DIR *d;
  418     struct dirent *de;
  419     int fd;
  420     struct stat st;
  421     unsigned long art;
  422     char *overview = NULL;
  423     int error;
  424     char *p, *q;
  425     char *tt = NULL; size_t s_tt;
  426 
  427     error = 0;
  428 
  429     /* free any memory left over from last time */
  430     freexover();
  431 
  432     /* find article range */
  433     d = opendir(".");
  434     if (!d) {
  435     ln_log(LNLOG_SERR, LNLOG_CTOP, "error: opendir: %m");
  436     return 0;
  437     }
  438 
  439     xfirst = ULONG_MAX;
  440     xlast = 0;
  441     while ((de = readdir(d))) {
  442     /* weed out temporary .overview files from aborted earlier run */
  443     if (0 == strncmp(".overview.", de->d_name, 10))
  444         log_unlink(de->d_name, 0);
  445     if (!isdigit((unsigned char)de->d_name[0]))
  446         continue; /* skip files that don't start with a digit */
  447     /* WARNING: strtoul will happily return the negated value when
  448      * fed a string that starts with a minus character! */
  449     art = strtoul(de->d_name, &p, 10);
  450     if (art && p && !*p) {
  451         if (art < xfirst)
  452         xfirst = art;
  453         if (art > xlast)
  454         xlast = art;
  455     }
  456     }
  457 
  458     if (xlast < xfirst) {
  459     /* we did not find any article files (1, 17, 815 or the like) */
  460     closedir(d);
  461     (void)unlink(".overview");
  462     if (debugmode) {
  463         char *t = NULL; size_t s_t;
  464         if (!agetcwd(&t, &s_t)) {
  465         ln_log(LNLOG_SERR, LNLOG_CGROUP, "error: getcwd: %m");
  466         } else {
  467         syslog(LOG_DEBUG, "removed .overview file for %s", t);
  468         free(t);
  469         }
  470     }
  471     killcwd();
  472     return 0;
  473     }
  474 
  475     /* next, read .overview, correct it if it seems too different from
  476        what the directory implies, and write the result back */
  477     rewinddir(d);
  478 
  479     xoverinfo = (struct xoverinfo *)
  480     critmalloc(sizeof(struct xoverinfo) * (xlast + 1 - xfirst),
  481             "allocating overview array");
  482     memset(xoverinfo, 0, sizeof(struct xoverinfo) * (xlast + 1 - xfirst));
  483 
  484     if ((fd = open(".overview", O_RDONLY)) >= 0 &&
  485         fstat(fd, &st) == 0) {
  486     overview = (char *)critmalloc(st.st_size + 1, "getxover");
  487     if ((off_t) read(fd, overview, st.st_size) != st.st_size) {
  488         int e = errno;
  489         char *t = NULL; size_t s_t;
  490         /* short read */
  491         close(fd);
  492 
  493         if (!agetcwd(&t, &s_t)) {
  494         ln_log(LNLOG_SERR, LNLOG_CGROUP, "error: getcwd: %m");
  495         } else {
  496         ln_log(LNLOG_SWARNING, LNLOG_CGROUP,
  497             "warning: short read on %s/.overview: %s",
  498             t, strerror(e));
  499         free(t);
  500         }
  501     } else {
  502         close(fd);
  503         overview[st.st_size] = '\0';
  504 
  505         /* okay, we have the content, so let's parse it roughly */
  506         /* iterate line-wise */
  507         p = overview;
  508         while (p && *p) {
  509         const char *t;
  510 
  511         while (p && isspace((unsigned char)*p))
  512             p++;
  513         q = strchr(p, '\n');
  514         if (q)
  515             *q++ = '\0';
  516 
  517         
  518         art = strtoul(p, NULL, 10);
  519         if (legalxoverline(p, &t)) {
  520             if (art > xlast || art < xfirst) {
  521             error++;
  522             } else if (xoverinfo[art - xfirst].text) {
  523             char *tt = NULL; size_t s_tt;
  524             error++;
  525             if (!agetcwd(&tt, &s_tt)) {
  526                 ln_log(LNLOG_SERR, LNLOG_CARTICLE, "error: getcwd: %m");
  527             } else {
  528                 ln_log(LNLOG_SERR, LNLOG_CARTICLE, "error: multiple lines for article %lu "
  529                     "in .overview for %s", art, tt);
  530                 free(tt);
  531             }
  532             free (xoverinfo[art - xfirst].text);
  533             xoverinfo[art - xfirst].text = NULL;
  534             xoverinfo[art - xfirst].exists = -1;
  535             } else if (xoverinfo[art - xfirst].exists == 0) {
  536             xoverinfo[art - xfirst].text = critstrdup(p, "getxover");
  537             }
  538         } else {
  539             char *tt = NULL; size_t s_tt;
  540             if (!agetcwd(&tt, &s_tt)) {
  541             ln_log(LNLOG_SERR, LNLOG_CTOP, "error: getcwd: %m");
  542             } else {
  543             ln_log(LNLOG_SNOTICE, LNLOG_CARTICLE, "illegal line for article %lu in .overview for %s: %s", art, tt, t);
  544             free(tt);
  545             }
  546         }
  547 
  548         p = q;
  549         } /* while p && *p */
  550     } /* if read went fine */
  551     } /* if open && fstat */
  552 
  553     if (!agetcwd(&tt, &s_tt)) {
  554     ln_log(LNLOG_SERR, LNLOG_CTOP, "error: getcwd: %m");
  555     closedir(d);
  556     return 0;
  557     }
  558 
  559     /* so, what was missing? */
  560     while ((de = readdir(d))) {
  561     if (de->d_name[0] == '.')
  562         continue;
  563     art = strtoul(de->d_name, &p, 10);
  564     if (p && !*p && art >= xfirst && art <= xlast) {
  565         if (!xoverinfo[art - xfirst].text) {
  566         const char *e;
  567 
  568         xoverinfo[art - xfirst].exists = 0;
  569         if (debugmode) {
  570             syslog(LOG_DEBUG, "reading XOVER info from %s/%s",
  571                 tt, de->d_name);
  572         }
  573         error++;
  574         if ((xoverinfo[art - xfirst].text =
  575              getxoverline(de->d_name, &e)) == NULL) {
  576             ln_log(LNLOG_SINFO, LNLOG_CARTICLE,
  577                "article %s/%s contained illegal headers: %s",
  578                tt, de->d_name, e);
  579             if (truncate(de->d_name, (off_t)0))
  580             ln_log(LNLOG_SWARNING, LNLOG_CARTICLE,
  581                 "warning: failed to truncate broken %s/%s to 0 size: %m",
  582                 tt,de->d_name);
  583             if ((lstat(de->d_name, &st) == 0) && S_ISREG(st.st_mode)) {
  584             if (unlink(de->d_name))
  585                 ln_log(LNLOG_SWARNING, LNLOG_CARTICLE,
  586                     "warning: failed to remove broken %s/%s: %m", tt, de->d_name);
  587             } else {
  588             ln_log(LNLOG_SWARNING, LNLOG_CARTICLE, 
  589                 "warning: %s/%s is not a regular file", tt, de->d_name);
  590             }
  591         }
  592         }
  593     }
  594 
  595     if (art >= xfirst && art <= xlast && xoverinfo[art - xfirst].text) {
  596         xoverinfo[art - xfirst].exists = 1;
  597     } else {
  598         /* kill non-article files, like "core" */
  599         if (art == 0)
  600         {
  601         if (unlink(de->d_name)
  602             && errno != EISDIR
  603             && errno != EPERM
  604             && verbose) {
  605             ln_log(LNLOG_SWARNING, LNLOG_CGROUP,
  606                 "warning: deleting junk %s/%s failed: %s",
  607                tt, de->d_name, strerror(errno));
  608         }
  609         }
  610     }
  611     } /* while (de = readdir(d)) */
  612 
  613     /* count removed articles */
  614     for (art = xfirst; art <= xlast; art++) {
  615     if (xoverinfo[art - xfirst].text
  616         && !xoverinfo[art - xfirst].exists) {
  617         ++error;
  618         free(xoverinfo[art - xfirst].text);
  619         xoverinfo[art - xfirst].text = NULL;
  620     }
  621     }
  622 
  623     /* if something had to be fixed, write a better file to disk for
  624        next time - race conditions here, but none dangerous */
  625     if (error) {
  626     int wfd;
  627     char newfile[20]; /* RATS: ignore */
  628 
  629     if (debugmode)
  630         syslog(LOG_DEBUG, "updated %d line%s in %s/.overview",
  631            error, PLURAL(error), tt);
  632 
  633     strcpy(newfile, ".overview.XXXXXX");
  634     if ((wfd = mkstemp(newfile)) != -1) {
  635         int va;
  636 
  637         va = 1;
  638         for (art = xfirst; art <= xlast; art++) {
  639         if (xoverinfo[art - xfirst].exists
  640             && xoverinfo[art - xfirst].text) {
  641             if (writes(wfd, xoverinfo[art - xfirst].text) == - 1
  642             || writes(wfd, "\n") == -1) 
  643             {
  644             ln_log(LNLOG_SERR, LNLOG_CGROUP,
  645                    "error: write() for .overview failed: %m");
  646             va = 0;
  647             break;
  648             }
  649         }
  650         }
  651         if (fchmod(wfd, 0664)) va = 0;
  652         if (fsync(wfd)) va = 0;
  653         if (close(wfd)) va = 0;
  654         if (va) {
  655         if (rename(newfile, ".overview")) {
  656             if (unlink(newfile))
  657             ln_log(LNLOG_SERR, LNLOG_CGROUP,
  658                    "error: unlink(%s) failed: %m", newfile);
  659             else
  660             ln_log(LNLOG_SERR, LNLOG_CGROUP,
  661                    "error: rename(%s/%s, .overview) failed: %m",
  662                    tt, newfile);
  663         } else {
  664             if (debugmode)
  665             syslog(LOG_DEBUG, "wrote %s/.overview", tt);
  666         }
  667         } else {
  668         unlink(newfile);
  669         /* the group must be newly empty: I want to keep the old
  670            .overview file I think */
  671         }
  672     } else {
  673         ln_log(LNLOG_SERR, LNLOG_CGROUP,
  674             "error: mkstemp of new .overview failed: %m");
  675     }
  676     }
  677 
  678     closedir(d);
  679     free(tt);
  680     if (overview) {
  681     free(overview);
  682     }
  683     return 1;
  684 }
  685 
  686 void
  687 fixxover(void)
  688 {
  689     DIR *d;
  690     struct dirent *de;
  691     char s[SIZE_s + 1];
  692 
  693     xsnprintf(s, SIZE_s, "%s/interesting.groups", spooldir);
  694     d = opendir(s);
  695     if (!d) {
  696     ln_log(LNLOG_SERR, LNLOG_CGROUP, "error: opendir %s: %m", s);
  697     return;
  698     }
  699 
  700     while ((de = readdir(d))) {
  701     if (isalnum((unsigned char)*(de->d_name)) && findgroup(de->d_name)) {
  702         if (chdirgroup(de->d_name, FALSE))
  703         getxover();
  704         freexover();
  705     }
  706     }
  707     closedir(d);
  708 }