|
|
1.1 root 1: #include "parms.h"
2: #include "structs.h"
3:
4: #ifdef RCSIDENT
5: static char rcsid[] = "$Header: archiver.c,v 1.7.0.4 85/06/05 14:16:24 notes Rel $";
6: #endif RCSIDENT
7:
8: /*
9: * archiver - archives a notesfile. Takes all articles older
10: * than 'daysold' days and places them, in generic format, in
11: * a sub-directory in the archie directory. The files are marked
12: * by the time that they were created.
13: * The deleteonly parameter is normally zero. If it is non-zero,
14: * no archive is taken; the old notes are merely thrown away.
15: *
16: * Ray Essick March 1982
17: *
18: * modified so that could also toggle on the director message.
19: * in addition to the days untouched.
20: * Ray Essick June 1982
21: *
22: * Now grabs an expiration threshold and a "working set size"
23: * from the notesfile itself. If zero, the values passed
24: * in as paramaters are used.
25: */
26:
27: archiver (nfname, daysold, worksetsize, deleteonly, dirmsgflag)
28: char *nfname;
29: int daysold;
30: int worksetsize;
31: int deleteonly;
32: int dirmsgflag;
33: {
34: struct io_f io,
35: archio;
36: struct when_f zaptime; /* boundary time */
37: struct note_f note;
38: struct note_f note2;
39: int i,
40: ncount,
41: rcount;
42: int dnotes, /* duplicates */
43: dresps, /* in the archive */
44: adopts; /* and adoptions */
45: int deletable; /* how many can zap */
46: int presps;
47: char line[WDLEN];
48: char archdest[WDLEN]; /* target notesfile */
49: char archbase[WDLEN]; /* target directory */
50: char archend[WDLEN]; /* and nf name */
51: char timeline[DATELEN];
52: char *endname;
53: FILE * log;
54: int wasopen;
55: int locktarget; /* whether to */
56: struct daddr_f where;
57: int rnum; /* copy responses */
58: int newnum; /* note place in arch */
59: int rblock,
60: roffset;
61: struct resp_f resp;
62: FILE * txtfile; /* for saving text */
63: char txtfn[WDLEN]; /* its name */
64: int dup_place; /* is in archive? */
65: int dup_resp; /* dup supression */
66:
67: if (init (&io, nfname) < 0)
68: return (-1); /* no notesfile */
69:
70:
71: if (allow (&io, DRCTOK) == 0 && globuid != Notesuid)
72: {
73: closenf (&io);
74: printf ("Archiver: %s: You don't have permission to archive\n",
75: io.fullname);
76: fflush (stdout);
77: return (-1);
78: }
79:
80: if (io.descr.d_stat & ISARCH) /* can't archive an archive */
81: {
82: closenf (&io);
83: printf ("Archiver: %s: You can't archive an archive\n", io.fullname);
84: fflush (stdout);
85: return (-1);
86: }
87:
88: /*
89: * select the archive name
90: */
91:
92: switch (nfalias (io.fullname, archdest, ARCHALIAS))
93: {
94: case -1: /* no file */
95: case 0: /* no match */
96: if (*nfname == '/') /* absolute path name */
97: {
98: strcpy (archend, io.nf); /* get nf */
99: strcpy (archbase, ARCHDIR); /* base directory */
100: printf ("Archiver: WARNING: possible naming conflict in %s (%s)\n",
101: nfname, io.fullname);
102: fflush (stdout);
103: }
104: else
105: {
106: strcpy (archend, io.nf);
107: strcpy (archbase, ARCHDIR); /* base directory */
108: }
109: break;
110:
111: case 1: /* an alias! */
112: if (archdest[0] != '/') /* expand it */
113: {
114: strcpy (archbase, ARCHDIR);
115: strcpy (archend, archdest); /* hold it */
116: }
117: else
118: {
119: endname = rindex (archdest, '/');
120: *endname++ = '\0'; /* split */
121: strcpy (archbase, archdest); /* directory */
122: strcpy (archend, endname); /* and nf */
123: }
124: break;
125:
126: }
127:
128: sprintf (archdest, "%s/%s", archbase, archend); /* full name */
129: sprintf (txtfn, "/tmp/nfa%d", getpid ()); /* hold texts */
130: ncount = rcount = 0; /* count archived */
131: dnotes = dresps = adopts = 0; /* duplicates */
132: locktarget = 0; /* changed if should */
133:
134: /*
135: * check notesfile specific thresholds, sizes and other options
136: */
137:
138: if (io.descr.d_archtime == NEVER) /* don't archive */
139: {
140: printf ("Archiver: %s has archive threshold of `never'\n",
141: nfname);
142: fflush (stdout);
143: goto docompress; /* compress anyway */
144: }
145:
146: if (io.descr.d_archtime != 0) /* non-default */
147: {
148: daysold = (int) io.descr.d_archtime; /* use this one */
149: printf ("Archiver: %s specifies threshold of %d days\n",
150: nfname, daysold);
151: fflush (stdout);
152: }
153:
154: if (io.descr.d_workset != 0)
155: {
156: worksetsize = (int) io.descr.d_workset;
157: printf ("Archiver: %s specifies working set size of %d\n",
158: nfname, worksetsize);
159: fflush (stdout);
160: }
161:
162: if (io.descr.d_dmesgstat != DIRDFLT) /* specific */
163: {
164: dirmsgflag = (int) io.descr.d_dmesgstat; /* set it */
165: printf ("Archiver: %s specifies dirmsg status of %s for expiring\n",
166: nfname,
167: dirmsgflag == DIRON ? "ON" :
168: dirmsgflag == DIROFF ? "OFF" :
169: "NOCARE");
170: fflush (stdout);
171: }
172:
173: if (io.descr.d_archkeep != KEEPDFLT) /* keep/delete */
174: {
175: if (io.descr.d_archkeep == KEEPYES)
176: deleteonly = 0;
177: else
178: deleteonly = 1;
179: printf ("Archiver: %s specifies %s expired notes\n",
180: nfname,
181: deleteonly ? "deleting" : "archiving");
182: fflush (stdout);
183: }
184:
185: deletable = ((int) io.descr.d_nnote) - ((int) io.descr.d_delnote) - worksetsize;
186: if (deletable <= 0) /* candidates? */
187: {
188: if (io.descr.d_nnote - io.descr.d_delnote > 0) /* only if non-empty */
189: {
190: printf ("Archiver: %s: %d notes <= working set size of %d\n",
191: nfname,
192: io.descr.d_nnote - io.descr.d_delnote,
193: worksetsize);
194: fflush (stdout);
195: }
196: goto docompress;
197: }
198:
199: gettime (&zaptime); /* threshold */
200: zaptime.w_gmttime -= 60L * 60L * 24L * ((long) daysold);/* internal */
201: maketime (&zaptime, zaptime.w_gmttime); /* re-format */
202:
203:
204: if (!deleteonly)
205: {
206: if (init (&archio, archdest) < 0) /* not already */
207: {
208: printf ("Archiver creating archive notesfile %s\n", archdest);
209: fflush (stdout);
210: if (buildnf (archend, archbase, 0, 0, 0) < 0)/* make one */
211: {
212: printf ("Archiver: Problems creating %s for archival\n",
213: archdest);
214: fflush (stdout);
215: goto docompress;
216: }
217: if (init (&archio, archdest) < 0) /* and open it */
218: {
219: printf ("Archiver: Problems opening %s for archival\n",
220: archdest);
221: fflush (stdout);
222: goto docompress;
223: }
224: locknf (&archio, DSCRLOCK); /* watch conflicts */
225: getdscr (&archio, &archio.descr);
226: archio.descr.d_stat |= ISARCH + OPEN;
227: putdscr (&archio, &archio.descr);
228: unlocknf (&archio, DSCRLOCK);
229: /*
230: * Copy the active notesfile's access list to
231: * the archive notesfile.
232: */
233: {
234: #ifdef FASTFORK
235: char old[WDLEN];
236: char new[WDLEN];
237: sprintf (old, "%s/%s/%s", io.basedir, io.nf, ACCESS);
238: sprintf (new, "%s/%s/%s", archio.basedir, archio.nf, ACCESS);
239: dounix (0, 0, "/bin/cp", old, new, 0, 0);
240: #else ! FASTFORK
241: char cmdline[WDLEN + WDLEN + 10];
242: sprintf (cmdline, "%s %s/%s/%s %s/%s/%s",
243: "/bin/cp",
244: io.basedir, io.nf, ACCESS,
245: archio.basedir, archio.nf, ACCESS);
246: dounix (cmdline, 0, 0);
247: #endif ! FASTFORK
248: }
249: }
250:
251: locktarget = strcmp (io.nf, archio.nf); /* lock if differ */
252:
253:
254: if (!(archio.descr.d_stat & ISARCH)) /* into archive? */
255: {
256: printf ("Archiver: %s: Target %s is not an archive\n",
257: nfname, archdest);
258: fflush (stdout);
259: closenf (&archio); /* close that */
260: goto docompress; /* compress him anyway */
261: }
262: }
263:
264:
265: #ifdef OLDGROUP
266: /*
267: * This code looks at the directory to see if the notesfile
268: * has been idle long enough to be deleted.
269: *
270: * This code hasn't been tested by me. It works in the
271: * Salkind/Spickelmier version.
272: *
273: * Should stuff a "wait-till-expire" in the master descriptor
274: * of each notesfile so "junk" ones can expire faster or
275: * something like that. Essentially we want the age at which
276: * the notesfile is deleted to be grabbed from the notesfile
277: * itself.
278: *
279: * My personal opinion is that they shouldn't disappear
280: * auto-magically
281: * NOTE: this probably no longer works with the
282: * changes I've made to archiving. (Dec '83)
283: *
284: * N.B. Need some locking in here
285: */
286:
287: /* delete inactive groups - RLS 1/8/83 */
288:
289: sprintf (line, "%s/%s", MSTDIR, nfname);
290: stat (line, &buf);
291: current = time (0);
292: if (current - buf.st_mtime > 60 * 60 * 24 * (OLDGROUP - daysold))
293: {
294: finish (&io);
295:
296: sprintf (line, "/bin/rm -rf %s/%s", MSTDIR, nfname);
297: system (line);
298:
299: gettime (&zaptime);
300: sprdate (&zaptime, timeline);
301:
302: /* message in nfmaint */
303: sprintf (line, "Archiver: removed %s\n", nfname);
304: nfcomment (NOSUCHWARN, line, line, 0, 0);
305:
306: sprintf (line, "%s/%s/%s", MSTDIR, UTILITY, NETLOG);
307: x ((log = fopen (line, "a")) == NULL, "archiver: no logfile");
308: fprintf (log, "Archiver: deleted %s at %s\n", nfname, timeline);
309: printf ("Archiver: deleted %s at %s\n", nfname, timeline);
310: fclose (log);
311: fflush (stdout);
312: return (0);
313: }
314: #endif OLDGROUP
315:
316:
317: locknf (&io, DSCRLOCK); /* MUTEX */
318: if (locktarget) /* and target */
319: locknf (&archio, DSCRLOCK);
320: getdscr (&io, &io.descr);
321: wasopen = io.descr.d_stat & OPEN; /* hold this */
322: io.descr.d_stat &= NOT OPEN; /* privacy */
323: putdscr (&io, &io.descr);
324:
325: for (i = 1; i <= io.descr.d_nnote && deletable; i++)
326: {
327: getnrec (&io, i, ¬e);
328: if (note.n_stat & DELETED)
329: continue; /* gone already */
330: if (dirmsgflag == DIROFF && (note.n_stat & DIRMES))
331: continue; /* don't if dir on */
332: if (dirmsgflag == DIRON && (note.n_stat & DIRMES) == 0)
333: continue; /* don't if dir off */
334: if (inorder (&zaptime, ¬e.n_lmod))
335: continue; /* too recent */
336: presps = note.n_nresp; /* response count */
337: if (!deleteonly) /* save it? */
338: {
339: /*
340: * check to see if this one is already in the archive
341: */
342: dup_place = chknote (&archio, ¬e.n_id, ¬e2);/* already there? */
343: if (dup_place == 0) /* not there */
344: {
345: /*
346: * This code copied almost verbatim from compression routines
347: */
348: #ifdef notdef
349: x ((txtfile = fopen (txtfn, "w")) == NULL, "archiver:bad txt");
350: pageout (&io, ¬e.n_addr, txtfile);
351: fclose (txtfile);
352: x ((txtfile = fopen (txtfn, "r")) == NULL, "archiver: txt read");
353: pagein (&archio, txtfile, &where);
354: fclose (txtfile);
355: #else
356: pagemove (&io, ¬e.n_addr, &archio, &where, LOCKIT);
357: #endif
358: newnum = putnote (&archio, &where, note.ntitle, note.n_stat, ¬e,
359: ¬e.n_auth, NOPOLICY, NOLOCKIT, NOADDID, note.n_from, NOADDTIME);
360: getnrec (&archio, newnum, ¬e2); /* get copy */
361: }
362: else
363: {
364: if ((note2.n_stat & ORPHND) && /* archived is foster */
365: !(note.n_stat & ORPHND)) /* and active isn't */
366: {
367: #ifdef notdef
368: x ((txtfile = fopen (txtfn, "w")) == NULL, "archiver:bad txt");
369: pageout (&io, ¬e.n_addr, txtfile);
370: fclose (txtfile);
371: x ((txtfile = fopen (txtfn, "r")) == NULL, "archiver: txt read");
372: pagein (&archio, txtfile, &where);
373: fclose (txtfile);
374: #else
375: pagemove (&io, ¬e.n_addr, &archio, &where, LOCKIT);
376: #endif
377:
378: note.n_nresp = note2.n_nresp; /* save resp chain */
379: note.n_rindx = note2.n_rindx;
380: note.n_addr = where; /* get text pointer */
381: putnrec (&archio, dup_place, ¬e);/* replace descriptor */
382: note2 = note; /* save good copy */
383: adopts++; /* count 'em */
384: }
385: else
386: {
387: dnotes++; /* count duplicate */
388: }
389: newnum = dup_place; /* for linking resps */
390: }
391:
392: for (rnum = 1; rnum <= presps; rnum++) /* process responses */
393: {
394: if (lrsp (&io, i, rnum, &resp, &roffset, &rblock) != 0)
395: break; /* bad response chain - drop rest */
396: if (dup_place) /* better check... */
397: {
398: dup_resp = chkresp (&archio, &resp.r_id[roffset], ¬e2, newnum);
399: if (dup_resp) /* already there */
400: {
401: dresps++; /* count doubles */
402: continue; /* skip this response */
403: }
404: }
405: #ifdef notdef
406: x ((txtfile = fopen (txtfn, "w")) == NULL, "compress:bad txt");
407: pageout (&io, &resp.r_addr[roffset], txtfile);
408: fclose (txtfile);
409: x ((txtfile = fopen (txtfn, "r")) == NULL, "compress: bad txt read");
410: pagein (&archio, txtfile, &where);
411: fclose (txtfile);
412: #else
413: pagemove (&io, &resp.r_addr[roffset], &archio, &where, LOCKIT);
414: #endif
415: putresp (&archio, &where, resp.r_stat[roffset], newnum, &resp.r_when[roffset],
416: &resp.r_auth[roffset], ¬e, NOLOCKIT, &resp.r_id[roffset],
417: NOADDID, resp.r_from[roffset], NOADDTIME, &resp.r_rcvd[roffset]);
418: }
419: }
420: delnote (&io, i, NOLOCKIT); /* delete entry */
421: ncount++;
422: rcount += presps; /* and responses */
423: deletable--; /* one down */
424: }
425:
426: unlocknf (&io, DSCRLOCK); /* Un MUTEX */
427: if (locktarget) /* and the target */
428: unlocknf (&archio, DSCRLOCK);
429:
430: if (!deleteonly)
431: {
432: finish (&archio); /* close target */
433: unlink (txtfn); /* don't litter */
434: }
435:
436: /*
437: * Time to compress the notesfile and eliminate those
438: * unsightly holes in the data structure.
439: */
440: docompress:
441:
442: locknf (&io, DSCRLOCK); /* MUTEX */
443: if (io.descr.d_nnote != 0) /* non-empty */
444: {
445: if (io.descr.d_delnote != 0 || io.descr.d_delresp != 0)
446: { /* has holes */
447: int nnote,
448: nresp;
449: compress (&io, NOLOCKIT, 0, &nnote, &nresp);
450: printf ("Archiver: %s contains (%d,%d) after compress\n",
451: nfname, nnote, nresp);
452: fflush (stdout);
453: }
454: else /* no holes so */
455: { /* don't compress */
456: printf ("Archiver: %s already compressed\n", nfname);
457: fflush (stdout);
458: }
459: }
460: else /* nothing there to */
461: { /* compress */
462: printf ("Archiver: %s is empty.\n", nfname);
463: fflush (stdout);
464: }
465:
466:
467: if (wasopen) /* if it was already */
468: {
469: getdscr (&io, &io.descr); /* open season */
470: io.descr.d_stat |= OPEN;
471: putdscr (&io, &io.descr); /* replace in file */
472: }
473:
474: unlocknf (&io, DSCRLOCK); /* all done with this */
475: finish (&io); /* and close the notesfile */
476:
477: gettime (&zaptime);
478: sprdate (&zaptime, timeline);
479: if (ncount) /* log only if did somethine */
480: {
481: sprintf (line, "%s/%s/%s", Mstdir, UTILITY, NETLOG);
482: x ((log = fopen (line, "a")) == NULL, "archiver: no logfile");
483: if (!deleteonly)
484: fprintf (log, "%s: archived (%d,%d) [%d,%d dups, %d adopted] into %s at %s\n",
485: nfname, ncount, rcount, dnotes, dresps, adopts, archdest, timeline);
486: else
487: fprintf (log, "%s: Archiver deleted (%d,%d) at %s\n",
488: nfname, ncount, rcount, timeline);
489: fclose (log);
490: }
491:
492: if (!deleteonly)
493: {
494: if (ncount)
495: printf ("Archiver: %s: (%d,%d) [%d,%d dups, %d adoptions] into %s at %s\n",
496: nfname, ncount, rcount, dnotes, dresps, adopts, archdest, timeline);
497: else
498: printf ("Archiver: %s: no notes archived\n",
499: nfname);
500: }
501: else
502: printf ("Archiver: %s: deleted (%d,%d) at %s\n",
503: nfname, ncount, rcount, timeline);
504: fflush (stdout);
505: return (0); /* and return */
506:
507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.