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