xref: /csrg-svn/usr.bin/tcopy/tcopy.c (revision 68193)
124973Sbloom /*
2*68193Spendry  * Copyright (c) 1985, 1987, 1993, 1995
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*68193Spendry static char sccsid[] = "@(#)tcopy.c	8.3 (Berkeley) 01/23/95";
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 
23*68193Spendry #include <err.h>
2456106Sbostic #include <errno.h>
2556106Sbostic #include <fcntl.h>
2651629Sbostic #include <signal.h>
2737859Sbostic #include <stdio.h>
2856106Sbostic #include <stdlib.h>
2956106Sbostic #include <string.h>
3056106Sbostic #include <unistd.h>
3156106Sbostic 
3237859Sbostic #include "pathnames.h"
3324973Sbloom 
3434185Sbostic #define	MAXREC	(64 * 1024)
3534185Sbostic #define	NOCOUNT	(-2)
3634185Sbostic 
3734185Sbostic int	filen, guesslen, maxblk = MAXREC;
38*68193Spendry long	lastrec, record;
39*68193Spendry off_t	size, tsize;
4066855Smckusick FILE	*msg = stdout;
4124973Sbloom 
4256106Sbostic void	*getspace __P((int));
4356106Sbostic void	 intr __P((int));
4456106Sbostic void	 usage __P((void));
4556106Sbostic void	 verify __P((int, int, char *));
4656106Sbostic void	 writeop __P((int, int));
4756106Sbostic 
4856106Sbostic int
main(argc,argv)4924973Sbloom main(argc, argv)
5032759Sbostic 	int argc;
5156106Sbostic 	char *argv[];
5224973Sbloom {
53*68193Spendry 	int ch, needeof, nw, inp, outp;
54*68193Spendry 	ssize_t lastnread, nread;
5534185Sbostic 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
5639834Sbostic 	sig_t oldsig;
5756106Sbostic 	char *buff, *inf;
5824973Sbloom 
5934185Sbostic 	guesslen = 1;
6066855Smckusick 	while ((ch = getopt(argc, argv, "cs:vx")) != EOF)
6134185Sbostic 		switch((char)ch) {
6234185Sbostic 		case 'c':
6334185Sbostic 			op = COPYVERIFY;
6434185Sbostic 			break;
6530870Skarels 		case 's':
6634185Sbostic 			maxblk = atoi(optarg);
6730870Skarels 			if (maxblk <= 0) {
68*68193Spendry 				warnx("illegal block size");
6934185Sbostic 				usage();
7030870Skarels 			}
7130870Skarels 			guesslen = 0;
7230870Skarels 			break;
7334185Sbostic 		case 'v':
7434185Sbostic 			op = VERIFY;
7534185Sbostic 			break;
7666855Smckusick 		case 'x':
7766855Smckusick 			msg = stderr;
7866855Smckusick 			break;
7934185Sbostic 		case '?':
8034185Sbostic 		default:
8134185Sbostic 			usage();
8230870Skarels 		}
8334185Sbostic 	argc -= optind;
8434185Sbostic 	argv += optind;
8534185Sbostic 
8634185Sbostic 	switch(argc) {
8734185Sbostic 	case 0:
8834185Sbostic 		if (op != READ)
8934185Sbostic 			usage();
9037859Sbostic 		inf = _PATH_DEFTAPE;
9134185Sbostic 		break;
9234185Sbostic 	case 1:
9334185Sbostic 		if (op != READ)
9434185Sbostic 			usage();
9534185Sbostic 		inf = argv[0];
9634185Sbostic 		break;
9734185Sbostic 	case 2:
9834185Sbostic 		if (op == READ)
9934185Sbostic 			op = COPY;
10034185Sbostic 		inf = argv[0];
10166855Smckusick 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
10266855Smckusick 		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
103*68193Spendry 			err(3, argv[1]);
10434185Sbostic 		}
10534185Sbostic 		break;
10634185Sbostic 	default:
10734185Sbostic 		usage();
10830870Skarels 	}
10934185Sbostic 
110*68193Spendry 	if ((inp = open(inf, O_RDONLY, 0)) < 0)
111*68193Spendry 		err(1, inf);
11234185Sbostic 
11334185Sbostic 	buff = getspace(maxblk);
11434185Sbostic 
11534185Sbostic 	if (op == VERIFY) {
11634185Sbostic 		verify(inp, outp, buff);
11734185Sbostic 		exit(0);
11824973Sbloom 	}
11934185Sbostic 
12034185Sbostic 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
12130870Skarels 		(void) signal(SIGINT, intr);
12234185Sbostic 
12334185Sbostic 	needeof = 0;
12434185Sbostic 	for (lastnread = NOCOUNT;;) {
12534185Sbostic 		if ((nread = read(inp, buff, maxblk)) == -1) {
12634185Sbostic 			while (errno == EINVAL && (maxblk -= 1024)) {
12734185Sbostic 				nread = read(inp, buff, maxblk);
12834185Sbostic 				if (nread >= 0)
12934185Sbostic 					goto r1;
13030870Skarels 			}
131*68193Spendry 			err(1, "read error, file %d, record %ld",
13230870Skarels 			    filen, record);
13334185Sbostic 		} else if (nread != lastnread) {
13434185Sbostic 			if (lastnread != 0 && lastnread != NOCOUNT) {
13530870Skarels 				if (lastrec == 0 && nread == 0)
13666855Smckusick 					fprintf(msg, "%ld records\n", record);
13730870Skarels 				else if (record - lastrec > 1)
13866855Smckusick 					fprintf(msg, "records %ld to %ld\n",
13930870Skarels 					    lastrec, record);
14030870Skarels 				else
14166855Smckusick 					fprintf(msg, "record %ld\n", lastrec);
14230870Skarels 			}
14330870Skarels 			if (nread != 0)
14466855Smckusick 				fprintf(msg, "file %d: block size %d: ",
14530870Skarels 				    filen, nread);
14632759Sbostic 			(void) fflush(stdout);
14730870Skarels 			lastrec = record;
14824973Sbloom 		}
14934185Sbostic r1:		guesslen = 0;
15030870Skarels 		if (nread > 0) {
15145518Skarels 			if (op == COPY || op == COPYVERIFY) {
15230870Skarels 				if (needeof) {
15334185Sbostic 					writeop(outp, MTWEOF);
15434185Sbostic 					needeof = 0;
15530870Skarels 				}
15630870Skarels 				nw = write(outp, buff, nread);
15730870Skarels 				if (nw != nread) {
158*68193Spendry 				    int error = errno;
15930870Skarels 				    fprintf(stderr,
16032759Sbostic 					"write error, file %d, record %ld: ",
16130870Skarels 					filen, record);
16230870Skarels 				    if (nw == -1)
163*68193Spendry 					fprintf(stderr,
164*68193Spendry 						": %s", strerror(error));
16530870Skarels 				    else
16630870Skarels 					fprintf(stderr,
16730870Skarels 					    "write (%d) != read (%d)\n",
16830870Skarels 					    nw, nread);
16930870Skarels 				    fprintf(stderr, "copy aborted\n");
17030870Skarels 				    exit(5);
17130870Skarels 				}
17230870Skarels 			}
17330870Skarels 			size += nread;
17430870Skarels 			record++;
17530870Skarels 		} else {
17634185Sbostic 			if (lastnread <= 0 && lastnread != NOCOUNT) {
17766855Smckusick 				fprintf(msg, "eot\n");
17824973Sbloom 				break;
17924973Sbloom 			}
18066855Smckusick 			fprintf(msg,
181*68193Spendry 			    "file %d: eof after %ld records: %qd bytes\n",
18266855Smckusick 			    filen, record, size);
18330870Skarels 			needeof = 1;
18424973Sbloom 			filen++;
18524973Sbloom 			tsize += size;
18634185Sbostic 			size = record = lastrec = 0;
18734185Sbostic 			lastnread = 0;
18824973Sbloom 		}
18934185Sbostic 		lastnread = nread;
19024973Sbloom 	}
191*68193Spendry 	fprintf(msg, "total length: %qd bytes\n", tsize);
19234185Sbostic 	(void)signal(SIGINT, oldsig);
19345518Skarels 	if (op == COPY || op == COPYVERIFY) {
19434185Sbostic 		writeop(outp, MTWEOF);
19534185Sbostic 		writeop(outp, MTWEOF);
19634185Sbostic 		if (op == COPYVERIFY) {
19734185Sbostic 			writeop(outp, MTREW);
19834185Sbostic 			writeop(inp, MTREW);
19934185Sbostic 			verify(inp, outp, buff);
20034185Sbostic 		}
20134185Sbostic 	}
20234185Sbostic 	exit(0);
20324973Sbloom }
20424973Sbloom 
20556106Sbostic void
verify(inp,outp,outb)20634185Sbostic verify(inp, outp, outb)
207*68193Spendry 	int inp, outp;
208*68193Spendry 	char *outb;
20934185Sbostic {
210*68193Spendry 	int eot, inmaxblk, inn, outmaxblk, outn;
211*68193Spendry 	char *inb;
21234185Sbostic 
21334185Sbostic 	inb = getspace(maxblk);
21434185Sbostic 	inmaxblk = outmaxblk = maxblk;
21534185Sbostic 	for (eot = 0;; guesslen = 0) {
21634185Sbostic 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
21734185Sbostic 			if (guesslen)
21834185Sbostic 				while (errno == EINVAL && (inmaxblk -= 1024)) {
21934185Sbostic 					inn = read(inp, inb, inmaxblk);
22034185Sbostic 					if (inn >= 0)
22134185Sbostic 						goto r1;
22234185Sbostic 				}
223*68193Spendry 			warn("read error");
22436197Sbostic 			break;
22534185Sbostic 		}
22634185Sbostic r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
22734185Sbostic 			if (guesslen)
22834185Sbostic 				while (errno == EINVAL && (outmaxblk -= 1024)) {
22934185Sbostic 					outn = read(outp, outb, outmaxblk);
23034185Sbostic 					if (outn >= 0)
23134185Sbostic 						goto r2;
23234185Sbostic 				}
233*68193Spendry 			warn("read error");
23436197Sbostic 			break;
23534185Sbostic 		}
23636197Sbostic r2:		if (inn != outn) {
23766855Smckusick 			fprintf(msg,
23866855Smckusick 			    "%s: tapes have different block sizes; %d != %d.\n",
23966855Smckusick 			    "tcopy", inn, outn);
24034185Sbostic 			break;
24136197Sbostic 		}
24234185Sbostic 		if (!inn) {
24334185Sbostic 			if (eot++) {
244*68193Spendry 				fprintf(msg, "%s: tapes are identical.\n",
245*68193Spendry 					"tcopy");
24634185Sbostic 				return;
24734185Sbostic 			}
24834185Sbostic 		} else {
24936197Sbostic 			if (bcmp(inb, outb, inn)) {
25066855Smckusick 				fprintf(msg,
251*68193Spendry 				    "%s: tapes have different data.\n",
252*68193Spendry 					"tcopy");
25334185Sbostic 				break;
25436197Sbostic 			}
25534185Sbostic 			eot = 0;
25634185Sbostic 		}
25734185Sbostic 	}
25834185Sbostic 	exit(1);
25934185Sbostic }
26034185Sbostic 
26139834Sbostic void
intr(signo)26256106Sbostic intr(signo)
26356106Sbostic 	int signo;
26424973Sbloom {
26530870Skarels 	if (record)
26630870Skarels 		if (record - lastrec > 1)
26766855Smckusick 			fprintf(msg, "records %ld to %ld\n", lastrec, record);
26824973Sbloom 		else
26966855Smckusick 			fprintf(msg, "record %ld\n", lastrec);
27066855Smckusick 	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
271*68193Spendry 	fprintf(msg, "total length: %qd bytes\n", tsize + size);
27224973Sbloom 	exit(1);
27324973Sbloom }
27434185Sbostic 
27556106Sbostic void *
getspace(blk)27634185Sbostic getspace(blk)
27734185Sbostic 	int blk;
27834185Sbostic {
27956106Sbostic 	void *bp;
28034185Sbostic 
281*68193Spendry 	if ((bp = malloc((size_t)blk)) == NULL)
282*68193Spendry 		errx(11, "no memory");
283*68193Spendry 
28456106Sbostic 	return (bp);
28534185Sbostic }
28634185Sbostic 
28756106Sbostic void
writeop(fd,type)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;
295*68193Spendry 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
296*68193Spendry 		err(6, "tape op");
29734185Sbostic }
29834185Sbostic 
29956106Sbostic void
usage()30034185Sbostic usage()
30134185Sbostic {
302*68193Spendry 
30366855Smckusick 	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
30434185Sbostic 	exit(1);
30534185Sbostic }
306