|
|
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.