tcopy.c revision 24360
161981Sbrian/*
261981Sbrian * Copyright (c) 1985, 1987, 1993
361981Sbrian *	The Regents of the University of California.  All rights reserved.
461981Sbrian *
561981Sbrian * Redistribution and use in source and binary forms, with or without
661981Sbrian * modification, are permitted provided that the following conditions
761981Sbrian * are met:
861981Sbrian * 1. Redistributions of source code must retain the above copyright
961981Sbrian *    notice, this list of conditions and the following disclaimer.
1061981Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1161981Sbrian *    notice, this list of conditions and the following disclaimer in the
1261981Sbrian *    documentation and/or other materials provided with the distribution.
13140771Skeramida * 3. All advertising materials mentioning features or use of this software
14140771Skeramida *    must display the following acknowledgement:
15140771Skeramida *	This product includes software developed by the University of
1661981Sbrian *	California, Berkeley and its contributors.
1761981Sbrian * 4. Neither the name of the University nor the names of its contributors
1861981Sbrian *    may be used to endorse or promote products derived from this software
1961981Sbrian *    without specific prior written permission.
2061981Sbrian *
2161981Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2261981Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23170085Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2461981Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2561981Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2661981Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2761981Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2865843Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2965843Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3065843Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3165843Sbrian * SUCH DAMAGE.
3265843Sbrian */
3365843Sbrian
3465843Sbrian#ifndef lint
3565843Sbrianstatic char copyright[] =
3665843Sbrian"@(#) Copyright (c) 1985, 1987, 1993\n\
3765843Sbrian	The Regents of the University of California.  All rights reserved.\n";
3861981Sbrian#endif /* not lint */
3961981Sbrian
4061981Sbrian#ifndef lint
4161981Sbrianstatic char sccsid[] = "@(#)tcopy.c	8.2 (Berkeley) 4/17/94";
4261981Sbrian#endif /* not lint */
4361981Sbrian
4461981Sbrian#include <sys/types.h>
4561981Sbrian#include <sys/stat.h>
4661981Sbrian#include <sys/ioctl.h>
4761981Sbrian#include <sys/mtio.h>
48174028Sjhb
49205509Sjoerg#include <errno.h>
50236284Seadler#include <fcntl.h>
51174028Sjhb#include <signal.h>
5261981Sbrian#include <stdio.h>
5361981Sbrian#include <stdlib.h>
5461981Sbrian#include <string.h>
5561981Sbrian#include <unistd.h>
5661981Sbrian
5761981Sbrian#include "pathnames.h"
5861981Sbrian
5961981Sbrian#define	MAXREC	(64 * 1024)
6061981Sbrian#define	NOCOUNT	(-2)
6161981Sbrian
6261981Sbrianint	filen, guesslen, maxblk = MAXREC;
6361981Sbrianu_long	lastrec, record, size, tsize;
6461981SbrianFILE	*msg = stdout;
6561981Sbrian
6661981Sbrianvoid	*getspace __P((int));
6761981Sbrianvoid	 intr __P((int));
6861981Sbrianvoid	 usage __P((void));
69108959Swollmanvoid	 verify __P((int, int, char *));
70108959Swollmanvoid	 writeop __P((int, int));
7161981Sbrian
7261981Sbrianint
7361981Sbrianmain(argc, argv)
7461981Sbrian	int argc;
7561981Sbrian	char *argv[];
7661981Sbrian{
7761981Sbrian	register int lastnread, nread, nw, inp, outp;
78220020Sdougb	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
79220020Sdougb	sig_t oldsig;
80220020Sdougb	int ch, needeof;
81220020Sdougb	char *buff, *inf;
8261981Sbrian
8361981Sbrian	guesslen = 1;
8461981Sbrian	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
8561981Sbrian		switch((char)ch) {
8661981Sbrian		case 'c':
8762054Sbrian			op = COPYVERIFY;
8877496Sbrian			break;
8977492Sbrian		case 's':
9061981Sbrian			maxblk = atoi(optarg);
9161981Sbrian			if (maxblk <= 0) {
9261981Sbrian				fprintf(stderr, "tcopy: illegal block size\n");
9361981Sbrian				usage();
9461981Sbrian			}
9561981Sbrian			guesslen = 0;
96281318Sjhb			break;
9761981Sbrian		case 'v':
98249095Smav			op = VERIFY;
99249095Smav			break;
100249095Smav		case 'x':
101168412Spjd			msg = stderr;
102168412Spjd			break;
103231171Sgjb		case '?':
104168412Spjd		default:
105154304Swollman			usage();
106154304Swollman		}
107154304Swollman	argc -= optind;
108156216Sbrueffer	argv += optind;
109156216Sbrueffer
110156216Sbrueffer	switch(argc) {
111156216Sbrueffer	case 0:
112156216Sbrueffer		if (op != READ)
113156216Sbrueffer			usage();
114156216Sbrueffer		inf = _PATH_DEFTAPE;
115156216Sbrueffer		break;
116156216Sbrueffer	case 1:
11761981Sbrian		if (op != READ)
11861981Sbrian			usage();
11961981Sbrian		inf = argv[0];
120282243Sjhb		break;
12161981Sbrian	case 2:
12261981Sbrian		if (op == READ)
12361981Sbrian			op = COPY;
12461981Sbrian		inf = argv[0];
12561981Sbrian		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
12661981Sbrian		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
12761981Sbrian			perror(argv[1]);
12894342Sgshapiro			exit(3);
12961981Sbrian		}
13061981Sbrian		break;
13161981Sbrian	default:
132254974Sjlh		usage();
133254974Sjlh	}
134254974Sjlh
13561981Sbrian	if ((inp = open(inf, O_RDONLY, 0)) < 0) {
13661981Sbrian		perror(inf);
13761981Sbrian		exit(1);
13862274Sbrian	}
139175153Sdds
14061981Sbrian	buff = getspace(maxblk);
141295461Scy
142295461Scy	if (op == VERIFY) {
143295461Scy		verify(inp, outp, buff);
144295461Scy		exit(0);
145295461Scy	}
146169517Smaxim
147169517Smaxim	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
148169517Smaxim		(void) signal(SIGINT, intr);
14972677Speter
15072677Speter	needeof = 0;
15194342Sgshapiro	for (lastnread = NOCOUNT;;) {
15272677Speter		if ((nread = read(inp, buff, maxblk)) == -1) {
153277520Sgjb			while (errno == EINVAL && (maxblk -= 1024)) {
154277520Sgjb				nread = read(inp, buff, maxblk);
155277520Sgjb				if (nread >= 0)
156277520Sgjb					goto r1;
157226471Sse			}
158226471Sse			fprintf(stderr, "read error, file %d, record %ld: ",
159226471Sse			    filen, record);
160226865Sdelphij			perror("");
161226865Sdelphij			exit(1);
162226471Sse		} else if (nread != lastnread) {
16361981Sbrian			if (lastnread != 0 && lastnread != NOCOUNT) {
16461981Sbrian				if (lastrec == 0 && nread == 0)
16561981Sbrian					fprintf(msg, "%ld records\n", record);
16661981Sbrian				else if (record - lastrec > 1)
167255169Sjlh					fprintf(msg, "records %ld to %ld\n",
168255169Sjlh					    lastrec, record);
169255169Sjlh				else
170255169Sjlh					fprintf(msg, "record %ld\n", lastrec);
171255169Sjlh			}
172255169Sjlh			if (nread != 0)
173255169Sjlh				fprintf(msg, "file %d: block size %d: ",
174255169Sjlh				    filen, nread);
175255169Sjlh			(void) fflush(stdout);
176255169Sjlh			lastrec = record;
177255169Sjlh		}
178255169Sjlhr1:		guesslen = 0;
179255169Sjlh		if (nread > 0) {
180255169Sjlh			if (op == COPY || op == COPYVERIFY) {
181255169Sjlh				if (needeof) {
182255169Sjlh					writeop(outp, MTWEOF);
183255169Sjlh					needeof = 0;
184255169Sjlh				}
185255169Sjlh				nw = write(outp, buff, nread);
186255169Sjlh				if (nw != nread) {
187255169Sjlh				    fprintf(stderr,
188255169Sjlh					"write error, file %d, record %ld: ",
189255169Sjlh					filen, record);
190255169Sjlh				    if (nw == -1)
191255169Sjlh					perror("");
192255169Sjlh				    else
193255169Sjlh					fprintf(stderr,
194255169Sjlh					    "write (%d) != read (%d)\n",
195255169Sjlh					    nw, nread);
196255169Sjlh				    fprintf(stderr, "copy aborted\n");
197255169Sjlh				    exit(5);
198255169Sjlh				}
199255169Sjlh			}
200255169Sjlh			size += nread;
201255169Sjlh			record++;
202255169Sjlh		} else {
203255169Sjlh			if (lastnread <= 0 && lastnread != NOCOUNT) {
204255169Sjlh				fprintf(msg, "eot\n");
205255169Sjlh				break;
206255169Sjlh			}
207255169Sjlh			fprintf(msg,
208255169Sjlh			    "file %d: eof after %lu records: %lu bytes\n",
209255169Sjlh			    filen, record, size);
210255169Sjlh			needeof = 1;
211255169Sjlh			filen++;
212255169Sjlh			tsize += size;
213255169Sjlh			size = record = lastrec = 0;
214255169Sjlh			lastnread = 0;
215255169Sjlh		}
216255169Sjlh		lastnread = nread;
217255169Sjlh	}
218255169Sjlh	fprintf(msg, "total length: %lu bytes\n", tsize);
219255169Sjlh	(void)signal(SIGINT, oldsig);
220255169Sjlh	if (op == COPY || op == COPYVERIFY) {
221255169Sjlh		writeop(outp, MTWEOF);
222255169Sjlh		writeop(outp, MTWEOF);
223255169Sjlh		if (op == COPYVERIFY) {
224255169Sjlh			writeop(outp, MTREW);
225255169Sjlh			writeop(inp, MTREW);
226255169Sjlh			verify(inp, outp, buff);
22787514Scjc		}
22887514Scjc	}
229101607Sfanf	exit(0);
230254974Sjlh}
231254974Sjlh
232254974Sjlhvoid
23387514Scjcverify(inp, outp, outb)
234255169Sjlh	register int inp, outp;
235254974Sjlh	register char *outb;
236255169Sjlh{
237254974Sjlh	register int eot, inmaxblk, inn, outmaxblk, outn;
238254974Sjlh	register char *inb;
239255169Sjlh
240255169Sjlh	inb = getspace(maxblk);
241255169Sjlh	inmaxblk = outmaxblk = maxblk;
242254974Sjlh	for (eot = 0;; guesslen = 0) {
24387514Scjc		if ((inn = read(inp, inb, inmaxblk)) == -1) {
244254974Sjlh			if (guesslen)
245254974Sjlh				while (errno == EINVAL && (inmaxblk -= 1024)) {
24687514Scjc					inn = read(inp, inb, inmaxblk);
247215213Sbrooks					if (inn >= 0)
248254974Sjlh						goto r1;
249254974Sjlh				}
250215213Sbrooks			perror("tcopy: read error");
25187514Scjc			break;
252254974Sjlh		}
253254974Sjlhr1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
254254974Sjlh			if (guesslen)
25587514Scjc				while (errno == EINVAL && (outmaxblk -= 1024)) {
256254974Sjlh					outn = read(outp, outb, outmaxblk);
25787514Scjc					if (outn >= 0)
25887514Scjc						goto r2;
259254974Sjlh				}
260254974Sjlh			perror("tcopy: read error");
26187514Scjc			break;
26287514Scjc		}
263254974Sjlhr2:		if (inn != outn) {
264254974Sjlh			fprintf(msg,
26587514Scjc			    "%s: tapes have different block sizes; %d != %d.\n",
266161602Strhodes			    "tcopy", inn, outn);
267254974Sjlh			break;
268254974Sjlh		}
269161602Strhodes		if (!inn) {
270210254Sgabor			if (eot++) {
271254974Sjlh				fprintf(msg, "tcopy: tapes are identical.\n");
272254974Sjlh				return;
273210254Sgabor			}
27487514Scjc		} else {
275254974Sjlh			if (bcmp(inb, outb, inn)) {
276254974Sjlh				fprintf(msg,
27787514Scjc				    "tcopy: tapes have different data.\n");
278105937Sthomas				break;
279254974Sjlh			}
280254974Sjlh			eot = 0;
281105937Sthomas		}
282138061Smlaier	}
283254974Sjlh	exit(1);
284254974Sjlh}
285138061Smlaier
28687514Scjcvoid
287254974Sjlhintr(signo)
288254974Sjlh	int signo;
28987514Scjc{
290128473Sdarrenr	if (record)
291254974Sjlh		if (record - lastrec > 1)
292254974Sjlh			fprintf(msg, "records %ld to %ld\n", lastrec, record);
293128473Sdarrenr		else
29487514Scjc			fprintf(msg, "record %ld\n", lastrec);
295254974Sjlh	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
296254974Sjlh	fprintf(msg, "total length: %ld bytes\n", tsize + size);
29787514Scjc	exit(1);
29887514Scjc}
299254974Sjlh
300254974Sjlhvoid *
30187514Scjcgetspace(blk)
30287514Scjc	int blk;
303254974Sjlh{
304254974Sjlh	void *bp;
30587514Scjc
30687514Scjc	if ((bp = malloc((size_t)blk)) == NULL) {
30761981Sbrian		fprintf(stderr, "tcopy: no memory\n");
30861981Sbrian		exit(11);
30961981Sbrian	}
31061981Sbrian	return (bp);
31161981Sbrian}
31261981Sbrian
313254974Sjlhvoid
314254974Sjlhwriteop(fd, type)
315254974Sjlh	int fd, type;
316254974Sjlh{
317254974Sjlh	struct mtop op;
318254974Sjlh
319257508Sjlh	op.mt_op = type;
320254974Sjlh	op.mt_count = (daddr_t)1;
321254974Sjlh	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
322254974Sjlh		perror("tcopy: tape op");
323254974Sjlh		exit(6);
324254974Sjlh	}
325254974Sjlh}
326254974Sjlh
327292841Sjillesvoid
328292841Sjillesusage()
329254974Sjlh{
330254974Sjlh	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
331257508Sjlh	exit(1);
332254974Sjlh}
333254974Sjlh