Dsplit - splitting files across multiple floppies
C M Votava
cmv at cbnewsc.ATT.COM
Sat Oct 28 02:48:26 AEST 1989
Here is the source for dsplit. It's a command that allows you to split
files across multiple hard disks. For more information, see the README
file included in this shar.
-Craig Votava
att!ihlpf!cmv
att!ihlpm!cmv
att!cbnewsc!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
More information about the Unix-pc.sources
mailing list