[mod.sources] v07i12: Multivol V1.00 - multivolume backup utility, part01/02

sources-request@munnari.OZ (08/29/86)

Submitted-by: Tony O'Hagan <tony%uqcspe.oz@seismo.css.gov>
Mod.sources: Volume 17, Issue 12
Archive-name: multivol

	[ This is a program that was announced in net.unix-wizards
	  some time ago (May perhaps).  It reads standard input
	  and splits the (assumed large) file across multiple
	  tape volumes.  It does some label checking on tapes.

	  I have tested this to the extent of seeing that it compiles,
	  and runs its own test cases, on both 4.3beta and Sys V.
	  To compile this on Sys V you will need to add
		  -Dindex=strchr -DSYSV
	  on the DEFINE= line in Makefile.

	  You should read the Makefile carefully, there are some system
	  dependant defines scattered through it.  Also read the READ_ME
	  carefully.

	  One day I will get a better version of shar, till then... kre ]

echo x - "READ_ME" 2>&1
sed "s/^X//" >"READ_ME" <<'!The!End!'
X	Multivol V1.00 - multivolume backup utility
X
X========================================================================
XTo install :-
X	0) check Makefile
X		- sorry you'll find a lot of testing junk - see below.
X	1) make depend
X		- to build dependencies in makefile 
X		- check them at the end of the Makefile.
X	2) make multivol
X	3) Test writting to a file (i.e. not a device)
X		3.0) make testdata - to build a test data program.
X		3.1) make wfile - test writting to file
X			The first time a file or device is written to
X			multivol will report that it finds no header.
X		3.2) make rfile - test reading the file.
X		3.3) make rewfile - test writting and re-reading the file.
X	4) Test writting to a device.
X		4.0) Change TSTDEV in makefile to the device used for testing.
X		     or better - create the link /dev/multivol to the device.
X		     This is compiled into multivol as the default device.
X		4.1 - 4.3) Simple tests are 'make w', 'make r', 'make ro'
X		4.4) Have a look at Makefile to try some other tests (e.g wbig)
X	End)
X		E.0) Change DEFINE in Makefile to not include -DDEBUG
X		     This ensures tracing is removed from object code.
X		E.1) Change CFLAGS in Makefile to include -O
X			(if you have an optimising compiler)
X		E.2) make clobber - to remove any object code.
X		E.3) make multivol - to rebuild the thing without any tracing.
X		E.4) If it still works (i.e. you can trust your optimiser)
X		     install it in you favourite bin directory and
X		     multivol.8 in /usr/man/man8 or wherever.
X========================================================================
X19-Jul-85  Tony O'Hagan
X	Using /dev/rmt0, doesn't appear to read volume header unless
X	the block size matches the written block size.  I/O failure.
X========================================================================
X 7-Aug-85  Tony O'Hagan
X	Expected lint errors :-		(Perkin-Elmer V7 lint)
X"rd.c", line 150: warning: possible pointer alignment problem
X"rd.c", line 152: warning: possible pointer alignment problem
X"wr.c", line 149: warning: possible pointer alignment problem
X"vhdr.c", line 51: warning: possible pointer alignment problem
X"vhdr.c", line 85: warning: blk_siz redefinition hides earlier one
Xaskf returns value which is always ignored
Xclose returns value which is always ignored
Xfgets returns value which is always ignored
Xmount_v returns value which is sometimes ignored
Xrd_put_ returns value which is always ignored
Xsprintf returns value which is always ignored
Xsscanf returns value which is sometimes ignored
Xstrncpy returns value which is always ignored
Xwrite returns value which is sometimes ignored
X========================================================================
!The!End!

echo x - "multivol.8" 2>&1
sed "s/^X//" >"multivol.8" <<'!The!End!'
X.TH MULTIVOL 8 local
X.SH NAME
Xmultivol \- handle multivolume files
X.SH SYNOPSIS
X.B multivol
X.B \-o
X.RB [ \-vtw ]
X.RB [ \-b
X.IR blocksize ]
X.RB [ \-n
X.IR count ]
X.RB [ \-l
X.IR label ]
X.RI [ device ]
X.PP
X.B multivol
X.B \-i
X.RB [ \-vtw ]
X.RB [ \-b
X.IR blocksize ]
X.RB [ \-n
X.IR count ]
X.RB [ \-l
X.IR label ]
X.RI [ device ]
X.PP
X.B multivol
X.B \-t
X.RI [ device ]
X.SH DESCRIPTION
X.I Multivol
Xallows for the convenient use of multiple volume files such as when
Xbacking up output from 
X.I cpio/tar
Xover several floppy disks.
X.PP
XOption
X.B \-o
Xreads the standard input file, breaking it into volumes on the output device.
XOption
X.BR \-i
Xreads volumes from the device, concatenates them
Xand writes the result to standard output.
X.PP
XThe device to use is given by the
X.I device
Xargument, or
X.I /dev/multivol
Xif none is specified.
XNormally this will be a character special file corresponding to a raw
Xdisk or tape unit.
XIt does not have to be a random access device:
X.I multivol
Xonly accesses it sequentially.
XHowever,
X.I multivol
Xmay close and re-open a volume in order to rewind devices such as magnetic tape.
X.PP
XThe
X.B \-b
X.I blocksize
Xargument specifies the physical block size to be used.
XThis number may end with
X.B k
Xor
X.B b
Xto specify multiplication by
X1024 or 512 respectively.
XWith a floppy disk it can usefully be made the size of one
Xtrack.
XThe default physical block size is 512 bytes.
XIf the device or its driver does not allow successful writing all the way to the
Xend of a physical volume, such as with magnetic tape, the
X.B \-n
X.I count
Xoptions should be used to specify the maximum number of physical blocks
Xto be written on one volume.
X.PP
XThe
X.B \-l
X.I label
Xoption allows the user to supply a short string to be written onto
Xthe volume for identification.
X.PP
XBefore reading or writing a new volume,
X.I multivol
Xprompts on the controlling terminal for the user to insert the appropriate
Xvolume into the physical device and waits for a new-line to be typed.
XWith
X.BR \-i ,
Xif the volume inserted is not a
X.I multivol
Xvolume,
Xis not the next volume in sequence,
Xor does not have the same date stamp as the previous volume,
X.I multivol
Xverifies that you really want to read it.
X.PP
X.I Multivol
Xwrites an \s-2ASCII\s0 header on each volume, 
Xand checksum info in each block
Xhence the actual amount of data stored on each volume will be slightly less
Xthan its physical size.
XThe
X.B \-t
Xoption prints some of this header information on standard error.
XIt includes:
X.IP \(bu
Xthe date that the volume was written
X.IP \(bu
Xthe sequence number of the volume
X.IP \(bu
Xany
X.I label
Xstring supplied at the time the volume was written
X.LP
XIf you specify
X.B \-w
Xwith
X.B \-i
Xor
X.B \-o
X.I multivol
Xassumes the
X.B \-t
Xoption also and
Xasks you to verify that each volume really is the required one.
X.PP
XThe
X.B \-v
Xoption tells
X.I multivol
Xto write various other verbose information on standard error
Xsuch as an indication of how many blocks it has read or written.
X.SH EXAMPLES
XTell me what you know about this volume:
X.br
X	multivol \-t
X.LP
XBackup a directory to the default device:
X.br
X	tar cf \- mydir | multivol \-o
X.sp
Xand retrieve it again:
X.br
X	cd mydir
X.br
X	multivol \-i | tar xf \-
X.LP
XBackup to tape all files changed since last time:
X.br
X	touch /etc/multivoldate1
X.br
X	find / \-newer /etc/multivoldate2 \-print | cpio \-ov |
X.br
X		multivol \-o \-l WEEKLY \-b 20k \-n 1000 /dev/rmt0
X.br
X	mv /etc/multivoldate1 /etc/multivoldate2
X.sp
XRetrieve a file from that backup:
X.br
X	cd /
X.br
X	multivol \-i /dev/rmt0 | cpio \-idmv usr/myname/myfile
X.SH FILES
X.ta \w'/dev/multivol     'u
X.nf
X/dev/tty	where prompts are written and responses read
X.br
X/dev/multivol	the default device
X.SH SEE ALSO
Xtar(1), cpio(1), dd(1), dump(8), ``your device''(4)
X.SH DIAGNOSTICS
X.PP
XA message is written on standard error and
X.I multivol
Xterminates in the event of
X.IP \(bu
Xincorrect usage
X.IP \(bu
Xnot being able to open the device
X.IP \(bu
Xnot being able to open /dev/tty
X.IP \(bu
Xa device I/O error 
X.SH BUGS
XIn the event of an I/O error you may have to start again with the first volume
Xdepending on the nature of the file and the program which produced it.  In
Xmany cases it simply means the end of the volume has been reached, and no more
Xcan be read/written.  If a block limit has been set
X.I multivol
Xwill indicate this condition.
X.PP
XWhen reading or writting,
X.I multivol
Xattempts to read the volumes header to display what is being written over,
Xor to determine the block size recorded in the header.
XSome raw devices will return an I/O error
Xwhen the volume has not been written before, or has been previously written
Xwith a different block size.
XHence the volume header cannot be read until the original
Xblock size is also specified.
XThe first time a volume is written,
X.I multivol
Xmay signal an I/O error as it attempts to read the header, but will proceed 
Xto allow the volume to be written.
X.PP
XVolume labels may not contain white space and are limited to 14 characters.
X.PP
XSome tape device drivers cannot handle a read/write request while the tape
Xis rewinding, for such drivers the
X.B \-w
Xswitch is recommended in place of just
X.B \-t
X\.
!The!End!

echo x - "maint.doc" 2>&1
sed "s/^X//" >"maint.doc" <<'!The!End!'
Xmultivol.doc V1.00 01-Jun-85 Tony O'Hagan
X	Documentation on developement of multi-volume backup utility "multivol".
X	Global flags
X1. rd_flag  -i Read each volume -> stdout
X2. wr_flag  -o Write each volume stdin ->
X3. dsp_vol  -t Attempt to read & print each volume header -> stderr
X4. dsp_blks -v Indicate number of blocks read/written -> stderr
X5. vfy_vol  -w Allow user to verify each volume mounted -> stderr /dev/tty ->  
X
XWhen dsp_vol is set the following will be tested :-
XWriting:-
X	* Writing over a volume in the set being tested;
XReading:-
X	* Reading a volume with a time stamp different from first volume read;
X	* Reading volumes out of sequence
X	* Check that label corresponds (if specified)
X
XQueries:-
X	a. What will happen if no blocks have ever been written to the volume
X	and an attempt is made to read the volumes header ?
X==============================================================================
X	multivol V2.00 01-Jul-85 Tony O'Hagan & Tim Roper
XBuffer data structure :-
X
X	First volume block		Other volume blocks
X
X . 	 ---------------  <- buf_ptr ->	 ---------------
X/|\	| block header	| (word aligned)|		|
X |	|---------------|		|		|
X |	|		|		|		|
X |	| volume header	|		|---------------|       .
X |	|		|		| block header	|      /|\
X |	 ---------------  <- dta_ptr ->	 ---------------	|
X |	|		| (word aligned)|		|	|
X |	|		|	     	|		|	|
Xblk_siz	|     data	|		|		|	|
X |	|		|		|     data	|    blk_siz
X |	|		|		|		|	|
X\!/	|		|		|		|	|
X 	|---------------|	       	|		|	|
X	|		|		|		|	|
X	|		|		|		|      \!/
X	 ---------------		 --------------- 
X
X	sizeof(vol_hdr) and sizeof(blk_hdr) must both be an integral number
X	of word alignment units.
X========================================================================
X19-Jul-85  Tony O'Hagan
X	Using /dev/rmt0, doesn't appear to read volume header unless
X	the block size matches the written block size.  I/O failure.
X========================================================================
X 7-Aug-85  Tony O'Hagan
X	Expected lint errors :-		(Perkin-Elmer V7 lint)
X"rd.c", line 150: warning: possible pointer alignment problem
X"rd.c", line 152: warning: possible pointer alignment problem
X"wr.c", line 149: warning: possible pointer alignment problem
X"vhdr.c", line 51: warning: possible pointer alignment problem
X"vhdr.c", line 85: warning: blk_siz redefinition hides earlier one
Xaskf returns value which is always ignored
Xclose returns value which is always ignored
Xfgets returns value which is always ignored
Xmount_v returns value which is sometimes ignored
Xrd_put_ returns value which is always ignored
Xsprintf returns value which is always ignored
Xsscanf returns value which is sometimes ignored
Xstrncpy returns value which is always ignored
Xwrite returns value which is sometimes ignored
X========================================================================
XTony O'Hagan		Australia: (07) 3774125  International: +61 7 3774125
XUniversity of Queensland	CSNET:	tony@uqcspe.oz	ACSnet:	tony@uqcspe.oz
XDept. of Computer Science	UUCP:	...!seismo!munnari!uqcspe.oz!tony
XSt. Lucia, Brisbane, 		ARPA:	tony%uqcspe.oz@seismo.css.gov
XAUSTRALIA  4067	 		JANET:	uqcspe.oz!tony@ukc
!The!End!

echo x - "Makefile" 2>&1
sed "s/^X//" >"Makefile" <<'!The!End!'
XMAKEFILE = Makefile
XTARGET	= multivol
X
X#	USER - user name used for sendfile requests
X#	HOSTS - sendfile hosts
XUSER	= tony
XHOSTS	= pisa rune uq ppse madvax1
X
X#	installation library
XINSTALL = /user0/tony/Bin
X
X#	MISC - misc. files to be listed and sent to other hosts
XMISC	= multivol.8 testdata.c READ_ME maint.doc
XHEADERS	= multivol.h options.h trace.h
XSRC1	= multivol.c rd.c wr.c
XSRC2	= vhdr.c mount.c bcopy.c ask.c error.c trace.c
XSOURCES	= $(SRC1) $(SRC2)
XOBJECTS	= multivol.o rd.o wr.o vhdr.o mount.o ask.o error.o trace.o
XSHSRC	=
X
X#	used to compile in bcopy() if it is not defined on the system
XLIBRARY	= multivol.a
XLIBSRC	= bcopy.c
XLIBOBJ	= bcopy.o
X
X#	**** shar switches ****
XSHAR	= shar -c -b -v
X
X#	**** defaults for compiled code ****
X#	DEFDEV - default device
X#	DEFLIM - default block limit (-1 = no limit)
X#	DEFBSIZ - default block size
XDEFDEV	= /dev/multivol
XDEFBSIZ	= 4096
XDEFBLIM	= -1
X
X#	**** compiler, loader & lint switches ****
X#	DEBUG 	- compile in traceing code.
X#	VOLNUM	- read/write to <device>.<vol-number> to test multiple volumes
X#		  with files pretending to be device volumes.
X#	REWIND	- manually rewind tape after reading volume header
XDEFINE	= -DDEBUG -Dvoid=int
X#DEFINE	= -Dvoid=int
XLINT	= -p $(DEFINE) 
X#CFLAGS	= -O $(DEFINE)
XCFLAGS	= $(DEFINE)
XLDFLAGS	= -n
X
X#	**** Variables used for Testing ****
X#	TSTFIL - Test file pretending to be a device - see wfile: and rfile:
X#	TSTDEV - Test device
XTSTFIL	= vol
X#	test device
X#TSTDEV	= $(TSTFIL)
XTSTDEV	= $(DEFDEV)
X#TSTDEV	= /dev/flop
X#TSTDEV	= /dev/rx2
X#TSTDEV	= /dev/rmt0
X#TSTDEV	= /dev/fd70
X
X#	Testing utilities use these switches :-
X#	These can be easily individually changed when invoking make
X#	LABEL	- volume label
X#	BLKSIZ	- Block size used in test runs
X#	BLKLIM	- Limit of blocks per volume ( -1 = no limit )
X#	OPT	- other multivol options
XLABEL	= -l testdata_label
XBLKSIZ	= -b $(DEFBSIZ)
XBLKLIM	= -n 10
X#OPT	= -vw
XOPT	= -tD
XRDOPTS	= -i $(OPT) $(BLKLIM) $(LABEL)
XWROPTS	= -o $(OPT) $(BLKSIZ) $(BLKLIM) $(LABEL)
X
X#	OUTDTA	- temporary file for comparing with output from 'testdata'.
X#	TSTSH	- temporary file for storing the last testdata command 
XOUTDTA	= $(TARGET).out
XTSTSH	= $(TARGET).sh
X
X$(TARGET):	$(OBJECTS) $(LIBRARY)
X	$(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) -lc $(LIBRARY)
X# for uq PDP11. to use correct ctime() routines.
X#	$(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) -lstd -lc $(LIBRARY)
X#	size $@
X
Xmultivol.o:		multivol.c
X	$(CC) $(CFLAGS) -DDEFBSIZ=$(DEFBSIZ) -DDEFBLIM=$(DEFBLIM) \
X			-DDEFDEV='"$(DEFDEV)"' -c multivol.c
X
X$(LIBRARY):	$(LIBOBJ)
X	ar ru $(LIBRARY) $(LIBOBJ)
X#	ranlib $(LIBRARY)
X
Xtestdata:	testdata.o
X	$(CC) $(LDFLAGS) -o testdata testdata.o
X
X#	******* Testing utilities for multivol *******
Xodfile:
X	od -c $(TSTFIL) | less
X
Xod:
X	od -c $(TSTDEV) | less
X
X# Test displaying volume header of a file
Xtfile:	$(TARGET) 
X	./$(TARGET) -t $(TSTFIL)
X
X# Test writing of files pretending to be devices - quick test
Xwfile:	testdata $(TARGET) # write data out to file
X	>$(TSTFIL)
X	echo './testdata 1005 xyz 1022 abc' > $(TSTSH)
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTFIL)
X
X# Test reading files pretending to be devices
X# Read file volume and compare output with the last input data written
Xrfile: 	$(TARGET)
X	./$(TARGET) $(RDOPTS) $(TSTFIL) > $(OUTDTA)
X	sh $(TSTSH) | cmp - $(OUTDTA)
X
X# Test re-writing of files pretending to be devices
Xrewfile:	testdata $(TARGET) wfile
X	echo './testdata 4096 zyxwvutsrqponml' > $(TSTSH)
X	sh $(TSTSH) |./$(TARGET) $(WROPTS) $(TSTFIL)
X
X# Test displaying volume header
Xt:	$(TARGET) 
X	./$(TARGET) -t $(TSTDEV)
X
X# Read volume and compare output with the last input data written
Xr: 	$(TARGET)
X	./$(TARGET) $(RDOPTS) $(TSTDEV) > $(OUTDTA)
X	sh $(TSTSH) | cmp - $(OUTDTA)
X
X# Read volume and count wo
Xro: 	$(TARGET)
X	./$(TARGET) $(RDOPTS) $(TSTDEV)
X
X# Test writing of volumes - quick test
Xw:	testdata $(TARGET) # write data out to device
X	echo './testdata 30 abcdefghi' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTDEV)
X
X# Test writing off end of a volume (NCR floppy)
Xwpisa:	testdata $(TARGET) # write data out to device
X	echo './testdata 7680 abcdefghijklmno' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTDEV)
X
X# Test writing off end of a volume (NCR floppy)
Xwwords:	testdata $(TARGET) # write data out to device
X	echo 'cat /usr/dict/words' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTDEV)
X
X# Read volume and compare output with the last input data written
Xrwords: 	$(TARGET)
X	./$(TARGET) $(RDOPTS) $(TSTDEV) | diff - /usr/dict/words
X
X# Test writing off end of a volume (rune host, 1600 bpi tape)
X#	100 blocks = 4088 * 100 - 68 = 102183 * 4  (4 chars = 'abc\n')
Xwrune:	testdata $(TARGET) # write data out to device
X	echo './testdata 102183 abc' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) -n -1 $(TSTDEV)
X
X# Test writing 2 volume set
Xw2vol:	testdata $(TARGET) # write data out to device
X	echo './testdata 7000 abcdefghi' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTDEV)
X
X# Test writing 3 volume set
Xw3vol:	testdata $(TARGET) # write data out to device
X	echo './testdata 12000 abcdefghi' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTDEV)
X
X# Test writing off end of a volume
Xwbig:	testdata $(TARGET) # write data out to device
X	echo './testdata 100000 abcdefghijklmno' > $(TSTSH) 
X	sh $(TSTSH) | ./$(TARGET) $(WROPTS) $(TSTDEV)
X
X#	******* General utilities *******
X
X#	Updates multivol files on other hosts
Xuqcspe $(HOSTS):	$(SOURCES) $(LIBSRC) $(HEADERS) $(MISC) $(MAKEFILE)
X	echo "`date` % $@ $?" >> $@
X	sendfile $(USER)@$@ $@ $?
X
X#	Update all hosts
Xhosts:	$(HOSTS)
X
X#	Retrieves sent files
Xgetfile:
X	getfile -DY
X
X# Sorry, $* doesn't work in our version of make.
Xshar:	$(TARGET)1.shar $(TARGET)2.shar $(TARGET)3.shar $(TARGET)4.shar
X
X$(TARGET)1.shar: $(MISC)
X	$(SHAR) $(MISC) > $@ 
X
X$(TARGET)2.shar: $(HEADERS) $(MAKEFILE) 
X	$(SHAR) $(HEADERS) $(MAKEFILE) > $@ 
X
X$(TARGET)3.shar: $(SRC1)
X	$(SHAR) $(SRC1) > $@
X
X$(TARGET)4.shar: $(SRC2)
X	$(SHAR) $(SRC2) > $@
X
X#	List files updated since last listing
Xlist:	$(SOURCES) $(LIBSRC) $(HEADERS) $(MISC) $(MAKEFILE)
X	echo "`date` % $@ $?" >> $@
X	list $? &
X
Xci:	$(SHSRC) $(SOURCES) $(HEADERS) $(MISC) $(MAKEFILE)
X	ci -l -q $? </dev/null
X	echo "`date` % $@ $?" >> $@
X
Xrun:	$(TARGET)
X	./$(TARGET)
X
Xvi:
X	vi $(SOURCES) $(LIBSRC) $(HEADERS)
X
Xtags:	$(SOURCES) $(LIBSRC) $(HEADERS)
X	ctags $(SOURCES) $(LIBSRC) $(HEADERS)
X	
Xtidy:
X	rm -f $(OUTDTA) LOG core a.out junk* $(TSTFIL) $(TSTFIL).[0-9] $(TSTSH) 
X
Xclean:		tidy
X	rm -f $(OBJECTS) $(LIBOBJ) $(LIBRARY) testdata testdata.o
X
Xclobber:	clean
X	rm -f $(TARGET)
X
Xlint:
X	lint $(LINT) -hbx -lc $(SOURCES) $(LIBSRC) 2>&1 | tee LOG
X
Xinstall:	$(TARGET)
X	mv $(TARGET) $(INSTALL)
X	chmod 711 $(INSTALL)/$(TARGET)
X
Xerr:
X	error -v LOG
X
Xdepend:
X	sed -n -e '1,/^### DO NOT DELETE THIS LINE./p' < $(MAKEFILE) > $(MAKEFILE).new
X	-for i in $(YACCFILES) $(LEXFILES) $(SOURCES) $(LIBSRC) $(FFILES) ; do\
X		base=`expr $$i ':' '\(.*\).[cylf]$$'`;\
X		suffix=`expr $$i ':' '.*\.\([cylf]\)$$'`;\
X		if /bin/test $$suffix = l ; then\
X			lex $$i;\
X			mv lex.yy.c $$base.c;\
X			suffix=c;\
X			echo "$$base.c:	$$base.l" >> $(MAKEFILE).new;\
X		elif /bin/test $$suffix = y ; then\
X			yacc $(YFLAGS) $$i;\
X			mv y.tab.c $$base.c;\
X			suffix=c;\
X			echo "$$base.c:	$$base.y" >> $(MAKEFILE).new;\
X			echo "y.tab.h:	$$base.y" >> $(MAKEFILE).new;\
X		fi;\
X		$(CC) $(CLOCALFLAGS) -I$(INCLUDE) -E $$base.$$suffix |\
X		grep '^# [0-9][0-9]* ".*"$$' > /tmp/grep$$$$;\
X		sed -e 's/.*"\(.*\)"$$/\1/' -e 's/^.\///' < /tmp/grep$$$$ |\
X		sort -u |\
X		awk\
X			"BEGIN { line=\"$$base.o:	\"}\
X			{\
X				if(length(line \$$0)>63)\
X				{\
X					print line,\"\\\\\";\
X					line=\"		\"\$$0\
X				}\
X				else\
X					line=line\" \"\$$0\
X			}\
X			END { print line}"\
X		>> $(MAKEFILE).new;\
X	done;\
X	rm /tmp/grep$$$$
X	mv $(MAKEFILE).new $(MAKEFILE)
X### The following dependancies are/can be generated automatically
X### by 'make depend'. Listen to this warning
X###
X### Do NOT put any of your own dependancies below this line,
X### they will be removed
X### DO NOT DELETE THIS LINE. USED FOR MAKE DEPEND
Xmultivol.o:	 /usr/include/assert.h /usr/include/ctype.h \
X		/usr/include/signal.h /usr/include/stdio.h \
X		/usr/include/sys/param.h /usr/include/sys/types.h multivol.c \
X		multivol.h options.h trace.h
Xrd.o:	 /usr/include/assert.h /usr/include/stdio.h multivol.h rd.c \
X		trace.h
Xwr.o:	 /usr/include/assert.h /usr/include/ctype.h \
X		/usr/include/errno.h /usr/include/stdio.h \
X		/usr/include/sys/types.h multivol.h trace.h wr.c
Xvhdr.o:	 /usr/include/assert.h /usr/include/stdio.h \
X		/usr/include/sys/types.h multivol.h trace.h vhdr.c
Xmount.o:	 /usr/include/assert.h /usr/include/ctype.h \
X		/usr/include/stdio.h mount.c multivol.h trace.h
Xask.o:	 /usr/include/stdio.h ask.c
Xerror.o:	 /usr/include/stdio.h error.c
Xtrace.o:	 trace.c
Xbcopy.o:	 bcopy.c
!The!End!

echo x - "multivol.h" 2>&1
sed "s/^X//" >"multivol.h" <<'!The!End!'
X/* multivol  V1.00  5-Jun-85  Tony O'Hagan
X * multivol (8) - handle multivolume files
X * multivol.h 
X */
X#define PROGNAM	"multivol"
X#define VERSION "1.00"
X#include <assert.h>
X#include "trace.h"
X
X#define export		/* used to import/export globals */
X#define import	extern
X
X#define bool	short
X#define FALSE	0
X#define TRUE	1
X
X#define READ	0
X#define WRITE	1
X/*
X * The size of block & volume headers must be a multiple of
X * of 4 to keep the DMA controllers happy when asked to 
X * read or write a buffer, and to keep this multiple 
X * consistant for volumes being transfered between systems
X * which round up the size of structures to a mulitple of 4.
X */
X#define wd_size	4
X#define	wd_round(x) (( (x) + wd_size-1 ) & ~(wd_size-1))
X#define BHDSIZ	wd_round(sizeof(blk_hdr))	/* Block header size */
X#define VHDSIZ	wd_round(sizeof(vol_hdr))	/* Volume header size */
X#define MINBLK	wd_round(BHDSIZ + VHDSIZ + 1)	/* Minmum block size */
X
X#define	NOLIMIT	-1		/* used when no limit on blocks per volume */
X
X#define BEGBLK	'B'		/* blk_hdr->bh_blk_typ values */
X#define DTABLK	'D'
X#define ENDBLK	'E'
X
X	/* Unpacked volume header */
X#define NULVHD	((up_vhdr *)NULL)
Xtypedef struct {
X	int	up_vol_num;
X	long	up_siz_blk, up_lim_blk, up_timestamp;
X	char	up_prog_name[15], up_version[5], up_label[15];
X} up_vhdr ;
X
X	/* Volume header (all ascii) */
Xtypedef struct {
X	char	v_volnum[4],sp0;	/* "0001" */
X  	char	v_prog[14],sp1;		/* program name */
X	char	v_version[5],sp2;	/* Vn.nn */
X	char	v_label[14],sp3;	/* volume label */
X	char	v_timestamp[10],sp4;	/* binary time stamp */
X	char	v_siz_blk[6], sp5;	/* digits of physical block size */
X	char	v_lim_blk[6];		/* maximum no. of blocks per volume */
X	char	nullch;			/* Null ch placed by sprintf() */
X} vol_hdr;
X
X	/* used to pack/unpack volume headers */
X#define VHDFIELDS	7
X#define VHDPACK		"%4d %-14s %-5s %-14s %10ld %6ld %6ld" 
X#define VHDUNPACK	"%d %s %s %s %ld %ld %ld"
X
X	/* Block header */
Xtypedef struct {
X	char	bh_blktyp;	/* block type - indicates end of volume set */
X	char	bh_chksum;	/* block check sum */
X	char	bh_dtalen[6];	/* amount of data in the block */
X} blk_hdr;
!The!End!

echo x - "options.h" 2>&1
sed "s/^X//" >"options.h" <<'!The!End!'
X/*
X *	Option processing.
X *
X *	Conforms to intro(1) in System V.
X *
X *	Typical layout:
X *
X *		OPTIONS ("-b -t c -f file -w N file ...")
X *			FLAG	('b', flag)
X *			CHAR	('t', tab_ch)
X *			STRING	('f', filename)
X *				f = fopen(filename, "r");
X *			NUMBER	('w', width)
X *		ENDOPTS
X */
Xchar	*O_name, *O_usage;
X
Xvoid
Xusage()
X{
X	/*
X	 * Poor man's version of:
X	 *
X	 *	fprintf(stderr, "Usage: %s %s\n", O_name, O_usage);
X	 */
X	write(2, "Usage: ", 7);
X	write(2, O_name, strlen(O_name));
X	write(2, " ", 1);
X	write(2, O_usage, strlen(O_usage));
X	write(2, "\n", 1);
X	exit(1);
X}
X
X/*
X *	An argument "-" is interpreted as a program argument and stops
X *	option processing.
X *
X *	An argument "--" stops option processing and is discarded.
X *
X *	An option which takes an argument uses either the rest of the
X *	the current argument, or, if at the end of an argument, the
X *	next argument.
X */
X#define OPTIONS(usage)							\
X	O_usage = usage;						\
X	O_name = argv[0];						\
X	while (*++argv && **argv == '-' && argv[0][1]) {		\
X		register int O_cont = 1;				\
X									\
X		argc--;							\
X		if (argv[0][1] == '-' && argv[0][2] == '\0') {		\
X			argv++;						\
X			break;						\
X		}							\
X		while (O_cont)						\
X			switch (*++*argv) {				\
X			case '\0':					\
X				O_cont = 0;
X
X# define FLAG(c,flag)	break;						\
X			case c:						\
X				flag = 1;
X
X# define NUMBER(c,num)	break;						\
X			case c:						\
X				if (*++*argv == '\0') {			\
X					if (--argc == 0)		\
X						usage();		\
X					argv++;				\
X				}					\
X				num = atol(*argv);			\
X				O_cont = 0;
X
X# define STRING(c,str)	break;						\
X			case c:						\
X				if (*++*argv == '\0') {			\
X					if (--argc == 0)		\
X						usage();		\
X					argv++;				\
X				}					\
X				str = *argv;				\
X				O_cont = 0;
X
X# define CHAR(c,ch)	break;						\
X			case c:						\
X				if (*++*argv == '\0') {			\
X					if (--argc == 0)		\
X						usage();		\
X					argv++;				\
X				}					\
X				ch = **argv;				\
X				O_cont = 0;
X
X# define ENDOPTS	break;						\
X			default:					\
X				usage();				\
X			}						\
X	}								\
X	*--argv = O_name;
!The!End!

echo x - "trace.h" 2>&1
sed "s/^X//" >"trace.h" <<'!The!End!'
X/* use tracef() as tracef((tr, <format>, <format-args> ... )); */
X#ifdef DEBUG
X	extern int	tron;
X	extern char	tr[];
X#	define trace(step) strace(__FILE__, __LINE__, step)
X#	define tracef(step) {sprintf step; trace(tr);}
X#else
X#	define trace(step)
X#	define tracef(step)
X#endif
!The!End!
exit