cmv@cbnewsc.ATT.COM (C M Votava) (09/08/89)
In article <10922@fluke.COM> vince@tc.fluke.COM (Craig Johnson) writes: > >Craig Votava's dsplit sounded vaguely familiar to me, so a scrounged >around a bit and found the following two scripts which were first posted >by Corey Satten four years ago. These should perform the same functions >as dsplit. Give them a try and see how you like them. I've received lots of requests for the source to dsplit, so I'm posting it here. I appreciate Craig Johnson's reply, posting the shell script sources for accomplishing the same thing. I'm going to be working on version 2 of dsplit, so any suggestions you may have would be helpful. -Craig Votava att!ihlpz!cmv ============================== Cut Here ===================================== #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # Makefile # README # dsplit.c echo x - extracting shar sed 's/^X//' << 'SHAR_EOF' > Makefile X#sccs "@(#)Makefile 1.1" X X# This makefile is an attempt at a general makefile template. The X# TARGETS variable is a list of all targets that you want to build. X# The LINKS variable is a list of all .o files needed by all targets. X# The HEADS variable is a list of all .h files needed by all targets. X# The commented out CC line is what you replace the LD line when you X# want to create sdb-able output. You will also need to use the commented X# out CFLAGS line for the sdb-able output too. X# 6/21/89 -- cmv X Xinclude $(MAKEINC)/Makepre.h X X# CFLAGS=-68010 -v -g X XTARGETS=dsplit XLINKS= XHEADS= X XDEPENDTS=$(HEADS) $(LINKS) X Xall: $(TARGETS) X X$(TARGETS): $(DEPENDTS) $$@.o X $(LD) $(LDFLAGS) $(SHAREDLIB) $(LINKS) -o $@ $@.o X X# $(CC) -lg -o $@ $@.o SHAR_EOF echo x - extracting shar sed 's/^X//' << 'SHAR_EOF' > README X# @(#)README 1.2 X XThis is the "dsplit" (device split) command, it's used to split output Xover multiple removable media. Let's say, for example that you want to Xback up your hard disk to a bunch of floppies. Using "dsplit" in the Xfollowing way will save you a BUNCH of floppies: X X $ find . -print | cpio -ocv | compress -c | dsplit -o X XTo restore your files from your set of backup floppies, try the command: X X $ dsplit -i | uncompress -c | cpio -icduv X XThe syntax for the "dsplit" command is: X X USAGE: dsplit [-i (default) | -o] [-v] [-d /dev/device] X XWhere: X -i Input from device, pipe to stdout (default) X -o Input from stdin, pipe to device X -v Print lots of meaningless messages X -d /dev/* Device to use (default is /dev/rfp021) X XREMEMBER: The good news about using "dsplit" with "cpio" and "compress" is Xthat you can save a lot of floppies on a backup, but the bad news is that Xif you "lose" even one bit, due to media degradation, the rest of the Xbackup from that point on is garbage! X XThe "dsplit" command has a buffer size of 5120 bytes, similar to using Xthe "-B" command on cpio. However, unlike cpio, it will write partial Xbuffers (in 512 byte chunks) up to the very end of the media, before Xgoing on to the next media. X XI've tried to make the command versatile enough for you brave souls out Xthere to use it in new and different ways. Let me know when you find bugs, Xso that I can keep a master copy up to date. Also, let me know of the Xstrange new ways you find it useful. X XFuture versions of "dsplit" may have such things as: X [ My last minute comments are in brackets -- cmv ] X X[ 0.) A man page - Ok, so I'm a lazy documentator, so sue me! -- cmv ] X X 1.) Disk numbering - Similar to the disk numbering that "cpio" gives X you when you output to a floppy. The VHB for floppies on the X unixpc include a spot for cpio disk numbering. X [ This is machine dependent though -- cmv ] X X 2.) Variable buffer size - So you'll be able to specify the size of X buffer you want. This makes writing the floppy go faster, X but the limiting factor really is using "compress" in the X pipeline. I'll leave it as an exercise for the reader to X come up with the optimal buffer size. Needless to say, the X buffer will be dynamically allocated too. X X 3.) I might take out that rotten "sleep" call that attempts to wait X for the pipe to back up before prompting the user for the X next media. The time needed seems to vary by a lot, and I X don't mind seeing file names printed after the prompt! X [ Let me know what you think! -- cmv ] X X 4.) Other neat tricks that people suggest to me, that I like. X [ Pete Fales had ported this to the AT&T 6386 with ] X [ one small change, delete the "#sccs" line. Let me ] X [ know what other machines it gets ported to! -- cmv ] X XBugs: X X 1.) Well, this is kind of a bug. When you eject the floppy while X writing is in progress, the driver thinks it's reached X the end of the media and asks you for the next one. The X only solution that I can come up with for now is X "Don't do this"! X [ The next version will solve this problem ] X [ by checking errno. Thanks Pete! -- cmv ] X X 2.) When you hit <cr> a bunch of times, before you are prompted X to change your media, those <cr's> are buffered, and used X against you after the prompt. I'd like to have the code X clear away all of the buffered input just before I output X the prompt, but I can't think of an easy way to do this X (fflush doesn't seem to work right) any suggestions? X [ Never mind, Pete Fales answered this one ] X [ for me, it'll be in the next release. -- cmv ] X X[ Have fun, and send me mail! I like getting mail! -- cmv ] X XCraig Votava X[att!]ihlpz!cmv SHAR_EOF echo x - extracting shar sed 's/^X//' << 'SHAR_EOF' > dsplit.c X#sccs "@(#)dsplit.c 1.2" X X/* This command can either read from or write to the floppy */ X/* disk, allowing for multi-volume files. It reads/writes to */ X/* stdout/stdin at the other side. */ X/* 6/25/89 -- cmv */ X X#include <stdio.h> X#include <fcntl.h> X X#define PUSAGE "\tUSAGE: %s [-i (default) | -o] [-v] [-d /dev/device]\n",argv[0] X X#define FLOPPY "/dev/rfp021" X#define BUFF_SZ 5120 /* Buffer size */ X X#define INCOMING 10 X#define OUTGOING 11 X X#define STDIN 0 X#define STDOUT 1 X X/* Some stuff to shut lint up */ Xchar *strcpy(); Xvoid perror(), exit(); Xunsigned sleep(); X X/* Some global variables... */ Xchar Udevice[50]; /* device to use, it seemed */ X /* like a good idea at the */ X /* time to make this global.*/ X Xint Debug=0; /* Global Debug Flag */ Xint Count=2; /* media count */ Xextern int errno; X X/* X * Main routine - It's job is to handle command line options, setup I/O X * file descriptors, and loop doing reads and writes until the job X * is completed. X */ X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X extern int optind; X extern char *optarg; X X register int ret; /* input return code */ X register int i; X X int errflg=0; /* error flag */ X int c; /* Options processing */ X int ofd; /* output file descriptor */ X int ifd; /* input file descriptor */ X X short direction=INCOMING; /* Direction flag */ X X unsigned char buff[BUFF_SZ]; /* Output buffer in bytes */ X int bsize=BUFF_SZ; /* buffer size */ X X X /* Catch signals??? */ X X /* setup default device */ X strcpy(Udevice,FLOPPY); X X while((c = getopt(argc,argv,"?iovd:"))!=EOF) X { X switch(c) X { X case 'i': X direction=INCOMING; X break; X case 'o': X direction=OUTGOING; X break; X case 'd': X strcpy(Udevice,optarg); X if(Debug) X fprintf(stderr, X "Using device %s\n",Udevice); X break; X case 'v': X Debug++; X if(Debug) X fprintf(stderr,"Debug is on...\n"); X break; X case '?': X errflg++; X break; X default: X fprintf(stderr, X "ASSERT1 - should never be here\n"); X errflg++; X break; X } X } X if(errflg!=0) X { X fprintf(stderr,PUSAGE); X exit(1); X } X X /* Check for input file name error conditions */ X if(optind>argc) X { X fprintf(stderr,"Extra gunk on the command line...\n"); X fprintf(stderr,PUSAGE); X exit(-1); X } X X /* Set up the file descriptors for the given direction */ X if(setup_io(&ifd,&ofd,direction) < 0) X { X if(Debug) X fprintf(stderr,"setup_io errno=%d\n",errno); X fprintf(stderr,"Trouble setting up I/O, goodbye...\n"); X exit(-1); X } X X do { X /* Fill up a buffer full of data */ X if((ret=fill_buff(buff,bsize,&ifd,direction))<0) X { X fprintf(stderr,"read ret=%d errno=%d\n",ret,errno); X perror("Read"); X ret=EOF; X } X X if(ret>0) X { X if((ret=drain_buff(buff,ret,&ofd,direction))<0) X { X fprintf(stderr,"write ret=%d errno=%d\n", X ret,errno); X perror("Write"); X ret=EOF; X } X } X /* A '0' return from fill_buff means EOF */ X else X ret=EOF; X X if(Debug) X fprintf(stderr,"ret=%d\n",ret); X X for(i=0;i<BUFF_SZ;i++) X buff[i]=0; X X } while(ret!=EOF); X X /* close up shop */ X close(ifd); X close(ofd); X X if(Debug) X fprintf(stderr,"EOF\n"); X X return(0); X} X X/* X * setup_io - It's job is to setup the file descriptors, and open X * appropriate devices, depending on the direction of the I/O X * passed from main. Information messages are printed for any X * errors, and the error codes passed back to main. X */ X Xint Xsetup_io(ifd,ofd,direction) Xint *ifd; /* input file descriptor */ Xint *ofd; /* output file descriptor */ Xshort direction; /* Direction flag */ X{ X /* If we're reading from the Udevice... */ X if(direction==INCOMING) X { X /* Duplicate stdout for output */ X if((*ofd = dup(STDOUT)) < 0) X { X if(Debug) X fprintf(stderr,"dup errno=%d\n",errno); X perror("dup of stdout"); X return(*ofd); X } X /* Open Udevice for input */ X if((*ifd = open(Udevice,O_RDONLY)) < 0) X { X if(Debug) X fprintf(stderr,"open errno=%d\n",errno); X perror("input device open"); X return(*ifd); X } X } X else /* Writing to the Udevice */ X { X /* Duplicate stdin for input */ X if((*ifd = dup(STDIN)) < 0) X { X if(Debug) X fprintf(stderr,"dup errno=%d\n",errno); X perror("dup of stdin"); X return(*ifd); X } X /* Open Udevice for output */ X if((*ofd = open(Udevice,O_RDWR)) < 0) X { X if(Debug) X fprintf(stderr,"open errno=%d\n",errno); X perror("output device open"); X return(*ofd); X } X } X return(0); X} X X/* X * fill_buff - It's job is to fill up an entire buffer with data. X * The direction indicates the general direction of the command so X * we can decide when to reload media. Upon errors, appropriate messages X * are printed out, and status is returned to the calling program. X */ X Xint Xfill_buff(buff,size,fd,direction) Xunsigned char *buff; /* Pointer to buffer */ Xint size; /* buffer size */ Xint *fd; /* File descriptor */ Xshort direction; /* direction flag */ X{ X X register int ret=0; /* return value */ X register int bytes=0; /* total number of bytes read */ X X while(bytes<size) X { X /* size-bytes MUST (should) allways be a multiple of 512 here */ X if((ret=read(*fd,(char *)&buff[bytes],size-bytes))<=0) X { X if(((ret==-1)||(ret==0))&&(direction==INCOMING)) X { X if((ret = reload(fd))<0) X { X fprintf(stderr,"reload error\n"); X return(ret); X } X if((ret=read(*fd,(char *)&buff[bytes], X size-bytes))<=0) X { X fprintf(stderr,"read - I give up...\n"); X return(ret); X } X } X else if(ret==0) X { X /* This handles the case where we read in less X * than a buffer full, then got EOF. We need to X * return the amount of good buffer there is X * left, next time around we'll send back EOF. X */ X if(bytes>0) X { X if(Debug) X fprintf(stderr, X "End Partial Buffer %d\n", X bytes); X return(bytes); X } X else X { X if(Debug) X fprintf(stderr, X "Returning EOF\n"); X return(0); X } X } X /* We should never get here... */ X else X { X fprintf(stderr,"ASSERT2 - ret=%d \n",ret); X perror("Read"); X return(ret); X } X X } X bytes+=ret; X if(Debug) X fprintf(stderr,"read in %d bytes total=%d\n", X ret,bytes); X } X X return(bytes); X} X X/* X * drain_buff - It's job is to empty out an entire buffer of data. X * The direction indicates the general direction of the command so X * we can decide when to reload media. Upon errors, appropriate messages X * are printed out, and status is returned to the calling program. X */ X Xint Xdrain_buff(buff,size,fd,direction) Xunsigned char *buff; /* Pointer to buffer */ Xint size; /* buffer size */ Xint *fd; /* File descriptor */ Xshort direction; /* direction flag */ X{ X X register int ret=0; /* return value */ X register int bytes=0; /* total number of bytes read */ X X while(bytes<size) X { X /* size-bytes MUST (should) allways be a multiple of 512 here */ X if((ret=write(*fd,(char *)&buff[bytes],size-bytes))<=0) X { X if(((ret==-1)||(ret==0))&&(direction==OUTGOING)) X { X if((ret = reload(fd))<0) X { X fprintf(stderr,"reload error\n"); X return(ret); X } X if((ret=write(*fd,(char *)&buff[bytes], X size-bytes))<=0) X { X fprintf(stderr, X "write - I give up...\n"); X return(ret); X } X } X else if(ret==0) X { X if(Debug) X fprintf(stderr,"Returning EOF\n"); X return(ret); X } X /* We should never get here... */ X else X { X fprintf(stderr,"ASSERT3 - ret=%d \n",ret); X perror("Write"); X return(ret); X } X X } X bytes+=ret; X if(Debug) X fprintf(stderr,"wrote out %d bytes total=%d\n", X ret,bytes); X } X X return(bytes); X} X X/* X * reload - It's job is to have the user reload the media. X * This routine will not return until a successful open on the X * new media is returned. X */ X Xint Xreload(fd) Xint *fd; X{ X register int ret; /* return value */ X X /* Close current device */ X close(*fd); X X /* Wait for the pipe to back up... */ X sleep(2); X X do { X /* Have user reload... */ X if((ret=prompt_user())<0) X { X fprintf(stderr,"Can't prompt user, goodbye...\n"); X break; X } X X } while((*fd = ret = open(Udevice,O_RDWR)) < 0); X X Count++; /* Bump up media count */ X return(ret); X} X X/* X * prompt_user - It's job is handle prompting the user for the response X * when fresh media is installed. X * Informative messages are printed upon error, and the error codes are X * returned to the calling proceedure. X */ X Xint Xprompt_user() X{ X register int ret=0; X char kib[22]; /* keyboard input buffer */ X FILE *keybd; /* keyboard input */ X X /* Talk to user */ X keybd = fopen("/dev/tty", "r"); X X fprintf(stderr, X "\nReload with fresh media number %d, hit return when ready...\n\n" X ,Count); X X fgets(kib, 20, keybd); X X /* in case we wanna look at what the kid typed... X kib[strlen(kib) - 1] = '\0'; X */ X X fclose(keybd); X X return(ret); X} SHAR_EOF exit