124973Sbloom /* 230870Skarels * Copyright (c) 1985, 1987 Regents of the University of California. 332759Sbostic * All rights reserved. 432759Sbostic * 532759Sbostic * Redistribution and use in source and binary forms are permitted 632759Sbostic * provided that this notice is preserved and that due credit is given 732759Sbostic * to the University of California at Berkeley. The name of the University 832759Sbostic * may not be used to endorse or promote products derived from this 932759Sbostic * software without specific written prior permission. This software 1032759Sbostic * is provided ``as is'' without express or implied warranty. 1124973Sbloom */ 1224973Sbloom 1324973Sbloom #ifndef lint 1424973Sbloom char copyright[] = 1530870Skarels "@(#) Copyright (c) 1985, 1987 Regents of the University of California.\n\ 1624973Sbloom All rights reserved.\n"; 1732759Sbostic #endif /* not lint */ 1824973Sbloom 1924973Sbloom #ifndef lint 20*34185Sbostic static char sccsid[] = "@(#)tcopy.c 5.7 (Berkeley) 05/04/88"; 2132759Sbostic #endif /* not lint */ 2224973Sbloom 2324973Sbloom #include <stdio.h> 2425590Sbloom #include <signal.h> 2524973Sbloom #include <sys/file.h> 2624973Sbloom #include <sys/types.h> 2724973Sbloom #include <sys/ioctl.h> 2824973Sbloom #include <sys/mtio.h> 2930873Skarels #include <sys/errno.h> 3024973Sbloom 31*34185Sbostic #define MAXREC (64 * 1024) 32*34185Sbostic #define NOCOUNT (-2) 33*34185Sbostic 3430870Skarels #undef DEFTAPE 3530870Skarels #define DEFTAPE "/dev/rmt0" 3624973Sbloom 37*34185Sbostic int filen, guesslen, maxblk = MAXREC; 38*34185Sbostic long lastrec, record, size, tsize; 3924973Sbloom 4024973Sbloom main(argc, argv) 4132759Sbostic int argc; 4232759Sbostic char **argv; 4324973Sbloom { 44*34185Sbostic extern char *optarg; 45*34185Sbostic extern int optind, errno; 46*34185Sbostic register int lastnread, nread, nw, inp, outp; 47*34185Sbostic enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 48*34185Sbostic int ch, needeof, intr(), (*oldsig)(); 49*34185Sbostic char *buff, *inf, *getspace(); 5024973Sbloom 51*34185Sbostic guesslen = 1; 52*34185Sbostic while ((ch = getopt(argc, argv, "cs:v")) != EOF) 53*34185Sbostic switch((char)ch) { 54*34185Sbostic case 'c': 55*34185Sbostic op = COPYVERIFY; 56*34185Sbostic break; 5730870Skarels case 's': 58*34185Sbostic maxblk = atoi(optarg); 5930870Skarels if (maxblk <= 0) { 60*34185Sbostic fputs("tcopy: illegal block size\n", stderr); 61*34185Sbostic usage(); 6230870Skarels } 6330870Skarels guesslen = 0; 6430870Skarels break; 65*34185Sbostic case 'v': 66*34185Sbostic op = VERIFY; 67*34185Sbostic break; 68*34185Sbostic case '?': 69*34185Sbostic default: 70*34185Sbostic usage(); 7130870Skarels } 72*34185Sbostic argc -= optind; 73*34185Sbostic argv += optind; 74*34185Sbostic 75*34185Sbostic switch(argc) { 76*34185Sbostic case 0: 77*34185Sbostic if (op != READ) 78*34185Sbostic usage(); 79*34185Sbostic inf = DEFTAPE; 80*34185Sbostic break; 81*34185Sbostic case 1: 82*34185Sbostic if (op != READ) 83*34185Sbostic usage(); 84*34185Sbostic inf = argv[0]; 85*34185Sbostic break; 86*34185Sbostic case 2: 87*34185Sbostic if (op == READ) 88*34185Sbostic op = COPY; 89*34185Sbostic inf = argv[0]; 90*34185Sbostic if ((outp = open(argv[1], O_RDWR, 0666)) < 0) { 91*34185Sbostic perror(argv[1]); 92*34185Sbostic exit(3); 93*34185Sbostic } 94*34185Sbostic break; 95*34185Sbostic default: 96*34185Sbostic usage(); 9730870Skarels } 98*34185Sbostic 9930870Skarels if ((inp = open(inf, O_RDONLY, 0)) < 0) { 10030870Skarels perror(inf); 10130870Skarels exit(1); 10230870Skarels } 103*34185Sbostic 104*34185Sbostic buff = getspace(maxblk); 105*34185Sbostic 106*34185Sbostic if (op == VERIFY) { 107*34185Sbostic verify(inp, outp, buff); 108*34185Sbostic exit(0); 10924973Sbloom } 110*34185Sbostic 111*34185Sbostic if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 11230870Skarels (void) signal(SIGINT, intr); 113*34185Sbostic 114*34185Sbostic needeof = 0; 115*34185Sbostic for (lastnread = NOCOUNT;;) { 116*34185Sbostic if ((nread = read(inp, buff, maxblk)) == -1) { 117*34185Sbostic while (errno == EINVAL && (maxblk -= 1024)) { 118*34185Sbostic nread = read(inp, buff, maxblk); 119*34185Sbostic if (nread >= 0) 120*34185Sbostic goto r1; 12130870Skarels } 12232759Sbostic fprintf(stderr, "read error, file %d, record %ld: ", 12330870Skarels filen, record); 12430870Skarels perror(""); 125*34185Sbostic exit(1); 126*34185Sbostic } else if (nread != lastnread) { 127*34185Sbostic if (lastnread != 0 && lastnread != NOCOUNT) { 12830870Skarels if (lastrec == 0 && nread == 0) 12932759Sbostic printf("%ld records\n", record); 13030870Skarels else if (record - lastrec > 1) 13130870Skarels printf("records %ld to %ld\n", 13230870Skarels lastrec, record); 13330870Skarels else 13430870Skarels printf("record %ld\n", lastrec); 13530870Skarels } 13630870Skarels if (nread != 0) 13730870Skarels printf("file %d: block size %d: ", 13830870Skarels filen, nread); 13932759Sbostic (void) fflush(stdout); 14030870Skarels lastrec = record; 14124973Sbloom } 142*34185Sbostic r1: guesslen = 0; 14330870Skarels if (nread > 0) { 144*34185Sbostic if (op >= COPY) { 14530870Skarels if (needeof) { 146*34185Sbostic writeop(outp, MTWEOF); 147*34185Sbostic needeof = 0; 14830870Skarels } 14930870Skarels nw = write(outp, buff, nread); 15030870Skarels if (nw != nread) { 15130870Skarels fprintf(stderr, 15232759Sbostic "write error, file %d, record %ld: ", 15330870Skarels filen, record); 15430870Skarels if (nw == -1) 15530870Skarels perror(""); 15630870Skarels else 15730870Skarels fprintf(stderr, 15830870Skarels "write (%d) != read (%d)\n", 15930870Skarels nw, nread); 16030870Skarels fprintf(stderr, "copy aborted\n"); 16130870Skarels exit(5); 16230870Skarels } 16330870Skarels } 16430870Skarels size += nread; 16530870Skarels record++; 16630870Skarels } else { 167*34185Sbostic if (lastnread <= 0 && lastnread != NOCOUNT) { 16824973Sbloom printf("eot\n"); 16924973Sbloom break; 17024973Sbloom } 17124973Sbloom printf("file %d: eof after %ld records: %ld bytes\n", 17230870Skarels filen, record, size); 17330870Skarels needeof = 1; 17424973Sbloom filen++; 17524973Sbloom tsize += size; 176*34185Sbostic size = record = lastrec = 0; 177*34185Sbostic lastnread = 0; 17824973Sbloom } 179*34185Sbostic lastnread = nread; 18024973Sbloom } 18124973Sbloom printf("total length: %ld bytes\n", tsize); 182*34185Sbostic (void)signal(SIGINT, oldsig); 183*34185Sbostic if (op >= COPY) { 184*34185Sbostic writeop(outp, MTWEOF); 185*34185Sbostic writeop(outp, MTWEOF); 186*34185Sbostic if (op == COPYVERIFY) { 187*34185Sbostic writeop(outp, MTREW); 188*34185Sbostic writeop(inp, MTREW); 189*34185Sbostic verify(inp, outp, buff); 190*34185Sbostic } 191*34185Sbostic } 192*34185Sbostic exit(0); 19324973Sbloom } 19424973Sbloom 195*34185Sbostic static 196*34185Sbostic verify(inp, outp, outb) 197*34185Sbostic register int inp, outp; 198*34185Sbostic register char *outb; 199*34185Sbostic { 200*34185Sbostic register int eot, inmaxblk, inn, outmaxblk, outn; 201*34185Sbostic register char *inb; 202*34185Sbostic char *getspace(); 203*34185Sbostic 204*34185Sbostic inb = getspace(maxblk); 205*34185Sbostic inmaxblk = outmaxblk = maxblk; 206*34185Sbostic for (eot = 0;; guesslen = 0) { 207*34185Sbostic if ((inn = read(inp, inb, inmaxblk)) == -1) { 208*34185Sbostic if (guesslen) 209*34185Sbostic while (errno == EINVAL && (inmaxblk -= 1024)) { 210*34185Sbostic inn = read(inp, inb, inmaxblk); 211*34185Sbostic if (inn >= 0) 212*34185Sbostic goto r1; 213*34185Sbostic } 214*34185Sbostic perror("tcopy: read error"); 215*34185Sbostic exit(1); 216*34185Sbostic } 217*34185Sbostic r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 218*34185Sbostic if (guesslen) 219*34185Sbostic while (errno == EINVAL && (outmaxblk -= 1024)) { 220*34185Sbostic outn = read(outp, outb, outmaxblk); 221*34185Sbostic if (outn >= 0) 222*34185Sbostic goto r2; 223*34185Sbostic } 224*34185Sbostic perror("tcopy: read error"); 225*34185Sbostic exit(1); 226*34185Sbostic } 227*34185Sbostic r2: if (inn != outn) 228*34185Sbostic break; 229*34185Sbostic if (!inn) { 230*34185Sbostic if (eot++) { 231*34185Sbostic puts("tcopy: tapes are identical."); 232*34185Sbostic return; 233*34185Sbostic } 234*34185Sbostic } else { 235*34185Sbostic if (bcmp(inb, outb, inn)) 236*34185Sbostic break; 237*34185Sbostic eot = 0; 238*34185Sbostic } 239*34185Sbostic } 240*34185Sbostic puts("tcopy: tapes are different."); 241*34185Sbostic exit(1); 242*34185Sbostic } 243*34185Sbostic 244*34185Sbostic static 24530870Skarels intr() 24624973Sbloom { 24730870Skarels if (record) 24830870Skarels if (record - lastrec > 1) 24930870Skarels printf("records %ld to %ld\n", lastrec, record); 25024973Sbloom else 25130870Skarels printf("record %ld\n", lastrec); 25230870Skarels printf("interrupt at file %d: record %ld\n", filen, record); 253*34185Sbostic printf("total length: %ld bytes\n", tsize + size); 25424973Sbloom exit(1); 25524973Sbloom } 256*34185Sbostic 257*34185Sbostic static char * 258*34185Sbostic getspace(blk) 259*34185Sbostic int blk; 260*34185Sbostic { 261*34185Sbostic char *bp, *malloc(); 262*34185Sbostic 263*34185Sbostic if ((bp = malloc((u_int)blk)) == NULL) { 264*34185Sbostic fputs("tcopy: no memory\n", stderr); 265*34185Sbostic exit(11); 266*34185Sbostic } 267*34185Sbostic return(bp); 268*34185Sbostic } 269*34185Sbostic 270*34185Sbostic static 271*34185Sbostic writeop(fd, type) 272*34185Sbostic int fd, type; 273*34185Sbostic { 274*34185Sbostic struct mtop op; 275*34185Sbostic 276*34185Sbostic op.mt_op = type; 277*34185Sbostic op.mt_count = (daddr_t)1; 278*34185Sbostic if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) { 279*34185Sbostic perror("tcopy: tape op"); 280*34185Sbostic exit(6); 281*34185Sbostic } 282*34185Sbostic } 283*34185Sbostic 284*34185Sbostic static 285*34185Sbostic usage() 286*34185Sbostic { 287*34185Sbostic fputs("usage: tcopy [-cv] [-s maxblk] src [dest]\n", stderr); 288*34185Sbostic exit(1); 289*34185Sbostic } 290