xref: /csrg-svn/usr.bin/tcopy/tcopy.c (revision 66855)
124973Sbloom /*
262301Sbostic  * Copyright (c) 1985, 1987, 1993
362301Sbostic  *	The Regents of the University of California.  All rights reserved.
432759Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
624973Sbloom  */
724973Sbloom 
824973Sbloom #ifndef lint
962301Sbostic static char copyright[] =
1062301Sbostic "@(#) Copyright (c) 1985, 1987, 1993\n\
1162301Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1232759Sbostic #endif /* not lint */
1324973Sbloom 
1424973Sbloom #ifndef lint
15*66855Smckusick static char sccsid[] = "@(#)tcopy.c	8.2 (Berkeley) 04/17/94";
1632759Sbostic #endif /* not lint */
1724973Sbloom 
1837859Sbostic #include <sys/types.h>
1956106Sbostic #include <sys/stat.h>
2024973Sbloom #include <sys/ioctl.h>
2124973Sbloom #include <sys/mtio.h>
2256106Sbostic 
2356106Sbostic #include <errno.h>
2456106Sbostic #include <fcntl.h>
2551629Sbostic #include <signal.h>
2637859Sbostic #include <stdio.h>
2756106Sbostic #include <stdlib.h>
2856106Sbostic #include <string.h>
2956106Sbostic #include <unistd.h>
3056106Sbostic 
3137859Sbostic #include "pathnames.h"
3224973Sbloom 
3334185Sbostic #define	MAXREC	(64 * 1024)
3434185Sbostic #define	NOCOUNT	(-2)
3534185Sbostic 
3634185Sbostic int	filen, guesslen, maxblk = MAXREC;
3734185Sbostic long	lastrec, record, size, tsize;
38*66855Smckusick FILE	*msg = stdout;
3924973Sbloom 
4056106Sbostic void	*getspace __P((int));
4156106Sbostic void	 intr __P((int));
4256106Sbostic void	 usage __P((void));
4356106Sbostic void	 verify __P((int, int, char *));
4456106Sbostic void	 writeop __P((int, int));
4556106Sbostic 
4656106Sbostic int
4724973Sbloom main(argc, argv)
4832759Sbostic 	int argc;
4956106Sbostic 	char *argv[];
5024973Sbloom {
5134185Sbostic 	register int lastnread, nread, nw, inp, outp;
5234185Sbostic 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
5339834Sbostic 	sig_t oldsig;
5439834Sbostic 	int ch, needeof;
5556106Sbostic 	char *buff, *inf;
5624973Sbloom 
5734185Sbostic 	guesslen = 1;
58*66855Smckusick 	while ((ch = getopt(argc, argv, "cs:vx")) != EOF)
5934185Sbostic 		switch((char)ch) {
6034185Sbostic 		case 'c':
6134185Sbostic 			op = COPYVERIFY;
6234185Sbostic 			break;
6330870Skarels 		case 's':
6434185Sbostic 			maxblk = atoi(optarg);
6530870Skarels 			if (maxblk <= 0) {
6636197Sbostic 				fprintf(stderr, "tcopy: illegal block size\n");
6734185Sbostic 				usage();
6830870Skarels 			}
6930870Skarels 			guesslen = 0;
7030870Skarels 			break;
7134185Sbostic 		case 'v':
7234185Sbostic 			op = VERIFY;
7334185Sbostic 			break;
74*66855Smckusick 		case 'x':
75*66855Smckusick 			msg = stderr;
76*66855Smckusick 			break;
7734185Sbostic 		case '?':
7834185Sbostic 		default:
7934185Sbostic 			usage();
8030870Skarels 		}
8134185Sbostic 	argc -= optind;
8234185Sbostic 	argv += optind;
8334185Sbostic 
8434185Sbostic 	switch(argc) {
8534185Sbostic 	case 0:
8634185Sbostic 		if (op != READ)
8734185Sbostic 			usage();
8837859Sbostic 		inf = _PATH_DEFTAPE;
8934185Sbostic 		break;
9034185Sbostic 	case 1:
9134185Sbostic 		if (op != READ)
9234185Sbostic 			usage();
9334185Sbostic 		inf = argv[0];
9434185Sbostic 		break;
9534185Sbostic 	case 2:
9634185Sbostic 		if (op == READ)
9734185Sbostic 			op = COPY;
9834185Sbostic 		inf = argv[0];
99*66855Smckusick 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
100*66855Smckusick 		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
10134185Sbostic 			perror(argv[1]);
10234185Sbostic 			exit(3);
10334185Sbostic 		}
10434185Sbostic 		break;
10534185Sbostic 	default:
10634185Sbostic 		usage();
10730870Skarels 	}
10834185Sbostic 
10930870Skarels 	if ((inp = open(inf, O_RDONLY, 0)) < 0) {
11030870Skarels 		perror(inf);
11130870Skarels 		exit(1);
11230870Skarels 	}
11334185Sbostic 
11434185Sbostic 	buff = getspace(maxblk);
11534185Sbostic 
11634185Sbostic 	if (op == VERIFY) {
11734185Sbostic 		verify(inp, outp, buff);
11834185Sbostic 		exit(0);
11924973Sbloom 	}
12034185Sbostic 
12134185Sbostic 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
12230870Skarels 		(void) signal(SIGINT, intr);
12334185Sbostic 
12434185Sbostic 	needeof = 0;
12534185Sbostic 	for (lastnread = NOCOUNT;;) {
12634185Sbostic 		if ((nread = read(inp, buff, maxblk)) == -1) {
12734185Sbostic 			while (errno == EINVAL && (maxblk -= 1024)) {
12834185Sbostic 				nread = read(inp, buff, maxblk);
12934185Sbostic 				if (nread >= 0)
13034185Sbostic 					goto r1;
13130870Skarels 			}
13232759Sbostic 			fprintf(stderr, "read error, file %d, record %ld: ",
13330870Skarels 			    filen, record);
13430870Skarels 			perror("");
13534185Sbostic 			exit(1);
13634185Sbostic 		} else if (nread != lastnread) {
13734185Sbostic 			if (lastnread != 0 && lastnread != NOCOUNT) {
13830870Skarels 				if (lastrec == 0 && nread == 0)
139*66855Smckusick 					fprintf(msg, "%ld records\n", record);
14030870Skarels 				else if (record - lastrec > 1)
141*66855Smckusick 					fprintf(msg, "records %ld to %ld\n",
14230870Skarels 					    lastrec, record);
14330870Skarels 				else
144*66855Smckusick 					fprintf(msg, "record %ld\n", lastrec);
14530870Skarels 			}
14630870Skarels 			if (nread != 0)
147*66855Smckusick 				fprintf(msg, "file %d: block size %d: ",
14830870Skarels 				    filen, nread);
14932759Sbostic 			(void) fflush(stdout);
15030870Skarels 			lastrec = record;
15124973Sbloom 		}
15234185Sbostic r1:		guesslen = 0;
15330870Skarels 		if (nread > 0) {
15445518Skarels 			if (op == COPY || op == COPYVERIFY) {
15530870Skarels 				if (needeof) {
15634185Sbostic 					writeop(outp, MTWEOF);
15734185Sbostic 					needeof = 0;
15830870Skarels 				}
15930870Skarels 				nw = write(outp, buff, nread);
16030870Skarels 				if (nw != nread) {
16130870Skarels 				    fprintf(stderr,
16232759Sbostic 					"write error, file %d, record %ld: ",
16330870Skarels 					filen, record);
16430870Skarels 				    if (nw == -1)
16530870Skarels 					perror("");
16630870Skarels 				    else
16730870Skarels 					fprintf(stderr,
16830870Skarels 					    "write (%d) != read (%d)\n",
16930870Skarels 					    nw, nread);
17030870Skarels 				    fprintf(stderr, "copy aborted\n");
17130870Skarels 				    exit(5);
17230870Skarels 				}
17330870Skarels 			}
17430870Skarels 			size += nread;
17530870Skarels 			record++;
17630870Skarels 		} else {
17734185Sbostic 			if (lastnread <= 0 && lastnread != NOCOUNT) {
178*66855Smckusick 				fprintf(msg, "eot\n");
17924973Sbloom 				break;
18024973Sbloom 			}
181*66855Smckusick 			fprintf(msg,
182*66855Smckusick 			    "file %d: eof after %ld records: %ld bytes\n",
183*66855Smckusick 			    filen, record, size);
18430870Skarels 			needeof = 1;
18524973Sbloom 			filen++;
18624973Sbloom 			tsize += size;
18734185Sbostic 			size = record = lastrec = 0;
18834185Sbostic 			lastnread = 0;
18924973Sbloom 		}
19034185Sbostic 		lastnread = nread;
19124973Sbloom 	}
192*66855Smckusick 	fprintf(msg, "total length: %ld bytes\n", tsize);
19334185Sbostic 	(void)signal(SIGINT, oldsig);
19445518Skarels 	if (op == COPY || op == COPYVERIFY) {
19534185Sbostic 		writeop(outp, MTWEOF);
19634185Sbostic 		writeop(outp, MTWEOF);
19734185Sbostic 		if (op == COPYVERIFY) {
19834185Sbostic 			writeop(outp, MTREW);
19934185Sbostic 			writeop(inp, MTREW);
20034185Sbostic 			verify(inp, outp, buff);
20134185Sbostic 		}
20234185Sbostic 	}
20334185Sbostic 	exit(0);
20424973Sbloom }
20524973Sbloom 
20656106Sbostic void
20734185Sbostic verify(inp, outp, outb)
20834185Sbostic 	register int inp, outp;
20934185Sbostic 	register char *outb;
21034185Sbostic {
21134185Sbostic 	register int eot, inmaxblk, inn, outmaxblk, outn;
21234185Sbostic 	register char *inb;
21334185Sbostic 
21434185Sbostic 	inb = getspace(maxblk);
21534185Sbostic 	inmaxblk = outmaxblk = maxblk;
21634185Sbostic 	for (eot = 0;; guesslen = 0) {
21734185Sbostic 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
21834185Sbostic 			if (guesslen)
21934185Sbostic 				while (errno == EINVAL && (inmaxblk -= 1024)) {
22034185Sbostic 					inn = read(inp, inb, inmaxblk);
22134185Sbostic 					if (inn >= 0)
22234185Sbostic 						goto r1;
22334185Sbostic 				}
22434185Sbostic 			perror("tcopy: read error");
22536197Sbostic 			break;
22634185Sbostic 		}
22734185Sbostic r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
22834185Sbostic 			if (guesslen)
22934185Sbostic 				while (errno == EINVAL && (outmaxblk -= 1024)) {
23034185Sbostic 					outn = read(outp, outb, outmaxblk);
23134185Sbostic 					if (outn >= 0)
23234185Sbostic 						goto r2;
23334185Sbostic 				}
23434185Sbostic 			perror("tcopy: read error");
23536197Sbostic 			break;
23634185Sbostic 		}
23736197Sbostic r2:		if (inn != outn) {
238*66855Smckusick 			fprintf(msg,
239*66855Smckusick 			    "%s: tapes have different block sizes; %d != %d.\n",
240*66855Smckusick 			    "tcopy", inn, outn);
24134185Sbostic 			break;
24236197Sbostic 		}
24334185Sbostic 		if (!inn) {
24434185Sbostic 			if (eot++) {
245*66855Smckusick 				fprintf(msg, "tcopy: tapes are identical.\n");
24634185Sbostic 				return;
24734185Sbostic 			}
24834185Sbostic 		} else {
24936197Sbostic 			if (bcmp(inb, outb, inn)) {
250*66855Smckusick 				fprintf(msg,
251*66855Smckusick 				    "tcopy: tapes have different data.\n");
25234185Sbostic 				break;
25336197Sbostic 			}
25434185Sbostic 			eot = 0;
25534185Sbostic 		}
25634185Sbostic 	}
25734185Sbostic 	exit(1);
25834185Sbostic }
25934185Sbostic 
26039834Sbostic void
26156106Sbostic intr(signo)
26256106Sbostic 	int signo;
26324973Sbloom {
26430870Skarels 	if (record)
26530870Skarels 		if (record - lastrec > 1)
266*66855Smckusick 			fprintf(msg, "records %ld to %ld\n", lastrec, record);
26724973Sbloom 		else
268*66855Smckusick 			fprintf(msg, "record %ld\n", lastrec);
269*66855Smckusick 	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
270*66855Smckusick 	fprintf(msg, "total length: %ld bytes\n", tsize + size);
27124973Sbloom 	exit(1);
27224973Sbloom }
27334185Sbostic 
27456106Sbostic void *
27534185Sbostic getspace(blk)
27634185Sbostic 	int blk;
27734185Sbostic {
27856106Sbostic 	void *bp;
27934185Sbostic 
28056106Sbostic 	if ((bp = malloc((size_t)blk)) == NULL) {
28136197Sbostic 		fprintf(stderr, "tcopy: no memory\n");
28234185Sbostic 		exit(11);
28334185Sbostic 	}
28456106Sbostic 	return (bp);
28534185Sbostic }
28634185Sbostic 
28756106Sbostic void
28834185Sbostic writeop(fd, type)
28934185Sbostic 	int fd, type;
29034185Sbostic {
29134185Sbostic 	struct mtop op;
29234185Sbostic 
29334185Sbostic 	op.mt_op = type;
29434185Sbostic 	op.mt_count = (daddr_t)1;
29534185Sbostic 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
29634185Sbostic 		perror("tcopy: tape op");
29734185Sbostic 		exit(6);
29834185Sbostic 	}
29934185Sbostic }
30034185Sbostic 
30156106Sbostic void
30234185Sbostic usage()
30334185Sbostic {
304*66855Smckusick 	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
30534185Sbostic 	exit(1);
30634185Sbostic }
307