/*	volcopy	COMPILE:	cc -O volcopy.c -s -i -o volcopy	*/
/*	u370	COMPILE:	cc -O -b1,1 volcopy.c -s -i -o volcopy	*/

/*	@(#)volcopy.c	2.1		*/

#define LOG
#define AFLG 0 
#ifdef RT
#include <rt/types.h>
#include <rt/param.h>
#include <rt/fmgr/filsys.h>
#include <rt/stat.h>
#else
#include <sys/param.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/filsys.h>
#include <sys/stat.h>
#endif
#include <stdio.h>
#include <signal.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 */
#ifdef RT
#define IFTAPE(s) (EQ(s,"/dev/mt",7)||EQ(s,"mt",2))
#else
#define IFTAPE(s) (EQ(s,"/dev/rmt",8)||EQ(s,"rmt",3)||EQ(s,"/dev/rtp",8)||EQ(s,"rtp",3))
#endif
#ifdef	u370
#define BLKSIZ	4096
#else
#define	BLKSIZ	512	/* use physical blocks */
#endif
#define _2_DAYS 172800L
#define MAX 1000000L
#ifdef	u370
#define Ft800x10	2L	/* u370 */
#define Ft1600x10	4L	/* u370 */
#define Ft6250x50	15L	/* u370 */
#else
#define Ft800x10	15L
#define Ft1600x4	22L
#define Ft1600x10	28L
#define Ft6250x10	90L
#define Ft6250x50	120L
#endif

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[468];
	int	t_type;		/* does tape have nblocks field? (u3b) */
} Tape_hdr;

int	K_drive = 0;		/* Kennedy tape drive? (4 blks/rec max) */
int	first = 0;
char	**args;
int	Nblocks = 0;
long	Reelblks = 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;
extern	int errno;
/*

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 "DEL if wrong"
	-s    - inverse of -a

  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 10 seconds to DEL if mistaken!
With '-a' option, a positive user response is required to continue.
With '-s' 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;
	struct	stat statb;
	long	tvec;
	int	i, altflg = AFLG;
	FILE	*fb, *popen();
	char	vol[12], dev[12], c;

	signal(SIGALRM, sigalrm);

	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],"-a",2))
			altflg++;
		else if(EQ(argv[1],"-s",2))
			altflg = 0;
		else {
			fprintf(stderr, "<%s> invalid option\n",
				argv[1]);
			exit(1);
		}
		++argv;
		--argc;
	}
	args = argv;

	Devtty = fopen("/dev/tty", "r");
	time(&tvec);
			/* get mandatory inputs */
	if(argc!=6){
		fprintf(stderr,"Usage: volcopy [options] fsname");
		fprintf(stderr,"/devfrom volfrom /devto volto\n");
		exit (9);
	}

	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");

#ifdef RT
	if((fstat(fsi, &statb)<0) || (((statb.st_mode&S_IFMT)!=S_IFBLK)
		&& ((statb.st_mode & S_IFMT) != S_IFREC)
		&& ((statb.st_mode & S_IFMT) != S_IFCHR)))
		err("From device not character, block, or record special");
	if(fstat(fso, &statb)<0 || (((statb.st_mode&S_IFMT)!=S_IFBLK)
		&& ((statb.st_mode & S_IFMT) != S_IFREC)
		&& ((statb.st_mode & S_IFMT) != S_IFCHR)))
		err("To device not character, block, or record special");
#else
	if(fstat(fsi, &statb)<0 || (statb.st_mode&S_IFMT)!=S_IFCHR)
		err("From device not character-special");
	if(fstat(fso, &statb)<0 || (statb.st_mode&S_IFMT)!=S_IFCHR)
		err("To device not character-special");
#endif

	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)
		err("Use dd(1) command to copy tapes");

#ifdef RT
	setio(-1,1);	/* use physical io */
#endif

#ifdef	u370
	Nblocks = (Totape||Fromtape)? 8:8; /* disk-disk can even be > 8 */
	Buf = (short *)malloc(BLKSIZ*(Nblocks+1));
	/* Force buffer to page boundary */
	Buf = (short *)((int)((char *)Buf+BLKSIZ) & ~(BLKSIZ-1));

	if ((int)Buf <= 1) {
		fprintf(stderr, "Not enough memory--get help\n");
		exit(1);
	}
#else

#ifdef u3b
	if (K_drive)
		Nblocks = 4;
	else
		Nblocks = ((Totape||Fromtape)&&(Bpi!=6250))? 10:152;
#else
	Nblocks = ((Totape||Fromtape)&&(Bpi!=6250))? 10:88;
#endif
#ifdef u3b
	if(Bpi == 6250) Nblocks = 10;
#else
	if(Bpi == 6250) Nblocks = 50;
#endif
	Buf = (short *)sbrk(BLKSIZ*Nblocks);
#ifdef u3b
	if((int)Buf == -1 && Nblocks ==152) {
		Nblocks = 32;
#else
	if((int)Buf == -1 && Nblocks ==88) {
		Nblocks = 22;
#endif
		Buf = (short *)sbrk(BLKSIZ*Nblocks);
	}
	if((int)Buf == -1) {
		fprintf(stderr, "Not enough memory--get help\n");
		exit(1);
	}
#endif
	Sptr = (struct filsys *)&Buf[BLKSIZ/2];
	if(!Fromtape && !Totape) reel = 1;
	if((reel == 1) || !Fromtape){
		if(read(fsi, Buf, 2*BLKSIZ) < 2*BLKSIZ)
			err("read error on input");
		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");
		}

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

	if(read(fso, Buf, 2*BLKSIZ) < 2*BLKSIZ){
		fprintf(stderr,"Read error on output\n");
		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 reels.\n", Reels);
		printf("(\tThe same size and density");
		printf(" is expected for all reels)\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();
	}

COPY:
	printf("From: %s, to: %s? ",
		argv[DEV_FROM], argv[DEV_TO]);
	if(altflg){
		if(!asks("(y or n) ")) {
					printf("\nvolcopy: STOP\n");
					exit(9);
					}
	}
	else {
                printf("(DEL if wrong)\n");
		sleep(10);   /*  10 seconds to DEL  */
	}
	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;
		write(fso, &Tape_hdr, sizeof Tape_hdr);
		strcpy(vol,argv[TO_VOL]);
	} else if(Fromtape) {
		read(fsi, &Tape_hdr, sizeof Tape_hdr);
	}
	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("  END: %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;
{
#ifdef u3b
	if (inp[4] == 'k' || inp[4] == 'K') {
		K_drive++;
		inp[4] = '\0';
	}
#endif
	return(atoi(inp));
}

char *tapeck(dev, vol, fd)
char *dev, *vol;
{
	char	resp[16];

	if(!IFTAPE(dev))
		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)
		printf("\n ERR %d\n",errno);
	alarm(0);
	if(!EQ(Tape_hdr.t_magic, "Volcopy", 7)){
		fprintf(stderr,"Not a labeled tape");
		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;
#ifdef u3b
		if (Tape_hdr.t_type == T_TYPE)
			if (Tape_hdr.t_nblocks == 4)
				K_drive++; /* use Kennedy tapedrive limit */
#endif
	}
	else{
		Reels = 0;
	}
	if(Reelsize == 0) {
		printf("Enter size of reel in feet for <%s>:   ", vol);
		fgets(resp, 10, Devtty);
		Reelsize = atoi(resp);
	}
#ifdef	u370
	if(Reelsize <= 0 || Reelsize > 3600) {
		fprintf(stderr, "Size of reel must be > 0, <= 3600\n");
#else
	if(Reelsize <= 0 || Reelsize > 2400) {
		fprintf(stderr, "Size of reel must be > 0, <= 2400\n");
#endif
		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) {
#ifdef u3b
		if (K_drive)
			Reelblks = Ft1600x4 * Reelsize;
		else
#endif
			Reelblks = Ft1600x10 * Reelsize;
	}
	else if(Bpi == 6250)
#ifdef u3b
		Reelblks = Ft6250x10 * Reelsize;
#else
		Reelblks = Ft6250x50 * Reelsize;
#endif
	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 header\n");
		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("\nWriting REEL %d of %d, VOL = %.6s\n",
		  reel,Reels,vol);
	if(Fromtape)
		printf("\nReading 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) == -1) {
		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 \"%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("rm /tmp/FSJUNK");
	exit(0);
}
copy(fsi,fso)
int fsi,fso;
{
	int i, cnt, pos;
	int p1[2], p2[2];
	char buf[20];

	pid = -1;
	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) {
			printf("Read error %d block %ld...\n", sts, 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) {
			printf("Write error %d, block %ld...\n",
				errno,Block);
			if(Totape) {
				if(pid == 1) {
					write(p_out,"Tape error",10);
					exit(1);
				}
		oterr:		if(asks("Want to try another tape?   ")) {
					asks("Type `y' when ready:   ");
					--reel;
					Block = reeloff;
					Fs = saveFs;
					lseek(fsi, (long)reeloff*BLKSIZ, 0);
					return(1);
				}
			} else {
				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) {
pfin:		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];

	rblock = 0;
	reeloff = Block;
	saveFs = Fs;
	++reel;
again:
	if((sts = close(fs)) < 0)
		printf("\n ERR %d\n",errno);
	 printf("Changing drives? (type RETURN for no, ");
#ifdef RT
		printf("`/dev/mt_' for yes: ");
#else
		printf("`/dev/rmt_' for yes: ");
#endif
	fgets(ctemp, 20, Devtty);
	ctemp[strlen(ctemp) -1] = '\0';
	if(ctemp[0] != '\0')
		while(strncmp(ctemp,"/dev/rmt",8)){
		  printf("\n'%s' is not a valid device",ctemp);
		  printf("\nenter device name `/dev/rmt?' : ");
		  fgets(ctemp, 20, Devtty);
		  ctemp[strlen(ctemp) -1] = '\0';
		}
		strcpy(dev,ctemp);
	printf("Mount tape %d\nType volume-ID when ready:   ",
		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 || fs > 10)
			printf("\n ERR %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 || fs > 10)
			printf("\n ERR %d\n",errno);
		if(write(fs, &Tape_hdr, sizeof Tape_hdr) < 0) {
 				 fprintf(stderr, "Cannot re-write header");
		 fprintf(stderr,"-%s\n","Try again!");
		  goto again;
		}
	} else {
		fs = open(Tape_nm, 0);
		if(fs <= 0 || fs > 10)
			printf("\n ERR %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);
}
