xref: /original-bsd/usr.bin/tcopy/tcopy.c (revision 4ee49cc0)
1 /*
2  * Copyright (c) 1985, 1987, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1985, 1987, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)tcopy.c	8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/ioctl.h>
21 #include <sys/mtio.h>
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "pathnames.h"
32 
33 #define	MAXREC	(64 * 1024)
34 #define	NOCOUNT	(-2)
35 
36 int	filen, guesslen, maxblk = MAXREC;
37 long	lastrec, record, size, tsize;
38 
39 void	*getspace __P((int));
40 void	 intr __P((int));
41 void	 usage __P((void));
42 void	 verify __P((int, int, char *));
43 void	 writeop __P((int, int));
44 
45 int
46 main(argc, argv)
47 	int argc;
48 	char *argv[];
49 {
50 	register int lastnread, nread, nw, inp, outp;
51 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
52 	sig_t oldsig;
53 	int ch, needeof;
54 	char *buff, *inf;
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 		    DEFFILEMODE)) < 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 || op == COPYVERIFY) {
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 || op == COPYVERIFY) {
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 void
202 verify(inp, outp, outb)
203 	register int inp, outp;
204 	register char *outb;
205 {
206 	register int eot, inmaxblk, inn, outmaxblk, outn;
207 	register char *inb;
208 
209 	inb = getspace(maxblk);
210 	inmaxblk = outmaxblk = maxblk;
211 	for (eot = 0;; guesslen = 0) {
212 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
213 			if (guesslen)
214 				while (errno == EINVAL && (inmaxblk -= 1024)) {
215 					inn = read(inp, inb, inmaxblk);
216 					if (inn >= 0)
217 						goto r1;
218 				}
219 			perror("tcopy: read error");
220 			break;
221 		}
222 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
223 			if (guesslen)
224 				while (errno == EINVAL && (outmaxblk -= 1024)) {
225 					outn = read(outp, outb, outmaxblk);
226 					if (outn >= 0)
227 						goto r2;
228 				}
229 			perror("tcopy: read error");
230 			break;
231 		}
232 r2:		if (inn != outn) {
233 			printf("tcopy: tapes have different block sizes; %d != %d.\n", inn, outn);
234 			break;
235 		}
236 		if (!inn) {
237 			if (eot++) {
238 				printf("tcopy: tapes are identical.\n");
239 				return;
240 			}
241 		} else {
242 			if (bcmp(inb, outb, inn)) {
243 				printf("tcopy: tapes have different data.\n");
244 				break;
245 			}
246 			eot = 0;
247 		}
248 	}
249 	exit(1);
250 }
251 
252 void
253 intr(signo)
254 	int signo;
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 void *
267 getspace(blk)
268 	int blk;
269 {
270 	void *bp;
271 
272 	if ((bp = malloc((size_t)blk)) == NULL) {
273 		fprintf(stderr, "tcopy: no memory\n");
274 		exit(11);
275 	}
276 	return (bp);
277 }
278 
279 void
280 writeop(fd, type)
281 	int fd, type;
282 {
283 	struct mtop op;
284 
285 	op.mt_op = type;
286 	op.mt_count = (daddr_t)1;
287 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
288 		perror("tcopy: tape op");
289 		exit(6);
290 	}
291 }
292 
293 void
294 usage()
295 {
296 	fprintf(stderr, "usage: tcopy [-cv] [-s maxblk] src [dest]\n");
297 	exit(1);
298 }
299