Annotation of src/usr.bin/tcopy/tcopy.c, Revision 1.10
1.10 ! deraadt 1: /* $OpenBSD: tcopy.c,v 1.9 2003/06/10 22:20:53 deraadt 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.10 ! deraadt 43: static char rcsid[] = "$OpenBSD: tcopy.c,v 1.9 2003/06/10 22:20:53 deraadt 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
1.9 deraadt 76: main(int argc, char *argv[])
1.1 deraadt 77: {
78: int ch, needeof, nw, inp, outp;
79: ssize_t lastnread, nread;
80: enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
81: sig_t oldsig;
82: char *buff, *inf;
83:
84: guesslen = 1;
1.3 millert 85: while ((ch = getopt(argc, argv, "cs:vx")) != -1)
1.1 deraadt 86: switch((char)ch) {
87: case 'c':
88: op = COPYVERIFY;
89: break;
90: case 's':
91: maxblk = atoi(optarg);
92: if (maxblk <= 0) {
93: warnx("illegal block size");
94: usage();
95: }
96: guesslen = 0;
97: break;
98: case 'v':
99: op = VERIFY;
100: break;
101: case 'x':
102: msg = stderr;
103: break;
104: case '?':
105: default:
106: usage();
107: }
108: argc -= optind;
109: argv += optind;
110:
111: switch(argc) {
112: case 0:
113: if (op != READ)
114: usage();
115: inf = _PATH_DEFTAPE;
116: break;
117: case 1:
118: if (op != READ)
119: usage();
120: inf = argv[0];
121: break;
122: case 2:
123: if (op == READ)
124: op = COPY;
125: inf = argv[0];
126: if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
127: op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
1.5 millert 128: err(3, "%s", argv[1]);
1.1 deraadt 129: }
130: break;
131: default:
132: usage();
133: }
134:
135: if ((inp = open(inf, O_RDONLY, 0)) < 0)
1.5 millert 136: err(1, "%s", inf);
1.1 deraadt 137:
138: buff = getspace(maxblk);
139:
140: if (op == VERIFY) {
141: verify(inp, outp, buff);
142: exit(0);
143: }
144:
145: if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
146: (void) signal(SIGINT, intr);
147:
148: needeof = 0;
149: for (lastnread = NOCOUNT;;) {
150: if ((nread = read(inp, buff, maxblk)) == -1) {
151: while (errno == EINVAL && (maxblk -= 1024)) {
152: nread = read(inp, buff, maxblk);
153: if (nread >= 0)
154: goto r1;
155: }
156: err(1, "read error, file %d, record %ld",
157: filen, record);
158: } else if (nread != lastnread) {
159: if (lastnread != 0 && lastnread != NOCOUNT) {
160: if (lastrec == 0 && nread == 0)
161: fprintf(msg, "%ld records\n", record);
162: else if (record - lastrec > 1)
163: fprintf(msg, "records %ld to %ld\n",
164: lastrec, record);
165: else
166: fprintf(msg, "record %ld\n", lastrec);
167: }
168: if (nread != 0)
1.6 deraadt 169: fprintf(msg, "file %d: block size %ld: ",
170: filen, (long)nread);
1.1 deraadt 171: (void) fflush(stdout);
172: lastrec = record;
173: }
174: r1: guesslen = 0;
175: if (nread > 0) {
176: if (op == COPY || op == COPYVERIFY) {
177: if (needeof) {
178: writeop(outp, MTWEOF);
179: needeof = 0;
180: }
181: nw = write(outp, buff, nread);
182: if (nw != nread) {
183: int error = errno;
184: fprintf(stderr,
185: "write error, file %d, record %ld: ",
186: filen, record);
187: if (nw == -1)
188: fprintf(stderr,
189: ": %s", strerror(error));
190: else
191: fprintf(stderr,
1.6 deraadt 192: "write (%d) != read (%ld)\n",
193: nw, (long)nread);
1.1 deraadt 194: fprintf(stderr, "copy aborted\n");
195: exit(5);
196: }
197: }
198: size += nread;
199: record++;
200: } else {
201: if (lastnread <= 0 && lastnread != NOCOUNT) {
202: fprintf(msg, "eot\n");
203: break;
204: }
205: fprintf(msg,
1.6 deraadt 206: "file %d: eof after %ld records: %lld bytes\n",
207: filen, record, (long long)size);
1.1 deraadt 208: needeof = 1;
209: filen++;
210: tsize += size;
211: size = record = lastrec = 0;
212: lastnread = 0;
213: }
214: lastnread = nread;
215: }
1.6 deraadt 216: fprintf(msg, "total length: %lld bytes\n", (long long)tsize);
1.1 deraadt 217: (void)signal(SIGINT, oldsig);
218: if (op == COPY || op == COPYVERIFY) {
219: writeop(outp, MTWEOF);
220: writeop(outp, MTWEOF);
221: if (op == COPYVERIFY) {
222: writeop(outp, MTREW);
223: writeop(inp, MTREW);
224: verify(inp, outp, buff);
225: }
226: }
227: exit(0);
228: }
229:
230: void
1.9 deraadt 231: verify(int inp, int outp, char *outb)
1.1 deraadt 232: {
233: int eot, inmaxblk, inn, outmaxblk, outn;
234: char *inb;
235:
236: inb = getspace(maxblk);
237: inmaxblk = outmaxblk = maxblk;
238: for (eot = 0;; guesslen = 0) {
239: if ((inn = read(inp, inb, inmaxblk)) == -1) {
240: if (guesslen)
241: while (errno == EINVAL && (inmaxblk -= 1024)) {
242: inn = read(inp, inb, inmaxblk);
243: if (inn >= 0)
244: goto r1;
245: }
246: warn("read error");
247: break;
248: }
249: r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
250: if (guesslen)
251: while (errno == EINVAL && (outmaxblk -= 1024)) {
252: outn = read(outp, outb, outmaxblk);
253: if (outn >= 0)
254: goto r2;
255: }
256: warn("read error");
257: break;
258: }
259: r2: if (inn != outn) {
260: fprintf(msg,
261: "%s: tapes have different block sizes; %d != %d.\n",
262: "tcopy", inn, outn);
263: break;
264: }
265: if (!inn) {
266: if (eot++) {
267: fprintf(msg, "%s: tapes are identical.\n",
268: "tcopy");
269: return;
270: }
271: } else {
272: if (bcmp(inb, outb, inn)) {
273: fprintf(msg,
274: "%s: tapes have different data.\n",
275: "tcopy");
276: break;
277: }
278: eot = 0;
279: }
280: }
281: exit(1);
282: }
283:
284: void
1.9 deraadt 285: intr(int signo)
1.1 deraadt 286: {
1.6 deraadt 287: if (record) {
1.1 deraadt 288: if (record - lastrec > 1)
289: fprintf(msg, "records %ld to %ld\n", lastrec, record);
290: else
291: fprintf(msg, "record %ld\n", lastrec);
1.6 deraadt 292: }
1.1 deraadt 293: fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
1.6 deraadt 294: fprintf(msg, "total length: %lld bytes\n", (long long)(tsize + size));
1.1 deraadt 295: exit(1);
296: }
297:
298: void *
1.9 deraadt 299: getspace(int blk)
1.1 deraadt 300: {
301: void *bp;
302:
303: if ((bp = malloc((size_t)blk)) == NULL)
304: errx(11, "no memory");
305:
306: return (bp);
307: }
308:
309: void
1.9 deraadt 310: writeop(int fd, int type)
1.1 deraadt 311: {
312: struct mtop op;
313:
314: op.mt_op = type;
1.10 ! deraadt 315: op.mt_count = 1;
1.1 deraadt 316: if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
317: err(6, "tape op");
318: }
319:
320: void
1.9 deraadt 321: usage(void)
1.1 deraadt 322: {
323:
324: fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
325: exit(1);
326: }