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