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