[net.sources] lotsend.c fixed

lee@kcl-cs.UUCP (Lee McLoughlin) (02/24/85)

Yes there is a rather serious bug in lotsend to do with the way uux
handles the mapping of names.  
	uux -r rnewsall!kcl-cs /f1/news/net/frobitz/11 /f1/news/net/general/11

	uuxqt causes the second file to overwrite the first on moving them
	to the execute directory and it then runs:

	rnewsall 11 11

Result lost news.  Thanks a bunch to everyone who pointed it out.

Simple fix.  Also it calls system() to run the command now to ensure that
a /bin/sh is called.


/*
 * Simple news batcher.
 * Rather than running compress and all that stuff simply submit a
 * command like:
 *	uux -r -c remote!rnewsall !/news/net/oa/1 !/news/net/ai/276
 * where rnewsall is a simple script which calls rnews on all its arguments.
 * Its input can be generated by a news sysfile line like:
 *	ic-cs:uk,eunet,net,mod,fa:F:/usr/lib/news/lots.ic-cs
 * Lotsend itself should be called (by cron) a few minutes before news is
 * due to be sent.  For example the following crontab entry.
0 0,1,2,3,4,5,6,7,8,23 * * * /usr/lib/news/lotsend ic-cs
 *
 * CAREFULL:  lotsend will zap the existing lots list. Remember to install
 * it with a mode of 6755 and a user/group id suitable for news.
 *
 * Note that you do not get the transmission saving that compress style 
 * batchers give you but you do save more blockspace since copies of the data
 * are never stored in the spool area.
 *
 * This is particulaly usefull if you have the uucp mod to prevent resending
 * successfully transmitted files.
 * 
 * L.M.McLoughlin.
 *	Feb 1984. Get around uux problem where the remote end only sees
 * 	the lastparts of names so make sure they're unique.
 *	Allow dir, cmd and wether to ! names to be specified.
 *
 * rnewsall:
for i
do	if test -r $i
	then	rnews < $i
		rm -f $i
	else	echo $0: failed to find $i >> $NEWS/rnewsall.log
	fi
done
 */

char *Rcsid = "$Header: /f0/UKUUCP/lotsend.c,v 1.2 85/02/24 01:43:41 lee Exp $";
/* $Log:	lotsend.c,v $
 * Revision 1.2  85/02/24  01:43:41  lee
 * Add a few usefull options and fix bug to do with tails of names being
 * treated the same by uux!
 * 
 * Revision 1.1  85/02/24  00:58:39  lee
 * Initial revision
 * 
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BLK	512	/* Don't fiddle with this */
#define MAXBLKS 200
#define MAXARGS 20
int maxblks = MAXBLKS;	/* Max blks of data per uux call. */
long maxsize;
int maxargs = MAXARGS;	/* Max no. of args per uux call. */
char *site;		/* Name of site to use */

/* Where the lists the news generates are kept
 * This program MUST have write permission on that directory.
 * Preferably run this program under the news id.
 */
#define LOTSDIR "/usr/lib/news"

char *dir = LOTSDIR;		/* Directory where lots are kept. */
char *base_cmd = "uux -r -z -c %.7s!rnewsall "; /*Command to run */
int nopling = 0;	/* Give filename as !file, default is to give ! */

main( argc, argv )
int argc;
char **argv;
{
	int ma, mb;
	FILE *lf;
	char *lt, lotname[ BUFSIZ ];
	char filename[ BUFSIZ ];

	while( argv++, --argc ){
		if( argv[ 0 ][ 0 ] != '-' )
			break;
		switch( argv[ 0 ][ 1 ] ){
		case 'a':
			ma = 0;
			sscanf( &argv[ 0 ][ 2 ], "%d", &ma );
			if( 0 < ma && ma <= MAXARGS )
				maxargs = ma;
			break;
		case 'b':
			mb = 0;
			sscanf( &argv[ 0 ][ 2 ], "%d", &mb );
			if( 0 < mb && mb <= MAXBLKS )
				maxblks = mb;
			break;
		case 'c':
			base_cmd = &argv[ 0 ][ 2 ];
			break;
		case 'd':
			dir = &argv[ 0 ][ 2 ];
			break;
		case 'n':
			nopling = 1;
			break;
		}
	}
	maxsize = (long)maxblks * BLK;

	if( argc == 0 ){
		fprintf( stderr, "Usage: lotsend [-aMAXARGS] [-bMAXBLKS] [-ccmd] [-ddir] [-n] file\n" );
		exit( 1 );
	}

	if( chdir( dir ) == -1 ){
		fprintf( stderr, "lotsend: cannot chdir to %s\n", LOTSDIR );
		exit( 2 );
	}

	/* Move the given lot file into a temporary to avoid problems
	 * with inews updates.
	 */
	site = argv[ 0 ];
	sprintf( lotname, "lots.%s", site );
	lt = mktemp( "LOTS.XXXXXX" );
	if( link( lotname, lt ) == -1 ){
		fprintf( stderr, "lotsend: cannot link %s to %s\n",
			lotname, lt );
		exit( 3 );
	}
	unlink( lotname );

	if( (lf = fopen( lt, "r" )) == NULL ){
		fprintf( stderr, "lotsend: cannot open to %s\n", lt );
		exit( 4 );
	}
	
	init();	/* Initialize the command generator */

	while( fgets( filename, BUFSIZ, lf ) != NULL ){
		filename[ strlen( filename ) - 1 ] = '\0';
		addname( filename );
	}
	outcmd();

	fclose( lf );
	unlink( lt );
	exit( 0 );
}

long size_sofar = 0;
int args_sofar = 0;
char cmd[ 5*1024 ];

/* Initialize the cmd.
 */
init()
{
	size_sofar = 0l;
	args_sofar = 0;
	sprintf( cmd, base_cmd, site );
}

/* Add the name to the list to be given to uux.
 * If maxargs  name in the list call outcmd.
 * If the total size of all files > maxblks then call outcmd
 * Force the list out on getting two names with the same tail part.
 * Eg: /f1/news/general/1 /f1/news/net/sport/1
 * since uux treats this badly.
 */
addname( name )
char *name;
{
	struct stat sb;
	long tot;
	char *lastpart();

	if( stat( name, &sb ) == -1 )
		return;	/* Its gone! Ignore it */

	if( (tot = sb.st_size + size_sofar) > maxsize ||
		inlist( lastpart( name ) ) )
		outcmd();	/* Send what we have sofar */
	
	size_sofar = tot;

	if( !nopling )
		strcat( cmd, "!" );
	strcat( cmd, name );
	strcat( cmd, " " );
	args_sofar++;

	if( args_sofar >= maxargs )
		outcmd();
}

/* See if the name given is the same as a lastpart of
 * an existing name in the cmd.
 */
inlist( name )
register char *name;
{
	register char *s = &cmd[ strlen( base_cmd ) + 1 ];

	while( *s != '\0' ){
		register char *sp = index( s, ' ' );

		/* Stomp on space terminator */
		*sp = '\0';

		/* Has it the same end? */
		if( strcmp( lastpart( s ), name ) == 0 ){
			*sp = ' ';
			return( 1 );
		}

		*sp = ' ';
		s = sp + 1;
	}
	return( 0 );
}

outcmd()
{
	if( args_sofar == 0 )
		return;
	system( cmd );
	init();
}

/* LMCL: This is needed since the Orion has a bug to do with decrementing
 * the argv[0] pointer before the start of memory.
 *
 * Bug has long since been fixed but this
 * is the only lastpart() I had around.
 */
char *
lastpart( file )
register char *file;
{
	register char *c;
	char *index();

	if( index( file, '/' ) != ((char *)0) ){
		c = file + strlen( file );
		while( c >= file) {	
			if( *(--c) == '/' )
				break;
		}
		return( ++c );
	}
	else	return( file );
}
-- 
UKUUCP SUPPORT  Lee McLoughlin	<UK>!ukc!lmcl
		kcl-cs!lee
	"What you once thought was only a nightmare is now a reality!"