Commit | Line | Data |
---|---|---|
f7c68695 | 1 | /* |
725a8fbf KB |
2 | * Copyright (c) 1985, 1987, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
b210d410 | 4 | * |
cb956e54 | 5 | * %sccs.include.redist.c% |
f7c68695 JB |
6 | */ |
7 | ||
8 | #ifndef lint | |
725a8fbf KB |
9 | static char copyright[] = |
10 | "@(#) Copyright (c) 1985, 1987, 1993\n\ | |
11 | The Regents of the University of California. All rights reserved.\n"; | |
b210d410 | 12 | #endif /* not lint */ |
f7c68695 JB |
13 | |
14 | #ifndef lint | |
cbc661f4 | 15 | static char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) %G%"; |
b210d410 | 16 | #endif /* not lint */ |
f7c68695 | 17 | |
f7c68695 | 18 | #include <sys/types.h> |
8b26f0ee | 19 | #include <sys/stat.h> |
f7c68695 JB |
20 | #include <sys/ioctl.h> |
21 | #include <sys/mtio.h> | |
8b26f0ee | 22 | |
daf38612 | 23 | #include <errno.h> |
8b26f0ee KB |
24 | #include <fcntl.h> |
25 | #include <signal.h> | |
435e8dff | 26 | #include <stdio.h> |
8b26f0ee KB |
27 | #include <stdlib.h> |
28 | #include <string.h> | |
29 | #include <unistd.h> | |
30 | ||
435e8dff | 31 | #include "pathnames.h" |
f7c68695 | 32 | |
ceb3a81e KB |
33 | #define MAXREC (64 * 1024) |
34 | #define NOCOUNT (-2) | |
35 | ||
ceb3a81e KB |
36 | int filen, guesslen, maxblk = MAXREC; |
37 | long lastrec, record, size, tsize; | |
cbc661f4 | 38 | FILE *msg = stdout; |
f7c68695 | 39 | |
8b26f0ee KB |
40 | void *getspace __P((int)); |
41 | void intr __P((int)); | |
42 | void usage __P((void)); | |
43 | void verify __P((int, int, char *)); | |
44 | void writeop __P((int, int)); | |
45 | ||
46 | int | |
f7c68695 | 47 | main(argc, argv) |
b210d410 | 48 | int argc; |
8b26f0ee | 49 | char *argv[]; |
f7c68695 | 50 | { |
ceb3a81e KB |
51 | register int lastnread, nread, nw, inp, outp; |
52 | enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; | |
6894b138 KB |
53 | sig_t oldsig; |
54 | int ch, needeof; | |
8b26f0ee | 55 | char *buff, *inf; |
f7c68695 | 56 | |
ceb3a81e | 57 | guesslen = 1; |
cbc661f4 | 58 | while ((ch = getopt(argc, argv, "cs:vx")) != EOF) |
ceb3a81e KB |
59 | switch((char)ch) { |
60 | case 'c': | |
61 | op = COPYVERIFY; | |
62 | break; | |
2c00311e | 63 | case 's': |
ceb3a81e | 64 | maxblk = atoi(optarg); |
2c00311e | 65 | if (maxblk <= 0) { |
d8eaee96 | 66 | fprintf(stderr, "tcopy: illegal block size\n"); |
ceb3a81e | 67 | usage(); |
2c00311e | 68 | } |
2c00311e MK |
69 | guesslen = 0; |
70 | break; | |
ceb3a81e KB |
71 | case 'v': |
72 | op = VERIFY; | |
73 | break; | |
cbc661f4 KM |
74 | case 'x': |
75 | msg = stderr; | |
76 | break; | |
ceb3a81e KB |
77 | case '?': |
78 | default: | |
79 | usage(); | |
2c00311e | 80 | } |
ceb3a81e KB |
81 | argc -= optind; |
82 | argv += optind; | |
83 | ||
84 | switch(argc) { | |
85 | case 0: | |
86 | if (op != READ) | |
87 | usage(); | |
435e8dff | 88 | inf = _PATH_DEFTAPE; |
ceb3a81e KB |
89 | break; |
90 | case 1: | |
91 | if (op != READ) | |
92 | usage(); | |
93 | inf = argv[0]; | |
94 | break; | |
95 | case 2: | |
96 | if (op == READ) | |
97 | op = COPY; | |
98 | inf = argv[0]; | |
cbc661f4 KM |
99 | if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : |
100 | op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) { | |
ceb3a81e KB |
101 | perror(argv[1]); |
102 | exit(3); | |
103 | } | |
104 | break; | |
105 | default: | |
106 | usage(); | |
c11c323a | 107 | } |
ceb3a81e | 108 | |
2c00311e MK |
109 | if ((inp = open(inf, O_RDONLY, 0)) < 0) { |
110 | perror(inf); | |
f7c68695 JB |
111 | exit(1); |
112 | } | |
ceb3a81e KB |
113 | |
114 | buff = getspace(maxblk); | |
115 | ||
116 | if (op == VERIFY) { | |
117 | verify(inp, outp, buff); | |
118 | exit(0); | |
f7c68695 | 119 | } |
ceb3a81e KB |
120 | |
121 | if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) | |
2c00311e | 122 | (void) signal(SIGINT, intr); |
ceb3a81e KB |
123 | |
124 | needeof = 0; | |
125 | for (lastnread = NOCOUNT;;) { | |
126 | if ((nread = read(inp, buff, maxblk)) == -1) { | |
127 | while (errno == EINVAL && (maxblk -= 1024)) { | |
128 | nread = read(inp, buff, maxblk); | |
129 | if (nread >= 0) | |
130 | goto r1; | |
2c00311e | 131 | } |
b210d410 | 132 | fprintf(stderr, "read error, file %d, record %ld: ", |
2c00311e MK |
133 | filen, record); |
134 | perror(""); | |
ceb3a81e KB |
135 | exit(1); |
136 | } else if (nread != lastnread) { | |
137 | if (lastnread != 0 && lastnread != NOCOUNT) { | |
2c00311e | 138 | if (lastrec == 0 && nread == 0) |
cbc661f4 | 139 | fprintf(msg, "%ld records\n", record); |
2c00311e | 140 | else if (record - lastrec > 1) |
cbc661f4 | 141 | fprintf(msg, "records %ld to %ld\n", |
2c00311e MK |
142 | lastrec, record); |
143 | else | |
cbc661f4 | 144 | fprintf(msg, "record %ld\n", lastrec); |
2c00311e MK |
145 | } |
146 | if (nread != 0) | |
cbc661f4 | 147 | fprintf(msg, "file %d: block size %d: ", |
2c00311e | 148 | filen, nread); |
b210d410 | 149 | (void) fflush(stdout); |
2c00311e | 150 | lastrec = record; |
f7c68695 | 151 | } |
ceb3a81e | 152 | r1: guesslen = 0; |
2c00311e | 153 | if (nread > 0) { |
1c63ce13 | 154 | if (op == COPY || op == COPYVERIFY) { |
2c00311e | 155 | if (needeof) { |
ceb3a81e KB |
156 | writeop(outp, MTWEOF); |
157 | needeof = 0; | |
2c00311e MK |
158 | } |
159 | nw = write(outp, buff, nread); | |
160 | if (nw != nread) { | |
161 | fprintf(stderr, | |
b210d410 | 162 | "write error, file %d, record %ld: ", |
2c00311e MK |
163 | filen, record); |
164 | if (nw == -1) | |
165 | perror(""); | |
166 | else | |
167 | fprintf(stderr, | |
168 | "write (%d) != read (%d)\n", | |
169 | nw, nread); | |
170 | fprintf(stderr, "copy aborted\n"); | |
171 | exit(5); | |
172 | } | |
173 | } | |
174 | size += nread; | |
175 | record++; | |
176 | } else { | |
ceb3a81e | 177 | if (lastnread <= 0 && lastnread != NOCOUNT) { |
cbc661f4 | 178 | fprintf(msg, "eot\n"); |
f7c68695 JB |
179 | break; |
180 | } | |
cbc661f4 KM |
181 | fprintf(msg, |
182 | "file %d: eof after %ld records: %ld bytes\n", | |
183 | filen, record, size); | |
2c00311e | 184 | needeof = 1; |
f7c68695 | 185 | filen++; |
f7c68695 | 186 | tsize += size; |
ceb3a81e KB |
187 | size = record = lastrec = 0; |
188 | lastnread = 0; | |
f7c68695 | 189 | } |
ceb3a81e | 190 | lastnread = nread; |
f7c68695 | 191 | } |
cbc661f4 | 192 | fprintf(msg, "total length: %ld bytes\n", tsize); |
ceb3a81e | 193 | (void)signal(SIGINT, oldsig); |
1c63ce13 | 194 | if (op == COPY || op == COPYVERIFY) { |
ceb3a81e KB |
195 | writeop(outp, MTWEOF); |
196 | writeop(outp, MTWEOF); | |
197 | if (op == COPYVERIFY) { | |
198 | writeop(outp, MTREW); | |
199 | writeop(inp, MTREW); | |
200 | verify(inp, outp, buff); | |
201 | } | |
202 | } | |
203 | exit(0); | |
204 | } | |
205 | ||
8b26f0ee | 206 | void |
ceb3a81e KB |
207 | verify(inp, outp, outb) |
208 | register int inp, outp; | |
209 | register char *outb; | |
210 | { | |
211 | register int eot, inmaxblk, inn, outmaxblk, outn; | |
212 | register char *inb; | |
ceb3a81e KB |
213 | |
214 | inb = getspace(maxblk); | |
215 | inmaxblk = outmaxblk = maxblk; | |
216 | for (eot = 0;; guesslen = 0) { | |
217 | if ((inn = read(inp, inb, inmaxblk)) == -1) { | |
218 | if (guesslen) | |
219 | while (errno == EINVAL && (inmaxblk -= 1024)) { | |
220 | inn = read(inp, inb, inmaxblk); | |
221 | if (inn >= 0) | |
222 | goto r1; | |
223 | } | |
224 | perror("tcopy: read error"); | |
d8eaee96 | 225 | break; |
ceb3a81e KB |
226 | } |
227 | r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { | |
228 | if (guesslen) | |
229 | while (errno == EINVAL && (outmaxblk -= 1024)) { | |
230 | outn = read(outp, outb, outmaxblk); | |
231 | if (outn >= 0) | |
232 | goto r2; | |
233 | } | |
234 | perror("tcopy: read error"); | |
d8eaee96 | 235 | break; |
ceb3a81e | 236 | } |
d8eaee96 | 237 | r2: if (inn != outn) { |
cbc661f4 KM |
238 | fprintf(msg, |
239 | "%s: tapes have different block sizes; %d != %d.\n", | |
240 | "tcopy", inn, outn); | |
ceb3a81e | 241 | break; |
d8eaee96 | 242 | } |
ceb3a81e KB |
243 | if (!inn) { |
244 | if (eot++) { | |
cbc661f4 | 245 | fprintf(msg, "tcopy: tapes are identical.\n"); |
ceb3a81e KB |
246 | return; |
247 | } | |
248 | } else { | |
d8eaee96 | 249 | if (bcmp(inb, outb, inn)) { |
cbc661f4 KM |
250 | fprintf(msg, |
251 | "tcopy: tapes have different data.\n"); | |
ceb3a81e | 252 | break; |
d8eaee96 | 253 | } |
ceb3a81e KB |
254 | eot = 0; |
255 | } | |
256 | } | |
ceb3a81e | 257 | exit(1); |
f7c68695 JB |
258 | } |
259 | ||
6894b138 | 260 | void |
8b26f0ee KB |
261 | intr(signo) |
262 | int signo; | |
f7c68695 | 263 | { |
2c00311e MK |
264 | if (record) |
265 | if (record - lastrec > 1) | |
cbc661f4 | 266 | fprintf(msg, "records %ld to %ld\n", lastrec, record); |
f7c68695 | 267 | else |
cbc661f4 KM |
268 | fprintf(msg, "record %ld\n", lastrec); |
269 | fprintf(msg, "interrupt at file %d: record %ld\n", filen, record); | |
270 | fprintf(msg, "total length: %ld bytes\n", tsize + size); | |
ceb3a81e KB |
271 | exit(1); |
272 | } | |
273 | ||
8b26f0ee | 274 | void * |
ceb3a81e KB |
275 | getspace(blk) |
276 | int blk; | |
277 | { | |
8b26f0ee | 278 | void *bp; |
ceb3a81e | 279 | |
8b26f0ee | 280 | if ((bp = malloc((size_t)blk)) == NULL) { |
d8eaee96 | 281 | fprintf(stderr, "tcopy: no memory\n"); |
ceb3a81e KB |
282 | exit(11); |
283 | } | |
8b26f0ee | 284 | return (bp); |
ceb3a81e KB |
285 | } |
286 | ||
8b26f0ee | 287 | void |
ceb3a81e KB |
288 | writeop(fd, type) |
289 | int fd, type; | |
290 | { | |
291 | struct mtop op; | |
292 | ||
293 | op.mt_op = type; | |
294 | op.mt_count = (daddr_t)1; | |
295 | if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) { | |
296 | perror("tcopy: tape op"); | |
297 | exit(6); | |
298 | } | |
299 | } | |
300 | ||
8b26f0ee | 301 | void |
ceb3a81e KB |
302 | usage() |
303 | { | |
cbc661f4 | 304 | fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n"); |
f7c68695 JB |
305 | exit(1); |
306 | } |