Article View: news.software.b
Article #6997Re: Is there a way to control the time when news is unpacked?
From: Allan Black
Date: Fri, 23 Feb 1990 17:07
Date: Fri, 23 Feb 1990 17:07
1135 lines
31605 bytes
31605 bytes
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
Technical Details
Message-ID:
<2123@baird.cs.strath.ac.uk>Path:
arc1-ca.pugleaf.net!utzoo!utstat!helios.physics.utoronto.ca!jarvis.csri.toronto.edu!cs.utexas.edu!uunet!mcsun!ukc!strath-cs!allanReferences:
<239@cmic.UUCP>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utstat!helios.physics.utoronto.ca!jarvis.csri.toronto.edu!cs.utexas.edu!uunet!mcsun!ukc!strath-cs!allan From: allan@cs.strath.ac.uk (Allan Black) Newsgroups: news.software.b Subject: Re: Is there a way to control the time when news is unpacked? Keywords: news, rnews, uucp Message-ID: <2123@baird.cs.strath.ac.uk> Date: 23 Feb 90 17:07:16 GMT References: <239@cmic.UUCP> Reply-To: allan@cs.strath.ac.uk Organization: Comp. Sci. Dept., Strathclyde Univ., Scotland. Lines: 1135