[comp.sources.unix] v23i012: Netnews transmission daemon, Part02/03

rsalz@bbn.com (Rich Salz) (08/31/90)

Submitted-by: Chris Myers <chris@wugate.wustl.edu>
Posting-number: Volume 23, Issue 12
Archive-name: newsxd/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  defs.h patchlevel.h process.c simple.conf util.c version.c
# Wrapped by rsalz@litchi.bbn.com on Fri Jul 13 15:03:57 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 2 (of 3)."'
if test -f 'defs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'defs.h'\"
else
  echo shar: Extracting \"'defs.h'\" \(6742 characters\)
  sed "s/^X//" >'defs.h' <<'END_OF_FILE'
X/* Define everything that all of the various pieces of code will be using */
X
X#include <stdio.h>
X#include <signal.h>
X#include <strings.h>
X#include <syslog.h>
X#include <nlist.h>
X#include <errno.h>
X#include <ctype.h>
X#include <sys/param.h>
X#include <sys/errno.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X#include <sys/wait.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <varargs.h>
X
X#include "newsxd.h"
X#include "patchlevel.h"
X
X/* If it's good enough for news 2.11, it's good enough for me ... */
X
X#ifdef BSD4_2
X#include <sys/time.h>
X#else
X#include <time.h>
X#endif
X
X#include <sys/resource.h>
X
X#if defined(mips) & defined(ultrix)
X#include <sys/../h/fixpoint.h>
X#endif
X
Xchar	*calloc();
X
X#define foreach(ctl, list) for (ctl = list; ctl != NULL; ctl = ctl->next)
X
X#ifdef	CNEWSLOCKING
Xextern char	*progname;
X#endif
X
Xint     debug,                  /* is debugging enabled                       */
X        DEBUG,                  /* painfully verbose debugging is enabled     */
X        newsxdebug,             /* run xmitter synchronously with debugging?  */
X        tallying,               /* is use of a tally file enabled?            */
X        locking,                /* is use of a locking file enabled?          */
X        CONFIGCHANGED,          /* a new configuration was read in            */
X#ifdef FAKESYSLOG
X        CONFIGCHANGEDFILE,      /* a new configuration was read in            */
X#endif
X        queueinterval,          /* number of seconds between xmit checks      */
X	daemon_idle,		/* prevent newsxd from running queue if set   */
X        pidlist[MAXXMITTERS];   /* map pid --> xmitter quicker                */
X
Xstruct	host	*pidmap[MAXXMITTERS];
X
Xchar    batchfile[MAXPATHLEN],  /* file inews places article IDs/paths in     */
X        workfile[MAXPATHLEN],   /* file to use for transmitter work file      */
X        xmitlogs[MAXPATHLEN],   /* where to log the output of transmitters    */
X        tallyfile[MAXPATHLEN],  /* where the tally file can be found          */
X        statusfile[MAXPATHLEN], /* where newsxd's status should be written    */
X        pidfile[MAXPATHLEN],    /* where newsxd's pid should be written       */
X#ifdef FAKESYSLOG
X        fakelogfile[MAXPATHLEN],/* where is the newsxd log file?              */
X#endif
X        configfile[MAXPATHLEN]; /* where is the newsxd configuration file?    */
X
X/* STRUCT OPTIONS
X * Used to define the options controlling the starting of transmitters for
X * classes and hosts.
X *
X * interval   : minimum start-to-start interval for each host's transmitter
X * startint   : minimum interval between starting transmitters in this class
X * ttl        : maximum time-to-live (secs) for a transmitter in this class
X * ttlpenalty : penalty time (secs) for a transmitter exceeding the ttl
X * deltanice  : amount to change nice before execing the transmitter
X * maxload    : maximum load where new xmitters can be started for this class
X *
X */
X
Xtypedef struct options {
X
X	int	deltanice;
X	int	interval;
X	int	startint;
X	int	ttl;
X	int	ttlpenalty;
X	int	maxload;
X	
X};
X
X/*
X * STRUCT CLASS
X * Contains the current state and description of each class of transmitters
X * that newsxd handles.
X *
X * classname  : textual name of this transmission class
X * maxxmits   : maximum number of simultaneous transmitters for this class
X * curxmits   : current number of active transmitters for this class
X * laststart  : last time a transmitter was started for this class
X * xmitsernum : transmission serial number used for fair news transmission
X * options    : defines default transmitter startup parameters for this class
X * members    : number of hosts that are a member of this class
X * flags      : special option flags for this class
X *                0 : don't rename <batchfile> to <workfile>
X *                1 : don't look for <batchfile> or <workfile>
X * xpath      : file path for an alternate transmission program
X * xargv      : arguments to be passed to the alternate transmitter
X * xargc      : number of arguments to be passed to the alternate xmitter
X * valid      : used to detect which classes are valid after a config update
X * next       : pointer to the next class descriptor in the list
X *
X */
X
Xstruct  class {
X
X        char    classname[MAXCLASSNAMELEN];
X        int     maxxmits;
X        int     curxmits;
X        int     laststart;
X        int     xmitsernum;
X        int     members;
X	struct	options	options;
X	char	slots[MAXCLASSXMITTERS];
X        int     flags[MAXCLASSFLAGS];
X	char	batchfile[MAXPATHLEN];
X	char	workfile[MAXPATHLEN];
X        char    xpath[MAXPATHLEN];
X        char    *xargv[MAXEXECARGS];
X        int     xargc;
X        char    *debugargv[MAXEXECARGS];
X        int     debugargc;
X        int     valid;
X        struct  class   *next;
X
X};
X
X/*
X * STRUCT HOST
X * Contains the current state and description of each host that newsxd
X * will be communicating with.
X *
X * hostname    : name of the host to pass to the transmitter
X * class       : name of the transmission class this host is in
X * times       : list of valid times to transmit in UUCP L.sys format
X * pid         : pid of forked transmitter
X * lasttime    : last time transmitter was forked off
X * xmitsernum  : transmission serial number used for fair news transmission
X * penaltytime : host xmitted to past ttl; secs before penalty is over
X * whynot      : why is there no transmitter running for this host NOW?
X * valid       : used to detect which hosts are valid after a config update
X * options     : defines default transmitter startup parameters for this host
X * next        : pointer to next host in the list of all hosts
X * xargv       : arguments to be passed to the transmitter
X * xargc       : number of arguments to be passed to the transmitter
X *
X */
X
Xstruct  host {
X
X        char    hostname[MAXHOSTNAMELEN];
X        char    class[MAXCLASSNAMELEN];
X        char    times[MAXTIMENAMELEN];
X        int     pid;
X        int     lasttime;
X        int     penaltytime;
X        int     xmitsernum;
X        int     whynot;
X        int     valid;
X	int	classslot;
X	struct	options	options;
X        char    *xargv[MAXEXECARGS];
X        int     xargc;
X        struct  host    *next;
X
X};
X
Xstruct  class   *classlist;
Xstruct  host    *hostlist;
X
X/* Predefine the return types of all of the functions */
X
Xvoid	addclass();
Xvoid	addhost();
Xvoid	clear_invalid();
Xvoid	daemon_start();
Xvoid	debug_off();
Xvoid	debug_on();
Xvoid	dprintf();
Xvoid	Dprintf();
Xvoid	dump_config();
Xvoid	dump_info();
Xvoid	idle();
Xvoid	reset();
Xstruct	class	*getclass();
Xvoid	freeclassslot();
Xint	getclassslot();
Xint	getla();
Xvoid	kill_children();
Xvoid	log();
Xvoid	logerr();
Xvoid	make_invalid();
Xint	parsetime();
Xvoid	processarg();
Xvoid	read_config();
Xvoid	run_queue();
Xint	validtime();
Xvoid	xmit_done();
END_OF_FILE
  if test 6742 -ne `wc -c <'defs.h'`; then
    echo shar: \"'defs.h'\" unpacked with wrong size!
  fi
  # end of 'defs.h'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
  echo shar: Extracting \"'patchlevel.h'\" \(41 characters\)
  sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define VERSION 2.5
X#define PATCHLEVEL 1
END_OF_FILE
  if test 41 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
  fi
  # end of 'patchlevel.h'
fi
if test -f 'process.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'process.c'\"
else
  echo shar: Extracting \"'process.c'\" \(20001 characters\)
  sed "s/^X//" >'process.c' <<'END_OF_FILE'
X/*
X * #include <legal/bs.h>
X >
X > Copyright (c) 1989 Washington University in Saint Louis, Missouri and
X > Chris Myers. All rights reserved.
X >
X > Permission is hereby granted to copy, reproduce, redistribute or
X > otherwise use this software as long as: (1) there is no monetary
X > profit gained specifically from the use or reproduction of this
X > software, (2) it is not sold, rented, traded, or otherwise marketed,
X > (3) the above copyright notice and this paragraph is included
X > prominently in any copy made, and (4) that the name of the University
X > is not used to endorse or promote products derived from this software
X > without the specific prior written permission of the University.
X > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X >
X */
X
X#include "defs.h"
Xextern int errno;
X
X/*************************************************************************/
X/* FUNCTION  : kill_children                                             */
X/* PURPOSE   : Kills all outstanding transmitters.  Kill_children will   */
X/*             wait thirty seconds to allow all of the transmitters to   */
X/*             exit gracefully.  If invoked by a signal (SIGTERM?), exit */
X/*             else return to caller.                                    */
X/* ARGUMENTS : Signal number or 0 if to return to caller                 */
X/*************************************************************************/
X
Xvoid
Xkill_children(sig)
X   int  sig;            /* sig will be nonzero if called by SIGTERM */
X
X{
Xstruct  host    *hostptr;
X
X   if ((hostlist == NULL) && (sig == 0)) return;
X
X   log(LOG_INFO, "newsxd: shutting down all transmitters\n");
X
X   foreach (hostptr, hostlist) {
X      if (hostptr->pid != 0) {
X         dprintf("newsxd: killing transmitter for %s\n", hostptr->hostname);
X         (void) kill (hostptr->pid, SIGTERM);
X      }
X   }
X
X   if (sig == 0) return;
X
X   dprintf("(kill_children): sleeping 30 seconds\n");
X
X   (void) sleep(30);            /* allow transmitters to quit gracefully */
X
X   log(LOG_INFO, "shut down by signal %d\n", sig);
X
X   if (debug == 0 && DEBUG == 0) {
X      (void) unlink(pidfile);
X      (void) unlink(statusfile);
X   }
X
X   (void) exit(0);              /* invoked by SIGTERM, time to quit */
X
X}
X
X/*************************************************************************/
X/* FUNCTION  : xmit_done                                                 */
X/* PURPOSE   : Catch the SIGCHLD from completed transmitters and do the  */
X/*             necessary cleanup.  Also wait synchronously for a xmitter */
X/*             to complete; also perform forced cleanup for an xmitter   */
X/* ARGUMENTS : sig, > 0 if xmit_done is called by SIGCHLD                */
X/*                 == 0 if called to check for a zombie w/NOHANG         */
X/*                 ==-1 if called to sync wait for a transmitter         */
X/*                 < -1 to perform a forced cleanup on a transmitter     */
X/*************************************************************************/
X
Xvoid
Xxmit_done(sig)
X   int  sig;                 /* sig will be nonzero if called by SIGCHLD */
X
X{
Xstruct  host    *hostptr;
Xstruct  class   *classptr;
Xunion   wait    status;
Xstruct  rusage  usage;
Xextern	char	*sys_errlist[];
X
Xint     options,
X	loop,
X        pid;
X
X   (void) sigsetmask(0);
X
X   /*
X    * Try and catch any completed transmitters first and process them.
X    * Then, if xmit_done() was called to synchronously wait on a transmitter
X    * or to perform forced cleanup on a transmitter, do it.
X    */
X
X   Dprintf("(xmit_done) sig %d\n", sig);
X
X   while (1) {
X      if (sig != -1) options = WNOHANG;
X
X      pid = wait3(&status, options, &usage);
X
X      if (pid <= 0) 
X         if (sig < -1) {
X            pid = -sig;
X            sig = 0;
X         } else {
X            Dprintf("(xmit_done) no process! pid=%d, errno=%s\n", pid,
X               sys_errlist[errno]);
X            return;
X         }
X   
X      Dprintf("(xmit_done) pid %d\n", pid);
X
X      for (loop = 0; loop < MAXXMITTERS; loop++) {
X         if (pidlist[loop] == pid) {
X            hostptr = pidmap[loop];
X            pidlist[loop] = 0;
X            pidmap[loop] = (struct host *) NULL;
X            hostptr->pid = 0;
X            hostptr->whynot = WN_NOTMYTURN;
X            foreach (classptr, classlist) {
X               if (strcmp(hostptr->class, classptr->classname) == 0) {
X                  classptr->curxmits--;
X                  freeclassslot(classptr, hostptr->classslot);
X                  dprintf("%s: transmission completed\n", hostptr->hostname);
X                  return;
X               }
X            }
X
X            /*
X             * The (sig < -1) check is here just in case a transmitter exitted
X             * normally just as run_queue tries to force a cleanup on it. If
X             * this isn't here, newsxd will abort with a corrupted data err.
X             */
X
X            if (sig < -1) return;
X
X            /* Something is seriously wrong here -- quit somewhat gracefully */
X
X            logerr("CORRUPTED HOST/CLASS STRUCTURE!\n");
X            kill_children(1);
X         }
X      }
X   }
X}
X
X/*************************************************************************/
X/* FUNCTION  : run_queue                                                 */
X/* PURPOSE   : Go through the list of hosts to transmit to and start any */
X/*             transmitter that meets all of the necessary conditions    */
X/* ARGUMENTS : none                                                      */
X/*************************************************************************/
X
Xvoid
Xrun_queue()
X
X{
Xstruct  host    *hostptr;
Xstruct  class   *classptr, *lastclass;
Xstruct  stat    statbuf;
Xstruct  tm      *curtime;
X
Xint     clock,
X        pid,
X        hadtheirchance,
X	which,
X	which2,
X        loop,
X        loop2,
X	hostargc,
X	classargc;
X
Xchar    fnbuf[MAXPATHLEN],
X        fnbuf2[MAXPATHLEN],
X	**hostargv,
X	**classargv;
X
X   CONFIGCHANGED = 0;
X   hadtheirchance = 0;
X   lastclass = (struct class *) NULL;
X
X   foreach (hostptr, hostlist) {
X
X      /*
X       * If the configuration has been changed (possibly via SIGHUP), we
X       * need to assume that all of the current pointers and such are
X       * invalid since the current host MAY have been deleted...
X       *
X       * There is still a race condition, but this check lessens the chance
X       * of problems considerably.
X       *
X       */
X
X      if (CONFIGCHANGED) {
X         dprintf("Reconfigured during queue run -- aborting queue run\n");
X         CONFIGCHANGED = 0;
X         return;
X      }
X
X      (void) time(&clock);
X      curtime = localtime(&clock);
X
X      classptr = getclass(hostptr->class);
X
X      if (classptr != lastclass) {
X         if (lastclass) {
X            dprintf("class %s: members %d, hadtheirchance %d\n",
X               lastclass->classname, lastclass->members, hadtheirchance);
X            if (lastclass->members == hadtheirchance) {
X               lastclass->xmitsernum++;
X               dprintf("class %s: add 1 to xmitsernum, now %d\n",
X                  lastclass->classname, lastclass->xmitsernum);
X            }
X         }
X         hadtheirchance = 0;
X         lastclass = classptr;
X      }
X
X      /*
X       * Check and see if we somehow missed the SIGCHLD for a transmitter and
X       * it's really gone and we don't know it.  If so, force a cleanup.
X       */
X
X      if ((hostptr->pid) && (kill(hostptr->pid, 0) == -1) && (errno == ESRCH)) {
X         xmit_done(-hostptr->pid);
X         hostptr->pid = 0;          /* Just in case xmit_done() missed it! */
X      }
X
X      /*
X       * Check to see if the host has had a transmitter running for more
X       * than the ttl of its transmission class.  If so, kill it.
X       */
X
X      which = (hostptr->options.ttl) ?
X         hostptr->options.ttl : classptr->options.ttl;
X      which2 = (hostptr->options.ttlpenalty) ?
X         hostptr->options.ttlpenalty : classptr->options.ttlpenalty;
X
X      dprintf("%s: checking ttl (%d/%d)\n", hostptr->hostname, which, which2);
X
X      if ((hostptr->pid > 0) && (clock > (hostptr->lasttime + which))) {
X         dprintf("%s: exceeded ttl, killing\n");
X         hostptr->penaltytime = clock + which2;
X         if (kill(hostptr->pid, SIGTERM) != 0) xmit_done(-hostptr->pid);
X         hostptr->whynot = WN_TTL;
X         continue;  /* skip this host to give others a chance */
X      }
X
X      /*
X       * If there is already a running transmitter for this host, skip it. We
X       * don't want more than one!
X       */
X
X      dprintf("%s: checking for active daemon (%d)\n", hostptr->hostname,
X         hostptr->pid);
X
X      if (hostptr->pid > 0) {
X         hostptr->whynot = WN_RUNNING;
X         hadtheirchance++;
X         continue;
X      }
X
X      /*
X       * Check to see if this host has already had a chance to start
X       * a transmitter.  If so, let someone else have a chance.
X       */
X
X      dprintf("%s: xmitsernum is %d, class xmitsernum is %d\n",
X         hostptr->hostname, hostptr->xmitsernum, classptr->xmitsernum);
X
X/*
X      if ((hostptr->xmitsernum == classptr->xmitsernum) &&
X          (classptr->maxxmits < classptr->members)) {
X */
X
X      if (hostptr->xmitsernum == classptr->xmitsernum) {
X         hadtheirchance++;
X/*       hostptr->whynot = WN_NOTMYTURN; */
X         continue;
X      }
X
X      /*
X       * Check the current time against the last time an xmit was started
X       * for this class to make sure we don't start too many daemons at
X       * one time.
X       */
X
X      which = (hostptr->options.startint) ?
X         hostptr->options.startint : classptr->options.startint;
X
X      dprintf("%s: checking class startup interval (clock is %d, start %d)\n",
X         hostptr->hostname, clock, (classptr->laststart + which));
X
X      if (clock < (classptr->laststart + which)) {
X         hostptr->whynot = WN_CLASSSTARTINT;
X         continue;
X      }
X
X      /*
X       * Check the current load and compare against the maximum allowed
X       * load for starting new transmitters for this hosts's class.
X       */
X
X      which = (hostptr->options.maxload) ?
X         hostptr->options.maxload : classptr->options.maxload;
X
X      dprintf("%s: checking maximum load (cur %d, max %d)\n",
X         hostptr->hostname, getla(), which);
X
X      if (getla() > which) {
X         hostptr->whynot = WN_LOAD;
X         continue;
X      }
X
X      /*
X       * Check the number of currently running transmitters for this host's
X       * transmission class.  If we're already running at the limit, skip
X       * this host.
X       */
X
X      dprintf("%s (%s): checking running xmit count (%d of %d)\n",
X         hostptr->hostname, classptr->classname, classptr->curxmits,
X         classptr->maxxmits);
X
X      if (classptr->curxmits >= classptr->maxxmits) {
X         hostptr->whynot = WN_MAXXMITS;
X         continue;
X      }
X
X      /*
X       * All tests after this point should be tests for some characteristic
X       * of the host that would cause it to avoid its turn to start its
X       * transmitter.  Things like: the host startup interval hasn't passed
X       * yet, or it's a bad time to send to that host, or there's no work
X       * to send to that host.
X       *
X       * Tests before this point should be tests for some characteristic not
X       * related to the particular host that prevents it from being able to
X       * start its transmitter.  Things like: load too high, too many xmits
X       * already running...
X       */
X
X      /*
X       * This host had a chance to send news (and can possibly skip it).
X       */
X
X      hostptr->xmitsernum = classptr->xmitsernum;
X      hadtheirchance++;
X
X      /*
X       * Check to see if the host had a transmitter killed because it ran
X       * longer than its class' ttl.  If so, see if its penalty time is
X       * still unexpired.
X       */
X
X      dprintf("%s: checking ttl penalty\n", hostptr->hostname);
X
X      if (hostptr->penaltytime > clock) {
X         hostptr->whynot = WN_PENALTYTIME;
X         continue;
X      }
X
X      /*
X       * Check the current time against the last time an xmit was started
X       * for this class to make sure we don't start a transmitter for this
X       * host too often...
X       */
X
X      which = (hostptr->options.interval) ?
X         hostptr->options.interval : classptr->options.interval;
X
X      dprintf("%s: checking host startup interval (%d)\n", hostptr->hostname,
X         which);
X
X      if (clock < (hostptr->lasttime + which)) {
X         hostptr->whynot = WN_HOSTSTARTINT;
X         continue;
X      }
X
X      /*
X       * Check to see that the current time is within the permitted range
X       * of transmission times.  If not, skip this host.
X       */
X
X      dprintf("%s: checking valid transmission times (%s)\n",
X         hostptr->hostname, hostptr->times);
X
X      if (!validtime(hostptr->times)) {
X         hostptr->whynot = WN_BADTIME;
X         continue;
X      }
X
X      /*
X       * See if there is an outstanding work file for this host, if so we
X       * just need to run a transmitter, otherwise rename the batch file
X       * to the work file and run the transmitter.
X       */
X
X      (void) sprintf(fnbuf, workfile, hostptr->hostname);
X
X      dprintf("%s: checking for workfile (%s)\n",
X            hostptr->hostname, fnbuf);
X
X      if ((loop = stat(fnbuf, &statbuf)) != 0) {
X         Dprintf("%s: stat(%s) returned %d (errno is %d)\n", hostptr->hostname,
X            fnbuf, loop, errno);
X
X         (void) sprintf(fnbuf2, batchfile, hostptr->hostname);
X
X         dprintf("%s: checking for batchfile (%s)\n",
X               hostptr->hostname, fnbuf2);
X
X         if (!classptr->flags[C_NOBATCH]) {
X            if ((loop = stat(fnbuf2, &statbuf)) != 0) {
X               Dprintf("%s: stat(%s) returned %d (errno is %d)\n",
X                  hostptr->hostname, fnbuf, loop, errno);
X
X               hostptr->whynot = WN_NOWORK;
X               continue;
X            } else {
X               hostptr->whynot = WN_RENAMEFAILED;
X               if (!classptr->flags[C_NOWORK] && rename(fnbuf2, fnbuf) != 0) {
X                  dprintf("%s: rename failed (%s to %s)\n",
X                        hostptr->hostname, fnbuf2, fnbuf);
X                  continue;
X               }
X            }
X         }
X      }
X      
X      /*
X       * Fork off a transmitter for this host
X       */
X
X      hostptr->whynot = WN_RUNNING;
X
X      if ((hostptr->classslot = getclassslot(classptr)) == -1) {
X         hostptr->whynot = WN_NOSLOT;
X         exit(1);
X      }
X
X      if ((pid = fork()) == 0) {
X	 /* Child. */
X         int fd;
X
X         /* Untrap all of the signals for newsxd; this is now a transmitter */
X
X         (void) signal(SIGCHLD, SIG_DFL);
X         (void) signal(SIGHUP, SIG_DFL);
X         (void) signal(SIGQUIT, SIG_DFL);
X         (void) signal(SIGTERM, SIG_DFL);
X         (void) signal(SIGUSR1, SIG_DFL);
X         (void) signal(SIGUSR2, SIG_DFL);
X         (void) signal(SIGIO, SIG_DFL);
X         (void) signal(SIGIOT, SIG_DFL);
X         (void) signal(SIGTRAP, SIG_DFL);
X
X         fd = open(classptr->flags[C_NOWORK] ? fnbuf2 : fnbuf, O_RDONLY);
X         if (fd > 0) (void) flock(fd, LOCK_EX);
X
X#ifdef	CNEWSLOCKING
X         if (!classptr->flags[C_NOWORK]) {
X
X            /* If we can get a valid lock then we know that since the batch
X             * file has been renamed to WORKFILE, cnews will now be writing
X             * to a different file (BATCHFILE).
X             */
X            (void) newslock();
X            (void) newsunlock();
X         }
X#endif	CNEWSLOCKING
X
X         Dprintf("(%s): classslot is %d\n", hostptr->hostname,
X            hostptr->classslot);
X
X         dprintf("%s: spawning transmitter\n", hostptr->hostname);
X
X         if (!newsxdebug) {
X            (void) sprintf(fnbuf2, xmitlogs, hostptr->hostname);
X            (void) freopen(fnbuf2, "a", stdout);
X            (void) freopen(fnbuf2, "a", stderr);
X         }
X
X         (void) fprintf(stderr, "%s: begin at %02d:%02d:%02d\n",
X            hostptr->hostname, curtime->tm_hour, curtime->tm_min,
X            curtime->tm_sec);
X         (void) fflush(stderr);
X
X         which = (hostptr->options.deltanice) ?
X            hostptr->options.deltanice : classptr->options.deltanice;
X
X         if (which != 0) {
X            Dprintf("Changing transmitter nice by %d for %s\n",
X               which, hostptr->hostname);
X
X            (void) nice(which);
X         }
X
X         if (classptr->xargc == 0) {
X            classptr = getclass("DEFAULT");
X            if (classptr->xargc == 0) {
X               logerr("host %s: No DEFAULT xmitter defined -- aborting\n",
X                  hostptr->hostname);
X               (void) _exit(1);
X            }
X         }
X
X         Dprintf("classptr->xargc = %d\n", classptr->xargc);
X
X         Dprintf("%s: EXECing %s with parameters:\n",
X            hostptr->hostname, classptr->xpath);
X
X         for (loop = 0; loop <= classptr->xargc; loop++) {
X            if (classptr->xargv[loop] == NULL) {
X               Dprintf("arg[%d] = NULL\n", loop);
X            } else {
X               Dprintf("arg[%d] = %s\n", loop, classptr->xargv[loop]);
X            }
X         }
X
X         classargc = classptr->xargc;
X         classargv = classptr->xargv;
X
X         classargv[classargc] = NULL;
X
X         for (loop = 0; loop < classargc; loop++) {
X            hostargv = NULL;
X            if (strcmp(classargv[loop], "%f") == NULL) {
X               hostargc = hostptr->xargc;
X               hostargv = hostptr->xargv;
X            }
X
X            if (strcmp(classargv[loop], "%d") == NULL) {
X               struct class *myclassptr = getclass(hostptr->class);
X               hostargc = myclassptr->debugargc;
X               hostargv = myclassptr->debugargv;
X               Dprintf("debug argc = %d\n", hostargc);
X            }
X
X            if (hostargv != NULL) {
X               if (hostargc == 0) {
X                  classargc--;
X                  for (loop2 = loop; loop2 < MAXEXECARGS-1; loop2++)
X                     classargv[loop2] = classargv[loop2 + 1];
X               } else {
X                  classargc += hostargc - 1;
X                  for (loop2 = MAXEXECARGS - hostargc; loop2 > loop; loop2--)
X                     classargv[loop2 + hostargc - 1] = classargv[loop2];
X                  for (loop2 = loop; loop2 < loop + hostargc; loop2++)
X                     classargv[loop2] = hostargv[loop2 - loop];
X                  loop += hostargc - 1;
X               }
X            }
X         }
X
X         Dprintf("(after host flag insertion) classargc = %d\n",
X            classargc);
X
X         for (loop = 0; loop <= classargc; loop++) {
X            /* WARNING: we are mangling the xargv array here! */
X            processarg(loop, hostptr, classptr);
X
X            if (classargv[loop] == NULL) {
X               Dprintf("arg[%d] = NULL\n", loop);
X            } else {
X               Dprintf("arg[%d] = %s\n", loop, classargv[loop]);
X            }
X         }
X
X         (void) execvp(classptr->xpath, classargv);
X
X         logerr("%s: can't exec %s\n", hostptr->hostname, classptr->xpath);
X
X         (void) _exit(1); /* could not exec the news transmitter! */
X      } else {
X	 /* Parent. */
X	 if (pid == -1) {
X	    logerr("host %s: Can't fork child.\n", hostptr->hostname);
X	    continue;
X	 }
X         for (loop = 0; loop < MAXXMITTERS; loop++) {
X            if (pidlist[loop] == 0) {
X               pidlist[loop] = pid;
X               pidmap[loop] = hostptr;
X               Dprintf("%s: entered into pidmap/list at %d\n",
X                  hostptr->hostname, loop);
X               break;
X            }
X         }
X         hostptr->pid = pid;
X         hostptr->lasttime = clock;
X         classptr->laststart = clock;
X         classptr->curxmits++;
X         if (newsxdebug) xmit_done(-1); /* wait for xmitter to complete */
X      }
X   }
X
X   if (classptr->members == hadtheirchance) {
X      dprintf("class %s: add 1 to sernum (members %d, hadchance %d)\n",
X         classptr->classname, classptr->members, hadtheirchance);
X      classptr->xmitsernum++;
X   }
X}
END_OF_FILE
  if test 20001 -ne `wc -c <'process.c'`; then
    echo shar: \"'process.c'\" unpacked with wrong size!
  fi
  # end of 'process.c'
fi
if test -f 'simple.conf' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'simple.conf'\"
else
  echo shar: Extracting \"'simple.conf'\" \(1073 characters\)
  sed "s/^X//" >'simple.conf' <<'END_OF_FILE'
X# Define a service class that just runs an nntpxmit to each host
X# every hour.  Don't run nntpxmit if the load goes over 8.
X
Xclass   normal  maxxmits=1  interval=3600  maxload=8
X
X# Define the default news transmitter
Xxmit    DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %h:%w
X
X# Check the list of hosts every 10 minutes to see if we can send news to
X# someone yet.
Xqueueinterval    600
X
X# In all of the following options, %s is replaced by the host name of the
X# system being sent to.
X
X# File news places articles paths/ids in
Xbatchfile   /usr/spool/batch/%s
X
X# File a news transmitter wants articles paths/ids in
Xworkfile    /usr/spool/batch/%s.work
X
X# Hosts to send news to.  Each line is of the format:
X#                            CLASS   VALID START
X# host HOSTNAME              NAME       TIMES
X
Xhost dorothy                 normal      Any
Xhost toto                    normal      Any
Xhost wizard                  normal      Any
Xhost witch                   normal      Any
Xhost tinman                  normal      Any
Xhost lion                    normal      Any
END_OF_FILE
  if test 1073 -ne `wc -c <'simple.conf'`; then
    echo shar: \"'simple.conf'\" unpacked with wrong size!
  fi
  # end of 'simple.conf'
fi
if test -f 'util.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util.c'\"
else
  echo shar: Extracting \"'util.c'\" \(10869 characters\)
  sed "s/^X//" >'util.c' <<'END_OF_FILE'
X/*
X * #include <legal/bs.h>
X >
X > Copyright (c) 1989 Washington University in Saint Louis, Missouri and
X > Chris Myers. All rights reserved.
X >
X > Permission is hereby granted to copy, reproduce, redistribute or
X > otherwise use this software as long as: (1) there is no monetary
X > profit gained specifically from the use or reproduction of this
X > software, (2) it is not sold, rented, traded, or otherwise marketed,
X > (3) the above copyright notice and this paragraph is included
X > prominently in any copy made, and (4) that the name of the University
X > is not used to endorse or promote products derived from this software
X > without the specific prior written permission of the University.
X > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X >
X */
X
X#include "defs.h"
X
X/*************************************************************************/
X/* FUNCTION  : daemon_start                                              */
X/* PURPOSE   : To disassociate newsxd from the calling process so it can */
X/*             run as a daemon.                                          */
X/* ARGUMENTS : none                                                      */
X/*************************************************************************/
X
Xvoid
Xdaemon_start()
X
X{
Xregister int    childpid, fd;
Xextern   int    errno;
X
X   /* Ignore the terminal stop signals */
X   (void) signal(SIGTTOU, SIG_IGN);
X   (void) signal(SIGTTIN, SIG_IGN);
X   (void) signal(SIGTSTP, SIG_IGN);
X
X   /* Fork and let the parent process exit */
X   if ((childpid = fork()) < 0) {
X      logerr("newsxd: can't fork to enter daemon mode\n");
X      (void) exit(1);
X   } else if (childpid > 0) exit(0);
X
X   /* Lose the process group */
X   if (setpgrp(0, getpid()) == -1) {
X      logerr("newsxd: can't change pgrp to enter daemon mode\n");
X      (void) exit(1);
X   }
X
X   /* Lose the controlling terminal */
X   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
X      (void) ioctl(fd, TIOCNOTTY, (char *) NULL);
X      (void) close(fd);
X   }
X
X   /* Close any open files */
X   for (fd = 0; fd < NOFILE; fd++) (void) close(fd);
X   errno = 0;
X
X   /* Set a proper default umask */
X   (void) umask(022);
X}
X
X/*************************************************************************/
X/* FUNCTION  : getla                                                     */
X/* PURPOSE   : Return the current system load                            */
X/* ARGUMENTS : none                                                      */
X/* NOTES     : this code stolen from sendmail 5.61 which stole it from   */
X/*             from something else...                                    */
X/*************************************************************************/
X
Xint
Xgetla()
X
X{
X#if defined(sun) | defined(mips)
Xlong    avenrun[3];
X#else
Xdouble  avenrun[3];
X#endif
Xextern  off_t lseek();
Xstatic  int     kmem = -1;
X
Xstatic	struct  nlist Nl[] =
X{
X        { "_avenrun" },
X#define X_AVENRUN       0
X        { 0 },
X};
X
X
X   if (kmem < 0) {
X      kmem = open("/dev/kmem", 0, 0);
X      if (kmem < 0) return (-1);
X      (void) ioctl(kmem, (int) FIOCLEX, (char *) 0);
X      (void) nlist("/vmunix", Nl);
X      if (Nl[0].n_type == 0) return (-1);
X   }
X
X   if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
X       read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
X   {
X      /* thank you Ian */
X      return (-1);
X   }
X#ifdef sun
X   return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
X#else
X#ifdef mips
X   return (FIX_TO_INT(avenrun[0]));
X#else
X   return ((int) (avenrun[0] + 0.5));
X#endif
X#endif
X}
X
X/*************************************************************************/
X/* FUNCTION  : processarg                                                */
X/* PURPOSE   : Do %value substitutions in xargv                          */
X/* ARGUMENTS : which value of argv to modify, hostptr, classptr          */
X/*************************************************************************/
X
Xvoid
Xprocessarg(which, hostptr, classptr)
X   int  which;
X   struct host  *hostptr;
X   struct class *classptr;
X
X{
Xchar    buf1[MAXPATHLEN],
X        buf2[MAXPATHLEN],
X        charbuf[2],
X        *newxargv,
X        *strptr;
X
X   if (classptr->xargv[which] == NULL) return;
X
X   charbuf[1] = '\0';
X   *buf1 = '\0';
X
X   for (strptr = classptr->xargv[which]; *strptr != '\0'; strptr++) {
X      if (*strptr != '%') {
X         charbuf[0] = *strptr;
X         (void) strcat(buf1, charbuf);
X      } else {
X         strptr++;
X         switch (*strptr) {
X            case 'h': (void) strcat(buf1, hostptr->hostname);
X                      break;
X            case 'f': (void) strcat(buf1, "%f");
X                      /* We shouldn't have seen a %f at this point! */
X                      break;
X            case 'd': (void) strcat(buf1, "%d");
X                      /* We shouldn't have seen a %d at this point! */
X                      break;
X            case 'b': (void) sprintf(buf2, batchfile, hostptr->hostname);
X                      (void) strcat(buf1, buf2);
X                      break;
X            case 'w': if (classptr->flags[C_NOWORK])
X                         (void) sprintf(buf2, batchfile, hostptr->hostname);
X                      else
X                         (void) sprintf(buf2, workfile, hostptr->hostname);
X                      (void) strcat(buf1, buf2);
X                      break;
X            case 's': (void) sprintf(buf2, "%d", hostptr->classslot);
X                      (void) strcat(buf1, buf2);
X                      break;
X            case '%': (void) strcat(buf1, "%"); /* %% changes to % */
X                      break;
X            default : strptr--;
X         }
X      }
X   }
X
X   newxargv = (char *) malloc(strlen(buf1) + 1);
X   (void) strcpy(newxargv, buf1);
X   classptr->xargv[which] = newxargv;
X
X}
X
X/*************************************************************************/
X/* FUNCTION  : parse_time                                                */
X/* PURPOSE   : Check a single valid-time-string against the current time */
X/*             and return whether or not a match occurs.                 */
X/* ARGUMENTS : a pointer to the time-string                              */
X/*************************************************************************/
X
Xint
Xparsetime(whattime)
Xchar    *whattime;
X
X{
Xstatic char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk" };
Xlong    clock;
Xstruct  tm *curtime;
Xint     wday, start, stop, ltime, validday, loop, match;
X
X   (void) time(&clock);
X   curtime = localtime(&clock);
X   wday = curtime->tm_wday;
X   validday = 0;
X   match = 1;
X
X   while (match && isalpha(*whattime) && isupper(*whattime)) {
X      match = 0;
X      for (loop = 0; loop < 8; loop++) {
X         if (strncmp(days[loop], whattime, 2) == NULL) {
X            whattime += 2;
X            match = 1;
X            if ((wday == loop) | ((loop == 7) && wday && (wday < 6))) {
X               validday = 1;
X            }
X         }
X      }
X   }
X
X   if (strncmp(whattime, "Any", 3) == NULL) {
X      validday = 1;
X      whattime += 3;
X   }
X
X   if (!validday) return 0;
X
X   if (sscanf(whattime, "%d-%d", &start, &stop) == 2) {
X      ltime = curtime->tm_min + 100 * curtime->tm_hour;
X      if ((start < stop) && ((ltime > start) & ltime < stop)) return 1;
X      if ((start > stop) && ((ltime > start) | ltime < stop)) return 1;
X   } else return 1;
X
X   return 0;
X}
X
X/*************************************************************************/
X/* FUNCTION  : validtime                                                 */
X/* PURPOSE   : Break apart a set of valid time-strings and pass them to  */
X/*             parse_time, returning whether or not ANY matches occurred */
X/* ARGUMENTS : a pointer to the time-string                              */
X/*************************************************************************/
X
Xint
Xvalidtime(ptr)
Xchar    *ptr;
X
X{
Xchar    *nextptr;
Xint	good;
X
X   while (1) {
X      nextptr = STRCHR(ptr, '|');
X      if (STRCHR(ptr, '|') == NULL) return(parsetime(ptr));
X      *nextptr = '\0';
X      good = parsetime(ptr);
X      *nextptr++ = '|';  /* gotta restore the | or things get skipped! */
X      if (good) return(1);
X      ptr = nextptr;
X   }
X}
X
X/*************************************************************************/
X/* FUNCTION  : getclassslot                                              */
X/* PURPOSE   :                                                           */
X/* ARGUMENTS : a pointer to the class structure                          */
X/* RETURNS   : the slot number                                           */
X/*************************************************************************/
X
Xint	getclassslot(classptr)
Xstruct	class	*classptr;
X
X{
Xint	loop;
X
X   for (loop = 0; loop < MAXCLASSXMITTERS; loop++)
X      if (classptr->slots[loop] != 'X') {
X         classptr->slots[loop] = 'X';
X         return loop;
X      }
X
X   logerr("(getclassslot) Too many xmitters for class %s", classptr->classname);
X   return -1;
X
X}
X
X/*************************************************************************/
X/* FUNCTION  : freeclassslot                                             */
X/* PURPOSE   :                                                           */
X/* ARGUMENTS : slot number to free and a pointer to the class structure  */
X/*************************************************************************/
X
Xvoid	freeclassslot(classptr, slot)
Xstruct	class	*classptr;
Xint		slot;
X
X{
X
X   classptr->slots[slot] = '.';
X
X}
X
X/*************************************************************************/
X/* FUNCTION  : idle                                                      */
X/* PURPOSE   : Set newsxd to idle mode.  Don't process xmitter queue...  */
X/* ARGUMENTS : none                                                      */
X/*************************************************************************/
X
Xvoid
Xidle()
X
X{
X
X   daemon_idle = 1;
X
X}
X
X/*************************************************************************/
X/* FUNCTION  : reset                                                     */
X/* PURPOSE   : Kill all outstanding transmitters and idle newsxd.        */
X/* ARGUMENTS : none                                                      */
X/*************************************************************************/
X
Xvoid
Xreset()
X
X{
X
X   kill_children(0);
X   daemon_idle = 1;
X
X}
X
X#ifdef CNEWSLOCKING
X
X/*************************************************************************/
X/* FUNCTION  : unprivileged                                              */
X/* PURPOSE   : keep the cnews libraries happy.                           */
X/* ARGUMENTS : none used.                                                */
X/*************************************************************************/
X
Xint
Xunprivileged(reason)
Xchar	*reason;
X{
X
X}
X
X#endif CNEWSLOCKING
END_OF_FILE
  if test 10869 -ne `wc -c <'util.c'`; then
    echo shar: \"'util.c'\" unpacked with wrong size!
  fi
  # end of 'util.c'
fi
if test -f 'version.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'version.c'\"
else
  echo shar: Extracting \"'version.c'\" \(10181 characters\)
  sed "s/^X//" >'version.c' <<'END_OF_FILE'
X/*
X * #include <legal/bs.h>
X >
X > Copyright (c) 1989 Washington University in Saint Louis, Missouri and
X > Chris Myers. All rights reserved.
X >
X > Permission is hereby granted to copy, reproduce, redistribute or
X > otherwise use this software as long as: (1) there is no monetary
X > profit gained specifically from the use or reproduction of this
X > software, (2) it is not sold, rented, traded, or otherwise marketed,
X > (3) the above copyright notice and this paragraph is included
X > prominently in any copy made, and (4) that the name of the University
X > is not used to endorse or promote products derived from this software
X > without the specific prior written permission of the University.
X > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X >
X * newsxd: a daemon for controlling the transmission of news
X *
X * Written by
X * Chris Myers                              Internet: chris@wugate.wustl.edu
X * Software Engineer                            UUCP: ...!uunet!wugate!chris
X * Office of the Network Coordinator              BITNET: chris@wunet.bitnet
X * Washington University in Saint Louis
X *
X * HISTORY:
X * Version 0.1:   first written in perl.  A grand experiment that just didn't
X *                work very reliably (no reflection on the quality of perl, it
X *                just wasn't meant to do this kind of thing).
X *
X * Version 1.0:   first C version
X *
X *         1.1:   added per-host locking
X *         1.2:   added maxload qualifier
X *         1.2.1: added time to live qualifier
X *
X *                SOURCE CODE INADVERTANTLY DESTROYED (SIGH)
X *                Oh well, it needed rewriting anyway. :-)
X *
X * Version 2.0:   here we go again. No per-host locking right now :-(
X *                Removed all static limits on the number of transmission
X *                classes and hosts.  Everything is now malloc'ed.
X *         2.0.1: added penalty time to time-to-live qualifier to allow other
X *                hosts to get news transmitters started.
X *         2.1:   Added the capability to specify a different transmission
X *                program (and parameters) for each transmission class.  This
X *                was the motive for the name change from nntpxd to newsxd.
X *         2.1.1: fixed bug caused by defunct transmitters which finally
X *                overran the ttl (did not do proper cleanup).
X *         2.1.2: added patches for Pyramid and BSD 4.3 support from Warren
X *                Lavallee and Jim Lowe.
X *         2.1.3: fixed bugs in calculating the ttl penalty and start/stop
X *                time ranges
X *         2.1.4: fixed bug in read_config where the loop went 1 past the end
X *                of the options for a transmission class.  This could cause
X *                the last parameter on a longer preceeding class line to be
X *                carried over to the subsequent classes.
X *         2.1.5: somehow the default value for nntplogs slipped away from the
X *                code.  Put it back in where it belongs.
X *         2.1.6: added inter-host startup interval for classes so that newsxd
X *                doesn't start up too many daemons at once
X *         2.1.7: fix stupid bug created in earlier patch where I set argptr[x]
X *                to NULL (what it was supposed to be) and then blithly reset it
X *                to something else -- preventing EXECing the program specified
X *                in an XMIT option.  ARGH.
X *         2.1.8: ARGH! Left out the code to make sure a transmitter for each
X *                host wasn't started up more often than <interval> seconds.
X *         2.2:   Cut down on the size of the wishlist by adding a bunch of
X *                features (and hopefully no more bugs):
X *                - syslog logging
X *                - lots of range/value checking on inputs
X *                - sort host/class names when inserting into list
X *                - move all configuration parameters into newsxd.h
X *                - add more error messages
X *                - document code even more
X *                - allow reconfiguration without killing outstanding xmitters
X *                - add a 'nobatchfile' switch
X *                - allocation of alternate xmitter parameters is now dynamic
X *                - Per-host delta-nice values for transmitters
X *                - make code more readable
X *                - write a manpage
X *         2.3:   Add SIGUSR1, SIGUSR2 to {en,dis}able debugging while running
X *                Shift the order of syslog initialization and switch to daemon
X *                Fix a "go past end of the array sometimes" bug in getclass().
X *                add "reason" to status display to show why xmitter not running
X *                in xmit options, %f=flags,%w=workfile,%b=batchfile,%h=hostname
X *                make transmission of news to hosts 'fair'
X *                minimize a race in run_queue if SIGQUIT causes reconfiguration
X *                change start/stop times to use UUCP-style permissible times
X *         2.3.1: fix bug in incr xmitsernum when only one service class in use
X *                enable fair transmission code even if maxxmits > class members
X *                change use of strpbrk to strchr and make strchr #define'd
X *         2.4:   add per-host flags
X *                added check for multiply-defined host/class in add{host,class}
X *                zero classptr->members in addclass to allow reconfiguration
X *         2.4.1: classptr->members++ in addhost was in the wrong spot
X *                buffer declaration for FAKESYSLOG had trailing ; should be ,
X *                log a reinitialization message after getting SIGHUP
X *                add -v switch to show version and logging
X *                if debugging == ON in daemon mode, don't dump status to stderr
X *                was closing pidfile with close() rather than fclose()
X *                change comments in xmit_done() to show sig==0 is NOHANG
X *                validtime() was mangling the valid times string
X *                parsetime() sometimes said a good time was not valid
X *                addhost() now resorts host list on reconfiguration
X *         2.4.2: modify xmit_done() to almost always use WNOHANG on wait calls
X *                add_host() was improperly decrementing classptr->members
X *                When debugging changes, log "On"/"Off" not the value (0/-1)
X *                get rid of remaining code for obsolete "nntpxmit" keyword
X *                finish updating comments, changing "nntpxmit" to "transmitter"
X *         2.5:   sigsetmask(0) to allow SIGCHLD in xmit_done(); don't lose kids
X *                modify "Why Not Running" messages slightly for readability
X *                xmit_done() now loops to catch all completed transmitters
X *                run_queue() now checks for MIA transmitters and cleans 'em up
X *                if no classes defined, dump_config() now returns immediately
X *                break the source apart into several files from one big'un
X *                class options are default, w/host options overriding
X *                   [ttl, interval, nice, maxload]
X *                run_queue() was setting whynotrunning wrong for active xmits
X *                moved ttl penalty check into "host gave up chance" code to
X *                   prevent a penalized host from blocking others
X *                added SIGIO to idle newsxd until SIGHUP is received
X *                added class slots
X *                added faster pid->host mapping data structure
X *                added SIGTRAP to dump internal data structures for debugging
X *         2.5.1: apply "lint" fixes from Andrew Partan <asp@uunet.uu.net>
X *                close and reopen logfiles on SIGHUP <asp@uunet.uu.net>
X *                put Why Not reasons in static array, use everywhere
X *                process.c: in fork()ed child, call _exit() not exit()
X *                check for duplicate newsxd running
X *                add support for per-class transmitter debugging flags
X *                fix an open file leak in config.c:read_config()
X *                add SIGIOT to kill all transmitters and idle newsxd
X *                add setuid(geteuid()), setgid(getegid()) in main()
X *                fix some potential null-ptr dereferencing problems in config.c
X *                fix array-index overrun problem in config.c <asp@uunet.uu.net>
X *                remove pidfile and statusfile on shutdown unless debug|DEBUG
X *                flock() the work file before EXECing the transmitter
X *                support CNEWS-style locking to prevent races on the work file
X *                restore default signal action after fork() for transmitter
X *
X * SPECIAL THANKS TO:
X *
X * Alpha tester:  John Coolidge <coolidge@brutus.cs.uiuc.edu>
X *
X * Beta testers:  Warren Lavallee <warren@schizo.samsung.com>
X *                Don Thomson <thomson@macc.wisc.edu>
X *                Michael A. Cooper <mcooper@usc.edu>
X *                Jim Lowe <james@csd4.csd.uwm.edu>
X *                David C. Lawrence <tale@pawl.rpi.edu>
X *                John Coolidge <coolidge@brutus.cs.uiuc.edu>
X *                Lloyd W. Taylor <lloyd@aplcen.apl.jhu.edu>
X *                Dave Alden <alden@shape.mps.ohio-state.edu>
X *                Greg Hackney <root@texbell.sbc.com>
X *                Rick Adams <rick@uunet.uu.net>
X *                Andrew Partan <asp@uunet.uu.net>
X *
X * This software has been tested on the following systems:
X *
X * DECstation 3100, Ultrix 3.1
X * DEC VAX 8810, Ultrix 3.1
X * Sun 3/60, SunOS 4.0.1
X * Sun 3/180, SunOS 4.0.3
X * Pyramid DualPort OSx
X * DEC MicroVAX-II, BSD 4.3 UNIX
X * DEC MicroVAX-II, Mt Xinu MORE/BSD 4.3
X *
X * Wishlist:
X *
X * - add logging of transmitter resource usage
X * - Exponential backoff for failed transmission attempts
X * - Per-host locking, using shlock-style locks
X * - ability to specify min. # of articles queued before xmission starts
X * - add per-class workfile and batchfile definitions
X * - add per-host maximum delay between transmitter startups
X *
X */
END_OF_FILE
  if test 10181 -ne `wc -c <'version.c'`; then
    echo shar: \"'version.c'\" unpacked with wrong size!
  fi
  # end of 'version.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.