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