xref: /original-bsd/usr.bin/tcopy/tcopy.c (revision 8e206d2f)
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.13 (Berkeley) 01/02/90";
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 	sig_t oldsig;
52 	int ch, needeof;
53 	char *buff, *inf, *getspace();
54 	void intr();
55 
56 	guesslen = 1;
57 	while ((ch = getopt(argc, argv, "cs:v")) != EOF)
58 		switch((char)ch) {
59 		case 'c':
60 			op = COPYVERIFY;
61 			break;
62 		case 's':
63 			maxblk = atoi(optarg);
64 			if (maxblk <= 0) {
65 				fprintf(stderr, "tcopy: illegal block size\n");
66 				usage();
67 			}
68 			guesslen = 0;
69 			break;
70 		case 'v':
71 			op = VERIFY;
72 			break;
73 		case '?':
74 		default:
75 			usage();
76 		}
77 	argc -= optind;
78 	argv += optind;
79 
80 	switch(argc) {
81 	case 0:
82 		if (op != READ)
83 			usage();
84 		inf = _PATH_DEFTAPE;
85 		break;
86 	case 1:
87 		if (op != READ)
88 			usage();
89 		inf = argv[0];
90 		break;
91 	case 2:
92 		if (op == READ)
93 			op = COPY;
94 		inf = argv[0];
95 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : O_RDWR,
96 		    0666)) < 0) {
97 			perror(argv[1]);
98 			exit(3);
99 		}
100 		break;
101 	default:
102 		usage();
103 	}
104 
105 	if ((inp = open(inf, O_RDONLY, 0)) < 0) {
106 		perror(inf);
107 		exit(1);
108 	}
109 
110 	buff = getspace(maxblk);
111 
112 	if (op == VERIFY) {
113 		verify(inp, outp, buff);
114 		exit(0);
115 	}
116 
117 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
118 		(void) signal(SIGINT, intr);
119 
120 	needeof = 0;
121 	for (lastnread = NOCOUNT;;) {
122 		if ((nread = read(inp, buff, maxblk)) == -1) {
123 			while (errno == EINVAL && (maxblk -= 1024)) {
124 				nread = read(inp, buff, maxblk);
125 				if (nread >= 0)
126 					goto r1;
127 			}
128 			fprintf(stderr, "read error, file %d, record %ld: ",
129 			    filen, record);
130 			perror("");
131 			exit(1);
132 		} else if (nread != lastnread) {
133 			if (lastnread != 0 && lastnread != NOCOUNT) {
134 				if (lastrec == 0 && nread == 0)
135 					printf("%ld records\n", record);
136 				else if (record - lastrec > 1)
137 					printf("records %ld to %ld\n",
138 					    lastrec, record);
139 				else
140 					printf("record %ld\n", lastrec);
141 			}
142 			if (nread != 0)
143 				printf("file %d: block size %d: ",
144 				    filen, nread);
145 			(void) fflush(stdout);
146 			lastrec = record;
147 		}
148 r1:		guesslen = 0;
149 		if (nread > 0) {
150 			if (op >= COPY) {
151 				if (needeof) {
152 					writeop(outp, MTWEOF);
153 					needeof = 0;
154 				}
155 				nw = write(outp, buff, nread);
156 				if (nw != nread) {
157 				    fprintf(stderr,
158 					"write error, file %d, record %ld: ",
159 					filen, record);
160 				    if (nw == -1)
161 					perror("");
162 				    else
163 					fprintf(stderr,
164 					    "write (%d) != read (%d)\n",
165 					    nw, nread);
166 				    fprintf(stderr, "copy aborted\n");
167 				    exit(5);
168 				}
169 			}
170 			size += nread;
171 			record++;
172 		} else {
173 			if (lastnread <= 0 && lastnread != NOCOUNT) {
174 				printf("eot\n");
175 				break;
176 			}
177 			printf("file %d: eof after %ld records: %ld bytes\n",
178 				filen, record, size);
179 			needeof = 1;
180 			filen++;
181 			tsize += size;
182 			size = record = lastrec = 0;
183 			lastnread = 0;
184 		}
185 		lastnread = nread;
186 	}
187 	printf("total length: %ld bytes\n", tsize);
188 	(void)signal(SIGINT, oldsig);
189 	if (op >= COPY) {
190 		writeop(outp, MTWEOF);
191 		writeop(outp, MTWEOF);
192 		if (op == COPYVERIFY) {
193 			writeop(outp, MTREW);
194 			writeop(inp, MTREW);
195 			verify(inp, outp, buff);
196 		}
197 	}
198 	exit(0);
199 }
200 
201 verify(inp, outp, outb)
202 	register int inp, outp;
203 	register char *outb;
204 {
205 	extern int errno;
206 	register int eot, inmaxblk, inn, outmaxblk, outn;
207 	register char *inb;
208 	char *getspace();
209 
210 	inb = getspace(maxblk);
211 	inmaxblk = outmaxblk = maxblk;
212 	for (eot = 0;; guesslen = 0) {
213 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
214 			if (guesslen)
215 				while (errno == EINVAL && (inmaxblk -= 1024)) {
216 					inn = read(inp, inb, inmaxblk);
217 					if (inn >= 0)
218 						goto r1;
219 				}
220 			perror("tcopy: read error");
221 			break;
222 		}
223 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
224 			if (guesslen)
225 				while (errno == EINVAL && (outmaxblk -= 1024)) {
226 					outn = read(outp, outb, outmaxblk);
227 					if (outn >= 0)
228 						goto r2;
229 				}
230 			perror("tcopy: read error");
231 			break;
232 		}
233 r2:		if (inn != outn) {
234 			printf("tcopy: tapes have different block sizes; %d != %d.\n", inn, outn);
235 			break;
236 		}
237 		if (!inn) {
238 			if (eot++) {
239 				printf("tcopy: tapes are identical.\n");
240 				return;
241 			}
242 		} else {
243 			if (bcmp(inb, outb, inn)) {
244 				printf("tcopy: tapes have different data.\n");
245 				break;
246 			}
247 			eot = 0;
248 		}
249 	}
250 	exit(1);
251 }
252 
253 void
254 intr()
255 {
256 	if (record)
257 		if (record - lastrec > 1)
258 			printf("records %ld to %ld\n", lastrec, record);
259 		else
260 			printf("record %ld\n", lastrec);
261 	printf("interrupt at file %d: record %ld\n", filen, record);
262 	printf("total length: %ld bytes\n", tsize + size);
263 	exit(1);
264 }
265 
266 char *
267 getspace(blk)
268 	int blk;
269 {
270 	char *bp, *malloc();
271 
272 	if ((bp = malloc((u_int)blk)) == NULL) {
273 		fprintf(stderr, "tcopy: no memory\n");
274 		exit(11);
275 	}
276 	return(bp);
277 }
278 
279 writeop(fd, type)
280 	int fd, type;
281 {
282 	struct mtop op;
283 
284 	op.mt_op = type;
285 	op.mt_count = (daddr_t)1;
286 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
287 		perror("tcopy: tape op");
288 		exit(6);
289 	}
290 }
291 
292 usage()
293 {
294 	fprintf(stderr, "usage: tcopy [-cv] [-s maxblk] src [dest]\n");
295 	exit(1);
296 }
297