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