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