|
|
1.1 ! root 1: /* ! 2: * This software is Copyright (c) 1986 by Rick Adams. ! 3: * ! 4: * Permission is hereby granted to copy, reproduce, redistribute or ! 5: * otherwise use this software as long as: there is no monetary ! 6: * profit gained specifically from the use or reproduction or this ! 7: * software, it is not sold, rented, traded or otherwise marketed, and ! 8: * this copyright notice is included prominently in any copy ! 9: * made. ! 10: * ! 11: * The author make no claims as to the fitness or correctness of ! 12: * this software for any use whatsoever, and it is provided as is. ! 13: * Any use of this software is at the user's own risk. ! 14: * ! 15: * expire - expire daemon runs around and nails all articles that ! 16: * have expired. ! 17: */ ! 18: ! 19: #ifdef SCCSID ! 20: static char *SccsId = "@(#)expire.c 2.55 10/15/87"; ! 21: #endif /* SCCSID */ ! 22: ! 23: #include "params.h" ! 24: #include <errno.h> ! 25: ! 26: #ifdef BSD4_2 ! 27: # include <sys/file.h> ! 28: #endif /* BSD4_2 */ ! 29: ! 30: #ifdef LOCKF ! 31: #include <unistd.h> ! 32: #endif /* LOCKF */ ! 33: ! 34: char *Progname = "expire"; /* used by xerror to identify failing program */ ! 35: ! 36: /* Number of array entries to allocate at a time. */ ! 37: #define SPACE_INCREMENT 1000 ! 38: ! 39: struct expdata { ! 40: char *e_name; ! 41: long e_min, e_max; ! 42: time_t e_droptime, e_expiretime; ! 43: char e_ignorexp; ! 44: char e_doarchive; ! 45: char e_doexpire; ! 46: }; ! 47: ! 48: extern int errno; ! 49: char NARTFILE[BUFLEN], OARTFILE[BUFLEN]; ! 50: char PAGFILE[BUFLEN], DIRFILE[BUFLEN]; ! 51: char NACTIVE[BUFLEN], OACTIVE[BUFLEN]; ! 52: char recdate[BUFLEN]; ! 53: long rectime, exptime; ! 54: extern char *OLDNEWS; ! 55: int verbose = 0; /* output trace information */ ! 56: int ignorexp = 0; /* ignore Expire: lines */ ! 57: int doarchive = 0; /* archive articles in SPOOL/oldnews */ ! 58: int nohistory = 0; /* ignore history file */ ! 59: int dorebuild = 0; /* rebuild history file */ ! 60: int dorbldhistory = 0; /* rebuild history.d directory */ ! 61: int usepost = 0; /* use posting date to expire */ ! 62: int frflag = 0; /* expire specific user */ ! 63: int doupdateactive = 0; /* update ACTIVE file */ ! 64: char baduser[BUFLEN]; ! 65: extern char filename[], nbuf[]; ! 66: ! 67: struct timeb Now; ! 68: ! 69: /* ! 70: * This code uses realloc to get more of the multhist array. ! 71: */ ! 72: struct multhist { ! 73: char *mh_ident; ! 74: char *mh_file; ! 75: } *multhist; ! 76: unsigned int mh_size; ! 77: extern char *calloc(), *realloc(); ! 78: struct tm *gmtime(); ! 79: ! 80: #ifndef DBM ! 81: FILE *nexthistfile(); ! 82: #endif /* !DBM */ ! 83: ! 84: long expincr; ! 85: long dropincr; ! 86: long atol(); ! 87: time_t cgtdate(), time(); ! 88: FILE *popen(); ! 89: struct passwd *pw; ! 90: struct group *gp; ! 91: char arpat[LBUFLEN]; ! 92: int arpatlen = 0; ! 93: char ngpat[LBUFLEN]; ! 94: int ngpatlen = 0; ! 95: char afline[BUFLEN]; ! 96: char grpsleft[BUFLEN]; ! 97: struct hbuf h; ! 98: int rmlock(); ! 99: time_t today; ! 100: ! 101: main(argc, argv) ! 102: int argc; ! 103: char **argv; ! 104: { ! 105: pathinit(); ! 106: (void) umask(N_UMASK); ! 107: username = NEWSUSR; ! 108: ! 109: /* ! 110: * Try to run as NEWSUSR/NEWSGRP ! 111: */ ! 112: if ((pw = getpwnam(NEWSUSR)) == NULL) ! 113: xerror("Cannot get NEWSUSR pw entry"); ! 114: ! 115: uid = pw->pw_uid; ! 116: if ((gp = getgrnam(NEWSGRP)) == NULL) ! 117: xerror("Cannot get NEWSGRP gr entry"); ! 118: gid = gp->gr_gid; ! 119: (void) setgid(gid); ! 120: (void) setuid(uid); ! 121: ! 122: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) ! 123: signal(SIGHUP, rmlock); ! 124: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 125: signal(SIGINT, rmlock); ! 126: expincr = DFLTEXP; ! 127: dropincr = HISTEXP; ! 128: ngpat[0] = ','; ! 129: arpat[0] = ','; ! 130: while (argc > 1) { ! 131: switch (argv[1][1]) { ! 132: case 'v': ! 133: if (isdigit(argv[1][2])) ! 134: verbose = argv[1][2] - '0'; ! 135: else if (argc > 2 && argv[2][0] != '-') { ! 136: ! 137: argv++; ! 138: argc--; ! 139: verbose = atoi(argv[1]); ! 140: } else ! 141: verbose = 1; ! 142: if (verbose < 3) ! 143: setbuf(stdout, (char *)NULL); ! 144: break; ! 145: case 'e': /* Use this as default expiration time */ ! 146: if (argc > 2 && argv[2][0] != '-') { ! 147: argv++; ! 148: argc--; ! 149: expincr = atol(argv[1]) * DAYS; ! 150: } else if (isdigit(argv[1][2])) ! 151: expincr = atol(&argv[1][2]) * DAYS; ! 152: break; ! 153: case 'E': /* Use this as default forget time */ ! 154: if (argc > 2 && argv[2][0] != '-') { ! 155: argv++; ! 156: argc--; ! 157: dropincr = atol(argv[1]) * DAYS; ! 158: } else if (isdigit(argv[1][2])) ! 159: dropincr = atol(&argv[1][2]) * DAYS; ! 160: break; ! 161: case 'I': /* Ignore any existing expiration date */ ! 162: ignorexp = 2; ! 163: break; ! 164: case 'i': /* Ignore any existing expiration date */ ! 165: ignorexp = 1; ! 166: break; ! 167: case 'n': ! 168: if (argc > 2) { ! 169: argv++; ! 170: argc--; ! 171: while (argc > 1 && argv[1][0] != '-') { ! 172: int argvlen; ! 173: argvlen = strlen(argv[1]); ! 174: if (ngpatlen + argvlen + 2 > sizeof (ngpat)) { ! 175: xerror("Too many groups specified for -n\n"); ! 176: } ! 177: if (ngpat[ngpatlen] == '\0') { ! 178: ngpat[ngpatlen++] = ','; ! 179: ngpat[ngpatlen] = '\0'; ! 180: } ! 181: strcpy(&ngpat[ngpatlen], argv[1]); ! 182: ngpatlen += argvlen; ! 183: argv++; ! 184: argc--; ! 185: } ! 186: argv--; ! 187: argc++; ! 188: } ! 189: break; ! 190: case 'a': /* archive expired articles */ ! 191: if (access(OLDNEWS,0) < 0){ ! 192: perror(OLDNEWS); ! 193: xerror("No archiving possible\n"); ! 194: } ! 195: doarchive++; ! 196: if (argc > 2) { ! 197: argv++; ! 198: argc--; ! 199: while (argc > 1 && argv[1][0] != '-') { ! 200: int argvlen; ! 201: argvlen = strlen(argv[1]); ! 202: if (arpatlen + argvlen + 2 > sizeof (arpat)) { ! 203: xerror("Too many groups specified for -a\n"); ! 204: } ! 205: if (arpat[arpatlen] == '\0') { ! 206: arpat[arpatlen++] = ','; ! 207: arpat[arpatlen] = '\0'; ! 208: } ! 209: strcpy(&arpat[arpatlen], argv[1]); ! 210: arpatlen += argvlen; ! 211: argv++; ! 212: argc--; ! 213: } ! 214: argv--; ! 215: argc++; ! 216: } ! 217: break; ! 218: case 'h': /* ignore history */ ! 219: nohistory++; ! 220: break; ! 221: case 'r': /* rebuild history file */ ! 222: dorebuild++; ! 223: nohistory++; ! 224: break; ! 225: case 'R': /* just rebuild the dbm files */ ! 226: #ifdef DBM ! 227: rebuilddbm(); ! 228: xxit(0); ! 229: #else /* !DBM */ ! 230: fprintf(stderr, "You have not compiled expire with DBM, so -R is meaningless\n"); ! 231: xxit(1); ! 232: #endif /* !DBM */ ! 233: ! 234: case 'p': /* use posting date to expire */ ! 235: usepost++; ! 236: break; ! 237: case 'f': /* expire messages from baduser */ ! 238: frflag++; ! 239: if (argc > 2) { ! 240: strcpy(baduser, argv[2]); ! 241: argv++; ! 242: argc--; ! 243: } ! 244: break; ! 245: case 'u': /* update the active file from 2.10.1 fmt */ ! 246: doupdateactive++; ! 247: break; ! 248: case 'H': /* convert to history.d format */ ! 249: dorbldhistory++; ! 250: break; ! 251: default: ! 252: printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-a] [-r] [-h] [-p] [-u] [-f username] [-n newsgroups] [-H]\n"); ! 253: xxit(1); ! 254: } ! 255: argc--; ! 256: argv++; ! 257: } ! 258: if (dorbldhistory) { ! 259: #ifndef DBM ! 260: rebuildhistorydir(); ! 261: #endif /* !DBM */ ! 262: exit(0); ! 263: } ! 264: if (dropincr < expincr) { ! 265: dropincr = HISTEXP; ! 266: fprintf(stderr, "History expiration time < article expiration time. Default used.\n"); ! 267: } ! 268: if (ngpat[0] == ',') ! 269: (void) strcpy(ngpat, "all,"); ! 270: if (arpat[0] == ',') ! 271: (void) strcpy(arpat, "all,"); ! 272: (void) ftime(&Now); ! 273: today = Now.time; ! 274: if (chdir(SPOOL)) ! 275: xerror("Cannot chdir %s", SPOOL); ! 276: ! 277: if (verbose) { ! 278: printf("expire: nohistory %d, rebuild %d, doarchive %d\n", ! 279: nohistory, dorebuild, doarchive); ! 280: printf("newsgroups: %s\n",ngpat); ! 281: if (doarchive) ! 282: printf("archiving: %s\n",arpat); ! 283: } ! 284: ! 285: #ifdef DBM ! 286: (void) sprintf(OARTFILE, "%s/%s", LIB, "ohistory"); ! 287: #endif /* DBM */ ! 288: (void) sprintf(NARTFILE, "%s/%s", LIB, "nhistory"); ! 289: ! 290: (void) sprintf(OACTIVE, "%s/%s", LIB, "oactive"); ! 291: (void) sprintf(NACTIVE, "%s/%s", LIB, "nactive"); ! 292: ! 293: if (!doupdateactive) { ! 294: expire(); ! 295: #ifndef DBM ! 296: rebuildhistorydir(); ! 297: #endif ! 298: } ! 299: ! 300: updateactive(); ! 301: rmlock(); ! 302: ! 303: /* ! 304: * Now read in any saved news. ! 305: */ ! 306: #ifdef PROFILING ! 307: monitor((int(*)())0,(int(*)())0,0,0,0); ! 308: #endif /* PROFILING */ ! 309: #ifdef LOGDIR ! 310: /*afline happens to be available - (we're getting out anyway)*/ ! 311: sprintf(afline, "%s/%s", logdir(HOME), RNEWS); ! 312: execl(afline, "rnews", "-U", (char *)NULL); ! 313: #else /* ! LOGDIR */ ! 314: execl(RNEWS, "rnews", "-U", (char *)NULL); ! 315: #endif /* ! LOGDIR */ ! 316: perror(RNEWS); ! 317: xxit(1); ! 318: /* NOTREACHED */ ! 319: } ! 320: ! 321: expire() ! 322: { ! 323: register char *p1, *p2, *p3; ! 324: register time_t newtime; ! 325: register FILE *fp = NULL; ! 326: FILE *ohfd, *nhfd; ! 327: int i; ! 328: char fn[BUFLEN]; ! 329: DIR *ngdirp = NULL; ! 330: static struct direct *ngdir; ! 331: ! 332: #ifdef DBM ! 333: if (!dorebuild) { ! 334: (void) sprintf(PAGFILE, "%s/%s", LIB, "nhistory.pag"); ! 335: (void) sprintf(DIRFILE, "%s/%s", LIB, "nhistory.dir"); ! 336: (void) close(creat(PAGFILE, 0666)); ! 337: (void) close(creat(DIRFILE, 0666)); ! 338: initdbm(NARTFILE); ! 339: } ! 340: #endif ! 341: ! 342: if (nohistory) { ! 343: ohfd = xfopen(ACTIVE, "r"); ! 344: if (dorebuild) { ! 345: /* Allocate initial space for multiple newsgroup (for ! 346: an article) array */ ! 347: multhist = (struct multhist *)calloc (SPACE_INCREMENT, ! 348: sizeof (struct multhist)); ! 349: mh_size = SPACE_INCREMENT; ! 350: ! 351: (void) sprintf(afline, "exec sort -t\t +1.6 -2 +1 >%s", ! 352: #ifdef DBM ! 353: NARTFILE); ! 354: #else /* !DBM */ ! 355: ARTFILE); ! 356: #endif /* !DBM */ ! 357: if ((nhfd = popen(afline, "w")) == NULL) ! 358: xerror("Cannot exec %s", afline); ! 359: } else ! 360: nhfd = xfopen("/dev/null", "w"); ! 361: } else { ! 362: #ifdef DBM ! 363: ohfd = xfopen(ARTFILE, "r"); ! 364: #else ! 365: ohfd = nexthistfile((FILE *)NULL); ! 366: #endif /* DBM */ ! 367: nhfd = xfopen(NARTFILE, "w"); ! 368: } ! 369: ! 370: dolock(); ! 371: ! 372: for(i=0;i<NUNREC;i++) ! 373: h.unrec[i] = NULL; ! 374: ! 375: while (TRUE) { ! 376: fp = NULL; ! 377: if (nohistory) { ! 378: recdate[0] = '\0'; ! 379: do { ! 380: if (ngdir == NULL) { ! 381: if ( ngdirp != NULL ) ! 382: closedir(ngdirp); ! 383: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 384: goto out; ! 385: (void) strcpy(nbuf, afline); ! 386: p1 = index(nbuf, ' '); ! 387: if (p1 == NULL) ! 388: p1 = index(nbuf, '\n'); ! 389: if (p1 != NULL) ! 390: *p1 = '\0'; ! 391: if (!ngmatch(nbuf, ngpat)) ! 392: continue; ! 393: ! 394: /* Change a group name from ! 395: a.b.c to a/b/c */ ! 396: for (p1=nbuf; *p1; p1++) ! 397: if (*p1 == '.') ! 398: *p1 = '/'; ! 399: ! 400: if ((ngdirp = opendir(nbuf)) == NULL) ! 401: continue; ! 402: ! 403: } ! 404: ngdir = readdir(ngdirp); ! 405: /* Continue looking if not an article. */ ! 406: } while (ngdir == NULL || !islegal(fn,nbuf,ngdir->d_name)); ! 407: ! 408: p2 = fn; ! 409: if (verbose > 2) ! 410: printf("article: %s\n", fn); ! 411: strcpy(filename, dirname(fn)); ! 412: fp = access(filename, 04) ? NULL : art_open(filename, "r"); ! 413: } else { ! 414: char dc; ! 415: #ifdef DBM ! 416: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 417: break; ! 418: #else ! 419: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 420: if (!(ohfd = nexthistfile(ohfd))) ! 421: break; ! 422: else ! 423: continue; ! 424: #endif /* DBM */ ! 425: if (verbose > 2) ! 426: printf("article: %s", afline); ! 427: p1 = index(afline, '\t'); ! 428: if (!p1) ! 429: continue; ! 430: *p1 = '\0'; ! 431: (void) strcpy(h.ident, afline); ! 432: *p1 = '\t'; ! 433: p2 = index(p1 + 1, '\t'); ! 434: if (!p2) ! 435: continue; ! 436: *p2 = '\0'; ! 437: (void) strcpy(recdate, p1+1); ! 438: (void) strcat(recdate, " GMT"); ! 439: rectime = cgtdate(recdate); ! 440: *p2++ = '\t'; ! 441: (void) strcpy(nbuf, p2); ! 442: p3 = index(nbuf, '/'); ! 443: if (p3) { ! 444: register char *p4; ! 445: ! 446: p4 = index(p3, '\n'); ! 447: if (p4) { ! 448: while (p4[-1] == ' ') ! 449: p4--; ! 450: *p4 = '\0'; ! 451: } ! 452: ! 453: /* ! 454: * convert list of newsgroups from ! 455: * ng1/num ng2/num ... ! 456: * to ! 457: * ng1,ng2,... ! 458: */ ! 459: p4 = p3; ! 460: do { ! 461: *p3++ = NGDELIM; ! 462: while (*p4 != '\0' && *p4 != ' ') ! 463: p4++; ! 464: if (*p4++ == '\0') { ! 465: *--p3 = '\0'; ! 466: break; ! 467: } ! 468: while (*p3 = *p4++) { ! 469: if (*p3 == '/') ! 470: break; ! 471: else ! 472: p3++; ! 473: } ! 474: } while (*p3); ! 475: } else { ! 476: /* ! 477: * Nothing after the 2nd tab. This happens ! 478: * when there is no message left in the spool ! 479: * directory, only the memory of it in the ! 480: * history file. (That is, it got cancelled ! 481: * or expired.) Use date in the history file ! 482: * to decide if we should keep the memory. ! 483: */ ! 484: grpsleft[0] = '\0'; ! 485: goto checkdate; ! 486: } ! 487: if (!ngmatch(nbuf, ngpat) || ! 488: ((rectime+expincr > today) && !dorebuild && ! 489: !frflag && !usepost && recdate[0] != ' ')) ! 490: goto keephist; ! 491: if (!dorebuild && !frflag && !usepost && ! 492: recdate[0] != ' ') { ! 493: grpsleft[0] = '\0'; ! 494: goto nailit; /* just expire it */ ! 495: } ! 496: ! 497: /* ! 498: * Look for the file--possibly several times, ! 499: * if it was posted to several news groups. ! 500: */ ! 501: dc = ' '; ! 502: p3 = p2; ! 503: while (dc != '\n') { ! 504: p1 = index(p3, ' '); ! 505: if (p1) { ! 506: dc = ' '; ! 507: *p1 = '\0'; ! 508: } else { ! 509: p1 = index(p3, '\n'); ! 510: if (p1 && p1 > p3) { ! 511: dc = '\n'; ! 512: *p1 = '\0'; ! 513: } else { ! 514: fp = NULL; ! 515: break; ! 516: } ! 517: } ! 518: strcpy(filename, dirname(p3)); ! 519: if (access(filename, 4) == 0 && ! 520: ((fp=art_open(filename, "r")) != NULL)) ! 521: break; ! 522: p3 = p1 + 1; ! 523: } ! 524: if (p1) ! 525: *p1 = dc; ! 526: } ! 527: ! 528: if (fp == NULL) { ! 529: /* ! 530: * this probably means that the article has been ! 531: * cancelled. Lets assume that, and make an ! 532: * entry in the history file to that effect. ! 533: */ ! 534: if (verbose) ! 535: perror(filename); ! 536: strcpy(p2, "cancelled\n"); ! 537: grpsleft[0] = '\0'; ! 538: goto checkdate; ! 539: } ! 540: for(i=0; i<NUNREC; i++) ! 541: if (h.unrec[i] != NULL) { ! 542: free(h.unrec[i]); ! 543: h.unrec[i] = NULL; ! 544: } else ! 545: break; ! 546: if (!hread(&h, fp, TRUE)) { ! 547: printf("Garbled article %s.\n", filename); ! 548: (void) fclose(fp); ! 549: /* ! 550: * Usually means disk ran out of space. ! 551: * Drop this article from our history file ! 552: * completely, so we have a chance of picking ! 553: * it up again from another feed .. ! 554: */ ! 555: goto nailit; ! 556: } ! 557: if (nohistory) { ! 558: if (recdate[0] == '\0') { ! 559: struct stat statb; ! 560: if (fstat(fileno(fp), &statb) < 0) ! 561: rectime = cgtdate(h.subdate); ! 562: else ! 563: rectime = statb.st_mtime; ! 564: } else ! 565: rectime = cgtdate(recdate); ! 566: } ! 567: if (dorebuild) { ! 568: register char *cp, *lastslash; ! 569: register struct multhist *mhp; ! 570: ! 571: /* ! 572: * Format of filename until now was /SPOOL/a/b/c/4 ! 573: * and this code changes it to a.b.c/4 (the correct ! 574: * kind of entry in the history file.) ! 575: * ! 576: * This cannot be a strcpy because the addresses ! 577: * overlap and some machines cannot handle that. ! 578: */ ! 579: p1 = filename; ! 580: cp = p1 + strlen(SPOOL); ! 581: while (*++cp) { ! 582: if (*cp == '/') { ! 583: lastslash = p1; ! 584: *p1++ = '.'; ! 585: } else ! 586: *p1++ = *cp; ! 587: } ! 588: *p1 = '\0'; ! 589: *lastslash = '/'; ! 590: ! 591: if ((cp = index(h.nbuf, NGDELIM)) == NULL) { ! 592: struct tm *tm; ! 593: saveit: ! 594: tm = gmtime(&rectime); ! 595: if (fprintf(nhfd, ! 596: #ifdef USG ! 597: "%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", ! 598: #else /* !USG */ ! 599: "%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", ! 600: #endif /* !USG */ ! 601: h.ident, h.expdate[0] ? " " : "", ! 602: tm->tm_mon+1, tm->tm_mday, tm->tm_year, ! 603: tm->tm_hour, tm->tm_min, filename) ! 604: == EOF) ! 605: xerror("History write failed"); ! 606: (void) fclose(fp); ! 607: continue; ! 608: } ! 609: for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) { ! 610: if (mhp->mh_file == NULL) ! 611: continue; ! 612: if (strcmp(mhp->mh_ident, h.ident)) ! 613: continue; ! 614: (void) strcat(filename, " "); ! 615: (void) strcat(filename, mhp->mh_file); ! 616: free(mhp->mh_file); ! 617: mhp->mh_file = NULL; ! 618: /* ! 619: * if we have all the links, write to hist now ! 620: */ ! 621: if (chrcnt(filename, ' ') == chrcnt(cp,NGDELIM)) ! 622: goto saveit; ! 623: break; ! 624: } ! 625: ! 626: /* ! 627: * Here is where we realloc the multhist space rather ! 628: * than the old way of static allocation. It is ! 629: * really trivial. We just clear out the space ! 630: * in case it was reused. The old static array was ! 631: * guaranteed to be cleared since it was cleared when ! 632: * the process started. ! 633: */ ! 634: if (mhp >= multhist + mh_size) { ! 635: multhist = (struct multhist *) ! 636: realloc ((char *)multhist, ! 637: sizeof (struct multhist) * ! 638: (SPACE_INCREMENT + mh_size)); ! 639: if (multhist == NULL) ! 640: xerror("Too many articles with multiple newsgroups"); ! 641: for (mhp = multhist + mh_size; ! 642: mhp < multhist+mh_size+SPACE_INCREMENT; ! 643: mhp++) { ! 644: mhp->mh_ident = NULL; ! 645: mhp->mh_file = NULL; ! 646: } ! 647: mhp = multhist + mh_size; ! 648: mh_size += SPACE_INCREMENT; ! 649: } ! 650: ! 651: if (mhp->mh_ident == NULL) { ! 652: mhp->mh_ident = malloc(strlen(h.ident)+1); ! 653: (void) strcpy(mhp->mh_ident, h.ident); ! 654: } ! 655: cp = malloc(strlen(filename) + 1); ! 656: if (cp == NULL) ! 657: xerror("Out of memory"); ! 658: (void) strcpy(cp, filename); ! 659: mhp->mh_file = cp; ! 660: (void) fclose(fp); ! 661: continue; ! 662: } ! 663: ! 664: (void) fclose(fp); ! 665: ! 666: if (h.expdate[0]) { ! 667: Now.time = rectime; ! 668: exptime = cgtdate(h.expdate); ! 669: } ! 670: newtime = (usepost ? cgtdate(h.subdate) : rectime) + expincr; ! 671: if (!h.expdate[0] || ignorexp == 2 || ! 672: (ignorexp == 1 && newtime < exptime)) ! 673: exptime = newtime; ! 674: if (frflag ? strcmp(baduser,h.from)==0 : today >= exptime) { ! 675: nailit: ! 676: #ifdef DEBUG ! 677: printf("cancel %s\n", filename); ! 678: #else /* !DEBUG */ ! 679: if (verbose) ! 680: printf("cancel %s\n", h.ident); ! 681: ulall(p2, &h); ! 682: (void) sprintf(p2, "%s\n", grpsleft); ! 683: if (verbose > 2 && grpsleft[0]) ! 684: printf("Some good in %s\n", h.ident); ! 685: #endif /* !DEBUG */ ! 686: } else { ! 687: if (verbose > 2) ! 688: printf("Good article %s\n", h.ident); ! 689: grpsleft[0] = '!'; ! 690: } ! 691: ! 692: checkdate: ! 693: if (grpsleft[0] == '\0' && today >= rectime + dropincr) { ! 694: if (verbose > 3) ! 695: printf("Drop history of %s - %s\n", ! 696: h.ident, recdate); ! 697: } else { ! 698: #ifdef DBM ! 699: long hpos; ! 700: #endif /* DBM */ ! 701: keephist: ! 702: #ifdef DBM ! 703: hpos = ftell(nhfd); ! 704: #endif /* DBM */ ! 705: ! 706: if (verbose > 3) ! 707: printf("Retain history of %s - %s\n", ! 708: h.ident, recdate); ! 709: if (fputs(afline, nhfd) == EOF) ! 710: xerror("history write failed"); ! 711: #ifdef DBM ! 712: if (!dorebuild) ! 713: remember(h.ident, hpos); ! 714: #endif /* DBM */ ! 715: } ! 716: } ! 717: out: ! 718: if (dorebuild) { ! 719: register struct multhist *mhp; ! 720: struct tm *tm; ! 721: for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) ! 722: if (mhp->mh_file != NULL) { ! 723: if (verbose) ! 724: printf("Article: %s [%s] Cannot find all links\n", mhp->mh_ident, mhp->mh_file); ! 725: (void) sprintf(filename,"%s/%s",SPOOL,mhp->mh_file); ! 726: for (p1 = filename; *p1 != ' ' && *p1 != '\0'; p1++) ! 727: if (*p1 == '.') ! 728: *p1 = '/'; ! 729: *p1 = '\0'; ! 730: if ((fp = art_open(filename, "r")) == NULL) { ! 731: if (verbose) ! 732: printf("Can't open %s.\n", filename); ! 733: continue; ! 734: } ! 735: if (!hread(&h, fp, TRUE)) { ! 736: printf("Garbled article %s.\n", filename); ! 737: (void) fclose(fp); ! 738: continue; ! 739: } else { ! 740: struct stat statb; ! 741: if (fstat(fileno(fp), &statb) < 0) ! 742: rectime = cgtdate(h.subdate); ! 743: else ! 744: rectime = statb.st_mtime; ! 745: } ! 746: tm = gmtime(&rectime); ! 747: if ( fprintf(nhfd, ! 748: #ifdef USG ! 749: "%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", ! 750: #else /* !USG */ ! 751: "%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", ! 752: #endif /* !USG */ ! 753: h.ident, h.expdate[0] ? " " : "", ! 754: tm->tm_mon+1, tm->tm_mday, tm->tm_year, ! 755: tm->tm_hour, tm->tm_min, mhp->mh_file) ! 756: == EOF ) ! 757: xerror("History write failed"); ! 758: (void) fclose(fp); ! 759: continue; ! 760: } ! 761: (void) pclose(nhfd); ! 762: free ((char *)multhist); ! 763: } else ! 764: if (fclose(nhfd)) ! 765: xerror("History write failed, %s", errmsg(errno)); ! 766: ! 767: if (dorebuild || !nohistory) { ! 768: #ifdef DBM ! 769: (void) rename(ARTFILE, OARTFILE); ! 770: (void) rename(NARTFILE, ARTFILE); ! 771: if (dorebuild) ! 772: rebuilddbm( ); ! 773: else { ! 774: char tempname[BUFLEN]; ! 775: (void) sprintf(tempname,"%s.pag", ARTFILE); ! 776: (void) strcat(NARTFILE, ".pag"); ! 777: (void) rename(NARTFILE, tempname); ! 778: (void) sprintf(tempname,"%s.dir", ARTFILE); ! 779: (void) strcpy(rindex(NARTFILE, '.'), ".dir"); ! 780: (void) rename(NARTFILE, tempname); ! 781: } ! 782: #endif ! 783: } ! 784: } ! 785: ! 786: #if defined(BSD4_2) || defined(LOCKF) ! 787: static int LockFd = -1; ! 788: #endif ! 789: ! 790: dolock() ! 791: { ! 792: /* set up exclusive locking so inews does not run while expire does */ ! 793: #if defined(BSD4_2) || defined(LOCKF) ! 794: LockFd = open(ACTIVE, 2); ! 795: # ifdef LOCKF ! 796: if (lockf(LockFd, F_LOCK, 0L) < 0) ! 797: # else /* BSD4_2 */ ! 798: if (flock(LockFd, LOCK_EX) < 0) ! 799: # endif /* BSD4_2 */ ! 800: xerror("Can't get lock for expire: %s", errmsg(errno)); ! 801: #else /* !BSD4_2 && !LOCKF */ ! 802: int i = 0; ! 803: sprintf(afline,"%s.lock", ACTIVE); ! 804: while (LINK(ACTIVE, afline) < 0 && errno == EEXIST) { ! 805: if (i++ > 5) { ! 806: xerror("Can't get lock for expire"); ! 807: } ! 808: sleep(i*2); ! 809: } ! 810: #endif /* !BSD4_2 && !LOCKF */ ! 811: } ! 812: ! 813: rmlock() ! 814: { ! 815: #if defined(BSD4_2) || defined(LOCKF) ! 816: close(LockFd); ! 817: #else ! 818: sprintf(bfr, "%s.lock", ACTIVE); ! 819: (void) UNLINK(bfr); ! 820: #endif /* !BSD4_2 */ ! 821: } ! 822: ! 823: updateactive() ! 824: { ! 825: register char *p1; ! 826: FILE *ohfd, *nhfd; ! 827: DIR *ngdirp = NULL; ! 828: static struct direct *ngdir; ! 829: ! 830: if (verbose) ! 831: printf("updating active file %s\n", ACTIVE); ! 832: ohfd = xfopen(ACTIVE, "r"); ! 833: nhfd = xfopen(NACTIVE, "w"); ! 834: do { ! 835: long n; ! 836: long maxart, minart; ! 837: char cansub; ! 838: int gdsize, hassubs; ! 839: struct stat stbuf; ! 840: ! 841: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 842: continue; ! 843: if (sscanf(afline,"%s %ld %ld %c",nbuf,&maxart, &minart, ! 844: &cansub) < 4) ! 845: xerror("Active file corrupt"); ! 846: if (verbose > 3) ! 847: printf("looking at group %s\n", nbuf); ! 848: if (!ngmatch(nbuf, ngpat)) { ! 849: if (fputs(afline, nhfd) == EOF) ! 850: xerror("active file write failed"); ! 851: continue; ! 852: } ! 853: minart = 99999L; ! 854: /* Change a group name from a.b.c to a/b/c */ ! 855: for (p1=nbuf; *p1; p1++) ! 856: if (*p1 == '.') ! 857: *p1 = '/'; ! 858: ! 859: hassubs = stat(nbuf, &stbuf) != 0 || stbuf.st_nlink != 2; ! 860: gdsize = strlen(nbuf); ! 861: if ((ngdirp = opendir(nbuf)) != NULL) { ! 862: while (ngdir = readdir(ngdirp)) { ! 863: nbuf[gdsize] = '/'; ! 864: (void) strcpy(&nbuf[gdsize+1], ngdir->d_name); ! 865: /* We have to do a stat because of micro.6809 */ ! 866: if (hassubs && (stat(nbuf, &stbuf) < 0 || ! 867: !(stbuf.st_mode&S_IFREG)) ) ! 868: continue; ! 869: n = atol(ngdir->d_name); ! 870: if (n > 0 && n < minart) ! 871: minart = n; ! 872: if (n > 0 && n > maxart) ! 873: maxart = n; ! 874: } ! 875: closedir(ngdirp); ! 876: } ! 877: afline[gdsize] = '\0'; ! 878: if (minart > maxart) ! 879: minart = maxart; ! 880: #ifdef USG ! 881: if (verbose > 4) ! 882: printf("\tmaxart = %5.5ld, minart = %5.5ld\n", ! 883: maxart, minart); ! 884: if (fprintf(nhfd,"%s %5.5ld %5.5ld %c\n", afline, maxart, ! 885: minart, cansub) == EOF) ! 886: xerror("Active file write failed"); ! 887: #else ! 888: if (verbose > 4) ! 889: printf("\tmaxart = %05ld, minart = %05ld\n", ! 890: maxart, minart); ! 891: if (fprintf(nhfd,"%s %05ld %05ld %c\n", afline, maxart, ! 892: minart, cansub) == EOF) ! 893: xerror("Active file write failed"); ! 894: #endif /* !USG */ ! 895: } while (!feof(ohfd)); ! 896: if (fclose(nhfd)) ! 897: xerror("Active file write failed, %s", errmsg(errno)); ! 898: (void) fclose(ohfd); /* this might unlock inews as a side effect */ ! 899: ! 900: (void) rename(ACTIVE, OACTIVE); ! 901: (void) rename(NACTIVE, ACTIVE); ! 902: } ! 903: ! 904: /* Unlink (using unwound tail recursion) all the articles in 'artlist'. */ ! 905: ulall(artlist, hp) ! 906: char *artlist; ! 907: struct hbuf *hp; ! 908: { ! 909: register char *p, *q; ! 910: int last = 0; ! 911: char newname[BUFLEN]; ! 912: time_t timep[2]; ! 913: char *fn; ! 914: ! 915: grpsleft[0] = '\0'; ! 916: do { ! 917: if (verbose > 2) ! 918: printf("ulall '%s', '%s'\n", artlist, hp->subdate); ! 919: if (nohistory) { ! 920: last = 1; ! 921: } else { ! 922: while (*artlist == ' ' || *artlist == '\n' || *artlist == ',') ! 923: artlist++; ! 924: if (*artlist == '\0') ! 925: return; ! 926: p = index(artlist, ' '); ! 927: if (p == NULL) { ! 928: last = 1; ! 929: p = index(artlist, '\n'); ! 930: } ! 931: if (p) ! 932: *p = 0; ! 933: } ! 934: strcpy(newname, artlist); ! 935: q = index(newname,'/'); ! 936: if (q) { ! 937: *q++ = NGDELIM; ! 938: *q = '\0'; ! 939: } else { ! 940: q = index(newname, '\0'); ! 941: if (q == artlist) /* null -> the end */ ! 942: return; ! 943: /* should be impossible to get here */ ! 944: } ! 945: fn = dirname(artlist); ! 946: if (ngmatch(newname, ngpat)) { ! 947: if (doarchive){ ! 948: if (ngmatch(newname, arpat)) { ! 949: q = fn + strlen(SPOOL) + 1; ! 950: (void) sprintf(newname, "%s/%s", OLDNEWS, q); ! 951: if (verbose) ! 952: printf("link %s to %s\n", fn, newname); ! 953: if (LINK(fn, newname) == -1) { ! 954: if (mkparents(newname) == 0) ! 955: if (LINK(fn, newname) == -1) ! 956: fcopy(fn, newname); ! 957: } ! 958: timep[0] = timep[1] = cgtdate(hp->subdate); ! 959: (void) utime(newname, timep); ! 960: } ! 961: } ! 962: if (verbose) ! 963: printf("unlink %s\n", fn); ! 964: if (UNLINK(fn) < 0 && errno != ENOENT) ! 965: perror(fn); ! 966: } else { ! 967: if (verbose > 3) ! 968: printf("retain %s (%s)\n", hp->ident, fn); ! 969: strcat(grpsleft, artlist); ! 970: strcat(grpsleft, " "); ! 971: } ! 972: artlist = p + 1; ! 973: } while (!last); ! 974: } ! 975: ! 976: fcopy(fn, newname) ! 977: char *fn, *newname; ! 978: { ! 979: int f1, f2; ! 980: int r; ! 981: char buf[BUFSIZ]; ! 982: f1 = open(fn, 0); ! 983: if (f1 < 0) ! 984: return -1; ! 985: f2 = open(newname, 1); ! 986: if (f2 < 0) { ! 987: if (errno == ENOENT) { ! 988: f2 = creat(newname,0644); ! 989: if (f2 < 0) { ! 990: close(f1); ! 991: return -1; ! 992: } ! 993: } else { ! 994: close(f1); ! 995: return -1; ! 996: } ! 997: } ! 998: while((r=read(f1, buf, BUFSIZ)) > 0) ! 999: write(f2, buf, r); ! 1000: (void) close(f1); ! 1001: (void) close(f2); ! 1002: return 0; ! 1003: } ! 1004: ! 1005: /* ! 1006: * Count instances of c in s ! 1007: */ ! 1008: chrcnt(s, c) ! 1009: register char *s; ! 1010: register c; ! 1011: { ! 1012: register n = 0; ! 1013: register cc; ! 1014: ! 1015: while (cc = *s++) ! 1016: if (cc == c) ! 1017: n++; ! 1018: return n; ! 1019: } ! 1020: ! 1021: /* ! 1022: * If any parent directories of this dir don't exist, create them. ! 1023: */ ! 1024: mkparents(fullname) ! 1025: char *fullname; ! 1026: { ! 1027: char buf[200]; ! 1028: register char *p; ! 1029: int rc; ! 1030: ! 1031: (void) strcpy(buf, fullname); ! 1032: p = rindex(buf, '/'); ! 1033: if (p) ! 1034: *p = '\0'; ! 1035: if (access(buf, 0) == 0) ! 1036: return 0; ! 1037: mkparents(buf); ! 1038: if ((rc = mkdir(buf, 0755)) < 0) ! 1039: perror("mkdir failed"); ! 1040: if (verbose) ! 1041: printf("mkdir %s, rc %d\n", buf, rc); ! 1042: ! 1043: return rc; ! 1044: } ! 1045: ! 1046: /* Make sure this file is a legal article. */ ! 1047: islegal(fullname, path, name) ! 1048: register char *fullname; ! 1049: register char *path; ! 1050: register char *name; ! 1051: { ! 1052: struct stat buffer; ! 1053: ! 1054: (void) sprintf(fullname, "%s/%s", path, name); ! 1055: ! 1056: /* make sure the article is numeric. */ ! 1057: while (*name != '\0') ! 1058: if (!isascii(*name) || !isdigit(*name)) ! 1059: return 0; ! 1060: else ! 1061: name++; ! 1062: ! 1063: /* Now make sure we don't have a group like net.micro.432, ! 1064: * which is numeric but not a regular file -- i.e., check ! 1065: * for being a regular file. ! 1066: */ ! 1067: if ((stat(fullname, &buffer) == 0) && ! 1068: ((buffer.st_mode & S_IFMT) == S_IFREG)) { ! 1069: /* Now that we found a legal group in a/b/c/4 ! 1070: notation, switch it to a.b.c/4 notation. */ ! 1071: for (name = fullname; name != NULL && *name != '\0'; name++) ! 1072: if (*name == '/' && name != rindex (name, '/')) ! 1073: *name = '.'; ! 1074: ! 1075: return 1; ! 1076: } ! 1077: return 0; ! 1078: } ! 1079: ! 1080: #ifdef DBM ! 1081: /* ! 1082: * This is taken mostly intact from ../cvt/cvt.hist.c and is used at the ! 1083: * end by the options that make a new history file. ! 1084: * Routine to convert history file to dbm file. The old 3 field ! 1085: * history file is still kept there, because we need it for expire ! 1086: * and for a human readable copy. But we keep a dbm hashed copy ! 1087: * around by message ID so we can answer the yes/no question "have ! 1088: * we already seen this message". The content is the ftell offset ! 1089: * into the real history file when we get the article - you can't ! 1090: * really do much with this because the file gets compacted. ! 1091: */ ! 1092: ! 1093: FILE *fd; ! 1094: ! 1095: char namebuf[BUFSIZ]; ! 1096: char lb[BUFSIZ]; ! 1097: ! 1098: rebuilddbm() ! 1099: { ! 1100: register char *p; ! 1101: long fpos; ! 1102: ! 1103: (void) sprintf(namebuf, "%s.dir", ARTFILE); ! 1104: (void) close(creat(namebuf, 0666)); ! 1105: (void) sprintf(namebuf, "%s.pag", ARTFILE); ! 1106: (void) close(creat(namebuf, 0666)); ! 1107: (void) sprintf(namebuf, "%s", ARTFILE); ! 1108: ! 1109: fd = fopen(namebuf, "r"); ! 1110: if (fd == NULL) { ! 1111: perror(namebuf); ! 1112: xxit(2); ! 1113: } ! 1114: ! 1115: initdbm(namebuf); ! 1116: while (fpos=ftell(fd), fgets(lb, BUFSIZ, fd) != NULL) { ! 1117: p = index(lb, '\t'); ! 1118: if (p) ! 1119: *p = 0; ! 1120: remember(lb, fpos); ! 1121: } ! 1122: } ! 1123: ! 1124: remember(article, fileoff) ! 1125: register char *article; ! 1126: long fileoff; ! 1127: { ! 1128: datum lhs, rhs; ! 1129: ! 1130: lcase(article); ! 1131: lhs.dptr = article; ! 1132: lhs.dsize = strlen(article) + 1; ! 1133: rhs.dptr = (char *) &fileoff; ! 1134: rhs.dsize = sizeof fileoff; ! 1135: ! 1136: if (verbose > 5) ! 1137: printf("remember: %s @ %ld\n", article, fileoff); ! 1138: if (store(lhs, rhs) < 0) ! 1139: xerror("dbm store failed"); ! 1140: } ! 1141: #else ! 1142: /* ! 1143: * Open the next history subdirectory file ! 1144: */ ! 1145: ! 1146: FILE * ! 1147: nexthistfile(ofp) ! 1148: FILE *ofp; ! 1149: { ! 1150: static int histfilecounter = -1; ! 1151: ! 1152: if (ofp) ! 1153: fclose(ofp); ! 1154: do { ! 1155: if (++histfilecounter > 9) ! 1156: return NULL; ! 1157: sprintf(bfr, "%s.d/%d", ARTFILE, histfilecounter); ! 1158: if (verbose > 3) ! 1159: printf("reading history file %s\n", bfr); ! 1160: ofp = xfopen(bfr, "r"); ! 1161: } while (ofp == NULL); ! 1162: return ofp; ! 1163: } ! 1164: ! 1165: /* ! 1166: * Rebuild the history subdirectory from LIBDIR/history ! 1167: */ ! 1168: rebuildhistorydir() ! 1169: { ! 1170: char fn[BUFLEN], ofn[BUFLEN]; ! 1171: register int i; ! 1172: FILE *subfd[10], *ohfd; ! 1173: ! 1174: /* rebuild history subfiles */ ! 1175: (void) sprintf(fn, "%s.od", ARTFILE); ! 1176: if (access(fn,0) != 0) ! 1177: (void) mkdir(fn, 0755); ! 1178: (void) sprintf(fn, "%s.d", ARTFILE); ! 1179: if (verbose) ! 1180: printf("Rebuilding history subfile directory %s.\n", fn); ! 1181: if (access(fn,0) != 0) ! 1182: (void) mkdir(fn, 0755); ! 1183: for (i = 0; i < 10; i++) { ! 1184: (void) sprintf(fn, "%s.d/%c", ARTFILE, i + '0'); ! 1185: (void) sprintf(ofn, "%s.od/%c", ARTFILE, i + '0'); ! 1186: (void) rename(fn, ofn); ! 1187: close(creat(fn, 0644)); ! 1188: subfd[i] = xfopen(fn, "w+"); ! 1189: } ! 1190: ohfd = xfopen(ARTFILE, "r"); ! 1191: while (fgets(fn, BUFLEN, ohfd) != NULL) { ! 1192: i = findhfdigit(fn) - '0'; ! 1193: fputs(fn, subfd[i]); ! 1194: } ! 1195: (void) fclose(ohfd); ! 1196: for (i = 0; i < 10; i++) ! 1197: if (ferror(subfd[i]) || fclose(subfd[i])) ! 1198: xerror("History subfile write"); ! 1199: (void) UNLINK(ARTFILE); ! 1200: } ! 1201: #endif /* !DBM */ ! 1202: ! 1203: xxit(i) ! 1204: { ! 1205: rmlock(); ! 1206: exit(i); ! 1207: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.