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