[news.software.b] beta version of C news speedups

zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff) (11/14/89)

These files, along with dbz, are some speed and security improvements 
for C news.  Read the code to see if these are applicable and remember 
that they are beta versions.  This code is not as portable as the 
originals.  Send me mail if you have any comments or improvements.  

Files include: rnews.c, spacefor.c, relaynews.c

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  rnews.c relaynews.c spacefor.c
# Wrapped by zeeff@b-tech on Mon Nov 13 12:45:27 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f rnews.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rnews.c\"
else
echo shar: Extracting \"rnews.c\" \(34307 characters\)
sed "s/^X//" >rnews.c <<'END_OF_rnews.c'
X
X/*
X
XJZ rnews.c for C news v.2 (beta)
X
XC News has a fair amount of overhead in all the processes that get run 
Xbetween rnews and relaynews.  This program eliminates most of this 
Xoverhead for a substantial performance increase.  I measure ~40% on my 
Xtests with 200k before compression batches.  Performance improvement 
Xwill be higher on smaller batches or with uncompressed feeds.  
XBasically, things go right from rnews into relaynews.  You do give up 
Xa little bit of error recovery since batches are not spooled.  
X
XMuch of standard C News overhead is concerned with disk space.  IMHO, 
Xthere are better ways of doing disk space managment than C New's 
Xlimited method of not unpacking news if the disk is full.  If news is 
Xcontinuing to come in, one is just delaying the inevitable (throwing 
Xaway news) anyway.  I run other, more effective things that take care 
Xof disk space; a progressive expire and a uucp killing demon (ie, 
Xif some site tries to send too much news, it gets cut off until there 
Xis more space).  
X
XC News makes some attempts to address local news security but leaves 
Xsome holes (newsspool and relaynews) that make some of this a wasted 
Xeffort.  You don't ever want a user directly or indirectly running a 
Xnews owned program while their uid is exposed.  There is little sense 
Xin using another id (such as news) if breaking that id allows one to 
Xbreak many others by a trojan horse attack.  This program runs suid 
Xroot and immediately gives it up.  It cures the problem of a uid being 
Xexposed through the rnews/newsspool entry point.  If you install the 
Xsupplied relaynews.c the other entry point (inews/relaynews) will be 
Xsecure from this attack.  You can get rid of setnewsids and change 
Xnewsspool and relaynews.real permissions and ownership to be like all 
Xthe other files.  
X
XThis program should be in a public bin directory and:
X
X -rws--x--x  root  bin    rnews
X
XTested only on a SUNOS 4.0 system and a Sys V.3.1 system.  Let me know
Xif it runs on others.
X
XCopyright 1989 Jon Zeeff <zeeff@b-tech.ann-arbor.mi.us>
X
XYou can do whatever you want with this code provided you 
X
X0) remember that this is a beta version
X1) leave my name on it
X2) don't hold me responsible for any problems.  
X3) report all bugs and modifications to me via email 
X
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <fcntl.h>
X
X#define NEWS_UID	10
X#define NEWS_GROUP	10
X#define RELAYNEWS	"/usr/lib/newsbin/relay/relaynews.real -r"
X#define SYSV		/* define on Sys V sites */
X/* #define BSD		/* define on BSD sites */
X#define HAVE_STATFS 	/* If you have statfs() syscall */
X#define NICE		/* define if you want to slow things down */
X#define LIB_MNT		"/usr" /* mount point (eg, /usr) for /usr/lib/news */
X#define SPOOL_MNT	"/usr/spool" /* mount point for spool directory */
X#define MIN_INODES	100   /* inodes needed for rnews to run */
X#define LIB_FREE	300   /* free blocks needed for rnews to run */
X#define SPOOL_FREE	300   /* ditto for the spool area */
X
X/* external declarations */
Xextern char **environ;
Xextern FILE *popen();
Xvoid perror();
Xvoid exit();
Xunsigned sleep();
X
X/* forward declarations */
Xvoid copyout();
X	
XFILE *relaynews;
X
Xmain()
X{
X	char buffer[20];
X
X	/* get rid of our suid root status completely */
X	if (setgid(NEWS_GROUP) || setuid(NEWS_UID)) {
X           perror("can't set uid or gid\n");
X           /* exit(1); /* */
X        }
X
X	/* replace environment with a clean one */
X        environ[0] = "IFS= \t\n";
X        environ[1] = "PATH=/bin:/usr/bin";
X        environ[2] = 0;
X
X	(void) umask(022);
X#ifdef NICE
X        (void) nice(20);
X#endif
X
X        /* Do we have a reasonable number of free blocks? */
X        /* Eliminate this test if you don't have disk space problems */
X
X        if (!have_space(LIB_MNT,LIB_FREE)||!have_space(SPOOL_MNT,SPOOL_FREE)) {
X           fprintf(stderr,"Not enough space to run rnews\n");
X
X           /* Why 75?  Because, I use 75 to indicate a temporary  
X              error that the program calling rnews (eg. uuxqt with 
X              the right modification) may be able to use to try again 
X              later.  */ 
X
X           exit(75);   
X        }
X
X	(void) fclose(stdout);
X        relaynews = popen(RELAYNEWS,"w");
X
X	if (relaynews == NULL) {
X		perror("can't popen relaynews");
X		exit(3);
X	}
X
X	if (fread(buffer, 1, 12, stdin) != 12) {
X		fprintf(stderr, "could not read in first 12 characters\n");
X		exit(4);
X	}
X
X	if (memcmp(buffer, "#! cunbatch\n",12) == 0) 
X	   uncompress();
X	else if (buffer[0] == 0x1f) {   /* compressed w/o cunbatch */
X                rewind(stdin);          /* won't work on a pipe */
X                uncompress();
X             }
X        else {                                          /* plain text */
X            if (fwrite(buffer,1,12,relaynews) != 12) {
X		fprintf(stderr, "error writing first 12 characters\n");
X		exit(5);
X	    }
X	    copyout();
X	}
X
X	if (pclose(relaynews) != 0) {
X           perror("pclose of relaynews failed");
X           exit(6);
X        }
X
X        return 0;
X}
X
X/* Copy stdin to relaynews */
X
Xvoid
Xcopyout()
X{
X	int count;
X	char buf[8192];
X
X        while ((count = fread(buf,1,8192,stdin)) > 0) {
X               (void) fwrite(buf,1,count,relaynews);
X#ifdef NICE
X		sleep(1);	/* reduce system load (for uncompressed) */
X#endif		
X        }
X
X}
X
X/*
X
X  Space checker.  Based on code by:
X
X  denny@mcmi.uucp (Denny Page)
X
X*/
X
X
X#ifdef SYSV
X#ifdef HAVE_STATFS
X#include <sys/statfs.h>
X#define FREEBLOCKS statfsb.f_bfree
X#define FREENODES statfsb.f_ffree
Xstruct statfs statfsb;
X#else /* HAVE_STATFS */
X#include <sys/stat.h>
X#include <ustat.h>
X#define FREEBLOCKS ustatb.f_tfree
X#define FREENODES ustatb.f_tinode
Xstruct stat statb;
Xstruct ustat ustatb;
X#endif /* HAVE_STATFS */
X#endif
X
X#ifdef BSD
X#define HAVE_STATFS
X#include <sys/vfs.h>
Xstruct statfs statfsb;
X#define FREEBLOCKS statfsb.f_bavail
X#define FREENODES statfsb.f_ffree
X#endif
X
Xhave_space(dirname, minblocks)
Xchar *dirname;
Xint minblocks;
X{
X
X#ifndef BSD 
X#ifndef SYSV
X   return 1;
X#endif
X#endif
X
X 
X#ifdef HAVE_STATFS
X    if (statfs(dirname, &statfsb, sizeof(statfsb), 0) != 0) {
X	perror("statfs failed");
X	return(1);
X    }
X#else /* HAVE_STATFS */
X    if (stat(dirname, &statb) != 0) {
X	perror("stat failed");
X	return(1);
X    }
X    if (ustat(statb.st_dev, &ustatb) != 0) {
X	perror("ustat failed");
X	return(1);
X    }
X#endif /* HAVE_STATFS */
X
X    if (FREEBLOCKS > minblocks && FREENODES > MIN_INODES)
X       return 1;
X    else
X       return 0;
X
X}
X
X/* The following is a slightly hacked up version of compress */
X/* It reads from stdin and writes to stdout */
X
X/* 
X * Compress - data compression program 
X */
X
X#define BITS 16
X
X#define	min(a,b)	((a>b) ? b : a)
Xextern char *strcpy(), *strcat();
X/*
X * machine variants which require cc -Dmachine:  pdp11, z8000, pcxt
X */
X/*
X * Set USERMEM to the maximum amount of physical user memory available
X * in bytes.  USERMEM is used to determine the maximum BITS that can be used
X * for compression.
X *
X * SACREDMEM is the amount of physical memory saved for others; compress
X * will hog the rest.
X */
X#ifndef SACREDMEM
X#define SACREDMEM	0
X#endif
X
X#ifndef USERMEM
X# define USERMEM 	450000	/* default user memory */
X#endif
X
X#ifdef interdata		/* (Perkin-Elmer) */
X#define SIGNED_COMPARE_SLOW	/* signed compare is slower than unsigned */
X#endif
X
X#ifdef pdp11
X# define BITS 	12	/* max bits/code for 16-bit machine */
X# define NO_UCHAR	/* also if "unsigned char" functions as signed char */
X# undef USERMEM 
X#endif /* pdp11 */	/* don't forget to compile with -i */
X
X#ifdef z8000
X# define BITS 	12
X# undef vax		/* weird preprocessor */
X# undef USERMEM 
X#endif /* z8000 */
X
X#ifdef pcxt
X# define BITS   12
X# undef USERMEM
X#endif /* pcxt */
X
X#ifdef USERMEM
X# if USERMEM >= (433484+SACREDMEM)
X#  define PBITS	16
X# else
X#  if USERMEM >= (229600+SACREDMEM)
X#   define PBITS	15
X#  else
X#   if USERMEM >= (127536+SACREDMEM)
X#    define PBITS	14
X#   else
X#    if USERMEM >= (73464+SACREDMEM)
X#     define PBITS	13
X#    else
X#     define PBITS	12
X#    endif
X#   endif
X#  endif
X# endif
X# undef USERMEM
X#endif /* USERMEM */
X
X/* Preferred BITS for this memory size */
X
X#ifdef PBITS	
X# ifndef BITS
X#  define BITS PBITS
X# endif 
X#endif 
X
X#if BITS == 16
X# define HSIZE	69001		/* 95% occupancy */
X#endif
X#if BITS == 15
X# define HSIZE	35023		/* 94% occupancy */
X#endif
X#if BITS == 14
X# define HSIZE	18013		/* 91% occupancy */
X#endif
X#if BITS == 13
X# define HSIZE	9001		/* 91% occupancy */
X#endif
X#if BITS <= 12
X# define HSIZE	5003		/* 80% occupancy */
X#endif
X
X#ifdef M_XENIX			/* Stupid compiler can't handle arrays with */
X# if BITS == 16			/* more than 65535 bytes - so we fake it */
X#  define XENIX_16
X# else
X#  if BITS > 13			/* Code only handles BITS = 12, 13, or 16 */
X#   define BITS	13
X#  endif
X# endif
X#endif
X
X/*
X * a code_int must be able to hold 2**BITS values of type int, and also -1
X */
X#if BITS > 15
Xtypedef long int	code_int;
X#else
Xtypedef int		code_int;
X#endif
X
X#ifdef SIGNED_COMPARE_SLOW
Xtypedef unsigned long int count_int;
Xtypedef unsigned short int count_short;
X#else
Xtypedef long int	  count_int;
X#endif
X
X#ifdef NO_UCHAR
X typedef char	char_type;
X#else
X typedef	unsigned char	char_type;
X#endif /* UCHAR */
Xchar_type magic_header[] = { "\037\235" };	/* 1F 9D */
X
X/* Defines for third byte of header */
X#define BIT_MASK	0x1f
X#define BLOCK_MASK	0x80
X/* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
X   a fourth header byte (for expansion).
X*/
X#define INIT_BITS 9			/* initial number of bits/code */
X
X/*
X * compress.c - File compression ala IEEE Computer, June 1984.
X *
X * Authors:	Spencer W. Thomas	(decvax!harpo!utah-cs!utah-gr!thomas)
X *		Jim McKie		(decvax!mcvax!jim)
X *		Steve Davies		(decvax!vax135!petsd!peora!srd)
X *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
X *		James A. Woods		(decvax!ihnp4!ames!jaw)
X *		Joe Orost		(decvax!vax135!petsd!joe)
X */
X
X/* $Log:	compress.c,v $
X * Revision 4.0  85/07/30  12:50:00  joe
X * Removed ferror() calls in output routine on every output except first.
X * Prepared for release to the world.
X * 
X * Revision 3.6  85/07/04  01:22:21  joe
X * Remove much wasted storage by overlaying hash table with the tables
X * used by decompress: tab_suffix[1<<BITS], stack[8000].  Updated USERMEM
X * computations.  Fixed dump_tab() DEBUG routine.
X *
X * Revision 3.5  85/06/30  20:47:21  jaw
X * Change hash function to use exclusive-or.  Rip out hash cache.  These
X * speedups render the megamemory version defunct, for now.  Make decoder
X * stack global.  Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
X *
X * Revision 3.4  85/06/27  12:00:00  ken
X * Get rid of all floating-point calculations by doing all compression ratio
X * calculations in fixed point.
X *
X * Revision 3.3  85/06/24  21:53:24  joe
X * Incorporate portability suggestion for M_XENIX.  Got rid of text on #else
X * and #endif lines.  Cleaned up #ifdefs for vax and interdata.
X *
X * Revision 3.2  85/06/06  21:53:24  jaw
X * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
X * Default to "quiet" output (no compression statistics).
X *
X * Revision 3.1  85/05/12  18:56:13  jaw
X * Integrate decompress() stack speedups (from early pointer mods by McKie).
X * Repair multi-file USERMEM gaffe.  Unify 'force' flags to mimic semantics
X * of SVR2 'pack'.  Streamline block-compress table clear logic.  Increase 
X * output byte count by magic number size.
X * 
X * Revision 3.0   84/11/27  11:50:00  petsd!joe
X * Set HSIZE depending on BITS.  Set BITS depending on USERMEM.  Unrolled
X * loops in clear routines.  Added "-C" flag for 2.0 compatibility.  Used
X * unsigned compares on Perkin-Elmer.  Fixed foreground check.
X *
X * Revision 2.7   84/11/16  19:35:39  ames!jaw
X * Cache common hash codes based on input statistics; this improves
X * performance for low-density raster images.  Pass on #ifdef bundle
X * from Turkowski.
X *
X * Revision 2.6   84/11/05  19:18:21  ames!jaw
X * Vary size of hash tables to reduce time for small files.
X * Tune PDP-11 hash function.
X *
X * Revision 2.5   84/10/30  20:15:14  ames!jaw
X * Junk chaining; replace with the simpler (and, on the VAX, faster)
X * double hashing, discussed within.  Make block compression standard.
X *
X * Revision 2.4   84/10/16  11:11:11  ames!jaw
X * Introduce adaptive reset for block compression, to boost the rate
X * another several percent.  (See mailing list notes.)
X *
X * Revision 2.3   84/09/22  22:00:00  petsd!joe
X * Implemented "-B" block compress.  Implemented REVERSE sorting of tab_next.
X * Bug fix for last bits.  Changed fwrite to putchar loop everywhere.
X *
X * Revision 2.2   84/09/18  14:12:21  ames!jaw
X * Fold in news changes, small machine typedef from thomas,
X * #ifdef interdata from joe.
X *
X * Revision 2.1   84/09/10  12:34:56  ames!jaw
X * Configured fast table lookup for 32-bit machines.
X * This cuts user time in half for b <= FBITS, and is useful for news batching
X * from VAX to PDP sites.  Also sped up decompress() [fwrite->putc] and
X * added signal catcher [plus beef in writeerr()] to delete effluvia.
X *
X * Revision 2.0   84/08/28  22:00:00  petsd!joe
X * Add check for foreground before prompting user.  Insert maxbits into
X * compressed file.  Force file being uncompressed to end with ".Z".
X * Added "-c" flag and "zcat".  Prepared for release.
X *
X * Revision 1.10  84/08/24  18:28:00  turtlevax!ken
X * Will only compress regular files (no directories), added a magic number
X * header (plus an undocumented -n flag to handle old files without headers),
X * added -f flag to force overwriting of possibly existing destination file,
X * otherwise the user is prompted for a response.  Will tack on a .Z to a
X * filename if it doesn't have one when decompressing.  Will only replace
X * file if it was compressed.
X *
X * Revision 1.9  84/08/16  17:28:00  turtlevax!ken
X * Removed scanargs(), getopt(), added .Z extension and unlimited number of
X * filenames to compress.  Flags may be clustered (-Ddvb12) or separated
X * (-D -d -v -b 12), or combination thereof.  Modes and other status is
X * copied with copystat().  -O bug for 4.2 seems to have disappeared with
X * 1.8.
X *
X * Revision 1.8  84/08/09  23:15:00  joe
X * Made it compatible with vax version, installed jim's fixes/enhancements
X *
X * Revision 1.6  84/08/01  22:08:00  joe
X * Sped up algorithm significantly by sorting the compress chain.
X *
X * Revision 1.5  84/07/13  13:11:00  srd
X * Added C version of vax asm routines.  Changed structure to arrays to
X * save much memory.  Do unsigned compares where possible (faster on
X * Perkin-Elmer)
X *
X * Revision 1.4  84/07/05  03:11:11  thomas
X * Clean up the code a little and lint it.  (Lint complains about all
X * the regs used in the asm, but I'm not going to "fix" this.)
X *
X * Revision 1.3  84/07/05  02:06:54  thomas
X * Minor fixes.
X *
X * Revision 1.2  84/07/05  00:27:27  thomas
X * Add variable bit length output.
X *
X */
X#include <ctype.h>
X#include <signal.h>
X#include <sys/stat.h>
X
X#define ARGVAL() (*++(*argv) || (--argc && *++argv))
X
Xint n_bits;				/* number of bits/code */
Xint maxbits = BITS;			/* user settable max # bits/code */
Xcode_int maxcode;			/* maximum code, given n_bits */
Xcode_int maxmaxcode = 1L << BITS;	/* should NEVER generate this code */
X#ifdef COMPATIBLE		/* But wrong! */
X# define MAXCODE(n_bits)	(1L << (n_bits) - 1)
X#else
X# define MAXCODE(n_bits)	((1L << (n_bits)) - 1)
X#endif /* COMPATIBLE */
X
X#ifdef XENIX_16
Xcount_int htab0[8192];
Xcount_int htab1[8192];
Xcount_int htab2[8192];
Xcount_int htab3[8192];
Xcount_int htab4[8192];
Xcount_int htab5[8192];
Xcount_int htab6[8192];
Xcount_int htab7[8192];
Xcount_int htab8[HSIZE-65536];
Xcount_int * htab[9] = {
X	htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8 };
X
X#define htabof(i)	(htab[(i) >> 13][(i) & 0x1fff])
Xunsigned short code0tab[16384];
Xunsigned short code1tab[16384];
Xunsigned short code2tab[16384];
Xunsigned short code3tab[16384];
Xunsigned short code4tab[16384];
Xunsigned short * codetab[5] = {
X	code0tab, code1tab, code2tab, code3tab, code4tab };
X
X#define codetabof(i)	(codetab[(i) >> 14][(i) & 0x3fff])
X
X#else	/* Normal machine */
Xunsigned short codetab [HSIZE]; 
Xcount_int htab [HSIZE];
X#define htabof(i)	htab[i]
X#define codetabof(i)	codetab[i]
X#endif	/* XENIX_16 */
Xcode_int hsize = HSIZE;			/* for dynamic table sizing */
Xcount_int fsize;
X
X/*
X * To save much memory, we overlay the table used by compress() with those
X * used by decompress().  The tab_prefix table is the same size and type
X * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
X * get this from the beginning of htab.  The output stack uses the rest
X * of htab, and contains characters.  There is plenty of room for any
X * possible stack (stack used to be 8000 characters).
X */
X
X#define tab_prefixof(i)	codetabof(i)
X#ifdef XENIX_16
X# define tab_suffixof(i)	((char_type *)htab[(i)>>15])[(i) & 0x7fff]
X# define de_stack		((char_type *)(htab2))
X#else	/* Normal machine */
X# define tab_suffixof(i)	((char_type *)(htab))[i]
X# define de_stack		((char_type *)&tab_suffixof(1L<<BITS))
X#endif	/* XENIX_16 */
X
Xcode_int free_ent = 0;			/* first unused entry */
Xint exit_stat = 0;
X
Xcode_int getcode();
X
XUsage() {
X#ifdef DEBUG
X(void)fprintf(stderr,"Usage: compress [-dDVfc] [-b maxbits] [file ...]\n");
X}
Xint debug = 0;
X#else
X(void)fprintf(stderr,"Usage: compress [-dfvcV] [-b maxbits] [file ...]\n");
X}
X#endif /* DEBUG */
Xint nomagic = 0;	/* Use a 3-byte magic number header, unless old file */
Xint zcat_flg = 0;	/* Write output on stdout, suppress messages */
Xint quiet = 1;		/* don't tell me about compression */
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
Xint block_compress = BLOCK_MASK;
Xint clear_flg = 0;
Xlong int ratio = 0;
X#define CHECK_GAP 10000	/* ratio check interval */
Xcount_int checkpoint = CHECK_GAP;
X/*
X * the next two codes should not be changed lightly, as they must not
X * lie within the contiguous general code space.
X */ 
X#define FIRST	257	/* first free entry */
X#define	CLEAR	256	/* table clear output code */
X
Xint force = 0;
Xchar ofname [100];
Xint oktozap = 0;	/* true if unlink(ofname) won't lose data */
X
X#ifdef DEBUG
Xint verbose = 0;
X#endif /* DEBUG */
Xvoid (*bgnd_flag)();
X
Xint do_decomp = 0;
X
X/*****************************************************************
X * TAG( main )
X *
X * Algorithm from "A Technique for High Performance Data Compression",
X * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
X *
X * Usage: compress [-dfvc] [-b bits] [file ...]
X * Inputs:
X *	-d:	    If given, decompression is done instead.
X *
X *      -c:         Write output on stdout, don't remove original.
X *
X *      -b:         Parameter limits the max number of bits/code.
X *
X *	-f:	    Forces output file to be generated, even if one already
X *		    exists, and even if no space is saved by compressing.
X *		    If -f is not used, the user will be prompted if stdin is
X *		    a tty, otherwise, the output file will not be overwritten.
X *
X *      -v:	    Write compression statistics
X *
X * 	file ...:   Files to be compressed.  If none specified, stdin
X *		    is used.
X * Outputs:
X *	file.Z:	    Compressed form of file with same mode, owner, and utimes
X * 	or stdout   (if stdin used as input)
X *
X * Assumptions:
X *	When filenames are given, replaces with the compressed version
X *	(.Z suffix) only if the file decreases in size.
X * Algorithm:
X * 	Modified Lempel-Ziv method (LZW).  Basically finds common
X * substrings and replaces them with a variable size code.  This is
X * deterministic, and can be done on the fly.  Thus, the decompression
X * procedure needs no input table, but tracks the way the table was built.
X */
X
Xuncompress()
X{
X    char tempname[100];
X    char *cp, *rindex(), *malloc();
X    extern onintr(), oops();
X
X    if(maxbits < INIT_BITS) maxbits = INIT_BITS;
X    if (maxbits > BITS) maxbits = BITS;
X    maxmaxcode = 1L << maxbits;
X
X	    /* Check the magic number */
X		if ((getchar()!=(magic_header[0] & 0xFF))
X		 || (getchar()!=(magic_header[1] & 0xFF))) {
X		    (void)fprintf(stderr, "stdin: not in compressed format\n");
X		    exit(1);
X		}
X		maxbits = getchar();	/* set -b from file */
X		block_compress = maxbits & BLOCK_MASK;
X		maxbits &= BIT_MASK;
X		maxmaxcode = 1L << maxbits;
X		fsize = 100000;		/* assume stdin large for USERMEM */
X		if(maxbits > BITS) {
X			(void)fprintf(stderr,
X			"stdin: compressed with %d bits, can only handle %d bits\n",
X			maxbits, BITS);
X			exit(1);
X		}
X	    decompress();
X}
X
Xstatic int offset;
Xlong int in_count = 1;			/* length of input */
Xlong int bytes_out;			/* length of compressed output */
Xlong int out_count = 0;			/* # of codes output (for debugging) */
X
X/*****************************************************************
X * TAG( output )
X *
X * Output the given code.
X * Inputs:
X * 	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
X *		that n_bits =< (long)wordsize - 1.
X * Outputs:
X * 	Outputs code to the file.
X * Assumptions:
X *	Chars are 8 bits long.
X * Algorithm:
X * 	Maintain a BITS character long buffer (so that 8 codes will
X * fit in it exactly).  Use the VAX insv instruction to insert each
X * code in turn.  When the buffer fills up empty it and start over.
X */
X
Xstatic char buf[BITS];
X
X#ifndef vax
Xchar_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
Xchar_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
X#endif /* vax */
X
Xoutput( code )
Xcode_int  code;
X{
X#ifdef DEBUG
X    static int col = 0;
X#endif /* DEBUG */
X
X    /*
X     * On the VAX, it is important to have the register declarations
X     * in exactly the order given, or the asm will break.
X     */
X    register int r_off = offset, bits= n_bits;
X    register char * bp = buf;
X
X#ifdef DEBUG
X	if ( verbose )
X	    (void)fprintf( stderr, "%5d%c", code,
X		    (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
X#endif /* DEBUG */
X    if ( code >= 0 ) {
X#ifdef vax
X	/* VAX DEPENDENT!! Implementation on other machines is below.
X	 *
X	 * Translation: Insert BITS bits from the argument starting at
X	 * offset bits from the beginning of buf.
X	 */
X	0;	/* Work around for pcc -O bug with asm and if stmt */
X	asm( "insv	4(ap),r11,r10,(r9)" );
X#else /* not a vax */
X/* 
X * byte/bit numbering on the VAX is simulated by the following code
X */
X	/*
X	 * Get to the first byte.
X	 */
X	bp += (r_off >> 3);
X	r_off &= 7;
X	/*
X	 * Since code is always >= 8 bits, only need to mask the first
X	 * hunk on the left.
X	 */
X	*bp = (*bp & rmask[r_off]) | ((long)code << r_off) & lmask[r_off];
X	bp++;
X	bits -= (8 - r_off);
X	code >>= 8 - r_off;
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if ( bits >= 8 ) {
X	    *bp++ = code;
X	    code >>= 8;
X	    bits -= 8;
X	}
X	/* Last bits. */
X	if(bits)
X	    *bp = code;
X#endif /* vax */
X	offset += n_bits;
X	if ( offset == ((long)n_bits << 3) ) {
X	    bp = buf;
X	    bits = n_bits;
X	    bytes_out += bits;
X	    do
X		(void)putchar(*bp++);
X	    while(--bits);
X	    offset = 0;
X	}
X
X	/*
X	 * If the next entry is going to be too big for the code size,
X	 * then increase it, if possible.
X	 */
X	if ( free_ent > maxcode || (clear_flg > 0))
X	{
X	    /*
X	     * Write the whole buffer, because the input side won't
X	     * discover the size increase until after it has read it.
X	     */
X	    if ( offset > 0 ) {
X		if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
X			writeerr();
X		bytes_out += n_bits;
X	    }
X	    offset = 0;
X
X	    if ( clear_flg ) {
X    	        maxcode = MAXCODE (n_bits = INIT_BITS);
X	        clear_flg = 0;
X	    }
X	    else {
X	    	n_bits++;
X	    	if ( n_bits == maxbits )
X		    maxcode = maxmaxcode;
X	    	else
X		    maxcode = MAXCODE(n_bits);
X	    }
X#ifdef DEBUG
X	    if ( debug ) {
X		(void)fprintf( stderr, "\nChange to %d bits\n", n_bits );
X		col = 0;
X	    }
X#endif /* DEBUG */
X	}
X    } else {
X	/*
X	 * At EOF, write the rest of the buffer.
X	 */
X	if ( offset > 0 )
X	    (void)fwrite( buf, 1, (offset + 7) / 8, stdout );
X	bytes_out += (offset + 7) / 8;
X	offset = 0;
X	(void)fflush( stdout );
X#ifdef DEBUG
X	if ( verbose )
X	    (void)fprintf( stderr, "\n" );
X#endif /* DEBUG */
X	if( ferror( stdout ) )
X		writeerr();
X    }
X}
X
X/*
X * Decompress stdin to stdout.  This routine adapts to the codes in the
X * file building the "string" table on-the-fly; requiring no table to
X * be stored in the compressed file.  The tables used herein are shared
X * with those of the compress() routine.  See the definitions above.
X */
X
Xdecompress() {
X    register char_type *stackp;
X    register int finchar;
X    register code_int code, oldcode, incode;
X
X    /*
X     * As above, initialize the first 256 entries in the table.
X     */
X    maxcode = MAXCODE(n_bits = INIT_BITS);
X    for ( code = 255; code >= 0; code-- ) {
X	tab_prefixof(code) = 0;
X	tab_suffixof(code) = (char_type)code;
X    }
X    free_ent = ((block_compress) ? FIRST : 256 );
X
X    finchar = oldcode = getcode();
X    if(oldcode == -1)	/* EOF already? */
X	return;			/* Get out of here */
X    (void)putchar( (char)finchar );		/* first code must be 8 bits = char */
X    if(ferror(stdout))		/* Crash if can't write */
X	writeerr();
X    stackp = de_stack;
X
X    while ( (code = getcode()) > -1 ) {
X
X	if ( (code == CLEAR) && block_compress ) {
X	    for ( code = 255; code >= 0; code-- )
X		tab_prefixof(code) = 0;
X	    clear_flg = 1;
X	    free_ent = FIRST - 1;
X	    if ( (code = getcode ()) == -1 )	/* O, untimely death! */
X		break;
X	}
X	incode = code;
X	/*
X	 * Special case for KwKwK string.
X	 */
X	if ( code >= free_ent ) {
X            *stackp++ = finchar;
X	    code = oldcode;
X	}
X
X	/*
X	 * Generate output characters in reverse order
X	 */
X#ifdef SIGNED_COMPARE_SLOW
X	while ( ((unsigned long)code) >= ((unsigned long)256) ) {
X#else
X	while ( code >= 256 ) {
X#endif
X	    *stackp++ = tab_suffixof(code);
X	    code = tab_prefixof(code);
X	}
X	*stackp++ = finchar = tab_suffixof(code);
X
X	/*
X	 * And put them out in forward order
X	 */
X	do
X	    (void)putchar ((char) *--stackp );
X	while ( stackp > de_stack );
X
X	/*
X	 * Generate the new entry.
X	 */
X	if ( (code=free_ent) < maxmaxcode ) {
X	    tab_prefixof(code) = (unsigned short)oldcode;
X	    tab_suffixof(code) = finchar;
X	    free_ent = code+1;
X	} 
X	/*
X	 * Remember previous code.
X	 */
X	oldcode = incode;
X    }
X    (void)fflush( stdout );
X    if(ferror(stdout))
X	writeerr();
X}
X
X/*****************************************************************
X * TAG( getcode )
X *
X * Read one code from the standard input.  If EOF, return -1.
X * Inputs:
X * 	stdin
X * Outputs:
X * 	code or -1 is returned.
X */
X
Xcode_int
Xgetcode() {
X    /*
X     * On the VAX, it is important to have the register declarations
X     * in exactly the order given, or the asm will break.
X     */
X    register code_int code;
X    static int poffset = 0, size = 0;
X    static char_type pbuf[BITS];
X    register int r_off, bits;
X    register char_type *bp = pbuf;
X
X    if ( clear_flg > 0 || poffset >= size || free_ent > maxcode ) {
X	/*
X	 * If the next entry will be too big for the current code
X	 * size, then we must increase the size.  This implies reading
X	 * a new pbuffer full, too.
X	 */
X	if ( free_ent > maxcode ) {
X	    n_bits++;
X	    if ( n_bits == maxbits )
X		maxcode = maxmaxcode;	/* won't get any bigger now */
X	    else
X		maxcode = MAXCODE(n_bits);
X	}
X	if ( clear_flg > 0) {
X    	    maxcode = MAXCODE (n_bits = INIT_BITS);
X	    clear_flg = 0;
X	}
X	size = fread((char *) pbuf, 1, n_bits, stdin );
X	if ( size <= 0 )
X	    return -1;			/* end of file */
X	poffset = 0;
X	/* Round size down to integral number of codes */
X	size = ((long)size << 3) - (n_bits - 1);
X    }
X    r_off = poffset;
X    bits = n_bits;
X#ifdef vax
X    asm( "extzv   r10,r9,(r8),r11" );
X#else /* not a vax */
X	/*
X	 * Get to the first byte.
X	 */
X	bp += (r_off >> 3);
X	r_off &= 7;
X	/* Get first part (low order bits) */
X#ifdef NO_UCHAR
X	code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
X#else
X	code = (*bp++ >> r_off);
X#endif /* NO_UCHAR */
X	bits -= (8 - r_off);
X	r_off = 8 - r_off;		/* now, poffset into code word */
X	/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
X	if ( bits >= 8 ) {
X#ifdef NO_UCHAR
X	    code |= (*bp++ & 0xff) << r_off;
X#else
X	    code |= *bp++ << r_off;
X#endif /* NO_UCHAR */
X	    r_off += 8;
X	    bits -= 8;
X	}
X	/* high order bits. */
X	code |= (*bp & rmask[bits]) << r_off;
X#endif /* vax */
X    poffset += n_bits;
X
X    return code;
X}
X
Xchar *
Xrindex(s, c)		/* For those who don't have it in libc.a */
Xregister char *s, c;
X{
X	char *p;
X	for (p = NULL; *s; s++)
X	    if (*s == c)
X		p = s;
X	return(p);
X}
X
X#ifdef DEBUG
Xprintcodes()
X{
X    /*
X     * Just print out codes from input file.  For debugging.
X     */
X    code_int code;
X    int col = 0, bits;
X
X    bits = n_bits = INIT_BITS;
X    maxcode = MAXCODE(n_bits);
X    free_ent = ((block_compress) ? FIRST : 256 );
X    while ( ( code = getcode() ) >= 0 ) {
X	if ( (code == CLEAR) && block_compress ) {
X   	    free_ent = FIRST - 1;
X   	    clear_flg = 1;
X	}
X	else if ( free_ent < maxmaxcode )
X	    free_ent++;
X	if ( bits != n_bits ) {
X	    (void)fprintf(stderr, "\nChange to %d bits\n", n_bits );
X	    bits = n_bits;
X	    col = 0;
X	}
X	(void)fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
X    }
X    (void)putc( '\n', stderr );
X    exit( 0 );
X}
X
Xcode_int sorttab[1L<<BITS];	/* sorted pointers into htab */
X
Xdump_tab()	/* dump string table */
X{
X    register int i, first;
X    register ent;
X#define STACK_SIZE	15000
X    int stack_top = STACK_SIZE;
X    register c;
X
X    if(do_decomp == 0) {	/* compressing */
X	register int flag = 1;
X
X	for(i=0; i<hsize; i++) {	/* build sort pointers */
X		if((long)htabof(i) >= 0) {
X			sorttab[codetabof(i)] = i;
X		}
X	}
X	first = block_compress ? FIRST : 256;
X	for(i = first; i < free_ent; i++) {
X		(void)fprintf(stderr, "%5d: \"", i);
X		de_stack[--stack_top] = '\n';
X		de_stack[--stack_top] = '"';
X		stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff, 
X                                     stack_top);
X		for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
X		    ent > 256;
X		    ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
X			stack_top = in_stack(htabof(sorttab[ent]) >> maxbits,
X						stack_top);
X		}
X		stack_top = in_stack(ent, stack_top);
X		(void)fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
X	   	stack_top = STACK_SIZE;
X	}
X   } else if(!debug) {	/* decompressing */
X
X       for ( i = 0; i < free_ent; i++ ) {
X	   ent = i;
X	   c = tab_suffixof(ent);
X	   if ( isascii(c) && isprint(c) )
X	       (void)fprintf( stderr, "%5d: %5d/'%c'  \"",
X			   ent, tab_prefixof(ent), c );
X	   else
X	       (void)fprintf( stderr, "%5d: %5d/\\%03o \"",
X			   ent, tab_prefixof(ent), c );
X	   de_stack[--stack_top] = '\n';
X	   de_stack[--stack_top] = '"';
X	   for ( ; ent != NULL;
X		   ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
X	       stack_top = in_stack(tab_suffixof(ent), stack_top);
X	   }
X	   (void)fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
X	   stack_top = STACK_SIZE;
X       }
X    }
X}
X
Xint
Xin_stack(c, stack_top)
X	register c, stack_top;
X{
X	if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
X	    de_stack[--stack_top] = c;
X	} else {
X	    switch( c ) {
X	    case '\n': de_stack[--stack_top] = 'n'; break;
X	    case '\t': de_stack[--stack_top] = 't'; break;
X	    case '\b': de_stack[--stack_top] = 'b'; break;
X	    case '\f': de_stack[--stack_top] = 'f'; break;
X	    case '\r': de_stack[--stack_top] = 'r'; break;
X	    case '\\': de_stack[--stack_top] = '\\'; break;
X	    default:
X	 	de_stack[--stack_top] = '0' + c % 8;
X	 	de_stack[--stack_top] = '0' + (c / 8) % 8;
X	 	de_stack[--stack_top] = '0' + c / 64;
X	 	break;
X	    }
X	    de_stack[--stack_top] = '\\';
X	}
X	return stack_top;
X}
X#endif /* DEBUG */
X
Xwriteerr()
X{
X    perror ( ofname );
X    (void)unlink ( ofname );
X    exit ( 1 );
X}
X
X/*
X * This routine returns 1 if we are running in the foreground and stderr
X * is a tty.
X */
Xforeground()
X{
X	if(bgnd_flag) {	/* background? */
X		return(0);
X	} else {			/* foreground */
X		if(isatty(2)) {		/* and stderr is a tty */
X			return(1);
X		} else {
X			return(0);
X		}
X	}
X}
X
Xonintr ( )
X{
X    if (oktozap) (void)unlink ( ofname );
X    exit ( 1 );
X}
X
Xoops ( )	/* wild pointer -- assume bad input */
X{
X    if ( do_decomp == 1 ) 
X    	(void)fprintf ( stderr, "uncompress: corrupt input\n" );
X    if (oktozap) (void)unlink ( ofname );
X    exit ( 1 );
X}
X
Xcl_block ()		/* table clear for block compress */
X{
X    register long int rat;
X
X    checkpoint = in_count + CHECK_GAP;
X#ifdef DEBUG
X	if ( debug ) {
X    		(void)fprintf ( stderr, "count: %ld, ratio: ", in_count );
X     		prratio ( stderr, in_count, bytes_out );
X		(void)fprintf ( stderr, "\n");
X	}
X#endif /* DEBUG */
X
X    if(in_count > 0x007fffff) {	/* shift will overflow */
X	rat = bytes_out >> 8;
X	if(rat == 0) {		/* Don't divide by zero */
X	    rat = 0x7fffffff;
X	} else {
X	    rat = in_count / rat;
X	}
X    } else {
X	rat = (in_count << 8) / bytes_out;	/* 8 fractional bits */
X    }
X    if ( rat > ratio ) {
X	ratio = rat;
X    } else {
X	ratio = 0;
X#ifdef DEBUG
X	if(verbose)
X		dump_tab();	/* dump string table */
X#endif
X 	cl_hash ( (count_int) hsize );
X	free_ent = FIRST;
X	clear_flg = 1;
X	output ( (code_int) CLEAR );
X#ifdef DEBUG
X	if(debug)
X    		(void)fprintf ( stderr, "clear\n" );
X#endif /* DEBUG */
X    }
X}
X
Xcl_hash(phsize)		/* reset code table */
X	register count_int phsize;
X{
X#ifndef XENIX_16	/* Normal machine */
X	register count_int *htab_p = htab+phsize;
X#else
X	register j;
X	register long k = phsize;
X	register count_int *htab_p;
X#endif
X	register long i;
X	register long m1 = -1;
X
X#ifdef XENIX_16
X    for(j=0; j<=8 && k>=0; j++,k-=8192) {
X	i = 8192;
X	if(k < 8192) {
X		i = k;
X	}
X	htab_p = &(htab[j][i]);
X	i -= 16;
X	if(i > 0) {
X#else
X	i = phsize - 16;
X#endif
X 	do {				/* might use Sys V memset(3) here */
X		*(htab_p-16) = m1;
X		*(htab_p-15) = m1;
X		*(htab_p-14) = m1;
X		*(htab_p-13) = m1;
X		*(htab_p-12) = m1;
X		*(htab_p-11) = m1;
X		*(htab_p-10) = m1;
X		*(htab_p-9) = m1;
X		*(htab_p-8) = m1;
X		*(htab_p-7) = m1;
X		*(htab_p-6) = m1;
X		*(htab_p-5) = m1;
X		*(htab_p-4) = m1;
X		*(htab_p-3) = m1;
X		*(htab_p-2) = m1;
X		*(htab_p-1) = m1;
X		htab_p -= 16;
X	} while ((i -= 16) >= 0);
X#ifdef XENIX_16
X	}
X    }
X#endif
X    	for ( i += 16; i > 0; i-- )
X		*--htab_p = m1;
X}
X
Xprratio(stream, num, den)
XFILE *stream;
Xlong int num, den;
X{
X	register int q;			/* Doesn't need to be long */
X
X	if(num > 214748L) {		/* 2147483647/10000 */
X		q = num / (den / 10000L);
X	} else {
X		q = 10000L * num / den;		/* Long calculations, though */
X	}
X	if (q < 0) {
X		(void)putc('-', stream);
X		q = -q;
X	}
X	(void)fprintf(stream, "%d.%02d%%", q / 100, q % 100);
X}
X
END_OF_rnews.c
if test 34307 -ne `wc -c <rnews.c`; then
    echo shar: \"rnews.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f relaynews.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"relaynews.c\"
else
echo shar: Extracting \"relaynews.c\" \(791 characters\)
sed "s/^X//" >relaynews.c <<'END_OF_relaynews.c'
X
X/* 
X
X   A secure version of relaynews.  Move relaynews to relaynews.real and
X   install this.  Make both root owned and make this one suid. 
X
X*/
X
X#include <stdio.h>
X
X#define PROGRAM 	"/usr/lib/newsbin/relay/relaynews.real"
X#define NEWS_UID 	10   /* news uid */
X#define NEWS_GROUP 	10   /* news gid */
X
Xextern char **environ;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X
X	/* get rid of our suid root status completely */
X	if (setgid(NEWS_GROUP) || setuid(NEWS_UID)) {
X           fprintf(stderr,"can't set uid or gid\n");
X        }
X
X	/* replace environment with a clean one */
X        environ[0] = "IFS= \t\n";
X        environ[1] = "PATH=/bin:/usr/bin";
X        environ[2] = 0;
X
X	(void) umask(022);
X
X	execv(PROGRAM,argv);
X	fprintf(stderr,"Can't exec %s\n",PROGRAM);
X	return 1;
X
X} /* main() */
X
END_OF_relaynews.c
if test 791 -ne `wc -c <relaynews.c`; then
    echo shar: \"relaynews.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f spacefor.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"spacefor.c\"
else
echo shar: Extracting \"spacefor.c\" \(2834 characters\)
sed "s/^X//" >spacefor.c <<'END_OF_spacefor.c'
X
X/*
X  Spacefor.c V1.0
X
X  Replacement for spacefor (shell script) in cnews.
X  Change the values below as appropriate.
X
X  Denny Page	July 25, 1989  (denny@mcmi.uucp)
X
X  BSD added by Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us)
X
X*/
X
X#define HAVE_STATFS	/* If you have statfs() syscall */
X/* #define BSD		/* define on bsd sites */
X#define BLOCKSIZE 512   /* try 512 for Sys V and 1024 for bsd */
X
X/* Make these the mount points */
X
X#define DIR_INCOMING	"/usr/spool/news/in.coming"
X#define DIR_NEWSARTS	"/usr/spool/news"
X#define DIR_NEWSCTL	"/usr/lib/news"
X#define DIR_OUTGOING	"/usr/spool/uucp"
X#define DIR_ARCHIVE	"/usr/spool/news"
X
X#define MIN_INCOMING	5000
X#define MIN_NEWSARTS	5000	
X#define MIN_NEWSCTL	3000
X#define MIN_OUTGOING	10000
X#define MIN_ARCHIVE	1000
X
X/***************************************************************************/
X
X#include	<sys/types.h>
X#include	<stdio.h>
X
X#ifndef BSD
X#ifdef HAVE_STATFS
X#include <sys/statfs.h>
X#define FREEBLOCKS statfsb.f_bfree
X#define FREENODES statfsb.f_ffree
Xstruct statfs statfsb;
X#else /* HAVE_STATFS */
X#include <sys/stat.h>
X#include <ustat.h>
X#define FREEBLOCKS ustatb.f_tfree
X#define FREENODES ustatb.f_tinode
Xstruct stat statb;
Xstruct ustat ustatb;
X#endif /* HAVE_STATFS */
X#else
X#define HAVE_STATFS
X#include <sys/vfs.h>
Xstruct statfs statfsb;
X#define FREEBLOCKS statfsb.f_bavail
X#define FREENODES statfsb.f_ffree
X#endif
X
X#endif
X
Xmain(argc, argv)
X    int argc;
X    char **argv;
X{
X    int size, minblocks, available;
X    char *dirname;
X
X    if (argc < 3) {
X	fprintf(stderr, "usage: %s size place\n", argv[0]);
X	exit(2);
X    }
X
X    if ((size = atoi(argv[1])) == 0) {
X	printf("10000\n");
X	exit(0);
X    }
X
X    if (! strcmp (argv[2], "incoming")) {
X	dirname = DIR_INCOMING;
X	minblocks = MIN_INCOMING;
X    }
X    else if (! strcmp (argv[2], "articles")) {
X	dirname = DIR_NEWSARTS;
X	minblocks = MIN_NEWSARTS;
X    }
X    else if (! strcmp (argv[2], "control")) {
X	dirname = DIR_NEWSCTL;
X	minblocks = MIN_NEWSCTL;
X    }
X    else if (! strcmp (argv[2], "outbound")) {
X	dirname = DIR_OUTGOING;
X	minblocks = MIN_OUTGOING;
X    }
X    else if (! strcmp (argv[2], "archive")) {
X	dirname = DIR_ARCHIVE;
X	minblocks = MIN_ARCHIVE;
X    }
X    else {
X	fprintf(stderr, "%s: bad argument type `%s'\n",
X		       argv[0], argv[2]);
X	exit(2);
X    }
X
X
X#ifdef HAVE_STATFS
X    if (statfs(dirname, &statfsb, sizeof(statfsb), 0) != 0) {
X	perror("statfs failed");
X	exit(1);
X    }
X#else /* HAVE_STATFS */
X    if (stat(dirname, &statb) != 0) {
X	perror("stat failed");
X	exit(1);
X    }
X    if (ustat(statb.st_dev, &ustatb) != 0) {
X	perror("ustat failed");
X	exit(1);
X    }
X#endif /* HAVE_STATFS */
X
X    available = ((FREEBLOCKS - minblocks) * BLOCKSIZE) / size;
X
X    if (available <= 0 || FREENODES == 0)
X	available = 0;
X
X    if (available > 10000)
X       available = 10000;
X
X    printf("%d\n", available);
X    exit(0);
X}
X
X
END_OF_spacefor.c
if test 2834 -ne `wc -c <spacefor.c`; then
    echo shar: \"spacefor.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
-- 
Branch Technology  <zeeff@b-tech.ann-arbor.mi.us>