rad@tekcbi.UUCP (Richard Doty) (04/30/86)
I'm listing Brian Reid's article entitled "great glacier news flood problem solved" in the references line, since that was the inspiration for this article. I implemented the mechanism for interlocking expire and rnews that Brian described, with good results (briefly, /usr/bin/rnews is replaced by an imposter shell script that checks for the presence of a lock file - if the lock file exists, standard input is copied to a temporary file for later processing; otherwise, standard input is passed to the "real" rnews. Commands "newsoff" and "newson" are used to respectively set the lock, and clear the lock and pass all the waiting articles to rnews). Like I said, I used Brian's method, and it worked like a charm, with a couple niggles. It doesn't keep locals from posting articles and changing the active file anyway. Besides that, it *is* kind of expensive to have to exec an extra shell for *every* article (not to mention the test for the lock file, if the shell doesn't have a built-in test). Also, there is no check to see if the temporary file *already* exists. But the thing that bothered me the most was that I had an rnews that wasn't really rnews, and the only way I could tell the two apart was to look at their sizes. But after all that, when it takes me 10 hours to run expire I'm *really* happy that my active file is kosher when I'm finished. Thanks, Brian, for bringing this up again so I finally looked closely, and thanks Chuq for the original idea. What I decided to do was to add this capability to inews. That way, rnews is still rnews, I can catch *all* the articles being posted, and I save 2 execs for each article. All at the expense of a little (#ifdeffed) non-standard code in inews.c. A context diff is appended. Depending on your news version (mine says "B 2.10.3 4.3bsd-beta 6/6/85"), line numbers and/or exact implementation may be different, but the idea is simplicity itself. Right before processing the article, call interlock(). If it returns, then the lock is not present. The fact that interlock() has the side-effect of saving the article and exitting, is an arguably un-elegant way to do things. It does seem to make the addition less complex though, and there are plenty of precedents in the netnews code. Let your conscience be your guide. Also, it was suggested to me that expire set the lock itself. I decided not to do that, because inews doesn't know how to automatically scoop up the saved articles. Done this way, if someone doesn't know about the feature, s/he won't get hurt. Oh, one last (!) thing. I made a small addition to Brian's newsoff program. If the lock already exists, or for some reason it can't create the lock file, newsoff exits 1. Else, exit 0. That way, if a lock file gets left from something else, I can tell. In case that was too obscure, here's the way I use newsoff: if newsoff expire newson else echo "could not lock for expire" | mail newsa fi Sorry for the length. I hope you think it was worth it. Richard. *** /tmp/,RCSt1019159 Tue Apr 29 17:00:52 1986 --- /tmp/,RCSt2019159 Tue Apr 29 17:00:54 1986 *************** *** 93,98 ptr = *argv - 1; if (!strncmp(ptr+1, "rnews", 5)) { mode = PROC; #ifdef NICENESS nice(NICENESS); #endif /* NICENESS */ --- 93,101 ----- ptr = *argv - 1; if (!strncmp(ptr+1, "rnews", 5)) { mode = PROC; + #ifdef TEK_INTERLOCK + interlock(stdin, mode); + #endif /* TEK_INTERLOCK */ #ifdef NICENESS nice(NICENESS); #endif /* NICENESS */ *************** *** 402,407 if (mode != PROC) input(); /* Do the actual insertion. */ insert(); } --- 405,413 ----- if (mode != PROC) input(); + #ifdef TEK_INTERLOCK + interlock(infp, mode); + #endif /* TEK_INTERLOCK */ /* Do the actual insertion. */ insert(); } *************** *** 405,410 /* Do the actual insertion. */ insert(); } /* * Create a newsgroup --- 411,467 ----- /* Do the actual insertion. */ insert(); } + + #ifdef TEK_INTERLOCK + /* + * if the file LIBDIR/rnews.lock exists, then copy our input into a + * unique SPOOLDIR/rnews.xxxx file, and exit. The primary intent + * of this is to permit expire to run without having articles localized + * behind its back, and so we don't have to have two kinds of inews/rnews. + * The lock can also be used to keep news processing from happening + * (e.g. during prime time) even if news gets delivered to you. + * + * Notes: a) this even works with arts posted via inews + * b) you have to retrieve the rnews.xxxx files yourself. + * + * Usage: create LIBDIR/lock (any incoming news will be dumped into SPOOLDIR) + * run expire (or whatever else you want to do without news processing) + * remove LIBDIR/lock + * for i in SPOOLDIR/rnews.* + * do rnews <$i && rm $i + * done + */ + interlock(infp,mode) + FILE *infp; + int mode; + { + char fname[BUFLEN], buf[BUFLEN]; + FILE *outfp; + struct stat sb; + extern int sys_nerr; + extern char *sys_errlist; + + sprintf(fname,"%s/rnews.lock",LIBDIR); + if (stat(fname, &sb) == -1) { + if (errno == ENOENT) { + return; /* no lock. let's go */ + } else if (errno <= sys_nerr) { + sprintf(buf,"interlock stat: %s",sys_errlist[errno]); + xerror(buf); + } else { + sprintf(buf,"interlock stat: unknown error %d",errno); + xerror(buf); + } + } + sprintf(fname,"%s/rnews.XXXXXX",SPOOLDIR); + outfp = xfopen(mktemp(fname), "w"); + if (mode != PROC) + lhwrite(&header, outfp); + while (fgets(buf, BUFLEN, infp) != NULL) + fputs(buf, outfp); + xxit(0); + } + #endif /* TEK_INTERLOCK */ /* * Create a newsgroup