home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-31 | 52.8 KB | 1,650 lines |
- Newsgroups: comp.sources.misc
- From: lmjm@doc.ic.ac.uk (Lee M J McLoughlin)
- Subject: v37i098: buffer1.16 - Very Fast Tape Writer, v1.16, Part01/01
- Message-ID: <1993May31.030804.15289@sparky.imd.sterling.com>
- X-Md4-Signature: bce0a2048a5c90b7a0df354b44e6f7b0
- Sender: kent@sparky.imd.sterling.com (Kent Landfield)
- Organization: Sterling Software
- Date: Mon, 31 May 1993 03:08:04 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: lmjm@doc.ic.ac.uk (Lee M J McLoughlin)
- Posting-number: Volume 37, Issue 98
- Archive-name: buffer1.16/part01
- Environment: SUNOS, SYSV, SYSVR4, HPUX, Shared Memory, Semaphores
- Supersedes: buffer: Volume 37, Issue 53
-
- This is version 1.16 of buffer. This is a program designed to speed up
- writing tapes on remote tape drives. Requirements are shared memory and
- locks which normally means that these are supported in your kernel.
-
- Buffer has been tested under SunOS 4.0.*, SunOS 4.1.*, Solarix, HP-UX 7.0,
- and Gould UTX 2.1A (sv universe).
-
- The program splits itself into two processes. The first process reads
- (and reblocks) from stdin into a shared memory buffer. The second
- writes from the shared memory buffer to stdout. Doing it this way
- means that the writing side effectly sits in a tight write loop and
- doesn't have to wait for input. Similarly for the input side. It is
- this waiting that slows down other reblocking processes, like dd.
-
- I run an archive and need to write large chunks out to tape regularly
- with an ethernet in the way. Using 'buffer' in a command like:
-
- tar cvf - stuff | rsh somebox "buffer > /dev/rst8"
-
- is a factor of 5 faster than the best alternative, gnu tar with its
- remote tape option:
-
- tar cvf somebox:/dev/rst8 stuff
-
- We have been using buffer here at Imperial for a couple of years now
- for writing tar tapes and the main system dumps.
-
- Thanks to Kevin Twidle <kpt@doc.ic.ac.uk> for the -p and -B code.
-
- INSTALLATION:
- Check that your kernel supports shared memory and semaphores.
- A quick way to check is to build buffer and run it.
- If it says "couldn't create shared memory segment" you probably
- need to reconfigure and rebuild your kernel.
-
- To install edit the Makefile and tailor the variables to
- your local systems. Then type make.
-
- DISCLAIMER:
- This package is under the GNU GENERAL PUBLIC LICENSE!
- In addtion under NO circumstances can I, or Imperial College,
- be held liable for any event caused by the running or storing
- of this program or its documentation.
-
- Lee McLoughlin. Phone: +44 71 589 5111 X 5085
- Dept of Computing, Imperial College, Fax: +44 71 581 8024
- 180 Queens Gate, London, SW7 2BZ, UK. Email: L.McLoughlin@doc.ic.ac.uk
- -------------------------------------------------------------------------
- #! /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: README buffer.man Makefile buffer.c sem.c COPYING
- # Wrapped by lmjm@kea.doc.ic.ac.uk on Fri May 28 11:55:06 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(1979 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XThis is a program designed to speed up writing tapes on remote tape
- Xdrives. Requirements are shared memory and locks which normally
- Xmeans that these are supported in your kernel.
- X
- XBuffer has been tested under SunOS 4.0.*, SunOS 4.1.*, Solarix, HP-UX 7.0,
- Xand Gould UTX 2.1A (sv universe).
- X
- XThe program splits itself into two processes. The first process reads
- X(and reblocks) from stdin into a shared memory buffer. The second
- Xwrites from the shared memory buffer to stdout. Doing it this way
- Xmeans that the writing side effectly sits in a tight write loop and
- Xdoesn't have to wait for input. Similarly for the input side. It is
- Xthis waiting that slows down other reblocking processes, like dd.
- X
- XI run an archive and need to write large chunks out to tape regularly
- Xwith an ethernet in the way. Using 'buffer' in a command like:
- X
- X tar cvf - stuff | rsh somebox "buffer > /dev/rst8"
- X
- Xis a factor of 5 faster than the best alternative, gnu tar with its
- Xremote tape option:
- X
- X tar cvf somebox:/dev/rst8 stuff
- X
- XWe have been using buffer here at Imperial for a couple of years now
- Xfor writing tar tapes and the main system dumps.
- X
- XThanks to Kevin Twidle <kpt@doc.ic.ac.uk> for the -p and -B code.
- X
- XINSTALLATION:
- X Check that your kernel supports shared memory and semaphores.
- X A quick way to check is to build buffer and run it.
- X If it says "couldn't create shared memory segment" you probably
- X need to reconfigure and rebuild your kernel.
- X
- X To install edit the Makefile and tailor the variables to
- X your local systems. Then type make.
- X
- XDISCLAIMER:
- X This package is under the GNU GENERAL PUBLIC LICENSE!
- X In addtion under NO circumstances can I, or Imperial College,
- X be held liable for any event caused by the running or storing
- X of this program or its documentation.
- X
- XLee McLoughlin. Phone: +44 71 589 5111 X 5085
- XDept of Computing, Imperial College, Fax: +44 71 581 8024
- X180 Queens Gate, London, SW7 2BZ, UK. Email: L.McLoughlin@doc.ic.ac.uk
- END_OF_FILE
- if test 1979 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'buffer.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'buffer.man'\"
- else
- echo shar: Extracting \"'buffer.man'\" \(5087 characters\)
- sed "s/^X//" >'buffer.man' <<'END_OF_FILE'
- X.\" Buffer. Very fast reblocking filter speedy writing of tapes.
- X.\" Copyright (C) 1990,1991 Lee McLoughlin
- X.\"
- X.\" This program is free software; you can redistribute it and/or modify
- X.\" it under the terms of the GNU General Public License as published by
- X.\" the Free Software Foundation; either version 1, or (at your option)
- X.\" any later version.
- X.\"
- X.\" This program is distributed in the hope that it will be useful,
- X.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
- X.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X.\" GNU General Public License for more details.
- X.\"
- X.\" You should have received a copy of the GNU General Public License
- X.\" along with this program; if not, write to the Free Software
- X.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X.\"
- X.\" Lee McLoughlin.
- X.\" Dept of Computing, Imperial College,
- X.\" 180 Queens Gate, London, SW7 2BZ, UK.
- X.\"
- X.\" Email: L.McLoughlin@doc.ic.ac.uk
- X.TH BUFFER 1 "14 May 1990"
- X.SH NAME
- Xbuffer \- very fast reblocking program
- X.SH SYNTAX
- X.B buffer
- X[\fB\-S size\fP] [\fB\-b blocks\fP] [\fB\-s size\fP] [\fB\-m size\fP]
- X[\fB\-p percentage\fP] [\fB\-u microseconds\fP] [\fB-B\fR] [\fB-t\fR]
- X[\fB-Z\fR] [\fB-i filename\fR] [\fB-o filename\fR]
- X.SH OPTIONS
- X.TP 5
- X.B \-i filename
- XUse the given file as the input file. The default is stdin.
- X.TP
- X.B \-o filename
- XUse the given file as the output file. The default is stdout.
- X.TP
- X.B \-S size
- XAfter every chunk this size has been writen print out how much been writen so far.
- XBy default this is not set.
- X.TP
- X.B \-s size
- XSize in bytes of each block. The default blocksize is 10k to match
- Xthe normal output of the
- X.I tar(1)
- Xprogram.
- X.TP
- X.B \-z size
- XCombines the
- X.B \-S
- Xand
- X.B \-s
- Xflags.
- X.TP
- X.B \-b blocks
- XNumber of blocks to allocate to shared memory circular buffer.
- XDefaults to the number required to fill up the shared memory requested.
- X.TP
- X.B \-m size
- XMaximum size of the shared memory chunk to allocate for the circular
- Xqueue. Defaults to one megabyte.
- X.TP
- X.B \-p percentage
- XOnly start a write when the given percentage of the internal queue is
- Xfull. A percentage around 75 often proves best. Defaults to zero.
- X.TP
- X.B \-u microseconds
- XAfter every write pause for this many microseconds. Defaults to zero.
- X(Suprisingly a small sleep, 100 usecs, after each write can greatly enhance
- Xthroughput on some drives.)
- X.TP
- X.B \-B
- XForce each block writen to be padded out to the blocksize. This is needed by some tape
- Xand cartridge drives. Defaults to unpadded. This only affects the
- Xlast block writen.
- X.TP
- X.B \-t
- XOn exiting print to stderr a brief message showing the total number of
- Xbytes written.
- X.TP
- X.B \-Z
- XIf reading/writing directly to a character device (like a tape drive)
- Xthen after each gigabyte perform an lseek to the start of the file.
- XUse this flag with extreme care. If can only be used on devices where
- Xan lseek does not rewind the tape but does reset the kernels position
- Xflags. It is used to allow more than 2 gigabytes to be written.
- X.PP
- XSizes are a number with an optional trailing character. A 'b'
- Xmultiplies the size by 512, a 'k' by 1024 and an 'm' by a meg.
- X.SH DESCRIPTION
- X.I Buffer
- Xreads from standard input reblocking to the given blocksize and writes
- Xeach block to standard output.
- X.PP
- XInternally
- X.I buffer
- Xis a pair of processes communicating via a large circular queue held
- Xin shared memory. The reader process only has to block when the queue
- Xis full and the writer process when the queue is empty.
- X.I Buffer
- Xis designed to try and keep the writer side continuously busy so that
- Xit can stream when writing to tape drives. When used to write tapes
- Xwith an intervening network
- X.I buffer
- Xcan result in a considerable increase in throughput.
- X.PP
- XThe default settings for
- X.I buffer
- Xare normally good enough. If you are a heavy tape user then it is
- Xworth your while trying out various different combinations of options.
- XIn particular running a
- X.I buffer
- Xat both ends of the pipe can provide a substantial increase (see last
- Xexample below).
- X.SH EXAMPLES
- X.br
- X$ \fBbuffer < /etc/termcap > /dev/rst8\fP
- X.br
- X.sp
- X$ \fBtar cf - . | rsh somehost 'buffer > /dev/rst8'\fP
- X.br
- X.sp
- X$ \fBdump fu - | rsh somehost 'buffer -s 16k > /dev/nrst8'\fP
- X.br
- X$ \fBtar cf - . | buffer |
- X.br
- X\ \ \ rsh somehost 'buffer -S 500K -p 75 > /dev/rst0'\fP
- X.SH BUGS
- XInternally, for printing purposes, buffer counts in terms of the
- Xnumber of kilobytes output. If the blocksize you use is not a whole
- Xnumber of kilobytes then the numbers printed will be inaccurate.
- X
- X.SH THANKS
- XThanks to Kevin Twidle <kpt@doc.ic.ac.uk> for a lot of early
- Xsuggestions and patches to make it work with non-tar/dump tapes to
- Xexabyte drives.
- X
- XThanks to Andi Karrer <karrer@bernina.ethz.ch>, Rumi Zahir
- X<rumi@iis.ethz.ch> and Christoph Wicki <wicki@iis.ethz.ch> for patches
- Xto make buffer work when trying to write single tape files of greater
- Xthan 2 gigabytes.
- X
- X.SH COPYRIGHT
- X.if n Copyright (C) 1990, 1991 by Lee McLoughlin.
- X.if t Copyright \(co 1990, 1991 by Lee McLoughlin.
- X.SH SEE ALSO
- Xdd(1), tar(1), rsh(1)
- END_OF_FILE
- if test 5087 -ne `wc -c <'buffer.man'`; then
- echo shar: \"'buffer.man'\" unpacked with wrong size!
- fi
- # end of 'buffer.man'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(875 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# Make the buffer program
- X
- X# Add -DSYS5 for A System 5 (USG) version of unix
- X# You should also add -DSYS5 for Ultrix, AIX, and Solarix.
- X# Add -DDEF_SHMEM=n if you can only have n bytes of shared memory
- X# (eg: -DDEF_SHMEM=524288 if you can only have half a meg.)
- XCFLAGS=
- X
- X# Where to install buffer and its manual pages
- XINSTBIN=/usr/local/bin
- XINSTMAN=/usr/man/manl
- X# The manual page section (normally l or 1)
- XS=l
- X
- XRM=/bin/rm
- XALL=README buffer.man Makefile buffer.c sem.c COPYING
- X
- Xall: buffer
- X
- Xbuffer: buffer.o sem.o
- X $(CC) -o buffer $(CFLAGS) buffer.o sem.o
- X
- Xclean:
- X $(RM) -f *.o core buffer .merrs
- X
- Xinstall: buffer
- X cp buffer $(INSTBIN)
- X chmod 111 $(INSTBIN)/buffer
- X cp buffer.man $(INSTMAN)/buffer.$S
- X chmod 444 $(INSTMAN)/buffer.$S
- X
- Xbuffer.tar: $(ALL)
- X $(RM) -f buffer.tar
- X tar cvf buffer.tar $(ALL)
- X
- Xbuffer.shar: $(ALL)
- X $(RM) -f buffer.shar
- X shar $(ALL) > buffer.shar
- END_OF_FILE
- if test 875 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'buffer.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'buffer.c'\"
- else
- echo shar: Extracting \"'buffer.c'\" \(18515 characters\)
- sed "s/^X//" >'buffer.c' <<'END_OF_FILE'
- X/*
- X Buffer. Very fast reblocking filter speedy writing of tapes.
- X Copyright (C) 1990,1991 Lee McLoughlin
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 1, or (at your option)
- X any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- X Lee McLoughlin.
- X Dept of Computing, Imperial College,
- X 180 Queens Gate, London, SW7 2BZ, UK.
- X
- X Email: L.McLoughlin@doc.ic.ac.uk
- X*/
- X
- X/* This is a reblocking process, designed to try and read from stdin
- X * and write to stdout - but to always try and keep the writing side
- X * busy. It is meant to try and stream tape writes.
- X *
- X * This program runs in two parts. The reader and the writer. They
- X * communicate using shared memory with semaphores locking the access.
- X * The shared memory implements a circular list of blocks of data.
- X *
- X * L.McLoughlin, Imperial College, 1990
- X *
- X * $Log: buffer.c,v $
- X * Revision 1.16 1993/05/28 10:47:32 lmjm
- X * Debug shutdown sequence.
- X *
- X * Revision 1.15 1992/11/23 23:32:58 lmjm
- X * Oops! This should be outside the ifdef
- X *
- X * Revision 1.14 1992/11/23 23:29:58 lmjm
- X * allow MAX_BLOCKSIZE and DEF_SHMEM to be configured
- X *
- X * Revision 1.13 1992/11/23 23:22:29 lmjm
- X * Printf's use %lu where appropriate.
- X *
- X * Revision 1.12 1992/11/23 23:17:55 lmjm
- X * Got rid of floats and use Kbyte counters instead.
- X *
- X * Revision 1.11 1992/11/03 23:11:51 lmjm
- X * Forgot Andi Karrer on the patch list.
- X *
- X * Revision 1.10 1992/11/03 22:58:41 lmjm
- X * Cleaned up the debugging prints.
- X *
- X * Revision 1.9 1992/11/03 22:53:00 lmjm
- X * Corrected stdin, stout and showevery use.
- X *
- X * Revision 1.8 1992/11/03 22:41:34 lmjm
- X * Added 2Gig patches from:
- X * Andi Karrer <karrer@bernina.ethz.ch>
- X * Rumi Zahir <rumi@iis.ethz.ch>
- X * Christoph Wicki <wicki@iis.ethz.ch>
- X *
- X * Revision 1.7 1992/07/23 20:42:03 lmjm
- X * Added 't' option to print total writen at end.
- X *
- X * Revision 1.6 1992/04/07 19:57:30 lmjm
- X * Added Kevins -B and -p options.
- X * Turn off buffering to make -S output appear ok.
- X * Added GPL.
- X *
- X * Revision 1.5 90/07/22 18:46:38 lmjm
- X * Added system 5 support.
- X *
- X * Revision 1.4 90/07/22 18:29:48 lmjm
- X * Updated arg handling to be more consistent.
- X * Make sofar printing size an option.
- X *
- X * Revision 1.3 90/05/15 23:27:46 lmjm
- X * Added -S option (show how much has been writen).
- X * Added -m option to specify how much shared memory to grab.
- X * Now tries to fill this with blocks.
- X * reader waits for writer to terminate and then frees the shared mem and sems.
- X *
- X * Revision 1.2 90/01/20 21:37:59 lmjm
- X * Reset default number of blocks and blocksize for best thruput of
- X * standard tar 10K blocks.
- X * Allow number of blocks to be changed.
- X * Don't need a hole in the circular queue since the semaphores prevent block
- X * clash.
- X *
- X * Revision 1.1 90/01/17 11:30:23 lmjm
- X * Initial revision
- X *
- X */
- X#include <unistd.h>
- X#include <stdio.h>
- X#include <signal.h>
- X#include <fcntl.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/ipc.h>
- X#include <sys/shm.h>
- X#include <sys/sem.h>
- X
- X#ifndef lint
- Xstatic char *rcsid = "$Header: /a/swan/home/swan/staff/csg/lmjm/src/buffer/RCS/buffer.c,v 1.16 1993/05/28 10:47:32 lmjm Exp lmjm $";
- X#endif
- X
- Xextern char *shmat();
- X
- X/* General macros */
- X#define TRUE 1
- X#define FALSE 0
- X#define K *1024
- X
- X/* Some forward declarations */
- Xvoid byee();
- Xvoid start_reader_and_writer();
- X
- X/* When showing print a note every this many bytes writen */
- Xint showevery = 0;
- X#define PRINT_EVERY 10 K
- X
- X/* Pause after every write */
- Xunsigned write_pause;
- X
- X/* This is the inter-process buffer - it implements a circular list
- X * of blocks. */
- X
- X#ifndef MAX_BLOCKSIZE
- X#define MAX_BLOCKSIZE (512 K)
- X#endif
- X#define DEF_BLOCKSIZE (10 K)
- Xint blocksize = DEF_BLOCKSIZE;
- X
- X/* Numbers of blocks in the queue.
- X */
- X#define MAX_BLOCKS 2048
- Xint blocks = 1;
- X/* Circular increment of a buffer index */
- X#define INC(i) (((i)+1) == blocks ? 0 : ((i)+1))
- X
- X/* Max amount of shared memory you can allocate - can't see a way to look
- X * this up.
- X */
- X#ifndef DEF_SHMEM
- X#define DEF_SHMEM (1 K K)
- X#endif
- Xint max_shmem = DEF_SHMEM;
- X
- X/* Just a flag to show unfilled */
- X#define NONE (-1)
- X
- X/* the shared memory id of the buffer */
- Xint buffer_id = NONE;
- Xstruct block {
- X int bytes;
- X char *data;
- X} *curr_block;
- X
- X#define NO_BUFFER ((struct buffer *)-1)
- Xstruct buffer {
- X /* writer will hang trying to lock this till reader fills in a block */
- X int blocks_used_lock;
- X /* reader will hang trying to lock this till writer empties a block */
- X int blocks_free_lock;
- X
- X int next_block_in;
- X int next_block_out;
- X
- X struct block block[ MAX_BLOCKS ];
- X
- X /* These actual space for the blocks is here - the array extends
- X * pass 1 */
- X char data_space[ 1 ];
- X} *pbuffer = NO_BUFFER;
- Xint buffer_size;
- X
- Xint fdin = 0;
- Xint fdout = 1;
- Xint in_ISCHR = 0;
- Xint out_ISCHR = 0;
- Xint padblock = FALSE;
- Xint writer_pid = 0;
- Xint reader_pid = 0;
- Xint percent = 0;
- Xint debug = 0;
- Xint Zflag = 0;
- Xchar *progname = "buffer";
- X
- Xchar print_total = 0;
- X/* Number of K output */
- Xunsigned long outk = 0;
- X
- Xmain( argc, argv )
- X int argc;
- X char **argv;
- X{
- X parse_args( argc, argv );
- X
- X set_handlers();
- X
- X buffer_allocate();
- X
- X start_reader_and_writer();
- X
- X byee( 0 );
- X}
- X
- Xparse_args( argc, argv )
- X int argc;
- X char **argv;
- X{
- X int c;
- X int iflag = 0;
- X int oflag = 0;
- X int zflag = 0;
- X extern char *optarg;
- X extern int optind;
- X char blocks_given = FALSE;
- X struct stat buf;
- X
- X
- X while( (c = getopt( argc, argv, "BS:Zdm:s:b:p:u:ti:o:z:" )) != -1 ){
- X switch( c ){
- X case 't': /* Print to stderr the total no of bytes writen */
- X print_total++;
- X break;
- X case 'u': /* pause after write for given microseconds */
- X write_pause = atoi( optarg );
- X break;
- X case 'B': /* Pad last block */
- X padblock = TRUE;
- X break;
- X case 'Z': /* Zero by lseek on the tape device */
- X Zflag = TRUE;
- X break;
- X case 'i': /* Input file */
- X iflag++;
- X if( iflag > 1 ){
- X fprintf( stderr, "buffer: -i given twice\n" );
- X byee( -1 );
- X }
- X if( (fdin = open( optarg, O_RDONLY )) < 0 ){
- X perror( "buffer: cannot open input file" );
- X fprintf( stderr, "filename: %s\n", optarg );
- X byee ( -1 );
- X }
- X break;
- X case 'o': /* Output file */
- X oflag++;
- X if( oflag > 1 ){
- X fprintf( stderr, "buffer: -o given twice\n" );
- X byee( -1 );
- X }
- X if( (fdout = open( optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666 )) < 0 ){
- X perror( "buffer: cannot open output file" );
- X fprintf( stderr, "filename: %s\n", optarg );
- X byee ( -1 );
- X }
- X break;
- X case 'S':
- X /* Show every once in a while how much is printed */
- X showevery = do_size( optarg );
- X if( showevery <= 0 )
- X showevery = PRINT_EVERY;
- X break;
- X case 'd': /* debug */
- X debug++;
- X if( debug == 1 ){
- X setbuf( stdout, NULL );
- X setbuf( stderr, NULL );
- X fprintf( stderr, "debugging turned on\n" );
- X }
- X break;
- X case 'm':
- X /* Max size of shared memory lump */
- X max_shmem = do_size( optarg );
- X
- X if( max_shmem < (sizeof( struct buffer ) + (blocksize * blocks)) ){
- X fprintf( stderr, "max_shmem %d too low\n", max_shmem );
- X byee( -1 );
- X }
- X break;
- X case 'b':
- X /* Number of blocks */
- X blocks_given = TRUE;
- X blocks = atoi( optarg );
- X if( (blocks <= 0) || (MAX_BLOCKS < blocks) ){
- X fprintf( stderr, "blocks %d out of range\n", blocks );
- X byee( -1 );
- X }
- X break;
- X case 'p': /* percent to wait before dumping */
- X percent = atoi( optarg );
- X
- X if( (percent < 0) || (100 < percent) ){
- X fprintf( stderr, "percent %d out of range\n", percent );
- X byee( -1 );
- X }
- X if( debug )
- X fprintf( stderr, "percent set to %d\n", percent );
- X break;
- X case 'z':
- X zflag++;
- X /* FALL THRU */
- X case 's': /* Size of a block */
- X blocksize = do_size( optarg );
- X
- X if( (blocksize <= 0) || (MAX_BLOCKSIZE < blocksize) ){
- X fprintf( stderr, "blocksize %d out of range\n", blocksize );
- X byee( -1 );
- X }
- X break;
- X default:
- X fprintf( stderr, "Usage: %s [-B] [-t] [-S size] [-m memsize] [-b blocks] [-p percent] [-s blocksize] [-u pause] [-i infile] [-o outfile] [-z size]\n",
- X progname );
- X fprintf( stderr, "-B = blocked device - pad out last block\n" );
- X fprintf( stderr, "-t = show total amount writen at end\n" );
- X fprintf( stderr, "-S size = show amount writen every size bytes\n" );
- X fprintf( stderr, "-m size = size of shared mem chunk to grab\n" );
- X fprintf( stderr, "-b num = number of blocks in queue\n" );
- X fprintf( stderr, "-p percent = don't start writing until percent blocks filled\n" );
- X fprintf( stderr, "-s size = size of a block\n" );
- X fprintf( stderr, "-u usecs = microseconds to sleep after each write\n" );
- X fprintf( stderr, "-i infile = file to read from\n" );
- X fprintf( stderr, "-o outfile = file to write to\n" );
- X fprintf( stderr, "-z size = combined -S/-s flag\n" );
- X byee( -1 );
- X }
- X }
- X
- X if (zflag) showevery = blocksize;
- X
- X /* If -b was not given try and work out the max buffer size */
- X if( !blocks_given ){
- X blocks = (max_shmem - sizeof( struct buffer )) / blocksize;
- X if( blocks <= 0 ){
- X fprintf( stderr, "Cannot handle blocks that big, aborting!\n" );
- X byee( -1 );
- X }
- X if( MAX_BLOCKS < blocks ){
- X fprintf( stderr, "Cannot handle that many blocks, aborting!\n" );
- X byee( -1 );
- X }
- X }
- X
- X /* check if fdin or fdout are character special files */
- X if( fstat( fdin, &buf ) != 0 ){
- X perror( "buffer: can't stat input file" );
- X byee( -1 );
- X }
- X in_ISCHR = S_ISCHR( buf.st_mode );
- X if( fstat( fdout, &buf ) != 0 ){
- X perror( "buffer: can't stat output file" );
- X byee( -1 );
- X }
- X out_ISCHR = S_ISCHR( buf.st_mode );
- X}
- X
- X/* The interrupt handler */
- Xshutdown()
- X{
- X static int shutting;
- X if( shutting ){
- X if( debug )
- X fprintf( stderr, "%s: ALREADY SHUTTING!\n", writer_pid ? "R" : "W" );
- X return;
- X }
- X shutting = 1;
- X if( debug )
- X fprintf( stderr, "%s: shutdown on signal\n", writer_pid ? "R" : "W" );
- X
- X byee( -1 );
- X}
- X
- Xset_handlers()
- X{
- X if( debug )
- X fprintf( stderr, "%s: setting handlers\n", writer_pid ? "R" : "W" );
- X
- X signal( SIGHUP, shutdown );
- X signal( SIGINT, shutdown );
- X signal( SIGQUIT, shutdown );
- X signal( SIGTERM, shutdown );
- X#ifdef SIGCHLD
- X signal( SIGCHLD, shutdown );
- X#endif
- X#ifdef SIGCLD
- X signal( SIGCLD, shutdown );
- X#endif
- X}
- X
- Xbuffer_allocate()
- X{
- X int i;
- X
- X /* Allow for the data space */
- X buffer_size = sizeof( struct buffer ) +
- X ((blocks * blocksize) - sizeof( char ));
- X
- X /* Create the space for the buffer */
- X buffer_id = shmget( IPC_PRIVATE,
- X buffer_size,
- X IPC_CREAT|S_IREAD|S_IWRITE );
- X if( buffer_id < 0 ){
- X perror( "buffer: couldn't create shared memory segment" );
- X byee( -1 );
- X }
- X
- X get_buffer();
- X
- X if( debug )
- X fprintf( stderr, "pbuffer is 0x%08x, buffer_size is %d [%d x %d]\n",
- X (char *)pbuffer, buffer_size, blocks, blocksize );
- X
- X#ifdef SYS5
- X memset( (char *)pbuffer, '\0', buffer_size );
- X#else
- X bzero( (char *)pbuffer, buffer_size );
- X#endif
- X pbuffer->blocks_used_lock = -1;
- X pbuffer->blocks_free_lock = -1;
- X
- X pbuffer->blocks_used_lock = new_sem();
- X /* Start it off locked - it is unlocked when a buffer gets filled in */
- X lock( pbuffer->blocks_used_lock );
- X
- X pbuffer->blocks_free_lock = new_sem();
- X /* start this off so lock() can be called on it for each block
- X * till all the blocks are used up */
- X sem_set( pbuffer->blocks_free_lock, blocks - 1 );
- X
- X /* Detattach the shared memory so the fork doesnt do anything odd */
- X shmdt( (char *)pbuffer );
- X pbuffer = NO_BUFFER;
- X}
- X
- Xbuffer_remove()
- X{
- X static char removing = FALSE;
- X int i;
- X
- X /* Avoid accidental recursion */
- X if( removing )
- X return;
- X removing = TRUE;
- X
- X /* Buffer not yet created */
- X if( buffer_id == NONE )
- X return;
- X
- X /* There should be a buffer so this must be after its detached it
- X * but before the fork picks it up */
- X if( pbuffer == NO_BUFFER )
- X get_buffer();
- X
- X if( debug )
- X fprintf( stderr, "R: removing semaphores and buffer\n" );
- X remove_sem( pbuffer->blocks_used_lock );
- X remove_sem( pbuffer->blocks_free_lock );
- X
- X if( shmctl( buffer_id, IPC_RMID, (struct shmid_ds *)0 ) == -1 )
- X perror( "buffer: failed to remove shared memory buffer" );
- X}
- X
- Xget_buffer()
- X{
- X int b;
- X
- X /* Grab the buffer space */
- X pbuffer = (struct buffer *)shmat( buffer_id, (char *)0, 0 );
- X if( pbuffer == NO_BUFFER ){
- X perror( "buffer: failed to attach shared memory" );
- X byee( -1 );
- X }
- X
- X /* Setup the data space pointers */
- X for( b = 0; b < blocks; b++ )
- X pbuffer->block[ b ].data =
- X &pbuffer->data_space[ b * blocksize ];
- X
- X}
- X
- Xvoid
- Xstart_reader_and_writer()
- X{
- X int status, deadpid;
- X
- X fflush( stdout );
- X fflush( stderr );
- X
- X if( (writer_pid = fork()) == -1 ){
- X perror( "buffer: unable to fork" );
- X byee( -1 );
- X }
- X else if( writer_pid == 0 ){
- X reader_pid = getppid();
- X
- X /* Never trust fork() to propogate signals - reset them */
- X set_handlers();
- X
- X writer();
- X }
- X else {
- X reader();
- X
- X /* Now wait for the writer to finish */
- X while( ((deadpid = wait( &status )) != writer_pid) &&
- X deadpid != -1 )
- X ;
- X }
- X}
- X
- X/* Read from stdin into the buffer */
- Xreader()
- X{
- X if( debug )
- X fprintf( stderr, "R: Entering reader\n" );
- X
- X get_buffer();
- X
- X while( 1 ){
- X get_next_free_block();
- X if( ! fill_block() )
- X break;
- X }
- X
- X if( debug )
- X fprintf( stderr, "R: Exiting reader\n" );
- X}
- X
- Xget_next_free_block()
- X{
- X /* Maybe wait till there is room in the buffer */
- X lock( pbuffer->blocks_free_lock );
- X
- X curr_block = &pbuffer->block[ pbuffer->next_block_in ];
- X
- X pbuffer->next_block_in = INC( pbuffer->next_block_in );
- X}
- X
- Xfill_block()
- X{
- X int bytes;
- X char *start;
- X int toread;
- X static char eof_reached = 0;
- X
- X if( eof_reached ){
- X curr_block->bytes = 0;
- X unlock( pbuffer->blocks_used_lock );
- X return 0;
- X }
- X
- X start = curr_block->data;
- X toread = blocksize;
- X
- X /* Fill the block with input. This reblocks the input. */
- X while( toread != 0 && (bytes = read( fdin, start, toread )) > 0 ){
- X start += bytes;
- X toread -= bytes;
- X }
- X
- X if( bytes == 0 ){
- X eof_reached = 1;
- X }
- X
- X if( bytes < 0 ){
- X perror( "buffer: failed to read input" );
- X byee( -1 );
- X }
- X
- X /* number of bytes available. Zero will be taken as eof */
- X if( !padblock || toread == blocksize )
- X curr_block->bytes = blocksize - toread;
- X else {
- X if( toread ) bzero( start, toread );
- X curr_block->bytes = blocksize;
- X }
- X
- X if( debug > 1 )
- X fprintf( stderr, "R: got %d bytes\n", curr_block->bytes );
- X
- X unlock( pbuffer->blocks_used_lock );
- X
- X return curr_block->bytes;
- X}
- X
- X/* Write the buffer to stdout */
- Xwriter()
- X{
- X int filled = 0;
- X int maxfilled = (blocks * percent) / 100;
- X int first_block;
- X
- X if( debug )
- X fprintf( stderr, "\tW: Entering writer\n blocks = %d\n maxfilled = %d\n",
- X blocks,
- X maxfilled );
- X
- X get_buffer();
- X
- X while( 1 ){
- X if( !filled )
- X first_block = pbuffer->next_block_out;
- X get_next_filled_block();
- X if( !data_to_write() )
- X break;
- X
- X filled++;
- X if( debug > 1 )
- X fprintf( stderr, "W: filled = %d\n", filled );
- X if( filled >= maxfilled ){
- X if( debug > 1 )
- X fprintf( stderr, "W: writing\n" );
- X write_blocks_to_stdout( filled, first_block );
- X filled = 0;
- X }
- X }
- X
- X write_blocks_to_stdout( filled, first_block );
- X
- X if( showevery ){
- X pr_out();
- X }
- X
- X if( print_total ){
- X fprintf( stderr, "Kilobytes Out %lu\n", outk );
- X }
- X
- X if( debug )
- X fprintf( stderr, "\tW: Exiting writer\n" );
- X}
- X
- Xget_next_filled_block()
- X{
- X /* Hang till some data is available */
- X lock( pbuffer->blocks_used_lock );
- X
- X curr_block = &pbuffer->block[ pbuffer->next_block_out ];
- X
- X pbuffer->next_block_out = INC( pbuffer->next_block_out );
- X}
- X
- Xdata_to_write()
- X{
- X return curr_block->bytes;
- X}
- X
- Xwrite_blocks_to_stdout( filled, first_block )
- X int filled;
- X int first_block;
- X{
- X pbuffer->next_block_out = first_block;
- X
- X while( filled-- ){
- X curr_block = &pbuffer->block[ pbuffer->next_block_out ];
- X pbuffer->next_block_out = INC( pbuffer->next_block_out );
- X write_block_to_stdout();
- X }
- X}
- X
- Xwrite_block_to_stdout()
- X{
- X static unsigned long out = 0;
- X static unsigned long last_gb = 0;
- X static unsigned long next_k = 0;
- X int written;
- X
- X if( next_k == 0 && showevery ){
- X if( debug > 3 )
- X fprintf( stderr, "next_k = %lu showevery = %lu\n", next_k, showevery );
- X showevery = showevery / 1024;
- X next_k = showevery;
- X }
- X
- X if( (written = write( fdout, curr_block->data, curr_block->bytes )) != curr_block->bytes ){
- X perror( "buffer: write of data failed" );
- X fprintf( stderr, "bytes to write=%d, bytes written=%d, total written %10luK\n", curr_block->bytes, written, outk );
- X byee( -1 );
- X }
- X
- X if( write_pause ){
- X usleep( write_pause );
- X }
- X
- X out = curr_block->bytes / 1024;
- X outk += out;
- X last_gb += out;
- X
- X /*
- X * on character special devices (tapes), do an lseek() every 1 Gb,
- X * to overcome the 2Gb limit. This resets the file offset to
- X * zero, but -- at least on exabyte SCSI drives -- does not perform
- X * any actual action on the tape.
- X */
- X if( Zflag && last_gb >= 1 K K ){
- X last_gb = 0;
- X if( in_ISCHR )
- X (void) lseek( fdin, 0, SEEK_SET);
- X if( out_ISCHR )
- X (void) lseek( fdout, 0, SEEK_SET);
- X }
- X if( showevery ){
- X if( debug > 3 )
- X fprintf( stderr, "outk = %lu, next_k = %lu\n",
- X outk, next_k );
- X if( outk >= next_k ){
- X pr_out();
- X next_k += showevery;
- X }
- X }
- X
- X unlock( pbuffer->blocks_free_lock );
- X}
- X
- X
- Xvoid
- Xbyee( exit_val )
- X int exit_val;
- X{
- X /* Only the parent (reader) should zap the buffer */
- X if( writer_pid != 0 )
- X buffer_remove();
- X else if( showevery )
- X fprintf( stderr, "\n" );
- X exit( exit_val );
- X}
- X
- X/* Given a string of <num>[<suff>] returns a num
- X * suff =
- X * m/M for 1meg
- X * k/K for 1k
- X * b/B for 512
- X */
- Xdo_size( arg )
- X char *arg;
- X{
- X char format[ 20 ];
- X int ret;
- X
- X *format = '\0';
- X sscanf( arg, "%d%s", &ret, format );
- X
- X switch( *format ){
- X case 'm':
- X case 'M':
- X ret = ret K K;
- X break;
- X case 'k':
- X case 'K':
- X ret = ret K;
- X break;
- X case 'b':
- X case 'B':
- X ret *= 512;
- X break;
- X }
- X
- X return ret;
- X}
- X
- Xpr_out()
- X{
- X fprintf( stderr, "% 10luK\r", outk );
- X}
- X
- X#ifdef SYS5
- X#include <sys/time.h>
- X
- Xbzero( b, l )
- X char *b;
- X unsigned l;
- X{
- X memset( b, '\0', l );
- X}
- X
- Xusleep_back()
- X{
- X}
- X
- Xusleep( u )
- X unsigned u;
- X{
- X struct itimerval old, t;
- X signal( SIGALRM, usleep_back );
- X t.it_interval.tv_sec = 0;
- X t.it_interval.tv_usec = 0;
- X t.it_value.tv_sec = u / 1000000;
- X t.it_value.tv_usec = u % 1000000;
- X setitimer( ITIMER_REAL, &t, &old );
- X pause();
- X setitimer( ITIMER_REAL, &old, NULL );
- X}
- X#endif
- END_OF_FILE
- if test 18515 -ne `wc -c <'buffer.c'`; then
- echo shar: \"'buffer.c'\" unpacked with wrong size!
- fi
- # end of 'buffer.c'
- fi
- if test -f 'sem.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sem.c'\"
- else
- echo shar: Extracting \"'sem.c'\" \(2766 characters\)
- sed "s/^X//" >'sem.c' <<'END_OF_FILE'
- X/*
- X Buffer. Very fast reblocking filter speedy writing of tapes.
- X Copyright (C) 1990,1991 Lee McLoughlin
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 1, or (at your option)
- X any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- X Lee McLoughlin.
- X Dept of Computing, Imperial College,
- X 180 Queens Gate, London, SW7 2BZ, UK.
- X
- X Email: L.McLoughlin@doc.ic.ac.uk
- X*/
- X
- X/* This is a simple module to provide an easier to understand interface to
- X * semaphores */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/ipc.h>
- X#include <sys/sem.h>
- X#include <errno.h>
- X
- X#if defined(SYS5) || defined(ultrix) || defined(_AIX)
- Xunion semun {
- X int val;
- X struct semid_ds *buf;
- X ushort *array;
- X};
- X#endif
- X
- X/* Set a semaphore to a particular value - meant to be used before
- X * first lock/unlock */
- Xvoid
- Xsem_set( sem_id, val )
- X int sem_id;
- X int val;
- X{
- X union semun arg;
- X extern int errno;
- X
- X arg.val = val;
- X
- X errno = 0;
- X semctl( sem_id, 0, SETVAL, arg );
- X if( errno != 0 ){
- X perror( "buffer: internal error, sem_set" );
- X exit( -1 );
- X }
- X}
- X
- Xint
- Xnew_sem()
- X{
- X int sem;
- X
- X sem = semget( IPC_PRIVATE, 1, IPC_CREAT|S_IREAD|S_IWRITE );
- X if( sem < 0 ){
- X perror( "buffer: internal error, couldn't create semaphore" );
- X exit( -1 );
- X }
- X sem_set( sem, 1 );
- X
- X return sem;
- X}
- X
- Xstatic
- Xdo_sem( sem_id, pbuf, err )
- X int sem_id;
- X struct sembuf *pbuf;
- X char *err;
- X{
- X /* This just keeps us going in case of EINTR */
- X while( 1 ){
- X if( semop( sem_id, pbuf, 1 ) == -1 ){
- X if( errno == EINTR ){
- X continue;
- X }
- X fprintf( stderr, "buffer: internal error pid %d, lock id %d\n", getpid(), sem_id );
- X perror( err );
- X exit( -1 );
- X }
- X return;
- X }
- X}
- X
- Xvoid
- Xlock( sem_id )
- X int sem_id;
- X{
- X struct sembuf sembuf;
- X
- X sembuf.sem_num = 0;
- X sembuf.sem_op = -1;
- X sembuf.sem_flg = 0;
- X
- X do_sem( sem_id, &sembuf, "buffer: lock error" );
- X}
- X
- Xvoid
- Xunlock( sem_id )
- X int sem_id;
- X{
- X struct sembuf sembuf;
- X
- X sembuf.sem_num = 0;
- X sembuf.sem_op = 1;
- X sembuf.sem_flg = 0;
- X
- X do_sem( sem_id, &sembuf, "buffer: unlock error" );
- X}
- X
- Xvoid
- Xremove_sem( sem_id )
- X int sem_id;
- X{
- X if( sem_id == -1 )
- X return;
- X
- X if( semctl( sem_id, 0, IPC_RMID, NULL ) == -1 )
- X perror( "buffer: internal error, failed to remove semaphore" );
- X}
- END_OF_FILE
- if test 2766 -ne `wc -c <'sem.c'`; then
- echo shar: \"'sem.c'\" unpacked with wrong size!
- fi
- # end of 'sem.c'
- fi
- if test -f 'COPYING' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'COPYING'\"
- else
- echo shar: Extracting \"'COPYING'\" \(17982 characters\)
- sed "s/^X//" >'COPYING' <<'END_OF_FILE'
- X GNU GENERAL PUBLIC LICENSE
- X Version 2, June 1991
- X
- X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- X 675 Mass Ave, Cambridge, MA 02139, USA
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license document, but changing it is not allowed.
- X
- X Preamble
- X
- X The licenses for most software are designed to take away your
- Xfreedom to share and change it. By contrast, the GNU General Public
- XLicense is intended to guarantee your freedom to share and change free
- Xsoftware--to make sure the software is free for all its users. This
- XGeneral Public License applies to most of the Free Software
- XFoundation's software and to any other program whose authors commit to
- Xusing it. (Some other Free Software Foundation software is covered by
- Xthe GNU Library General Public License instead.) You can apply it to
- Xyour programs, too.
- X
- X When we speak of free software, we are referring to freedom, not
- Xprice. Our General Public Licenses are designed to make sure that you
- Xhave the freedom to distribute copies of free software (and charge for
- Xthis service if you wish), that you receive source code or can get it
- Xif you want it, that you can change the software or use pieces of it
- Xin new free programs; and that you know you can do these things.
- X
- X To protect your rights, we need to make restrictions that forbid
- Xanyone to deny you these rights or to ask you to surrender the rights.
- XThese restrictions translate to certain responsibilities for you if you
- Xdistribute copies of the software, or if you modify it.
- X
- X For example, if you distribute copies of such a program, whether
- Xgratis or for a fee, you must give the recipients all the rights that
- Xyou have. You must make sure that they, too, receive or can get the
- Xsource code. And you must show them these terms so they know their
- Xrights.
- X
- X We protect your rights with two steps: (1) copyright the software, and
- X(2) offer you this license which gives you legal permission to copy,
- Xdistribute and/or modify the software.
- X
- X Also, for each author's protection and ours, we want to make certain
- Xthat everyone understands that there is no warranty for this free
- Xsoftware. If the software is modified by someone else and passed on, we
- Xwant its recipients to know that what they have is not the original, so
- Xthat any problems introduced by others will not reflect on the original
- Xauthors' reputations.
- X
- X Finally, any free program is threatened constantly by software
- Xpatents. We wish to avoid the danger that redistributors of a free
- Xprogram will individually obtain patent licenses, in effect making the
- Xprogram proprietary. To prevent this, we have made it clear that any
- Xpatent must be licensed for everyone's free use or not licensed at all.
- X
- X The precise terms and conditions for copying, distribution and
- Xmodification follow.
- X
- X GNU GENERAL PUBLIC LICENSE
- X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- X
- X 0. This License applies to any program or other work which contains
- Xa notice placed by the copyright holder saying it may be distributed
- Xunder the terms of this General Public License. The "Program", below,
- Xrefers to any such program or work, and a "work based on the Program"
- Xmeans either the Program or any derivative work under copyright law:
- Xthat is to say, a work containing the Program or a portion of it,
- Xeither verbatim or with modifications and/or translated into another
- Xlanguage. (Hereinafter, translation is included without limitation in
- Xthe term "modification".) Each licensee is addressed as "you".
- X
- XActivities other than copying, distribution and modification are not
- Xcovered by this License; they are outside its scope. The act of
- Xrunning the Program is not restricted, and the output from the Program
- Xis covered only if its contents constitute a work based on the
- XProgram (independent of having been made by running the Program).
- XWhether that is true depends on what the Program does.
- X
- X 1. You may copy and distribute verbatim copies of the Program's
- Xsource code as you receive it, in any medium, provided that you
- Xconspicuously and appropriately publish on each copy an appropriate
- Xcopyright notice and disclaimer of warranty; keep intact all the
- Xnotices that refer to this License and to the absence of any warranty;
- Xand give any other recipients of the Program a copy of this License
- Xalong with the Program.
- X
- XYou may charge a fee for the physical act of transferring a copy, and
- Xyou may at your option offer warranty protection in exchange for a fee.
- X
- X 2. You may modify your copy or copies of the Program or any portion
- Xof it, thus forming a work based on the Program, and copy and
- Xdistribute such modifications or work under the terms of Section 1
- Xabove, provided that you also meet all of these conditions:
- X
- X a) You must cause the modified files to carry prominent notices
- X stating that you changed the files and the date of any change.
- X
- X b) You must cause any work that you distribute or publish, that in
- X whole or in part contains or is derived from the Program or any
- X part thereof, to be licensed as a whole at no charge to all third
- X parties under the terms of this License.
- X
- X c) If the modified program normally reads commands interactively
- X when run, you must cause it, when started running for such
- X interactive use in the most ordinary way, to print or display an
- X announcement including an appropriate copyright notice and a
- X notice that there is no warranty (or else, saying that you provide
- X a warranty) and that users may redistribute the program under
- X these conditions, and telling the user how to view a copy of this
- X License. (Exception: if the Program itself is interactive but
- X does not normally print such an announcement, your work based on
- X the Program is not required to print an announcement.)
- X
- XThese requirements apply to the modified work as a whole. If
- Xidentifiable sections of that work are not derived from the Program,
- Xand can be reasonably considered independent and separate works in
- Xthemselves, then this License, and its terms, do not apply to those
- Xsections when you distribute them as separate works. But when you
- Xdistribute the same sections as part of a whole which is a work based
- Xon the Program, the distribution of the whole must be on the terms of
- Xthis License, whose permissions for other licensees extend to the
- Xentire whole, and thus to each and every part regardless of who wrote it.
- X
- XThus, it is not the intent of this section to claim rights or contest
- Xyour rights to work written entirely by you; rather, the intent is to
- Xexercise the right to control the distribution of derivative or
- Xcollective works based on the Program.
- X
- XIn addition, mere aggregation of another work not based on the Program
- Xwith the Program (or with a work based on the Program) on a volume of
- Xa storage or distribution medium does not bring the other work under
- Xthe scope of this License.
- X
- X 3. You may copy and distribute the Program (or a work based on it,
- Xunder Section 2) in object code or executable form under the terms of
- XSections 1 and 2 above provided that you also do one of the following:
- X
- X a) Accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of Sections
- X 1 and 2 above on a medium customarily used for software interchange; or,
- X
- X b) Accompany it with a written offer, valid for at least three
- X years, to give any third party, for a charge no more than your
- X cost of physically performing source distribution, a complete
- X machine-readable copy of the corresponding source code, to be
- X distributed under the terms of Sections 1 and 2 above on a medium
- X customarily used for software interchange; or,
- X
- X c) Accompany it with the information you received as to the offer
- X to distribute corresponding source code. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form with such
- X an offer, in accord with Subsection b above.)
- X
- XThe source code for a work means the preferred form of the work for
- Xmaking modifications to it. For an executable work, complete source
- Xcode means all the source code for all modules it contains, plus any
- Xassociated interface definition files, plus the scripts used to
- Xcontrol compilation and installation of the executable. However, as a
- Xspecial exception, the source code distributed need not include
- Xanything that is normally distributed (in either source or binary
- Xform) with the major components (compiler, kernel, and so on) of the
- Xoperating system on which the executable runs, unless that component
- Xitself accompanies the executable.
- X
- XIf distribution of executable or object code is made by offering
- Xaccess to copy from a designated place, then offering equivalent
- Xaccess to copy the source code from the same place counts as
- Xdistribution of the source code, even though third parties are not
- Xcompelled to copy the source along with the object code.
- X
- X 4. You may not copy, modify, sublicense, or distribute the Program
- Xexcept as expressly provided under this License. Any attempt
- Xotherwise to copy, modify, sublicense or distribute the Program is
- Xvoid, and will automatically terminate your rights under this License.
- XHowever, parties who have received copies, or rights, from you under
- Xthis License will not have their licenses terminated so long as such
- Xparties remain in full compliance.
- X
- X 5. You are not required to accept this License, since you have not
- Xsigned it. However, nothing else grants you permission to modify or
- Xdistribute the Program or its derivative works. These actions are
- Xprohibited by law if you do not accept this License. Therefore, by
- Xmodifying or distributing the Program (or any work based on the
- XProgram), you indicate your acceptance of this License to do so, and
- Xall its terms and conditions for copying, distributing or modifying
- Xthe Program or works based on it.
- X
- X 6. Each time you redistribute the Program (or any work based on the
- XProgram), the recipient automatically receives a license from the
- Xoriginal licensor to copy, distribute or modify the Program subject to
- Xthese terms and conditions. You may not impose any further
- Xrestrictions on the recipients' exercise of the rights granted herein.
- XYou are not responsible for enforcing compliance by third parties to
- Xthis License.
- X
- X 7. If, as a consequence of a court judgment or allegation of patent
- Xinfringement or for any other reason (not limited to patent issues),
- Xconditions are imposed on you (whether by court order, agreement or
- Xotherwise) that contradict the conditions of this License, they do not
- Xexcuse you from the conditions of this License. If you cannot
- Xdistribute so as to satisfy simultaneously your obligations under this
- XLicense and any other pertinent obligations, then as a consequence you
- Xmay not distribute the Program at all. For example, if a patent
- Xlicense would not permit royalty-free redistribution of the Program by
- Xall those who receive copies directly or indirectly through you, then
- Xthe only way you could satisfy both it and this License would be to
- Xrefrain entirely from distribution of the Program.
- X
- XIf any portion of this section is held invalid or unenforceable under
- Xany particular circumstance, the balance of the section is intended to
- Xapply and the section as a whole is intended to apply in other
- Xcircumstances.
- X
- XIt is not the purpose of this section to induce you to infringe any
- Xpatents or other property right claims or to contest validity of any
- Xsuch claims; this section has the sole purpose of protecting the
- Xintegrity of the free software distribution system, which is
- Ximplemented by public license practices. Many people have made
- Xgenerous contributions to the wide range of software distributed
- Xthrough that system in reliance on consistent application of that
- Xsystem; it is up to the author/donor to decide if he or she is willing
- Xto distribute software through any other system and a licensee cannot
- Ximpose that choice.
- X
- XThis section is intended to make thoroughly clear what is believed to
- Xbe a consequence of the rest of this License.
- X
- X 8. If the distribution and/or use of the Program is restricted in
- Xcertain countries either by patents or by copyrighted interfaces, the
- Xoriginal copyright holder who places the Program under this License
- Xmay add an explicit geographical distribution limitation excluding
- Xthose countries, so that distribution is permitted only in or among
- Xcountries not thus excluded. In such case, this License incorporates
- Xthe limitation as if written in the body of this License.
- X
- X 9. The Free Software Foundation may publish revised and/or new versions
- Xof the General Public License from time to time. Such new versions will
- Xbe similar in spirit to the present version, but may differ in detail to
- Xaddress new problems or concerns.
- X
- XEach version is given a distinguishing version number. If the Program
- Xspecifies a version number of this License which applies to it and "any
- Xlater version", you have the option of following the terms and conditions
- Xeither of that version or of any later version published by the Free
- XSoftware Foundation. If the Program does not specify a version number of
- Xthis License, you may choose any version ever published by the Free Software
- XFoundation.
- X
- X 10. If you wish to incorporate parts of the Program into other free
- Xprograms whose distribution conditions are different, write to the author
- Xto ask for permission. For software which is copyrighted by the Free
- XSoftware Foundation, write to the Free Software Foundation; we sometimes
- Xmake exceptions for this. Our decision will be guided by the two goals
- Xof preserving the free status of all derivatives of our free software and
- Xof promoting the sharing and reuse of software generally.
- X
- X NO WARRANTY
- X
- X 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- XREPAIR OR CORRECTION.
- X
- X 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- XPOSSIBILITY OF SUCH DAMAGES.
- X
- X END OF TERMS AND CONDITIONS
- X
- X Appendix: How to Apply These Terms to Your New Programs
- X
- X If you develop a new program, and you want it to be of the greatest
- Xpossible use to the public, the best way to achieve this is to make it
- Xfree software which everyone can redistribute and change under these terms.
- X
- X To do so, attach the following notices to the program. It is safest
- Xto attach them to the start of each source file to most effectively
- Xconvey the exclusion of warranty; and each file should have at least
- Xthe "copyright" line and a pointer to where the full notice is found.
- X
- X <one line to give the program's name and a brief idea of what it does.>
- X Copyright (C) 19yy <name of author>
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 2 of the License, or
- X (at your option) any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- XAlso add information on how to contact you by electronic and paper mail.
- X
- XIf the program is interactive, make it output a short notice like this
- Xwhen it starts in an interactive mode:
- X
- X Gnomovision version 69, Copyright (C) 19yy name of author
- X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- X This is free software, and you are welcome to redistribute it
- X under certain conditions; type `show c' for details.
- X
- XThe hypothetical commands `show w' and `show c' should show the appropriate
- Xparts of the General Public License. Of course, the commands you use may
- Xbe called something other than `show w' and `show c'; they could even be
- Xmouse-clicks or menu items--whatever suits your program.
- X
- XYou should also get your employer (if you work as a programmer) or your
- Xschool, if any, to sign a "copyright disclaimer" for the program, if
- Xnecessary. Here is a sample; alter the names:
- X
- X Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- X `Gnomovision' (which makes passes at compilers) written by James Hacker.
- X
- X <signature of Ty Coon>, 1 April 1989
- X Ty Coon, President of Vice
- X
- XThis General Public License does not permit incorporating your program into
- Xproprietary programs. If your program is a subroutine library, you may
- Xconsider it more useful to permit linking proprietary applications with the
- Xlibrary. If this is what you want to do, use the GNU Library General
- XPublic License instead of this License.
- END_OF_FILE
- if test 17982 -ne `wc -c <'COPYING'`; then
- echo shar: \"'COPYING'\" unpacked with wrong size!
- fi
- # end of 'COPYING'
- fi
- echo shar: End of shell archive.
- exit 0
- exit 0 # Just in case...
-