[alt.sources] Bundle 1.1

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (01/03/90)

  This is an intermediate version of the "bundle" program I released
many years ago. What bundle does is to assist when sending stdout to a
multivolume device (like backing up to floppy). This is NOT the final
version, please don't redistribute it, I'll put the real thing out in a
few days unless people have trouble with this one.

  To use: for floppy the buffer size should be one cylinder. This can
reduce the realtime to do a dump by a factor of two. You will get
prompted to mount each new volume. There's a man page...

:
#!/bin/sh
# shar+ created from directory /u/davidsen/tmp/unpack
# 13:30 on Tue Jan 02, 1990 by wed
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.7
X |  Last modified: 1/2/90
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.7";
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    int pipex[2];               /* pipe for double buffering */
X    int wklen;			/* working pie read length */
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    /* open the pipe */
X    if (pipe(pipex)) {
X        fprintf(stderr, "Can't open pipe for double buffering\n");
X        exit(1);
X    }
X
X    if (fork() == 0) {
X        /* child - copy stdin to pipe */
X        for (wklen = 0;
X	    (istat = read(0, buffer+wklen, (int)(bufsize - wklen))) > 0 
X	        || wklen;
X	) {
X	    if (istat > 0) wklen += istat;
X            debug("Child read %5d bytes\n", istat);
X	    debug("  buffer has %d bytes\n", wklen);
X
X            /* output the size read, then the data */
X            if (istat <= 0 || wklen == bufsize) {
X	        write(pipex[1], (char *)&wklen, sizeof(int));
X                if (write(pipex[1], buffer, wklen) != wklen) {
X                    fprintf(stderr, "Child can't write pipe!\n");
X                    exit(1);
X                }
X                else debug("Child wrote %d bytes\n", wklen);
X	        wklen = 0;
X            }
X        }
X
X        /* output a size of zero */
X	istat = 0;
X	write(pipex[1], (char *)&istat, sizeof(int));
X    }
X    else {
X        /* main copy loop */
X        while (read(pipex[0], (char *)&istat, sizeof(int)), istat) {
X            /* show the size factor and read those bytes */
X    	    debug ("Input read size %d\n", istat);
X	    for (wklen = 0; wklen < istat; ) {
X	    	wklen += read(pipex[0], buffer+wklen, istat-wklen);
X	    }
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    exit(0);
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 5384 ]
then echo "File bundle.c was $newsize bytes, 5384 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 - buntest.c (text)'
sed << 'E!O!F' 's/^X//' > buntest.c
X/* 
X *  generate NNk of crap data, read from argv[1]
X *
X *  if the nap() call is not available don't use the 2nd arg
X *  and don't define HAS_NAP
X */
X
X#include <stdio.h>
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int size;					/* size to output, in k */
X	int havedone = 0;			/* already done */
X#if		HAS_NAP
X	int pause = 0;				/* time to pause between writes */
X#endif
X
X	char junkbuf[1024];			/* buffer of junk values */
X
X	if (argc < 2) {
X		fprintf(stderr, "No size!\n");
X		fprintf(stderr,"\nFormat:\n  buntest nn [ k/sec]\n");
X		exit(1);
X	}
X
X	size = atoi(argv[1]);
X#if		HAS_NAP
X	if (argc > 2) {
X		/* get the kb/sec data rate to supply */
X		pause = 1000/atoi(argv[2]);
X	}
X#endif
X
X	/* output loop */
X	for (havedone = 0; havedone < size; havedone++) {
X		write(1, junkbuf, 1024);
X#if		HAS_NAP
X		if (pause) nap(pause);
X#endif
X	}
X
X	exit(0);
X}
E!O!F
newsize=`wc -c < buntest.c`
if [ $newsize -ne 839 ]
then echo "File buntest.c was $newsize bytes, 839 expected"
fi
echo 'x - bundle.1 (text)'
sed << 'E!O!F' 's/^X//' > bundle.1
X'\"  Copyright 1986,87,90 by Bill Davidsen. This code may be used for
X'\"  personal or commercial purposes. It may be freely distributed
X'\"  in unmodified source form providing this notice is kept intact.
X.TH bundle 1 (v1.1)
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 (davidsen@crdos1.crd.ge.com)
X.SH COPYRIGHT
XCopyright 1986,87,90 by Bill Davidsen, all rights reserved. This program
Xmay be distributed in any manner providing that further distribution is
Xnot restricted and the package is kept intact. Modified versions must
Xinclude the original source and documentation.
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 2121 ]
then echo "File bundle.1 was $newsize bytes, 2121 expected"
fi
echo 'x - Makefile (text)'
sed << 'E!O!F' 's/^X//' > Makefile
X# makefile for bundle items v%I% %G%
X
X# distribution and source files
XDIST	= bundle.c unbundle.c buntest.c bundle.1 Makefile
XSCCS	= s.bundle.c s.unbundle.c s.Makefile s.bundle.1
X
X# which shar to use
XSHAR	= shar
X
X# makerule for SCCS which doesn't leave writable files on error
X.c~.c:
X	get $?
X
X# start makeing here
X
Xall		: bundle unbundle
X
Xtest		: all buntest
X
Xbundle		: bundle.o
X	$(CC) -o bundle bundle.o
X
Xunbundle	: unbundle.o
X	$(CC) -o unbundle unbundle.o
X
Xbuntest		: buntest.o
X	$(CC) -o buntest buntest.o
X
Xshar		: bundle.shar
Xbundle.shar	: $(DIST)
X	shar $(DIST) > bundle.shar
X
Xzoo		: $(SCCS)
X	zoo aunPP bundle.zoo $?
E!O!F
newsize=`wc -c < Makefile`
if [ $newsize -ne 619 ]
then echo "File Makefile was $newsize bytes, 619 expected"
fi
exit 0

-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon