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