[comp.os.minix] BUNDLE for Minix

nispa@hutcs.hut.fi (Tapani Lindgren) (02/23/88)

In article <46400003@ztivax.UUCP> freizeit@ztivax writes:
>
>Subject : Backup for HD asked
>
>if anyone has an easy way to backup the harddisk onto floppy
>(for instance  a version of tar which asks for a new floppy
>when the old is full) sent it to the audience  or to
>
We use PD-TAR with Bill Davidsen's BUNDLE.
Here is a version of BUNDLE tuned for MINIX.

PS. We could'n't make pipes work with block sizes larger than 7K.
Is there a BUG in Minix? (No, that would be impossible:-)
If somebody has a fix, please let the world know!

---- CUT HERE -----

#!/bin/sh

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# README Makefile bundle.1 bundle.h bundle.c unbundle.c

echo x - README
cat > "README" << '//E*O*F README//'
BUNDLE is a program that reads its standard input and writes it to
a named special file in [Bsize]-byte blocks.
When [Dsize] bytes have been written, bundle prompts for a new volume.

UNBUNDLE does the opposite, eg. prompts for volumes, reads them, and
writes to standard output.

These programs are designed to be used with programs like tar, that
produce a long stream of data, but don't know about volumes.
Usage: "tar something | bundle [ device [ Dsize [ Bsize ]]]"
or "unbundle [ device [ Dsize [ Bsize ]]] | tar something".
See included manual page for more information.

Bundle and Unbundle, version 1.6, were written by Bill Davidsen
in August 1987, and modified for Minix Operating System by
Tapani Lindgren (nispa@hutcs.hut.fi) and Pertti Kasanen
(ptk@hutcs.hut.fi) in January 1988.

We added a possibility to omit the arguments so the program should
be easier to use.  Default device names and sizes are provided for
Minix with either 360K or 1.2M drives and Vaxes with a TS-11.

We use Bundle with PD-TAR, posted to net some time ago. Minix tar
cannot be used, since it cannot use standard input/output as the
tar file.

WARNING
There is a "feature" in Minix file system that limits the usability of
this and similiar programs: if pipes are read or written in too large
hunks, the data gets lost without warning.  We haven't figured out the
reason yet.  Instead, we try to avoid the problem by using block sizes
smaller than 7K.

	Tapani Lindgren
//E*O*F README//

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
CFLAGS = -DMINIX -DAT

all: bundle unbundle

bundle: bundle.c bundle.h
	cc $(CFLAGS) -o bundle -O bundle.c

unbundle: unbundle.c bundle.h
	cc $(CFLAGS) -o unbundle -O unbundle.c

install: all
	cp bundle unbundle /usr/local/bin
	cp bundle.1 /usr/local/man
	rm /usr/local/man/unbundle.1
	ln /usr/local/man/bundle.1 /usr/local/man/unbundle.1
	-ln -s /usr/local/man/bundle.1 /usr/man/man1
	-ln -s /usr/local/man/unbundle.1 /usr/man/man1

clean:
	rm core *.o bundle unbundle *~
//E*O*F Makefile//

echo x - bundle.1
cat > "bundle.1" << '//E*O*F bundle.1//'
'\"  Copyright 1986,87 by Bill Davidsen. This code may be used for
'\"  personal or commercial purposes. It may be freely distributed
'\"  in source form providing this notice is kept intact.
.TH bundle 1 Local
'\" Heading: name(sect)    center (paren)    name(sect)
.SH NAME
bundle \- buffer and copy \fIstdin\fR to a physicaql device
unbundle \- buffer and copy a physical device to \fIstdout\fR
.SH SYNOPSIS
\fBbundle\fR special dev_size buf_size
.br
\fBunbundle\fR special buf_size
.SH DESCRIPTION
These programs allow a physical device to be the head or end of a pipe,
allows software which does not know about volumes to operate on
multi-volume sets, and improves the performance of programs such as
\fItar\fR and \fIcpio\fR.
.P
\fBSpecial\fR is the name of a raw device, such as /dev/rmt0.
\fBdev_size\fR is the size of the device, given in bytes or kilobytes.
When \fBdev_size\fR bytes have been written to the output device, the
operator will be prompted for a media change. \fBBuf_size\fR is the size
of the buffer for the write or read. For tape this should be the desired
tape block size. For disk this should be a multiple of the size of a
track. For disk output writing a track at a time rather than sectors
can reduce real time by a factor of three.
.P
If arguments are omitted, system defaults are used.  For minix these
\fB/dev/at0, 1200k\fR and \fB15k\fR (device name, device size and
buffer size, respectively). 
.SH EXAMPLES
  ls *.c | cpio -o | bundle /dev/rfp021 395k 5k
  unbundle /dev/rfp021 5k | cpio -idm
  tar cf - /usr/local | bundle /dev/rmt0 4000k 8k
  unbundle /dev/rmt0 8k | tar cf -
.SH WARNINGS
\fIunbundle\fR reads to EOF on the input device. There is no way to read
only part of a volume. If the \fBdev_size\fR is not a multiple of the
\fBbuf_size\fR, bizarre errors may occur.
.SH FILES
/dev/\fBspecial\fR
.SH SEE ALSO
tar, cpio.
.SH AUTHOR
Bill Davidsen (ihnp4!chinet!crdos1!davidsen)
'\" For more details, see man(7), as well as man(1), manroff(1), and mmt(1)
//E*O*F bundle.1//

echo x - bundle.h
cat > "bundle.h" << '//E*O*F bundle.h//'
/* definitions for bundle and unbundle */

#include <stdio.h>

#ifdef DEBUG
# define debug(f,v) fprintf(stderr, f, v)
#else
# define debug(f,v)
#endif

#define K <<10L /* kilobytes */

#ifdef MINIX
# ifdef XT
#  define DEF_DNAME "/dev/fd0"
#  define DEF_DSIZE (360 K)
#  define DEF_BSIZE (6 K)      /* should be 9, but minix pipes are too short */
# else
#  define DEF_DNAME "/dev/at0"
#  define DEF_DSIZE (1200 K)
#  define DEF_BSIZE (6 K)      /* should be 15, but minix pipes are too short */
# endif
#endif
#ifdef BSD
# ifdef VAX
#  define DEF_DNAME "/dev/rmt8"
#  define DEF_DSIZE (40000 K)
#  define DEF_BSIZE (20 K)
# endif
#endif

//E*O*F bundle.h//

echo x - bundle.c
cat > "bundle.c" << '//E*O*F bundle.c//'
/*****************************************************************
 |  Program name:  bundle.c
 |----------------------------------------------------------------
 |  accept standard input and write to a device named on the command
 |  line. The total bytes on the device and the buffer size are
 |  given on the command line. When the device is full, prompt
 |  for a new medium in the device and continue.
 |
 |  Command form:
 |   bundle [ device [ Dsize [ Bsize ]]]
 |----------------------------------------------------------------
 |  Author: Bill Davidsen, 8/16/86
 |  Version 1.6
 |  Last modified: 3/6/87
 |  Version 1.6M for Minix Operating System
 |  Modified by Tapani Lindgren <nispa@hutcs.hut.fi> 87-12-28
 |----------------------------------------------------------------
 |  Copyright 1986,87 by Bill Davidsen. This code may be used for
 |  personal or commercial purposes. It may be freely distributed
 |  in source form providing this notice is kept intact.
 *****************************************************************/

#include "bundle.h"

static char *SCCS = "@(#) bundle 1.6M";
     
     usage()
{
  fprintf (stderr, "Usage:\n bundle [ device [ DevSize [ BufSize ]]]\n");
  fprintf (stderr, "Where size may be bytes (as 5120) or k (as 5k)\n");
  exit (1);
}

main (argc, argv)
     int  argc;
     char *argv[];
{
  char *devname;		/* device name */
  char *buffer,		/* i/o buffer */
  *malloc ();
  register  long left;	/* room left in the buffer */
  long  bufsize, devsize;	/* buffer and device size */
  long  devleft = 0;		/* room left on device */
  int  istat,			/* stdin read status */
  ostat,			/* device write status */
  dev,			/* device name from open */
  MediaNum = 1;		/* sequential media # */
  FILE *tty, *fopen ();
  long getsize ();		/* get size from argument */
  
  /* validate arguments */
  if (argc > 4) usage();
  
  if (argc > 1) devname = argv[1]; else devname = DEF_DNAME;
  if (argc > 2) devsize = getsize (argv[2]); else devsize = DEF_DSIZE;
  debug ("Device size %ld", devsize);
  if (argc > 3) bufsize = getsize (argv[3]); else bufsize = DEF_BSIZE;
  debug (", buffer size %ld\n", bufsize);
  if (devsize < 1 || devsize < bufsize)
    { /* invalid specification of size */
      fprintf (stderr, "Invalid buffer and/or device size\n");
      exit (1);
    }
  
  /* open the terminal for prompt */
  tty = fopen ("/dev/tty", "r");
  if (tty == NULL)
    { /* mystery failure */
      fprintf (stderr, "Unable to open /dev/tty for prompt\n");
      exit (1);
    }
  
  /* open the buffer */
  buffer = malloc (bufsize);
  debug ("Buffer allocated\n", 0);
  if (buffer == NULL)
    { /* can't mallocate */
      fprintf (stderr, "Can't allocate space for the buffer\n");
      exit (1);
    }
  
  /* see if you can open the device */
  fprintf (stderr, "Mount media #1 on %s and press RETURN\n", devname);
  while (getc (tty) != '\n');
  dev = open (devname, 1);
  if (dev < 0)
    { /* invalid name */
      fprintf (stderr, "Can't access device %s\n", devname);
      exit (1);
    }
  devleft = devsize; /* set media ready */
  debug ("Enter copy loop\n\n", 0);
  
  /* main copy loop */
  while (istat = fread (buffer, 1, (int) bufsize, stdin))
    { /* until EOF */
      debug ("Input read size %d\n", istat);
      
      if (devleft < istat)
	{ /* change media */
	  close (dev);
	  fprintf (stderr, "\007Mount media #%d on %s and press RETURN\n",
		  ++MediaNum, devname);
	  while (getc (tty) != '\n');
	  dev = open (devname, 1);
	  devleft = devsize;
	}
      
      /* write the buffer */
      ostat = write (dev, buffer, bufsize);
      debug ("Output write size %d\n", ostat);
      
      if (bufsize != ostat)
	{ /* error on write */
	  fprintf (stderr, "Error on device write!\n");
	  exit (1);
	}
      devleft -= ostat;
    }
}

/*
  |  Procedure:  getsize
  |-
  |  Convert the size string to bytes. If the last character is
  |  'k', multiply by 1024
  */

long
  getsize (string)
char *string;
{
  register int  len = strlen (string);
  register long val = atol (string);
  
  if (string[len - 1] == 'k')
    val *= 1024;
  
  return val;
}
//E*O*F bundle.c//

echo x - unbundle.c
cat > "unbundle.c" << '//E*O*F unbundle.c//'
/*****************************************************************
  |  Program: unbundle
  |    accept input from a device and write to stdout
  |----------------------------------------------------------------
  |  Arguments:
  |   1) device name
  |   2) block size in bytes or k
  |  Version: 1.6
  |  Last modified: 3/6/87
  |  Modified 87-12-28 by Tapani Lindgren <nispa@hutcs.hut.fi>
  |----------------------------------------------------------------
  |  Copyright 1986,87 by Bill Davidsen. This code may be used for
  |  personal or commercial purposes. It may be freely distributed
  |  in source form providing this notice is kept intact.
  ****************************************************************/

#include "bundle.h"

usage()
{ /* bad calling sequence */
  fprintf (stderr, "Usage:\n  unbundle [ device [ bufsize ]]\n");
  exit (1);
}

main (argc, argv)
     int  argc;
     char *argv[];
{
  char *devname;
  char *buf, *malloc ();
  int  bufsize, dn, mnum = 1, ch, readsize;
  static char *SCCSid = "@(#)unbundle 1.6";
  long getsize ();		/* size of buffer */
  FILE *tty, *fopen();

  if (argc > 3) usage();
  
  /* try to open the device */
  if (argc > 1) devname = argv[1]; else devname = DEF_DNAME;
  dn = open (devname, 0);
  if (dn < 0)
    { /* open failed */
      fprintf (stderr, "%s: can't open device %s\n", argv[0], devname);
      exit (1);
    }
  close (dn); /* so I can reopen */
  
  /* allocate the buffer */
  if (argc > 2) bufsize = getsize (argv[2]); else bufsize = DEF_BSIZE;
  debug ("Bufsize: %d\n", bufsize);
  if (bufsize < 1) usage();
  
  buf = malloc (bufsize);
  if (buf == NULL)
    { /* can't allocate the buffer */
      fprintf (stderr, "Can't allocate %d byte buffer\n", bufsize);
      exit (1);
    }

  /* open the terminal for prompt */
  tty = fopen ("/dev/tty", "r+");
  if (tty == NULL)
    { /* mystery failure */
      fprintf (stderr, "Unable to open /dev/tty for prompt\n");
      exit (1);
    }
  
  for (;;)
    { /* get a fresh mount and read it */
      fprintf (stderr, "\007Mount media #%d on %s and press RETURN: ",
	       mnum++, devname);
      read(0, &ch, 1); 

      dn = open (devname, 0);
      
      while (readsize = read (dn, buf, bufsize)) {
	write (1, buf, readsize);
	}
      close (dn);
    }
}

/*
  |  Procedure:  getsize
  |-
  |  Convert the size string to bytes. If the last character is
  |  'k', multiply by 1024
  */

long
  getsize (string)
char *string;
{
  register int  len = strlen (string);
  register long val = atol (string);
  
  if (string[len - 1] == 'k')
    val *= 1024;
  
  return val;
}




//E*O*F unbundle.c//

exit 0

roskos@csed-1.UUCP (Eric Roskos) (02/26/88)

This is in response to the postings on how to do backups under Minix.

To handle this I am using PD tar (not the most recent version, an earlier
version with some DOS support changes I couldn't get John to put in) which
I modified to use multivolume support.  However, I am still testing it;
if there is enough interest I could post the current diffs, though.

The changes to PD tar are only about 3 or 4 lines worth; fortunately it
has comments in there already telling where the changes need to go.

However, Minix turned out to have a bug -- at least, I guess it's a bug --
in that it does not cause an EOF when you are *writing* to the floppy
disk special files and you reach the end of the disk; it only gets an EOF
when you are reading.  So, to use it, you have to change that too.

If there's any interest in this, send me email, and if there's enough
interest I can post the changes... if not I'll just email them.
-- 
Eric Roskos, IDA (...dgis!csed-1!roskos or csed-1!roskos@HC.DSPO.GOV)

ast@cs.vu.nl (Andy Tanenbaum) (02/27/88)

In article <10579@santra.UUCP> nispa@hutcs.hut.fi (Tapani Lindgren) writes:
>In article <46400003@ztivax.UUCP> freizeit@ztivax writes:
>We could'n't make pipes work with block sizes larger than 7K.
>Is there a BUG in Minix? (No, that would be impossible:-)
>If somebody has a fix, please let the world know!

It is not a bug.  It is a feature.  Having pipes larger than
7K would mean not using "small" files, but files with indirect blocks as pipe
inodes.  V7 does not allow this; neither does MINIX.  There is no easy fix.

Andy Tanenbaum (ast@cs.vu.nl)

rmtodd@uokmax.UUCP (Richard Michael Todd) (02/29/88)

In article <665@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes:
>It is not a bug.  It is a feature.  Having pipes larger than
>7K would mean not using "small" files, but files with indirect blocks as pipe
>inodes.  V7 does not allow this; neither does MINIX.  There is no easy fix.
I think it's a bug.  When you attempt to write a block greater than 7K to
a file and it fails for no apparent reason, it's a violation of the Principle
of Least Astonishment.  Why should MINIX perpetuate all of V7's bugs?  Does
Sys5 have this bug? (BSD pipes aren't implemented using spare inodes, so this
doesn't apply to them, and BSD doesn't freak out when you write >7k to a pipe.)
Some time ago I found a way to patch MINIX FS to allow writes >7K to a pipe.
It required changes to two lines, I think.  Nothing else seemed to break.
Unfortunately I'm at school right now and the MINIX machine's at home, so
it'll be at least this weekend before I can post them.
--------------------------------------------------------------------------
Richard Todd
USSnail:820 Annie Court,Norman OK 73069
UUCP: {allegra!cbosgd|ihnp4}!occrsh!uokmax!rmtodd