[comp.sources.unix] v19i086: Cnews production release, Part09/19

rsalz@uunet.uu.net (Rich Salz) (06/28/89)

Submitted-by: utzoo!henry
Posting-number: Volume 19, Issue 86
Archive-name: cnews2/part09

: ---CUT HERE---
echo 'hfake/timeb.h':
sed 's/^X//' >'hfake/timeb.h' <<'!'
X/*
X * simulation of research unix's <sys/timeb.h> for Uglix.
X */
Xstruct timeb {
X	time_t time;
X	unsigned short millitm;
X	short timezone;
X	short dstflag;
X};
!
echo 'hfake/Makefile':
sed 's/^X//' >'hfake/Makefile' <<'!'
XI = ../include
X
X# beware -- build knows about NEEDED
XNEEDED =  ../include/stdlib.h
X
Xall:	$(NEEDED)
X
X$(I)/stdlib.h:	stdlib.h
X	cp stdlib.h $@
X$(I)/string.h:	string.h
X	cp string.h $@
X$(I)/sys/timeb.h:	timeb.h
X	cp timeb.h $@
X
Xclean:
!
echo 'input/bdecode.c':
sed 's/^X//' >'input/bdecode.c' <<'!'
X/*
X * bdecode [file]
X */
X#include <stdio.h>
X#include "coder.h"
Xchar *myname, *inputfile = "(stdin)";
X
Xmain(argc, argv) 
X	char **argv;
X{
X	register long word;
X	register int c, bcount;
X	register FILE *fin = stdin, *fout = stdout;	/* in regs for speed */
X	register char *map, *p;
X	register long nbytes;
X	register int crc;
X	long nbytes2;
X	int w, crc2;
X	char buf[512];
X	extern char *index();
X
X	myname = argv[0];
X	if (sizeof(word) < 4)
X		fprintf(stderr, "%s: word size too small\n", myname), exit(1);
X	if (argc > 2)
X		fprintf(stderr, "Usage: %s [file]\n", myname), exit(1);
X	if (argc == 2) {
X		if ((fin = fopen(argv[1], "r")) == NULL) {
X			fprintf(stderr, "%s: ", myname);
X			perror(argv[1]);
X			exit(1);
X		}
X		inputfile = argv[1];
X	}
X	/* skip to beginning of encoded data */
X	do {
X		if (fgets(buf, sizeof buf, fin) == NULL)
X			fatal("Missing header");
X		/* trim trailing blanks (sigh) */
X		p = index(buf, '\n');
X		if (p == 0)
X			continue;
X		while (*--p == ' ')
X			;
X		p[1] = '\n';
X		p[2] = '\0';
X	} while (strcmp(buf, header) != 0);
X	
X	/* define input mapping table */
X	map = buf+1;
X	for (c = 0; c < 256; c++)
X		map[c] = 64;		/* illegal */
X	for (c = 0; c < 64; c++)
X		map[ENCODE(c)] = c;
X	map[EOF] = 65;		/* special cases */
X	map['/'] = 66;
X
X	word = 0;
X	bcount = 4;
X	nbytes = 0;
X	crc = 0;
X#define PUTC(x)  { c = (x) & 0xff; CRC(crc, c); putc(c, fout); nbytes++; }
X	for (;;) {
X		c = map[getc(fin)];
X		if ((unsigned)c < 64) {
X			word <<= 6;
X			word |= c;
X			if (--bcount == 0) {
X				PUTC(word >> 16);
X				PUTC(word >>  8);
X				PUTC(word);
X				word = 0;
X				bcount = 4;
X			}
X			continue;
X		}
X		switch (c) {
X
X		default:
X			/*
X			 * Ignore stuff not in the code set.
X			 */
X			continue;
X
X		case 65:	/* EOF */
X			fatal("Unexpected EOF");
X
X		case 66:	/* '/' */
X			/* trailer follows: %d%x */
X			c = getc(fin);
X			if (fscanf(fin, "%x", &w) != 1)
X				fatal("Corrupted input (trailer)");
X			switch (c) {
X			case '2': PUTC(w >> 8);
X			case '1': PUTC(w);
X			case '0': break;
X			default: fatal("Corrupted input (trailer)");
X			}
X			/*
X			 * Byte count and CRC follow.
X			 */
X			if (fscanf(fin, "%ld%x", &nbytes2, &crc2) != 2)
X				fatal("Corrupted input (missing byte count/CRC)");
X			if (nbytes2 != nbytes)
X				fatal("Corrupted input (byte count is wrong)");
X			if (crc2 != (crc & 0xffff))
X				fatal("Corrupted input (CRC mismatch)");
X			exit(0);
X		}
X	}
X}
X
Xfatal(s)
X	char *s;
X{
X	fprintf(stderr, "%s: %s: %s\n", myname, inputfile, s);
X	exit(2);
X}
!
echo 'input/newsspool.c':
sed 's/^X//' >'input/newsspool.c' <<'!'
X/*
X * newsspool - copy incoming news into incoming directory
X *
X * The -i option relies on the parent setting (and exporting) $PATH.
X *
X * $Log$
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <errno.h>
X#include "libc.h"
X#include "news.h"
X#include "config.h"
X
X#ifndef lint
Xstatic char RCSid[] = "$Header$";
X#endif
X
X#ifndef MAXTRIES
X#define	MAXTRIES	100	/* limit on attempts to make links */
X#endif
X
Xint debug = 0;
Xchar *progname;
X
Xextern void error(), exit();
X#ifdef UTZOOERR
Xextern char *mkprogname();
X#else
X#define	mkprogname(a)	(a)
X#endif
X
Xchar buf[BUFSIZ*16];	/* try to get a batch in a few gulps */
Xint immed = 0;		/* try an immediate newsrun? */
X
Xvoid process();
XFILE *outopen();
Xvoid outclose();
Xextern time_t time();
Xchar *outname();
X
X/*
X - main - parse arguments and handle options
X */
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c;
X	int errflg = 0;
X	FILE *in;
X	struct stat statbuf;
X	extern int optind;
X	extern char *optarg;
X	extern FILE *efopen();
X	void process();
X
X	progname = mkprogname(argv[0]);
X
X	while ((c = getopt(argc, argv, "id")) != EOF)
X		switch (c) {
X		case 'i':	/* try immediate newsrun */
X			immed++;
X			break;
X		case 'd':	/* Debugging. */
X			debug++;
X			setbuf(stderr, (char *)NULL);
X			break;
X		case '?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg) {
X		fprintf(stderr, "usage: %s [file] ...\n", progname);
X		exit(2);
X	}
X
X	/* probe to get unprivileged() called if necessary */
X	(void) ctlfile((char *)NULL);
X
X	/* mktemp() uses access(2) [ARGH!] so minimize chances of trouble */
X	(void) setgid(getegid());
X	(void) setuid(geteuid());
X
X	(void) umask(newsumask());
X
X	if (optind >= argc)
X		process(stdin, "stdin");
X	else
X		for (; optind < argc; optind++)
X			if (STREQ(argv[optind], "-"))
X				process(stdin, "-");
X			else {
X				in = efopen(argv[optind], "r");
X				if (fstat(fileno(in), &statbuf) < 0)
X					error("can't fstat `%s'", argv[optind]);
X				if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
X					error("`%s' is directory!", argv[optind]);
X				process(in, argv[optind]);
X				(void) fclose(in);
X			}
X
X	if (immed) {
X		/* execlp because shell files may not be directly execable */
X		execlp(binfile("input/newsrun"), "newsrun", (char *)NULL);
X		error("attempt to run newsrun failed!", "");
X	}
X	exit(0);
X}
X
X/*
X * process - process input file
X */
X/* ARGSUSED */
Xvoid
Xprocess(in, inname)
XFILE *in;
Xchar *inname;
X{
X	register int count;
X	register int firstblock;
X	FILE *out;
X	register char *p;
X	register int n;
X	char *name;
X
X	name = outname();
X	out = outopen(name);
X
X	/* do the copying */
X	firstblock = 1;
X	while ((count = fread(buf, sizeof(char), sizeof(buf), in)) > 0) {
X		if (firstblock) {
X			n = cunskip(buf, count);
X			p = buf + n;
X			count -= n;
X			firstblock = 0;
X		} else
X			p = buf;
X		n = fwrite(p, sizeof(char), count, out);
X		if (n != count)
X			error("write error in output to `%s'", name);
X	}
X
X	outclose(out, name);
X}
X
X/*
X - outname - construct name for the temporary output file
X */
Xchar *
Xoutname()
X{
X	register char *p;
X
X	p = strsave(fullartfile("in.coming/nspool.XXXXXX"));
X	mktemp(p);
X	return(p);
X}
X
X/*
X - outopen - acquire an output file
X */
XFILE *
Xoutopen(name)
Xchar *name;
X{
X	FILE *f;
X
X	f = fopen(name, "w");
X	if (f == NULL)
X		error("unable to create temporary `%s'", name);
X	if (debug)
X		fprintf(stderr, "output into %s\n", name);
X
X	return(f);
X}
X
X/*
X - outclose - close output file, moving it to the right place
X *
X * Names are based on the current time in hopes of keeping input in order.
X */
Xvoid
Xoutclose(f, tmpname)
XFILE *f;
Xchar *tmpname;
X{
X	register char *p;
X	register char *name;
X	register int ntries;
X	time_t now;
X	extern int errno;
X
X	if (fclose(f) == EOF)
X		error("fclose error on file `%s'", tmpname);
X
X	p = fullartfile("in.coming/");
X	name = emalloc(strlen(p) + 20);	/* plenty for a number */
X	(void) strcpy(name, p);
X	p = name + strlen(name);
X
X	ntries = 0;
X	for (;;) {
X		now = time((time_t *)NULL);
X		sprintf(p, "%ld", now);
X		if (debug)
X			fprintf(stderr, "trying renaming to %s\n", name);
X		if (link(tmpname, name) >= 0)
X			break;		/* NOTE BREAK OUT */
X		if (errno != EEXIST)	/* something strange is wrong */
X			error("unable to link `%s'", tmpname);
X		errno = 0;
X		if (ntries > MAXTRIES)	/* sanity check */
X			error("too many attempts to link `%s'", tmpname);
X		if (debug)
X			fprintf(stderr, "failed\n");
X		sleep(2);	/* avoid rumored race in 1-sec sleep */
X		ntries++;
X	}
X
X	if (debug)
X		fprintf(stderr, "succeeded\n");
X	(void) unlink(tmpname);
X}
X
X/*
X - cunskip - inspect block for silly #! cunbatch headers
X */
Xint				/* number of chars at start to skip */
Xcunskip(bufp, count)
Xchar *bufp;
Xint count;
X{
X	static char goop[] = "cunbatch";
X#	define	GOOPLEN	(sizeof(goop)-1)	/* strlen(goop) */
X	static char goop2[] = "c7unbatch";
X#	define	GOOP2LEN	(sizeof(goop2)-1)	/* strlen(goop2) */
X	register char *p;
X	register int nleft;
X
X	nleft = count;
X	p = bufp;
X
X	if (nleft < 2)				/* no room for a header */
X		return(0);
X	if (*p++ != '#' || *p++ != '!')		/* doesn't start with #! */
X		return(0);
X	nleft -= 2;
X
X	/* skip space */
X	while (nleft > 0 && (*p == ' ' || *p == '\t')) {
X		p++;
X		nleft--;
X	}
X
X	/* recognize headers (the +1s ensure room for the newline) */
X	if (nleft >= GOOPLEN+1 && STREQN(p, goop, GOOPLEN)) {
X		p += GOOPLEN;
X		nleft -= GOOPLEN;
X	} else if (nleft >= GOOP2LEN+1 && STREQN(p, goop2, GOOP2LEN)) {
X		p += GOOP2LEN;
X		nleft -= GOOP2LEN;
X	} else					/* no header */
X		return(0);
X
X	/* skip more space */
X	while (nleft > 0 && (*p == ' ' || *p == '\t')) {
X		p++;
X		nleft--;
X	}
X
X	if (nleft == 0 || *p++ != '\n')		/* didn't end properly */
X		return(0);
X
X	return(p - bufp);
X}
X
X/*
X - unprivileged - drop setuidness if configuration is overridden
X */
Xvoid
Xunprivileged()
X{
X	setgid(getgid());
X	setuid(getuid());
X}
!
echo 'input/Makefile':
sed 's/^X//' >'input/Makefile' <<'!'
X# You get your choice of rnews.immed or rnews.batch; rnews.immed tries
X# to start processing immediately, while rnews.batch waits for somebody
X# else (cron) to do it.  Running rnews.immed might, perhaps, be reasonable
X# if your news load is light and you are wildly impatient about processing
X# incoming news.  Otherwise, leave this alone.
XRNEWS = rnews.batch
X
XDEFINES =
XCOPTS = -O
XCFLAGS = $(COPTS) $(DEFINES) -I../include
XLINTFLAGS = $(DEFINES) -I../include -ha
XLDFLAGS = $(CFLAGS)
XLIBS= ../libcnews.a
XBATCH = ../batch
XTHEMBIN = newsrun newsrunning c7decode bdecode recenews recpnews rnews
XTHEM = newsspool $(THEMBIN)
XRBIN = /bin
X# =()<NEWSARTS = @<NEWSARTS>@>()=
XNEWSARTS = /usr/spool/news
X# =()<NEWSBIN = @<NEWSBIN>@>()=
XNEWSBIN = /usr/lib/newsbin
X# workaround for System V make bug
XSHELL = /bin/sh
XDTR = README Makefile newsrun newsrunning newsspool.c c7decode.c rnews.batch \
X	rnews.8 bdecode.c recenews recpnews
X
Xall:	$(THEM) rnews
X
Xbininstall:	all
X	chmod +x $(THEM) rnews
X	-if test ! -d $(NEWSBIN)/input ; then mkdir $(NEWSBIN)/input ; fi
X	rm -f $(NEWSBIN)/input/newsspool
X	cp $(THEM) $(NEWSBIN)/input
X	cp rnews $(RBIN)/rnews
X	cp rnews $(RBIN)/cunbatch
X	: "and newsspool needs to be made setuid-news"
X
Xnewsinstall:
X	: nothing
X
Xnewsspool: newsspool.o $(LIBS)
X	$(CC) $(LDFLAGS) newsspool.o $(LIBS) -o $@
X
Xc7decode: c7decode.o $(LIBS)
X	$(CC) $(LDFLAGS) c7decode.o $(LIBS) -o $@
X
Xbdecode: bdecode.o $(BATCH)/crctab.o $(LIBS)
X	$(CC) $(LDFLAGS) bdecode.o $(BATCH)/crctab.o $(LIBS) -o $@
X
X$(BATCH)/crctab.o:	$(BATCH)/crctab.c
X	( cd $(BATCH) ; make crctab.o )
X
Xbdecode.o:	bdecode.c $(BATCH)/coder.h
X	$(CC) -c -I$(BATCH) $(CFLAGS) bdecode.c
X
Xlint:	newsspool.c
X	lint $(LINTFLAGS) newsspool.c 2>&1 | tee lint
X
Xtest.1:
X	echo '#! rnews' >$@
X	echo 'here is a phony first batch' >>$@
X
Xtest.2:
X	echo '#! cunbatch' >$@
X	echo '#! rnews' >>$@
X	echo 'here is a phony second batch' >>$@
X
Xtest.3p:
X	echo '#! rnews' >$@
X	echo 'here is a phony third batch' >>$@
X
Xtest.3:	test.3c
X	( echo '#! cunbatch' ; cat test.3c ) >$@
X
Xtest.3c:	test.3p
X	: compress tends to return silly exit status for tiny inputs
X	-compress -b12 <test.3p >$@
X
Xtest.out:
X	echo '#! rnews' >$@
X	echo 'here is a phony first batch' >>$@
X	echo '#! rnews' >>$@
X	echo 'here is a phony second batch' >>$@
X	echo '#! rnews' >>$@
X	echo 'here is a phony third batch' >>$@
X
Xrnews.immed:	rnews.batch
X	sed '/qqq/s/newsspool/& -i/' rnews.batch >$@
X
Xrnews:	rnews.batch rnews.immed
X	cp $(RNEWS) rnews
X	chmod +x rnews
X
Xsetup:	all
X	chmod +x rnews.batch rnews.immed
X	rm -rf bin
X	mkdir bin
X	cp $(THEM) bin
X	mkdir bin/input
X	cp newsrun bin/input
X	rm -f tmp.1
X	here=`pwd` ; echo "cat >>$$here/tmp.1" >bin/relaynews
X	echo "echo 1" >bin/spacefor
X	echo 'ln $$*' >bin/newslock
X	echo 'echo 10' >bin/sizeof
X	chmod +x bin/* bin/input/*
X	rm -rf in.coming
X	mkdir in.coming
X
Xr:	all test.1 test.2 test.3 test.3c test.out setup
X	chmod +x $(THEM)
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./rnews.batch <test.1
X	cmp in.coming/* test.1
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./rnews.batch <test.2
X	sed 1d test.2 >tmp.2
X	cmp `ls -t in.coming | sed -n '1s;^;in.coming/;p'` tmp.2
X	rm tmp.2
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./rnews.batch <test.3
X	cmp `ls -t in.coming | sed -n '1s;^;in.coming/;p'` test.3c
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./newsrunning off
X	test -r in.coming/stop
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./newsrunning on
X	test ! -r in.coming/stop
X	mkdir in.coming/bad
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./newsrun
X	cmp tmp.1 test.out
X	test " `echo in.coming/*`" = ' in.coming/bad'
X	rm tmp.1
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./rnews.batch <test.1
X	NEWSARTS=`pwd` NEWSCTL=`pwd` ./rnews.batch <test.2
X	NEWSARTS=`pwd` NEWSCTL=`pwd` NEWSBIN=`pwd`/bin ./rnews.immed <test.3
X	cmp tmp.1 test.out
X	test " `echo in.coming/*`" = ' in.coming/bad'
X	rm tmp.1
X	rm -r bin in.coming
X
Xclean:
X	rm -f *.o newsspool c7decode tmp.? test.* dtr lint rnews rnews.immed
X	rm -f bdecode
X	rm -rf in.coming bin
X
Xdtr:	$(DTR)
X	makedtr $(DTR) >dtr
!
echo 'input/README':
sed 's/^X//' >'input/README' <<'!'
XThis is the input processing, which starts at rnews (aka cunbatch).  It
Xinvokes newsspool, which actually puts the stuff where it belongs (peeling
Xoff the silly and unnecessary "#! cunbatch" header, if any, as it goes).
X
XNewsrun should be run regularly; it unspools the stuff and feeds it into
Xthe relay subsystem for processing.  Newsrunning can be used to turn this
Xfunction on and off if you want to avoid news processing during busy hours.
X
XUsing rnews.immed instead of rnews.batch as rnews will arrange for newsrun
Xto be run after each newsspool -- this is expensive but cuts down latency.
XIf you've got a fast machine and a light newsfeed and totally lack patience,
Xlike Geoff :-), this might be a good idea; otherwise, no.
X
X"make r" builds everything and runs a full regression test on most everything.
!
echo 'input/recenews':
sed 's/^X//' >'input/recenews' <<'!'
X#! /bin/sh
X# News reception via mail, bencoded format.
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/input:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xbdecode | rnews
!
echo 'input/newsrun':
sed 's/^X//' >'input/newsrun' <<'!'
X#! /bin/sh
X# Process spooled news.
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/input:$NEWSBIN/relay:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xhere="$NEWSARTS/in.coming"
Xcd $here
X
X# First, is it worth trying at all?
Xif test -r stop
Xthen
X	exit 0
Xfi
X
X# Lock against others running.
Xlock="$NEWSCTL/LOCKinput"
Xltemp="$NEWSCTL/L.$$"
Xecho $$ >$ltemp
Xtrap "rm -f $ltemp ; exit 0" 0 1 2 15
Xif newslock $ltemp $lock
Xthen
X	trap "rm -f $ltemp $lock ; exit 0" 0 1 2 15
Xelse
X	exit 0
Xfi
X
X# Sort out where we are.
Xif test -r $NEWSCTL/server
Xthen
X	me="`hostname`"
X	server=`cat $NEWSCTL/server`
Xelse
X	me=me			# don't need actual name
X	server="$me"		# no server file --> we're it
Xfi
X
X# Master loop.
Xwhile :				# "while true", but : is faster
Xdo
X	# Find some work.
X	them=`ls | sed '/[^0-9]/d;50q'`
X	if test " $them" = " "
X	then
X		break			# NOTE BREAK OUT
X	fi
X
X	# Check space.  It is *probably* better to stop processing
X	# when things get too full.  (This test is actually a bit
X	# inaccurate since the batches may be compressed, but it's
X	# good enough to catch major space problems.)
X	allsize=`sizeof $them`
X	if test " `spacefor $allsize articles`" -gt 1	# lots of room
X	then
X		muchroom=y
X	else
X		muchroom=
X	fi
X
X	# Do it.
X	rmlist=
X	for f in $them
X	do
X		# Check for request to stop.
X		if test -r stop
X		then
X			rm -f $rmlist
X			exit 0
X		fi
X
X		# Check for empty.
X		if test ! -s $f
X		then
X			rm -f $f
X			continue			# NOTE CONTINUE
X		fi
X
X		# Space check, if we're close.
X		if test " $muchroom" != " y"
X		then
X			batchsize=`sizeof $f`
X			if test " `spacefor $batchsize articles`" -le 0
X			then
X				rm -f $rmlist
X				exit 0
X			fi
X		fi
X
X		# Decompress if necessary.  People who get lots of
X		# uncompressed batches and never use c7 encoding might
X		# want to remove the c7decode attempt to speed things up.
X		text=nruntmp.$$
X		if compress -d <$f >$text 2>/dev/null
X		then
X			rmlist="$rmlist $f $text"
X		elif c7decode <$f 2>/dev/null | compress -d >$text 2>/dev/null
X		then
X			rmlist="$rmlist $f $text"
X		else
X			rm -f $text
X			text=$f
X			rmlist="$rmlist $f"
X		fi
X
X		# Do it.  -r redirects stdout and stderr into logs.  -n makes
X		# history entries for refused articles; this is right for
X		# NNTP-feed sites and doesn't hurt uucp-feed sites unless
X		# they refuse a good fraction of what they get.
X		if test " $server" = " $me"	# if local
X		then
X			relaynews -r -n <$text
X		else
X			# N.B.: rsh always returns exit status 0!
X			rsh $server "PATH=$PATH relaynews -r -n" <$text
X		fi
X		st=$?
X		if test $st -ne 0
X		then
X			# trouble
X			if test ! -d bad
X			then
X				mkdir bad
X			fi
X			bad=bad/$f
X
X			if test -s bad/limit
X			then
X				limit=`sed 1q bad/limit`
X			else
X				limit=50
X			fi
X			nfiles=`ls bad | wc | awk '{print $1}'`
X			if test " $nfiles" -lt " $limit"
X			then
X				mv $f $bad	# Not $text, save the ORIGINAL!
X			fi
X			echo "$server $consumer \`$bad' failed, status $st" |
X							mail "$NEWSMASTER"
X		fi
X
X	done
X	rm -f $rmlist
Xdone
X
Xexit 0
!
echo 'input/newsrunning':
sed 's/^X//' >'input/newsrunning' <<'!'
X#! /bin/sh
X# newsrunning - turn news processing on and off
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/input:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xstop=$NEWSARTS/in.coming/stop
X
Xcase "$1"
Xin
X	on)
X	rm -f $stop
X	;;
X
X	off)
X	if test ! -r $stop	# don't update already-existing file
X	then
X		>$stop
X	fi
X	;;
X
X	*)
X	echo "Usage: $0 on/off" >&2
X	exit 2
X	;;
Xesac
X
Xexit 0
!
echo 'input/c7decode.c':
sed 's/^X//' >'input/c7decode.c' <<'!'
X#include <stdio.h>
X
X/*
X * This program is the inverse of encode
X *
X * It collects runs of 12 characters, combines pairs of those
X * to form 6 13 bit numbers, extracts the top bit of each of
X * those to make a 13th 6 bit character, and splits each of
X * the remaining 6 12 bit numbers to form 12 6 bit ones.
X *
X * The strings of 6 bit numbers are collected into groups of
X * 4 and converted into 3 8 bit characters.
X *
X * Now all that would be trivial, if we didn't need to worry
X * about ending all this correctly.  About 1/2 of the following
X * program wouldn't be here if the ending didn't matter....
X */
X
X/*
X * the following pair of characters can never occur as a pair
X * in legal input (since (90 * 91 + 90) > 2^13) - they are
X * noticed at the beginning of a 12 char block, and serve to
X * indicate that this block is the terminator.  The character
X * immediately following is the (expanded) terminator length.
X */
X#define	ENDMARK1	((90*91 + 90) / 91)
X#define	ENDMARK2	((90*91 + 90) % 91)
X
Xint errcnt = 0;
X
Xmain()
X{
X	register c;
X	register char *p;
X	register i;
X	register first = 1;
X	register cnt = 0;
X	char b12[12];
X	char c12[12];
X
X	p = b12;
X	i = 12;
X
X	while ((c = getchar()) != EOF) {
X		if (c < ' ' || c >= (' ' + 91)) {
X			if (errcnt++ == 0)
X				fprintf(stderr, "c7decode: Bad data\n");
X			continue;
X		}
X		if (i == 10 && p[-1] == ENDMARK1 && p[-2] == ENDMARK2) {
X			cnt = c - ' ';
X			i = 12;
X			p -= 2;
X			continue;
X		}
X		*p++ = c - ' ';
X		if (--i == 0) {
X			if (p == &b12[12]) {
X				if (!first)
X					pack12(c12, 12, 0);
X				else
X					first = 0;
X				p = c12;
X			} else {
X				pack12(b12, 12, 0);
X				p = b12;
X			}
X			i = 12;
X		}
X	}
X
X	if (p >= &b12[0] && p < &b12[12]) {
X		if (!first)
X			pack12(c12, 12, i == 12 ? cnt : 0);
X	} else
X		pack12(b12, 12, i == 12 ? cnt : 0);
X
X	if (i != 12) {
X		if (p >= &b12[0] && p < &b12[12])
X			pack12(b12, 12-i, cnt);
X		else
X			pack12(c12, 12-i, cnt);
X	}
X
X	exit((errcnt > 0) ? 1 : 0);
X}
X
Xstatic char b4[4];
Xstatic int cnt = 0;
X
Xpack12(p, n, last)
X	register char *p;
X	register n;
X	int last;
X{
X	register i;
X	register char *q;
X	char b13[13];
X
X	{
X		register c;
X		register c13;
X
X		q = b13;
X		c13 = 0;
X
X		for (i = 0; i < n; i += 2) {
X			c = *p++ * 91;
X			c += *p++;
X			c13 <<= 1;
X			if (c & (1 << 12))
X				c13 |= 1;
X			*q++ = (c >> 6) & 0x3f;
X			*q++ = c & 0x3f;
X		}
X		*q++ = c13;
X		if (last)
X			q = &b13[last];
X	}
X
X	p = b13;
X	n = q - p;
X	i = cnt;
X	q = &b4[cnt];
X
X	while (--n > 0) {
X		*q++ = *p++;
X		if (++i == 4) {
X			char b3[3];
X			register char *b = b4;
X
X			/* inline expansion of pack6bit, to save calls ... */
X
X			q = b3;
X			*q++ = (b[0] << 2) | ((b[1] >> 4) & 0x3);
X			*q++ = (b[1] << 4) | ((b[2] >> 2) & 0xf);
X			*q = (b[2] << 6) | (b[3] & 0x3f);
X
X			q = b3;
X			while (--i > 0)
X				putchar(*q++);
X
X			q = b4;
X		}
X	}
X
X	*q++ = *p++;	/* the last octet */
X	++i;
X
X	if (last || i == 4) {
X		pack6bit(b4, i, last);
X		i = 0;
X	}
X
X	cnt = i;
X}
X
Xpack6bit(p, n, last)
X	register char *p;
X	register int n;
X	int last;
X{
X	register char *q;
X	register i = 3;
X	char b3[3];
X
X	if (last) {
X		i = p[n-1];
X		if (i >= 3) {
X			fprintf(stderr, "c7decode: Badly encoded file\n");
X			errcnt++;
X			i = 3;		/* do the best we can */
X		}
X	}
X
X	q = b3;
X	*q++ = (p[0] << 2) | ((p[1] >> 4) & 0x3);
X	*q++ = (p[1] << 4) | ((p[2] >> 2) & 0xf);
X	*q = (p[2] << 6) | (p[3] & 0x3f);
X
X	q = b3;
X
X	while (--i >= 0)
X		putchar(*q++);
X}
!
echo 'input/rnews.batch':
sed 's/^X//' >'input/rnews.batch' <<'!'
X#! /bin/sh
X# Incoming-news spooling.
X# We ignore arguments -- it looks tempting to put "$*" after cat and
X# newsspool, but there are security problems.
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/input:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
X# check space, assuming a pretty large batch (no cheap way to find real size)
Xcounter=1
Xwhile test " `spacefor 250000 incoming`" -le 0
Xdo
X	sleep 300
X	if test " $counter" -gt 1111		# four tries is plenty
X	then
X		# oh no! -- nothing we can do, really...
X		cat >/dev/null
X		echo incoming news discarded due to space shortage |
X							mail "$NEWSMASTER"
X		exit 1
X	fi
X	counter="1$counter"
Xdone
X
Xif newsspool >/tmp/ngripe.$$ 2>&1		# qqq (marker for Makefile)
Xthen
X	rm -f /tmp/ngripe.$$
X	exit 0
Xelse
X	# there really isn't any way to save the data if newsspool fails,
X	# not without causing other problems
X	(
X		echo newsspool failed!!!
X		cat /tmp/ngripe.$$
X	) | mail "$NEWSMASTER"
X	rm -f /tmp/ngripe.$$
X	exit 1
Xfi
!
echo 'input/recpnews':
sed 's/^X//' >'input/recpnews' <<'!'
X#! /bin/sh
X# News reception via mail, protected format (inferior to bencode).
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/input:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xsed -n '1,/^$/d
Xs/^N//p' | rnews
!
echo 'libbig/active.fast.c':
sed 's/^X//' >'libbig/active.fast.c' <<'!'
X/*
X * active file access functions (big, fast, in-memory version)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "libc.h"
X#include "news.h"
X#include "config.h"
X#include "active.h"
X
X/* private */
Xstatic char *active = NULL;	/* cache: points at entire active file */
Xstatic int actsize;		/* bytes in active: type int fixed by fread */
Xstatic char **actlnps;		/* point at lines in active file */
Xstatic unsigned actlines;	/* lines in actlnps actually used */
X
X/* imports from active.c */
Xextern char actrelnm[];
X
X/* forwards */
XFORWARD statust actmkindx();
X
Xstatust
Xactfload(fp)
XFILE *fp;
X{
X	statust status = ST_OKAY;
X
X	if (fp != NULL && active == NULL) {
X		struct stat sb;
X
X		errno = 0;
X		if (fstat(fileno(fp), &sb) < 0)
X			warning("can't fstat `%s'", ctlfile(actrelnm));
X		else if (actsize = sb.st_size, /* squeeze into an int */
X		    (unsigned)actsize != sb.st_size)
X			warning("`%s' won't fit into memory", ctlfile(actrelnm));
X		else if ((active = malloc((unsigned)actsize+1)) == NULL)
X			warning("can't allocate memory for `%s'",
X				ctlfile(actrelnm));
X		else {
X			rewind(fp);
X			/*
X			 * If we read with fgetms, we might be able to avoid
X			 * calling linescan().
X			 */
X			if (fread(active, 1, actsize, fp) != actsize) {
X				warning("error reading `%s'", ctlfile(actrelnm));
X				status |= ST_DROPPED;
X			} else
X				status |= actmkindx();
X		}
X		if (active == NULL)
X			status |= ST_DROPPED;	/* give up! */
X		if (status != ST_OKAY) {
X			nnfree(&active);
X			nnafree(&actlnps);
X		}
X	}
X	return status;
X}
X
Xstatic statust
Xactmkindx()			/* build actlnps index for active */
X{
X	register statust status = ST_OKAY;
X	unsigned lnpsz;
X	int maxlines;
X
X	active[actsize] = '\0';		/* make a proper string */
X	/* +1 for a possible partial line +1 for a dummy to check overflow */
X	maxlines = charcount(active, '\n') + 2;
X	lnpsz = sizeof(char *) * (long) maxlines;
X	if (lnpsz != sizeof(char *) * (long)maxlines ||
X	    (actlnps = (char **)malloc(lnpsz)) == NULL) {
X		warning("`%s' index won't fit in memory", ctlfile(actrelnm));
X	    	status |= ST_DROPPED;
X	} else {
X		actlnps[maxlines - 2] = "";	/* in case no partial line */
X		actlnps[maxlines - 1] = "";	/* end sentinel */
X		actlines = linescan(active, actlnps, maxlines);
X		if (actlines >= maxlines) {
X			(void) fprintf(stderr,
X				"%s: too many newsgroups in `%s' (can't happen)\n",
X				progname, ctlfile(actrelnm));
X			status |= ST_DROPPED;
X		}
X	}
X	return status;
X}
X
X/*
X * Store in lnarray the addresses of the starts of lines in s.
X * Return the number of lines found; if greater than nent,
X * store only nent and return nent.
X * Thus lnarray should be one bigger than needed to detect overflow.
X */
Xint
Xlinescan(s, lnarray, nent)
Xchar *s;
Xchar **lnarray;
Xregister int nent;
X{
X	register char **lnarrp = lnarray;
X	register int i = 0;
X	register char *nlp = s;
X
X	if (i < nent)
X		*lnarrp++ = nlp;
X	while (++i < nent && (nlp = index(nlp, '\n')) != NULL && *++nlp != '\0')
X		*lnarrp++ = nlp;
X	return i;		/* number of addrs stored */
X}
X
Xstatust
Xactfsync(fp)			/* write to disk, fp is open */
XFILE *fp;
X{
X	statust status = ST_OKAY;
X
X	rewind(fp);
X	if (active != NULL) {
X		if (fwrite(active, actsize, 1, fp) != 1)
X			status |= ST_DROPPED;	/* serious loss */
X		nnfree(&active);
X		nnafree(&actlnps);
X	}
X	return status;
X}
X
X/* ARGSUSED fp */
Xchar *
Xactfind(fp, ng, nglen)
XFILE *fp;
Xregister char *ng;
Xregister int nglen;
X{
X	register char *pos;
X	register unsigned line = 0;
X
X	while (pos = actlnps[line], line++ < actlines && pos[0] != '\0')
X		if (STREQN(pos, ng, nglen) && pos[nglen] == ' ')
X			return pos;
X	return NULL;
X}
X
X/* ARGSUSED */
Xstatust
Xactfwrnum(fp, pos)
XFILE *fp;
Xchar *pos;
X{
X	return ST_OKAY;
X}
!
echo 'libbig/sys.fast.c':
sed 's/^X//' >'libbig/sys.fast.c' <<'!'
X/*
X * news sys file reading functions (fast, big, in-memory version)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "news.h"
X#include "system.h"
X
X/* imports */
Xextern struct system *currsys, *firstsys;
X
X/* exports */
Xboolean justone = NO;
X
X/* private */
Xstatic struct system *thissys = NULL;
X
X/* ARGSUSED */
Xvoid
Xrewsys(fp)
XFILE *fp;
X{
X	currsys = firstsys;
X}
X
Xstruct system *
Xmysysincache()				/* optimisation */
X{
X	return thissys;
X}
X
Xvoid
Xremmysys(sys)				/* remember this system */
Xstruct system *sys;
X{
X	thissys = sys;
X}
X
Xvoid
Xfreecurrsys()
X{
X	/* never free sys entries */
X}
!
echo 'libbig/Makefile':
sed 's/^X//' >'libbig/Makefile' <<'!'
X# libbig makefile
XINCLUDE=../include
XDEFINES=-I$(INCLUDE) -I../relay
XCOPTS= -O # -g -p -pg
XCFLAGS= $(COPTS) $(DEFINES)
XLINTFLAGS=-hau $(DEFINES)
XLIB=libbig.a
X# RANLIB is ranlib on non-USG systems, echo on USG systems
XRANLIB=ranlib
X#RANLIB=:
XSRCS=active.fast.c sys.fast.c
XOBJS=active.fast.o sys.fast.o
X# workaround for System V make bug
XSHELL = /bin/sh
X
Xu:	$(OBJS)
X	ar ruv ../libcnews.a $(OBJS)
X
Xall:	$(OBJS)
X
X$(LIB): $(SRCS)
X	$(CC) $(CFLAGS) -c $?
X	ar rv $@ *.o
X	rm *.o
X	$(RANLIB) $@
X
Xlint:
X	lint $(LINTFLAGS) $(SRCS)
X
Xclean:
X	rm -f *.o
!
echo 'libbsd42/clsexec.c':
sed 's/^X//' >'libbsd42/clsexec.c' <<'!'
X/*
X * set close on exec (on Berklix)
X */
X
X#include <stdio.h>
X#include <sgtty.h>
X
Xvoid
Xfclsexec(fp)
XFILE *fp;
X{
X	(void) ioctl(fileno(fp), FIOCLEX, (char *)NULL);
X}
!
echo 'libbsd42/getcwd.c':
sed 's/^X//' >'libbsd42/getcwd.c' <<'!'
X/*
X * SystemV getcwd simulation on 4.2BSD
X */
X
X#include <stdio.h>
X#include <sys/param.h>
X
X/* imports from libc */
Xextern char *getwd();
Xextern char *strncpy();
X
Xchar *
Xgetcwd(path, size)
Xregister char *path;
Xint size;
X{
X	if (size >= MAXPATHLEN)
X		return getwd(path);
X	else {
X		char wd[MAXPATHLEN];
X
X		if (getwd(wd) == 0)
X			return 0;
X		else {
X			(void) strncpy(path, wd, size-1);
X			path[size-1] = '\0';
X			return path;
X		}
X	}
X}
!
echo 'libbsd42/fopenexcl.c':
sed 's/^X//' >'libbsd42/fopenexcl.c' <<'!'
X/*
X * fopenexcl(name) - fopen(name, "w") with error if name exists (Berklix)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>		/* 4.2's O_EXCL defn */
X
XFILE *
Xfopenexcl(name)
Xregister char *name;
X{
X	/* This is the cheaper way. */
X	register int fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0666);
X
X	if (fd < 0)
X		return NULL;		/* name existed or couldn't be made */
X	else
X		return fdopen(fd, "w");
X}
!
echo 'libbsd42/Makefile':
sed 's/^X//' >'libbsd42/Makefile' <<'!'
X# C news libbsd42 makefile
XINCLUDE = ../include
XDEFINES=-I$(INCLUDE)
XCOPTS=-O  # -g -p
XCFLAGS=$(COPTS) $(DEFINES)
XLINTFLAGS=-hau $(DEFINES)
X# workaround for System V make bug
XSHELL = /bin/sh
X
XSRCS = clsexec.c fopenexcl.c getcwd.c
XOBJS = clsexec.o fopenexcl.o getcwd.o
X
X# RANLIB is ranlib on non-USG systems, echo on USG systems
XRANLIB=ranlib
X
Xu:	$(OBJS)
X	ar ruv ../libcnews.a $(OBJS)
X
Xall:	$(OBJS)
X
Xlibbsd42.a: $(SRCS)
X	$(CC) $(CFLAGS) -c $?
X	ar ru $@ *.o
X	rm *.o
X	$(RANLIB) $@
Xlint:
X	lint $(LINTFLAGS) $(SRCS)
X
Xclean:
X	rm -f *.o
!
echo 'libc/Makefile':
sed 's/^X//' >'libc/Makefile' <<'!'
X# C news local libc makefile - added by Ian Darwin
XINCLUDE=../include
XDEFINES=-I$(INCLUDE)
XCOPTS=-O # -g -p
XCFLAGS=$(COPTS) $(DEFINES)
XLINTFLAGS=-hau $(DEFINES)
X# workaround for System V make bug
XSHELL = /bin/sh
X
XSRCS=closeall.c efopen.c error.c fgetmfs.c \
X	nfclose.c \
X	standard.c stdfdopen.c warning.c emalloc.c
XOBJS = closeall.o efopen.o error.o fgetmfs.o getdate.o nfclose.o \
X	standard.o stdfdopen.o warning.o emalloc.o
X
X# RANLIB is ranlib on non-USG systems, echo on USG systems
XRANLIB=ranlib
X#RANLIB=echo
X
Xu:	$(OBJS)
X	ar ruv ../libcnews.a $(OBJS)
X
Xall:	$(OBJS)
X
Xlibc.a:	$(SRCS)
X	$(CC) $(CFLAGS) -c $?
X	ar ru $@ *.o
X	rm *.o
X	$(RANLIB) $@
Xlint:
X	lint $(LINTFLAGS) $(SRCS)
X
Xclean:
X	rm -f *.o *.a getdate.c y.*.h y.*.c
!
echo 'libc/emalloc.c':
sed 's/^X//' >'libc/emalloc.c' <<'!'
X/*
X * emalloc - malloc with error() called when out of space
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "libc.h"
X
Xextern void error();
X
Xchar *
Xemalloc(amount)
Xunsigned amount;
X{
X	register char *it;
X	char camount[25];		/* Enough to sprintf an unsigned. */
X
X	it = malloc(amount);
X	if (it == NULL) {
X		sprintf(camount, "%u", amount);
X		error("malloc(%s) failed", camount);
X	}	
X
X	return(it);
X}
!
echo 'libc/fgetmfs.3':
sed 's/^X//' >'libc/fgetmfs.3' <<'!'
X.TH FGETMFS 3 local
X.DA 23 May 1989
X.SH NAME
Xfgetmfs \- read an arbitrarily long, possibly continued line
X.SH SYNOPSIS
X.B "#include <stdio.h>
X.br
X.B "#include <fgetmfs.h>
X.PP
X.B "char *fgetmfs(stream, limit, cont)"
X.br
X.B "FILE *stream;"
X.br
X.B "int limit, cont;"
X.PP
X.B "char *fgetms(stream)
X.br
X.B "FILE *stream;"
X.PP
X.B "char *cfgetms(stream)
X.br
X.B "FILE *stream;"
X.SH DESCRIPTION
X.I Fgetmfs
Xreads an arbitrarily long line from
X.IR stream ,
Xallocating memory via
X.IR malloc (3)
Xas needed.
XIf
X.I limit
Xis non-negative,
X.I fgetmfs
Xwill read no more than
X.I limit
Xbytes from
X.IR stream .
XFor efficiency,
Xif
X.I cont
Xis not
X.IR CONT_NO ,
Xsuch as
X.I CONT_NOSPC
Xor
X.IR CONT_SPC ,
Xoccurrences of a backslash and a newline together
Xand in that order
Xwill be deleted from the input stream;
Xif
X.I cont
Xis
X.IR CONT_NOSPC ,
Xany whitespace after the newline
Xin the input stream will also be deleted from it.
X.PP
XThe macros
X.I fgetms
X(to read without continuations)
Xand
X.I cfgetms
X(to read with continuations and remove leading whitespace)
Xshould be used instead when the
X.I limit
Xis not needed.
X.PP
X.I Fgetmfs
Xis intended to provide a reliable mechanism for reading
Xinput containing lines of arbitrary length,
Xrather than trusting that no line with be longer than some
Xarbitrary tolerance.
X.PP
XThe memory returned by
X.I fgetmfs
Xshould be returned when no longer needed via
X.IR free (3).
X.\" .SH FILES
X.SH SEE ALSO
X.IR malloc (3),
X.IR fgets (3)
X.SH DIAGNOSTICS
XReturns NULL (0) if memory cannot be allocated or upon reading end-of-file;
Xuse
X.I feof(stream)
Xto distinguish.
X.SH HISTORY
XWritten by Geoff Collyer
Xat the University of Toronto
Xas part of the C news project.
X.SH BUGS
XIt's too slow.
X.br
XThe meaning of the
X.I cont
Xflag is ugly,
Xbut layering this form of continuation on top is even slower.
!
echo 'libc/fgetmfs.c':
sed 's/^X//' >'libc/fgetmfs.c' <<'!'
X/*
X * fgetmfs - read an arbitrarily long, possibly continued line;
X * return a pointer to it, in malloced memory.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <fgetmfs.h>
X#include "libc.h"
X
X#define max(a,b) ((a) > (b)? (a): (b))
X#define min(a,b) ((a) < (b)? (a): (b))
X
X/* One could make these arguments, with defaults. */
X#define INITLN 90		/* initial allocation per line */
X#define GROWLN 200		/* additional allocation size */
X
X/* getseg returns */
X#define FAILED 0
X#define HITLIMIT 1
X#define OKAY 2
X
Xstatic unsigned sz;		/* bytes currently allocated (in line) */
Xstatic int incr;		/* for sz */
Xstatic char *line;		/* current allocation */
Xstatic char *segment;		/* start of line segment in "line" */
Xstatic char *morep;		/* last byte possibly containing input */
X
X/*
X * `fget malloced, flagged string' with continuations and limit on bytes.
X * The limit is like fgets's; limit-1 bytes can be read.  -1 means "no limit".
X */
Xchar *
Xfgetmfs(fp, limit, cont)
XFILE *fp;
Xregister int limit, cont;		/* honour \ continuations? */
X{
X	/* allocate room for an initial segment of a line */
X	sz = INITLN;
X	incr = GROWLN;
X	if (limit >= 0 && sz > limit)
X		sz = limit;
X	line = malloc(sz);
X	if (line == NULL)
X		return NULL;		/* no memory, can't go on */
X	segment = line;
X	morep = line + sz - 2;
X
X	/* read all lines, including continuations */
X	do {
X		/* read the first segment of a line */
X		*morep = '\0';			/* mark end of segment */
X		if (fgets(segment, (int)sz-(segment-line), fp) == NULL) {
X			free(line);		/* EOF: give up */
X			return NULL;
X		}
X
X		/* read more of this line, if it didn't fit */
X		while (*morep != '\0' && *morep != '\n') {
X			register int code = getseg(fp, limit);
X
X			if (code == FAILED)
X				return NULL;
X			else if (code == HITLIMIT)
X				break;
X		}
X	} while (cont && ismore(fp, cont));
X	return realloc(line, (unsigned)(strlen(line)+1));	/* save space */
X}
X
Xstatic int
Xgetseg(fp, limit)
XFILE *fp;
Xregister int limit;
X{
X	register int oldsz = sz;
X
X	/* extend the allocation, within limit */
X	incr = GROWLN;
X	sz += incr;
X	if (limit >= 0 && sz > limit) {
X		sz = limit;
X		incr = sz - oldsz;
X	}
X	if (incr <= 0)			/* hit the limit? */
X		return HITLIMIT;
X	line = realloc(line, sz);
X	if (line == NULL)
X		return FAILED;		/* no memory, can't go on */
X	/* -1 starts on the terminating NUL of the prev. segment */
X	segment = line + oldsz - 1;
X	morep = line + sz - 2;		/* recompute for new line, sz */
X
X	/* read the next segment */
X	*morep = '\0';
X	/* +1 because segment includes terminating NUL of the prev. segment */
X	if (fgets(segment, incr+1, fp) == NULL) {
X		free(line);		/* EOF: give up */
X		return FAILED;
X	}
X	return OKAY;
X}
X
Xstatic int
Xismore(fp, cont)
Xregister FILE *fp;
Xint cont;
X{
X	register char *nlp;
X
X	/* got a whole line: is it to be continued? */
X	if (incr > 0 && cont && (nlp = rindex(line, '\n')) != NULL &&
X	    nlp > line && *--nlp == '\\') {
X		*nlp = '\0';			/* delete "\\\n" */
X		segment = nlp;
X	    	if (cont == CONT_NOSPC) {
X			register int c;
X
X			/* discard leading whitespace */
X			while ((c = getc(fp)) != EOF && c != '\n' &&
X			   isascii(c) && isspace(c))
X				;
X			if (c != EOF)
X				(void) ungetc(c, fp);
X	    	}
X		return 1;			/* read next line */
X	} else
X		return 0;
X}
!
echo 'libc/standard.c':
sed 's/^X//' >'libc/standard.c' <<'!'
X#define	NULL	0
X
Xextern void closeall();
Xextern char	**environ;
X
Xstatic char	*stdenv[] = {
X/* =()<	"PATH=@<NEWSPATH>@",>()=	*/
X	"PATH=/bin:/usr/bin",
X	"IFS= \t\n",
X	NULL
X};
X
Xvoid
Xstandard()
X{
X	environ = stdenv;
X	closeall(1);
X}
X
Xvoid
Xsafe()
X{
X	setgid(getgid());
X	setuid(getuid());
X	closeall(1);
X}
!
echo 'libc/stdfdopen.c':
sed 's/^X//' >'libc/stdfdopen.c' <<'!'
X/*
X * stdfdopen - ensure that the standard i/o descriptors are open,
X *	to avoid mayhem.
X */
X
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifndef NSYSFILE
X#define NSYSFILE 3					/* hmm, not on V8 */
X#endif
X
Xextern int errno;
X
Xvoid
Xstdfdopen()			/* ensure standard descriptors are open */
X{
X	register int fd;
X	struct stat stbuf;
X
X	for (fd = 0; fd < NSYSFILE; fd++)
X		if (fstat(fd, &stbuf) < 0 && errno == EBADF)
X			if (open("/dev/null", 2) != fd)	/* open read/write */
X				exit(1);		/* bad news */
X}
!
echo 'libc/error.3':
sed 's/^X//' >'libc/error.3' <<'!'
X.TH ERROR 3 local
X.DA 8 May 1984
X.SH NAME
Xerror, warning \- print error messages
X.SH SYNOPSIS
X.nf
X.B error(s1, s2)
X.B char *s1;
X.B char *s2;
X
X.B warning(s1, s2)
X.B char *s1;
X.B char *s2;
X
X.B extern char *progname;
X.B extern int errno;
X
X.B progname = argv[0];
X.SH DESCRIPTION
X.I Warning
Xprints an error message, with suitable embellishments,
Xand clears
X.IR errno .
X.I Error
Xdoes likewise and then exits.
XThe
X.I s1
Xargument should be a
X.I printf
Xformat string (without a trailing newline), with
X.I s2
Xavailable as an argument.
X.PP
XIf there is an environment variable
X.BR CMDNAME
Xwith non-null value,
Xits contents are printed first, followed by a colon.
XFollowing this,
Xany non-null value of
X.I progname
Xis printed, followed by a colon and a space.
XFollowing this,
X.IR fprintf (3)
Xis invoked with
X.I s1
Xas the format string and
X.I s2
Xas the argument.
XIf the value of
X.I errno
Xis within the normal range,
Xa standard elaborating message is printed (see
X.IR intro (2)).
X.PP
X.B CMDNAME
Xshould be set by shellfiles that expect subordinate programs to
Xissue error message in the shellfile's name.
X.I Progname
Xshould be set by all programs;
X.I argv[0]
Xis usually a suitable thing to set it to.
X.I Errno
Xis set by system calls and various other routines,
Xalthough its use is not universal;
Xnote that it is not reset by successful system calls following an
Xunsuccessful one.
X.SH SEE ALSO
Xintro(2), intro(3), printf(3), exit(2), getopt(3)
X.SH DIAGNOSTICS
X.IR Error 's
Xexit status is 1.
X.SH HISTORY
XLocal products, modelled on the
X.I error
Xin Kernighan&Pike.
X.SH BUGS
XBe nice if they could take a full
X.IR printf -style
Xargument list.
!
echo 'libc/error.c':
sed 's/^X//' >'libc/error.c' <<'!'
X/*
X * error - print best error message possible and exit
X */
X
X#include <stdio.h>
X
Xextern void warning();
X
Xvoid
Xerror(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X	warning(s1, s2);
X	exit(1);
X}
!
echo 'libc/warning.c':
sed 's/^X//' >'libc/warning.c' <<'!'
X/*
X * warning - print best error message possible and clear errno
X */
X
X#include <stdio.h>
X
Xvoid
Xwarning(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X	char *cmdname;
X	extern int errno, sys_nerr;
X	extern char *sys_errlist[];
X	extern char *progname;
X	extern char *getenv();
X
X	(void) fflush(stdout);				/* hack */
X	cmdname = getenv("CMDNAME");
X	if (cmdname != NULL && *cmdname != '\0')
X		fprintf(stderr, "%s:", cmdname);	/* No space after :. */
X	if (progname != NULL)
X		fprintf(stderr, "%s: ", progname);
X	fprintf(stderr, s1, s2);
X	if (errno > 0 && errno < sys_nerr)
X		fprintf(stderr, " (%s)", sys_errlist[errno]);
X	fprintf(stderr, "\n");
X	errno = 0;
X}
!
echo 'libc/standard.3':
sed 's/^X//' >'libc/standard.3' <<'!'
X.TH STANDARD 3 local
X.DA 9 Feb 1982
X.SH NAME
Xstandard, safe \- standardize conditions in preparation for exec
X.SH SYNOPSIS
X.B standard()
X.PP
X.B safe()
X.SH DESCRIPTION
X.I Standard
Xalters a process's environment to make it relatively safe to do
X.IR execvp ,
X.IR system ,
X.IR popen ,
Xetc.
XIt closes all descriptors except
Xthe standard ones and supplies a standard set of environment variables
Xthat ensure a standard interpretation of shell commands and a
Xstandard search path for programs.
X.PP
X.I Safe
Xis similar, but is intended for use in shell escapes and suchlike.
XIt leaves the environment variables untouched but turns off
Xsetuid and setgid permissions.
X.PP
XUse of either one permits a setuid/setgid program to
Xrun other programs without inadvertently bestowing special powers
Xon nonstandard programs.
XCare must still be exercised as to what the standard descriptors
Xrefer to,
Xand it is still possible for
Xprograms executed after use of
X.I standard
X(as opposed to
X.IR safe )
Xto give away special powers through
X.I their
Xcarelessness.
X.SH SEE ALSO
Xenviron(3), closeall(3)
X.SH HISTORY
XLocal products.
X.SH BUGS
X.I Standard
Xmust necessarily supply standard values for some environment variables,
Xbut it is not clear whether it should pass other variables
Xthrough or eliminate them.
XThe current implementation eliminates them, which is safer but sometimes
Xinconvenient.
X.PP
XOne can construct elaborate scenarios in which a setuid
Xprogram employing
X.I safe
Xcould be duped into
Xexecuting a user-supplied program in a current directory
Xthe user ordinarily could not have reached.
X.PP
XPossibly
Xone or both should standardize the
X.I umask
Xsetting.
!
echo 'libc/closeall.3':
sed 's/^X//' >'libc/closeall.3' <<'!'
X.TH CLOSEALL 3 local
X.DA 9 Feb 1982
X.SH NAME
Xcloseall \- close all files
X.SH SYNOPSIS
X.ft B
Xcloseall(leavestd)
X.br
Xint leavestd;
X.ft R
X.SH DESCRIPTION
X.I Closeall
Xcloses all currently-open file descriptors.
XIf
X.I leavestd
Xis non-zero,
Xthe standard input, output, and diagnostic descriptors are left open;
Xotherwise they are closed too.
X.SH SEE ALSO
Xclose(2), standard(3)
X.SH HISTORY
XLocal invention.
X.SH BUGS
XNothing wrong with
X.IR closeall ,
Xbut there ought to be an
X.IR fcloseall .
!
echo 'libc/closeall.c':
sed 's/^X//' >'libc/closeall.c' <<'!'
X#include <sys/param.h>
X
Xvoid
Xcloseall(leavestd)
Xint leavestd;
X{
X	register int i;
X
X	for (i = (leavestd? 3: 0); i < NOFILE; i++)
X		close(i);
X}
!
echo 'libc/README':
sed 's/^X//' >'libc/README' <<'!'
XThese should, ideally, be inserted into your C library if they aren't
Xthere already.  If they can't be put into your C library nor -llocal,
Xjust put the ones not in your C library into libc.a in this directory.
X
XThey were all written by either Henry Spencer, Geoff Collyer or Brian
XKernighan & Rob Pike.
!
echo 'libc/efopen.3':
sed 's/^X//' >'libc/efopen.3' <<'!'
X.TH EFOPEN 3 local
X.DA 24 April 1984
X.SH NAME
Xefopen \- open a stream, checking for errors
X.SH SYNOPSIS
X.nf
X.B FILE *
X.B efopen(file, mode)
X.B char *file;
X.B char *mode;
X.SH DESCRIPTION
X.I Efopen
Xinvokes
X.IR fopen (3)
Xand checks the result for errors.
XIn the absence of errors, it returns the stream pointer;
Xin the presence of errors, it prints a message and exits.
X.SH SEE ALSO
Xfopen(3), error(3)
X.SH DIAGNOSTICS
XExit status, in the event of error, is 1.
X.SH HISTORY
XLocal product, roughly following the one in Kernighan&Pike.
!
echo 'libc/efopen.c':
sed 's/^X//' >'libc/efopen.c' <<'!'
X/*
X * efopen - fopen file, exit with message if impossible
X */
X
X#include <stdio.h>
X
X/* imports from libc */
Xextern char *strcpy(), *strncat();
Xextern void error();
X
Xstatic char message[] = "can't open file \"%s\" mode ";
X
XFILE *
Xefopen(file, mode)
Xchar *file;
Xchar *mode;
X{
X	FILE *fp;
X	char fullmsg[sizeof(message)+10];
X	extern int errno;
X
X	errno = 0;		/* Wipe out residue of earlier errors. */
X	fp = fopen(file, mode);
X	if (fp == NULL) {
X		(void) strcpy(fullmsg, message);
X		(void) strncat(fullmsg, mode, 10);
X		error(fullmsg, file);
X		/* NOTREACHED */
X	}
X	return(fp);
X}
!
echo done


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.