Subject: v06i052: Usenet news batcher control program (newbatchA) Newsgroups: mod.sources Approved: rs@mirror.UUCP Submitted by: cca!caip!cbmvax!bpa!espo (Bob Esposito) Mod.sources: Volume 6, Issue 52 Archive-name: newbatchA [ This is the first of two batched news utility programs (BNUP, to coin an acronym). It was written on a SystemV machine, but it looks like it would be fairly easy to convert to BSD and, e.g., the directory library. Stuff dealing with the UUCP queue is much less portable, of course, but Bob nicely provides a default mechanism. Take a look at the check_uucp routine, however -- I think you may want a different default value. Also, I added a modified xerror routine that doesn't depend on knowing the internal's of the FILE struct. I haven't tested it, but a "grep xerror *." seems to say I'm ok; add -DUSE_PORT_CODE for my version. --r$ ] #!/bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # Contents: README nbatcher.1 nbatcher.ctl nbatcher.doc Makefile # bst.c checkwork.c define.c logger.c main.c nbatcher.c parse.c echo x - README sed 's/^XX//' > "README" <<'@//E*O*F README//' XXThe program provides a better way to handling batching of USENET news XXto neighboring sites. It works with 2.10B and later, including XX2.10.3B, which provides compression batching. XXPlease send any questions and bug reports to me (bpa!espo) for XXdistribution to the net. This software is public domain, and cannot be XXsold for any profit. XXNbatcher was written for UNIX (trademark of AT&T) System V, but should XXbe compatible with most version currently being used today. It is XXpresently running on a VAX (trademark of DEC) 11/780 feeding 5 remote XXsites with news. Two important issues MUST be noted here. XXSince nbatcher checks the UUCP directory for each site listed in the XXcontrol file, directory configuration should be UUCPDIR/sitename, e.g. XX/usr/spool/uucp/foo for site foo. But since not everyone is generic, XXI've allowed nbatcher to skip over the UUCP byte counting routine if XXthis is not so. In addition to this, some uucpcleanup daemons remove XXthe site directory if there's nothing spooled there. When this XXhappens, nbatcher will notify you of this and continue on. XXThe other issue is that you MUST configure your NEWSLIB/sys file using the XXbatch syntax as described in the USENET Installation document. Field 3 XXshould contain the `F' flag indicating a batched transmission for that XXsite and field 4 should contain the filename where news article's full XXpathname will be appended to. Nbatcher requires that the filename in XXfield 4 match the sitename in the control file. For example, the entry: XX foo:net,mod,usa,na,to.foo:F:/usr/spool/batchnews/foo XXsays that all news articles going to site `foo' will be batched, using XXthe file `foo' in /usr/spool/batchnews. Nbatcher's control file entry: XX foo:3,14,22:16:150000: XXwill get the news article's full pathname from /usr/spool/batchnews/foo XXfor batching. This requirement MUST be adhered to for nbatcher to work XXcorrectly. I believe most sites that batch news use this type of XXconfiguration, since its easy to keep track of a remote site's work. XXNote that the name of the directory "/usr/spool/batchnews" is set XXin the Makefile. XXThe manual page describes the control file, as does nbatcher.doc. Note XXthat even though nbatcher indicates max bytes has been reached, if that XXsite gets compressed batches, the next time nbatcher runs for that site XXwork could get scheduled. XXAlso included is a utility program called "bst," BatchSTatus, which XXshows who many news articles are currently in the batch file for each XXsystem. Just type "make bst" for that and copy it to where you want, XXusually LIBDIR. Note that bst does reads on the directory structure XXdirectly. XXInstallation is simple: look at the first few #define's in nbatcher.h; XXalso edit the Makefile for the appropriate BATCHDIR and LIBDIR for your XXsite. Type "make" or "make install." XXNOTE: Read the comments in parse.c concerning MAX_BYTES. This is the XXmaximum amount of bytes per site that's allowed in the control file for XXqueue_size. Change it at your own risk! XX Bob Esposito XX bpa!espo XX Bell of Penna. @//E*O*F README// chmod u=rw,g=rw,o=rw README echo x - nbatcher.1 sed 's/^XX//' > "nbatcher.1" <<'@//E*O*F nbatcher.1//' XX.TH NBATCHER 1 LOCAL XX.SH NAME XXnbatcher \- new batching system for news XX.SH SYNOPSIS XX.B nbatcher XX.IR "(run out of " cron ".)" XX.SH DESCRIPTION XX.PP XX.I Nbatcher XXis a program designed to send batched USENET data out in an orderly and XXcontrolled fashion, while providing alternative transmission methods. XXAs such, it is a replacement for XX.I csendbatch XXand the like, which typically require many entries in XX.IR crontab . XX.I Nbatcher XXis intended to be run hourly out of XX.I cron XXas the USENET administrator (NEWSID). XX.PP XX.I Nbatcher XXscans the file XX.I nbatcher.ctl XXin the NEWSLIB directory to determine if work should be spooled for a system. XXIn the control file, lines starting with asterisks are ignored; data lines XXare comprised of five colon\-separated fields: XX.RS XXsite:hour:bits:queue_size:command XX.RE XX.TP ``site'' XXName of the USENET neighbor; it is the same as the site in the news XX.I sys XXfile. XX.TP ``hours'' XXThis field is patterned after XX.IR cron 's. XXIf the hour is ``off,'' no work is spooled for the site. XXAn hour of ``*'' matches every hour. XXIt is also possible to specify specific hours, (e.g., 8, 09, or 22), a XXcomma\-separated list (e.g., 8,09,22), or a twenty\-four range, like XX1-\15 for 10am through 3pm and 22\-4, for 10pm through 4am. XX.TP ``bits'' XXThis field specifies the number of bits to use in compression; it should be XXa number between nine and 16, inclusive, or null. XXIf a number is specified, it is passed on to the XX.I compress XXprogram via the ``\-b'' flag. XX.TP ``queue_size'' XXThis field specifies the maximum number of bytes allowed in the UUCP queue XXfor this site. XXThe default is 100K. XXThe UUCP queue size is determined by looking in the XX.IR /usr/spool/uucp/ site XXdirectory; if it doesn't exist, the check is bypassed. XXIf there is data in the UUCP queue, XX.I nbatcher XXwill only queue up as many USENET transfers as will fit within the limit XXspecified by the ``queue_size'' field. XX.TP ``command'' XXThis field is used to specific the UUCP command that should be used to queue XXthe job; as distributed, the default is ``uux \- \-r site!rnews''; note the XXabsence of the ``\-z'' flag. XX.PP XXTo set up a USENET neighbor to be controlled by XX.IR nbatcher , XXthe news XX.I sys XXentry for the neighbor must be modified to specify the ``F'' flag, and the XXfile used to contain the article names must be XX.RI BATCHDIR/sysname , XXwhere BATCHDIR is set in the Makefile as distributed. XX.SH FILES XX.TP NEWSLIB/nbatcher.log XXA logfile of failures, postponements, etc. XX.SH BUGS XXParsing of the control file is fairly robust, but not perfect. @//E*O*F nbatcher.1// chmod u=rw,g=rw,o=rw nbatcher.1 echo x - nbatcher.ctl sed 's/^XX//' > "nbatcher.ctl" <<'@//E*O*F nbatcher.ctl//' XX* XX* NBATCHER.CTL XX* Edit and install in your NEWSLIB directory. XX* XX* Comments start with *; data lines look like: XX* site:hours:bits:queue_size:command XX* Where XX* site = name of the remote site XX* hour = when to do work (* is all, off is never, 22-4 is ok) XX* bits = passed on to compress via -b; null gets default XX* queue_size = Max # bytes allowed in UUCP queue before postponing XX* command = optional command line XX* XX* See manpage and README for more info. @//E*O*F nbatcher.ctl// chmod u=rw,g=rw,o=rw nbatcher.ctl echo x - nbatcher.doc sed 's/^XX//' > "nbatcher.doc" <<'@//E*O*F nbatcher.doc//' XXDETAILED DESCRIPTION OF "NBATCHER.CTL" FILE XX------------------------------------------- XXAs distributed, nbatcher.ctl contains just a terse summary of its XXformat. For each site you feed news to, providing that site uses the XX":F:BATCHDIR/site" batching syntax in the sys file, a corresponding XXentry should exist in nbatcher.ctl Each line is a five-field, XXcolon-separated entry indicating what to do for that site. The default XXfor BATCHDIR is /usr/spool/batchnews. XXThe format is: XX site:hour:bits:queue_size:command XXThe site field is the name of the UUCP site that will get the batched XXnews. There MUST be a file in the BATCHDIR directory with the XXsitename. Nbatcher will complain about mismatches. This file contains XXa full-path listing of the files to batch. XXNext is the hour field. The syntax directly imitates the crontab entry XXfor hour. If hour = "*", than assume a match for every hour. If hour XX= "off", then no work is ever spooled for this site. (This is the only XXdifference from crontab). You can specify a specific hour, like 8 or XX09 or 22. Or a range of hours, like 10-15, meaning check for work from XX10am thru 3pm. You can also cycle thru a 24-hour period by saying XX22-4, which matches for 10pm thru 4am. Also, hours comma separated XXlike 7,14,21, says check for work at 7 AM, 4PM and 9PM only. This XXgives lots of flexibility for sites that feed multiple remotes. XXNext is the bits field, which has a value of 9-16, or may be left blank. XXIf non-null, this field is directly passed on to compress with the -b XXflag. If it is null, then no compression is done for this site. XXThe queue_size field is the maximum number of bytes allowed on the UUCP XXqueue at any time. It defaults to 100K bytes, and if it's greater than XX1MB (see parse.c about MAX_BYTES), than it uses 1MB as the default XXnumber of bytes. XXWhat nbatcher does is first check the UUCPDIR for that site and sums up XXthe number of bytes already on-queue. The size of each news article is XXaccumulated prior to batching to the tempfile, and this accumulation + XXthe UUCP on-queue bytes are checked to see if they surpass the queue_size XXvalue. If not, things proceed normally. But if it would exceed the XXmax value, then spool what's already been batched, and save the XXremainder of the articles for the next scheduled batch. XXThis is so noted in the nbatcher.log file, showing the UUCP bytes that XXwere on-queue (if any), and the number of bytes that were spooled. XXAlso, if nbatcher is run from a terminal instead of from cron, a copy XXof what gets logged is sent to the terminal. XXThe last field is the command field. This optional field is used for XXspecific UUCP command execution. As written, it defaults to "uux - -r XXsite!rnews". Since my uux doesn't require the -z option for rnews, I XXleft it out of the UUX define in nbatcher.h This can easily be changed XXfor your own taste, or just use the command field. XXExample: XX site-A:3,10:16:450000: XXCheck for work for site-A at 3AM and 10AM. Use compress with XX16 bits and only spool up to 450K bytes, using "uux - -r site-A!rnews". XXAnother example: XX foo:23-4::300000:uux - -r -z foo!rnews XXCheck for work for foo between 11PM and 4AM. No compression is used XXand spool up to 300K bytes using the command field. XXThis format should help ease UUCP congestion on the local site for XXnews. I currently feed 5 remote sites, compressed and non-compressed XXformats, and have noticed a vast improvement in disk space as well as XXout port availability for UUCP. It has allowed me to check for work XXfor all sites every hour, since there's a limit on how much gets XXqueued. And if the remote doesn't answer on the hourly UUCP poll, so XXwhat! Nbatcher just won't spool any more until the queue_size limit XXon-queue is reduced. XXNbatcher was designed to weed out any illegal syntax in the control XXfile, but it's not bug-proof, so use some discretion. XXBob Esposito XXBell of Penna. XXJune 1986 @//E*O*F nbatcher.doc// chmod u=rw,g=rw,o=rw nbatcher.doc echo x - Makefile sed 's/^XX//' > "Makefile" <<'@//E*O*F Makefile//' XX# XX# Makefile for nbatcher XX# XX# R.J. Esposito XX# Bell of Penna. XX# June 1986 XX# XX# You MUST define BATCHDIR as the place where USENET XX# puts the articles to be batched. XX# XX# LIBDIR is where you USENET library is and also XX# MUST be defined. XXBATCHDIR = /usr/spool/batchnews XXLIBDIR = /misc/lib/usenet XXCFLAGS = -O -c XXLFLAGS = -s XXDFLAGS = -DBATCHDIR='"$(BATCHDIR)"' -DLIBDIR='"$(LIBDIR)"' XXOBJS = define.o main.o parse.o checkwork.o nbatcher.o logger.o XXSRC = define.c main.c parse.c checkwork.c nbatcher.c logger.c nbatcher.h bst.c XXDOCS = README nbatcher.ctl nbatcher.doc XXall: $(OBJS) XX $(CC) $(DFLAGS) $(LFLAGS) -o nbatcher $(OBJS) XX chmod 0755 nbatcher XXinstall: all XX cp nbatcher $(LIBDIR) XX chmod 0755 $(LIBDIR)/nbatcher XX cp nbatcher.ctl $(LIBDIR)/nbatcher.ctl XX chmod 0644 $(LIBDIR)/nbatcher.ctl XXdefine.o: nbatcher.h define.c XX $(CC) $(CFLAGS) $(DFLAGS) define.c XXmain.o: nbatcher.h main.c XX $(CC) $(CFLAGS) $(DFLAGS) main.c XXparse.o: nbatcher.h parse.c XX $(CC) $(CFLAGS) $(DFLAGS) parse.c XXcheckwork.o: nbatcher.h checkwork.c XX $(CC) $(CFLAGS) $(DFLAGS) checkwork.c XXnbatcher.o: nbatcher.h nbatcher.c XX $(CC) $(CFLAGS) $(DFLAGS) nbatcher.c XXlogger.o: nbatcher.h logger.c XX $(CC) $(CFLAGS) $(DFLAGS) logger.c XXbst: bst.c XX $(CC) $(CFLAGS) $(DFLAGS) bst.c XX $(CC) $(LFLAGS) -o bst bst.o XXclean: XX rm -f *.o *.shar XXclobber: clean XX rm -f nbatcher XXshar: XX shar -v $(SRC) $(DOCS) Makefile > nbatcher.shar @//E*O*F Makefile// chmod u=rw,g=rw,o=rw Makefile echo x - bst.c sed 's/^XX//' > "bst.c" <<'@//E*O*F bst.c//' XX/* XX * bst.c - a utility for indicating how many XX * news articles are ready for batching XX * for each site in the BACTHDIR directory. XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include XX#include XX#include XXchar buf[512]; XXFILE *dd; XXstruct direct dp; XXstruct stat st; XXmain() XX{ XX int fd, j; XX int bcnt, lcnt; XX if(chdir(BATCHDIR) != 0) { XX perror(BATCHDIR); XX exit(1); XX } XX if((dd=fopen(".", "r")) == NULL) { XX printf("can't open %s\n", BATCHDIR); XX exit(1); XX } XX while((fread((char *)&dp, sizeof(dp), 1, dd)) == 1) { XX if(dp.d_ino == 0 || dp.d_name[0] == '.') XX continue; XX if(stat(dp.d_name, &st) != 0) { XX printf("can't stat %s\n", dp.d_name); XX exit(1); XX } XX if(st.st_size <= 0 ) XX continue; XX if((fd=open(dp.d_name, 0)) < 0) { XX printf("can't open %s\n", dp.d_name); XX exit(1); XX } XX lcnt = 0; XX while((bcnt=read(fd,buf,512)) > 0) { XX for(j=0; j<=bcnt; j++) XX if(buf[j] == '\n') XX lcnt += 1; XX } XX close(fd); XX printf("%s\t %d article", dp.d_name, lcnt); XX printf("%c\n", lcnt > 1 ? 's' : ' '); XX } XX} @//E*O*F bst.c// chmod u=rw,g=rw,o=rw bst.c echo x - checkwork.c sed 's/^XX//' > "checkwork.c" <<'@//E*O*F checkwork.c//' XX/* XX * XX * checkwork.c - look to see if there's any work XX * to do for a site. XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include XX#include XX#include XX#include XX#include XX#include XX#include "nbatcher.h" XXwork_to_do () XX{ XX register char *p; XX struct tm *localtime(), *tp; XX struct stat st; XX char buf[BUFSIZ]; XX long time(), clock; XX int hour; XX short num, upper, lower; XX sprintf (buf, "%s/%s", BATCHDIR, ep.site); XX if (stat(buf, &st) < 0) XX xerror ("bad stat on %s\n", buf); XX /* if the size of the batch file is XX zero, return FALSE XX */ XX if (st.st_size == 0) XX return (FALSE); XX /* now see if it time to do anything */ XX clock = time ((long *)0); XX tp = localtime (&clock); XX hour = tp->tm_hour; XX p = (char *) ep.hour; XX if (*p == '*') /* match any hour */ XX return (check_uucp()); XX if (strncmp(p, "off", 3) == 0) /* just what it says, off */ XX return (FALSE); XX /* parse thru hour field to see if XX this is the hour to do work */ XX num = 0; XX do { XX num = num*10 + (*p - '0'); XX } while (isdigit(*++p)); XX if (num == hour) XX return (check_uucp()); XX if (*p == '-') { XX lower = num; XX p++; XX num = 0; XX do { XX num = num*10 + (*p - '0'); XX } while (isdigit(*++p)); XX upper = num; XX if (lower < upper) { /* normal hour range */ XX if (hour >= lower && hour <= upper) XX return (check_uucp()); XX } else if (lower > upper) { /* 24 hr. cycle thru */ XX if (hour >= lower || hour <= upper) XX return (TRUE); XX } else XX return (FALSE); XX } XX if (*p == ',') { XX p++; XX while (*p) { XX num = 0; XX do { XX num = num*10 + (*p - '0'); XX } while (isdigit(*++p)); XX if (num == hour) XX return (check_uucp()); XX p++; XX } XX } XX return (FALSE); XX} XX/* If check_uucp cannot find the remote site XX * directory, just bypass the byte counting XX * routine. This is necessary because the XX * uucpcleanup daemon, on some sites, removes XX * the site directory when there's nothing there. XX */ XXcheck_uucp() XX{ XX struct utsname utsn; XX struct direct dp; XX struct stat st; XX FILE *dfp; XX char u_name[9], buf[80]; XX short prefix_len; XX if (uname(&utsn) < 0) XX xerror ("can't get local nodename\n"); XX sprintf (buf, "%s/%s", UUCPDIR, ep.site); XX if (chdir(buf) < 0) { XX fprintf (stderr, "nbatcher: can't chdir to %s - bypassing UUCP check\n", buf); XX return (TRUE); XX } XX if ((dfp=fopen(".", "r")) == NULL) { XX fprintf (stderr, "nbatcher: fopen error on %s - bypassing UUCP check\n", UUCPDIR); XX return (TRUE); XX } XX sprintf (buf, "D.%s", utsn.nodename); XX prefix_len = (short) strlen(buf); XX n_bytes = 0; XX while ((fread((char *)&dp, sizeof(dp), 1, dfp)) == 1) { XX if (dp.d_ino == 0 || dp.d_name[0] == '.') XX continue; XX if (strncmp(dp.d_name, buf, prefix_len)) XX continue; XX if (stat(dp.d_name, &st) < 0) { XX fprintf (stderr, "nbatcher: bad stat on UUCP_file %s - bypassing\n", dp.d_name); XX continue; XX } XX n_bytes += st.st_size; XX if (n_bytes > ep.m_bytes) { XX fclose (dfp); XX return (FALSE); XX } XX } XX fclose (dfp); XX if (chdir(LIBDIR) < 0) XX xerror ("can't chdir back to %s\n", LIBDIR); XX return (TRUE); XX} @//E*O*F checkwork.c// chmod u=rw,g=rw,o=rw checkwork.c echo x - define.c sed 's/^XX//' > "define.c" <<'@//E*O*F define.c//' XX/* XX * define.c - global defines for nbatcher. XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include "nbatcher.h" XXFILE *lfp, XX *tfp, XX *log = NULL; XXlong n_bytes, XX cu_bytes; XXchar *tfile = NULL; XXshort vflg = 0, XX nfiles = 10; XXint fcnt = 0, XX scnt = 0; @//E*O*F define.c// chmod u=rw,g=rw,o=rw define.c echo x - logger.c sed 's/^XX//' > "logger.c" <<'@//E*O*F logger.c//' XX/* XX * XX * logger.c - log info about nbatcher XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include XX#include "nbatcher.h" XXlog_it (bytes) XXlong bytes; XX{ XX struct tm *localtime(), *tp; XX long time(), clock; XX char logfile[80], buf[BUFSIZ]; XX char pbuf[BUFSIZ]; XX sprintf (logfile, "%s/%s", LIBDIR, "nbatcher.log"); XX if (log == NULL) { XX if ((log=fopen(logfile, "a")) == NULL) XX fprintf (stderr, "can't append to logfile\n"); XX } XX rewind (log, 0L, 2); /* just incase */ XX clock = time ((long *)0); XX tp = localtime (&clock); XX sprintf (buf, "%.2d/%.2d %.2d:%.2d %s: %d %s batched, %d %s queued\n", XX tp->tm_mon+1, tp->tm_mday, tp->tm_hour, tp->tm_min, ep.site, XX fcnt, (fcnt==1 ? "file" : "files"), scnt, XX (scnt==1 ? "file" : "files")); XX if (bytes) XX sprintf (pbuf, "%s\tmax bytes reached. UUCP bytes was %ld, byte count = %ld\n", XX buf, n_bytes, bytes); XX else XX sprintf (pbuf, "%s", buf); XX if (vflg) XX fprintf (stdout, "%s",pbuf); XX if (log != NULL) XX fputs (pbuf, log); XX} @//E*O*F logger.c// chmod u=rw,g=rw,o=rw logger.c echo x - main.c sed 's/^XX//' > "main.c" <<'@//E*O*F main.c//' XX/* XX * XX * main.c - for nbatcher XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include "nbatcher.h" XXmain() XX{ XX int uid; XX FILE *cfp; XX char fbuf[BUFSIZ]; XX uid = getuid(); XX if (uid && uid != NEWSUID) XX xerror ("permission denied - not NEWSUSER\n"); XX if (chdir(LIBDIR) < 0) XX xerror ("can't chdir to %s\n", LIBDIR); XX if ((cfp=fopen("nbatcher.ctl", "r")) == NULL) XX xerror ("no `batcher.ctl' file found\n"); XX if (isatty(0)) XX vflg = TRUE; XX while ((fgets(fbuf, sizeof(fbuf), cfp)) != NULL) { XX if (fbuf[0] == '*' || fbuf[0] == '\n') XX continue; XX parse_entry (fbuf); XX if (!work_to_do()) XX continue; XX batch_it (); XX } XX fclose (cfp); XX unlink (tfile); XX exit (0); XX} XX @//E*O*F main.c// chmod u=rw,g=rw,o=rw main.c echo x - nbatcher.c sed 's/^XX//' > "nbatcher.c" <<'@//E*O*F nbatcher.c//' XX/* XX * XX * nbatcher.c - where it really happens. XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include XX#include XX#include XX#include "nbatcher.h" XXbatch_it () XX{ XX struct stat st; XX FILE *bfp, *afp; XX char fbuf[BUFSIZ], lckfile[40]; XX char tbuf[80]; XX short count; XX int c; XX if (chdir(BATCHDIR) < 0) XX xerror ("can't chdir to %s\n", BATCHDIR); XX /* we create a lock file for two purposes, XX first to make sure a previous nbatcher XX didn't blowup and leave the lock file XX laying around, and second to put the XX remaining news article filenames when XX we go over the max UUCP bytes and there's XX still files remaining for batching. XX */ XX sprintf (lckfile, ".%s.lock", ep.site); XX if (!access(lckfile, 0)) XX xerror ("lockfile already exists for %s\n", ep.site); XX if ((lfp=fopen(lckfile, "w")) == NULL) XX xerror ("can't create lockfile for %s\n", ep.site); XX /* now that we've locked ourselves for this site, XX lets carry on */ XX if ((bfp=fopen(ep.site, "r")) == NULL) XX xerror ("can't open %s/%s for reading\n", BATCHDIR, ep.site); XX if (tfile == NULL) { XX tfile = mktemp("/tmp/bnewsXXXXXX"); XX if ((tfp=fopen(tfile, "w")) == NULL) XX xerror ("can't open %s for writing\n", tfile); XX } XX count = fcnt = scnt = 0; XX cu_bytes = 0; XX while ((fgets(fbuf, sizeof(fbuf), bfp)) != NULL) { XX fbuf[strlen(fbuf)-1] = '\0'; /* remove the newline */ XX if ((afp=fopen(fbuf, "r")) == NULL) { XX fprintf (stderr, "bypassing article %s: can't read it\n", XX fbuf); XX continue; XX } XX if (fstat (fileno(afp), &st) < 0) XX xerror ("fstat failed on %s\n", fbuf); XX cu_bytes += st.st_size; XX /* if the max byte count is exceeded, XX save the remaining files for later */ XX if ((cu_bytes + n_bytes) > ep.m_bytes) { XX fprintf (lfp, "%s\n", fbuf); /* put the '\n' back */ XX while ((fgets(fbuf, sizeof(fbuf), bfp)) != NULL) XX fputs (fbuf, lfp); XX fclose (bfp); XX fclose (lfp); XX fclose (afp); XX unlink (ep.site); XX if (link(lckfile, ep.site) < 0) XX xerror ("can't link lockfile to %s\n", ep.site); XX unlink (lckfile); XX chown (ep.site, NEWSUID, NEWSGID); XX if (count) XX spoolit (); XX if (cu_bytes - st.st_size) XX log_it (cu_bytes - st.st_size); XX return; XX } XX sprintf (tbuf, "#! rnews %ld\n", st.st_size); XX fputs (tbuf, tfp); XX while ((c=getc(afp)) != EOF) XX putc (c, tfp); XX fclose (afp); XX if (++count == nfiles) { XX spoolit (); XX count = 0; XX } XX fcnt++; XX } XX /* The final spool if less than nfiles XX is encountered. The zero out the XX batchfile and unlink the lock file */ XX spoolit (); XX close (creat(ep.site, 0664)); XX chown (ep.site, NEWSUID, NEWSGID); XX unlink (lckfile); XX /* here we log what we've done, and XX if vflg is set, a copy to stdout XX as well */ XX log_it (0); XX if (chdir(LIBDIR) < 0) XX xerror ("can't chdir back to %s\n", LIBDIR); XX} XXspoolit () XX{ XX struct stat st; XX char cmd[BUFSIZ], cfile[80]; XX FILE *pfp; XX int c; XX fclose (tfp); XX stat (tfile, &st); XX /* if for some reason the temp file XX is zero, just return */ XX if (st.st_size == 0) XX return; XX /* if ep.c_bits is set use COMPRESS to compress XX the temp file first XX */ XX if (ep.c_bits) { XX sprintf (cmd, "%s -b%d %s", COMPRESS, ep.c_bits, tfile); XX if (system(cmd) != 0) XX xerror ("system(%s) failed\n", cmd); XX strcpy (cfile, tfile); XX strcat (cfile, ".Z"); XX if ((tfp=fopen(cfile, "r")) == NULL) XX xerror ("can't open %s for reading\n", cfile); XX /* if ep.command has a specific command XX for UUCP spooling, use it. If not, XX use UUX. XX */ XX if (ep.command[0] != '\0') XX strcpy (cmd, ep.command); XX else XX sprintf (cmd, "%s %s!rnews", UUX, ep.site); XX /* now popen the command for writing XX and send it the contents of tempfile */ XX if ((pfp=popen(cmd, "w")) == NULL) XX xerror ("popen failed on %s\n", cmd); XX /******************************************** XX * for version 2.10.3 and above, XX * prepend `#! cunbatch'. XX * XX * NOTE: The remote site MUST be able to XX * except this format, or it will XX * be lost!!! XX *******************************************/ XX fputs ("#! cunbatch\n", pfp); XX while ((c=getc(tfp)) != EOF) XX putc (c, pfp); XX pclose (pfp); XX fclose (tfp); XX unlink (cfile); XX } else { /* regular batching here */ XX if ((tfp=fopen(tfile, "r")) == NULL) XX xerror ("can't open %s for reading\n", tfile); XX /* if ep.command has a specific command XX for UUCP spooling, use it. If not, XX use UUX. XX */ XX if (ep.command[0] != '\0') XX strcpy (cmd, ep.command); XX else XX sprintf (cmd, "%s %s!rnews", UUX, ep.site); XX if ((pfp=popen(cmd, "w")) == NULL) XX xerror ("popen failed on %s\n", cmd); XX while ((c=getc(tfp)) != EOF) XX putc (c, pfp); XX pclose (pfp); XX fclose (tfp); XX } XX if ((tfp=fopen(tfile, "w")) == NULL) XX xerror ("can't re-open %s\n", tfile); XX scnt++; XX} @//E*O*F nbatcher.c// chmod u=rw,g=rw,o=rw nbatcher.c echo x - parse.c sed 's/^XX//' > "parse.c" <<'@//E*O*F parse.c//' XX/* XX * XX * parse.c - nbatcher line parser for the control file XX * XX * XX * R.J. Esposito XX * Bell of Penna. XX * June 1986 XX * XX */ XX#include XX#include XX#include XX#include "nbatcher.h" XX#define MAX_BYTES 1000000L /* max allowable bytes */ XXparse_entry (line) XXchar *line; XX{ XX register char *p; XX short num, upper; XX short lower, dash; XX long l_num; XX upper = 23; /* upper hour limit */ XX lower = 0; /* lower hour limit */ XX dash = 0; XX clear_entry (&ep); /* zero out the structure */ XX p = (char *) ep.site; XX /* get the site name and copy XX it to the structure */ XX while (*line && *line != COLON) XX *p++ = *line++; XX *p = '\0'; XX if (*++line == '\n' || *line == '\0') XX xerror ("illegal number of fields\n"); XX /* check that its valid */ XX if (ep.site[0] == '\0') XX xerror ("null site name in control file\n"); XX /* now, parse the hour string and check XX for valid syntax */ XX p = (char *) ep.hour; XX while (*line && *line != COLON) XX *p++ = *line++; XX *p = '\0'; XX if (*++line == '\n' || *line == '\0') XX xerror ("illegal number of fields\n"); XX if (ep.hour[0] == '\0') XX xerror ("null hour string in control file\n"); XX /* now re-scan the hour in structure and XX weed out the badies */ XX if (ep.hour[0] == '*' && ep.hour[1] != '\0') XX xerror ("invalid hour string syntax: %s\n", ep.hour); XX else if (ep.hour[0] == '*') XX goto h_skip; XX if (strcmp(ep.hour, "off", 3) == 0 && ep.hour[3] != '\0') XX xerror ("invalid hour string syntax: %s\n", ep.hour); XX else if (strncmp(ep.hour, "off", 3) == 0) XX goto h_skip; XX p = (char *) ep.hour; XX if (!isdigit(*p)) XX xerror ("non-numeric char in hour string: %c\n", *p); XX while (*p) { XX num = 0; XX do { XX num = num*10 + (*p - '0'); XX } while (isdigit(*++p)); XX if (num < lower || num > upper) XX xerror ("illegal hour: %d\n", num); XX if (!*p) XX break; XX if (*p == '-' && dash) XX xerror ("syntax error in hour field\n"); XX else if (*p == '-') XX dash = TRUE; XX if (*p != ',' && *p != '-') XX xerror ("non-numeric char in hour string: %c\n", *p); XX else if (!isdigit(*++p)) XX xerror ("syntax error in hour field\n"); XX } XX /* now that thats over with, let do the compression XX field. Only 9-16 is allowed, except a null field XX indicates no compression for this site. */ XXh_skip: XX num = 0; XX while (*line && *line != COLON) { XX if (!isdigit(*line)) XX xerror ("non-numeric in compression field\n"); XX num = num*10 + (*line++ - '0'); XX } XX if (*++line == '\n' || *line == '\0') XX xerror ("illegal number of fields\n"); XX if (num != 0 && (num < 9 || num > 16)) XX xerror ("illegal compression bits: %d\n", num); XX ep.c_bits = num; XX /* now check the max. bytes for UUCP queue. XX Note: There is a max. allowable # of bytes XX here, set at 1MB. Change it at your XX own risk. XX */ XX l_num = 0; XX while (*line && *line != COLON) { XX if (!isdigit(*line)) XX xerror ("non-numeric in max. bytes field\n"); XX l_num = l_num*10 + (*line++ - '0'); XX } XX if (l_num > MAX_BYTES) XX xerror ("%ld max. bytes exceeds allowable maximun\n", l_num); XX if (l_num != 0) XX ep.m_bytes = l_num; XX else XX ep.m_bytes = DFL_BYTES; XX /* and finally the command line (if there is one) */ XX p = (char *) ep.command; XX if (*++line != '\n' && *line != '\0') { XX while (*line && *line != '\n') XX *p++ = *line++; XX *p = '\0'; XX } XX} XX#ifdef USE_PORT_CODE XXxerror (fmt, a1, a2) XXchar *fmt; XXchar *a1, *a2; XX{ XX char buf[BUFSIZ]; XX sprintf (buf, fmt, a1, a2); XX printf ("nbatcher: %s\n", fmt); XX exit (99); XX} XX#else XXxerror (fmt, argp) XXchar *fmt; XXint argp; XX{ XX char buf[BUFSIZ]; XX char fbuf[BUFSIZ]; XX FILE prwbuf; XX register char *cp; XX XX prwbuf._flag = _IOWRT; XX prwbuf._file = _NFILE; XX prwbuf._cnt = 32767; XX prwbuf._ptr = (unsigned char *)buf; XX prwbuf._base = (unsigned char *)buf; XX sprintf (fbuf, "%s: %s", "nbatcher", fmt); XX _doprnt (fbuf, (char *)&argp, &prwbuf); XX putc ('\0', &prwbuf); XX for (cp = buf; *cp != '\0'; cp++) XX putchar (*cp); XX exit (99); XX} XX#endif /* USE_PORT_CODE */ XXclear_entry (s) XXchar *s; XX{ XX register int i; XX for (i=0; i $temp <<\!!! 60 480 3043 README 76 441 2526 nbatcher.1 14 88 459 nbatcher.ctl 81 678 3907 nbatcher.doc 67 185 1387 Makefile 61 159 1088 bst.c 155 501 3094 checkwork.c 27 52 284 define.c 50 148 1022 logger.c 47 103 699 main.c 212 696 4805 nbatcher.c 202 668 4011 parse.c 1052 4199 26325 total !!! wc README nbatcher.1 nbatcher.ctl nbatcher.doc Makefile bst.c checkwork.c define.c logger.c main.c nbatcher.c parse.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if test -s $dtemp then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0