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