xref: /original-bsd/usr.bin/tcopy/tcopy.c (revision 38045c73)
1 /*
2  * Copyright (c) 1985, 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific written prior permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 char copyright[] =
15 "@(#) Copyright (c) 1985, 1987 Regents of the University of California.\n\
16  All rights reserved.\n";
17 #endif /* not lint */
18 
19 #ifndef lint
20 static char sccsid[] = "@(#)tcopy.c	5.7 (Berkeley) 05/04/88";
21 #endif /* not lint */
22 
23 #include <stdio.h>
24 #include <signal.h>
25 #include <sys/file.h>
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
28 #include <sys/mtio.h>
29 #include <sys/errno.h>
30 
31 #define	MAXREC	(64 * 1024)
32 #define	NOCOUNT	(-2)
33 
34 #undef DEFTAPE
35 #define	DEFTAPE	"/dev/rmt0"
36 
37 int	filen, guesslen, maxblk = MAXREC;
38 long	lastrec, record, size, tsize;
39 
40 main(argc, argv)
41 	int argc;
42 	char **argv;
43 {
44 	extern char *optarg;
45 	extern int optind, errno;
46 	register int lastnread, nread, nw, inp, outp;
47 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
48 	int ch, needeof, intr(), (*oldsig)();
49 	char *buff, *inf, *getspace();
50 
51 	guesslen = 1;
52 	while ((ch = getopt(argc, argv, "cs:v")) != EOF)
53 		switch((char)ch) {
54 		case 'c':
55 			op = COPYVERIFY;
56 			break;
57 		case 's':
58 			maxblk = atoi(optarg);
59 			if (maxblk <= 0) {
60 				fputs("tcopy: illegal block size\n", stderr);
61 				usage();
62 			}
63 			guesslen = 0;
64 			break;
65 		case 'v':
66 			op = VERIFY;
67 			break;
68 		case '?':
69 		default:
70 			usage();
71 		}
72 	argc -= optind;
73 	argv += optind;
74 
75 	switch(argc) {
76 	case 0:
77 		if (op != READ)
78 			usage();
79 		inf = DEFTAPE;
80 		break;
81 	case 1:
82 		if (op != READ)
83 			usage();
84 		inf = argv[0];
85 		break;
86 	case 2:
87 		if (op == READ)
88 			op = COPY;
89 		inf = argv[0];
90 		if ((outp = open(argv[1], O_RDWR, 0666)) < 0) {
91 			perror(argv[1]);
92 			exit(3);
93 		}
94 		break;
95 	default:
96 		usage();
97 	}
98 
99 	if ((inp = open(inf, O_RDONLY, 0)) < 0) {
100 		perror(inf);
101 		exit(1);
102 	}
103 
104 	buff = getspace(maxblk);
105 
106 	if (op == VERIFY) {
107 		verify(inp, outp, buff);
108 		exit(0);
109 	}
110 
111 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
112 		(void) signal(SIGINT, intr);
113 
114 	needeof = 0;
115 	for (lastnread = NOCOUNT;;) {
116 		if ((nread = read(inp, buff, maxblk)) == -1) {
117 			while (errno == EINVAL && (maxblk -= 1024)) {
118 				nread = read(inp, buff, maxblk);
119 				if (nread >= 0)
120 					goto r1;
121 			}
122 			fprintf(stderr, "read error, file %d, record %ld: ",
123 			    filen, record);
124 			perror("");
125 			exit(1);
126 		} else if (nread != lastnread) {
127 			if (lastnread != 0 && lastnread != NOCOUNT) {
128 				if (lastrec == 0 && nread == 0)
129 					printf("%ld records\n", record);
130 				else if (record - lastrec > 1)
131 					printf("records %ld to %ld\n",
132 					    lastrec, record);
133 				else
134 					printf("record %ld\n", lastrec);
135 			}
136 			if (nread != 0)
137 				printf("file %d: block size %d: ",
138 				    filen, nread);
139 			(void) fflush(stdout);
140 			lastrec = record;
141 		}
142 r1:		guesslen = 0;
143 		if (nread > 0) {
144 			if (op >= COPY) {
145 				if (needeof) {
146 					writeop(outp, MTWEOF);
147 					needeof = 0;
148 				}
149 				nw = write(outp, buff, nread);
150 				if (nw != nread) {
151 				    fprintf(stderr,
152 					"write error, file %d, record %ld: ",
153 					filen, record);
154 				    if (nw == -1)
155 					perror("");
156 				    else
157 					fprintf(stderr,
158 					    "write (%d) != read (%d)\n",
159 					    nw, nread);
160 				    fprintf(stderr, "copy aborted\n");
161 				    exit(5);
162 				}
163 			}
164 			size += nread;
165 			record++;
166 		} else {
167 			if (lastnread <= 0 && lastnread != NOCOUNT) {
168 				printf("eot\n");
169 				break;
170 			}
171 			printf("file %d: eof after %ld records: %ld bytes\n",
172 				filen, record, size);
173 			needeof = 1;
174 			filen++;
175 			tsize += size;
176 			size = record = lastrec = 0;
177 			lastnread = 0;
178 		}
179 		lastnread = nread;
180 	}
181 	printf("total length: %ld bytes\n", tsize);
182 	(void)signal(SIGINT, oldsig);
183 	if (op >= COPY) {
184 		writeop(outp, MTWEOF);
185 		writeop(outp, MTWEOF);
186 		if (op == COPYVERIFY) {
187 			writeop(outp, MTREW);
188 			writeop(inp, MTREW);
189 			verify(inp, outp, buff);
190 		}
191 	}
192 	exit(0);
193 }
194 
195 static
196 verify(inp, outp, outb)
197 	register int inp, outp;
198 	register char *outb;
199 {
200 	register int eot, inmaxblk, inn, outmaxblk, outn;
201 	register char *inb;
202 	char *getspace();
203 
204 	inb = getspace(maxblk);
205 	inmaxblk = outmaxblk = maxblk;
206 	for (eot = 0;; guesslen = 0) {
207 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
208 			if (guesslen)
209 				while (errno == EINVAL && (inmaxblk -= 1024)) {
210 					inn = read(inp, inb, inmaxblk);
211 					if (inn >= 0)
212 						goto r1;
213 				}
214 			perror("tcopy: read error");
215 			exit(1);
216 		}
217 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
218 			if (guesslen)
219 				while (errno == EINVAL && (outmaxblk -= 1024)) {
220 					outn = read(outp, outb, outmaxblk);
221 					if (outn >= 0)
222 						goto r2;
223 				}
224 			perror("tcopy: read error");
225 			exit(1);
226 		}
227 r2:		if (inn != outn)
228 			break;
229 		if (!inn) {
230 			if (eot++) {
231 				puts("tcopy: tapes are identical.");
232 				return;
233 			}
234 		} else {
235 			if (bcmp(inb, outb, inn))
236 				break;
237 			eot = 0;
238 		}
239 	}
240 	puts("tcopy: tapes are different.");
241 	exit(1);
242 }
243 
244 static
245 intr()
246 {
247 	if (record)
248 		if (record - lastrec > 1)
249 			printf("records %ld to %ld\n", lastrec, record);
250 		else
251 			printf("record %ld\n", lastrec);
252 	printf("interrupt at file %d: record %ld\n", filen, record);
253 	printf("total length: %ld bytes\n", tsize + size);
254 	exit(1);
255 }
256 
257 static char *
258 getspace(blk)
259 	int blk;
260 {
261 	char *bp, *malloc();
262 
263 	if ((bp = malloc((u_int)blk)) == NULL) {
264 		fputs("tcopy: no memory\n", stderr);
265 		exit(11);
266 	}
267 	return(bp);
268 }
269 
270 static
271 writeop(fd, type)
272 	int fd, type;
273 {
274 	struct mtop op;
275 
276 	op.mt_op = type;
277 	op.mt_count = (daddr_t)1;
278 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
279 		perror("tcopy: tape op");
280 		exit(6);
281 	}
282 }
283 
284 static
285 usage()
286 {
287 	fputs("usage: tcopy [-cv] [-s maxblk] src [dest]\n", stderr);
288 	exit(1);
289 }
290