tcopy.c revision 93123
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#include <sys/cdefs.h>
35
36__FBSDID("$FreeBSD: head/usr.bin/tcopy/tcopy.c 93123 2002-03-25 05:23:45Z mike $");
37
38#ifndef lint
39static const char copyright[] =
40"@(#) Copyright (c) 1985, 1987, 1993\n\
41	The Regents of the University of California.  All rights reserved.\n";
42#endif
43
44#ifndef lint
45static const char sccsid[] = "@(#)tcopy.c	8.2 (Berkeley) 4/17/94";
46#endif
47
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <sys/ioctl.h>
51#include <sys/mtio.h>
52
53#include <err.h>
54#include <errno.h>
55#include <fcntl.h>
56#include <paths.h>
57#include <signal.h>
58#include <stdint.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <unistd.h>
63
64#define	MAXREC	(64 * 1024)
65#define	NOCOUNT	(-2)
66
67int	filen, guesslen, maxblk = MAXREC;
68u_int64_t	lastrec, record, size, tsize;
69FILE	*msg;
70
71void	*getspace(int);
72void	 intr(int);
73static void	 usage(void);
74void	 verify(int, int, char *);
75void	 writeop(int, int);
76void	rewind_tape(int);
77
78int
79main(argc, argv)
80	int argc;
81	char *argv[];
82{
83	register int lastnread, nread, nw, inp, outp;
84	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
85	sig_t oldsig;
86	int ch, needeof;
87	char *buff;
88	const char *inf;
89
90	msg = stdout;
91	guesslen = 1;
92	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
93		switch((char)ch) {
94		case 'c':
95			op = COPYVERIFY;
96			break;
97		case 's':
98			maxblk = atoi(optarg);
99			if (maxblk <= 0) {
100				warnx("illegal block size");
101				usage();
102			}
103			guesslen = 0;
104			break;
105		case 'v':
106			op = VERIFY;
107			break;
108		case 'x':
109			msg = stderr;
110			break;
111		case '?':
112		default:
113			usage();
114		}
115	argc -= optind;
116	argv += optind;
117
118	switch(argc) {
119	case 0:
120		if (op != READ)
121			usage();
122		inf = _PATH_DEFTAPE;
123		break;
124	case 1:
125		if (op != READ)
126			usage();
127		inf = argv[0];
128		break;
129	case 2:
130		if (op == READ)
131			op = COPY;
132		inf = argv[0];
133		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
134		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0)
135			err(3, "%s", argv[1]);
136		break;
137	default:
138		usage();
139	}
140
141	if ((inp = open(inf, O_RDONLY, 0)) < 0)
142		err(1, "%s", inf);
143
144	buff = getspace(maxblk);
145
146	if (op == VERIFY) {
147		verify(inp, outp, buff);
148		exit(0);
149	}
150
151	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
152		(void) signal(SIGINT, intr);
153
154	needeof = 0;
155	for (lastnread = NOCOUNT;;) {
156		if ((nread = read(inp, buff, maxblk)) == -1) {
157			while (errno == EINVAL && (maxblk -= 1024)) {
158				nread = read(inp, buff, maxblk);
159				if (nread >= 0)
160					goto r1;
161			}
162			err(1, "read error, file %d, record %qu", filen, record);
163		} else if (nread != lastnread) {
164			if (lastnread != 0 && lastnread != NOCOUNT) {
165				if (lastrec == 0 && nread == 0)
166					fprintf(msg, "%qu records\n", record);
167				else if (record - lastrec > 1)
168					fprintf(msg, "records %qu to %qu\n",
169					    lastrec, record);
170				else
171					fprintf(msg, "record %qu\n", lastrec);
172			}
173			if (nread != 0)
174				fprintf(msg, "file %d: block size %d: ",
175				    filen, nread);
176			(void) fflush(stdout);
177			lastrec = record;
178		}
179r1:		guesslen = 0;
180		if (nread > 0) {
181			if (op == COPY || op == COPYVERIFY) {
182				if (needeof) {
183					writeop(outp, MTWEOF);
184					needeof = 0;
185				}
186				nw = write(outp, buff, nread);
187				if (nw != nread) {
188					if (nw == -1) {
189					warn("write error, file %d, record %qu", filen, record);
190					} else {
191					warnx("write error, file %d, record %qu", filen, record);
192					warnx("write (%d) != read (%d)", nw, nread);
193					}
194					errx(5, "copy aborted");
195				}
196			}
197			size += nread;
198			record++;
199		} else {
200			if (lastnread <= 0 && lastnread != NOCOUNT) {
201				fprintf(msg, "eot\n");
202				break;
203			}
204			fprintf(msg,
205			    "file %d: eof after %qu records: %qu bytes\n",
206			    filen, record, size);
207			needeof = 1;
208			filen++;
209			tsize += size;
210			size = record = lastrec = 0;
211			lastnread = 0;
212		}
213		lastnread = nread;
214	}
215	fprintf(msg, "total length: %qu bytes\n", tsize);
216	(void)signal(SIGINT, oldsig);
217	if (op == COPY || op == COPYVERIFY) {
218		writeop(outp, MTWEOF);
219		writeop(outp, MTWEOF);
220		if (op == COPYVERIFY) {
221			rewind_tape(outp);
222			rewind_tape(inp);
223			verify(inp, outp, buff);
224		}
225	}
226	exit(0);
227}
228
229void
230verify(inp, outp, outb)
231	register int inp, outp;
232	register char *outb;
233{
234	register int eot, inmaxblk, inn, outmaxblk, outn;
235	register char *inb;
236
237	inb = getspace(maxblk);
238	inmaxblk = outmaxblk = maxblk;
239	for (eot = 0;; guesslen = 0) {
240		if ((inn = read(inp, inb, inmaxblk)) == -1) {
241			if (guesslen)
242				while (errno == EINVAL && (inmaxblk -= 1024)) {
243					inn = read(inp, inb, inmaxblk);
244					if (inn >= 0)
245						goto r1;
246				}
247			warn("read error");
248			break;
249		}
250r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
251			if (guesslen)
252				while (errno == EINVAL && (outmaxblk -= 1024)) {
253					outn = read(outp, outb, outmaxblk);
254					if (outn >= 0)
255						goto r2;
256				}
257			warn("read error");
258			break;
259		}
260r2:		if (inn != outn) {
261			fprintf(msg,
262			    "%s: tapes have different block sizes; %d != %d.\n",
263			    "tcopy", inn, outn);
264			break;
265		}
266		if (!inn) {
267			if (eot++) {
268				fprintf(msg, "tcopy: tapes are identical.\n");
269				return;
270			}
271		} else {
272			if (bcmp(inb, outb, inn)) {
273				fprintf(msg,
274				    "tcopy: tapes have different data.\n");
275				break;
276			}
277			eot = 0;
278		}
279	}
280	exit(1);
281}
282
283void
284intr(signo)
285	int signo __unused;
286{
287	if (record) {
288		if (record - lastrec > 1)
289			fprintf(msg, "records %qu to %qu\n", lastrec, record);
290		else
291			fprintf(msg, "record %qu\n", lastrec);
292	}
293	fprintf(msg, "interrupt at file %d: record %qu\n", filen, record);
294	fprintf(msg, "total length: %ju bytes\n", (uintmax_t)(tsize + size));
295	exit(1);
296}
297
298void *
299getspace(blk)
300	int blk;
301{
302	void *bp;
303
304	if ((bp = malloc((size_t)blk)) == NULL)
305		errx(11, "no memory");
306	return (bp);
307}
308
309void
310writeop(fd, type)
311	int fd, type;
312{
313	struct mtop op;
314
315	op.mt_op = type;
316	op.mt_count = (daddr_t)1;
317	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
318		err(6, "tape op");
319}
320
321static void
322usage()
323{
324	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n");
325	exit(1);
326}
327
328void
329rewind_tape(int fd)
330{
331	struct stat sp;
332
333	if(fstat(fd, &sp))
334		errx(12, "fstat in rewind");
335
336	/*
337	 * don't want to do tape ioctl on regular files:
338	 */
339	if( S_ISREG(sp.st_mode) ) {
340		if( lseek(fd, 0, SEEK_SET) == -1 )
341			errx(13, "lseek");
342	} else
343		/*  assume its a tape	*/
344		writeop(fd, MTREW);
345}
346