#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # Makefile # config.c # log.c # main.c # process.c # util.c # version.c # defs.h # newsxd.h # patchlevel.h # complex.conf # newsxd.conf # simple.conf # newsxd.8 # This archive created: Tue May 29 09:52:34 1990 export PATH; PATH=/bin:$PATH if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' The newsxd program is a configurable daemon for controlling the transmission of netnews. It allows the definition of multiple categories of service, by setting a number of parameters defining things such as how often news is to be transmitted, the number of news transmitters that can be active at one time, the maximum time a transmitter may spend sending netnews to a single host, and the maximum system load at which netnews transmitters may be started. newsxd can also be used to start up other programs which must be restarted upon exit, or which must be run at regular intervals with greater granularity than cron(8) allows. newsxd Installation To compile newsxd, you need to do the following things: 1) Edit newsxd.h, and make any changes necessary to the default locations for the newsxd data files. Also select whether you want to have newsxd log to syslog or to it's own log file. 2) Edit the Makefile and define the correct locations to store newsxd and it's manpage on your system. 3) make depend 4) make install 5) Create a newsxd.conf file and install it in the appropriate location (the default is /usr/local/etc/newsxd.conf). Sample configuration files are included as complex.conf and simple.conf. 6) Turn off any nntpxmit's, sendbatch's, etc. so they don't conflict with the ones started by newsxd. 7) Run newsxd SHAR_EOF chmod +x 'README' fi # end of overwriting check if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # 1. If the compiler complains about undefined structs, try removing the # -DBSD4_2 in CFLAGS, below. # # 2. If the linker complains that it can't find 'index', change -DSTRCHR=index # to -DSTRCHR=strchr in CFLAGS, below. CFLAGS= -O -DBSD4_2 -DSTRCHR=index LINTFLAGS= -abchx CC= cc LIBS= -lcnews # The uid and gid that newsxd (and the news transmitters) should run as OWNER=news GROUP=news # Where to put newsxd when it's compiled BINDIR=/usr/local/etc # Where to put the manpage and the manual section it's going into MANDIR=/usr/man/manl MANEXT=l SRCS= config.c log.c main.c process.c util.c OBJS= config.o log.o main.o process.o util.o all: newsxd newsxd: ${OBJS} ${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS} clean: rm -f ${OBJS} newsxd core depend: ${SRCS} mkdep ${CFLAGS} ${SRCS} install: newsxd newsxd.8 install -c -m 444 -o root -g staff newsxd.8 ${MANDIR}/newsxd.${MANEXT} install -s -c -m 6755 -o ${OWNER} -g ${GROUP} newsxd ${BINDIR} shar: shar README Makefile *.c *.h *.conf newsxd.8 > newsxd.shar lint: ${SRCS} lint ${LINTFLAGS} ${CFLAGS} ${SRCS} # DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. config.o: config.c defs.h /usr/include/stdio.h /usr/include/signal.h config.o: /usr/include/strings.h /usr/include/syslog.h /usr/include/nlist.h config.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/sys/param.h config.o: /usr/include/machine/param.h /usr/include/signal.h config.o: /usr/include/sys/types.h /usr/include/sys/errno.h config.o: /usr/include/sys/file.h /usr/include/sys/types.h config.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h config.o: /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h config.o: /usr/include/sgtty.h /usr/include/sys/wait.h /usr/include/sys/types.h config.o: /usr/include/sys/stat.h newsxd.h patchlevel.h /usr/include/time.h config.o: /usr/include/sys/resource.h /usr/include/sys/../h/fixpoint.h log.o: log.c defs.h /usr/include/stdio.h /usr/include/signal.h log.o: /usr/include/strings.h /usr/include/syslog.h /usr/include/nlist.h log.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/sys/param.h log.o: /usr/include/machine/param.h /usr/include/signal.h log.o: /usr/include/sys/types.h /usr/include/sys/errno.h log.o: /usr/include/sys/file.h /usr/include/sys/types.h log.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h log.o: /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h /usr/include/sgtty.h log.o: /usr/include/sys/wait.h /usr/include/sys/types.h /usr/include/sys/stat.h log.o: newsxd.h patchlevel.h /usr/include/time.h /usr/include/sys/resource.h log.o: /usr/include/sys/../h/fixpoint.h main.o: main.c defs.h /usr/include/stdio.h /usr/include/signal.h main.o: /usr/include/strings.h /usr/include/syslog.h /usr/include/nlist.h main.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/sys/param.h main.o: /usr/include/machine/param.h /usr/include/signal.h main.o: /usr/include/sys/types.h /usr/include/sys/errno.h main.o: /usr/include/sys/file.h /usr/include/sys/types.h main.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h main.o: /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h /usr/include/sgtty.h main.o: /usr/include/sys/wait.h /usr/include/sys/types.h main.o: /usr/include/sys/stat.h newsxd.h patchlevel.h /usr/include/time.h main.o: /usr/include/sys/resource.h /usr/include/sys/../h/fixpoint.h process.o: process.c defs.h /usr/include/stdio.h /usr/include/signal.h process.o: /usr/include/strings.h /usr/include/syslog.h /usr/include/nlist.h process.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/sys/param.h process.o: /usr/include/machine/param.h /usr/include/signal.h process.o: /usr/include/sys/types.h /usr/include/sys/errno.h process.o: /usr/include/sys/file.h /usr/include/sys/types.h process.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h process.o: /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h process.o: /usr/include/sgtty.h /usr/include/sys/wait.h process.o: /usr/include/sys/types.h /usr/include/sys/stat.h newsxd.h process.o: patchlevel.h /usr/include/time.h /usr/include/sys/resource.h process.o: /usr/include/sys/../h/fixpoint.h util.o: util.c defs.h /usr/include/stdio.h /usr/include/signal.h util.o: /usr/include/strings.h /usr/include/syslog.h /usr/include/nlist.h util.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/sys/param.h util.o: /usr/include/machine/param.h /usr/include/signal.h util.o: /usr/include/sys/types.h /usr/include/sys/errno.h util.o: /usr/include/sys/file.h /usr/include/sys/types.h util.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h util.o: /usr/include/sys/ttydev.h /usr/include/sys/ttyio.h /usr/include/sgtty.h util.o: /usr/include/sys/wait.h /usr/include/sys/types.h util.o: /usr/include/sys/stat.h newsxd.h patchlevel.h /usr/include/time.h util.o: /usr/include/sys/resource.h /usr/include/sys/../h/fixpoint.h version.o: version.c # IF YOU PUT ANYTHING HERE IT WILL GO AWAY SHAR_EOF chmod +x 'Makefile' fi # end of overwriting check if test -f 'config.c' then echo shar: will not over-write existing file "'config.c'" else cat << \SHAR_EOF > 'config.c' /* * #include > > Copyright (c) 1989 Washington University in Saint Louis, Missouri and > Chris Myers. All rights reserved. > > Permission is hereby granted to copy, reproduce, redistribute or > otherwise use this software as long as: (1) there is no monetary > profit gained specifically from the use or reproduction of this > software, (2) it is not sold, rented, traded, or otherwise marketed, > (3) the above copyright notice and this paragraph is included > prominently in any copy made, and (4) that the name of the University > is not used to endorse or promote products derived from this software > without the specific prior written permission of the University. > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. > */ #include "defs.h" /*************************************************************************/ /* FUNCTION : getclass */ /* PURPOSE : Return a pointer to the class structure given the name of */ /* a class */ /* ARGUMENTS : The name of a class */ /*************************************************************************/ struct class * getclass(classname) char *classname; { struct class *classptr; if (strlen(classname) > MAXCLASSNAMELEN - 1) { Dprintf("(getclass): classname %s is too long, no match\n", classname); return((struct class *) NULL); } foreach (classptr, classlist) { Dprintf("(getclass): now checking class %s\n", classptr->classname); if (strcmp(classname, classptr->classname) == 0) break; } return(classptr); } /*************************************************************************/ /* FUNCTION : addclass */ /* PURPOSE : Add a class to or modify a class in the class list */ /* ARGUMENTS : All the information needed to define a class... */ /*************************************************************************/ void addclass(classname,maxxmits,interval,startint,maxload,ttl,ttlpenalty,nice,flags, debugflags) char *classname, *debugflags; int maxxmits, interval, startint, maxload, ttl, ttlpenalty, nice, flags; { struct class *classptr = classlist; char *flagbuf; int loop, newclass = 0; if (strlen(classname) > MAXCLASSNAMELEN - 1) { logerr("(addclass) Class name %s too long, max %d - ignoring\n", classname, MAXCLASSNAMELEN - 1); return; } if ((classptr = getclass(classname)) == NULL) { Dprintf("(addclass): CALLOCing new class structure\n"); classptr = (struct class *) calloc(1, sizeof(struct class)); if (classptr == NULL) { logerr("(addclass) Can't calloc struct class for class %s\n", classname); return; } for (loop = 0; loop < MAXCLASSXMITTERS; loop++) classptr->slots[loop] = '.'; newclass++; } else if (classptr->valid == 1) { logerr("(addclass) Duplicated class %s\n", classname); return; } /* * Build class structure for this class and insert at the head of the * class list */ (void) strcpy(classptr->classname, classname); classptr->maxxmits = maxxmits; classptr->options.maxload = maxload; classptr->options.interval = interval; classptr->options.startint = startint; classptr->options.ttl = ttl; classptr->options.deltanice = nice; classptr->options.ttlpenalty = ttlpenalty; classptr->valid = 1; classptr->xmitsernum = 0; classptr->members = 0; classptr->debugargc = 0; if (debug && strlen(debugflags) > 0) { if ((flagbuf = (char *) calloc(1, strlen(debugflags) + 1)) != NULL) { (void) strcpy(flagbuf, debugflags); while (1) { classptr->debugargv[classptr->debugargc++] = flagbuf; if ((flagbuf = STRCHR(flagbuf, '|')) == (char *) NULL) break; *flagbuf++ = '\0'; } Dprintf("(addclass) %s: debugargc = %d\n", classname, classptr->debugargc); } } /* * Set all of the class flags. flag is a bitmap. */ for (loop = 0; loop < MAXCLASSFLAGS; loop++) { if (flags & (1 << loop)) classptr->flags[loop] = 1; else classptr->flags[loop] = 0; Dprintf("(addclass): flags[%d] = %d\n", loop, classptr->flags[loop]); } /* * Check to see if we are just overwriting a class description, if so don't * wipe the pointer to the next entry in the list. */ if (newclass) { classptr->next = classlist; classlist = classptr; } Dprintf("(addclass): classlist = %d\n", classlist); } /*************************************************************************/ /* FUNCTION : addhost */ /* PURPOSE : Add a host to the list of hosts to transmit to */ /* ARGUMENTS : Name of the host, class name, start and stop times */ /*************************************************************************/ void addhost(hostname, classname, times, deltanice, maxload, interval, startint, ttl, ttlpenalty, flags) char *hostname, *classname, *times, *flags; int deltanice, maxload, interval, startint, ttl, ttlpenalty; { struct host *hostptr, *loopptr, *lastptr = NULL; struct class *classptr; int loop; char *flagbuf; if (strlen(hostname) > MAXHOSTNAMELEN - 1) { logerr("(addhost) Host name %s too long, max %d - ignoring\n", classname, MAXHOSTNAMELEN - 1); return; } if (strlen(times) > MAXTIMENAMELEN - 1) { logerr("(addhost) Host time %s too long, max %d - ignoring\n", classname, MAXTIMENAMELEN - 1); return; } if ((classptr = getclass(classname)) == NULL) { logerr("(addhost) Host's (%s) class %s doesn't exist - ignoring host\n", hostname, classname); return; } if (classptr->valid == 0) { logerr("(addhost) Host's (%s) class %s is invalid - ignoring host\n", hostname, classname); return; } if (strcmp(classname, "DEFAULT") == 0) { logerr("(addhost) Host (%s) can't be a member of class DEFAULT\n", hostname); return; } lastptr = NULL; foreach (hostptr, hostlist) { Dprintf("(addhost): now checking host %s\n", hostptr->hostname); if (strcmp(hostname, hostptr->hostname) == 0) break; lastptr = hostptr; } if (hostptr != NULL) { if (hostptr->valid == 1) { logerr("(addhost) Duplicated host %s\n", hostname); return; } if (lastptr != NULL) { lastptr->next = hostptr->next; Dprintf("(addhost) host %s next was %s, now %s\n", lastptr->hostname, hostptr->hostname, hostptr->next ? hostptr->next->hostname : NULL); } else hostlist = hostptr->next; } else { Dprintf("(addhost): CALLOCing new host structure\n"); hostptr = (struct host *) calloc(1, sizeof(struct host)); if (hostptr == NULL) { logerr("(addhost) Can't calloc struct host for host %s\n", hostname); return; } } (void) strcpy(hostptr->hostname, hostname); (void) strcpy(hostptr->class, classname); (void) strcpy(hostptr->times, times); hostptr->valid = 1; hostptr->options.deltanice = deltanice; hostptr->options.maxload = maxload; hostptr->options.interval = interval; hostptr->options.startint = startint; hostptr->options.ttl = ttl; hostptr->options.ttlpenalty = ttlpenalty; hostptr->xmitsernum = 0; hostptr->xargc = 0; classptr->members++; if (flags && strlen(flags) > 0) { if ((flagbuf = (char *) calloc(1, strlen(flags) + 1)) != NULL) { (void) strcpy(flagbuf, flags); while (1) { hostptr->xargv[hostptr->xargc++] = flagbuf; if ((flagbuf = STRCHR(flagbuf, '|')) == (char *) NULL) break; *flagbuf++ = '\0'; } } } for (loop = 0; loop < hostptr->xargc; loop++) Dprintf("host %s: flag[%d] = %s\n", hostname, loop, hostptr->xargv[loop]); /* * If this is a new host, do a two-key insertion sort based on the * hostname and name of the transmission class. Makes things look nice * in the status display... */ lastptr = NULL; if (hostlist == NULL) { Dprintf("(addhost): %s IS hostlist now\n", hostname); hostlist = hostptr; } else { foreach (loopptr, hostlist) { if (((strcmp(hostptr->hostname, loopptr->hostname) < 0) & (strcmp(hostptr->class, loopptr->class) == 0)) | (strcmp(hostptr->class, loopptr->class) < 0)) { Dprintf("(addhost): Inserting %s before %s\n", hostname, loopptr->hostname); hostptr->next = loopptr; if (lastptr != NULL) lastptr->next = hostptr; if (loopptr == hostlist) hostlist = hostptr; break; } lastptr = loopptr; } if (loopptr == NULL) { Dprintf("(addhost): appending host %s to hostlist\n", hostname); lastptr->next = hostptr; /* append to current host list */ hostptr->next = NULL; } } Dprintf("(addhost): hostlist = %d\n", hostlist); } /*************************************************************************/ /* FUNCTION : make_invalid */ /* PURPOSE : Mark all hosts and classes as invalid */ /* ARGUMENTS : none */ /*************************************************************************/ void make_invalid() { struct class *classptr, *nextclass; struct host *hostptr, *nexthost; dprintf("(make_invalid) marking all classes as invalid\n"); for (classptr = classlist; classptr != NULL; classptr = nextclass) { Dprintf("(make_invalid) marking class %s as invalid\n", classptr->classname); classptr->valid = 0; classptr->members = 0; nextclass = classptr->next; } dprintf("(make_invalid) marking all hosts as invalid\n"); for (hostptr = hostlist; hostptr != NULL; hostptr = nexthost) { Dprintf("(make_invalid) marking host %s as invalid\n", hostptr->hostname); hostptr->valid = 0; nexthost = hostptr->next; } } /*************************************************************************/ /* FUNCTION : clear_invalid */ /* PURPOSE : Remove all hosts and classes which are not valid anymore */ /* ARGUMENTS : none */ /*************************************************************************/ void clear_invalid() { struct class *lastclass = NULL, *classptr, *nextclass; struct host *lasthost = NULL, *hostptr, *nexthost; int loop; dprintf("(clear_invalid) clearing all invalid hosts\n"); for (hostptr = hostlist; hostptr != NULL; hostptr = nexthost) { nexthost = hostptr->next; if (hostptr->valid == 0) { if (hostptr->pid > 0) { dprintf("(clear_invalid): killing transmitter for host %s\n", hostptr->hostname); if (kill(hostptr->pid, SIGTERM) != 0) xmit_done(-hostptr->pid); } Dprintf("(clear_invalid): clearing host %s\n", hostptr->hostname); if (hostlist == hostptr) hostlist = nexthost; (void) free(hostptr); if (lasthost) lasthost->next = nexthost; } else { lasthost = hostptr; } } dprintf("(clear_invalid) clearing all invalid classes\n"); for (classptr = classlist; classptr != NULL; classptr = nextclass) { nextclass = classptr->next; if (classptr->valid == 0) { Dprintf("(clear_invalid): clearing class %s\n", classptr->classname); for (loop = 0; loop < classptr->xargc; loop++) { Dprintf("(clear_invalid): clearing class %s argv %d\n", classptr->classname, loop); (void) free(classptr->xargv[loop]); } if (classlist == classptr) classlist = nextclass; (void) free(classptr); if (lastclass) lastclass->next = nextclass; } else { lastclass = classptr; } } } /*************************************************************************/ /* FUNCTION : read_config */ /* PURPOSE : Read the newsxd configuration file */ /* ARGUMENTS : none */ /*************************************************************************/ void read_config(sig) int sig; { FILE *config; char line[MAXPATHLEN], /* buffer used for inputting lines */ buf[10][MAXPATHLEN], /* buffers for various command parameters */ *comment; /* used to trim comments from input lines */ int loop, deltanice, /* Amount to change proc's nice for xmit */ optioncnt, /* number of parameters found by sscanf */ maxxmits, /* number of allowed simul. transmitters */ interval, /* interval between xmits to a single host */ startint, /* interval between starting xmits 4 a class */ maxload, /* max allowed load for starting new xmits */ ttl, /* maximum time-to-live for a transmitter */ ttlpenalty, /* time penalty for exceeding ttl */ flags; /* option flags for this transmission class */ struct class *classptr; /* used to traverse the class list */ struct stat statbuf; if (!(config = fopen(configfile, "r"))) { logerr("Couldn't open config file (%s) - aborting\n", configfile); (void) exit(1); } /* * Mark all hosts and classes as undefined, but don't delete 'em yet */ if (sig) log(LOG_INFO, "reinitializing\n"); make_invalid(); CONFIGCHANGED = 1; #ifdef FAKESYSLOG CONFIGCHANGEDFILE = 1; #endif daemon_idle = 0; /* Allow newsxd to begin running the queue again */ /* * Reset all of the various data files to their default location */ (void) strcpy(batchfile, default_batchfile); (void) strcpy(workfile, default_workfile); (void) strcpy(xmitlogs, default_xmitlogs); locking = 0; /* locking defaults to OFF */ tallying = 0; /* use of the tally file defaults to OFF */ queueinterval = 60; /* default queue run interval of 1 minute */ /* * Add the DEFAULT pseudo-class so that a default xmitter can be specified */ addclass("DEFAULT", 0, 0, 0, 0, 0, 0, 0, 0, 0); while (fgets(line, 255, config) != NULL) { if ((comment = index(line, '#')) != NULL) (void) strcpy(comment, "\n"); Dprintf("> %s", line); if (sscanf(line, "tallyfile %s\n", tallyfile) > 0) { dprintf("tallyfile is %s\n", tallyfile); tallying = 1; } if (sscanf(line, "batchfile %s\n", batchfile) > 0) dprintf("batchfile is %s\n", batchfile); if (sscanf(line, "xmitlogs %s\n", xmitlogs) > 0) { dprintf("xmitlogs is %s\n", xmitlogs); continue; } if (sscanf(line, "workfile %s\n", workfile) > 0) dprintf("workfile is %s\n", workfile); if (sscanf(line, "queueinterval %d\n", &queueinterval) > 0) dprintf("queueinterval is %d\n", queueinterval); if ((optioncnt = sscanf(line, "class %s %s %s %s %s %s %s %s", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8])) > 0) { maxxmits = 1; interval = 60; startint = 0; maxload = 99; ttl = 999999; ttlpenalty = 0; flags = 0; deltanice = 0; *buf[9] = '\0'; Dprintf("optioncnt = %d\n", optioncnt); for (loop = 1; loop < optioncnt; loop++) { (void) sscanf(buf[loop], "maxxmits=%d", &maxxmits); (void) sscanf(buf[loop], "maxload=%d", &maxload); (void) sscanf(buf[loop], "nice=%d", &deltanice); (void) sscanf(buf[loop], "interval=%d/%d", &interval, &startint); (void) sscanf(buf[loop], "ttl=%d/%d", &ttl, &ttlpenalty); (void) sscanf(buf[loop], "debug=%s", buf[9]); if (strcmp(buf[loop], "noworkfile") == 0) flags |= (1< 0) { classptr = getclass(buf[0]); if (!classptr | (classptr->valid == 0)) { logerr("(read_config) xmit class for invalid class %s ignored\n", buf[0]); } if (stat(buf[1], &statbuf) != 0) { logerr("(read_config) xmit program %s for class %s unavailable\n", buf[1], buf[0]); logerr("(read_config) no xmit for class %s, invalidating class\n", buf[0]); classptr->valid = 0; continue; } (void) strcpy(classptr->xpath, buf[1]); for (loop = 2; loop < optioncnt; loop++) { Dprintf("class %s: setting xmit parm %d = %s\n", classptr->classname, loop - 2, buf[loop]); classptr->xargv[loop-2] = (char *) malloc(strlen(buf[loop])+1); (void) strcpy(classptr->xargv[loop-2], buf[loop]); } classptr->xargv[optioncnt - 2] = NULL; classptr->xargc = optioncnt - 2; } if ((optioncnt = sscanf(line, "host %s %s %s %s %s %s %s %s", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])) > 0) { Dprintf("optioncnt = %d\n", optioncnt); interval = 0; startint = 0; maxload = 0; ttl = 0; ttlpenalty = 0; deltanice = 0; *buf[9] = '\0'; for (loop = 3; loop < optioncnt; loop++) { (void) sscanf(buf[loop], "maxload=%d", &maxload); (void) sscanf(buf[loop], "interval=%d/%d", &interval, &startint); (void) sscanf(buf[loop], "ttl=%d/%d", &ttl, &ttlpenalty); (void) sscanf(buf[loop], "nice=%d", &deltanice); (void) sscanf(buf[loop], "flags=%s", buf[9]); } dprintf("host %s, class %s, times %s, deltanice %d, maxload %d, intvl %d/%d, ttl %d/%d, flags=\"%s\"\n", buf[0], buf[1], buf[2], deltanice, maxload, interval, startint, ttl, ttlpenalty, buf[9]); addhost(buf[0], buf[1], buf[2], deltanice, maxload, interval, startint, ttl, ttlpenalty, buf[9]); } } /* * Remove any hosts or classes not defined anymore */ clear_invalid(); (void) fclose(config); } /*************************************************************************/ /* FUNCTION : dump_config */ /* PURPOSE : Write the current configuration and status of newsxd to */ /* a file */ /* ARGUMENTS : none */ /*************************************************************************/ void dump_config() { struct host *hostptr; struct class *classptr; char lastxmittime[30], /* bunches of buffers for ctime */ buf1[30], buf2[30], pid[30]; /* holds (pid) or "none" */ FILE *status; int curtime; if ((debug <= 0) || (DEBUG <= 0)) { status = fopen(statusfile, "w"); if (status == NULL) { logerr("Can't open statusfile (%s, \"w\")\n", statusfile); return; } } else status = stderr; curtime = time((long *) NULL); (void) fprintf(status, "%s", ctime(&curtime)); if (daemon_idle) (void) fprintf(status, "Newsxd is idled\n"); if (classlist == NULL) { (void) fprintf(status, "No valid classes defined!\n"); return; } (void) fputc('\n', status); foreach (classptr, classlist) { if (strcmp(classptr->classname, "DEFAULT") == 0) continue; (void) fprintf(status, "Class %-7.7s : %2d active transmitters (%2d max)", classptr->classname, classptr->curxmits, classptr->maxxmits); if (getla() > classptr->options.maxload) (void) fprintf(status, " [no new xmits, load %d > %d max]", getla(), classptr->options.maxload); (void) fputc('\n', status); } (void) fputc('\n', status); (void) fprintf(status, " Service Valid Start Last XMIT Xmitter Why Not\n"); (void) fprintf(status, "Hostname Class Times Started pid Running\n"); (void) fprintf(status, "----------------------- ------- ------------- --------- ------- ----------\n"); if (hostlist == NULL) { (void) fprintf(status, "No valid hosts defined!\n"); } foreach (hostptr, hostlist) { if (hostptr->lasttime == NULL) (void) strcpy(lastxmittime, "* NEVER *"); else { (void) sscanf(ctime(&hostptr->lasttime), "%s %*s %*s %s", buf1, buf2); (void) sprintf(lastxmittime, "%s %5.5s", buf1, buf2); } (void) sprintf(pid, (hostptr->pid) ? "%d" : "none", hostptr->pid); (void) fprintf(status, "%-23.23s %-7s %-13.13s %9s %5s ", hostptr->hostname, hostptr->class, hostptr->times, lastxmittime, pid); if (daemon_idle && hostptr->whynot != WN_RUNNING) (void) fputs("newsxd Idl", status); else (void) fputs(wnlist[hostptr->whynot], status); (void) fputc('\n', status); } if ((debug <= 0) || (DEBUG <= 0)) (void) fclose(status); } /*************************************************************************/ /* FUNCTION : dump_info */ /* PURPOSE : Dump newsxd's data structures to a file. */ /* ARGUMENTS : none */ /*************************************************************************/ void dump_info() { struct host *hostptr; struct class *classptr; long curtime; int loop, which; FILE *status; char outfile[MAXPATHLEN]; if ((debug <= 0) || (DEBUG <= 0)) { (void) sprintf(outfile, "%s.dump", statusfile); status = fopen(outfile, "w"); if (status == NULL) { logerr("Can't open statusfile (%s, \"w\")\n", statusfile); return; } } else status = stderr; curtime = time((long *) NULL); (void) fprintf(status, "Newsxd data structures at %s\n", ctime(&curtime)); (void) fprintf(status, "debug is %s, DEBUG is %s, newsxdebug is %s\n", debug ? "On" : "Off", DEBUG ? "On" : "Off", newsxdebug ? "On" : "Off"); (void) fprintf(status, "Queue runs occur every %d seconds, newsxd %s idled\n\n", queueinterval, daemon_idle ? "IS" : "is not"); (void) fprintf(status, "Active transmitter PID mappings:\n"); which = 0; for (loop = 0; loop < MAXXMITTERS; loop++) { if (pidlist[loop] != 0) { if (!which) (void) fputc('\n', status); (void) fprintf(status, "pid %5d --> %-25.25s ", pidlist[loop], pidmap[loop]->hostname); which = !which; } } (void) fputs("\n\n", status); (void) fprintf(status, "batchfile is %s\n", batchfile); (void) fprintf(status, "workfile is %s\n", workfile); (void) fprintf(status, "xmitlogs is %s\n", xmitlogs); (void) fprintf(status, "newsxd status written to %s\n", statusfile); (void) fprintf(status, "newsxd pid written to %s\n", pidfile); (void) fprintf(status, "newsxd config file is %s\n", configfile); (void) fprintf(status, "\n"); if (classlist == NULL) (void) fprintf(status, "NO DEFINED CLASSES\n"); foreach (classptr, classlist) { (void) fprintf(status, "CLASS %s (%02d members)\n\n", classptr->classname, classptr->members); (void) fprintf(status, " xmit prog %s", classptr->xpath); for (loop = 0; loop < classptr->xargc; loop++) (void) fprintf(status, " %s", classptr->xargv[loop]); (void) fprintf(status, "\n"); (void) fprintf(status, " xmitters %02d running, %02d max\n", classptr->curxmits, classptr->maxxmits); (void) fprintf(status, " last xmit %s", ctime(&classptr->laststart)); (void) fprintf(status, " sernum %d\n", classptr->xmitsernum); (void) fprintf(status, " options "); if (classptr->options.deltanice) (void) fprintf(status, " nice=%d", classptr->options.deltanice); if (classptr->options.interval) (void) fprintf(status, " interval=%d", classptr->options.interval); if (classptr->options.startint) (void) fprintf(status, " startint=%d", classptr->options.startint); if (classptr->options.ttl) (void) fprintf(status, " ttl=%d", classptr->options.ttl); if (classptr->options.ttlpenalty) (void) fprintf(status, " ttlpenalty=%d", classptr->options.ttlpenalty); if (classptr->options.maxload) (void) fprintf(status, " maxload=%d", classptr->options.maxload); (void) fputc('\n', status); (void) fprintf(status, " slots "); for (loop = 0; loop < MAXCLASSXMITTERS; loop++) { if ((loop > 0) & ((loop % 50) == 0)) (void) fputs("\n ", status); (void) fputc(classptr->slots[loop], status); } (void) fputs("\n\n", status); } if (hostlist == NULL) (void) fprintf(status, "NO DEFINED HOSTS\n"); foreach (hostptr, hostlist) { (void) fprintf(status, "HOST %s\n", hostptr->hostname); (void) fprintf(status, " class %s\n", hostptr->class); (void) fprintf(status, " xmit times %s\n", hostptr->times); (void) fprintf(status, " xmit pid %d\n", hostptr->pid); (void) fprintf(status, " last xmit %s", hostptr->lasttime ? ctime(&hostptr->lasttime) : "NEVER\n"); (void) fprintf(status, " penalty to %s", hostptr->penaltytime ? ctime(&hostptr->penaltytime) : "NONE\n"); (void) fprintf(status, " xmitsernum %d\n", hostptr->xmitsernum); (void) fprintf(status, " whynot %s (%d)\n", wnlist[hostptr->whynot], hostptr->whynot); (void) fprintf(status, " xmit slot %d\n", hostptr->classslot); (void) fprintf(status, " xmit flags"); for (loop = 0; loop < hostptr->xargc; loop++) (void) fprintf(status, " %s", hostptr->xargv[loop]); (void) fputc('\n', status); (void) fprintf(status, " options "); if (hostptr->options.deltanice) (void) fprintf(status, " nice=%d", hostptr->options.deltanice); if (hostptr->options.interval) (void) fprintf(status, " interval=%d", hostptr->options.interval); if (hostptr->options.startint) (void) fprintf(status, " startint=%d", hostptr->options.startint); if (hostptr->options.ttl) (void) fprintf(status, " ttl=%d", hostptr->options.ttl); if (hostptr->options.ttlpenalty) (void) fprintf(status, " ttlpenalty=%d", hostptr->options.ttlpenalty); if (hostptr->options.maxload) (void) fprintf(status, " maxload=%d", hostptr->options.maxload); (void) fputs("\n\n", status); } if ((debug <= 0) || (DEBUG <= 0)) (void) fclose(status); } SHAR_EOF chmod +x 'config.c' fi # end of overwriting check if test -f 'log.c' then echo shar: will not over-write existing file "'log.c'" else cat << \SHAR_EOF > 'log.c' /* * #include > > Copyright (c) 1989 Washington University in Saint Louis, Missouri and > Chris Myers. All rights reserved. > > Permission is hereby granted to copy, reproduce, redistribute or > otherwise use this software as long as: (1) there is no monetary > profit gained specifically from the use or reproduction of this > software, (2) it is not sold, rented, traded, or otherwise marketed, > (3) the above copyright notice and this paragraph is included > prominently in any copy made, and (4) that the name of the University > is not used to endorse or promote products derived from this software > without the specific prior written permission of the University. > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. > */ #include "defs.h" /*************************************************************************/ /* FUNCTION : log */ /* PURPOSE : Log messages to syslog or a log file, as defined in */ /* newsxd.h. If debug or DEBUG is set, log to stderr. */ /* ARGUMENTS : Log priority, message to log, and message parameters */ /*************************************************************************/ void log(priority, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) /*VARARGS2*/ int priority; char *message, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; { static FILE *logfile = NULL; long clock; extern int errno; char buffer[30]; if ((debug > 0) || (DEBUG > 0)) { (void) fprintf(stderr, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); return; } #if defined(SYSLOG) syslog(priority, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); #endif #if defined(FAKESYSLOG) if ((logfile != NULL) && (CONFIGCHANGEDFILE)) { (void) fclose(logfile); logfile = NULL; CONFIGCHANGEDFILE = 0; } if (logfile == NULL) { logfile = fopen(fakelogfile, "a"); } if (logfile != NULL) { (void) time(&clock); (void) strcpy(buffer, ctime(&clock)); *index(buffer, '\n') = ' '; (void) fputs(buffer, logfile); (void) fprintf(logfile, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); (void) fflush(logfile); } #endif } /*************************************************************************/ /* FUNCTION : logerr */ /* PURPOSE : Log an error to syslog */ /* ARGUMENTS : Message to log, and message parameters */ /*************************************************************************/ void logerr(message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) /*VARARGS1*/ char *message, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; { log(LOG_ERR, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } /*************************************************************************/ /* FUNCTION : Dprintf */ /* PURPOSE : Do COPIOUS debugging logging */ /* ARGUMENTS : Message to log, and message parameters */ /*************************************************************************/ void Dprintf(message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) /*VARARGS1*/ char *message, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; { if (DEBUG != 0) log(LOG_DEBUG, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } /*************************************************************************/ /* FUNCTION : dprintf */ /* PURPOSE : Do normal debugging logging */ /* ARGUMENTS : Message to log, and message parameters */ /*************************************************************************/ void dprintf(message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) /*VARARGS1*/ char *message, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; { if (debug != 0) log(LOG_DEBUG, message, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } /*************************************************************************/ /* FUNCTION : debug_off */ /* PURPOSE : Increase debugging level during program execution */ /* ARGUMENTS : none */ /*************************************************************************/ void debug_on() { if (debug) DEBUG = -1; else debug = -1; log(LOG_INFO, "Debugging changed to debug %s, DEBUG %s\n", debug ? "On" : "Off", DEBUG ? "On" : "Off"); } /*************************************************************************/ /* FUNCTION : debug_off */ /* PURPOSE : Reduce debugging level during program execution */ /* ARGUMENTS : none */ /*************************************************************************/ void debug_off() { if (DEBUG) DEBUG = 0; else debug = 0; log(LOG_INFO, "Debugging changed to debug %s, DEBUG %s\n", debug ? "On" : "Off", DEBUG ? "On" : "Off"); } SHAR_EOF chmod +x 'log.c' fi # end of overwriting check if test -f 'main.c' then echo shar: will not over-write existing file "'main.c'" else cat << \SHAR_EOF > 'main.c' /* * #include > > Copyright (c) 1989 Washington University in Saint Louis, Missouri and > Chris Myers. All rights reserved. > > Permission is hereby granted to copy, reproduce, redistribute or > otherwise use this software as long as: (1) there is no monetary > profit gained specifically from the use or reproduction of this > software, (2) it is not sold, rented, traded, or otherwise marketed, > (3) the above copyright notice and this paragraph is included > prominently in any copy made, and (4) that the name of the University > is not used to endorse or promote products derived from this software > without the specific prior written permission of the University. > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. > */ #include "defs.h" char *progname = "newsxd"; /*************************************************************************/ /* FUNCTION : main */ /* PURPOSE : */ /* ARGUMENTS : argc and argv passed in by calling program */ /*************************************************************************/ void main(argc, argv, envp) int argc; char *argv[], *envp[]; { int loop, ltime, clock, pid, sleeptime; FILE *pidout; struct tm *curtime; debug = 0; DEBUG = 0; newsxdebug = 0; (void) strcpy(configfile, default_configfile); (void) strcpy(statusfile, default_statusfile); (void) strcpy(pidfile, default_pidfile); #ifdef FAKESYSLOG (void) strcpy(fakelogfile, FAKESYSLOG); #endif FAKESYSLOG for (loop = 0; loop < argc; loop++) { if (strcmp(argv[loop], "-v") == 0) { (void) fprintf(stderr, "newsxd version %1.1f", VERSION); #if PATCHLEVEL > 0 (void) fprintf(stderr, "-%d", PATCHLEVEL); #endif (void) fprintf(stderr, ", written by Chris Myers \n"); #ifdef SYSLOG (void) fprintf(stderr, "Logging to syslog\n"); #endif #ifdef FAKESYSLOG (void) fprintf(stderr, "Logging to %s\n", fakelogfile); #endif exit(0); } if (strcmp(argv[loop], "-debug") == 0) debug++; if (strcmp(argv[loop], "-DEBUG") == 0) { DEBUG++; debug++; } if (strcmp(argv[loop], "-newsxdebug") == 0) newsxdebug++; if ((strcmp(argv[loop], "-c") == 0) && (loop < argc - 1)) (void) strcpy(configfile, argv[++loop]); if ((strcmp(argv[loop], "-pid") == 0) && (loop < argc - 1)) (void) strcpy(pidfile, argv[++loop]); if ((strcmp(argv[loop], "-status") == 0) && (loop < argc - 1)) (void) strcpy(statusfile, argv[++loop]); #ifdef FAKESYSLOG if ((strcmp(argv[loop], "-log") == 0) && (loop < argc - 1)) (void) strcpy(fakelogfile, argv[++loop]); #endif } (void) signal(SIGCHLD, xmit_done); (void) signal(SIGHUP, read_config); (void) signal(SIGQUIT, dump_config); (void) signal(SIGTERM, kill_children); (void) signal(SIGUSR1, debug_on); (void) signal(SIGUSR2, debug_off); (void) signal(SIGIO, idle); (void) signal(SIGIOT, reset); (void) signal(SIGTRAP, dump_info); (void) setuid(geteuid()); (void) setgid(getegid()); if (!debug) daemon_start(); #ifdef SYSLOG # ifdef LOG_LOCAL7 openlog("newsxd", LOG_PID, SYSLOG); # else openlog("newsxd", LOG_PID); # endif #endif pidout = fopen(pidfile, "r"); if (pidout != (FILE *) NULL) { (void) fscanf(pidout, "%d", &pid); (void) fclose(pidout); if (kill(pid, 0) == 0) { logerr("duplicate invocation of newsxd -- aborting\n"); (void) exit(1); } } log(LOG_INFO, "starting\n"); for (loop = 0; loop < MAXXMITTERS; loop++) { pidlist[loop] = 0; pidmap[loop] = (struct host *) NULL; } read_config(0); if (debug) dump_config(); pidout = fopen(pidfile, "w"); if (pidout != (FILE *) NULL) { (void) fprintf(pidout, "%d\n", getpid()); (void) fflush(pidout); (void) fclose(pidout); } while (1) { if (!daemon_idle) run_queue(); xmit_done(0); (void) time(&clock); curtime = localtime(&clock); ltime = curtime->tm_sec + curtime->tm_min * 60 + curtime->tm_hour * 3600; sleeptime = queueinterval - (ltime % queueinterval); if (sleeptime == 0) sleeptime++; dprintf("%d:sleeping for %d seconds\n", ltime, sleeptime); (void) sleep((unsigned) sleeptime); } } SHAR_EOF chmod +x 'main.c' fi # end of overwriting check if test -f 'process.c' then echo shar: will not over-write existing file "'process.c'" else cat << \SHAR_EOF > 'process.c' /* * #include > > Copyright (c) 1989 Washington University in Saint Louis, Missouri and > Chris Myers. All rights reserved. > > Permission is hereby granted to copy, reproduce, redistribute or > otherwise use this software as long as: (1) there is no monetary > profit gained specifically from the use or reproduction of this > software, (2) it is not sold, rented, traded, or otherwise marketed, > (3) the above copyright notice and this paragraph is included > prominently in any copy made, and (4) that the name of the University > is not used to endorse or promote products derived from this software > without the specific prior written permission of the University. > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. > */ #include "defs.h" extern int errno; /*************************************************************************/ /* FUNCTION : kill_children */ /* PURPOSE : Kills all outstanding transmitters. Kill_children will */ /* wait thirty seconds to allow all of the transmitters to */ /* exit gracefully. If invoked by a signal (SIGTERM?), exit */ /* else return to caller. */ /* ARGUMENTS : Signal number or 0 if to return to caller */ /*************************************************************************/ void kill_children(sig) int sig; /* sig will be nonzero if called by SIGTERM */ { struct host *hostptr; if ((hostlist == NULL) && (sig == 0)) return; log(LOG_INFO, "newsxd: shutting down all transmitters\n"); foreach (hostptr, hostlist) { if (hostptr->pid != 0) { dprintf("newsxd: killing transmitter for %s\n", hostptr->hostname); (void) kill (hostptr->pid, SIGTERM); } } if (sig == 0) return; dprintf("(kill_children): sleeping 30 seconds\n"); (void) sleep(30); /* allow transmitters to quit gracefully */ log(LOG_INFO, "shut down by signal %d\n", sig); if (debug == 0 && DEBUG == 0) { (void) unlink(pidfile); (void) unlink(statusfile); } (void) exit(0); /* invoked by SIGTERM, time to quit */ } /*************************************************************************/ /* FUNCTION : xmit_done */ /* PURPOSE : Catch the SIGCHLD from completed transmitters and do the */ /* necessary cleanup. Also wait synchronously for a xmitter */ /* to complete; also perform forced cleanup for an xmitter */ /* ARGUMENTS : sig, > 0 if xmit_done is called by SIGCHLD */ /* == 0 if called to check for a zombie w/NOHANG */ /* ==-1 if called to sync wait for a transmitter */ /* < -1 to perform a forced cleanup on a transmitter */ /*************************************************************************/ void xmit_done(sig) int sig; /* sig will be nonzero if called by SIGCHLD */ { struct host *hostptr; struct class *classptr; union wait status; struct rusage usage; extern char *sys_errlist[]; int options, loop, pid; (void) sigsetmask(0); /* * Try and catch any completed transmitters first and process them. * Then, if xmit_done() was called to synchronously wait on a transmitter * or to perform forced cleanup on a transmitter, do it. */ Dprintf("(xmit_done) sig %d\n", sig); while (1) { if (sig != -1) options = WNOHANG; pid = wait3(&status, options, &usage); if (pid <= 0) if (sig < -1) { pid = -sig; sig = 0; } else { Dprintf("(xmit_done) no process! pid=%d, errno=%s\n", pid, sys_errlist[errno]); return; } Dprintf("(xmit_done) pid %d\n", pid); for (loop = 0; loop < MAXXMITTERS; loop++) { if (pidlist[loop] == pid) { hostptr = pidmap[loop]; pidlist[loop] = 0; pidmap[loop] = (struct host *) NULL; hostptr->pid = 0; hostptr->whynot = WN_NOTMYTURN; foreach (classptr, classlist) { if (strcmp(hostptr->class, classptr->classname) == 0) { classptr->curxmits--; freeclassslot(classptr, hostptr->classslot); dprintf("%s: transmission completed\n", hostptr->hostname); return; } } /* * The (sig < -1) check is here just in case a transmitter exitted * normally just as run_queue tries to force a cleanup on it. If * this isn't here, newsxd will abort with a corrupted data err. */ if (sig < -1) return; /* Something is seriously wrong here -- quit somewhat gracefully */ logerr("CORRUPTED HOST/CLASS STRUCTURE!\n"); kill_children(1); } } } } /*************************************************************************/ /* FUNCTION : run_queue */ /* PURPOSE : Go through the list of hosts to transmit to and start any */ /* transmitter that meets all of the necessary conditions */ /* ARGUMENTS : none */ /*************************************************************************/ void run_queue() { struct host *hostptr; struct class *classptr, *lastclass; struct stat statbuf; struct tm *curtime; int clock, pid, hadtheirchance, which, which2, loop, loop2, hostargc, classargc; char fnbuf[MAXPATHLEN], fnbuf2[MAXPATHLEN], **hostargv, **classargv; CONFIGCHANGED = 0; hadtheirchance = 0; lastclass = (struct class *) NULL; foreach (hostptr, hostlist) { /* * If the configuration has been changed (possibly via SIGHUP), we * need to assume that all of the current pointers and such are * invalid since the current host MAY have been deleted... * * There is still a race condition, but this check lessens the chance * of problems considerably. * */ if (CONFIGCHANGED) { dprintf("Reconfigured during queue run -- aborting queue run\n"); CONFIGCHANGED = 0; return; } (void) time(&clock); curtime = localtime(&clock); classptr = getclass(hostptr->class); if (classptr != lastclass) { if (lastclass) { dprintf("class %s: members %d, hadtheirchance %d\n", lastclass->classname, lastclass->members, hadtheirchance); if (lastclass->members == hadtheirchance) { lastclass->xmitsernum++; dprintf("class %s: add 1 to xmitsernum, now %d\n", lastclass->classname, lastclass->xmitsernum); } } hadtheirchance = 0; lastclass = classptr; } /* * Check and see if we somehow missed the SIGCHLD for a transmitter and * it's really gone and we don't know it. If so, force a cleanup. */ if ((hostptr->pid) && (kill(hostptr->pid, 0) == -1) && (errno == ESRCH)) { xmit_done(-hostptr->pid); hostptr->pid = 0; /* Just in case xmit_done() missed it! */ } /* * Check to see if the host has had a transmitter running for more * than the ttl of its transmission class. If so, kill it. */ which = (hostptr->options.ttl) ? hostptr->options.ttl : classptr->options.ttl; which2 = (hostptr->options.ttlpenalty) ? hostptr->options.ttlpenalty : classptr->options.ttlpenalty; dprintf("%s: checking ttl (%d/%d)\n", hostptr->hostname, which, which2); if ((hostptr->pid > 0) && (clock > (hostptr->lasttime + which))) { dprintf("%s: exceeded ttl, killing\n"); hostptr->penaltytime = clock + which2; if (kill(hostptr->pid, SIGTERM) != 0) xmit_done(-hostptr->pid); hostptr->whynot = WN_TTL; continue; /* skip this host to give others a chance */ } /* * If there is already a running transmitter for this host, skip it. We * don't want more than one! */ dprintf("%s: checking for active daemon (%d)\n", hostptr->hostname, hostptr->pid); if (hostptr->pid > 0) { hostptr->whynot = WN_RUNNING; hadtheirchance++; continue; } /* * Check to see if this host has already had a chance to start * a transmitter. If so, let someone else have a chance. */ dprintf("%s: xmitsernum is %d, class xmitsernum is %d\n", hostptr->hostname, hostptr->xmitsernum, classptr->xmitsernum); /* if ((hostptr->xmitsernum == classptr->xmitsernum) && (classptr->maxxmits < classptr->members)) { */ if (hostptr->xmitsernum == classptr->xmitsernum) { hadtheirchance++; /* hostptr->whynot = WN_NOTMYTURN; */ continue; } /* * Check the current time against the last time an xmit was started * for this class to make sure we don't start too many daemons at * one time. */ which = (hostptr->options.startint) ? hostptr->options.startint : classptr->options.startint; dprintf("%s: checking class startup interval (clock is %d, start %d)\n", hostptr->hostname, clock, (classptr->laststart + which)); if (clock < (classptr->laststart + which)) { hostptr->whynot = WN_CLASSSTARTINT; continue; } /* * Check the current load and compare against the maximum allowed * load for starting new transmitters for this hosts's class. */ which = (hostptr->options.maxload) ? hostptr->options.maxload : classptr->options.maxload; dprintf("%s: checking maximum load (cur %d, max %d)\n", hostptr->hostname, getla(), which); if (getla() > which) { hostptr->whynot = WN_LOAD; continue; } /* * Check the number of currently running transmitters for this host's * transmission class. If we're already running at the limit, skip * this host. */ dprintf("%s (%s): checking running xmit count (%d of %d)\n", hostptr->hostname, classptr->classname, classptr->curxmits, classptr->maxxmits); if (classptr->curxmits >= classptr->maxxmits) { hostptr->whynot = WN_MAXXMITS; continue; } /* * All tests after this point should be tests for some characteristic * of the host that would cause it to avoid its turn to start its * transmitter. Things like: the host startup interval hasn't passed * yet, or it's a bad time to send to that host, or there's no work * to send to that host. * * Tests before this point should be tests for some characteristic not * related to the particular host that prevents it from being able to * start its transmitter. Things like: load too high, too many xmits * already running... */ /* * This host had a chance to send news (and can possibly skip it). */ hostptr->xmitsernum = classptr->xmitsernum; hadtheirchance++; /* * Check to see if the host had a transmitter killed because it ran * longer than its class' ttl. If so, see if its penalty time is * still unexpired. */ dprintf("%s: checking ttl penalty\n", hostptr->hostname); if (hostptr->penaltytime > clock) { hostptr->whynot = WN_PENALTYTIME; continue; } /* * Check the current time against the last time an xmit was started * for this class to make sure we don't start a transmitter for this * host too often... */ which = (hostptr->options.interval) ? hostptr->options.interval : classptr->options.interval; dprintf("%s: checking host startup interval (%d)\n", hostptr->hostname, which); if (clock < (hostptr->lasttime + which)) { hostptr->whynot = WN_HOSTSTARTINT; continue; } /* * Check to see that the current time is within the permitted range * of transmission times. If not, skip this host. */ dprintf("%s: checking valid transmission times (%s)\n", hostptr->hostname, hostptr->times); if (!validtime(hostptr->times)) { hostptr->whynot = WN_BADTIME; continue; } /* * See if there is an outstanding work file for this host, if so we * just need to run a transmitter, otherwise rename the batch file * to the work file and run the transmitter. */ (void) sprintf(fnbuf, workfile, hostptr->hostname); dprintf("%s: checking for workfile (%s)\n", hostptr->hostname, fnbuf); if ((loop = stat(fnbuf, &statbuf)) != 0) { Dprintf("%s: stat(%s) returned %d (errno is %d)\n", hostptr->hostname, fnbuf, loop, errno); (void) sprintf(fnbuf2, batchfile, hostptr->hostname); dprintf("%s: checking for batchfile (%s)\n", hostptr->hostname, fnbuf2); if (!classptr->flags[C_NOBATCH]) { if ((loop = stat(fnbuf2, &statbuf)) != 0) { Dprintf("%s: stat(%s) returned %d (errno is %d)\n", hostptr->hostname, fnbuf, loop, errno); hostptr->whynot = WN_NOWORK; continue; } else { hostptr->whynot = WN_RENAMEFAILED; if (!classptr->flags[C_NOWORK] && rename(fnbuf2, fnbuf) != 0) { dprintf("%s: rename failed (%s to %s)\n", hostptr->hostname, fnbuf2, fnbuf); continue; } } } } /* * Fork off a transmitter for this host */ hostptr->whynot = WN_RUNNING; if ((hostptr->classslot = getclassslot(classptr)) == -1) { hostptr->whynot = WN_NOSLOT; exit(1); } if ((pid = fork()) == 0) { /* Child. */ int fd; /* Untrap all of the signals for newsxd; this is now a transmitter */ (void) signal(SIGCHLD, SIG_DFL); (void) signal(SIGHUP, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); (void) signal(SIGTERM, SIG_DFL); (void) signal(SIGUSR1, SIG_DFL); (void) signal(SIGUSR2, SIG_DFL); (void) signal(SIGIO, SIG_DFL); (void) signal(SIGIOT, SIG_DFL); (void) signal(SIGTRAP, SIG_DFL); fd = open(classptr->flags[C_NOWORK] ? fnbuf2 : fnbuf, O_RDONLY); if (fd > 0) (void) flock(fd, LOCK_EX); #ifdef CNEWSLOCKING if (!classptr->flags[C_NOWORK]) { /* If we can get a valid lock then we know that since the batch * file has been renamed to WORKFILE, cnews will now be writing * to a different file (BATCHFILE). */ (void) newslock(); (void) newsunlock(); } #endif CNEWSLOCKING Dprintf("(%s): classslot is %d\n", hostptr->hostname, hostptr->classslot); dprintf("%s: spawning transmitter\n", hostptr->hostname); if (!newsxdebug) { (void) sprintf(fnbuf2, xmitlogs, hostptr->hostname); (void) freopen(fnbuf2, "a", stdout); (void) freopen(fnbuf2, "a", stderr); } (void) fprintf(stderr, "%s: begin at %02d:%02d:%02d\n", hostptr->hostname, curtime->tm_hour, curtime->tm_min, curtime->tm_sec); (void) fflush(stderr); which = (hostptr->options.deltanice) ? hostptr->options.deltanice : classptr->options.deltanice; if (which != 0) { Dprintf("Changing transmitter nice by %d for %s\n", which, hostptr->hostname); (void) nice(which); } if (classptr->xargc == 0) { classptr = getclass("DEFAULT"); if (classptr->xargc == 0) { logerr("host %s: No DEFAULT xmitter defined -- aborting\n", hostptr->hostname); (void) _exit(1); } } Dprintf("classptr->xargc = %d\n", classptr->xargc); Dprintf("%s: EXECing %s with parameters:\n", hostptr->hostname, classptr->xpath); for (loop = 0; loop <= classptr->xargc; loop++) { if (classptr->xargv[loop] == NULL) { Dprintf("arg[%d] = NULL\n", loop); } else { Dprintf("arg[%d] = %s\n", loop, classptr->xargv[loop]); } } classargc = classptr->xargc; classargv = classptr->xargv; classargv[classargc] = NULL; for (loop = 0; loop < classargc; loop++) { hostargv = NULL; if (strcmp(classargv[loop], "%f") == NULL) { hostargc = hostptr->xargc; hostargv = hostptr->xargv; } if (strcmp(classargv[loop], "%d") == NULL) { struct class *myclassptr = getclass(hostptr->class); hostargc = myclassptr->debugargc; hostargv = myclassptr->debugargv; Dprintf("debug argc = %d\n", hostargc); } if (hostargv != NULL) { if (hostargc == 0) { classargc--; for (loop2 = loop; loop2 < MAXEXECARGS-1; loop2++) classargv[loop2] = classargv[loop2 + 1]; } else { classargc += hostargc - 1; for (loop2 = MAXEXECARGS - hostargc; loop2 > loop; loop2--) classargv[loop2 + hostargc - 1] = classargv[loop2]; for (loop2 = loop; loop2 < loop + hostargc; loop2++) classargv[loop2] = hostargv[loop2 - loop]; loop += hostargc - 1; } } } Dprintf("(after host flag insertion) classargc = %d\n", classargc); for (loop = 0; loop <= classargc; loop++) { /* WARNING: we are mangling the xargv array here! */ processarg(loop, hostptr, classptr); if (classargv[loop] == NULL) { Dprintf("arg[%d] = NULL\n", loop); } else { Dprintf("arg[%d] = %s\n", loop, classargv[loop]); } } (void) execvp(classptr->xpath, classargv); logerr("%s: can't exec %s\n", hostptr->hostname, classptr->xpath); (void) _exit(1); /* could not exec the news transmitter! */ } else { /* Parent. */ if (pid == -1) { logerr("host %s: Can't fork child.\n", hostptr->hostname); continue; } for (loop = 0; loop < MAXXMITTERS; loop++) { if (pidlist[loop] == 0) { pidlist[loop] = pid; pidmap[loop] = hostptr; Dprintf("%s: entered into pidmap/list at %d\n", hostptr->hostname, loop); break; } } hostptr->pid = pid; hostptr->lasttime = clock; classptr->laststart = clock; classptr->curxmits++; if (newsxdebug) xmit_done(-1); /* wait for xmitter to complete */ } } if (classptr->members == hadtheirchance) { dprintf("class %s: add 1 to sernum (members %d, hadchance %d)\n", classptr->classname, classptr->members, hadtheirchance); classptr->xmitsernum++; } } SHAR_EOF chmod +x 'process.c' fi # end of overwriting check if test -f 'util.c' then echo shar: will not over-write existing file "'util.c'" else cat << \SHAR_EOF > 'util.c' /* * #include > > Copyright (c) 1989 Washington University in Saint Louis, Missouri and > Chris Myers. All rights reserved. > > Permission is hereby granted to copy, reproduce, redistribute or > otherwise use this software as long as: (1) there is no monetary > profit gained specifically from the use or reproduction of this > software, (2) it is not sold, rented, traded, or otherwise marketed, > (3) the above copyright notice and this paragraph is included > prominently in any copy made, and (4) that the name of the University > is not used to endorse or promote products derived from this software > without the specific prior written permission of the University. > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. > */ #include "defs.h" /*************************************************************************/ /* FUNCTION : daemon_start */ /* PURPOSE : To disassociate newsxd from the calling process so it can */ /* run as a daemon. */ /* ARGUMENTS : none */ /*************************************************************************/ void daemon_start() { register int childpid, fd; extern int errno; /* Ignore the terminal stop signals */ (void) signal(SIGTTOU, SIG_IGN); (void) signal(SIGTTIN, SIG_IGN); (void) signal(SIGTSTP, SIG_IGN); /* Fork and let the parent process exit */ if ((childpid = fork()) < 0) { logerr("newsxd: can't fork to enter daemon mode\n"); (void) exit(1); } else if (childpid > 0) exit(0); /* Lose the process group */ if (setpgrp(0, getpid()) == -1) { logerr("newsxd: can't change pgrp to enter daemon mode\n"); (void) exit(1); } /* Lose the controlling terminal */ if ((fd = open("/dev/tty", O_RDWR)) >= 0) { (void) ioctl(fd, TIOCNOTTY, (char *) NULL); (void) close(fd); } /* Close any open files */ for (fd = 0; fd < NOFILE; fd++) (void) close(fd); errno = 0; /* Set a proper default umask */ (void) umask(022); } /*************************************************************************/ /* FUNCTION : getla */ /* PURPOSE : Return the current system load */ /* ARGUMENTS : none */ /* NOTES : this code stolen from sendmail 5.61 which stole it from */ /* from something else... */ /*************************************************************************/ int getla() { #if defined(sun) | defined(mips) long avenrun[3]; #else double avenrun[3]; #endif extern off_t lseek(); static int kmem = -1; static struct nlist Nl[] = { { "_avenrun" }, #define X_AVENRUN 0 { 0 }, }; if (kmem < 0) { kmem = open("/dev/kmem", 0, 0); if (kmem < 0) return (-1); (void) ioctl(kmem, (int) FIOCLEX, (char *) 0); (void) nlist("/vmunix", Nl); if (Nl[0].n_type == 0) return (-1); } if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) { /* thank you Ian */ return (-1); } #ifdef sun return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); #else #ifdef mips return (FIX_TO_INT(avenrun[0])); #else return ((int) (avenrun[0] + 0.5)); #endif #endif } /*************************************************************************/ /* FUNCTION : processarg */ /* PURPOSE : Do %value substitutions in xargv */ /* ARGUMENTS : which value of argv to modify, hostptr, classptr */ /*************************************************************************/ void processarg(which, hostptr, classptr) int which; struct host *hostptr; struct class *classptr; { char buf1[MAXPATHLEN], buf2[MAXPATHLEN], charbuf[2], *newxargv, *strptr; if (classptr->xargv[which] == NULL) return; charbuf[1] = '\0'; *buf1 = '\0'; for (strptr = classptr->xargv[which]; *strptr != '\0'; strptr++) { if (*strptr != '%') { charbuf[0] = *strptr; (void) strcat(buf1, charbuf); } else { strptr++; switch (*strptr) { case 'h': (void) strcat(buf1, hostptr->hostname); break; case 'f': (void) strcat(buf1, "%f"); /* We shouldn't have seen a %f at this point! */ break; case 'd': (void) strcat(buf1, "%d"); /* We shouldn't have seen a %d at this point! */ break; case 'b': (void) sprintf(buf2, batchfile, hostptr->hostname); (void) strcat(buf1, buf2); break; case 'w': if (classptr->flags[C_NOWORK]) (void) sprintf(buf2, batchfile, hostptr->hostname); else (void) sprintf(buf2, workfile, hostptr->hostname); (void) strcat(buf1, buf2); break; case 's': (void) sprintf(buf2, "%d", hostptr->classslot); (void) strcat(buf1, buf2); break; case '%': (void) strcat(buf1, "%"); /* %% changes to % */ break; default : strptr--; } } } newxargv = (char *) malloc(strlen(buf1) + 1); (void) strcpy(newxargv, buf1); classptr->xargv[which] = newxargv; } /*************************************************************************/ /* FUNCTION : parse_time */ /* PURPOSE : Check a single valid-time-string against the current time */ /* and return whether or not a match occurs. */ /* ARGUMENTS : a pointer to the time-string */ /*************************************************************************/ int parsetime(whattime) char *whattime; { static char *days[] = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk" }; long clock; struct tm *curtime; int wday, start, stop, ltime, validday, loop, match; (void) time(&clock); curtime = localtime(&clock); wday = curtime->tm_wday; validday = 0; match = 1; while (match && isalpha(*whattime) && isupper(*whattime)) { match = 0; for (loop = 0; loop < 8; loop++) { if (strncmp(days[loop], whattime, 2) == NULL) { whattime += 2; match = 1; if ((wday == loop) | ((loop == 7) && wday && (wday < 6))) { validday = 1; } } } } if (strncmp(whattime, "Any", 3) == NULL) { validday = 1; whattime += 3; } if (!validday) return 0; if (sscanf(whattime, "%d-%d", &start, &stop) == 2) { ltime = curtime->tm_min + 100 * curtime->tm_hour; if ((start < stop) && ((ltime > start) & ltime < stop)) return 1; if ((start > stop) && ((ltime > start) | ltime < stop)) return 1; } else return 1; return 0; } /*************************************************************************/ /* FUNCTION : validtime */ /* PURPOSE : Break apart a set of valid time-strings and pass them to */ /* parse_time, returning whether or not ANY matches occurred */ /* ARGUMENTS : a pointer to the time-string */ /*************************************************************************/ int validtime(ptr) char *ptr; { char *nextptr; int good; while (1) { nextptr = STRCHR(ptr, '|'); if (STRCHR(ptr, '|') == NULL) return(parsetime(ptr)); *nextptr = '\0'; good = parsetime(ptr); *nextptr++ = '|'; /* gotta restore the | or things get skipped! */ if (good) return(1); ptr = nextptr; } } /*************************************************************************/ /* FUNCTION : getclassslot */ /* PURPOSE : */ /* ARGUMENTS : a pointer to the class structure */ /* RETURNS : the slot number */ /*************************************************************************/ int getclassslot(classptr) struct class *classptr; { int loop; for (loop = 0; loop < MAXCLASSXMITTERS; loop++) if (classptr->slots[loop] != 'X') { classptr->slots[loop] = 'X'; return loop; } logerr("(getclassslot) Too many xmitters for class %s", classptr->classname); return -1; } /*************************************************************************/ /* FUNCTION : freeclassslot */ /* PURPOSE : */ /* ARGUMENTS : slot number to free and a pointer to the class structure */ /*************************************************************************/ void freeclassslot(classptr, slot) struct class *classptr; int slot; { classptr->slots[slot] = '.'; } /*************************************************************************/ /* FUNCTION : idle */ /* PURPOSE : Set newsxd to idle mode. Don't process xmitter queue... */ /* ARGUMENTS : none */ /*************************************************************************/ void idle() { daemon_idle = 1; } /*************************************************************************/ /* FUNCTION : reset */ /* PURPOSE : Kill all outstanding transmitters and idle newsxd. */ /* ARGUMENTS : none */ /*************************************************************************/ void reset() { kill_children(0); daemon_idle = 1; } #ifdef CNEWSLOCKING /*************************************************************************/ /* FUNCTION : unprivileged */ /* PURPOSE : keep the cnews libraries happy. */ /* ARGUMENTS : none used. */ /*************************************************************************/ int unprivileged(reason) char *reason; { } #endif CNEWSLOCKING SHAR_EOF chmod +x 'util.c' fi # end of overwriting check if test -f 'version.c' then echo shar: will not over-write existing file "'version.c'" else cat << \SHAR_EOF > 'version.c' /* * #include > > Copyright (c) 1989 Washington University in Saint Louis, Missouri and > Chris Myers. All rights reserved. > > Permission is hereby granted to copy, reproduce, redistribute or > otherwise use this software as long as: (1) there is no monetary > profit gained specifically from the use or reproduction of this > software, (2) it is not sold, rented, traded, or otherwise marketed, > (3) the above copyright notice and this paragraph is included > prominently in any copy made, and (4) that the name of the University > is not used to endorse or promote products derived from this software > without the specific prior written permission of the University. > THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR > IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED > WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. > * newsxd: a daemon for controlling the transmission of news * * Written by * Chris Myers Internet: chris@wugate.wustl.edu * Software Engineer UUCP: ...!uunet!wugate!chris * Office of the Network Coordinator BITNET: chris@wunet.bitnet * Washington University in Saint Louis * * HISTORY: * Version 0.1: first written in perl. A grand experiment that just didn't * work very reliably (no reflection on the quality of perl, it * just wasn't meant to do this kind of thing). * * Version 1.0: first C version * * 1.1: added per-host locking * 1.2: added maxload qualifier * 1.2.1: added time to live qualifier * * SOURCE CODE INADVERTANTLY DESTROYED (SIGH) * Oh well, it needed rewriting anyway. :-) * * Version 2.0: here we go again. No per-host locking right now :-( * Removed all static limits on the number of transmission * classes and hosts. Everything is now malloc'ed. * 2.0.1: added penalty time to time-to-live qualifier to allow other * hosts to get news transmitters started. * 2.1: Added the capability to specify a different transmission * program (and parameters) for each transmission class. This * was the motive for the name change from nntpxd to newsxd. * 2.1.1: fixed bug caused by defunct transmitters which finally * overran the ttl (did not do proper cleanup). * 2.1.2: added patches for Pyramid and BSD 4.3 support from Warren * Lavallee and Jim Lowe. * 2.1.3: fixed bugs in calculating the ttl penalty and start/stop * time ranges * 2.1.4: fixed bug in read_config where the loop went 1 past the end * of the options for a transmission class. This could cause * the last parameter on a longer preceeding class line to be * carried over to the subsequent classes. * 2.1.5: somehow the default value for nntplogs slipped away from the * code. Put it back in where it belongs. * 2.1.6: added inter-host startup interval for classes so that newsxd * doesn't start up too many daemons at once * 2.1.7: fix stupid bug created in earlier patch where I set argptr[x] * to NULL (what it was supposed to be) and then blithly reset it * to something else -- preventing EXECing the program specified * in an XMIT option. ARGH. * 2.1.8: ARGH! Left out the code to make sure a transmitter for each * host wasn't started up more often than seconds. * 2.2: Cut down on the size of the wishlist by adding a bunch of * features (and hopefully no more bugs): * - syslog logging * - lots of range/value checking on inputs * - sort host/class names when inserting into list * - move all configuration parameters into newsxd.h * - add more error messages * - document code even more * - allow reconfiguration without killing outstanding xmitters * - add a 'nobatchfile' switch * - allocation of alternate xmitter parameters is now dynamic * - Per-host delta-nice values for transmitters * - make code more readable * - write a manpage * 2.3: Add SIGUSR1, SIGUSR2 to {en,dis}able debugging while running * Shift the order of syslog initialization and switch to daemon * Fix a "go past end of the array sometimes" bug in getclass(). * add "reason" to status display to show why xmitter not running * in xmit options, %f=flags,%w=workfile,%b=batchfile,%h=hostname * make transmission of news to hosts 'fair' * minimize a race in run_queue if SIGQUIT causes reconfiguration * change start/stop times to use UUCP-style permissible times * 2.3.1: fix bug in incr xmitsernum when only one service class in use * enable fair transmission code even if maxxmits > class members * change use of strpbrk to strchr and make strchr #define'd * 2.4: add per-host flags * added check for multiply-defined host/class in add{host,class} * zero classptr->members in addclass to allow reconfiguration * 2.4.1: classptr->members++ in addhost was in the wrong spot * buffer declaration for FAKESYSLOG had trailing ; should be , * log a reinitialization message after getting SIGHUP * add -v switch to show version and logging * if debugging == ON in daemon mode, don't dump status to stderr * was closing pidfile with close() rather than fclose() * change comments in xmit_done() to show sig==0 is NOHANG * validtime() was mangling the valid times string * parsetime() sometimes said a good time was not valid * addhost() now resorts host list on reconfiguration * 2.4.2: modify xmit_done() to almost always use WNOHANG on wait calls * add_host() was improperly decrementing classptr->members * When debugging changes, log "On"/"Off" not the value (0/-1) * get rid of remaining code for obsolete "nntpxmit" keyword * finish updating comments, changing "nntpxmit" to "transmitter" * 2.5: sigsetmask(0) to allow SIGCHLD in xmit_done(); don't lose kids * modify "Why Not Running" messages slightly for readability * xmit_done() now loops to catch all completed transmitters * run_queue() now checks for MIA transmitters and cleans 'em up * if no classes defined, dump_config() now returns immediately * break the source apart into several files from one big'un * class options are default, w/host options overriding * [ttl, interval, nice, maxload] * run_queue() was setting whynotrunning wrong for active xmits * moved ttl penalty check into "host gave up chance" code to * prevent a penalized host from blocking others * added SIGIO to idle newsxd until SIGHUP is received * added class slots * added faster pid->host mapping data structure * added SIGTRAP to dump internal data structures for debugging * 2.5.1: apply "lint" fixes from Andrew Partan * close and reopen logfiles on SIGHUP * put Why Not reasons in static array, use everywhere * process.c: in fork()ed child, call _exit() not exit() * check for duplicate newsxd running * add support for per-class transmitter debugging flags * fix an open file leak in config.c:read_config() * add SIGIOT to kill all transmitters and idle newsxd * add setuid(geteuid()), setgid(getegid()) in main() * fix some potential null-ptr dereferencing problems in config.c * fix array-index overrun problem in config.c * remove pidfile and statusfile on shutdown unless debug|DEBUG * flock() the work file before EXECing the transmitter * support CNEWS-style locking to prevent races on the work file * restore default signal action after fork() for transmitter * * SPECIAL THANKS TO: * * Alpha tester: John Coolidge * * Beta testers: Warren Lavallee * Don Thomson * Michael A. Cooper * Jim Lowe * David C. Lawrence * John Coolidge * Lloyd W. Taylor * Dave Alden * Greg Hackney * Rick Adams * Andrew Partan * * This software has been tested on the following systems: * * DECstation 3100, Ultrix 3.1 * DEC VAX 8810, Ultrix 3.1 * Sun 3/60, SunOS 4.0.1 * Sun 3/180, SunOS 4.0.3 * Pyramid DualPort OSx * DEC MicroVAX-II, BSD 4.3 UNIX * DEC MicroVAX-II, Mt Xinu MORE/BSD 4.3 * * Wishlist: * * - add logging of transmitter resource usage * - Exponential backoff for failed transmission attempts * - Per-host locking, using shlock-style locks * - ability to specify min. # of articles queued before xmission starts * - add per-class workfile and batchfile definitions * - add per-host maximum delay between transmitter startups * */ SHAR_EOF chmod +x 'version.c' fi # end of overwriting check if test -f 'defs.h' then echo shar: will not over-write existing file "'defs.h'" else cat << \SHAR_EOF > 'defs.h' /* Define everything that all of the various pieces of code will be using */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "newsxd.h" #include "patchlevel.h" /* If it's good enough for news 2.11, it's good enough for me ... */ #ifdef BSD4_2 #include #else #include #endif #include #if defined(mips) & defined(ultrix) #include #endif char *calloc(); #define foreach(ctl, list) for (ctl = list; ctl != NULL; ctl = ctl->next) #ifdef CNEWSLOCKING extern char *progname; #endif int debug, /* is debugging enabled */ DEBUG, /* painfully verbose debugging is enabled */ newsxdebug, /* run xmitter synchronously with debugging? */ tallying, /* is use of a tally file enabled? */ locking, /* is use of a locking file enabled? */ CONFIGCHANGED, /* a new configuration was read in */ #ifdef FAKESYSLOG CONFIGCHANGEDFILE, /* a new configuration was read in */ #endif queueinterval, /* number of seconds between xmit checks */ daemon_idle, /* prevent newsxd from running queue if set */ pidlist[MAXXMITTERS]; /* map pid --> xmitter quicker */ struct host *pidmap[MAXXMITTERS]; char batchfile[MAXPATHLEN], /* file inews places article IDs/paths in */ workfile[MAXPATHLEN], /* file to use for transmitter work file */ xmitlogs[MAXPATHLEN], /* where to log the output of transmitters */ tallyfile[MAXPATHLEN], /* where the tally file can be found */ statusfile[MAXPATHLEN], /* where newsxd's status should be written */ pidfile[MAXPATHLEN], /* where newsxd's pid should be written */ #ifdef FAKESYSLOG fakelogfile[MAXPATHLEN],/* where is the newsxd log file? */ #endif configfile[MAXPATHLEN]; /* where is the newsxd configuration file? */ /* STRUCT OPTIONS * Used to define the options controlling the starting of transmitters for * classes and hosts. * * interval : minimum start-to-start interval for each host's transmitter * startint : minimum interval between starting transmitters in this class * ttl : maximum time-to-live (secs) for a transmitter in this class * ttlpenalty : penalty time (secs) for a transmitter exceeding the ttl * deltanice : amount to change nice before execing the transmitter * maxload : maximum load where new xmitters can be started for this class * */ typedef struct options { int deltanice; int interval; int startint; int ttl; int ttlpenalty; int maxload; }; /* * STRUCT CLASS * Contains the current state and description of each class of transmitters * that newsxd handles. * * classname : textual name of this transmission class * maxxmits : maximum number of simultaneous transmitters for this class * curxmits : current number of active transmitters for this class * laststart : last time a transmitter was started for this class * xmitsernum : transmission serial number used for fair news transmission * options : defines default transmitter startup parameters for this class * members : number of hosts that are a member of this class * flags : special option flags for this class * 0 : don't rename to * 1 : don't look for or * xpath : file path for an alternate transmission program * xargv : arguments to be passed to the alternate transmitter * xargc : number of arguments to be passed to the alternate xmitter * valid : used to detect which classes are valid after a config update * next : pointer to the next class descriptor in the list * */ struct class { char classname[MAXCLASSNAMELEN]; int maxxmits; int curxmits; int laststart; int xmitsernum; int members; struct options options; char slots[MAXCLASSXMITTERS]; int flags[MAXCLASSFLAGS]; char batchfile[MAXPATHLEN]; char workfile[MAXPATHLEN]; char xpath[MAXPATHLEN]; char *xargv[MAXEXECARGS]; int xargc; char *debugargv[MAXEXECARGS]; int debugargc; int valid; struct class *next; }; /* * STRUCT HOST * Contains the current state and description of each host that newsxd * will be communicating with. * * hostname : name of the host to pass to the transmitter * class : name of the transmission class this host is in * times : list of valid times to transmit in UUCP L.sys format * pid : pid of forked transmitter * lasttime : last time transmitter was forked off * xmitsernum : transmission serial number used for fair news transmission * penaltytime : host xmitted to past ttl; secs before penalty is over * whynot : why is there no transmitter running for this host NOW? * valid : used to detect which hosts are valid after a config update * options : defines default transmitter startup parameters for this host * next : pointer to next host in the list of all hosts * xargv : arguments to be passed to the transmitter * xargc : number of arguments to be passed to the transmitter * */ struct host { char hostname[MAXHOSTNAMELEN]; char class[MAXCLASSNAMELEN]; char times[MAXTIMENAMELEN]; int pid; int lasttime; int penaltytime; int xmitsernum; int whynot; int valid; int classslot; struct options options; char *xargv[MAXEXECARGS]; int xargc; struct host *next; }; struct class *classlist; struct host *hostlist; /* Predefine the return types of all of the functions */ void addclass(); void addhost(); void clear_invalid(); void daemon_start(); void debug_off(); void debug_on(); void dprintf(); void Dprintf(); void dump_config(); void dump_info(); void idle(); void reset(); struct class *getclass(); void freeclassslot(); int getclassslot(); int getla(); void kill_children(); void log(); void logerr(); void make_invalid(); int parsetime(); void processarg(); void read_config(); void run_queue(); int validtime(); void xmit_done(); SHAR_EOF chmod +x 'defs.h' fi # end of overwriting check if test -f 'newsxd.h' then echo shar: will not over-write existing file "'newsxd.h'" else cat << \SHAR_EOF > 'newsxd.h' /* * USER CONFIGURABLE OPTIONS */ #define default_configfile "/usr/local/etc/newsxd.conf" #define default_pidfile "/usr/tmp/newsxd.pid" #define default_statusfile "/usr/tmp/newsxd.status" /* * If you run CNEWS, enable CNEWS-compatible locking by defining the * CNEWSLOCKING symbol. If you don't do this, there is a race condition * than can result in some articles not being transmitted * * If CNEWSLOCKING is enabled, after renaming the batch file to the work file, * each transmitter attempts to lock and then immediately unlock the news * system to ensure that relaynews is no longer writing into the batch file. */ #define CNEWSLOCKING /* * CNEWS sites will probably want to define default_workfile and * default_batchfile in the following manner: * * #define default_batchfile "/usr/spool/out.going/%s/togo" * #define default_workfile "/usr/spool/out.going/%s/togo.work" */ #define default_batchfile "/usr/spool/batch/%s" #define default_workfile "/usr/spool/batch/%s.work" #define default_xmitlogs "/dev/null" /* * MAXXMITTERS is the maximum number of transmitters that newsxd will * support. MAXCLASSXMITTERS is used to define the dimensions of an array * used to quickly map PIDs back to particular transmitters. */ #define MAXXMITTERS 200 #define MAXCLASSXMITTERS 100 /* * Define SYSLOG if you want logging via syslog. If so, define SYSLOG to * the facility to log at as defined in . This is usually * something like LOG_NEWS or LOG_LOCAL7. * * If your system doesn't support syslog or you don't want to use syslog, * you can have newsxd log to a file instead by defining FAKESYSLOG to be * the name of the file to log to. * * If you are planning on turning on debugging while newsxd is running (by * using SIGUSR1), you should STRONGLY CONSIDER using FAKESYSLOG. Enabling * one level of debugging can log several MBytes/hour of debugging info and * enabling full debugging will easily triple that amount. This will do bad * things to your syslogd! * * DO NOT DEFINE BOTH SYSLOG AND FAKESYSLOG * */ /* #define SYSLOG LOG_NEWS /* normal syslog */ #define FAKESYSLOG "/usr/tmp/newsxd.log" /* fake log file */ /* * Things you probably shouldn't change unless modifying newsxd */ #define MAXCLASSFLAGS 2 /* number of defined class flags */ #define MAXEXECARGS 16 /* max number of args to execv */ #define MAXTIMENAMELEN 40 /* max len of UUCP L.sys-style time */ #define MAXCLASSNAMELEN 8 /* max length of a class name */ #define C_NOWORK 0 /* Don't rename batchfile->workfile */ #define C_NOBATCH 1 /* Don't look for batchfile */ /* * Why isn't a transmitter running (used in status display) */ static char *wnlist[] = { "TTL Penlty", #define WN_PENALTYTIME 0 /* host went over ttl, now penalized */ "TTL Kill", #define WN_TTL 1 /* host hit ttl, killed xmit */ "Class Intv", #define WN_CLASSSTARTINT 2 /* started xmit this class recently */ "Host Intvl", #define WN_HOSTSTARTINT 3 /* started xmit this host recently */ "High Load", #define WN_LOAD 4 /* load too high */ "Wrong Time", #define WN_BADTIME 5 /* wrong time to xmit */ "Max Xmits", #define WN_MAXXMITS 6 /* too many transmitters running */ "RUNNING", #define WN_RUNNING 7 /* it's running! */ "No Work", #define WN_NOWORK 8 /* no work to transmit */ "Bad Rename", #define WN_RENAMEFAILED 9 /* couldn't rename batch -> workfile */ "NotMyTurn", #define WN_NOTMYTURN 10 /* give other host a chance to xmit */ "No Slot!" #define WN_NOSLOT 11 /* no class slot, recompile newsxd */ }; SHAR_EOF chmod +x 'newsxd.h' fi # end of overwriting check if test -f 'patchlevel.h' then echo shar: will not over-write existing file "'patchlevel.h'" else cat << \SHAR_EOF > 'patchlevel.h' #define VERSION 2.5 #define PATCHLEVEL 1 SHAR_EOF chmod +x 'patchlevel.h' fi # end of overwriting check if test -f 'complex.conf' then echo shar: will not over-write existing file "'complex.conf'" else cat << \SHAR_EOF > 'complex.conf' # Define a series of service classes for sending news to other sites: # nlink NNTPlink Transmits (Continuous NNTPXMITs) # high High Priority Transmits (Top-40) # med Medium Prio Transmits (Non Top-40) # low Low Priority Transmits (Endnodes) # batch Batched (with sendbatch) newsfeeds class nlink maxxmits=20 interval=60 maxload=10 noworkfile xmit nlink /usr/local/lib/news/nntplink nntplink %h:%b class high maxxmits=99 interval=60/20 maxload=8 ttl=1800 class med maxxmits=5 interval=300 maxload=6 ttl=1800/60 class low maxxmits=3 interval=1200 maxload=5 ttl=1100/60 nice=10 class batch maxxmits=1 interval=3600 maxload=5 ttl=1800/1800 xmit batch /usr/local/lib/news/sendbatch sendbatch %f %h # Define the default news transmitter xmit DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %h:%w # Check the transmit queue every seconds (this should be at least as # low as the smallest "interval" in all of the transmission classes). queueinterval 20 # In all of the following options, %s is replaced by the host name of the # system being sent to. # File news places articles paths/ids in batchfile /usr/spool/batch/%s # File a news transmitter wants articles paths/ids in workfile /usr/spool/batch/%s.work # Where to log the output of a news transmitter (default is /dev/null) # [leave it as the default of /dev/null for now] # nntplogs /usr/spool/batch/%s.log # Hosts to send news to. Each line is of the format: # CLASS VALID START # host HOSTNAME NAME TIMES OPTIONS host dorothy low Any host toto low Any host wizard low Any host witch low Any host tinman low Any host lion low Any host cactus.biz.com low Any host endnode.foobar.edu low Any2000-0500 host biggernode.foobar.edu med SaSu|Wk1730-0730 host bignode.company.com med Any host midsize.company.com med Any host university.podunk.edu med Any host mrbackbone.bigu.edu high Any host gateway.bizness.com high Any host supernews.hellou.edu high Any host mrnntp.aloha.edu high Any host hello.world.edu high Any host supernews.foou.edu nlink Any host backbone.newssite.edu nlink Any host fred batch Any nice=20 flags=-s500000 interval=86400 host barney batch Any nice=20 flags=-s250000 interval=86400 host wilma batch Any nice=20 flags=-s500000 host betty batch Any nice=20 flags=-s500000|-m500000 host kitty batch SaSu|Wk1730-730 flags=-c|-s250000 host dino batch SaSu|Wk1730-730 flags=-c|-s250000 host bambam batch Sa interval=86400 # Notes: Only send news to biggernode.foobar.edu during non-business hours # endnode.foobar.edu only wants news transmitted from 8PM to 5AM. # Only send news to fred and barney once per day (every 24 hours). # Do one batching run for bambam each Saturday. SHAR_EOF chmod +x 'complex.conf' fi # end of overwriting check if test -f 'newsxd.conf' then echo shar: will not over-write existing file "'newsxd.conf'" else cat << \SHAR_EOF > 'newsxd.conf' # Define transmission service classes and alternate transmitters # nlink NNTPlink Transmits (Continuous NNTPXMITs) # high High Priority Transmits (Top-40) # med Medium Prio Transmits (Non Top-40) # low Low Priority Transmits (Endnodes) class nlink maxxmits=99 interval=60 maxload=10 noworkfile debug=-d xmit nlink /usr/local/lib/news/nntplink nntplink -L100 %d %h:%b class high maxxmits=3 interval=1800 maxload=8 debug=-d class med maxxmits=3 interval=7200 maxload=6 nice=15 debug=-d class low maxxmits=2 interval=14400 maxload=4 nice=15 debug=-d class batch maxxmits=1 interval=14400 maxload=6 nice=15 xmit batch /usr/local/lib/news/sendbatch sendbatch %f %h # define the default transmitter xmit DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %d %h:%w # Check the transmit queue every seconds (this should be at least as low # as the smallest "interval" in all of the transmission classes). queueinterval 20 # In all of the following options, %s is replaced by the host name of the # system being sent to. # File news places articles paths/ids in batchfile /usr/spool/batch/%s # File a news transmitter wants articles paths/ids in workfile /usr/spool/batch/%s.work # Where to log the output of a news transmitter (default is /dev/null) # xmitlogs /tmp/paramlog # Hosts to send news to. Each line is of the format: # CLASS VALID XMIT # host HOSTNAME NAME TIMES OPTIONS host cec2 high Any host dinorah high Any host gauss low Any host wubios high Any host wuche2 high Any host wuibc low Any host wuphys low Any # host sbctri.sbc.com low Any host brazos.rice.edu low Any host kuhub.cc.ukans.edu nlink Any # host wums2 low Any flags=-D host rouge.usl.edu low Any host husc6.harvard.edu med Any host swbatl.sbc.com med Any host dogie.macc.wisc.edu high Any host emory.mathcs.emory.edu high Any host eddie.mit.edu high Any host decwrl.dec.com nlink Any flags=-C200 host mailrus.cc.umich.edu nlink Any flags=-C200 host nigel.ee.udel.edu nlink Any flags=-C200 host psuvax1.cs.psu.edu nlink Any flags=-C200 host rex.cs.tulane.edu nlink Any flags=-C200 host s.ms.uky.edu nlink Any flags=-C200 host uwm.edu nlink Any flags=-C200 host tness7.sbc.com nlink Any flags=-C200 host uunet.uu.net nlink Any flags=-C1000000 host bu.edu nlink Any flags=-C200 host usc.edu nlink Any flags=-C200 host zaphod.mps.ohio-state.edu nlink Any flags=-C200 host cs.utexas.edu nlink Any flags=-C200 host brutus.cs.uiuc.edu nlink Any flags=-C200 host wums2 batch Any flags=-s500000 host dranet batch Any flags=-s250000 host biolgy batch Any flags=-s500000 host crygtw batch SaSu|Wk1730-730 flags=-s250000|-c host jgaltstl batch SaSu|Wk1730-730 flags=-c|-s250000|-m10000000 host plus5 batch SaSu|Wk1730-730 flags=-c|-s250000|-m10000000 host slustl batch SaSu|Wk1730-730 flags=-c|-s250000|-m10000000 host hpuslma batch SaSu|Wk1730-730 flags=-c|-s250000|-m10000000 host hilco2 batch SaSu|Wk1730-730 flags=-c|-s250000|-m10000000 SHAR_EOF chmod +x 'newsxd.conf' fi # end of overwriting check if test -f 'simple.conf' then echo shar: will not over-write existing file "'simple.conf'" else cat << \SHAR_EOF > 'simple.conf' # Define a service class that just runs an nntpxmit to each host # every hour. Don't run nntpxmit if the load goes over 8. class normal maxxmits=1 interval=3600 maxload=8 # Define the default news transmitter xmit DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %h:%w # Check the list of hosts every 10 minutes to see if we can send news to # someone yet. queueinterval 600 # In all of the following options, %s is replaced by the host name of the # system being sent to. # File news places articles paths/ids in batchfile /usr/spool/batch/%s # File a news transmitter wants articles paths/ids in workfile /usr/spool/batch/%s.work # Hosts to send news to. Each line is of the format: # CLASS VALID START # host HOSTNAME NAME TIMES host dorothy normal Any host toto normal Any host wizard normal Any host witch normal Any host tinman normal Any host lion normal Any SHAR_EOF chmod +x 'simple.conf' fi # end of overwriting check if test -f 'newsxd.8' then echo shar: will not over-write existing file "'newsxd.8'" else cat << \SHAR_EOF > 'newsxd.8' .TH newsxd 8 .SH NAME newsxd \- daemon for managing the transmission of news .SH SYNTAX .B newsxd [\-debug] [\-DEBUG] [\-newsxdebug] [\-c \fIfile\fR] [\-v] [\-pid \fIfile\fR\|] [\-status \fIfile\fR] [\-log \fIfile\fR] .br .SH DESCRIPTION The .I newsxd program is a configurable daemon for controlling the transmission of netnews. It allows the definition of multiple categories of service, by setting a number of parameters defining things such as how often news is to be transmitted, the number of news transmitters that can be active at one time, the maximum time a transmitter may spend sending netnews to a single host, and the maximum system load at which netnews transmitters may be started. .I newsxd can also be used to start up other programs which must be restarted upon exit, or which must be run at regular intervals with greater granularity than .I cron(8) allows. .PP When starting up, the .I newsxd program reads a configuration file (usually \fI/usr/local/etc/newsxd.conf\fR) which specifies all of the classes of service and their characteristics, where certain data files are to be stored and what hosts netnews is to be transmitted to. .PP .I newsxd is a daemon, and while it replaces such programs as .I nntpsend, it is not meant to be run from .I cron(8), but rather from /etc/rc.local. If you have multiple copies of .I newsxd running the results will be unpredictable. .SH OPTIONS .IP -debug 15 Enables debugging. If debugging is enabled, .I newsxd will not switch to daemon mode (i.e. will not detach itself from the controlling terminal). .IP -DEBUG Enables painfully verbose debugging. .IP -newsxdebug Enables debugging when running .I nntpxmit. Also causes .I nntpxmit to be run synchronously .I (newsxd will wait for the .I nntpxmit to complete before continuing with other hosts). .IP "-c \fIfile\fR" Specifies an alternate configuration file for .I newsxd to load. .IP "-pid \fIfile\fR" Specifies an alternate file for .I newsxd to write its PID into when starting up. .IP "-status \fIfile\fR" Specifies an alternate file for .I newsxd to write its status into upon receipt of a QUIT signal. .IP "-log \fIfile\fR" Specifies an alternate file for .I newsxd to write its logging information into when FAKESYSLOG is being used. .IP "-v" Displays the version of newsxd that you are running. \fINewsxd\fR does NOT start running if the -v switch is specified. .RE .PP The configuration file for .I newsxd consists of commands from the list below. Comments are preceded by pound (\#) signs and continue to the end of the line. Case is significant. .PP class \fItype [options]\fR defines a class of service. \fItype\fR can be any printable string less than eight characters long (0, 5, 9, high, low, boring, etc.) There are a number of options that can be specified (as a space-separated list) that will modify the behavior of a service class: .RS +.5i .IP maxxmits=\fIn\fR 15 specifies the maximum number of netnews transmitters that .I newsxd will allow to be running simultaneously for this service class. The default value is 1. .IP interval=\fIn[/m]\fR specifies the start-to-start interval (in seconds) between successive invocations of a netnews transmitter for a single host. The default value is 60 seconds. The optional parameter \fIm\fR specifies the number of seconds to wait between starting new transmitters for ANY host in this service class; this is useful to prevent many transmitters from being started simultaneously and spiking the system load. The intra-class startup interval, \fIm\fR, should not divide the \fIqueueinterval\fR (below) evenly. .IP maxload=\fIn\fR defines the maximum load at which .I newsxd will start transmitters for this service class. If the load passes beyond this value, no new transmitters will be started until the load drops. Any currently running transmitters will not be affected. .IP ttl=\fIn[/m]\fR gives the maximum time-to-live in seconds for any invocation of a netnews transmitter. The default value is 999999 seconds (about 11 days). The optional parameter, \fIm\fR, gives the number of seconds to penalize a transmitter that has exceeded its ttl; this is the number of seconds to prevent a new transmitter from starting up for the penalized host. .IP noworkfile Normally the article batch file for the host is renamed before executing the netnews transmitter as defined by the \fIworkfile\fR below. This option causes the renaming to be bypassed. .IP nobatchfile Normally an article batch file must exist for the host before .I newsxd will execute the transmitter for the host. If this option is defined, the check for a batch file will be bypassed. .RE .IN -5 .PP xmit \fIclassname programpath programname [parameters]\fR defines an alternate netnews transmission program, for which command-line options can be specified. You *MUST* define a transmission program for the class .I DEFAULT, which will be used as the default news transmitter for all other classes. See the example configuration shown below. \fINewsxd\fR will use the environment variable PATH that it was invoked with to search for the program if an explicit path is not given. .RS +.5i .IP classname 15 is the name of an already-defined service class which is to use this transmission program. .IP programpath is the path of the file to execute .IP programname is the name to be passed to the program as argv[0]; usually the last component of \fIprogrampath\fR. .IP [parameters] optional parameters and options (up to nine) to be passed to the news transmitter. In .I parameters, the following conversions will be made: .RS 15 .IP %f 5 will be replaced with the per-host flags specified by the .I host command (see below). .IP %h will be replaced with the host name. .IP %w will be replaced with the name of the workfile for the host. .IP %b will be replaced with the name of the batchfile for the host. .IP %s will be replaced by an integer which is unique to all of the active transmitters for that class. Newsxd will select the lowest unused integer each time a transmitter is started. These 'slot numbers' start at 0. .RE .RE .PP queueinterval \fIseconds\fR specifies the number of seconds between "queue runs". During each queue run .I newsxd will check each host to see if a netnews transmitter can be started for that host. The queueinterval should be at least as small as the smallest interval specified in all of the \fIclass\fR definitions. The default value for \fIqueueinterval\fR is 60 seconds. .PP batchfile \fIfile\fR specifies the file path where the batch files (files listing article paths or IDs to be used by a netnews transmitter) are stored. A %s in \fIfile\fR will be replaced by the name of the current host. Unless the .I nobatchfile option was specified for the host's service class, this file must exist before a netnews transmitter will be executed for the host. The default value for \fIbatchfile\fR is defined in newsxd.h and is normally \fI/usr/spool/batch/%s\fR. .PP workfile \fIfile\fR specifies the file path which the batch files are to be renamed to before executing the netnews transmitter. A %s in \fIfile\fR will be replaced by the name of the current host. If the \fInoworkfile\fR option was specified for this host's service class, the batch file will NOT be renamed. The default value for \fIworkfile\fR is defined in newsxd.h and is normally \fI/usr/spool/batch/%s.work\fR. .PP xmitlogs \fIfile\fR where to log the output of each netnews transmitter. If you need to keep the information printed by a transmitter, use this option. If you don't need to use up the disk space, leave \fIxmitlogs\fR undefined and output will be sent to /dev/null. .PP host \fIhostname classname xmittimes [options]\fR defines a host which to which .I newsxd will transmit netnews. .RS +.5i .IP hostname 15 The name of the host to pass to the netnews transmitter. .IP classname The name of the service class that this host is in. .IP xmittimes The time(s) to allow new transmitters to start for this host. See the manpage for .I L.sys(5) for the format of .I xmittimes. .IP [options] There are some options which can be used to modify the behavior of the netnews transmitter for a host: .RS +.5i .IP nice=\fIn\fR 15 This optional value is added to the \fInice(3)\fR of the netnews transmitter. To be able to run at higher priorities (a lower \fInice\fR value), .I newsxd must be .I setuid(3) root; otherwise .I newsxd should be .I setuid(3) news. If no \fIdeltanice\fR value is specified, the nice of the transmitter is not modified by .I newsxd. .IP flags=\fIn\fR 15 Used to specify optional flags to be passed to the netnews transmitter for the host. The flags must be separated by vertical bars (|), not spaces, in the .I newsxd.conf file. Note that "-l something" would be TWO flags and you would say flags=-l|something. .I Newsxd will automatically separate the flags before calling the netnews transmitter. XXX .IP ttl=\fIn[/m]\fR The \fIttl\fR option may be used to override the default value established by the \fIclass\fR command (described above). .IP interval=\fIn[/m]\fR The \fIinterval\fR option may be used to override the default value established by the \fIclass\fR command (described above). .IP maxload=\fIn\fR The \fImaxload\fR option may be used to override the default value established by the \fIclass\fR command (described above). .IP maxxmits=\fIn\fR The \fImaxxmits\fR option may be used to override the default value established by the \fIclass\fR command (described above). .RE .IN -5 .PP .SH "SIMPLE EXAMPLE" The following is an example of a simple configuration file: .nf .ft CW # Define a service class that just runs an nntpxmit to each host # every hour. Don't run nntpxmit if the load goes over 8. class normal maxxmits=1 interval=3600 maxload=8 # Define the default news transmitter xmit DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %h:%w # Check the list of hosts every 10 minutes to see if we can send news to # someone yet. queueinterval 600 # In all of the following options, %s is replaced by the host name of the # system being sent to. # File news places articles paths/ids in batchfile /usr/spool/batch/%s # File a news transmitter wants articles paths/ids in workfile /usr/spool/batch/%s.work # Hosts to send news to. Each line is of the format: # CLASS VALID START # host HOSTNAME NAME TIMES host dorothy normal Any host toto normal Any host wizard normal Any host witch normal Any host tinman normal Any host lion normal Any .ft P .fi .PP .RE .LP .SH "COMPLEX EXAMPLE" The following is an example of a more complex configuration file that uses most of the options supported by .I newsxd: .nf .ft CW # Define a series of service classes for sending news to other sites: # nlink NNTPlink Transmits (Continuous NNTPXMITs) # high High Priority Transmits (Top-40) # med Medium Prio Transmits (Non Top-40) # low Low Priority Transmits (Endnodes) # batch Batched (with sendbatch) newsfeeds class nlink maxxmits=20 interval=60 maxload=10 noworkfile xmit nlink /usr/local/lib/news/nntplink nntplink %h:%b class high maxxmits=99 interval=60/20 maxload=8 ttl=1800 class med maxxmits=5 interval=300 maxload=6 ttl=1800/60 class low maxxmits=3 interval=1200 maxload=5 ttl=1100/60 class batch maxxmits=1 interval=3600 maxload=5 ttl=1800/1800 xmit batch /usr/local/lib/news/sendbatch sendbatch %f %h # Define the default news transmitter xmit DEFAULT /usr/local/lib/news/nntpxmit nntpxmit %h:%w # Check the transmit queue every seconds (this should be at least as # low as the smallest "interval" in all of the transmission classes). queueinterval 20 # In all of the following options, %s is replaced by the host name of the # system being sent to. # File news places articles paths/ids in batchfile /usr/spool/batch/%s # File a news transmitter wants articles paths/ids in workfile /usr/spool/batch/%s.work # Where to log the output of a news transmitter (default is /dev/null) # xmitlogs /usr/spool/batch/%s.log # Hosts to send news to. Each line is of the format: # CLASS VALID START # host HOSTNAME NAME TIMES OPTIONS host dorothy low Any nice=10 host toto low Any nice=10 host wizard low Any nice=10 host witch low Any nice=10 host tinman low Any nice=10 host lion low Any nice=10 host cactus.biz.com low Any nice=10 host endnode.foobar.edu low Any2000-0500 nice=10 host biggernode.foobar.edu med SaSu|Wk1730-0730 host bignode.company.com med Any host midsize.company.com med Any host university.podunk.edu med Any host mrbackbone.bigu.edu high Any host gateway.bizness.com high Any host supernews.hellou.edu high Any host mrnntp.aloha.edu high Any host hello.world.edu high Any host supernews.foou.edu nlink Any host backbone.newssite.edu nlink Any host fred batch Any nice=20 flags=-s500000 interval=86400 host barney batch Any nice=20 flags=-s250000 interval=86400 host wilma batch Any nice=20 flags=-s500000 host betty batch Any nice=20 flags=-s500000|-m500000 host kitty batch SaSu|Wk1730-730 flags=-c|-s250000 host dino batch SaSu|Wk1730-730 flags=-c|-s250000 host bambam batch Sa interval=86400 # Notes: Only send news to biggernode.foobar.edu during non-business hours # endnode.foobar.edu only wants news transmitted from 8PM to 5AM. # Only send news to fred and barney once per day (every 24 hours). # Do one batching run for bambam each Saturday. .ft P .fi .PP .RE .LP .SH "CONTROLLING NEWSXD" The following signals have the specified effect when sent to the server .I named process using the .I kill command: .IP SIGHUP 13 Causes newsxd to reload newsxd.conf and remove (kill) any hosts or transmitters which are no longer defined. .IP SIGTERM Causes newsxd to shut down, killing all active transmitters .IP SIGQUIT Dumps the current newsxd status to .I /usr/tmp/newsxd.status .IP SIGIOT Causes newsxd to kill all active transmitters and go into idle mode. Send a HUP signal to newsxd to return to normal operating mode. .IP SIGIO Causes newsxd to go into idle mode, where no new transmitters are started. Send a HUP signal to newsxd to return to normal operating mode. .IP SIGTRAP Causes newsxd to write a DETAILED list of the contents of all important internal data structures to .I /usr/tmp/newsxd.status.dump .IP SIGUSR1 Increases the current debugging level. Caution: the debugging information can get very voluminous, especially if DEBUG is enabled. .IP SIGUSR2 Decreases the current debugging level. .SH "THE STATUS FILE" The .I newsxd.status file, which is created when a SIGQUIT signal is sent to .I newsxd, shows the current state of all of the hosts managed by .I newsxd. There are several pieces of information listed for each host, including the host name, the times during which a new netnews transmitter can be started, the last time a netnews transmitter was started, and a "Why Not Running" field which indicates why a netnews transmitter is not currently running for that host. The various types of "Why Not Running" messages include: .IP "TTL Penlty" 15 The netnews transmitter for the host ran longer than the time-to-live defined for the service class, and the host is currently being penalized. .IP "TTL Kill" The netnews transmitter for the host was just killed because it ran longer than the time-to-live defined for the service class. .IP "Class Intv" No new transmitters in this service class can start up yet because the intra-class transmitter startup interval hasn't passed. See the .I interval option under .I class, above. .IP "Host Intvl" No new transmitters for this host can start up yet because a transmitter has already been run for this host recently (see the .I interval option under .I class, above). .IP "High Load" The system load is too high to start new netnews transmitters for this service class. See the .I maxload option under .I class, above. .IP "Wrong Time" The current time doesn't fit any of the allowed startup times specified for the host. .IP "Max Xmits" The maximum number of netnews transmitters for this class are already running. See the .I maxxmits option under .I class, above. .IP "RUNNING" A netnews transmitter for this host is currently running. .IP "No Work" There are currently no articles to send to this host. .IP "Bad Rename" .I newsxd couldn't rename the host's .I batchfile to the .I workfile. .IP "NotMyTurn" The host has already had a chance to transmit news and now it's time for the other hosts to get a chance. .I Newsxd uses a round-robin scheduling algorithm to insure the fair transmission of netnews. .SH RESTRICTIONS Does not do exponential backoff when the transmitter for a host fails. .SH BUGS No known bugs exist in .I newsxd, but the wish list of features to add is quite long... .SH FILES .IP /usr/local/etc/newsxd.conf 28 .I newsxd configuration file .IP /usr/tmp/newsxd.pid Process ID number .IP /usr/tmp/newsxd.status Dump of .I newsxd status .IP /usr/spool/batch/* batch and work files for .I newsxd and netnews transmitters. .SH "SEE ALSO" nntpxmit(1) .SH AUTHOR Chris Myers SHAR_EOF chmod +x 'newsxd.8' fi # end of overwriting check # End of shell archive exit 0