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