1 /* $NetBSD: tcopy.c,v 1.4 1995/08/31 22:17:24 jtc 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 #ifndef lint 37 static char copyright[] = 38 "@(#) 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 static char rcsid[] = "$NetBSD: tcopy.c,v 1.4 1995/08/31 22:17:24 jtc 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 <fcntl.h> 57 #include <signal.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 63 #include "pathnames.h" 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 void usage __P((void)); 76 void verify __P((int, int, char *)); 77 void writeop __P((int, int)); 78 79 int 80 main(argc, argv) 81 int argc; 82 char *argv[]; 83 { 84 int ch, needeof, nw, inp, outp; 85 ssize_t lastnread, nread; 86 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 87 sig_t oldsig; 88 char *buff, *inf; 89 90 guesslen = 1; 91 while ((ch = getopt(argc, argv, "cs:vx")) != EOF) 92 switch((char)ch) { 93 case 'c': 94 op = COPYVERIFY; 95 break; 96 case 's': 97 maxblk = atoi(optarg); 98 if (maxblk <= 0) { 99 warnx("illegal block size"); 100 usage(); 101 } 102 guesslen = 0; 103 break; 104 case 'v': 105 op = VERIFY; 106 break; 107 case 'x': 108 msg = stderr; 109 break; 110 case '?': 111 default: 112 usage(); 113 } 114 argc -= optind; 115 argv += optind; 116 117 switch(argc) { 118 case 0: 119 if (op != READ) 120 usage(); 121 inf = _PATH_DEFTAPE; 122 break; 123 case 1: 124 if (op != READ) 125 usage(); 126 inf = argv[0]; 127 break; 128 case 2: 129 if (op == READ) 130 op = COPY; 131 inf = argv[0]; 132 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 133 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) { 134 err(3, argv[1]); 135 } 136 break; 137 default: 138 usage(); 139 } 140 141 if ((inp = open(inf, O_RDONLY, 0)) < 0) 142 err(1, inf); 143 144 buff = getspace(maxblk); 145 146 if (op == VERIFY) { 147 verify(inp, outp, buff); 148 exit(0); 149 } 150 151 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 152 (void) signal(SIGINT, intr); 153 154 needeof = 0; 155 for (lastnread = NOCOUNT;;) { 156 if ((nread = read(inp, buff, maxblk)) == -1) { 157 while (errno == EINVAL && (maxblk -= 1024)) { 158 nread = read(inp, buff, maxblk); 159 if (nread >= 0) 160 goto r1; 161 } 162 err(1, "read error, file %d, record %ld", 163 filen, record); 164 } else if (nread != lastnread) { 165 if (lastnread != 0 && lastnread != NOCOUNT) { 166 if (lastrec == 0 && nread == 0) 167 fprintf(msg, "%ld records\n", record); 168 else if (record - lastrec > 1) 169 fprintf(msg, "records %ld to %ld\n", 170 lastrec, record); 171 else 172 fprintf(msg, "record %ld\n", lastrec); 173 } 174 if (nread != 0) 175 fprintf(msg, "file %d: block size %d: ", 176 filen, nread); 177 (void) fflush(stdout); 178 lastrec = record; 179 } 180 r1: guesslen = 0; 181 if (nread > 0) { 182 if (op == COPY || op == COPYVERIFY) { 183 if (needeof) { 184 writeop(outp, MTWEOF); 185 needeof = 0; 186 } 187 nw = write(outp, buff, nread); 188 if (nw != nread) { 189 int error = errno; 190 fprintf(stderr, 191 "write error, file %d, record %ld: ", 192 filen, record); 193 if (nw == -1) 194 fprintf(stderr, 195 ": %s", strerror(error)); 196 else 197 fprintf(stderr, 198 "write (%d) != read (%d)\n", 199 nw, nread); 200 fprintf(stderr, "copy aborted\n"); 201 exit(5); 202 } 203 } 204 size += nread; 205 record++; 206 } else { 207 if (lastnread <= 0 && lastnread != NOCOUNT) { 208 fprintf(msg, "eot\n"); 209 break; 210 } 211 fprintf(msg, 212 "file %d: eof after %ld records: %qd bytes\n", 213 filen, record, size); 214 needeof = 1; 215 filen++; 216 tsize += size; 217 size = record = lastrec = 0; 218 lastnread = 0; 219 } 220 lastnread = nread; 221 } 222 fprintf(msg, "total length: %qd bytes\n", tsize); 223 (void)signal(SIGINT, oldsig); 224 if (op == COPY || op == COPYVERIFY) { 225 writeop(outp, MTWEOF); 226 writeop(outp, MTWEOF); 227 if (op == COPYVERIFY) { 228 writeop(outp, MTREW); 229 writeop(inp, MTREW); 230 verify(inp, outp, buff); 231 } 232 } 233 exit(0); 234 } 235 236 void 237 verify(inp, outp, outb) 238 int inp, outp; 239 char *outb; 240 { 241 int eot, inmaxblk, inn, outmaxblk, outn; 242 char *inb; 243 244 inb = getspace(maxblk); 245 inmaxblk = outmaxblk = maxblk; 246 for (eot = 0;; guesslen = 0) { 247 if ((inn = read(inp, inb, inmaxblk)) == -1) { 248 if (guesslen) 249 while (errno == EINVAL && (inmaxblk -= 1024)) { 250 inn = read(inp, inb, inmaxblk); 251 if (inn >= 0) 252 goto r1; 253 } 254 warn("read error"); 255 break; 256 } 257 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 258 if (guesslen) 259 while (errno == EINVAL && (outmaxblk -= 1024)) { 260 outn = read(outp, outb, outmaxblk); 261 if (outn >= 0) 262 goto r2; 263 } 264 warn("read error"); 265 break; 266 } 267 r2: if (inn != outn) { 268 fprintf(msg, 269 "%s: tapes have different block sizes; %d != %d.\n", 270 "tcopy", inn, outn); 271 break; 272 } 273 if (!inn) { 274 if (eot++) { 275 fprintf(msg, "%s: tapes are identical.\n", 276 "tcopy"); 277 return; 278 } 279 } else { 280 if (bcmp(inb, outb, inn)) { 281 fprintf(msg, 282 "%s: tapes have different data.\n", 283 "tcopy"); 284 break; 285 } 286 eot = 0; 287 } 288 } 289 exit(1); 290 } 291 292 void 293 intr(signo) 294 int signo; 295 { 296 if (record) 297 if (record - lastrec > 1) 298 fprintf(msg, "records %ld to %ld\n", lastrec, record); 299 else 300 fprintf(msg, "record %ld\n", lastrec); 301 fprintf(msg, "interrupt at file %d: record %ld\n", filen, record); 302 fprintf(msg, "total length: %qd bytes\n", tsize + size); 303 exit(1); 304 } 305 306 void * 307 getspace(blk) 308 int blk; 309 { 310 void *bp; 311 312 if ((bp = malloc((size_t)blk)) == NULL) 313 errx(11, "no memory"); 314 315 return (bp); 316 } 317 318 void 319 writeop(fd, type) 320 int fd, type; 321 { 322 struct mtop op; 323 324 op.mt_op = type; 325 op.mt_count = (daddr_t)1; 326 if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 327 err(6, "tape op"); 328 } 329 330 void 331 usage() 332 { 333 334 fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n"); 335 exit(1); 336 } 337