Ultrix-3.1/src/cmd/volcopy.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

static char Sccsid[] =	"@(#)volcopy.c	3.0	4/22/86";
/*
 *	volcopy -- copy file systems w/label checking (from SYSTEM V)
 *
 * Changes for ULTRIX-11
 *	Removed 3b processor and RT dependencies.
 *	John Dustin	7/25/84
 */
/* Based on:	(SYSTEM V)  volcopy.c	4.9	*/

#define LOG	/* keep log of system copy activity */
#define AFLG 0	/* AFLG == 0 will ask: Ready to copy? */
#include <sys/param.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/filsys.h>
#include <sys/stat.h>
#include <sys/devmaj.h>
#include <stdio.h>
#include <signal.h>
#include <sys/mount.h>
#include <a.out.h>
#include <errno.h>
#define FILE_SYS 1
#define DEV_FROM 2
#define FROM_VOL 3
#define DEV_TO 4
#define TO_VOL 5
#define	T_TYPE	0xfd187e20	/* like FsMAGIC */
#define	BLKSIZ	512	/* use physical blocks */
#define _2_DAYS 172800L
#define V_MAX 1000000L
#define Ft800x10	15L
#define Ft1600x4	22L
#define Ft1600x10	28L
#define Ft6250x10	90L
#define Ft6250x50	120L

struct Tphdr {
	char	t_magic[8];
	char	t_volume[6];
	char	t_reels,
		t_reel;
	long	t_time;
	long	t_length;
	long	t_dens;
	long	t_reelblks;	/* u370 added field */
	long	t_blksize;	/* u370 added field */
	long	t_nblocks;	/* u370 added field */
	char	t_fill[470];
	int	t_type;		/* does tape have nblocks field? (u3b) */
} Tape_hdr;

int	first = 0;
char	**args;
int	Nblocks = 0;
long	Reelblks = V_MAX;
int	Reels = 1;
int	reel = 1;
int	Reelsize = 0;
long	rblock = 0, reeloff = 0;
long	saveFs;
int	Bpi = 0;
int	bufflg = 0;
long	Fs;
short	*Buf;
long	Fstype;
int	sts;
int	p_in, p_out;

short	magtape;
#define	NMNT	0
#define	MNT	1
struct	nlist	nl[] = {
	{ "_nmount" },
	{ "_mount" },
	{ "" },
};
int	nmount;
struct	mount	*mp;
struct	mount	*mpp;
char	*coref = "/dev/mem";

/*

filesystem copy with propagation of volume ID and filesystem name:

  volcopy [-options]  filesystem /dev/from from_vol /dev/to to_vol

options are:
	-feet - length of tape
	-bpi  - recording density
	-reel - reel number (if not starting from beginning)
	-buf  - use double buffered i/o (if dens >= 1600 bpi)
	-a    - ask "y or n" instead of usual 5 second delay. This is default.
	-n    - inverse of -a	( this used to be the '-s' option)

  Examples:

  volcopy root /dev/rrp2 pk5 /dev/rrp12 pk12

  volcopy u3 /dev/rrp15 pk1 /dev/rmt0 tp123

  volcopy u5 /dev/rmt0 -  /dev/rrp15 -

In the last example, dashed volume args mean "use label that's there."

From/to devices are printed followed by `?'.
User has 5 seconds to ^C if mistaken!
With '-a' option, a positive user response is required to continue.
With '-n' option, -a is cancelled, some override questions are bypassed.
 */

long	Block;
char *Totape, *Fromtape;
FILE	*Devtty;
char	*Tape_nm;
int	pid;

struct filsys	Superi, Supero, *Sptr;

extern int	read(), write();

sigalrm()
{
	signal(SIGALRM, sigalrm);
}

sigint()
{
	if(pid != 1){
		if(asks("Want Shell?  "))
			system("sh");
		else if(asks("Want to Quit?  ")) {
			if(pid) kilchld();
			exit(2);
		}
	}
	signal(SIGINT, sigint);
}
char kilcmd[] = "kill -9 000000";
kilchld()
{
	sprintf(&kilcmd[8],"%d",pid -1);
	system(kilcmd);
}
char *tapeck();

main(argc, argv) char **argv;
{
	int	fsi, fso;
	int	i,j,mem;
	struct	stat statb;
	long	tvec;
	int	altflg = AFLG;
	FILE	*popen();
	char	vol[12], dev[12], c;

	signal(SIGALRM, sigalrm);
	sync();
	while(argv[1][0] == '-') {
		if(EQ(argv[1], "-bpi", 4))
			if((c = argv[1][4]) >= '0' & c <= '9')
				Bpi = getbpi(&argv[1][4]);
			else {
				++argv;
				--argc;
				Bpi = getbpi(&argv[1][0]);
			}
		else if(EQ(argv[1], "-feet", 5))
			if((c = argv[1][5]) >= '0' & c <= '9')
				Reelsize = atoi(&argv[1][5]);
			else {
				++argv;
				--argc;
				Reelsize = atoi(&argv[1][0]);
			}
		else if(EQ(argv[1],"-reel",5))
			if((c = argv[1][5]) >= '0' & c <= '9')
				reel = atoi(&argv[1][5]);
			else {
				++argv;
				--argc;
				reel = atoi(&argv[1][0]);
			}
		else if(EQ(argv[1],"-buf",4))
			bufflg++;
		else if(EQ(argv[1],"-n",2))
			altflg++;
		else if(EQ(argv[1],"-a",2))
			altflg = 0;
		else {
			fprintf(stderr, "<%s> invalid option\n",
				argv[1]);
			exit(1);
		}
		++argv;
		--argc;
	}
	args = argv;

	if ((Devtty = fopen("/dev/tty", "r")) < 0) {
		fprintf(stderr,"Cannot open terminal!\n");
		exit(1);
	}
	time(&tvec);
			/* get mandatory inputs */
	if(argc!=6){
		fprintf(stderr,"Usage: volcopy [options] fsname");
		fprintf(stderr," /devfrom volfrom /devto volto\n");
		exit (9);
	}
	if(!magtape) {
		if ((stat(argv[DEV_TO],&statb)) < 0) {
			fprintf(stderr,"volcopy: cannot stat %s\n",argv[DEV_TO]);
			exit(2);
		}
		nlist("/unix", nl);
		if((nl[NMNT].n_value==0) || (nl[MNT].n_value==0)) {
			fprintf(stderr, "volcopy: cannot access /unix namelist\n");
			exit(2);
		}
		mem = open(coref, 0);
		if(mem < 0 ) {
			fprintf(stderr, "volcopy: cannot open %s\n", coref);
			exit(2);
		}
		lseek(mem, (long)nl[NMNT].n_value, 0);
		read(mem, (char *)&nmount, sizeof(nmount));
		mp = malloc(sizeof(struct mount) * nmount);
		lseek(mem, (long)nl[MNT].n_value, 0);
		read(mem, (char *)mp, sizeof(struct mount) * nmount);
		mpp = mp;
		for(i=0; i<nmount; i++, mpp++) {
			j = (statb.st_rdev >> 8) & 0377;
			j -= RK_RMAJ;	/* convert to block major */
			j <<= 8;
			j |= (statb.st_rdev & 0377);
			if((mpp->m_bufp == 0) || (mpp->m_dev != j))
				continue;
			fprintf(stderr, "\7\7volcopy: SORRY - output file system is mounted!\n");
			exit(2);
		}
	}

	if((fsi = open(argv[DEV_FROM],0)) < 1)
		fprintf(stderr, "%s: ",argv[DEV_FROM]), err("cannot open");
	if((fso = open(argv[DEV_TO],0)) < 1)
		fprintf(stderr, "%s: ",argv[DEV_TO]), err("cannot open");

	if(fstat(fsi, &statb)<0 || (statb.st_mode&S_IFMT)!=S_IFCHR)
		err("From device not RAW !");/* was "character-special" */
	if(fstat(fso, &statb)<0 || (statb.st_mode&S_IFMT)!=S_IFCHR)
		err("To device not RAW !");

	Fromtape = argv[DEV_FROM]; /* this will get reset if not appropriate
			but is needed by tapeck's label processing */
	Fromtape = tapeck(argv[DEV_FROM], argv[FROM_VOL], fsi);
	Totape = tapeck(argv[DEV_TO], argv[TO_VOL], fso);
	if(Totape && Fromtape) {
		fprintf(stderr,"Use dd(1) command to copy tapes\n");
		exit(1);
	}

	Nblocks = ((Totape||Fromtape)&&(Bpi!=6250))? 10:88;

	if(Bpi == 6250) Nblocks = 50;

	Buf = -1;
	/*
	 * Check if enough space, if not, scale down...
	 */
	if (!((BLKSIZ*Nblocks) <= 0))
		Buf = (short *)sbrk(BLKSIZ*Nblocks);
	if((int)Buf == -1 && Nblocks == 88) {
		Nblocks = 22;
		if (!((BLKSIZ*Nblocks) <= 0))
			Buf = (short *)sbrk(BLKSIZ*Nblocks);
	}
	if((int)Buf == -1) {
		fprintf(stderr, "Not enough memory--get help\n");
		exit(1);
	}
#ifdef UCB_NKB
	Sptr = (struct filsys *)&Buf[BLKSIZ];
#else
	Sptr = (struct filsys *)&Buf[BLKSIZ/2];
#endif
	if(!Fromtape && !Totape) reel = 1;
	if((reel == 1) || !Fromtape){
#ifdef UCB_NKB
		if(read(fsi, Buf, 4*BLKSIZ) != 4*BLKSIZ)
#else
		if(read(fsi, Buf, 2*BLKSIZ) != 2*BLKSIZ)
#endif
		{
			fprintf(stderr, "read error on input (ERR %d)",errno);
			err();
		}
		strncpy(Superi.s_fname,  Sptr->s_fname,6);
		strncpy(Superi.s_fpack,  Sptr->s_fpack,6);

/***
		if (Sptr->s_magic != FsMAGIC)
			Sptr->s_type = Fs1b;
		switch ((int)Sptr->s_type) {

		case Fs1b:
			Fstype = 1;
			Fs = Sptr->s_fsize;
			break;
		case Fs2b:
			Fstype = 2;
			Fs = Sptr->s_fsize * 2;
			break;
		default:
			err("File System type unknown--get help");
		}
 ***/

#ifdef UCB_NKB
		Fstype = 2;		/* 1024 byte block filesystem */
		Fs = Sptr->s_fsize * 2;
#else
		Fstype = 1;		/* 512 byte block filesystem */
		Fs = Sptr->s_fsize;
#endif

		Superi.s_fsize = Sptr->s_fsize;
		Superi.s_time = Sptr->s_time;
	}

#ifdef UCB_NKB
	if(read(fso, Buf, 4*BLKSIZ) != 4*BLKSIZ){
#else
	if(read(fso, Buf, 2*BLKSIZ) != 2*BLKSIZ){
#endif
		fprintf(stderr,"read error on output (ERR = %d)\n", errno);
		if(!Totape | !altflg) ask();
	}
	strncpy(Supero.s_fname, Sptr->s_fname,6);
	strncpy(Supero.s_fpack, Sptr->s_fpack,6);
	Supero.s_fsize = Sptr->s_fsize;
	Supero.s_time = Sptr->s_time;

	if((reel != 1) && Fromtape){	/* if this isn't reel 1,
			the TO_FS better have been initialized */
                printf("volcopy: IF REEL 1 HAS NOT BEEN RESTORED,");
		printf(" STOP NOW AND START OVER ***\n");
		if(!asks("Continue?  ")) exit(9);
		strncpy(Superi.s_fname,argv[FILE_SYS],6);
		strncpy(Superi.s_fpack,argv[FROM_VOL],6);
	}
	if(Totape){
		Reels = Fs / Reelblks + ((Fs % Reelblks) && 1);
		printf("You will need %d reel", Reels);
		Reels>1 ? printf("s.\n(The same size and density is expected for all reels)\n") : printf(".\n");
		/* output vol name was validated already */
		strncpy(Tape_hdr.t_volume,argv[TO_VOL],6);
		strncpy(Supero.s_fpack,argv[TO_VOL],6);
		strncpy(vol,argv[TO_VOL],6);
		strncpy(Supero.s_fname,argv[FILE_SYS],6);
	}
	if(Fromtape){
		if((Tape_hdr.t_reel != reel
			|| Tape_hdr.t_reels!=Reels)){
			fprintf(stderr, "Tape disagrees: Reel %d of %d",
				Tape_hdr.t_reel, Tape_hdr.t_reels);
			fprintf(stderr," : looking for %d of %d\n",
				reel,Reels);
			ask();
		}
		strncpy(vol,Tape_hdr.t_volume,6);
	}

	if(!EQ(argv[FILE_SYS],Superi.s_fname, 6)) {
		printf("arg. (%.6s) doesn't agree with from fs. (%.6s)\n",
			argv[FILE_SYS],Superi.s_fname);
		if(!Totape | !altflg) ask();
	}
	if(!EQ(argv[FROM_VOL],"-", 6) &
	   !EQ(argv[FROM_VOL],Superi.s_fpack, 6)) {
		printf("arg. (%.6s) doesn't agree with from vol. (%.6s)\n",
			argv[FROM_VOL],Superi.s_fpack);
		if(!Totape | !altflg) ask();
	}

	if(argv[FROM_VOL][0]=='-') argv[FROM_VOL] = Superi.s_fpack;
	if(argv[TO_VOL][0]=='-') argv[TO_VOL] = Supero.s_fpack;

	if((reel == 1) & (Supero.s_time+_2_DAYS > Superi.s_time)) {
		printf("%s less than 48 hours older than %s\n",
			argv[DEV_TO], argv[DEV_FROM]);
		printf("To filesystem dated:  %s", ctime(&Supero.s_time));
		if(!altflg) ask();
	}
	if(!EQ(argv[TO_VOL],Supero.s_fpack, 6)) {
		printf("arg. (%.6s) doesn't agree with to vol. (%.6s)\n",
			argv[TO_VOL],Supero.s_fpack);
		ask();
		strncpy(Supero.s_fpack,  argv[TO_VOL],6);
	}
	if(Superi.s_fsize > Supero.s_fsize && !Totape) {
		printf("from fs larger than to fs\n");
		ask();
	}
	if(!Totape && !EQ(Superi.s_fname,Supero.s_fname, 6)) {
		printf("warning! from fs <%.6s> differs from to fs <%.6s>\n",
			Superi.s_fname,Supero.s_fname);
		if(!altflg) ask();
	}

	printf("From: %s  To: %s",argv[DEV_FROM],argv[DEV_TO]);
	if(altflg){	/* user entered -n flag... he's on his own. */
	/*	printf("(DEL if wrong)\n");	*/
                printf("\nCopying...\n");
		sleep(5);	/* But really give him 5 seconds to ^C... */
	}
	else if(!asks("  Ready? (y or n):  ")) {
			printf("volcopy: STOP\n");
			exit(9);
		}
	close(fso); close(fsi);
	sync();
	fsi = open(argv[DEV_FROM], 0);
	fso = open(argv[DEV_TO], 1);

	if(Totape) {
		Tape_hdr.t_reels = Reels;
		Tape_hdr.t_reel = reel;
		Tape_hdr.t_time = tvec;
		Tape_hdr.t_reelblks = Reelblks;
		Tape_hdr.t_blksize = BLKSIZ*Nblocks;
		Tape_hdr.t_nblocks = Nblocks;
		Tape_hdr.t_type = T_TYPE;
		if (write(fso, &Tape_hdr, sizeof Tape_hdr) != sizeof Tape_hdr) {
			fprintf(stderr, "volcopy: cannot write tape label (ERR %d)", errno);
			err();
		}
		if (read(fsi, Buf, 2048) != 2048) {
			fprintf(stderr, "volcopy: cannot read superblock (ERR %d)", errno);
			err();
		}
		if (write(fso, Buf, 2048) != 2048) {
			fprintf(stderr, "volcopy: cannot write superblock (ERR %d)", errno);
			err();
		}

		strcpy(vol,argv[TO_VOL]);
	} else if(Fromtape) {
		if (read(fsi, &Tape_hdr, sizeof Tape_hdr) != sizeof Tape_hdr) {
			fprintf(stderr, "volcopy: cannot read tape label (ERR %d)", errno);
			err();
		}
		if (read(fsi, Buf, 2048) != 2048) {
			fprintf(stderr, "volcopy: cannot read superblock (ERR %d)", errno);
			err();
		}
		if (write(fso, Buf, 2048) != 2048) {
			fprintf(stderr, "volcopy: cannot write superblock (ERR %d)", errno);
			err();
		}
	}
	if(reel > 1) {
		Fs = (reel -1) * Reelblks + Nblocks;
		lseek(Totape ? fsi : fso,(unsigned)(Fs * BLKSIZ),0);
		Sptr = Totape? &Superi: &Supero;
		Fs = (Sptr->s_fsize * Fstype) - Fs;
	}

	rprt(vol);

	signal(SIGINT, sigint);

	while(copy(fsi,fso))
		chgreel(Totape ? fso : fsi, dev,vol);
	printf("DONE: %ld blocks.\n", Block);

#ifdef LOG
	fslog(argv);
#endif
	exit(0);
}

err(s) char *s; {
	printf("%s\n\t%d reel(s) completed\n",s,--reel);
	exit(9);
}
EQ(s1, s2, ct)
char *s1, *s2;
int ct;
{
	register i;

	for(i=0; i<ct; ++i) {
		if(*s1 == *s2) {;
			if(*s1 == '\0') return(1);
			s1++; s2++;
			continue;
		} else return(0);
	}
	return(1);
}
ask() {
	char ans[12];
	printf("Type `y' to override:  ");
	fgets(ans, 10, Devtty);
	if(EQ(ans,"y", 1))
		return;
	if(EQ(ans,"a",1))
		abort();
	exit(9);
}
asks(s)
char *s;
{
	char ans[12];
	printf(s);
	ans[0] = '\0';
	fgets(ans, 10, Devtty);
	for(;;){
		switch(ans[0]) {

		case 'a':
			if(pid == 1) {
				write(p_out,"ABORT",1);
				exit(1);
			}
			if(pid) kilchld();
			abort();
		case 'y':
			return(1);
		case 'n':
			return(0);
		default:
			printf("\n(y or n)?");
			fgets(ans, 10, Devtty);
		}
	}
}

getbpi(inp)
char *inp;
{
	return(atoi(inp));
}

char *tapeck(dev, vol, fd)
char *dev, *vol;
{
	struct	stat	statb;
	int	i;
	char	resp[16];

	if(stat(dev, &statb) < 0) {
		fprintf(stderr, "volcopy: cannot stat %s\n",dev);
		exit(2);
	}
	i = (statb.st_rdev >> 8) & 0377;
	switch(i) {
	case HT_RMAJ:
	case TS_RMAJ:
	case TM_RMAJ:
	case TK_RMAJ:
		magtape = 1;
		break;
	default:
		magtape = 0;
		break;
	}
	if (!magtape)		/* the real tape check */
		return(0);
	Tape_nm = dev;
	Tape_hdr.t_magic[0] = '\0';	/* scribble on old data */
	alarm(5);
	if(read(fd, &Tape_hdr, sizeof Tape_hdr) <= 0)
		fprintf(stderr,"Tape read error: (ERR %d)\n",errno);
	alarm(0);
	if(!EQ(Tape_hdr.t_magic, "Volcopy", 7)){
		fprintf(stderr,"Not a labeled tape.\n");
		if(!Fromtape){
			ask();
			makelab();
			strncpy(Tape_hdr.t_volume, vol, 6);
			Supero.s_time = 0;
		}
		else err();
	}
	else if(Tape_hdr.t_reel == (char)0)
		if(Fromtape){
			fprintf(stderr,"Input tape is empty\n");
			exit(9);
		}
	if((vol[0] != '-') && (!EQ(Tape_hdr.t_volume, vol, 6))) {
		fprintf(stderr, "Header volume (%.6s) does not match (%s)\n",
			Tape_hdr.t_volume, vol);
		ask();
		strncpy(Tape_hdr.t_volume, vol, 6);

	}
tapein:
	if(Fromtape){
		Reels = Tape_hdr.t_reels;
		Reelsize = Tape_hdr.t_length;
		Bpi = Tape_hdr.t_dens;
	}
	else{
		Reels = 0;
	}
	if(Reelsize == 0) {
		printf("Enter size of reel in feet for <%s>:   ", vol);
		fgets(resp, 10, Devtty);
		Reelsize = atoi(resp);
	}
	if(Reelsize <= 0 || Reelsize > 2400) {
		fprintf(stderr, "Size of reel must be > 0, <= 2400\n");
		Reelsize = 0;
		goto tapein;
	}
	if(!Bpi) {
		printf("Tape density? (i.e., 800 | 1600 | 6250)?   ");
		fgets(resp, 10, Devtty);
		Bpi = getbpi(resp);
	}
	if(Bpi == 800)
		Reelblks = Ft800x10 * Reelsize;
	else if(Bpi == 1600) {
		Reelblks = Ft1600x10 * Reelsize;
	}
	else if(Bpi == 6250)
		Reelblks = Ft6250x50 * Reelsize;
	else {
		fprintf(stderr, "Bpi must be 800, 1600, or 6250\n");
		Bpi = 0;
		goto tapein;
	}
	printf("\nReel %.6s",Tape_hdr.t_volume);
	Tape_hdr.t_length = Reelsize;
	printf(", %d feet",Reelsize);
	Tape_hdr.t_dens = Bpi;
	printf(", %d BPI\n",Bpi);
	return dev;
}
hdrck(fd, tvol)
char *tvol;
{
	struct Tphdr *thdr;
	int siz;

	thdr = (struct Tphdr *) Buf;
	alarm(15);	/* dont scan whole tape for label */
	if((siz = read(fd, thdr, sizeof Tape_hdr)) != sizeof Tape_hdr) {
		alarm(0);
		fprintf(stderr, "Cannot read tape header (ERR %d)\n", errno);
		if(Totape){
			ask();
			strncpy(Tape_hdr.t_volume, tvol, 6);
			return(1);
		}
		else{
			close(fd);
			return 0;
		}
	}
	alarm(0);
	Tape_hdr.t_reel = thdr->t_reel;
	if(!EQ(thdr->t_volume, tvol, 6)) {
		fprintf(stderr, "Volume is <%.6s>, not <%s>.\n",
			thdr->t_volume, tvol);
		if(asks("Want to override?  ")) {
			if(Totape) {
				strncpy(Tape_hdr.t_volume, tvol, 6);
			}
			else{
				strncpy(tvol,thdr->t_volume,6);
			}
			return 1;
		}
		return 0;
	}
	return 1;
}
makelab()
{
	int i;

	for(i = 0; i < sizeof Tape_hdr; i++)
		Tape_hdr.t_magic[i] = '\0';
	strncpy(Tape_hdr.t_magic,"Volcopy\0",8);
}
rprt(vol)
char *vol;
{
	if(Totape)
		printf("Writing REEL %d of %d, VOL = %.6s\n",
		  reel,Reels,vol);
	if(Fromtape)
		printf("Reading REEL %d of %d, VOL = %.6s\n",
		  reel,Reels,vol);
}
#ifdef LOG
fslog(argv)
char *argv[];
{
	char cmd[100];

	if(access("/etc/log/filesave.log", 6) < 0) {
		fprintf(stderr,
			"volcopy: cannot access /etc/log/filesave.log\n");
		exit(0);
	}
	system("tail -200 /etc/log/filesave.log >/tmp/FSJUNK");
	system("cp /tmp/FSJUNK /etc/log/filesave.log");
	sprintf(cmd,"echo -n \"%s;%.6s;%.6s -> %s;%.6s;%.6s\n\" >>/etc/log/filesave.log",
		argv[DEV_FROM], Superi.s_fname, Superi.s_fpack, 
		argv[DEV_TO], Supero.s_fname,
		 Supero.s_fpack);
	system(cmd);
	system("date >> /etc/log/filesave.log");
	system("rm /tmp/FSJUNK");
	exit(0);
}
#endif

copy(fsi,fso)
int fsi,fso;
{
	int i, cnt;
	int p1[2], p2[2];
	char buf[20];

	pid = -1;
	if(bufflg && (Bpi < 1600))
		fprintf(stderr,"Not using double buffered i/o.  (tape density not >= 1600 BPI)\n");
	if(bufflg && (Bpi >= 1600)) {
		if( pipe(p1) | pipe(p2)) {
			printf("\volcopy: cannot open pipe, err = %d\n",errno);
			exit(1);
		}
		pid = fork();
		if(pid) {
			close(p1[0]);
			close(p2[1]);
			p_in = p2[0];
			p_out = p1[1];
		}
		else {
			close(p1[1]);
			close(p2[0]);
			p_in = p1[0];
			p_out = p2[1];
			write(p_out,"rw",2);	/* prime the pipe */
		}
	}
	pid++;		/* pid is >0 if we forked */
			/* child has pid == 1 */

		/* copy from fsi to fso */

	while((Fs > 0) && (rblock < Reelblks)) {
		Nblocks = Fs > Nblocks ? Nblocks : Fs;

		if(pid) {
			if(pid == 1) {
				Fs -= Nblocks;
				if(Fs <= 0) goto cfin;
				Block += Nblocks;
				rblock += Nblocks;
				Nblocks = Fs > Nblocks ? Nblocks : Fs;
			}
			cnt = read(p_in,buf,1);
			if(cnt < 0 | buf[0] != 'r') {
			   if(pid == 1) {
				write(p_out,"R",1);
				exit(1);
			   }
			   else {
				piperr(buf);
			   }
			}

		}

		if((sts = read(fsi, Buf, BLKSIZ * Nblocks)) != BLKSIZ * Nblocks) {
			/*
			 * From tape? then always an error; otherwise,
			 * From disk? then only an error if not errno == 6
			 */
			if((Fromtape) || ((!Fromtape) && (errno != ENXIO)))
			    printf("Read error %d block %ld...\n",
				errno, Block);
			for(i=0; i != Nblocks * (BLKSIZ/2); ++i) Buf[i] = 0;
			if(!Fromtape)
				lseek(fsi,(long)((Block+Nblocks) * BLKSIZ), 0);
		}
		/*
		 * This code was moved out of main (which did the
		 * first read & write) so that the same number of
		 * blocks would be written on each tape--a change
		 * required for finc, frec, and ff compatibility.
		 */
		if(!first && pid != 1 && reel == 1){
			first++;
			strncpy(Sptr->s_fpack,  args[TO_VOL],6);
			strncpy(Sptr->s_fname,  args[FILE_SYS],6);
		}
		if(pid) {
			write(p_out,"r",1);	/* signal read complete */
			cnt = read(p_in,buf,1);
			if(cnt < 0 | buf[0] != 'w') {
				if(pid == 1) {
					write(p_out,"W",1);
					exit(1);
				}
				piperr(buf);
			}
		}

		if((sts = write(fso, Buf, BLKSIZ*Nblocks)) != BLKSIZ*Nblocks) {
			/*
			 * To tape? then always an error; otherwise,
			 * To disk? then only an error if not errno == 6
			 */
			if((Totape) || ((!Totape) && (errno != ENXIO)))
				printf("Write error %d, block %ld...\n", errno,Block);
			if(Totape) {
				if(pid == 1) {
					write(p_out,"Tape error",10);
					exit(1);
				}
				if(asks("Want to try another tape?  ")) {
					asks("Mount the new tape.  Type `y' when ready:  ");
					--reel;
					Block = reeloff;
					Fs = saveFs;
					lseek(fsi, (long)reeloff*BLKSIZ, 0);
					return(1);
				}
			} else {
				if(errno != ENXIO)
					exit(9);
			}
		}

		if(pid) {
			write(p_out,"w",1);	/* signal write complete */
			if(pid != 1) {
				Fs -= Nblocks;
				Block += Nblocks;
				rblock += Nblocks;
				Nblocks = Fs > Nblocks ? Nblocks : Fs;
			}
		}
		Fs -= Nblocks;
		Block += Nblocks;
		rblock += Nblocks;
	}
	if(pid == 1) {
cfin:		write(p_out,"Done",4);
		while (cnt < 0 | buf[0] != 'D') {
			cnt = read(p_in,buf,1);
		}
		exit(0);
	}
	else if(pid) {
		cnt = read(p_in,buf,1);
/*
 * Ihcc code debugs some end condition problems
 */
		if ((Fs + Nblocks) > 0) {
			if (cnt < 0 | buf[0] != 'r') piperr(buf);
			cnt = read(p_in, buf, 1);
			if (cnt < 0 | buf[0] != 'w') piperr(buf);
			cnt = read(p_in, buf, 1);
		}
/***/
		if(cnt < 0 | buf[0] != 'D') piperr(buf);
		write(p_out,"Done",4);
		close(p_in);
		close(p_out);
	}
	return((Fs > 0) ? 1 : 0);
}

chgreel(fs,dev,vol)
int fs;
char *dev, *vol;
{
	char ctemp[21];
	struct	stat statb;
	rblock = 0;
	reeloff = Block;
	saveFs = Fs;
	++reel;
again:
	if((sts = close(fs)) < 0)
		printf("Close failed: (ERR %d). (warning only)\n",errno);
	printf("Changing drives? (type RETURN for no),\n");
	printf("enter device name, ie:  /dev/rmt?  for yes:  ");
	fgets(ctemp, 20, Devtty);
	ctemp[strlen(ctemp) -1] = '\0';
	if(ctemp[0] != '\0')
		while(strncmp(ctemp,"/dev/r",6)){
			/* should do a magtape check here ! */
			printf("%s is not a RAW tape!\n",ctemp);
			/* /dev/rmt check: %s not a valid device */
			printf("enter device name, ie:  /dev/rmt?  :  ");
			fgets(ctemp, 20, Devtty);
			ctemp[strlen(ctemp) -1] = '\0';
			if(ctemp[0] == '\0') {
				strcpy(dev, Tape_nm);	/* assume old drive */
				break;
			}
			else
				strcpy(dev,ctemp);
		}
	printf("Mount tape %d\nEnter volume-ID:  ", reel);
	fgets(ctemp, 10, Devtty);
	ctemp[strlen(ctemp) -1] = '\0';
	if(ctemp[0] != '\0')	/*if only <cr> - use old vol-id */
		strcpy(vol,ctemp);
	if(*dev)
		Tape_nm = dev;
	if(Totape) {
		fs = open(Tape_nm, 0);
		if(fs < 0) {
			printf("Cannot open %s for reading.  ( ERR %d )\n",Tape_nm,errno);
			goto again;
		}
		if(fstat(fs, &statb)<0 || (statb.st_mode&S_IFMT)!=S_IFCHR) {
			printf("output device (%s) not RAW tape!\n",Tape_nm);
			goto again;
		}
		/*
		if(fs > 10)
			printf("\nERR %d\n",errno);
		*/
		if(!hdrck(fs, vol))
			goto again;
		Tape_hdr.t_reel = reel;
		close(fs);
		sleep(2);
		fs = open(Tape_nm, 1);
		if(fs <= 0) {
			printf("Cannot open %s for writing.  ( ERR %d )\n",Tape_nm,errno);
			goto again;
		}
		/*
		if (fs > 10)
			printf("\nERR %d\n",errno);
		*/
		if(write(fs, &Tape_hdr, sizeof Tape_hdr) < 0) {
			fprintf(stderr,"The tape doesn't seem to be labeled!\n");
			fprintf(stderr, "Cannot re-write header!");
			fprintf(stderr,"  Dismount tape and try another.\n");
			goto again;
		}
	} else {
		fs = open(Tape_nm, 0);
		if(fs < 0) {
			printf("Cannot open %s for reading. (ERR %d )\n",Tape_nm,errno);
			goto again;
		}
		if(fstat(fs, &statb)<0 || (statb.st_mode&S_IFMT)!=S_IFCHR) {
			printf("input device (%s) not RAW tape!\n",Tape_nm);
			goto again;
		}
		/*
		if(fs > 10)
			printf("\nERR %d\n",errno);
		*/
		if(!hdrck(fs, vol))
			goto again;
		if(Tape_hdr.t_reel != reel) {
			fprintf(stderr,"Need reel %d,",reel);
			fprintf(stderr," label says reel %d\n",Tape_hdr.t_reel);
			goto again;
		}
	}
	rprt(vol);
}
piperr(pbuff)
char pbuff[];
{
	if(pbuff[0] == 'R')
		printf("\volcopy: read sequence error");
	
	else if(pbuff[0] == 'W')
		printf("\volcopy: write sequence error");
	
	else
		printf("\nvolcopy: pipe error = %d",errno);

	printf(" pipe buffer: %.10s\n",pbuff);
	printf(" reel %d, %d blocks\n",reel, Block);
	kilchld();
/*	if(pbuff[0] == 'A') */
		abort();
	exit(1);
}