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