xref: /netbsd-src/usr.bin/tcopy/tcopy.c (revision f5d3fbbc6ff4a77159fb268d247bd94cb7d7e332)
1 /*	$NetBSD: tcopy.c,v 1.6 1997/10/20 00:35:14 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, 1987, 1993, 1995
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)tcopy.c	8.3 (Berkeley) 1/23/95";
45 #endif
46 __RCSID("$NetBSD: tcopy.c,v 1.6 1997/10/20 00:35:14 lukem Exp $");
47 #endif /* not lint */
48 
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <sys/mtio.h>
53 
54 #include <err.h>
55 #include <errno.h>
56 #include <paths.h>
57 #include <fcntl.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 
64 
65 #define	MAXREC	(64 * 1024)
66 #define	NOCOUNT	(-2)
67 
68 int	filen, guesslen, maxblk = MAXREC;
69 long	lastrec, record;
70 off_t	size, tsize;
71 FILE	*msg = stdout;
72 
73 void	*getspace __P((int));
74 void	 intr __P((int));
75 int	 main __P((int, char **));
76 void	 usage __P((void));
77 void	 verify __P((int, int, char *));
78 void	 writeop __P((int, int));
79 
80 int
81 main(argc, argv)
82 	int argc;
83 	char *argv[];
84 {
85 	int ch, needeof, nw, inp, outp;
86 	ssize_t lastnread, nread;
87 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
88 	sig_t oldsig;
89 	char *buff, *inf;
90 
91 	outp = 0;
92 	inf = NULL;
93 	guesslen = 1;
94 	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
95 		switch((char)ch) {
96 		case 'c':
97 			op = COPYVERIFY;
98 			break;
99 		case 's':
100 			maxblk = atoi(optarg);
101 			if (maxblk <= 0) {
102 				warnx("illegal block size");
103 				usage();
104 			}
105 			guesslen = 0;
106 			break;
107 		case 'v':
108 			op = VERIFY;
109 			break;
110 		case 'x':
111 			msg = stderr;
112 			break;
113 		case '?':
114 		default:
115 			usage();
116 		}
117 	argc -= optind;
118 	argv += optind;
119 
120 	switch(argc) {
121 	case 0:
122 		if (op != READ)
123 			usage();
124 		inf = _PATH_DEFTAPE;
125 		break;
126 	case 1:
127 		if (op != READ)
128 			usage();
129 		inf = argv[0];
130 		break;
131 	case 2:
132 		if (op == READ)
133 			op = COPY;
134 		inf = argv[0];
135 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
136 		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
137 			err(3, argv[1]);
138 		}
139 		break;
140 	default:
141 		usage();
142 	}
143 
144 	if ((inp = open(inf, O_RDONLY, 0)) < 0)
145 		err(1, inf);
146 
147 	buff = getspace(maxblk);
148 
149 	if (op == VERIFY) {
150 		verify(inp, outp, buff);
151 		exit(0);
152 	}
153 
154 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
155 		(void) signal(SIGINT, intr);
156 
157 	needeof = 0;
158 	for (lastnread = NOCOUNT;;) {
159 		if ((nread = read(inp, buff, maxblk)) == -1) {
160 			while (errno == EINVAL && (maxblk -= 1024)) {
161 				nread = read(inp, buff, maxblk);
162 				if (nread >= 0)
163 					goto r1;
164 			}
165 			err(1, "read error, file %d, record %ld",
166 			    filen, record);
167 		} else if (nread != lastnread) {
168 			if (lastnread != 0 && lastnread != NOCOUNT) {
169 				if (lastrec == 0 && nread == 0)
170 					fprintf(msg, "%ld records\n", record);
171 				else if (record - lastrec > 1)
172 					fprintf(msg, "records %ld to %ld\n",
173 					    lastrec, record);
174 				else
175 					fprintf(msg, "record %ld\n", lastrec);
176 			}
177 			if (nread != 0)
178 				fprintf(msg, "file %d: block size %d: ",
179 				    filen, nread);
180 			(void) fflush(stdout);
181 			lastrec = record;
182 		}
183 r1:		guesslen = 0;
184 		if (nread > 0) {
185 			if (op == COPY || op == COPYVERIFY) {
186 				if (needeof) {
187 					writeop(outp, MTWEOF);
188 					needeof = 0;
189 				}
190 				nw = write(outp, buff, nread);
191 				if (nw != nread) {
192 				    int error = errno;
193 				    fprintf(stderr,
194 					"write error, file %d, record %ld: ",
195 					filen, record);
196 				    if (nw == -1)
197 					fprintf(stderr,
198 						": %s", strerror(error));
199 				    else
200 					fprintf(stderr,
201 					    "write (%d) != read (%d)\n",
202 					    nw, nread);
203 				    fprintf(stderr, "copy aborted\n");
204 				    exit(5);
205 				}
206 			}
207 			size += nread;
208 			record++;
209 		} else {
210 			if (lastnread <= 0 && lastnread != NOCOUNT) {
211 				fprintf(msg, "eot\n");
212 				break;
213 			}
214 			fprintf(msg,
215 			    "file %d: eof after %ld records: %qd bytes\n",
216 			    filen, record, size);
217 			needeof = 1;
218 			filen++;
219 			tsize += size;
220 			size = record = lastrec = 0;
221 			lastnread = 0;
222 		}
223 		lastnread = nread;
224 	}
225 	fprintf(msg, "total length: %qd bytes\n", tsize);
226 	(void)signal(SIGINT, oldsig);
227 	if (op == COPY || op == COPYVERIFY) {
228 		writeop(outp, MTWEOF);
229 		writeop(outp, MTWEOF);
230 		if (op == COPYVERIFY) {
231 			writeop(outp, MTREW);
232 			writeop(inp, MTREW);
233 			verify(inp, outp, buff);
234 		}
235 	}
236 	exit(0);
237 }
238 
239 void
240 verify(inp, outp, outb)
241 	int inp, outp;
242 	char *outb;
243 {
244 	int eot, inmaxblk, inn, outmaxblk, outn;
245 	char *inb;
246 
247 	inb = getspace(maxblk);
248 	inmaxblk = outmaxblk = maxblk;
249 	for (eot = 0;; guesslen = 0) {
250 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
251 			if (guesslen)
252 				while (errno == EINVAL && (inmaxblk -= 1024)) {
253 					inn = read(inp, inb, inmaxblk);
254 					if (inn >= 0)
255 						goto r1;
256 				}
257 			warn("read error");
258 			break;
259 		}
260 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
261 			if (guesslen)
262 				while (errno == EINVAL && (outmaxblk -= 1024)) {
263 					outn = read(outp, outb, outmaxblk);
264 					if (outn >= 0)
265 						goto r2;
266 				}
267 			warn("read error");
268 			break;
269 		}
270 r2:		if (inn != outn) {
271 			fprintf(msg,
272 			    "%s: tapes have different block sizes; %d != %d.\n",
273 			    "tcopy", inn, outn);
274 			break;
275 		}
276 		if (!inn) {
277 			if (eot++) {
278 				fprintf(msg, "%s: tapes are identical.\n",
279 					"tcopy");
280 				return;
281 			}
282 		} else {
283 			if (memcmp(inb, outb, inn)) {
284 				fprintf(msg,
285 				    "%s: tapes have different data.\n",
286 					"tcopy");
287 				break;
288 			}
289 			eot = 0;
290 		}
291 	}
292 	exit(1);
293 }
294 
295 void
296 intr(signo)
297 	int signo;
298 {
299 	if (record)
300 		if (record - lastrec > 1)
301 			fprintf(msg, "records %ld to %ld\n", lastrec, record);
302 		else
303 			fprintf(msg, "record %ld\n", lastrec);
304 	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
305 	fprintf(msg, "total length: %qd bytes\n", tsize + size);
306 	exit(1);
307 }
308 
309 void *
310 getspace(blk)
311 	int blk;
312 {
313 	void *bp;
314 
315 	if ((bp = malloc((size_t)blk)) == NULL)
316 		errx(11, "no memory");
317 
318 	return (bp);
319 }
320 
321 void
322 writeop(fd, type)
323 	int fd, type;
324 {
325 	struct mtop op;
326 
327 	op.mt_op = type;
328 	op.mt_count = (daddr_t)1;
329 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
330 		err(6, "tape op");
331 }
332 
333 void
334 usage()
335 {
336 
337 	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
338 	exit(1);
339 }
340