[news.software.b] Is there a way to control the time when news is unpacked?

garvey@cmic.UUCP (Joe Garvey) (02/17/90)

I would like to hold all incoming news until late at night (even though
it may be received at all times during the day), before unpacking it (using
rnews).

However, I'm unwilling to just stall the whole uucp system that long. Mail
that comes in should be immediately unpacked. I'm using a HDB based uucp
on an HP 9000/370 running HP-UX 6.5.

Any suggestions? Any one out there doing this already?

--

Joe Garvey                       UUCP: {apple,backbone}!versatc!mips!cmic!garvey
California Microwave             Internet: garvey%cmic@mips.com
990 Almanor Ave                  HP Desk: garvey (cmic@mips.com) /hp1900/ux
Sunnyvale, Ca, 94086             800-831-3104 (outside CA)
408-720-6439 (let it ring)       800-824-7814 (inside CA)

jbayer@ispi.UUCP (Jonathan Bayer) (02/17/90)

garvey@cmic.UUCP (Joe Garvey) writes:

>I would like to hold all incoming news until late at night (even though
>it may be received at all times during the day), before unpacking it (using
>rnews).

>However, I'm unwilling to just stall the whole uucp system that long. Mail
>that comes in should be immediately unpacked. I'm using a HDB based uucp
>on an HP 9000/370 running HP-UX 6.5.



What you will want to do is the following:

	1.	Rename rnews to be rnews.x

	2.	Replace rnews with a small program that will simply do
		a "mv" to move the news files to a holding directory.  Also,
		it should create a command file which will hold all the
		commands necessary to unpack each file.

	3.	Create a cron entry which will execute the command file
		at the time you want.


JB
-- 
Jonathan Bayer		Intelligent Software Products, Inc.
(201) 245-5922		500 Oakwood Ave.
jbayer@ispi.COM		Roselle Park, NJ   07204    

tneff@bfmny0.UU.NET (Tom Neff) (02/18/90)

In article <239@cmic.UUCP> garvey@cmic.UUCP (Joe Garvey) writes:
>I would like to hold all incoming news until late at night (even though
>it may be received at all times during the day), before unpacking it (using
>rnews).
>
>However, I'm unwilling to just stall the whole uucp system that long. Mail
>that comes in should be immediately unpacked. I'm using a HDB based uucp
>on an HP 9000/370 running HP-UX 6.5.

Jonathan Bayer points out one way, which is to front end 'rnews' with
a program of your own that waits till evening before letting the real
unbatcher do its thing.  The only reason I don't like this is that it
lets the batches sit around in your spool directory all day, and also
makes you pay for downloading them in daytime when you don't really want
the contents till later.

Another, perhaps simpler approach is to fine tune the *grade* of UUCP
traffic you collect during the day.  Many feed sites queue news batches
with a lower grade than mail; if you're not sure whether your feed
sites do this, ask their news admins.  Mine does, so I can say this in
my HDB 'Systems' file:

	uunet Any/C,Any1900-0700 ACU 2400 5551212 "" \d\r Host UUNET ...

This lets me transfer grade C or better (including mail and filecopy)
around the clock, but anything else only from 7pm-7am.  

For more info about this stuff, peruse the Nutshell handbook on Managing
UUCP and Usenet.  Wotta tome :-)

icsu6000@caesar (Jaye Mathisen) (02/19/90)

In article <1309@ispi.UUCP> jbayer@ispi.UUCP (Jonathan Bayer) writes:
>garvey@cmic.UUCP (Joe Garvey) writes:
>
>>I would like to hold all incoming news until late at night (even though
>>it may be received at all times during the day), before unpacking it (using
>>rnews).
>
>>However, I'm unwilling to just stall the whole uucp system that long. Mail
>>that comes in should be immediately unpacked. I'm using a HDB based uucp
>>on an HP 9000/370 running HP-UX 6.5.
>What you will want to do is the following:





Why not just rebuild your news software with the SPOOLNEWS options (assuming
you have B news) defined, and then run rnews -U from cron late at night?


I assume this is doable inside C news, although I have no experience
using it.



Hope this helps.
--
+-----------------------------------------------------------------------------+
| Jaye Mathisen,systems manager       Internet: icsu6000@caesar.cs.montana.edu|
| 410 Roberts Hall                      BITNET: icsu6000@mtsunix1.bitnet      |
| Dept. of Computer Science	                                              |

dce@smsc.sony.com (David Elliott) (02/20/90)

In article <3273@caesar.cs.montana.edu> icsu6000@caesar.cs.montana.edu (Jaye Mathisen) writes:
>>garvey@cmic.UUCP (Joe Garvey) writes:
>>>I would like to hold all incoming news until late at night (even though
>>>it may be received at all times during the day), before unpacking it (using
>>>rnews).

>I assume this is doable inside C news, although I have no experience
>using it.

It's not only doable, it's trivial.  C news leaves the incoming batches
in /usr/spool/news/in.coming.  You set up a cron job that unbatches
the news.

I currently unbatch news at 20 minutes past each hour, but I could
easily change this to only unbatch once a day.

Note that you will probably want to unbatch *after* you expire.
-- 
David Elliott
dce@smsc.sony.com | ...!{uunet,mips}!sonyusa!dce
(408)944-4073

henry@utzoo.uucp (Henry Spencer) (02/20/90)

In article <3273@caesar.cs.montana.edu> icsu6000@caesar.cs.montana.edu (Jaye Mathisen) writes:
>>>I would like to hold all incoming news until late at night (even though
>>>it may be received at all times during the day), before unpacking it...
>
>I assume this is doable inside C news, although I have no experience
>using it.

It's standard with C News.  If you want to pay the extra costs of doing
an unpacking immediately (it does cost a little extra, it turns out),
you have to work at it.
-- 
"The N in NFS stands for Not, |     Henry Spencer at U of Toronto Zoology
or Need, or perhaps Nightmare"| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff) (02/20/90)

>>>>I would like to hold all incoming news until late at night (even though
>>>>it may be received at all times during the day), before unpacking it...
>
>It's standard with C News.  If you want to pay the extra costs of doing
>an unpacking immediately (it does cost a little extra, it turns out),
>you have to work at it.

I agree, if you use the standard C News method.  I used to do it, but 
now have something more efficient and less of a hassle (it does some 
disk space management).  It seems to run about 40% faster by avoiding 
a copy and puting all the front end code into one process.  It also 
has enough "niceness" features that you may not notice it running 
during the day.  Copies of rnews.c are available on request.  

-- 
Jon Zeeff    	zeeff@b-tech.ann-arbor.mi.us  or b-tech!zeeff

henry@utzoo.uucp (Henry Spencer) (02/21/90)

In article <FKT#$T&@b-tech.uucp> zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff) writes:
>>... standard with C News.  If you want to pay the extra costs of doing
>>an unpacking immediately (it does cost a little extra, it turns out),
>>you have to work at it.
>
>I agree, if you use the standard C News method...

Jon, it costs a little extra no matter how you do it; amortizing startup
and shutdown overhead over multiple batches is a win even when those
overheads are small.  Of course, it may not be enough of a win to be
worth bothering with.
-- 
"The N in NFS stands for Not, |     Henry Spencer at U of Toronto Zoology
or Need, or perhaps Nightmare"| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff) (02/21/90)

>>>... standard with C News.  If you want to pay the extra costs of doing
>>>an unpacking immediately (it does cost a little extra, it turns out),
>>>you have to work at it.
>>
>>I agree, if you use the standard C News method...
>
>Jon, it costs a little extra no matter how you do it; amortizing startup
>and shutdown overhead over multiple batches is a win even when those
>overheads are small.  

I'm not sure I agree.  A process (rnews) is already running and if you 
are going to delay processing and do it in a batch, you have to copy 
the news off somewhere (which adds disk i/o overhead) and then start 
up another process to handle it later.  It's also suprising how little 
processing doesn't get repeated for every batch - looking at newsrun, 
all I see if a few lines of minor code (like a lock creation and a 
hostname determination) that aren't in the main loop.  Plus, my rnews 
is faster than either of the C News methods, meaning that while in 
theory you might be able to gain something (what?) by doing it in 
batches, in practice you can't (with currently available code).  

-- 
Jon Zeeff    	zeeff@b-tech.ann-arbor.mi.us  or b-tech!zeeff

allan@cs.strath.ac.uk (Allan Black) (02/24/90)

In article <239@cmic.UUCP> garvey@cmic.UUCP (Joe Garvey) writes:
>I would like to hold all incoming news until late at night (even though
>it may be received at all times during the day), before unpacking it (using
>rnews).

Try this - I've been using it for a couple of years and it seems to work OK.
It checks time of day, load average and number of free inodes in /usr/spool.
[If you're on a SYS5 machine you probably won't get load average & you may
have to tweak some of the code - sorry]

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	Makefile
#	qnews.8
#	unqnews.8
#	config.h
#	qnews.h
#	ctl.c
#	loadav.c
#	qerror.c
#	qnews.c
#	unqnews.c
# This archive created: Fri Feb 23 16:59:22 1990
echo shar: extracting README '(3803 characters)'
sed 's/^XX//' << \SHAR_EOF > README
XXqnews/unqnews 8/4/88
XX
XX  Qnews and unqnews provide a simple queuing mechanism for incoming news
XXbatches. Qnews, invoked by the appropriate listener, places each news
XXbatch in a spool file. Unqnews picks up these spool files in chronological
XXorder and invokes inews(1) to process them.
XX
XXCONFIGURATION
XX  There are several options to be configured before building qnews and
XXunqnews. These are defined in config.h:
XX
XXBATCHDIR	The directory to be used for the news spool files. The
XX		names of the spool files are all of the form
XX		"${BATCHDIR}/rnews.XXXXXX" where "XXXXXX" is a serial
XX		number used to ensure chronological processing of
XX		incoming news articles. This is almost always
XX		"/usr/spool/news/<subdir>" where <subdir> is something
XX		like "inbatch" or "incoming".
XX
XXCOPYDIR		This is the directory where the TRANSPORT SERVICE
XX		software has spooled the file containing the news batch.
XX		Normally, the niftp listener will pass the file name to
XX		qnews as an absolute pathname, so COPYDIR will not be
XX		used. In any strange case where qnews is given a relative
XX		pathname, it will look for the spool file in
XX		"${COPYDIR}/<pathname>". Typical values of COPYDIR are
XX		"/usr/spool/niftp/news" or "/usr/spool/hhcp".
XX
XXERRLOG		The absolute pathname of a file to be used for error
XX		logging by either qnews or unqnews. The file should be
XX		writable by the UID specified by NEWSUID or the group
XX		specified by NEWSGID (see below). Typically, ERRLOG
XX		will be "/usr/lib/news/qnews.errlog".
XX
XXNEWSUID		The UID of the news administrator, usually "news".
XXNEWSGID		The GID of the news administrator, also usually "news".
XX
XXMAXLOAD		The maximum load average at which news processing will
XX		be done. If this is undefined, no account will be taken
XX		of the load average and news will be processed no matter
XX		how crippling this could turn out to be to your poor
XX		machine. If defined, the load average is examined before
XX		starting the processing of each batch by inews. The load
XX		average used is the one averaged over five minutes (the
XX		middle of the three as printed by uptime etc.).
XX
XXPEAKTIME	If PEAKTIME is defined, no news processing will be done
XX		during peak hours (8 a.m. to 6 p.m.). Unqnews will exit
XX		whether it is started by qnews or cron.
XX
XXDAEMON		If daemon is defined, qnews will NOT start up unqnews
XX		upon receiving a news batch. Unqnews can then be started
XX		by cron at the appropriate time (usually sometime during
XX		the night).
XX
XXRWHO		If rwho is defined, unqnews will use the rwho daemon
XX		to find out the load average. If undefined, it will
XX		dig around in /dev/kmem looking at kernel variables.
XX		Only meaningful when MAXLOAD is defined.
XX
XXIFREE		Most transport systems check to make sure sufficient
XX		disk space is available before accepting incoming news.
XX		They don't, however, check sufficient inodes are available
XX		to unpack the news into separate files. IFREE defines
XX		the minimum number of free inodes required before unqnews
XX		will start unbatching. Should be about 10% of total inodes -
XX		"df -i" will tell you what you need to know.
XX
XXSPOOLDEV	The cooked device where news is spooled (for the IFREE
XX		option). E.g. "/dev/zd5e".
XX
XXINSTALLATION
XX  Usually the binaries for qnews and unqnews will reside in the news
XXhome directory, "/usr/lib/news". If this is not the case, edit Makefile
XXand change NEWSDIR to be the directory you want to put them in.
XX  Type "make" and, if all goes according to plan, "make install".
XX
XXINVOCATION
XX  Qnews is invoked either with a single argument giving the ABSOLUTE
XXPATHNAME of the batch file, or with the batch file open on the standard
XXinput:
XX/usr/lib/news/qnews <filename>
XX
XX[For the UK NIFTP system]
XXThis is typically achieved by putting the following line in your
XXniftptailor file:
XXNEWSPROC   "/usr/lib/news/qnews %s"
XX
XXAllan Black <allan@uk.ac.strath.cs>
XX
SHAR_EOF
if test 3803 -ne "`wc -c README`"
then
echo shar: error transmitting README '(should have been 3803 characters)'
fi
echo shar: extracting Makefile '(1545 characters)'
sed 's/^XX//' << \SHAR_EOF > Makefile
XX# Makefile for qnews/unqnews
XX
XXCFLAGS=	-O
XX
XXNEWSDIR=	/usr/lib/news
XX
XXSRC= qnews.c unqnews.c ctl.c qerror.c loadav.c
XXHEADER= config.h qnews.h
XX
XXall: qnews unqnews
XX
XXqnews: qnews.o ctl.o qerror.o
XX	cc -o qnews qnews.o ctl.o qerror.o
XX
XXunqnews: unqnews.o ctl.o qerror.o loadav.o
XX	cc -o unqnews unqnews.o ctl.o qerror.o loadav.o
XX
XXinstall: all
XX	install -m 500 -o news -g news -s qnews ${NEWSDIR}
XX	install -m 2500 -o news -g operator -s unqnews ${NEWSDIR}
XX
XXdepend:
XX	for i in ${SRC}; do \
XX		( /bin/grep '^#[ 	]*include[ 	]*"' $$i | sed -n \
XX			-e 's/[^"]*"\([^"]*\)".*/\1/' \
XX			-e H -e '$$g' -e '$$s/\n/ /g' \
XX			-e '$$s/.*/'$$i': &/' -e '$$s/\.c:/.o:/p' \
XX			>> makedep); done
XX	for i in ${HEADER}; do \
XX		echo '$$s/.*/'$$i': &\' >eddep; \
XX		echo '	touch '$$i'/p' >>eddep; \
XX		( /bin/grep '^#[ 	]*include[ 	]*"' $$i | sed -n \
XX			-e 's/[^"]*"\([^"]*\)".*/\1/' \
XX			-e H -e '$$g' -e '$$s/\n/ /g' \
XX			-f eddep \
XX			>> makedep); done
XX	@echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
XX	@echo '$$r makedep' >>eddep
XX	@echo 'w' >>eddep
XX	@cp Makefile Makefile.bak
XX	ed - Makefile < eddep
XX	@rm -f eddep makedep
XX	@echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
XX	@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
XX	@echo '# see make depend above' >> Makefile
XX	- diff Makefile Makefile.bak
XX	@rm -f Makefile.bak
XX
XX# DO NOT DELETE THIS LINE
XX
XXqnews.o:  qnews.h
XXunqnews.o:  qnews.h
XXctl.o:  qnews.h
XXqerror.o:  qnews.h
XXqnews.h:  config.h
XX	touch qnews.h
XX# DEPENDENCIES MUST END AT END OF FILE
XX# IF YOU PUT STUFF HERE IT WILL GO AWAY
XX# see make depend above
SHAR_EOF
if test 1545 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 1545 characters)'
fi
echo shar: extracting qnews.8 '(1018 characters)'
sed 's/^XX//' << \SHAR_EOF > qnews.8
XX.lg 0
XX.TH QNEWS 8 "8 April 1988"
XX.UC 4
XX.SH NAME
XXqnews \- Queue incoming news batches for processing by inews(1).
XX.SH SYNOPSIS
XX.B /usr/lib/news/qnews
XX[ batchfile ]
XX.SH DESCRIPTION
XX.I Qnews
XXtakes a news batch and queues it for processing by inews(1) at some later time.
XXThe single argument should be the absolute pathname of a file containing
XXthe news batch.
XXIf a relative pathname is given,
XXa default directory will be prepended.
XXIf
XX.I qnews
XXis invoked without any argument the standard input will be used.
XXThe batches are given serially numbered filenames of the form "rnews.XXXXXX",
XXwhere "XXXXXX" is a six-digit integer.
XXThese files are later picked up by
XX.I unqnews(1)
XXin chronological order and given to
XX.I inews.
XX.SH FILES
XX/usr/lib/news/qnews.errlog	error logging file
XX/usr/spool/news/inbatch/.qnews	serial number seqence
XX/usr/spool/news/inbatch/rnews.XXXXXX	news batches
XX/usr/spool/news/inbatch/rnews.qnews	temporary
XX.SH SEE ALSO
XXinews(1), unqnews(8)
XX.SH AUTHORS
XXAllan R. Black
XX.SH DIAGNOSTICS
XXSelf-explanatory.
SHAR_EOF
if test 1018 -ne "`wc -c qnews.8`"
then
echo shar: error transmitting qnews.8 '(should have been 1018 characters)'
fi
echo shar: extracting unqnews.8 '(708 characters)'
sed 's/^XX//' << \SHAR_EOF > unqnews.8
XX.lg 0
XX.TH UNQNEWS 8 "11 April 1988"
XX.UC 4
XX.SH NAME
XXunqnews \- Give queued news batches to inews(1).
XX.SH SYNOPSIS
XX.B /usr/lib/news/unqnews
XX.SH DESCRIPTION
XX.I Unqnews
XXtakes the news batches queued by qnews(8) in chronological order
XXand gives them to inews(1).
XXThe batches have serially numbered filenames of the form "rnews.XXXXXX"
XXwhere "XXXXXX" is a six-digit integer.
XX.SH FILES
XX/usr/lib/news/qnews.errlog	error logging file
XX/usr/spool/news/inbatch/.qnews	serial number seqence
XX/usr/spool/news/inbatch/.unqnews	lock file
XX/usr/spool/news/inbatch/rnews.XXXXXX	news batches
XX/usr/spool/news/inbatch/rnews.tmp	temporary
XX.SH SEE ALSO
XXinews(1), qnews(8)
XX.SH AUTHORS
XXAllan R. Black
XX.SH DIAGNOSTICS
XXSelf-explanatory.
SHAR_EOF
if test 708 -ne "`wc -c unqnews.8`"
then
echo shar: error transmitting unqnews.8 '(should have been 708 characters)'
fi
echo shar: extracting config.h '(1858 characters)'
sed 's/^XX//' << \SHAR_EOF > config.h
XX/*	config.h	University of Strathclyde	24/3/86
XX *
XX *	Configuration options for news batch spooler
XX *
XX */
XX
XX	/* Configurable directories/files:
XX	 * BATCHDIR -	Spool directory for temporary storage of news batches
XX	 *		until they have been given to rnews
XX	 * COPYDIR -	The directory used by the transport system to spool
XX	 *		temporary files. This is only needed in case qnews
XX	 *		is presented with a relative path name by the
XX	 *		transport system's Q process.
XX	 * ERRLOG -	File for various error messages
XX	 */
XX#define BATCHDIR	"/usr/spool/news/inbatch"
XX#define COPYDIR		"/usr/spool/niftp/news"
XX#define ERRLOG		"/usr/lib/news/qnews.errlog"
XX
XX	/* User ID and group ID to run rnews under */
XX#define NEWSUID		7
XX#define NEWSGID		6
XX
XX	/* Define MAXLOAD to be the maximum load average (over 5 minutes)
XX	 * at which news processing will be done. Undefine it if you want
XX	 * unconditional news processing. Define PEAKTIME if you want to
XX	 * prevent news processing during the hours 8 a.m. to 6 p.m.
XX	 */
XX#define MAXLOAD		6.0
XX#undef PEAKTIME
XX
XX	/* Define daemon if you want news processing to be kicked off by
XX	 * cron and ONLY by cron. If you want unqnews started by qnews
XX	 * when a news batch appears, (and perhaps also by cron, if the
XX	 * load average/time of day have resulted in news lying around
XX	 * for a few hours) undefine DAEMON.
XX	 */
XX#undef DAEMON
XX
XX	/* Define RWHO if you want to take the load average from the rwho
XX	 * daemon. Otherwise, loadav() will dig around in /dev/kmem to
XX	 * find the load average in kernel variables. RWHO is only meaningful 
XX	 * if MAXLOAD is defined.
XX	 */
XX#define RWHO
XX
XX	/* Define IFREE to be the minimum number of inodes free on the spool
XX	 * spool partition before news unbatching will be done. SPOOLDEV
XX	 * should be set to the (cooked) device where the spool partition is.
XX	 */
XX#define IFREE		3000
XX#define SPOOLDEV	"/dev/zd5e"
XX
SHAR_EOF
if test 1858 -ne "`wc -c config.h`"
then
echo shar: error transmitting config.h '(should have been 1858 characters)'
fi
echo shar: extracting qnews.h '(280 characters)'
sed 's/^XX//' << \SHAR_EOF > qnews.h
XX/*	qnews.h		University of Strathclyde	24/3/86
XX *
XX *	Batch spooler for incoming news
XX *
XX */
XX
XX#include "config.h"
XX
XX#define RNTEMPLATE	"rnews.XXXXXX"
XX
XXstruct control {
XX	int	c_next;
XX	int	c_last;
XX	int	c_bad;
XX};
XX
XXstruct control	ctl;
XX
XXchar	*func;
XX
XX#ifdef MAXLOAD
XXfloat	loadav();
XX#endif
XX
SHAR_EOF
if test 280 -ne "`wc -c qnews.h`"
then
echo shar: error transmitting qnews.h '(should have been 280 characters)'
fi
echo shar: extracting ctl.c '(1700 characters)'
sed 's/^XX//' << \SHAR_EOF > ctl.c
XX/*	ctl.c		University of Strathclyde	24/3/86
XX *
XX *	Control file handler for incoming news processors
XX *
XX */
XX
XX#include "qnews.h"
XX#include <errno.h>
XX#include <sys/file.h>
XX
XX#define CTLSIZE		22		/* Three six-digit integers plus
XX					 * a newline each = 21 characters.
XX					 */
XX
XXchar	cfile[] =	".qnews";
XX
XXint	cfd;
XX
XXchar	ctlbuf[CTLSIZE];
XX
XXopen_ctl(c)
XX	int c;
XX	/* Open the control file. "c" gives us permission to create it if it
XX	 * doesn't exist. Otherwise, we wait for someone else to do it.
XX	 * Notice that 'qnews' runs as super-user, so it gives ownership
XX	 * of the file to news, enabling the unbatchers to do a setuid(news).
XX	 */
XX{
XX	while((cfd = open(cfile,2)) < 0) {
XX		if(c) {
XX			if((cfd = creat(cfile,0644)) >= 0) {
XX				close(cfd);
XX				chown(cfile,NEWSUID,NEWSGID);
XX				continue;
XX			}
XX			qerror(cfile);
XX		}
XX		sleep(300);
XX	}
XX}
XX
XXget_ctl()
XX	/* Get the info in the control file, plus an exclusive lock */
XX{
XX	if(flock(cfd,LOCK_EX) < 0) qerror(cfile);
XX	if(lseek(cfd,0L,0) < 0) qerror(cfile);
XX	if(read(cfd,ctlbuf,CTLSIZE) < 0) qerror(cfile);
XX	sscanf(ctlbuf,"%6d\n%6d\n%6d\n",&ctl.c_next,&ctl.c_last,&ctl.c_bad);
XX}
XX
XXput_ctl()
XX	/* Put info back to the control file and release the lock */
XX{
XX	if(lseek(cfd,0L,0) < 0) qerror(cfile);
XX	sprintf(ctlbuf,"%06d\n%06d\n%06d\n",ctl.c_next,ctl.c_last,ctl.c_bad);
XX	if(write(cfd,ctlbuf,strlen(ctlbuf)) < 0) qerror(cfile);
XX	flock(cfd,LOCK_UN);
XX}
XX
XXrel_ctl()
XX	/* Release the control file */
XX{
XX	flock(cfd,LOCK_UN);
XX}
XX
XXexists(file)
XX	char *file;
XX	/* Test for persence of file. If the file exists, We simulate a
XX	 * "File exists" error, to facilitate qerror's job.
XX	 */
XX{
XX	extern int errno;
XX	if(access(file,F_OK) < 0) {
XX		return 0;
XX	} else {
XX		errno = EEXIST;
XX		return 1;
XX	}
XX}
XX
SHAR_EOF
if test 1700 -ne "`wc -c ctl.c`"
then
echo shar: error transmitting ctl.c '(should have been 1700 characters)'
fi
echo shar: extracting loadav.c '(3645 characters)'
sed 's/^XX//' << \SHAR_EOF > loadav.c
XX/*	loadav.c
XX *
XX * This code is all 4.[23] BSD specific. Who cares about System V?
XX * We 'fail-safe' by returning values that'll prevent unbatching
XX * if something unexpected occurs, like a system call failing.
XX */
XX
XX#include "config.h"
XX
XX/*
XX * NB - On 'vanilla' 4.2 BSD systems, the kernel stores the load
XX * averages as floats and the values there should not be divided
XX * by 100. If you plan to read /dev/kmem on such a system, the
XX * definition of avenrun[] and the value of MAXLOADAVG will have
XX * to be changed accordingly. #define VANILLA should do this OK.
XX */
XX
XX#undef VANILLA
XX
XX#ifdef MAXLOAD
XX#ifdef RWHO
XX/*
XX * Find out the load average by looking at the files created by
XX * the rwho daemon in /usr/spool/rwho. This won't work if the
XX * daemon isn't running.
XX */
XX
XX/*
XX * rwho protocol packet format.
XX * - lifted from /usr/src/etc/rwhod/rwho.h
XX */
XXstruct	whod {
XX	char	wd_vers;		/* protocol version # */
XX	char	wd_type;		/* packet type, see below */
XX	char	wd_pad[2];
XX	int	wd_sendtime;		/* time stamp by sender */
XX	int	wd_recvtime;		/* time stamp applied by receiver */
XX	char	wd_hostname[32];	/* hosts's name */
XX	int	wd_loadav[3];		/* load average as in uptime */
XX	int	wd_boottime;		/* time system booted */
XX	/* who cares about the login crud from utmp ? */
XX} whod;
XX
XXchar whodfile[100];
XXchar hostname[32];
XX
XX#define SPOOLPATH "/usr/spool/rwho/whod."
XX
XXfloat loadav()
XX/*
XX * Return the load average over the last 5 minutes
XX */
XX{
XX	int fd;
XX	if(gethostname(hostname,sizeof(hostname)) != 0) return 0;
XX	sprintf(whodfile, "%s%s", SPOOLPATH, hostname);
XX	if((fd = open(whodfile,0)) < 0) return (float)0;
XX	if(read(fd,&whod,sizeof(struct whod)) < 0) {
XX		close(fd);
XX		return (float)0;
XX	}
XX	return (float)(whod.wd_loadav[1]/100);
XX}
XX
XX#else RWHO
XX
XX#include <nlist.h>
XX
XXstruct nlist nl[] = {
XX	{ "_avenrun" },
XX#define X_AVENRUN 0
XX	{ "" },
XX};
XX
XXfloat loadav()
XX/*
XX * Poke around in /dev/kmem and the kernel symbol table
XX * and fish out the load average ourselves (Yuk)! This
XX * won't be allowed on systems that keep /dev/*mem* away
XX * from prying eyes.
XX *
XX */
XX{
XX	int kmem, kloadav;
XX#ifdef VANILLA
XX	float avenrun[3];
XX#else
XX	long avenrun[3];
XX#endif
XX
XX	if((kmem = open("/dev/kmem",0)) < 0) return 0;
XX	nlist("/vmunix", nl);
XX	if(nl[0].n_type == 0) return 0;
XX	if(lseek(kmem,(long)nl[X_AVENRUN].n_value,0) < 0) {
XX		close(kmem);
XX		return 0;
XX	}
XX	if(read(kmem,avenrun,sizeof(avenrun)) != sizeof(avenrun)) {
XX		close(kmem);
XX		return 0;
XX	}
XX	close(kmem);
XX#ifdef VANILLA
XX	return avenrun[1];
XX#else
XX	return (float)(avenrun[1]/100)
XX#endif
XX}
XX
XX#endif RWHO
XX#endif MAXLOAD
XX
XX#ifdef PEAKTIME
XX
XX#include <sys/time.h>
XX
XX#define SECSPERDAY (24*60*60)
XX#define EIGHT_AM (8*60*60)
XX#define SIX_PM (18*60*60)
XX
XXint peaktime()
XX/*
XX * Return non-zero if we're in peak time - between 8 am and 6 pm.
XX * This'll stop us processing news during the daytime when there
XX * are 1,000 users logged in all running emacs and compiling Ada
XX * programs.......
XX */
XX{
XX	struct timeval tv;
XX	struct timezone tz;
XX	int now;
XX
XX	if (gettimeofday(&tv,&tz) < 0) return 0;
XX	now = tv.tv_sec % SECSPERDAY;
XX	return now >= EIGHT_AM && now <= SIX_PM;
XX}
XX
XX#endif PEAKTIME
XX
XX#ifdef IFREE
XX
XX/* Examine number of free inodes on /usr/spool partition */
XX
XX#include <sys/param.h>
XX#include <sys/fs.h>
XX
XXunion {
XX	struct fs	sb_fs;
XX	char		sb_pad[SBSIZE];
XX} sb;
XX#define sblock	sb.sb_fs
XX
XXifree()
XX{
XX	int dev;
XX	if((dev = open(SPOOLDEV, 0)) < 0) {
XX		qerror(SPOOLDEV);
XX		return IFREE;
XX	}
XX	if(lseek(dev, (long) (SBLOCK*DEV_BSIZE), 0) < 0) {
XX		qerror("lseek");
XX		close(dev);
XX		return IFREE;
XX	}
XX	if(read(dev, (char *) &sblock, SBSIZE) != SBSIZE) {
XX		qerror("read");
XX		close(dev);
XX		return IFREE;
XX	}
XX	close(dev);
XX	return sblock.fs_cstotal.cs_nifree;
XX}
XX
XX#endif IFREE
XX
SHAR_EOF
if test 3645 -ne "`wc -c loadav.c`"
then
echo shar: error transmitting loadav.c '(should have been 3645 characters)'
fi
echo shar: extracting qerror.c '(620 characters)'
sed 's/^XX//' << \SHAR_EOF > qerror.c
XX/*	qerror.c	University of Strathclyde	24/3/86
XX *
XX *	Error messages
XX *
XX */
XX
XX#include "qnews.h"
XX#include <stdio.h>
XX#include <sys/file.h>
XX
XXqerror(str)
XX	char *str;
XX	/* Open the error log file and simulate a perror() */
XX{
XX	extern int errno;
XX	extern char *sys_errlist[];
XX	qlog("%s: %s: %s\n",func,str,sys_errlist[errno]);
XX}
XX
XXqlog(fmt,args)
XX	char *fmt;
XX	int args;
XX{
XX	register FILE *errlog;
XX	if((errlog = fopen(ERRLOG,"a")) == NULL) return;
XX	flock(fileno(errlog),LOCK_EX);
XX	_doprnt(fmt,&args,errlog);
XX	flock(fileno(errlog),LOCK_UN);
XX	fclose(errlog);
XX}
XX
XXpanic(str)
XX	char *str;
XX	/* I give up ..... */
XX{
XX	qerror(str);
XX	exit(1);
XX}
XX
SHAR_EOF
if test 620 -ne "`wc -c qerror.c`"
then
echo shar: error transmitting qerror.c '(should have been 620 characters)'
fi
echo shar: extracting qnews.c '(3229 characters)'
sed 's/^XX//' << \SHAR_EOF > qnews.c
XX/*	qnews.c		University of Strathclyde	24/3/86
XX *
XX *	Batch spooler for incoming news
XX *
XX */
XX
XX/* Called as "qnews filename"; filename being the name of the spool
XX * file which hhcp/uucp etc. has just finished receiving.
XX * Renames, or copies if rename fails, the file into the news
XX * batch directory for processing by unqnews.
XX * With no arg, copies standard input to news batch directory.
XX * This a) lets the comms link close as soon as possible
XX *	b) allows a certain amount of control over processing
XX * N.B. MUST be called as "qnews <absolute pathname>", since it does
XX * a but of cd'ing.
XX */
XX
XX#include <signal.h>
XX#include <sys/ioctl.h>
XX#include "qnews.h"
XX
XX#define BUFSIZE		1024
XX
XXchar	batchdir[] =	BATCHDIR;
XXchar	rnfile[] =	RNTEMPLATE;
XXchar	unqnews[] =	"/usr/lib/news/unqnews";
XXchar	xfile[] =	"rnews.qnews";
XX
XXchar	copyfile[100];
XX
XXchar	buf[BUFSIZE];
XX
XXmain(argc,argv,envp)
XX	int argc;
XX	char **argv;
XX	char **envp;
XX{
XX	register int rfd, wfd;
XX	register char *sfile;
XX	register int n;
XX
XX	*envp = 0;
XX
XX	func = argv[0];
XX	for(n = 0; n < NSIG; n++) signal(n,SIG_IGN);
XX	rfd = open("/dev/tty",2);
XX	ioctl(rfd,TIOCNOTTY);
XX	close(rfd);
XX
XX	if(chdir(batchdir) < 0) {
XX		/* Surely not.... */
XX		panic(batchdir);
XX	}
XX
XX	open_ctl(1);
XX	get_ctl();
XX
XX	if(argc > 1) {
XX		/* Just take the file.... */
XX		sfile = argv[1];
XX		if(*sfile != '/') {
XX			/* Make it an absolute pathname in the
XX			 * hh/uu/ftp etc. spool directory [COPYDIR]
XX			 */
XX			strcpy(copyfile,COPYDIR);
XX			strcat(copyfile,"/");
XX			strcat(copyfile,sfile);
XX			sfile = copyfile;
XX		}
XX	} else {
XX		/* Copy stdin to tmp file */
XX		if((wfd = creat(xfile,0644)) < 0) panic(xfile);
XX		while((n = read(0,buf,BUFSIZE)) > 0) {
XX			if(write(wfd,buf,n) < 0) {
XX				qerror(xfile);
XX				unlink(xfile);
XX				exit(1);
XX			}
XX		}
XX		close(wfd);
XX		sfile = xfile;
XX	}
XX
XX	mkrnfile(rnfile,ctl.c_last);
XX	while(rename(sfile,rnfile) < 0) {
XX		if(sfile != xfile) {
XX			/* We can't rename the hhcp/ftp/uucp[etc.] spool file
XX			 * into the news spool directory, so try to copy it.
XX			 */
XX			if((rfd = open(sfile,0)) < 0) {
XX				qerror(sfile);
XX				goto junk;
XX			}
XX			if((wfd = creat(xfile,0644)) < 0) {
XX				qerror(xfile);
XX				goto junk;
XX			}
XX			while((n = read(rfd,buf,BUFSIZE)) > 0) {
XX				if(write(wfd,buf,n) < 0) {
XX					qerror(xfile);
XX					goto junk;
XX				}
XX			}
XX			close(rfd);
XX			close(wfd);
XX			if(unlink(sfile) < 0) qerror(sfile);
XX			sfile = xfile;
XX			continue;
XX		}
XX		/* If we can't rename a file within the same directory,
XX		 * there's something seriously wrong.....
XX		 */
XX		qerror(sfile);
XX		qerror(rnfile);
XX	junk:
XX		unlink(xfile);	/* May or may not exist */
XX		rel_ctl();	/* Locks on files, not fd's... */
XX		exit(1);
XX	}
XX
XX	/* Done successfully. Chown and chmod the file */
XX	chown(rnfile,NEWSUID,NEWSGID);
XX	chmod(rnfile,0644);
XX	ctl.c_last++;
XX	put_ctl();
XX
XX#ifndef DAEMON
XX	/* unqnews will fork and exit immediately.... */
XX	execl(unqnews,unqnews,0);
XX	qerror(unqnews);
XX	/* Even if we can't unqueue it, the news is still ok,
XX	 * so we can exit(0)
XX	 */
XX#endif
XX
XX	exit(0);
XX}
XX
XXmkrnfile(fname,num)
XX	char *fname;
XX	register int num;
XX	/* Transform the "rnews.XXXXXX" template into "rnews.nnnnnn"
XX	 * where 'nnnnnn' is the serial number 'num'.
XX	 */
XX{
XX	register char *f;
XX	for(f = fname; *f; f++);
XX	while(*--f == 'X') {
XX		*f = num%10+'0';
XX		num /= 10;
XX	}
XX}
XX
SHAR_EOF
if test 3229 -ne "`wc -c qnews.c`"
then
echo shar: error transmitting qnews.c '(should have been 3229 characters)'
fi
echo shar: extracting unqnews.c '(6189 characters)'
sed 's/^XX//' << \SHAR_EOF > unqnews.c
XX/*	unqnews.c	University of Strathclyde	24/3/86
XX *
XX *	Batch processor for incoming news
XX *
XX */
XX
XX/* Give the news batches in "/usr/spool/news/batched/rnews.nnnnnn" to
XX * rnews. Invoked in /etc/rc.local will restart processing.
XX */
XX
XX#include "qnews.h"
XX#include <stdio.h>
XX#include <signal.h>
XX#include <sys/ioctl.h>
XX#include <sys/file.h>
XX
XX#define MAXENV		50
XX
XXchar	batchdir[] =	BATCHDIR;
XXchar	rnfile[] =	RNTEMPLATE;
XX
XXchar	newsdir[] =	"/usr/lib/news";
XXchar	tmpfile[] =	"rnews.tmp";
XXchar	rnews[] =	"rnews";
XXchar	rnewspath[] =	"/usr/lib/news/rnews";
XXchar	null[] =	"/dev/null";
XXchar	unqlfile[] =	".unqnews";
XXchar	badfile[] =	"badbatch.XXXXXX";
XXchar	newpath[100] =	"PATH=/bin:/usr/bin:/usr/ucb:";
XX
XXchar	*newenv[MAXENV+1];
XX
XXint	unqlfd;
XX
XXint	terminate();
XX
XXint	(*sigfunc[NSIG+1])() = {
XX	0,		/* 0: UNUSED */
XX	terminate,	/* 1 SIGHUP */
XX	SIG_IGN,	/* 2 SIGINT */
XX	SIG_IGN,	/* 3 SIGQUIT */
XX	SIG_IGN,	/* 4 SIGILL */
XX	SIG_IGN,	/* 5 SIGTRAP */
XX	SIG_IGN,	/* 6 SIGIOT */
XX	SIG_IGN,	/* 7 SIGEMT */
XX	SIG_IGN,	/* 8 SIGFPE */
XX	SIG_DFL,	/* 9 SIGKILL */
XX	SIG_DFL,	/* 10 SIGBUS */
XX	SIG_DFL,	/* 11 SIGSEGV */
XX	SIG_DFL,	/* 12 SIGSYS */
XX	SIG_DFL,	/* 13 SIGPIPE */
XX	SIG_IGN,	/* 14 SIGALRM */
XX	terminate,	/* 15 SIGTERM */
XX	SIG_DFL,	/* 16 SIGURG */
XX	SIG_DFL,	/* 17 SIGSTOP */
XX	SIG_IGN,	/* 18 SIGTSTP */
XX	SIG_IGN,	/* 19 SIGCONT */
XX	SIG_DFL,	/* 20 SIGCHLD */
XX	SIG_DFL,	/* 21 SIGTTIN */
XX	SIG_DFL,	/* 22 SIGTTOU */
XX	SIG_DFL,	/* 23 SIGIO */
XX	SIG_IGN,	/* 24 SIGXCPU */
XX	SIG_IGN,	/* 25 SIGXFSZ */
XX	SIG_IGN,	/* 26 SIGVTALRM */
XX	SIG_IGN,	/* 27 SIGPROF */
XX	SIG_IGN,	/* 28 SIGWINCH */
XX	SIG_DFL,	/* 29 (UNUSED) */
XX	SIG_DFL,	/* 30 (UNUSED) */
XX	SIG_DFL,	/* 31 (UNUSED) */
XX	SIG_DFL,	/* 32 (UNUSED) */
XX};
XX
XXextern char	tmpfile[];
XX
XXchar	*mkfile();
XX
XXmain(argc,argv,envp)
XX	int argc;
XX	char **argv;
XX	char **envp;
XX{
XX	register int i;
XX	register char *file;
XX	register char **ep;
XX
XX	func = argv[0];
XX
XX#ifdef PEAKTIME
XX	if(peaktime()) exit(0);
XX#endif
XX
XX#ifdef MAXLOAD
XX	if(loadav() > MAXLOAD) exit(0);
XX#endif
XX
XX#ifdef IFREE
XX	if(ifree() < IFREE) exit(0);
XX#endif IFREE
XX
XX	if(fork()) exit(0);
XX
XX	for(i = 1; i <= NSIG; i++) signal(i,sigfunc[i]);
XX
XX	i = open("/dev/tty",2);
XX	ioctl(i,TIOCNOTTY);
XX	close(i);
XX
XX	strcat(newpath, newsdir);
XX	for(ep = newenv; ep < &newenv[MAXENV-1] && *envp; envp++)
XX		if(!strncmp(*envp, newpath, 5)) *ep++ = *envp;
XX	*ep++ = newpath;
XX	*ep = 0;
XX
XX	setuid(NEWSUID);
XX
XX	if(chdir(batchdir) < 0) {
XX		/* If we can't get to the batch directory .... */
XX		panic(batchdir);
XX	}
XX
XX	open_ctl(0);
XX	get_ctl();
XX	unqlock();
XX	rel_ctl();
XX
XX	/* Now we are sure we have control. Make sure there isn't an old
XX	 * batch which hasn't been completely processed yet.
XX	 */
XX	if(exists(tmpfile)) do_rnews();
XX
XX	for(;;) {
XX
XX#ifdef PEAKTIME
XX		if(peaktime()) unqexit(0);
XX#endif
XX#ifdef MAXLOAD
XX		if(loadav() > MAXLOAD) unqexit(0);
XX#endif
XX#ifdef IFREE
XX		if(ifree() < IFREE) unqexit(0);
XX#endif IFREE
XX
XX		get_ctl();
XX		if(ctl.c_next < ctl.c_last) {
XX			/* Something claims to be there. Try to process
XX			 * the batch.
XX			 */
XX			file = mkfile(rnfile,ctl.c_next);
XX			if(++ctl.c_next >= ctl.c_last) {
XX				/* Last one - go back to zero */
XX				ctl.c_next = ctl.c_last = 0;
XX			}
XX			if(!exists(file)) {
XX				/* If the file doesn't exist, too bad */
XX				qerror(file);
XX				put_ctl();
XX				continue;
XX			}
XX			if(rename(file,tmpfile) < 0) {
XX				/* If we can't rename it, something's
XX				 * seriously wrong. Give up.
XX				 */
XX				qerror(tmpfile);
XX				rel_ctl();
XX				unqexit(1);
XX			}
XX		} else {
XX			/* Nothing to process */
XX			rel_ctl();
XX			unqexit(0);
XX		}
XX		put_ctl();
XX		do_rnews();
XX	}
XX}
XX
XXterminate(n)
XX	int n;
XX{
XX	qlog("%s: terminated by signal %d\n",func,n);
XX	unqexit(1);
XX}
XX
XXchar *mkfile(fname,num)
XX	char *fname;
XX	register int num;
XX	/* Return a file name constructed from the 'fname' template, by
XX	 * printing 'num' into the 'X's
XX	 * 'fname' usually = "rnews.XXXXXX"
XX	 */
XX{
XX	register char *f;
XX	static char buf[100];
XX	for(f = buf; *f = *fname++; f++);
XX	while(*--f == 'X') {
XX		*f = num%10+'0';
XX		num /= 10;
XX	}
XX	return(buf);
XX}
XX
XXdo_rnews()
XX	/* Call rnews [at last!] giving it 'tmpfile' as standard input.
XX	 * If ANYTHING AT ALL goes wrong, we abort and kill the parent
XX	 * process.
XX	 * We can't afford to ignore errors here - I had a nasty experience
XX	 * with rnews once where /dev/null wasn't opened on channels 1 & 2.
XX	 * [The history.pag database ended up being opened on stderr by rnews
XX	 * and "inews: Article too old, moved to junk" didn't go down too
XX	 * well with the database functions]
XX	 * If the child process terminates abnormally, we assume we have a
XX	 * bad batch and save it for the news administrator to salvage what
XX	 * he can from it.
XX	 */
XX{
XX	register int n, pid;
XX	int st;
XX	register char *file;
XX	extern int errno;
XX	pid = getpid();
XX	if((n = fork()) == 0) {
XX		for(n = 1; n <= NSIG; n++) signal(n,SIG_DFL);
XX		for(n = 0; n < _NFILE; n++) close(n);
XX		if(open(tmpfile,0) != 0) {
XX			qerror(tmpfile);
XX			kill(pid,1);
XX			unqexit(1);
XX		}
XX		if(open(null,1) != 1) {
XX			qerror(null);
XX			kill(pid,1);
XX			unqexit(1);
XX		}
XX		if(open(null,1) != 2) {
XX			qerror(null);
XX			kill(pid,1);
XX			unqexit(1);
XX		}
XX		if(chdir(newsdir) < 0) {
XX			qerror(newsdir);
XX			kill(pid,1);
XX			unqexit(1);
XX		}
XX		execle(rnewspath,rnews,0,newenv);
XX		qerror(rnews);
XX		kill(pid,1);
XX		unqexit(1);
XX	}
XX	while(wait(&st) != n);
XX	if(st) {
XX		get_ctl();
XX		file = mkfile(badfile,ctl.c_bad);
XX		++ctl.c_bad;
XX		if(rename(tmpfile,file) < 0) {
XX			rel_ctl();
XX			panic(file);
XX		}
XX		put_ctl();
XX	} else {
XX		unlink(tmpfile);
XX	}
XX}
XX
XXunqlock()
XX	/* Lock on the .unqnews file. This ensures only one copy of
XX	 * unqnews runs at a time. It also makes it safe to start
XX	 * unqnews by hand, or restart from /etc/rc.local. Thus,
XX	 * if we don't get the lock, we just exit(0). THE LOCK ON
XX	 * THE CONTROL FILE MUST BE MADE BEFORE ATTEMPTING TO CALL
XX	 * THIS!
XX	 */
XX{
XX	unsigned int x;
XX	if(!exists(unqlfile)) {
XX		if((unqlfd = creat(unqlfile,0644)) < 0) panic(unqlfile);
XX		close(unqlfile);
XX	}
XX	if((unqlfd = open(unqlfile,2)) < 0) panic(unqlfile);
XX	if(flock(unqlfd,LOCK_EX|LOCK_NB) < 0) exit(0);
XX	x = getpid();
XX	write(unqlfd,&x,sizeof(int));
XX}
XX
XXunqexit(st)
XX	int st;
XX	/* Don't forget to release the lock on unqueueing before
XX	 * exiting! Some versions of BSD [at least older systems]
XX	 * don't always release locks automatically.
XX	 */
XX{
XX	flock(unqlfd,LOCK_UN);
XX	exit(st);
XX}
XX
SHAR_EOF
if test 6189 -ne "`wc -c unqnews.c`"
then
echo shar: error transmitting unqnews.c '(should have been 6189 characters)'
fi
#	End of shell archive
exit 0