[net.sources] copying a tape with only one tape drive.

lmc@denelcor.UUCP (09/03/84)

This program will copy a tape exactly, reading the tape in from a drive
to a disk, and then back out to the same drive. See the manual page
for details.
----------------------------------------------------------------------
: This is a shar archieve.  Extract with sh, not csh.
: The rest of this file will extract:
: tcp.l tcp.c
echo extracting - tcp.l
sed 's/^X//' > tcp.l << 'FUNKYSTUFF'
X.TH TCP 1 "21 Aug 1984"
X.UC 4
X.SH NAME
Xtcp \- tape copy with one tape drive
X.SH SYNOPSIS
X.B tcp
X[
X.B \-i
X] [
X.B \-o
X] [
X.B \-1..15
X] [
X.B \-c
X] [
X.B -nxx
X]
X.br
X.SH DESCRIPTION
XNeed to copy a tape, but only have a
Xsingle tape drive?
X.I Tcp
Xwill do it.
XIn the
X.I \-i
Xmode
X.I tcp
Xreads in all the files of a tape,
Xcopying them to disk along with enough
Xinformation to reconstruct the record
Xblocking. The tape is assumed to be
Xterminated with the usual double
Xtape marks.  In output mode (
X.I \-o
X)
X.I tcp
Xreads the files and rebuilds the tape
Xexactly as it was. The
X.I \-n
Xoption allows several tapes to be saved
Xin a single directory, if that is
Xrequired, by giving each a separate
Xnumber (0-99), and then specifying
Xthat number on both input and output.
XThe
X.I \-c
Xoption specifies that a conversational
Xmode is to be entered in the event
Xof tape read errors, in which the user
Xcan specify the action to be taken
Xwhen such an error occurs: ignore the
Xerror (copy whatever was received; this
Xmay not give desired results on some
Xsystems), retry the I/O, or abort the
Xentire copy operation. (Note that the
X.I \-c
Xoption is only available on Berkeley
Xsystems with mag tape ioctls.)
XThe numeric options allow the tape drive
Xdefault selection to be changed. The
Xinput operation uses /dev/rmtX, where
XX can be specified from 0 to 15, while
Xon output /dev/nrmtX is used (which
Xcan normally only accept 0-3 and 8-11
Xas valid drive numbers). In both cases
Xthe default drive is drive 0.
X.SH DIAGNOSTICS
XThe usual usage diagnostic and
Xothers for cannot open and tape
Xread errors.
X.PP
XExit status is 0 normally, 1 for
Xusage error and 2 for tape read error.
X.SH DEFINES
X.I MAXBUF
Xdefines the maximum size of a tape
Xblock. Default at 16000 works with both
X4.2bsd and S3 on an 11/44.
X.I MTIO,
Xif defined, compiles in the conversational
Xoption, which requires the mag tape
Xioctls from the Berkeley distributions.
X.SH AUTHOR
XLyle McElhaney
FUNKYSTUFF
echo extracting - tcp.c
sed 's/^X//' > tcp.c << 'FUNKYSTUFF'
X/*
X *      tcp - this routine runs in input (-i) and output (-o) modes. On
X *      input, it reads a tape's contents (out to the double tape-marks)
X *      and writes that data to files in a the current directory, along
X *      with a file of data which will allow reconstruction of the tape
X *      in the output mode.
X *
X *      Copyright (C) 1983, 1984 Lyle McElhaney
X *      Permission to copy for non-commercial use granted under condition
X *      that this notice remains intact in the copy.
X *
X *      Address: 2489 W. Ridge Rd., Littleton, CO 80120
X *      ....denelcor!lmc
X *
X */
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/ioctl.h>
X#ifdef MTIO
X#include <sys/mtio.h>
X#endif
X#ifndef YES
X#define NO 0
X#define YES 1
X#endif
X#define NYU 2
X
Xextern char *index();
Xextern int errno;
Xchar nrtape[]="/dev/nrmt0\0\0";
Xchar tape[]="/dev/rmt0\0\0";
Xchar ffh[]="tcp,f";      /* headers for temp filenames */
Xchar nfh[]="tcp,n";
Xchar format[]="%s%02d%05d"; /* format of filenames. args: [fcn]fh, tapen, nfile */
X#define FMTSIZ 13       /* limit on size of filenames created + 1 */
Xchar ffile[FMTSIZ], cfile[FMTSIZ];
X#define MAXBUF 16000    /* works on 11/44 under SYS3 */
Xchar buff[MAXBUF];
Xchar buf[10];
Xint nfile;
Xint tapen=0;
Xint inmode=NYU;         /* input mode - not yet set. User must choose. */
XFILE *tapedev, *filedev, *ctldev;
Xlong recno, nrec, fsize, filen;
X#ifdef MTIO
Xint convmode=NO;        /* conversational mode default to no */
Xstruct mtop mtop;
X#endif
X
Xmain (argc, argv)
X    int argc;
X    char **argv;
X{
X    char *p;
X    int n;
X
X    argv++;
X    if (argc > 1) {
X	p = *argv;
X	if (*p == '-') {
X	    p++;
X	    while (*p != '\0') {
X		switch (*p++) {
X#ifdef MTIO
X		case 'c':
X			convmode = YES;
X			break;
X#endif
X		case 'i':
X			if (inmode != NYU) goto Usage;
X			inmode = YES;
X			break;
X		case 'o':
X			if (inmode != NYU) goto Usage;
X			inmode = NO;
X			break;
X		case 'n':
X			tapen = atoi (p);
X			break;
X		case '2':
X		case '3':
X		case '4':
X		case '5':
X		case '6':
X		case '7':
X		case '8':
X		case '9':
X		case '0':
X		    tape[8] = nrtape[9] = *(p-1);
X		    break;
X		case '1':
X		    tape[8] = nrtape[9] = '1';
X		    if (*p >= '0' && *p <= '5')
X			tape[9] = nrtape[10] = *p++;
X		    break;
X		default:
XUsage:
X		    fprintf (stderr, "Usage: tcp [-i] [-o] [-nxx] [-1...15]\n");
X		    exit (2);
X		}
X	    }
X	    argc--;
X	    argv++;
X	}
X    } else goto Usage;
X    if (inmode == NYU) goto Usage;
X
X    if (inmode) {
X/*
X *      input mode - read tape into files.
X */
X	sprintf (cfile, format, nfh, tapen, 0);
X	if ((ctldev = fopen (cfile, "w+")) == NULL) {
X	    fprintf (stderr, "tcp: cannot open %s\n", cfile);
X	    exit (2);
X	}
X	if ((tapedev = fopen (tape, "r")) == NULL) {
X	    fprintf (stderr, "tcp: cannot open %s\n", tape);
X	    exit (2);
X	}
X	filen = 0;
X	for (;;) {
X	    recno = nrec = fsize = 0;
Xreread:     while ((n = read (fileno (tapedev), buff, sizeof buff)) > 0) {
X		if (recno == 0) {
X		    sprintf (ffile, format, ffh, tapen, filen);
X		    if ((filedev = fopen (ffile, "w+")) == NULL) {
X			fprintf (stderr, "tcp: cannot open %s\n", ffile);
X			exit (2);
X		    }
X		}
X		if (write (fileno (filedev), buff, n) <= 0) {
X		    fprintf (stderr, "tcp: file write error #%d in %s\n",
X			errno, ffile);
X		    exit (2);
X		}
X		if (fsize != 0 && fsize != n) {
X			fprintf (ctldev, "%d,%d\n", recno - nrec + 1, n);
X			nrec = recno;
X		}
X		fsize = n;
X		recno ++;
X	    }
X	    if (n == 0)
X		if (recno == 0)
X		    break;
X		else {
X		    fprintf (ctldev, "%d,%d\n0,0\n", recno - nrec, fsize);
X		    filen ++;
X		    fclose (filedev);
X		}
X	    else {
X		printf ("Tape read error %d in record %ld\n", n, recno);
X#ifdef MTIO
X		for (;;) {
X		    if (convmode) {
X			printf ("Abort, Retry, or Ignore? ");
X			if (gets (buf) != NULL) {
X			    if (*buf == 'R' || *buf == 'r') {
X				mtop.mt_count = 1;
X				mtop.mt_op = MTBSR;
X				if (ioctl (fileno (tapedev), MTIOCTOP, &mtop) < 0) {
X				    printf ("error %d in ioctl; ignoring prev error.\n", errno);
X				    recno ++;
X				}
X				goto reread;
X			    } else if (*buf == 'I' || *buf == 'i') {
X				recno ++;
X				goto reread;
X			    } else if (*buf == 'A' || *buf == 'a')
X				exit (1);
X			}
X		    } else
X			exit (1);
X		}
X#else
X	    exit (1);
X#endif  MTIO
X	    }
X	}
X	fclose (tapedev);
X	fprintf (ctldev, "0,1\n");
X	fclose (ctldev);
X    } else {
X/*
X *      output mode - copy files back out to tape.
X */
X	sprintf (cfile, format, nfh, tapen, 0);
X	if ((ctldev = fopen (cfile, "r")) == NULL) {
X	    fprintf (stderr, "tcp: cannot open %s\n", cfile);
X	    exit (2);
X	}
X	recno = 0;
X	for (;;) {
X	    if (fgets (buf, sizeof(buf), ctldev) == NULL) {
X		fprintf (stderr, "tcp: file %s malformed.\n", cfile);
X		exit (2);
X	    }
X	    nrec = atoi (buf);
X	    n = atoi (index (buf, ',') + 1);
X	    if (nrec != 0) {
X		if (recno == 0) {
X		    if ((tapedev = fopen (nrtape, "a")) == NULL) {
X			fprintf (stderr, "tcp: cannot open %s\n", nrtape);
X			exit (2);
X		    }
X		    sprintf (ffile, format, ffh, tapen, filen);
X		    if ((filedev = fopen (ffile, "r")) == NULL) {
X			fprintf (stderr, "tcp: cannot open %s\n", ffile);
X			exit (2);
X		    }
X		}
X		for (; nrec > 0; nrec--) {
X		    if (read (fileno (filedev), buff, n) <= 0) {
X			fprintf (stderr, "tcp: file read error #%d in %s\n",
X			    errno, ffile);
X			exit (2);
X		    }
X		    if (write (fileno (tapedev), buff, n) <= 0) {
X			fprintf (stderr, "tcp: tape write error #%d in %s\n",
X			    errno, nrtape);
X			exit (2);
X		    }
X		    recno ++;
X		}
X	    } else if (n == 0) {
X		fclose (filedev);
X		fclose (tapedev);
X		recno = 0;
X	    } else
X		break;
X	}
X	fclose (ctldev);
X    }
X    exit (0);
X}
FUNKYSTUFF
-- 
		Lyle McElhaney
		(hao,brl-bmd,nbires,csu-cs,scgvaxd)!denelcor!lmc