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