add -x option to output all messages to standard out
[unix-history] / usr / src / usr.bin / tcopy / tcopy.c
CommitLineData
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
9static 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 15static 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
36int filen, guesslen, maxblk = MAXREC;
37long lastrec, record, size, tsize;
cbc661f4 38FILE *msg = stdout;
f7c68695 39
8b26f0ee
KB
40void *getspace __P((int));
41void intr __P((int));
42void usage __P((void));
43void verify __P((int, int, char *));
44void writeop __P((int, int));
45
46int
f7c68695 47main(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 152r1: 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 206void
ceb3a81e
KB
207verify(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 }
227r1: 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 237r2: 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 260void
8b26f0ee
KB
261intr(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 274void *
ceb3a81e
KB
275getspace(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 287void
ceb3a81e
KB
288writeop(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 301void
ceb3a81e
KB
302usage()
303{
cbc661f4 304 fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
f7c68695
JB
305 exit(1);
306}