tcopy.c revision 24360
1/*
2 * Copyright (c) 1985, 1987, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1985, 1987, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)tcopy.c	8.2 (Berkeley) 4/17/94";
42#endif /* not lint */
43
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <sys/ioctl.h>
47#include <sys/mtio.h>
48
49#include <errno.h>
50#include <fcntl.h>
51#include <signal.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56
57#include "pathnames.h"
58
59#define	MAXREC	(64 * 1024)
60#define	NOCOUNT	(-2)
61
62int	filen, guesslen, maxblk = MAXREC;
63u_long	lastrec, record, size, tsize;
64FILE	*msg = stdout;
65
66void	*getspace __P((int));
67void	 intr __P((int));
68void	 usage __P((void));
69void	 verify __P((int, int, char *));
70void	 writeop __P((int, int));
71
72int
73main(argc, argv)
74	int argc;
75	char *argv[];
76{
77	register int lastnread, nread, nw, inp, outp;
78	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
79	sig_t oldsig;
80	int ch, needeof;
81	char *buff, *inf;
82
83	guesslen = 1;
84	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
85		switch((char)ch) {
86		case 'c':
87			op = COPYVERIFY;
88			break;
89		case 's':
90			maxblk = atoi(optarg);
91			if (maxblk <= 0) {
92				fprintf(stderr, "tcopy: illegal block size\n");
93				usage();
94			}
95			guesslen = 0;
96			break;
97		case 'v':
98			op = VERIFY;
99			break;
100		case 'x':
101			msg = stderr;
102			break;
103		case '?':
104		default:
105			usage();
106		}
107	argc -= optind;
108	argv += optind;
109
110	switch(argc) {
111	case 0:
112		if (op != READ)
113			usage();
114		inf = _PATH_DEFTAPE;
115		break;
116	case 1:
117		if (op != READ)
118			usage();
119		inf = argv[0];
120		break;
121	case 2:
122		if (op == READ)
123			op = COPY;
124		inf = argv[0];
125		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
126		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
127			perror(argv[1]);
128			exit(3);
129		}
130		break;
131	default:
132		usage();
133	}
134
135	if ((inp = open(inf, O_RDONLY, 0)) < 0) {
136		perror(inf);
137		exit(1);
138	}
139
140	buff = getspace(maxblk);
141
142	if (op == VERIFY) {
143		verify(inp, outp, buff);
144		exit(0);
145	}
146
147	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
148		(void) signal(SIGINT, intr);
149
150	needeof = 0;
151	for (lastnread = NOCOUNT;;) {
152		if ((nread = read(inp, buff, maxblk)) == -1) {
153			while (errno == EINVAL && (maxblk -= 1024)) {
154				nread = read(inp, buff, maxblk);
155				if (nread >= 0)
156					goto r1;
157			}
158			fprintf(stderr, "read error, file %d, record %ld: ",
159			    filen, record);
160			perror("");
161			exit(1);
162		} else if (nread != lastnread) {
163			if (lastnread != 0 && lastnread != NOCOUNT) {
164				if (lastrec == 0 && nread == 0)
165					fprintf(msg, "%ld records\n", record);
166				else if (record - lastrec > 1)
167					fprintf(msg, "records %ld to %ld\n",
168					    lastrec, record);
169				else
170					fprintf(msg, "record %ld\n", lastrec);
171			}
172			if (nread != 0)
173				fprintf(msg, "file %d: block size %d: ",
174				    filen, nread);
175			(void) fflush(stdout);
176			lastrec = record;
177		}
178r1:		guesslen = 0;
179		if (nread > 0) {
180			if (op == COPY || op == COPYVERIFY) {
181				if (needeof) {
182					writeop(outp, MTWEOF);
183					needeof = 0;
184				}
185				nw = write(outp, buff, nread);
186				if (nw != nread) {
187				    fprintf(stderr,
188					"write error, file %d, record %ld: ",
189					filen, record);
190				    if (nw == -1)
191					perror("");
192				    else
193					fprintf(stderr,
194					    "write (%d) != read (%d)\n",
195					    nw, nread);
196				    fprintf(stderr, "copy aborted\n");
197				    exit(5);
198				}
199			}
200			size += nread;
201			record++;
202		} else {
203			if (lastnread <= 0 && lastnread != NOCOUNT) {
204				fprintf(msg, "eot\n");
205				break;
206			}
207			fprintf(msg,
208			    "file %d: eof after %lu records: %lu bytes\n",
209			    filen, record, size);
210			needeof = 1;
211			filen++;
212			tsize += size;
213			size = record = lastrec = 0;
214			lastnread = 0;
215		}
216		lastnread = nread;
217	}
218	fprintf(msg, "total length: %lu bytes\n", tsize);
219	(void)signal(SIGINT, oldsig);
220	if (op == COPY || op == COPYVERIFY) {
221		writeop(outp, MTWEOF);
222		writeop(outp, MTWEOF);
223		if (op == COPYVERIFY) {
224			writeop(outp, MTREW);
225			writeop(inp, MTREW);
226			verify(inp, outp, buff);
227		}
228	}
229	exit(0);
230}
231
232void
233verify(inp, outp, outb)
234	register int inp, outp;
235	register char *outb;
236{
237	register int eot, inmaxblk, inn, outmaxblk, outn;
238	register char *inb;
239
240	inb = getspace(maxblk);
241	inmaxblk = outmaxblk = maxblk;
242	for (eot = 0;; guesslen = 0) {
243		if ((inn = read(inp, inb, inmaxblk)) == -1) {
244			if (guesslen)
245				while (errno == EINVAL && (inmaxblk -= 1024)) {
246					inn = read(inp, inb, inmaxblk);
247					if (inn >= 0)
248						goto r1;
249				}
250			perror("tcopy: read error");
251			break;
252		}
253r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
254			if (guesslen)
255				while (errno == EINVAL && (outmaxblk -= 1024)) {
256					outn = read(outp, outb, outmaxblk);
257					if (outn >= 0)
258						goto r2;
259				}
260			perror("tcopy: read error");
261			break;
262		}
263r2:		if (inn != outn) {
264			fprintf(msg,
265			    "%s: tapes have different block sizes; %d != %d.\n",
266			    "tcopy", inn, outn);
267			break;
268		}
269		if (!inn) {
270			if (eot++) {
271				fprintf(msg, "tcopy: tapes are identical.\n");
272				return;
273			}
274		} else {
275			if (bcmp(inb, outb, inn)) {
276				fprintf(msg,
277				    "tcopy: tapes have different data.\n");
278				break;
279			}
280			eot = 0;
281		}
282	}
283	exit(1);
284}
285
286void
287intr(signo)
288	int signo;
289{
290	if (record)
291		if (record - lastrec > 1)
292			fprintf(msg, "records %ld to %ld\n", lastrec, record);
293		else
294			fprintf(msg, "record %ld\n", lastrec);
295	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
296	fprintf(msg, "total length: %ld bytes\n", tsize + size);
297	exit(1);
298}
299
300void *
301getspace(blk)
302	int blk;
303{
304	void *bp;
305
306	if ((bp = malloc((size_t)blk)) == NULL) {
307		fprintf(stderr, "tcopy: no memory\n");
308		exit(11);
309	}
310	return (bp);
311}
312
313void
314writeop(fd, type)
315	int fd, type;
316{
317	struct mtop op;
318
319	op.mt_op = type;
320	op.mt_count = (daddr_t)1;
321	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
322		perror("tcopy: tape op");
323		exit(6);
324	}
325}
326
327void
328usage()
329{
330	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
331	exit(1);
332}
333