Annotation of src/usr.bin/tcopy/tcopy.c, Revision 1.8
1.8 ! millert 1: /* $OpenBSD: tcopy.c,v 1.7 2002/02/16 21:27:54 millert Exp $ */
1.4 millert 2: /* $NetBSD: tcopy.c,v 1.5 1997/04/15 07:23:08 lukem Exp $ */
1.1 deraadt 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.
1.8 ! millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #ifndef lint
34: static char copyright[] =
35: "@(#) Copyright (c) 1985, 1987, 1993\n\
36: The Regents of the University of California. All rights reserved.\n";
37: #endif /* not lint */
38:
39: #ifndef lint
40: #if 0
41: static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95";
42: #endif
1.8 ! millert 43: static char rcsid[] = "$OpenBSD: tcopy.c,v 1.7 2002/02/16 21:27:54 millert Exp $";
1.1 deraadt 44: #endif /* not lint */
45:
46: #include <sys/types.h>
47: #include <sys/stat.h>
48: #include <sys/ioctl.h>
49: #include <sys/mtio.h>
50:
51: #include <err.h>
52: #include <errno.h>
53: #include <fcntl.h>
1.4 millert 54: #include <paths.h>
1.1 deraadt 55: #include <signal.h>
56: #include <stdio.h>
57: #include <stdlib.h>
58: #include <string.h>
59: #include <unistd.h>
60:
61: #define MAXREC (64 * 1024)
62: #define NOCOUNT (-2)
63:
64: int filen, guesslen, maxblk = MAXREC;
65: long lastrec, record;
66: off_t size, tsize;
67: FILE *msg = stdout;
68:
1.7 millert 69: void *getspace(int);
70: void intr(int);
71: void usage(void);
72: void verify(int, int, char *);
73: void writeop(int, int);
1.1 deraadt 74:
75: int
76: main(argc, argv)
77: int argc;
78: char *argv[];
79: {
80: int ch, needeof, nw, inp, outp;
81: ssize_t lastnread, nread;
82: enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
83: sig_t oldsig;
84: char *buff, *inf;
85:
86: guesslen = 1;
1.3 millert 87: while ((ch = getopt(argc, argv, "cs:vx")) != -1)
1.1 deraadt 88: switch((char)ch) {
89: case 'c':
90: op = COPYVERIFY;
91: break;
92: case 's':
93: maxblk = atoi(optarg);
94: if (maxblk <= 0) {
95: warnx("illegal block size");
96: usage();
97: }
98: guesslen = 0;
99: break;
100: case 'v':
101: op = VERIFY;
102: break;
103: case 'x':
104: msg = stderr;
105: break;
106: case '?':
107: default:
108: usage();
109: }
110: argc -= optind;
111: argv += optind;
112:
113: switch(argc) {
114: case 0:
115: if (op != READ)
116: usage();
117: inf = _PATH_DEFTAPE;
118: break;
119: case 1:
120: if (op != READ)
121: usage();
122: inf = argv[0];
123: break;
124: case 2:
125: if (op == READ)
126: op = COPY;
127: inf = argv[0];
128: if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
129: op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
1.5 millert 130: err(3, "%s", argv[1]);
1.1 deraadt 131: }
132: break;
133: default:
134: usage();
135: }
136:
137: if ((inp = open(inf, O_RDONLY, 0)) < 0)
1.5 millert 138: err(1, "%s", inf);
1.1 deraadt 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: err(1, "read error, file %d, record %ld",
159: filen, record);
160: } else if (nread != lastnread) {
161: if (lastnread != 0 && lastnread != NOCOUNT) {
162: if (lastrec == 0 && nread == 0)
163: fprintf(msg, "%ld records\n", record);
164: else if (record - lastrec > 1)
165: fprintf(msg, "records %ld to %ld\n",
166: lastrec, record);
167: else
168: fprintf(msg, "record %ld\n", lastrec);
169: }
170: if (nread != 0)
1.6 deraadt 171: fprintf(msg, "file %d: block size %ld: ",
172: filen, (long)nread);
1.1 deraadt 173: (void) fflush(stdout);
174: lastrec = record;
175: }
176: r1: guesslen = 0;
177: if (nread > 0) {
178: if (op == COPY || op == COPYVERIFY) {
179: if (needeof) {
180: writeop(outp, MTWEOF);
181: needeof = 0;
182: }
183: nw = write(outp, buff, nread);
184: if (nw != nread) {
185: int error = errno;
186: fprintf(stderr,
187: "write error, file %d, record %ld: ",
188: filen, record);
189: if (nw == -1)
190: fprintf(stderr,
191: ": %s", strerror(error));
192: else
193: fprintf(stderr,
1.6 deraadt 194: "write (%d) != read (%ld)\n",
195: nw, (long)nread);
1.1 deraadt 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,
1.6 deraadt 208: "file %d: eof after %ld records: %lld bytes\n",
209: filen, record, (long long)size);
1.1 deraadt 210: needeof = 1;
211: filen++;
212: tsize += size;
213: size = record = lastrec = 0;
214: lastnread = 0;
215: }
216: lastnread = nread;
217: }
1.6 deraadt 218: fprintf(msg, "total length: %lld bytes\n", (long long)tsize);
1.1 deraadt 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:
232: void
233: verify(inp, outp, outb)
234: int inp, outp;
235: char *outb;
236: {
237: int eot, inmaxblk, inn, outmaxblk, outn;
238: 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: warn("read error");
251: break;
252: }
253: r1: 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: warn("read error");
261: break;
262: }
263: r2: 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, "%s: tapes are identical.\n",
272: "tcopy");
273: return;
274: }
275: } else {
276: if (bcmp(inb, outb, inn)) {
277: fprintf(msg,
278: "%s: tapes have different data.\n",
279: "tcopy");
280: break;
281: }
282: eot = 0;
283: }
284: }
285: exit(1);
286: }
287:
288: void
289: intr(signo)
290: int signo;
291: {
1.6 deraadt 292: if (record) {
1.1 deraadt 293: if (record - lastrec > 1)
294: fprintf(msg, "records %ld to %ld\n", lastrec, record);
295: else
296: fprintf(msg, "record %ld\n", lastrec);
1.6 deraadt 297: }
1.1 deraadt 298: fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
1.6 deraadt 299: fprintf(msg, "total length: %lld bytes\n", (long long)(tsize + size));
1.1 deraadt 300: exit(1);
301: }
302:
303: void *
304: getspace(blk)
305: int blk;
306: {
307: void *bp;
308:
309: if ((bp = malloc((size_t)blk)) == NULL)
310: errx(11, "no memory");
311:
312: return (bp);
313: }
314:
315: void
316: writeop(fd, type)
317: int fd, type;
318: {
319: struct mtop op;
320:
321: op.mt_op = type;
322: op.mt_count = (daddr_t)1;
323: if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
324: err(6, "tape op");
325: }
326:
327: void
328: usage()
329: {
330:
331: fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
332: exit(1);
333: }