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 this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific written prior permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #ifndef lint 14 char copyright[] = 15 "@(#) Copyright (c) 1985, 1987 Regents of the University of California.\n\ 16 All rights reserved.\n"; 17 #endif /* not lint */ 18 19 #ifndef lint 20 static char sccsid[] = "@(#)tcopy.c 5.7 (Berkeley) 05/04/88"; 21 #endif /* not lint */ 22 23 #include <stdio.h> 24 #include <signal.h> 25 #include <sys/file.h> 26 #include <sys/types.h> 27 #include <sys/ioctl.h> 28 #include <sys/mtio.h> 29 #include <sys/errno.h> 30 31 #define MAXREC (64 * 1024) 32 #define NOCOUNT (-2) 33 34 #undef DEFTAPE 35 #define DEFTAPE "/dev/rmt0" 36 37 int filen, guesslen, maxblk = MAXREC; 38 long lastrec, record, size, tsize; 39 40 main(argc, argv) 41 int argc; 42 char **argv; 43 { 44 extern char *optarg; 45 extern int optind, errno; 46 register int lastnread, nread, nw, inp, outp; 47 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 48 int ch, needeof, intr(), (*oldsig)(); 49 char *buff, *inf, *getspace(); 50 51 guesslen = 1; 52 while ((ch = getopt(argc, argv, "cs:v")) != EOF) 53 switch((char)ch) { 54 case 'c': 55 op = COPYVERIFY; 56 break; 57 case 's': 58 maxblk = atoi(optarg); 59 if (maxblk <= 0) { 60 fputs("tcopy: illegal block size\n", stderr); 61 usage(); 62 } 63 guesslen = 0; 64 break; 65 case 'v': 66 op = VERIFY; 67 break; 68 case '?': 69 default: 70 usage(); 71 } 72 argc -= optind; 73 argv += optind; 74 75 switch(argc) { 76 case 0: 77 if (op != READ) 78 usage(); 79 inf = DEFTAPE; 80 break; 81 case 1: 82 if (op != READ) 83 usage(); 84 inf = argv[0]; 85 break; 86 case 2: 87 if (op == READ) 88 op = COPY; 89 inf = argv[0]; 90 if ((outp = open(argv[1], O_RDWR, 0666)) < 0) { 91 perror(argv[1]); 92 exit(3); 93 } 94 break; 95 default: 96 usage(); 97 } 98 99 if ((inp = open(inf, O_RDONLY, 0)) < 0) { 100 perror(inf); 101 exit(1); 102 } 103 104 buff = getspace(maxblk); 105 106 if (op == VERIFY) { 107 verify(inp, outp, buff); 108 exit(0); 109 } 110 111 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 112 (void) signal(SIGINT, intr); 113 114 needeof = 0; 115 for (lastnread = NOCOUNT;;) { 116 if ((nread = read(inp, buff, maxblk)) == -1) { 117 while (errno == EINVAL && (maxblk -= 1024)) { 118 nread = read(inp, buff, maxblk); 119 if (nread >= 0) 120 goto r1; 121 } 122 fprintf(stderr, "read error, file %d, record %ld: ", 123 filen, record); 124 perror(""); 125 exit(1); 126 } else if (nread != lastnread) { 127 if (lastnread != 0 && lastnread != NOCOUNT) { 128 if (lastrec == 0 && nread == 0) 129 printf("%ld records\n", record); 130 else if (record - lastrec > 1) 131 printf("records %ld to %ld\n", 132 lastrec, record); 133 else 134 printf("record %ld\n", lastrec); 135 } 136 if (nread != 0) 137 printf("file %d: block size %d: ", 138 filen, nread); 139 (void) fflush(stdout); 140 lastrec = record; 141 } 142 r1: guesslen = 0; 143 if (nread > 0) { 144 if (op >= COPY) { 145 if (needeof) { 146 writeop(outp, MTWEOF); 147 needeof = 0; 148 } 149 nw = write(outp, buff, nread); 150 if (nw != nread) { 151 fprintf(stderr, 152 "write error, file %d, record %ld: ", 153 filen, record); 154 if (nw == -1) 155 perror(""); 156 else 157 fprintf(stderr, 158 "write (%d) != read (%d)\n", 159 nw, nread); 160 fprintf(stderr, "copy aborted\n"); 161 exit(5); 162 } 163 } 164 size += nread; 165 record++; 166 } else { 167 if (lastnread <= 0 && lastnread != NOCOUNT) { 168 printf("eot\n"); 169 break; 170 } 171 printf("file %d: eof after %ld records: %ld bytes\n", 172 filen, record, size); 173 needeof = 1; 174 filen++; 175 tsize += size; 176 size = record = lastrec = 0; 177 lastnread = 0; 178 } 179 lastnread = nread; 180 } 181 printf("total length: %ld bytes\n", tsize); 182 (void)signal(SIGINT, oldsig); 183 if (op >= COPY) { 184 writeop(outp, MTWEOF); 185 writeop(outp, MTWEOF); 186 if (op == COPYVERIFY) { 187 writeop(outp, MTREW); 188 writeop(inp, MTREW); 189 verify(inp, outp, buff); 190 } 191 } 192 exit(0); 193 } 194 195 static 196 verify(inp, outp, outb) 197 register int inp, outp; 198 register char *outb; 199 { 200 register int eot, inmaxblk, inn, outmaxblk, outn; 201 register char *inb; 202 char *getspace(); 203 204 inb = getspace(maxblk); 205 inmaxblk = outmaxblk = maxblk; 206 for (eot = 0;; guesslen = 0) { 207 if ((inn = read(inp, inb, inmaxblk)) == -1) { 208 if (guesslen) 209 while (errno == EINVAL && (inmaxblk -= 1024)) { 210 inn = read(inp, inb, inmaxblk); 211 if (inn >= 0) 212 goto r1; 213 } 214 perror("tcopy: read error"); 215 exit(1); 216 } 217 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 218 if (guesslen) 219 while (errno == EINVAL && (outmaxblk -= 1024)) { 220 outn = read(outp, outb, outmaxblk); 221 if (outn >= 0) 222 goto r2; 223 } 224 perror("tcopy: read error"); 225 exit(1); 226 } 227 r2: if (inn != outn) 228 break; 229 if (!inn) { 230 if (eot++) { 231 puts("tcopy: tapes are identical."); 232 return; 233 } 234 } else { 235 if (bcmp(inb, outb, inn)) 236 break; 237 eot = 0; 238 } 239 } 240 puts("tcopy: tapes are different."); 241 exit(1); 242 } 243 244 static 245 intr() 246 { 247 if (record) 248 if (record - lastrec > 1) 249 printf("records %ld to %ld\n", lastrec, record); 250 else 251 printf("record %ld\n", lastrec); 252 printf("interrupt at file %d: record %ld\n", filen, record); 253 printf("total length: %ld bytes\n", tsize + size); 254 exit(1); 255 } 256 257 static char * 258 getspace(blk) 259 int blk; 260 { 261 char *bp, *malloc(); 262 263 if ((bp = malloc((u_int)blk)) == NULL) { 264 fputs("tcopy: no memory\n", stderr); 265 exit(11); 266 } 267 return(bp); 268 } 269 270 static 271 writeop(fd, type) 272 int fd, type; 273 { 274 struct mtop op; 275 276 op.mt_op = type; 277 op.mt_count = (daddr_t)1; 278 if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) { 279 perror("tcopy: tape op"); 280 exit(6); 281 } 282 } 283 284 static 285 usage() 286 { 287 fputs("usage: tcopy [-cv] [-s maxblk] src [dest]\n", stderr); 288 exit(1); 289 } 290