xref: /original-bsd/usr.bin/tcopy/tcopy.c (revision 5fd6b0d9)
1 /*
2  * Copyright (c) 1985, 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1985, 1987 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)tcopy.c	5.10 (Berkeley) 09/22/88";
26 #endif /* not lint */
27 
28 #include <stdio.h>
29 #include <signal.h>
30 #include <sys/file.h>
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <sys/mtio.h>
34 #include <sys/errno.h>
35 
36 #define	MAXREC	(64 * 1024)
37 #define	NOCOUNT	(-2)
38 
39 #undef DEFTAPE
40 #define	DEFTAPE	"/dev/rmt0"
41 
42 int	filen, guesslen, maxblk = MAXREC;
43 long	lastrec, record, size, tsize;
44 
45 main(argc, argv)
46 	int argc;
47 	char **argv;
48 {
49 	extern char *optarg;
50 	extern int optind, errno;
51 	register int lastnread, nread, nw, inp, outp;
52 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
53 	int ch, needeof, intr(), (*oldsig)();
54 	char *buff, *inf, *getspace();
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 				fputs("tcopy: illegal block size\n", stderr);
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 = 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 		    0666)) < 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) {
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) {
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 verify(inp, outp, outb)
202 	register int inp, outp;
203 	register char *outb;
204 {
205 	extern int errno;
206 	register int eot, inmaxblk, inn, outmaxblk, outn;
207 	register char *inb;
208 	char *getspace();
209 
210 	inb = getspace(maxblk);
211 	inmaxblk = outmaxblk = maxblk;
212 	for (eot = 0;; guesslen = 0) {
213 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
214 			if (guesslen)
215 				while (errno == EINVAL && (inmaxblk -= 1024)) {
216 					inn = read(inp, inb, inmaxblk);
217 					if (inn >= 0)
218 						goto r1;
219 				}
220 			perror("tcopy: read error");
221 			exit(1);
222 		}
223 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
224 			if (guesslen)
225 				while (errno == EINVAL && (outmaxblk -= 1024)) {
226 					outn = read(outp, outb, outmaxblk);
227 					if (outn >= 0)
228 						goto r2;
229 				}
230 			perror("tcopy: read error");
231 			exit(1);
232 		}
233 r2:		if (inn != outn)
234 			break;
235 		if (!inn) {
236 			if (eot++) {
237 				puts("tcopy: tapes are identical.");
238 				return;
239 			}
240 		} else {
241 			if (bcmp(inb, outb, inn))
242 				break;
243 			eot = 0;
244 		}
245 	}
246 	puts("tcopy: tapes are different.");
247 	exit(1);
248 }
249 
250 intr()
251 {
252 	if (record)
253 		if (record - lastrec > 1)
254 			printf("records %ld to %ld\n", lastrec, record);
255 		else
256 			printf("record %ld\n", lastrec);
257 	printf("interrupt at file %d: record %ld\n", filen, record);
258 	printf("total length: %ld bytes\n", tsize + size);
259 	exit(1);
260 }
261 
262 char *
263 getspace(blk)
264 	int blk;
265 {
266 	char *bp, *malloc();
267 
268 	if ((bp = malloc((u_int)blk)) == NULL) {
269 		fputs("tcopy: no memory\n", stderr);
270 		exit(11);
271 	}
272 	return(bp);
273 }
274 
275 writeop(fd, type)
276 	int fd, type;
277 {
278 	struct mtop op;
279 
280 	op.mt_op = type;
281 	op.mt_count = (daddr_t)1;
282 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
283 		perror("tcopy: tape op");
284 		exit(6);
285 	}
286 }
287 
288 usage()
289 {
290 	fputs("usage: tcopy [-cv] [-s maxblk] src [dest]\n", stderr);
291 	exit(1);
292 }
293