ahby@meccts.UUCP (03/22/87)
The following shar contains a few programs that make it possible to use MULTICAST effectively under UUCP based news transfer. I have submitted this to mod.sources, but I have had so many requests for these sources, and mod.sources is so backlogged, that I am sending this out here. If you find any problems, please let me know ASAP. Also, if you have to patch uucast for your particular flavor of UUCP, please send me those patches. Good luck! #! /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: # README # Makefile # multibatch.c # multisend.sh # uucast.c # uucast.h # This archive created: Sun Mar 15 11:21:50 1987 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'README'" '(4214 characters)' if test -f 'README' then echo shar: "will not over-write existing file 'README'" else sed 's/^ X//' << \SHAR_EOF > 'README' XINSTALLATION X============ X XFirst, be sure to customize Makefile for your site. The variables should Xbe the same as news 2.10.3 and beyond. X XUucast may have to be customized for you site so that the uucp file Xnames that are used are recognized by your uucico. The only real option Xis HDB. Sites running HDB UUCP should just have to define XHDB in Makefile. I hope that this works :-). If you don't have HDB, Xthe other configuration should work just fine for you. There are two XGRADE values that are defined in the file uucast.h. These are the Xgrade values that can be used by 4.3 BSD to regulate traffic flow. In Xthe case of uucast they should be used to guarantee a unique job file Xname. If your uux generates jobs like: X X C.ihnp4AD8471 local command file X D.mecctsXA8471 remote command file (becomes X. file on ihnp4) X D.ihnp4BC8471 data to transmit X Xthen the grade is AD. Choose a grade that doesn't conflict with this. XThe defaults are MA and XM. Uucast would have generated: X X C.ihnp4MA8471 local command file X D.mecctsXM8471 remote command file (becomes X. file on ihnp4) X D.ihnp4MA8471 data to transmit X XNote that while the grades in the data and local command files are not Xdifferent, UUCP doesn't seem to care about this. If it cares on your Xsystem, you should define a third grade (GRADE3) and use that as well. XAlso note that the remote command file usually must have an X in it's Xname so that it is recognized as such by the system. This is a little Xcurious, but since I don't have source I can't puzzle it out on my Xown. X XOn Ultrix systems the UUCP datafiles are in a strange place, and job Xfiles are in different directories. This can all be specified by Xchanging the CDIR, DDIR, and XDIR definitions in uucast.h. There may Xbe other systems where this is weird as well. In any case, you can Xspecify the location of each type of file individually. See uucast.h Xfor more information. X XAll of this stuff is different for each implementation of uucp, so XI have made it as easy as possible to change. If you need to hack it for your Xsystem, please send those hacks to ahby@MECC.COM, so I can incorporate them into Xfuture releases. X XA word of warning: you WILL have trouble installing this software. It Xis not perfect, nor is it forgiving. If you are unsure about the Xstability of any of the modules on your system, there are ways in each Xof them to preserve the original state of things. Please be careful Xwhen using this software, as it can be very detrimental to your news Xsystem, as well as all of your downstream sites. X XAlso note that there is no make install option in the Makefile. This Xis really just laziness on my part. Move all of the generated files Xinto LIBDIR. Remember that uucast MUST be suid to uucp so that it can Xgenerate job files with the correct ownership. X X XOPERATION X========= X XExample sys file. X Xmeccsd:mod,usa,na,net,world,comp,news,sci,rec,misc,soc,talk,to.meccsd:M:master Xkarau:net.sources,news.admin,news.software.b,to.karau:M:master Xnis:mod,usa,na,net,world,comp,news,sci,rec,misc,soc,talk,to.nis:M:master Xzeke:mod,usa,na,net,world,comp,news,sci,rec,misc,soc,talk,to.zeke:M:master Xmaster:all:OF:/usr/spool/batch/master X XThe M indicates that the site is being multicast to. The Xword master is the name of a dummy entry in the sys file which gives Xthe information about what to do with these multi cast sites. Site X"master" is receiving all articles, is the destination of a multicast X(O) and is a batched feed (F). The file it places things into is X/usr/spool/batch/master, just like a normal batched entry. X XIn your crontab, replace the sendbatches with something like: X X 55 18-5 * * * cat /usr/spool/batch/master >> /usr/spool/batch/hold; /usr/lib/news/multibatch -c master >> /usr/lib/cron/cast-log X XThis preserves the batch file (just in case) and then multibatches the Xarticles indicated in file master compressed (-c flag for multisend). X XRemember that multibatch calls the script multisend, and expects Xmultisend to be in the $(LIBDIR) directory for news. Multisend calls Xuucast, which should be in the path or in your $(LIBDIR) directory. X XGood luck! If you have any problems, please drop me a line. X XCopyright (C) Shane McCarron, 1987. SHAR_EOF if test 4214 -ne "`wc -c < 'README'`" then echo shar: "error transmitting 'README'" '(should have been 4214 characters)' fi fi echo shar: "extracting 'Makefile'" '(774 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else sed 's/^ X//' << \SHAR_EOF > 'Makefile' X# Makefile for multibatch and uucast. X# X# Copyright (C) Shane McCarron, 1987. X# X# Note that the symbols used here are compatible with those of X# news 2.10.3 and beyond... X X# Directory where news batch files are kept. XBATCHDIR = /mecc/spool/batch X X# Directory with news software is kept. XLIBDIR = /mecc/bin/news X X# Define WANTZ if you don't want uux completion notices from other systems. XDEFS = -DBATCHDIR=\"$(BATCHDIR)\" -DLIBDIR=\"$(LIBDIR)\" -DWANTZ XCFLAGS = -O X XFILES = multibatch multisend uucast X Xall: $(FILES) X Xmultibatch: Makefile X $(CC) $(CFLAGS) $(DEFS) multibatch.c -o multibatch X Xmultisend: Makefile multisend.sh X sed -e 's;LIBDIR;$(LIBDIR);g' < multisend.sh > multisend X chmod +x multisend X Xuucast: Makefile uucast.h X $(CC) $(CFLAGS) $(DEFS) uucast.c -o uucast SHAR_EOF if test 774 -ne "`wc -c < 'Makefile'`" then echo shar: "error transmitting 'Makefile'" '(should have been 774 characters)' fi fi echo shar: "extracting 'multibatch.c'" '(3964 characters)' if test -f 'multibatch.c' then echo shar: "will not over-write existing file 'multibatch.c'" else sed 's/^ X//' << \SHAR_EOF > 'multibatch.c' X/* multibatch.c - program to send news batches to multiple systems. X * X * 86/06/14. 2.1 Shane P. McCarron (MECC) X * X * Copyright (C) Shane McCarron, 1987. X * X * Multibatch will take a batch file created with the Multicasting X * option of news 2.10.3 and later, and distribute common articles to X * sites using the broadcasting facility of uucast (also included in X * this software package). X * X * The format of this command is: X * X * multibatch [-s size] [ -c ] [ -c7 ] [ -obBC ] multicast X * X * all parameters are like those of sendbatch except multicast, which X * is used in place of site. Multicast is the name of the file which X * contains the inews generated lines about article name and destination X * sites. Multibatch will cluster those articles which need to go to the X * same sites, and feed that list to a sendbatch like script. X * X * Since the parameters (options) are not really used by this X * program, but are used by the script it calls, the options are X * just ripped out of argv and placed in a string. X */ X X#include <stdio.h> X#include <errno.h> X X#ifndef PATH_MAX X#define PATH_MAX 255 X#endif PATH_MAX X X#ifndef LIBDIR X#define LIBDIR "/usr/lib/news" X#endif LIBDIR X X#ifndef BATCHDIR X#define BATCHDIR "/usr/spool/batch" X#endif BATCHDIR X Xextern int errno; X Xtypedef struct node X{ X struct node *link; /* forward link */ X char *line; /* line from file */ X} NODE; X Xtypedef NODE *NODEPTR; X XFILE *outfile; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X FILE *fopen(); X char *getsys(); X char *malloc(); X void error(); X void printart(); X X NODE arts; X NODEPTR last = &arts; X char argstr[BUFSIZ]; X char filename[PATH_MAX]; X char flags[BUFSIZ]; X char instr[BUFSIZ]; X char oldname[PATH_MAX]; X char *systems; X X int artsleft; X int i = 1; X int numarts = 0; X X arts.link = NULL; X while ((i < argc) && (argv[i][0] == '-')) X { X strcat(flags, argv[i]); X strcat(flags, " "); X i++; X } /* end while */ X if (i == argc) X { X fprintf(stderr, "usage: %s options batch\n", argv[0]); X exit(2); X } /* end if */ X X fclose(stdin); /* we don't need this */ X (void) sprintf(oldname, "%s/%s", BATCHDIR, argv[i]); X (void) sprintf(filename, "%s.work", oldname); X if (link(oldname, filename) == -1) X { X if (errno == ENOENT) X exit(1); X else X error(errno); X } /* end if */ X X /* get rid of the original file */ X X (void) unlink(oldname); X X if (fopen(filename, "r") == NULL) X error(errno); X while (gets(instr) != NULL) X { X if ((last->link = (NODEPTR) malloc(sizeof(NODE))) == NULL) X error(2); X last = last->link; X if ((last->line = malloc((unsigned) strlen(instr) + 1)) == NULL) X error(2); X strcpy(last->line, instr); X numarts++; X } /* end while */ X X /* If you are testing this, then comment out the unlink */ X X unlink(filename); X X /* start processing these articles */ X X artsleft = numarts; X while (artsleft > 0) X { X last = arts.link; /* start with first node */ X while (last->line == NULL) X last = last->link; X systems = getsys(last->line); X strcpy(filename, "/tmp/mbXXXXXX"); X if (mktemp(filename) == NULL) X error(254); X if ((outfile = fopen(filename, "w")) == NULL) X error(errno); X printart(last->line); X last->line = NULL; X last = last->link; X artsleft--; X while (last) X { X if (last->line != NULL) X if (strcmp(systems, getsys(last->line)) == 0) X { X printart(last->line); X last->line = NULL; X artsleft--; X } /* end if */ X last = last->link; X } /* end while */ X fclose(outfile); X (void) sprintf(argstr, "%s/multisend %s -S %s %s", LIBDIR, flags, filename, systems); X i = system(argstr); X unlink(filename); X if (i != 0) X error(i); X } /* end while */ X X return(0); X} X Xchar *getsys(line) Xchar *line; X{ X char *s = line; X X while (*s != ' ') s++; X return(++s); X} X Xvoid printart(line) Xchar *line; X{ X int i = 0; X X while (line[i] != ' ') X { X putc(line[i], outfile); X i++; X } /* end while */ X putc('\n', outfile); X} X Xvoid error(err) Xint err; X{ X fprintf(stderr, "Program blew off. Error = %d.\n", err); X exit(err); X} SHAR_EOF if test 3964 -ne "`wc -c < 'multibatch.c'`" then echo shar: "error transmitting 'multibatch.c'" '(should have been 3964 characters)' fi fi echo shar: "extracting 'multisend.sh'" '(1251 characters)' if test -f 'multisend.sh' then echo shar: "will not over-write existing file 'multisend.sh'" else sed 's/^ X//' << \SHAR_EOF > 'multisend.sh' X: '@(#)multisend.sh 2.1 3/13/87' X# Copyright (C) Shane McCarron, 1987. X# X# This script is intended to be called only by multibatch. X# Any parameters you give multibatch are passed onto this X# script with the exception of the MULTICAST generated batch X# file. X# X# Note that the interface to multisend is pretty much like X# sendbatch. However, it does not support the ihave flags. X# Also the flag -S is used to indicate that the rest of the X# parameters are system names. It is supplied by multibatch. X X Xcflags= XLIM=50000 XECHO= XCOMP= XC7= XRNEWS=rnews Xdate Xecho $* X Xwhile [ $1 != '-S' ] Xdo X case $1 in X -[bBC]*) cflags="$cflags $rmt"; continue;; X -s*) LIM=`expr "$rmt" : '-s\(.*\)'` ;; X -c7) COMP='| LIBDIR/compress $cflags' X C7='| LIBDIR/encode' X ECHO='echo "#! c7unbatch"' ;; X -c) COMP='| LIBDIR/compress $cflags' X ECHO='echo "#! cunbatch"' ;; X -o*) ECHO=`expr "$rmt" : '-o\(.*\)'` X RNEWS='cunbatch' ;; X esac X shift Xdone X Xshift XFILE=$1 Xshift XSYSTEMS=$* X Xif test -n "$COMP" Xthen X LIM=`expr $LIM \* 2` Xfi X X: make sure $? is zero Xwhile test $? -eq 0 -a \( -s $FILE -o -s $FILE.work \) Xdo X file=`date +10/16/86M%S` X (eval $ECHO; eval LIBDIR/batch $FILE $LIM $COMP $C7) > /tmp/msend$$ X LIBDIR/uucast /tmp/msend$$ $RNEWS $SYSTEMS X rm /tmp/msend$$ Xdone SHAR_EOF if test 1251 -ne "`wc -c < 'multisend.sh'`" then echo shar: "error transmitting 'multisend.sh'" '(should have been 1251 characters)' fi fi echo shar: "extracting 'uucast.c'" '(5467 characters)' if test -f 'uucast.c' then echo shar: "will not over-write existing file 'uucast.c'" else sed 's/^ X//' << \SHAR_EOF > 'uucast.c' X/* X * uucast - Cast a UUX command to multiple systems. X * X * 86/07/12. 2.1 Shane P. McCarron (MECC). X * X * Copyright (C) Shane McCarron, 1987. X * X * Note: this program must run suid uucp. It will create the X * files in the uucp directories owned by user uucp, with X * mask MASK. X */ X X#include <pwd.h> X#include <stdio.h> X#include <errno.h> X#include "uucast.h" X#ifndef NODE X#include <sys/utsname.h> X#endif NODE X X#define NAMELEN 15 /* length of file names */ X Xchar sccsid[] = "@(#)uucast.c 1.5"; X X#ifdef NODE Xchar node[] = NODE, X#else NODE Xchar node[8], /* variable for node name from uname */ X#endif NODE X user[] = USER, /* the user that is doing the sending */ X comname[NAMELEN], /* name of command file */ X remname[NAMELEN], /* name of remote command file */ X nremname[NAMELEN], /* name of remote data file */ X locname[NAMELEN]; /* name of local data file */ Xextern errno; X X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X void makename(); X void usage(); X X char file[128], /* file name to transmit */ X path[128], /* temporary path name */ X *command = argv[2], /* command to UUX */ X *sysname[MAXSYS]; /* array of system names */ X FILE *fptr; /* file descriptor */ X int i, /* looping variable */ X result, /* result of link call */ X seq, /* sequence number */ X syscount = 0; /* number of systems to send to */ X struct passwd *uucp; /* struct for user uucp information */ X struct passwd *getpwnam(); X X if (argc < 4) X usage(argv[0]); X X uucp = getpwnam("uucp"); X setuid(uucp->pw_uid); X setgid(uucp->pw_gid); X X strcpy(file, argv[1]); /* get the data file name */ X X for (i = 3; i < argc; i++) /* get the system names */ X { X sysname[i-3] = argv[i]; X syscount++; X } X#ifndef NODE X (void) getnode(node); /* get the node name */ X#endif NODE X (void) umask(MASK); /* clear the mask bits */ X seq = getpid(); /* get the process id */ X i = 0; X while (i < syscount) X { X /* X * Cleaned up logic a bit - MHC X */ X do { X makename(sysname[i], seq++); X#ifdef HDB X (void) sprintf(path, "%s/%s/%s", XDIR, sysname[i], remname); X#else X (void) sprintf(path, "%s/%s", XDIR, remname); X#endif HDB X } while (!access(path, 0)); X X#ifdef HDB X (void) sprintf(path, "%s/%s/%s", DDIR, sysname[i], comname); X#else X (void) sprintf(path, "%s/%s", DDIR, comname); X#endif HDB X X if ((result = link(file, path)) == -1 && (errno == EXDEV)) X { X /* X * Link failed due to target directoring being on X * a different file system. Try doing a copy. X * If copy works then move path to file so that it X * can be used as a source to link the rest of the X * files. X */ X X /* changed to do strcpy only if copy works - MHC */ X X if (result = copy(file, path) == 0) X strcpy(file, path); X } /* end if */ X else if (result != 0) X { X fprintf(stderr, "uucast: Link failed from %s to %s: %d\n", X file, path, errno); X exit(errno); X } /* end else */ X#ifdef HDB X (void) sprintf(path, "%s/%s/%s", XDIR, sysname[i], remname); X#else X (void) sprintf(path, "%s/%s", XDIR, remname); X#endif HDB X fptr = fopen(path, "w"); X#ifdef WANTZ X fprintf(fptr, "U %s %s\nN\nZ\nR %s\nF %s\nI %s\nC %s\n", X user, node, user, comname, comname, command); X#else X fprintf(fptr, "U %s %s\nF %s\nI %s\nC %s\n", user, node, X comname, comname, command); X#endif WANTZ X fclose(fptr); X#ifdef HDB X (void) sprintf(path, "%s/%s/%s", CDIR, sysname[i], locname); X#else X (void) sprintf(path, "%s/%s", CDIR, locname); X#endif HDB X fptr = fopen(path, "w"); X#ifdef HDB X fprintf(fptr, "S %s %s %s - %s 0666 %s\nS %s %s %s - %s 0666 %s\n", X comname, comname, user, comname, user, remname, nremname, X user, remname, user); X#else X fprintf(fptr, "S %s %s %s - %s 0666\nS %s %s %s - %s 0666\n", X comname, comname, user, comname, remname, nremname, X user, remname); X#endif HDB X fclose(fptr); X i++; X } /* end for */ X} X X Xint copy(file1, file2) Xchar *file1, *file2; /* source and destination name */ X{ X char cmd[BUFSIZ]; /* make a command string */ X X (void) sprintf(cmd, "cp %s %s", file1, file2); X return(system(cmd)); X} X X#ifndef NODE Xint getnode(name) Xchar *name; X{ X struct utsname buffer; X X (void) uname(&buffer); X strcpy(name, buffer.nodename); X} X#endif NODE X X/* makename - make the name files for casting. X** X** remname and nremname use grade2 because on some systems (Ultrix) X** the remote command file must have an X in its name. On normal X** systems, just make GRADE and GRADE2 the same. X** X*/ X Xvoid makename(sysnam, num) /* make file names */ Xchar *sysnam; /* system name */ Xint num; /* sequence number */ X{ X while (num > (10000-1)) X num = num - 10000; X#ifdef HDB X (void) sprintf(comname, "D.%.5s%s%04d", node, GRADE, num); X (void) sprintf(remname, "D.%.5s%04da12c", sysnam, num); X (void) sprintf(nremname, "X.%.7s%s%04d", sysnam, GRADE, num); X (void) sprintf(locname, "C.%.7s%s%04d", sysnam, GRADE, num); X#else X#ifndef GRADE2 X (void) sprintf(comname, "D.%s%s%04d", sysnam, GRADE, num); X (void) sprintf(remname, "D.%s%s%04d", node, GRADE, num); X (void) sprintf(nremname, "X.%s%s%04d", node, GRADE, num); X (void) sprintf(locname, "C.%s%s%04d", sysnam, GRADE, num); X#else X (void) sprintf(comname, "D.%s%s%04d", sysnam, GRADE, num); X (void) sprintf(remname, "D.%s%s%04d", node, GRADE2, num); X (void) sprintf(nremname, "X.%s%s%04d", node, GRADE2, num); X (void) sprintf(locname, "C.%s%s%04d", sysnam, GRADE, num); X#endif !GRADE2 X#endif HDB X} X Xvoid usage(command) Xchar *command; X{ X fprintf(stderr, "usage: %s file command system(s)\n", command); X exit(1); X} X SHAR_EOF if test 5467 -ne "`wc -c < 'uucast.c'`" then echo shar: "error transmitting 'uucast.c'" '(should have been 5467 characters)' fi fi echo shar: "extracting 'uucast.h'" '(860 characters)' if test -f 'uucast.h' then echo shar: "will not over-write existing file 'uucast.h'" else sed 's/^ X//' << \SHAR_EOF > 'uucast.h' X/* X** uucast.h - Header file for uucast. X*/ X X/* #define NODE "foobar" /* name of this node, define if system X call uname is not available. This name can X be no longer than 7 characters. */ X#define MASK 026 /* umask for files */ X#define CDIR "/usr/spool/uucp" /* local command files directory */ X#define DDIR "/usr/spool/uucp" /* data files directory */ X#define XDIR "/usr/spool/uucp" /* remote command files directory */ X X/* For HoneyDanBer users: Grades are a single character, so use M and X * X (for example). X */ X X#define GRADE "MA" /* grade to use for uucico files. X Should not be used by anyone else */ X#define GRADE2 "XM" /* other grade to use for files X This grade should start X with an X. */ X#define USER "usenet" /* name of news user on your system */ X#define MAXSYS 20 /* maximum number of systems per cast */ SHAR_EOF if test 860 -ne "`wc -c < 'uucast.h'`" then echo shar: "error transmitting 'uucast.h'" '(should have been 860 characters)' fi fi exit 0 # End of shell archive -- Shane P. McCarron UUCP ihnp4!meccts!ahby, ahby@MECC.COM MECC Technical Services ATT (612) 481-3589 (C) Copyright 1987 Shane P. McCarron Redistribution allowed only if your recipients can redistribute