file_cmds-45.tar.gz
[apple/file_cmds.git] / tcopy / tcopy.c
1 /* $NetBSD: tcopy.c,v 1.8 1998/08/25 20:59:41 ross 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.8 1998/08/25 20:59:41 ross 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 #define MAXREC (64 * 1024)
65 #define NOCOUNT (-2)
66
67 int filen, guesslen, maxblk = MAXREC;
68 long lastrec, record;
69 off_t size, tsize;
70 FILE *msg = stdout;
71
72 void *getspace __P((int));
73 void intr __P((int));
74 int main __P((int, char **));
75 void usage __P((void));
76 void verify __P((int, int, char *));
77 void writeop __P((int, int));
78
79 int
80 main(argc, argv)
81 int argc;
82 char *argv[];
83 {
84 int ch, needeof, nw, inp, outp;
85 ssize_t lastnread, nread;
86 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
87 sig_t oldsig;
88 char *buff, *inf;
89
90 outp = 0;
91 inf = NULL;
92 guesslen = 1;
93 while ((ch = getopt(argc, argv, "cs:vx")) != -1)
94 switch((char)ch) {
95 case 'c':
96 op = COPYVERIFY;
97 break;
98 case 's':
99 maxblk = atoi(optarg);
100 if (maxblk <= 0) {
101 warnx("illegal block size");
102 usage();
103 }
104 guesslen = 0;
105 break;
106 case 'v':
107 op = VERIFY;
108 break;
109 case 'x':
110 msg = stderr;
111 break;
112 case '?':
113 default:
114 usage();
115 }
116 argc -= optind;
117 argv += optind;
118
119 switch(argc) {
120 case 0:
121 if (op != READ)
122 usage();
123 inf = _PATH_DEFTAPE;
124 break;
125 case 1:
126 if (op != READ)
127 usage();
128 inf = argv[0];
129 break;
130 case 2:
131 if (op == READ)
132 op = COPY;
133 inf = argv[0];
134 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
135 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
136 err(3, argv[1]);
137 }
138 break;
139 default:
140 usage();
141 }
142
143 if ((inp = open(inf, O_RDONLY, 0)) < 0)
144 err(1, inf);
145
146 buff = getspace(maxblk);
147
148 if (op == VERIFY) {
149 verify(inp, outp, buff);
150 exit(0);
151 }
152
153 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
154 (void) signal(SIGINT, intr);
155
156 needeof = 0;
157 for (lastnread = NOCOUNT;;) {
158 if ((nread = read(inp, buff, maxblk)) == -1) {
159 while (errno == EINVAL && (maxblk -= 1024)) {
160 nread = read(inp, buff, maxblk);
161 if (nread >= 0)
162 goto r1;
163 }
164 err(1, "read error, file %d, record %ld",
165 filen, record);
166 } else if (nread != lastnread) {
167 if (lastnread != 0 && lastnread != NOCOUNT) {
168 if (lastrec == 0 && nread == 0)
169 fprintf(msg, "%ld records\n", record);
170 else if (record - lastrec > 1)
171 fprintf(msg, "records %ld to %ld\n",
172 lastrec, record);
173 else
174 fprintf(msg, "record %ld\n", lastrec);
175 }
176 if (nread != 0)
177 fprintf(msg, "file %d: block size %ld: ",
178 filen, (long)nread);
179 (void) fflush(stdout);
180 lastrec = record;
181 }
182 r1: guesslen = 0;
183 if (nread > 0) {
184 if (op == COPY || op == COPYVERIFY) {
185 if (needeof) {
186 writeop(outp, MTWEOF);
187 needeof = 0;
188 }
189 nw = write(outp, buff, nread);
190 if (nw != nread) {
191 int error = errno;
192 fprintf(stderr,
193 "write error, file %d, record %ld: ",
194 filen, record);
195 if (nw == -1)
196 fprintf(stderr,
197 ": %s", strerror(error));
198 else
199 fprintf(stderr,
200 "write (%d) != read (%ld)\n",
201 nw, (long)nread);
202 fprintf(stderr, "copy aborted\n");
203 exit(5);
204 }
205 }
206 size += nread;
207 record++;
208 } else {
209 if (lastnread <= 0 && lastnread != NOCOUNT) {
210 fprintf(msg, "eot\n");
211 break;
212 }
213 fprintf(msg,
214 "file %d: eof after %ld records: %qd bytes\n",
215 filen, record, (long long)size);
216 needeof = 1;
217 filen++;
218 tsize += size;
219 size = record = lastrec = 0;
220 lastnread = 0;
221 }
222 lastnread = nread;
223 }
224 fprintf(msg, "total length: %qd bytes\n", (long long)tsize);
225 (void)signal(SIGINT, oldsig);
226 if (op == COPY || op == COPYVERIFY) {
227 writeop(outp, MTWEOF);
228 writeop(outp, MTWEOF);
229 if (op == COPYVERIFY) {
230 writeop(outp, MTREW);
231 writeop(inp, MTREW);
232 verify(inp, outp, buff);
233 }
234 }
235 exit(0);
236 }
237
238 void
239 verify(inp, outp, outb)
240 int inp, outp;
241 char *outb;
242 {
243 int eot, inmaxblk, inn, outmaxblk, outn;
244 char *inb;
245
246 inb = getspace(maxblk);
247 inmaxblk = outmaxblk = maxblk;
248 for (eot = 0;; guesslen = 0) {
249 if ((inn = read(inp, inb, inmaxblk)) == -1) {
250 if (guesslen)
251 while (errno == EINVAL && (inmaxblk -= 1024)) {
252 inn = read(inp, inb, inmaxblk);
253 if (inn >= 0)
254 goto r1;
255 }
256 warn("read error");
257 break;
258 }
259 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
260 if (guesslen)
261 while (errno == EINVAL && (outmaxblk -= 1024)) {
262 outn = read(outp, outb, outmaxblk);
263 if (outn >= 0)
264 goto r2;
265 }
266 warn("read error");
267 break;
268 }
269 r2: if (inn != outn) {
270 fprintf(msg,
271 "%s: tapes have different block sizes; %d != %d.\n",
272 "tcopy", inn, outn);
273 break;
274 }
275 if (!inn) {
276 if (eot++) {
277 fprintf(msg, "%s: tapes are identical.\n",
278 "tcopy");
279 return;
280 }
281 } else {
282 if (memcmp(inb, outb, inn)) {
283 fprintf(msg,
284 "%s: tapes have different data.\n",
285 "tcopy");
286 break;
287 }
288 eot = 0;
289 }
290 }
291 exit(1);
292 }
293
294 void
295 intr(signo)
296 int signo;
297 {
298 if (record) {
299 if (record - lastrec > 1)
300 fprintf(msg, "records %ld to %ld\n", lastrec, record);
301 else
302 fprintf(msg, "record %ld\n", lastrec);
303 }
304 fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
305 fprintf(msg, "total length: %qd bytes\n", (long long)(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 }