"Fossies" - the Fresh Open Source Software Archive

Member "leafnode-1.12.0/texpire.c" (28 Dec 2021, 18738 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 "texpire.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.11.12_vs_1.12.0.

    1 /*
    2 texpire -- expire old articles
    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 Kazushi (Jam) Marukawa <jam@pobox.com>.
   17 Copyright of the modifications 1998, 1999.
   18 Modified by Matthias Andree <matthias.andree@gmx.de>.
   19 Copyright of the modifications 2000 - 2010.
   20 
   21 See file COPYING for restrictions on the use of this software.
   22 */
   23 
   24 #include "leafnode.h"
   25 #include "ln_log.h"
   26 
   27 #ifdef SOCKS
   28 #include <socks.h>
   29 #endif
   30 
   31 #include <ctype.h>
   32 #include <limits.h>
   33 #include <sys/types.h>
   34 #include <sys/stat.h>
   35 #include <fcntl.h>
   36 #include "system.h"
   37 #include <stdio.h>
   38 #include <stdlib.h>
   39 #include <string.h>
   40 #include <syslog.h>
   41 #include <unistd.h>
   42 #include <errno.h>
   43 #include <signal.h>
   44 #include "mysigact.h"
   45 #include "mastring.h"
   46 
   47 static time_t default_expire;
   48 
   49 int verbose = 0;
   50 int debug = 0;
   51 static int repair = 0;          /* run expensive checks */
   52 
   53 static int use_atime = 1;       /* look for atime on articles to expire */
   54 static int quiet = 0;           /* shut up */
   55 
   56 static int eflag;           /* set to 1 if "mids" file based expiry must not take place */
   57 
   58 static const char *const MIDSFILE = "mids";
   59 
   60 struct exp {
   61     char *xover;    /* full xover info */
   62     int kill;
   63     int exists;
   64 };
   65 
   66 static sigjmp_buf jmpbuffer;
   67 static int blocksig;
   68 
   69 static void
   70 sig_int(int signo)
   71 {
   72     if (blocksig) return;
   73     if (signo == SIGINT || signo == SIGTERM) {
   74     siglongjmp(jmpbuffer, 1);
   75     }
   76 }
   77 
   78 /* hook for traverseidtree */
   79 /* writes "mids" file for reliable expiry without counting hard links
   80  * to evade local hard link attack DoS */
   81 static int
   82 th(const char *mm) {
   83     const char *f;
   84     char *p, *t;
   85     int fd;
   86     ssize_t ml;
   87     char *m;
   88     struct stat st;
   89     /*@only@*/ static char *b;
   90     static size_t b_siz;
   91 
   92     if (mm == NULL)
   93     {
   94     b_siz = 0;
   95     free(b);
   96     return 0;
   97     }
   98 
   99     m = critstrdup(mm, "th");
  100     f = lookup(m);
  101     p = critmalloc(strlen(f) + 6, "th");
  102     strcpy(p, f);
  103     t = strrchr(p, '/');
  104     if (!t) {
  105     ln_log(LNLOG_SERR, LNLOG_CTOP, "can't find / - internal error");
  106     free(m);
  107     free(p);
  108     return 1;
  109     }
  110     strcpy(++t, MIDSFILE);
  111 
  112     fd = open(p, O_WRONLY|O_APPEND|O_CREAT, 0600);
  113     if (fd < 0) {
  114     ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot append to file %s: %m", p);
  115     free(p);
  116     free(m);
  117     return 1;
  118     }
  119     if (fstat(fd, &st)) {
  120     ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot fstat fd #%d: %m", fd);
  121     free(p);
  122     free(m);
  123     close(fd);
  124     return 1;
  125     }
  126     /* this file is not portable across endianness, why bother, we're
  127      * alone - the spool is locked */
  128 
  129     ml = strlen(m);
  130 
  131     /* resize buffer memory, generously */
  132     if (b_siz < ml + 1 + sizeof(ml)) {
  133     if (b) free(b);
  134     b_siz = ml + 128 + sizeof(ml);
  135     b = critmalloc(b_siz, "th");
  136     }
  137 
  138     /* make some effort to write the whole record (size + content)
  139      * atomically, to avoid corruption when we're interrupted */
  140     memcpy(b, &ml, sizeof(ml));
  141     for(t = m; *t; t++)
  142     if (*t == '/')
  143         *t = '@';
  144     strcpy(b + sizeof(ml), m);
  145     if (write(fd, b, ml + sizeof(ml)) < (ssize_t)(ml + sizeof(ml))) {
  146     /* short write -> rollback: truncate file to old size */
  147     ftruncate(fd, st.st_size);
  148     goto barf;
  149     }
  150     if (close(fd) < 0) goto barf;
  151     free(m);
  152     free(p);
  153     return 0;
  154 barf:
  155     ln_log(LNLOG_SERR, LNLOG_CTOP, "write error on file %s: %m", p);
  156     close(fd);
  157     free(m);
  158     free(p);
  159     return 1;
  160 }
  161 
  162 static void
  163 dogroup(/*@null@*/ struct newsgroup *g, const char *name, int expdays)
  164 {
  165     char *gdir = NULL;
  166     size_t s_gdir;
  167     char *p;
  168     char *q;
  169     DIR *d;
  170     struct dirent *de;
  171     struct stat st;
  172     unsigned long first, last, art, dupli = 0;
  173     struct exp *articles;
  174     int n;
  175     int fd;
  176     char *overview;     /* xover: read then free */
  177 
  178     int deleted, kept;
  179 
  180     deleted = kept = 0;
  181     clearidtree();
  182 
  183     /* eliminate empty groups */
  184     if (!chdirgroup(name, FALSE)) {
  185     if (g) { g->first = g->last + 1; }
  186     return;
  187     }
  188     if (!agetcwd(&gdir, &s_gdir)) {
  189     ln_log(LNLOG_SERR, LNLOG_CGROUP, "getcwd: %m");
  190     return;
  191     }
  192 
  193     /* find low-water and high-water marks */
  194 
  195     d = opendir(".");
  196     if (!d) {
  197     ln_log(LNLOG_SERR, LNLOG_CGROUP, "opendir in %s: %m", gdir);
  198     free(gdir);
  199     return;
  200     }
  201 
  202     first = ULONG_MAX;
  203     last = 0;
  204     while ((de = readdir(d)) != 0) {
  205     if (!isdigit((unsigned char)de->d_name[0]) ||
  206         stat(de->d_name, &st) || !S_ISREG(st.st_mode))
  207         continue;
  208     art = strtoul(de->d_name, &p, 10);
  209     if (p && !*p) {
  210         if (art < first)
  211         first = art;
  212         if (art > last)
  213         last = art;
  214     }
  215     }
  216     closedir(d);
  217 
  218     /* update overview info */
  219     getxover();
  220     freexover();
  221 
  222     if (last < first) {
  223     if (verbose > 1) printf("%s: empty group\n", name);
  224     if (g) g->first = g->last + 1;
  225     free(gdir);
  226     return;
  227     }
  228 
  229     if (verbose > 1)
  230     printf("%s: low water mark %lu, high water mark %lu\n",
  231            name, first, last);
  232     if (debugmode)
  233     syslog(LOG_DEBUG,
  234            "%s: expire %lu, low water mark %lu, high water mark %lu",
  235            name, (unsigned long)expdays, first, last);
  236 
  237     /* allocate and clear article array */
  238     articles = (struct exp *)critmalloc((last - first + 1) * sizeof(struct exp),
  239                     "Reading articles to expire");
  240     for (art = 0; art <= last - first; art++) {
  241     articles[art].xover = NULL;
  242     articles[art].kill = 0;
  243     articles[art].exists = 0;
  244     }
  245 
  246     /* read in overview info, to be purged and written back */
  247     overview = NULL;
  248 
  249     if (stat(".overview", &st) == 0) {
  250     overview = critmalloc(st.st_size + 1, "Reading article overview info");
  251     if ((fd = open(".overview", O_RDONLY)) < 0 ||
  252         ((off_t) read(fd, overview, st.st_size) < st.st_size)) {
  253         ln_log(LNLOG_SERR, LNLOG_CGROUP, "can't open/read %s/.overview: %m", gdir);
  254         *overview = '\0';
  255         if (fd > -1)
  256         close(fd);
  257     } else {
  258         close(fd);
  259         overview[st.st_size] = '\0';    /* 0-terminate string */
  260     }
  261 
  262     p = overview;
  263     while (p && *p) {
  264         while (p && isspace((unsigned char)*p))
  265         p++;
  266         art = strtoul(p, NULL, 10);
  267         if (art >= first && art <= last && !articles[art - first].xover) {
  268         articles[art - first].xover = p;
  269         articles[art - first].kill = 1;
  270         }
  271         p = strchr(p, '\n');
  272         if (p) {
  273         *p = '\0';
  274         if (p[-1] == '\r')
  275             p[-1] = '\0';
  276         p++;
  277         }
  278     }
  279     }
  280 
  281     /* check the syntax of the .overview info, and delete all illegal stuff */
  282     for (art = first; art <= last; art++) {
  283     const char *x;
  284 
  285     if (articles[art - first].xover &&
  286         !legalxoverline(articles[art - first].xover, &x)) {
  287         articles[art - first].xover = NULL;
  288     }
  289     }
  290 
  291     /* insert articles in tree, and clear 'kill' for new or read articles */
  292     d = opendir(".");
  293     if (!d) {
  294     ln_log(LNLOG_SERR, LNLOG_CGROUP, "opendir in %s: %m", gdir);
  295     free(gdir);
  296     free(articles);
  297     return;
  298     }
  299     while ((de = readdir(d)) != 0) {
  300     art = strtoul(de->d_name, &p, 10);
  301     if (p && !*p && art <= last && art >= first) {
  302         articles[art - first].exists = 1;
  303         /* mark all articles as to-be-deleted and rescue those
  304          * which fulfill certain criteria */
  305         articles[art - first].kill = 1;
  306         /* save file if it is a regular non-empty file
  307          * and has no expire time */
  308         if (stat(de->d_name, &st) == 0 &&
  309         (S_ISREG(st.st_mode)) &&
  310         (st.st_size != 0) &&
  311         (expdays < 0
  312          || (st.st_mtime > expdays)
  313          || (use_atime && (st.st_atime > expdays)))) {
  314         articles[art - first].kill = 0;
  315         p = articles[art - first].xover;
  316         for (n = 0; n < 4; n++)
  317             if (p && (p = strchr(p + 1, '\t')))
  318             p++;
  319         q = p ? strchr(p, '\t') : NULL;
  320         if (p && q) {
  321             *q = '\0';
  322             if (findmsgid(p)) { /* another file with same msgid? */
  323             /* kill this article and keep the first to have
  324              * that message-id */
  325             articles[art - first].kill = 1;
  326             ln_log(LNLOG_SINFO, LNLOG_CARTICLE,
  327                 "%s: removing duplicate article %lu %s",
  328                 name, art, p);
  329             dupli++;
  330             } else {
  331             int relink = 0;
  332             const char *t = lookup(p);
  333 
  334             insertmsgid(p);
  335 
  336             if (repair == 0) {
  337                 /* fast path, relink only if link is
  338                  * obviously missing (may not work for
  339                  * cross-posted articles) */
  340                 if (st.st_nlink < 2) {
  341                 relink = 1;
  342                 }
  343             } else {
  344                 /* slow path, texpire -r => repair/relink
  345                  * mode, will check if newsgroup file is
  346                  * same as message.id file linked */
  347                 struct stat st2;
  348                 if (stat(t, &st2)
  349                     || st2.st_dev != st.st_dev
  350                     || st2.st_ino != st.st_ino) {
  351                 relink = 1;
  352                 }
  353             }
  354 
  355             if (relink) {   /* repair fs damage */
  356                 if (link(de->d_name, t)
  357                 /* if EEXIST, link reverse
  358                  * rename first because it is atomic and
  359                  * guarantees the file de->d_name is
  360                  * always present. This file is precious.
  361                  * If we used unlink and link, a lone
  362                  * message.id/000 file would be deleted
  363                  * by expiremsgid()!
  364                  */
  365                 && (errno != EEXIST
  366                     || rename(t, de->d_name)
  367                     || link(de->d_name, t)))
  368                 {
  369                     ln_log(LNLOG_SERR, LNLOG_CGROUP,
  370                        "%s: relink of %s <-> %s failed: %s (%s)",
  371                        name, p, de->d_name, strerror(errno), t);
  372                 } else {
  373                 ln_log(LNLOG_SINFO, LNLOG_CARTICLE,
  374                     "%s: relinked message %s <-> %s", name, p, de->d_name);
  375                 }
  376             }
  377             *q = '\t';
  378             }
  379         } else if (articles[art - first].xover) {
  380             /* data structure inconsistency: delete and be rid of it */
  381             articles[art - first].kill = 1;
  382         } else {
  383             /* possibly read the xover line into memory? */
  384         }
  385         }
  386     }
  387     }
  388     closedir(d);
  389 
  390     /* compute new low-water mark */
  391 
  392     art = first;
  393     while (art <= last && articles[art - first].kill)
  394     art++;
  395     if (g) g->first = art;
  396 
  397     /* remove old postings */
  398 
  399     for (art = first; art <= last; art++) {
  400     char artname[40]; /* must hold a decimal long + NUL */ /* RATS: ignore */
  401     if (articles[art - first].exists) {
  402         if (articles[art - first].kill) {
  403         snprintf(artname, sizeof(artname), "%lu", art);
  404         if (0 == unlink(artname)) {
  405             if (debugmode)
  406             syslog(LOG_DEBUG, "deleted article %s/%lu", gdir, art);
  407             deleted++;
  408         } else if (errno != ENOENT && errno != EEXIST) {
  409             /* if file was deleted alredy or it was not a file */
  410             /* but a directory, skip error message */
  411             kept++;
  412             ln_log(LNLOG_SERR, LNLOG_CGROUP, "unlink %s/%lu: %m", gdir, art);
  413         } else {
  414             /* deleted by someone else */
  415         }
  416         } else {
  417         kept++;
  418         }
  419     }
  420     }
  421     free((char *)articles);
  422     if (overview)
  423     free(overview);
  424 
  425     if (g && last > g->last)        /* try to correct insane newsgroup info */
  426     g->last = last;
  427 
  428     if (!quiet)
  429     printf("%s: %d article%s deleted (%lu duplicate%s), %d kept\n",
  430         name, deleted, PLURAL(deleted), dupli, PLURAL(dupli), kept);
  431     syslog(LOG_INFO,
  432         "%s: %d article%s deleted (%lu duplicate%s), %d kept",
  433         name, deleted, PLURAL(deleted), dupli, PLURAL(dupli), kept);
  434 
  435     if (!kept) {
  436     if (unlink(".overview") < 0)
  437         ln_log(LNLOG_SERR, LNLOG_CGROUP, "unlink %s/.overview: %m", gdir);
  438     if (!chdir("..") && (isinteresting(name) == 0)) {
  439         /* delete directory and empty parent directories */
  440         while (rmdir(gdir) == 0) {
  441         if (!agetcwd(&gdir, &s_gdir)) {
  442             ln_log(LNLOG_SERR, LNLOG_CGROUP, "getcwd: %m");
  443             break;
  444         }
  445         chdir("..");
  446         }
  447     }
  448     }
  449     if (gdir)
  450     free(gdir); /* previous loop may have freed *gdir */
  451 
  452     /* write MIDSFILE */
  453     if (!eflag)
  454     eflag |= traverseidtree(th);
  455 
  456     clearidtree();
  457 }
  458 
  459 static void
  460 expiregroup(void)
  461 {
  462     struct newsgroup *g;
  463     struct stringlist *t, *l = get_grouplist();
  464     int expdays;
  465 
  466     if (!l) {
  467     ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot obtain group list\n");
  468     return;
  469     }
  470 
  471     for(t = l; t; t = t -> next) {
  472     char *x = t->string;
  473 
  474     g = findgroup(x);
  475     if ((expdays = lookup_expiredays(x)) >= 0) {
  476         if (expdays == 0 || !(expdays = lookup_expire(x)))
  477         expdays = default_expire;
  478     } else {
  479         expdays = -1;
  480         if (verbose) {
  481         printf("%s: never expires\n", x);
  482         }
  483         syslog(LOG_INFO, "%s: never expires", x);
  484     }
  485     dogroup(g, x, expdays);
  486     }
  487     freelist(l);
  488 }
  489 
  490 static void
  491 fixupgroup(/*@null@*/ struct newsgroup *g)
  492 {
  493     for (/*nil*/ ; g && g->name; g++) {
  494     if (!chdirgroup(g->name, FALSE))
  495         g->first = g->last + 1;
  496     }
  497 }
  498 
  499 static int
  500 readmids(void)
  501 {
  502     int fd;
  503     ssize_t l;
  504     ssize_t r;
  505     char *buf;
  506     ssize_t bufsiz = 128;
  507     int rc = 0;
  508 
  509     fd = open(MIDSFILE, O_RDONLY);
  510     if (fd < 0) {
  511     if (errno != ENOENT) {
  512         ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot open \"%s\" file: %m",
  513             MIDSFILE);
  514         return 1;
  515     }
  516     return 0;
  517     }
  518 
  519     /* delete file early so we don't barf again and again if the file is
  520      * corrupt */
  521     log_unlink(MIDSFILE, 0);
  522 
  523     buf = critmalloc(bufsiz, "readmids");
  524 
  525     while((r = read(fd, &l, sizeof(l))) == (ssize_t)sizeof(l)) {
  526     /* length obtained */
  527     if (l+1 > bufsiz) {
  528         free(buf);
  529         bufsiz = l + 1;
  530         buf = critmalloc(bufsiz, "readmids");
  531     }
  532     if ((r = read(fd, buf, l)) < l) {
  533         /* short read */
  534         rc = -1;
  535         break;
  536     }
  537     buf[l] = '\0';
  538     /* sanity check */
  539     if (strlen(buf) != (size_t)l) {
  540         rc = -1;
  541         break;
  542     }
  543     insertmsgid(buf);
  544     }
  545     free(buf);
  546     (void)close(fd);
  547     if (rc)
  548     ln_log(LNLOG_SERR, LNLOG_CTOP, "corrupt \"%s\" file", MIDSFILE);
  549     if (r < 0) {
  550     ln_log(LNLOG_SERR, LNLOG_CTOP, "cannot read \"%s\" file: %m", MIDSFILE);
  551     rc = -1;
  552     }
  553     return rc;
  554 }
  555 
  556 /* returns 0 for success */
  557 static int
  558 cleanmids(void)
  559 {
  560     int n, rc = 0;
  561     mastr *s = mastr_new(256);
  562 
  563     for (n = 0; n < 1000; n++) {
  564     char buf[4];
  565     snprintf(buf, sizeof(buf), "%03d", n); /* safe */
  566     mastr_clear(s);
  567     mastr_vcat(s, spooldir, "/message.id/", buf, "/", MIDSFILE, NULL);
  568     if (log_unlink(mastr_str(s), 1))
  569         rc = 1;
  570     }
  571     mastr_delete(s);
  572     return rc;
  573 }
  574 
  575 static void
  576 expiremsgid(void)
  577 {
  578     int n, s_len;
  579     DIR *d;
  580     struct dirent *de;
  581     struct stat st;
  582     int deleted, kept;
  583     const char *t;
  584     int nomids = eflag;
  585 
  586     deleted = kept = 0;
  587 
  588     if (verbose)
  589     puts("Expiring message.id...");
  590 
  591     for (n = 0; n < 1000; n++) {
  592     char s[SIZE_s+1];
  593 
  594     s_len = xsnprintf(s, SIZE_s, "%s/message.id/%03d/", spooldir, n);
  595     if (chdir(s)) {
  596         if (errno == ENOENT)
  597         mkdir(s, 0755); /* file system damage? */
  598         if (chdir(s)) {
  599         ln_log(LNLOG_SERR, LNLOG_CGROUP, "chdir %s: %m", s);
  600         continue;
  601         }
  602     }
  603 
  604     if (nomids == 0)
  605         nomids |= readmids();
  606     else
  607         unlink(MIDSFILE); /* ignore errors */
  608 
  609     d = opendir(".");
  610     if (!d)
  611         continue;
  612     while ((de = readdir(d)) != 0) {
  613         if (stat(de->d_name, &st) == 0 && S_ISREG(st.st_mode)) {
  614         int ul = 0;
  615         const char *reason = "";
  616         if (st.st_nlink < 2) ul = 1, reason = "link count below 2";
  617         if (!nomids && !findmsgid(de->d_name)) ul = 1, reason = "not seen in group scan";
  618         if (ul) {
  619             if (debugmode)
  620             ln_log(LNLOG_SDEBUG, LNLOG_CARTICLE, "unlinking %03d/%s, %s",
  621                 n, de->d_name, reason);
  622             if (0 == log_unlink(de->d_name, 1)
  623                 && de->d_name[0] == '<' /* only count MID files */)
  624             deleted++;
  625         } else {
  626             kept++;
  627             /* check hash */
  628             t = lookup(de->d_name);
  629             if (strncmp(t, s, s_len)) {
  630             /* in wrong directory, move to the right one
  631              * note however that if the right file is
  632              * already present, we'll leave it in place,
  633              * because it may have been relinked from a
  634              * group directory and we don't want to break
  635              * links again
  636              */
  637             if (link(de->d_name, t) && errno != EEXIST)
  638                 ln_log(LNLOG_SERR, LNLOG_CARTICLE,
  639                     "rehash: cannot move %s%s to %s: %m",
  640                     s, de->d_name, t);
  641             else {
  642                 char buf[4];
  643                 memcpy(buf, t + s_len - 4, 3);
  644                 buf[3] = '\0';
  645 
  646                 ln_log(LNLOG_SINFO, LNLOG_CARTICLE,
  647                     "rehashed %s from %03d to %s", de->d_name,
  648                     n, buf);
  649             }
  650             log_unlink(de->d_name, 0);
  651             }
  652         }
  653         }
  654     }
  655     closedir(d);
  656     clearidtree();
  657     }
  658 
  659     if (verbose)
  660     puts("Done.");
  661 
  662     if (!quiet)
  663     printf("message.id/: %d article%s deleted, %d kept\n", deleted, PLURAL(deleted), kept);
  664     syslog(LOG_INFO, "message.id/: %d article%s deleted, %d kept", deleted, PLURAL(deleted), kept);
  665 }
  666 
  667 
  668 int
  669 main(int argc, char **argv)
  670 {
  671     int option;
  672     int rc = 1;
  673 
  674     myopenlog("texpire");
  675     if (!initvars(argv[0]))
  676     exit(1);
  677 
  678     while ((option = getopt(argc, argv, "vfqhr")) != -1) {
  679     switch(option) {
  680         case 'v':
  681         verbose++;
  682         quiet = 0;
  683         break;
  684         case 'f':
  685         use_atime = 0;
  686         break;
  687         case 'r':
  688         repair = 1;
  689         break;
  690         case 'q':
  691         quiet = 1;
  692         verbose = 0;
  693         break;
  694         case 'h':
  695         rc = 0;
  696         /*FALLTHROUGH*/
  697         default:
  698         if (rc)
  699             fprintf(stderr, "texpire: unknown option -%c.\n", optopt);
  700         fprintf(stderr, "Usage: texpire {[-v[v[v[v]]]]|-q} [-f]\n"
  701             "  -q: be quiet (cancels -v)\n"
  702             "  -v: more verbose (cancels -q, may be repeated)\n"
  703             "  -f: force expire irrespective of access time\n");
  704         exit(rc);
  705     }
  706     }
  707 
  708     expire = 0;
  709     expire_base = NULL;
  710 
  711     if (!readconfig(0)) {
  712     fprintf(stderr, "Reading configuration failed, exiting "
  713            "(see syslog for more information).\n");
  714     exit(2);
  715     }
  716     freeservers();
  717 
  718     if (verbose || debugmode) {
  719     printf("texpire %s: verbosity level %d, debugmode %d, %s\n", version,
  720         verbose, debugmode,
  721         use_atime ? "check mtime and atime" : "check mtime only");
  722     }
  723     syslog(LOG_INFO, "texpire %s: use_atime is %d, verbosity level %d, "
  724         "debugmode %d", version, use_atime, verbose, debugmode);
  725 
  726     if (try_lock(timeout_lock)) {
  727     ln_log(LNLOG_SERR, LNLOG_CTOP, "Cannot obtain lock file, aborting.\n");
  728     exit(1);
  729     }
  730 
  731     if (cleanmids()) {
  732     ln_log(LNLOG_SERR, LNLOG_CTOP, "Cannot weed out MIDS files, aborting.\n");
  733     unlink(lockfile);
  734     exit(1);
  735     }
  736 
  737     readactive();
  738     if (!active) {
  739     ln_log(LNLOG_SWARNING, LNLOG_CTOP, "Reading active file failed. Trying to build my own.");
  740     fakeactive();
  741     }
  742 
  743     if (expire == 0) {
  744     fprintf(stderr, "%s: no expire time\n", argv[0]);
  745     unlink(lockfile);
  746     exit(2);
  747     }
  748 
  749     default_expire = expire;
  750 
  751     if (sigsetjmp(jmpbuffer, 1) == 0) {
  752     /* if we can't catch either signal, don't care,
  753      * it's just more work next time */
  754     (void)mysigact(SIGINT, 0, sig_int, 0);
  755     (void)mysigact(SIGTERM, 0, sig_int, 0);
  756     expiregroup();
  757     fixupgroup(active);
  758     expiremsgid();
  759     } else {
  760     blocksig = 1;
  761     ln_log(LNLOG_SNOTICE, LNLOG_CTOP,
  762         "caught interrupt/termination signal, aborting gracefully.");
  763     }
  764     if (writeactive())
  765     ln_log(LNLOG_SERR, LNLOG_CTOP, "error writing groupinfo.");
  766     freeactive(active);
  767     unlink(lockfile);
  768     freeservers();
  769     freexover();
  770     freeconfig();
  771     th(NULL);
  772     return 0;
  773 }