[comp.sources.unix] v11i009: Buffered copy to/from physical devices

rs@uunet.UU.NET (Rich Salz) (08/14/87)

Submitted-by: <steinmetz!crdos1!davidsen>
Posting-number: Volume 11, Issue 9
Archive-name: bundle

These programs allow a physical device to be the head or end of a pipe,
allowing software which does not know about volumes to operate on
multi-volume sets, and improving the performance of programs such as
tar and cpio.  It works on systems with 16 bit ints such as PC/IX, Xenix,
and Microport.

bill davidsen		(davidsen@ge-crd.ARPA)
	ihnp4!seismo!rochester!steinmetz! \
				  chinet! ->--- crdos1!davidsen

[  Another spliced-in Makefile.  --r$  ]
#!/bin/sh
# shar+ created from directory /usr2/davidsen
echo 'x - bundle.1 (text)'
sed << 'E!O!F' 's/^X//' > bundle.1
X'\"  Copyright 1986,87 by Bill Davidsen. This code may be used for
X'\"  personal or commercial purposes. It may be freely distributed
X'\"  in source form providing this notice is kept intact.
X.TH bundle 1 Local
X'\" Heading: name(sect)    center (paren)    name(sect)
X.SH NAME
Xbundle \- buffer and copy \fIstdin\fR to a physicaql device
Xunbundle \- buffer and copy a physical device to \fIstdout\fR
X.SH SYNOPSIS
X\fBbundle\fR special dev_size buf_size
X.br
X\fBunbundle\fR special buf_size
X.SH DESCRIPTION
XThese programs allow a physical device to be the head or end of a pipe,
Xallows software which does not know about volumes to operate on
Xmulti-volume sets, and improves the performance of programs such as
X\fItar\fR and \fIcpio\fR.
X.P
X\fBSpecial\fR is the name of a raw device, such as /dev/rmt0.
X\fBdev_size\fR is the size of the device, given in bytes or kilobytes.
XWhen \fBdev_size\fR bytes have been written to the output device, the
Xoperator will be prompted for a media change. \fBBuf_size\fR is the size
Xof the buffer for the write or read. For tape this should be the desired
Xtape block size. For disk this should be a multiple of the size of a
Xtrack. For disk output writing a track at a time rather than sectors
Xcan reduce real time by a factor of three.
X.SH EXAMPLES
X  ls *.c | cpio -o | bundle /dev/rfp021 395k 5k
X  unbundle /dev/rfp021 5k | cpio -idm
X  tar cf - /usr/local | bundle /dev/rmt0 4000k 8k
X  unbundle /dev/rmt0 8k | tar cf -
X.SH WARNINGS
X\fIunbundle\fR reads to EOF on the input device. There is no way to read
Xonly part of a volume. If the \fBdev_size\fR is not a multiple of the
X\fBbuf_size\fR, bizarre errors may occur.
X.SH FILES
X/dev/\fBspecial\fR
X.SH SEE ALSO
Xtar, cpio.
X.SH AUTHOR
XBill Davidsen (ihnp4!chinet!crdos1!davidsen)
X'\" For more details, see man(7), as well as man(1), manroff(1), and mmt(1)
E!O!F
newsize=`wc -c < bundle.1`
if [ $newsize -ne 1832 ]
then echo "File bundle.1 was $newsize bytes, 1832 expected"
fi
echo 'x - bundle.c (text)'
sed << 'E!O!F' 's/^X//' > bundle.c
X/*****************************************************************
X |  Program name:  bundle.c
X |----------------------------------------------------------------
X |  accept standard input and write to a device named on the command
X |  line. The total bytes on the device and the buffer size are
X |  given on the command line. When the device is full, prompt
X |  for a new medium in the device and continue.
X |
X |  Command form:
X |   bundle device Dsize Bsize
X |----------------------------------------------------------------
X |  Author: Bill Davidsen, 8/16/86
X |  Version 1.6
X |  Last modified: 3/6/87
X |----------------------------------------------------------------
X |  Copyright 1986,87 by Bill Davidsen. This code may be used for
X |  personal or commercial purposes. It may be freely distributed
X |  in source form providing this notice is kept intact.
X *****************************************************************/
X
X#include <stdio.h>
X
X#ifdef DEBUG
X#define debug(f,v) fprintf(stderr, f, v)
X#else
X#define debug(f,v)
X#endif
X
Xstatic char *SCCS = "@(#) bundle 1.6";
X
Xmain (argc, argv)
X    int  argc;
X    char *argv[];
X{
X    char *buffer,		/* i/o buffer */
X         *malloc ();
X    register  long left;	/* room left in the buffer */
X    long  bufsize, devsize;	/* buffer and device size */
X    long  devleft = 0;		/* room left on device */
X    int  istat,			/* stdin read status */
X         ostat,			/* device write status */
X         dev,			/* device name from open */
X         MediaNum = 1;		/* sequential media # */
X    FILE *tty, *fopen ();
X    long getsize ();		/* get size from argument */
X
X /* validate arguments */
X    if (argc != 4)
X    { /* invalid */
X	printf ("Format:\n bundle device DevSize BufSize\n");
X	printf ("Where size may be bytes (as 5120) or k (as 5k)\n");
X	exit (1);
X    }
X
X    devsize = getsize (argv[2]);
X    debug ("Device size %ld", devsize);
X    bufsize = getsize (argv[3]);
X    debug (", buffer size %ld\n", bufsize);
X    if (devsize < 1 || devsize < bufsize)
X    { /* invalid specification of size */
X	printf ("Invalid buffer and/or device size\n");
X	exit (1);
X    }
X
X /* open the terminal for prompt */
X    tty = fopen ("/dev/tty", "r");
X    if (tty == NULL)
X    { /* mystery failure */
X	printf ("Unable to open /dev/tty for prompt\n");
X	exit (1);
X    }
X
X /* open the buffer */
X    buffer = malloc (bufsize);
X    debug ("Buffer allocated\n", 0);
X    if (buffer == NULL)
X    { /* can't mallocate */
X	printf ("Can't allocate space for the buffer\n");
X	exit (1);
X    }
X
X /* see if you can open the device */
X    printf ("Mount media #1 on %s and press RETURN", argv[1]);
X    while (getc (tty) != '\n');
X    dev = open (argv[1], 1);
X    if (dev < 0)
X    { /* invalid name */
X	printf ("Can't access device %s\n", argv[1]);
X	exit (1);
X    }
X    devleft = devsize; /* set media ready */
X    debug ("Enter copy loop\n\n", 0);
X
X /* main copy loop */
X    while (istat = fread (buffer, 1, (int) bufsize, stdin))
X    { /* until EOF */
X	debug ("Input read size %d\n", istat);
X
X	if (devleft < istat)
X	{ /* change media */
X	    close (dev);
X	    printf ("\007Mount media #%d on %s and press RETURN: ",
X		    ++MediaNum, argv[1]);
X	    while (getc (tty) != '\n');
X	    dev = open (argv[1], 1);
X	    devleft = devsize;
X	}
X
X    /* write the buffer */
X	ostat = write (dev, buffer, bufsize);
X	debug ("Output write size %d\n", ostat);
X
X	if (bufsize != ostat)
X	{ /* error on write */
X	    printf ("Error on device write!\n");
X	    exit (1);
X	}
X	devleft -= ostat;
X    }
X}
X
X/*
X |  Procedure:  getsize
X |-
X |  Convert the size string to bytes. If the last character is
X |  'k', multiply by 1024
X */
X
Xlong
Xgetsize (string)
X    char *string;
X{
X    register long  len = strlen (string),
X                   val = atol (string);
X
X    if (string[len - 1] == 'k')
X	val *= 1024;
X
X    return val;
X}
E!O!F
newsize=`wc -c < bundle.c`
if [ $newsize -ne 3803 ]
then echo "File bundle.c was $newsize bytes, 3803 expected"
fi
echo 'x - unbundle.c (text)'
sed << 'E!O!F' 's/^X//' > unbundle.c
X/*****************************************************************
X |  Program: unbundle
X |    accept input from a device and write to stdout
X |----------------------------------------------------------------
X |  Arguments:
X |   1) device name
X |   2) block size in bytes or k
X |  Version: 1.6
X |  Last modified: 3/6/87
X |----------------------------------------------------------------
X |  Copyright 1986,87 by Bill Davidsen. This code may be used for
X |  personal or commercial purposes. It may be freely distributed
X |  in source form providing this notice is kept intact.
X ****************************************************************/
X
X#include <stdio.h>
X
X#ifdef DEBUG
X#define debug(f,v) fprintf(stderr, f, v)
X#else
X#define debug(f,v)
X#endif
Xmain (argc, argv)
X    int  argc;
X    char *argv[];
X{
X    char *buf, *malloc ();
X    int  bufsize, dn, mnum = 1, ch, readsize;
X    static char *SCCSid = "@(#)unbundle 1.6";
X    long getsize ();		/* size of buffer */
X
X    if (argc != 3)
X    { /* bad calling sequence */
X	fprintf (stderr, "%s: wrong # of arguments\n", argv[0]);
X        fprintf (stderr, "Calling seq:\n  %s device bufsize\n", 
X                argv[0]);
X	exit (1);
X    }
X
X /* try to open the device */
X    dn = open (argv[1], 0);
X    if (dn < 0)
X    { /* open failed */
X	fprintf (stderr, "%s: can't open device %s\n", argv[0], argv[1]);
X	exit (1);
X    }
X    close (dn); /* so I can reopen */
X
X /* allocate the buffer */
X    bufsize = getsize (argv[2]);
X    debug ("Bufsize: %d\n", bufsize);
X
X    buf = malloc (bufsize);
X    if (buf == NULL)
X    { /* can't allocate the buffer */
X	fprintf (stderr, "Can't allocate %d byte buffer\n", bufsize);
X	exit (1);
X    }
X
X    for (;;)
X    { /* get a fresh mount and read it */
X	fprintf (stderr, "Mount input medium #%d on %s and press return: ",
X		mnum++, argv[1]);
X	read (0, &ch, 1);
X	open (argv[1], 0);
X
X	while (readsize = read (dn, buf, bufsize))
X	    write (1, buf, readsize);
X	close (dn);
X    }
X}
X
X/*
X |  Procedure:  getsize
X |-
X |  Convert the size string to bytes. If the last character is
X |  'k', multiply by 1024
X */
X
Xlong
Xgetsize (string)
X    char *string;
X{
X    register long  len = strlen (string),
X                   val = atol (string);
X
X    if (string[len - 1] == 'k')
X	val *= 1024;
X
X    return val;
X}
X
E!O!F
newsize=`wc -c < unbundle.c`
if [ $newsize -ne 2271 ]
then echo "File unbundle.c was $newsize bytes, 2271 expected"
fi

echo x - Makefile
sed -e 's/^X// >Makefile <\SHAR_EOF
#all:	bundle unbundle
#bundle:	bundle.c
#	$(CC) -o bundle $(CFLAGS) bundle.c
#unbundle:	unbundle.c
#	$(CC) -o unbundle $(CFLAGS) unbundle.c
#install:	all bundle.c
#	@echo Copy programs and manpage to appropriate directories
SHAR_EOF
echo No error check, lazy moderator...

-- 

Rich $alz
Cronus Project, BBN Labs			rsalz@bbn.com
Moderator, comp.sources.unix			sources@uunet.uu.net