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 634911Sbostic * provided that the above copyright notice and this paragraph are 734911Sbostic * duplicated in all such forms and that any documentation, 834911Sbostic * advertising materials, and other materials related to such 934911Sbostic * distribution and use acknowledge that the software was developed 1034911Sbostic * by the University of California, Berkeley. The name of the 1134911Sbostic * University may not be used to endorse or promote products derived 1234911Sbostic * from this software without specific prior written permission. 1334911Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434911Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534911Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1624973Sbloom */ 1724973Sbloom 1824973Sbloom #ifndef lint 1924973Sbloom char copyright[] = 2030870Skarels "@(#) Copyright (c) 1985, 1987 Regents of the University of California.\n\ 2124973Sbloom All rights reserved.\n"; 2232759Sbostic #endif /* not lint */ 2324973Sbloom 2424973Sbloom #ifndef lint 25*35696Sbostic static char sccsid[] = "@(#)tcopy.c 5.10 (Berkeley) 09/22/88"; 2632759Sbostic #endif /* not lint */ 2724973Sbloom 2824973Sbloom #include <stdio.h> 2925590Sbloom #include <signal.h> 3024973Sbloom #include <sys/file.h> 3124973Sbloom #include <sys/types.h> 3224973Sbloom #include <sys/ioctl.h> 3324973Sbloom #include <sys/mtio.h> 3430873Skarels #include <sys/errno.h> 3524973Sbloom 3634185Sbostic #define MAXREC (64 * 1024) 3734185Sbostic #define NOCOUNT (-2) 3834185Sbostic 3930870Skarels #undef DEFTAPE 4030870Skarels #define DEFTAPE "/dev/rmt0" 4124973Sbloom 4234185Sbostic int filen, guesslen, maxblk = MAXREC; 4334185Sbostic long lastrec, record, size, tsize; 4424973Sbloom 4524973Sbloom main(argc, argv) 4632759Sbostic int argc; 4732759Sbostic char **argv; 4824973Sbloom { 4934185Sbostic extern char *optarg; 5034185Sbostic extern int optind, errno; 5134185Sbostic register int lastnread, nread, nw, inp, outp; 5234185Sbostic enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 5334185Sbostic int ch, needeof, intr(), (*oldsig)(); 5434185Sbostic char *buff, *inf, *getspace(); 5524973Sbloom 5634185Sbostic guesslen = 1; 5734185Sbostic while ((ch = getopt(argc, argv, "cs:v")) != EOF) 5834185Sbostic switch((char)ch) { 5934185Sbostic case 'c': 6034185Sbostic op = COPYVERIFY; 6134185Sbostic break; 6230870Skarels case 's': 6334185Sbostic maxblk = atoi(optarg); 6430870Skarels if (maxblk <= 0) { 6534185Sbostic fputs("tcopy: illegal block size\n", stderr); 6634185Sbostic usage(); 6730870Skarels } 6830870Skarels guesslen = 0; 6930870Skarels break; 7034185Sbostic case 'v': 7134185Sbostic op = VERIFY; 7234185Sbostic break; 7334185Sbostic case '?': 7434185Sbostic default: 7534185Sbostic usage(); 7630870Skarels } 7734185Sbostic argc -= optind; 7834185Sbostic argv += optind; 7934185Sbostic 8034185Sbostic switch(argc) { 8134185Sbostic case 0: 8234185Sbostic if (op != READ) 8334185Sbostic usage(); 8434185Sbostic inf = DEFTAPE; 8534185Sbostic break; 8634185Sbostic case 1: 8734185Sbostic if (op != READ) 8834185Sbostic usage(); 8934185Sbostic inf = argv[0]; 9034185Sbostic break; 9134185Sbostic case 2: 9234185Sbostic if (op == READ) 9334185Sbostic op = COPY; 9434185Sbostic inf = argv[0]; 9534954Sbostic if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : O_RDWR, 9634954Sbostic 0666)) < 0) { 9734185Sbostic perror(argv[1]); 9834185Sbostic exit(3); 9934185Sbostic } 10034185Sbostic break; 10134185Sbostic default: 10234185Sbostic usage(); 10330870Skarels } 10434185Sbostic 10530870Skarels if ((inp = open(inf, O_RDONLY, 0)) < 0) { 10630870Skarels perror(inf); 10730870Skarels exit(1); 10830870Skarels } 10934185Sbostic 11034185Sbostic buff = getspace(maxblk); 11134185Sbostic 11234185Sbostic if (op == VERIFY) { 11334185Sbostic verify(inp, outp, buff); 11434185Sbostic exit(0); 11524973Sbloom } 11634185Sbostic 11734185Sbostic if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 11830870Skarels (void) signal(SIGINT, intr); 11934185Sbostic 12034185Sbostic needeof = 0; 12134185Sbostic for (lastnread = NOCOUNT;;) { 12234185Sbostic if ((nread = read(inp, buff, maxblk)) == -1) { 12334185Sbostic while (errno == EINVAL && (maxblk -= 1024)) { 12434185Sbostic nread = read(inp, buff, maxblk); 12534185Sbostic if (nread >= 0) 12634185Sbostic goto r1; 12730870Skarels } 12832759Sbostic fprintf(stderr, "read error, file %d, record %ld: ", 12930870Skarels filen, record); 13030870Skarels perror(""); 13134185Sbostic exit(1); 13234185Sbostic } else if (nread != lastnread) { 13334185Sbostic if (lastnread != 0 && lastnread != NOCOUNT) { 13430870Skarels if (lastrec == 0 && nread == 0) 13532759Sbostic printf("%ld records\n", record); 13630870Skarels else if (record - lastrec > 1) 13730870Skarels printf("records %ld to %ld\n", 13830870Skarels lastrec, record); 13930870Skarels else 14030870Skarels printf("record %ld\n", lastrec); 14130870Skarels } 14230870Skarels if (nread != 0) 14330870Skarels printf("file %d: block size %d: ", 14430870Skarels filen, nread); 14532759Sbostic (void) fflush(stdout); 14630870Skarels lastrec = record; 14724973Sbloom } 14834185Sbostic r1: guesslen = 0; 14930870Skarels if (nread > 0) { 15034911Sbostic if (op >= COPY) { 15130870Skarels if (needeof) { 15234185Sbostic writeop(outp, MTWEOF); 15334185Sbostic needeof = 0; 15430870Skarels } 15530870Skarels nw = write(outp, buff, nread); 15630870Skarels if (nw != nread) { 15730870Skarels fprintf(stderr, 15832759Sbostic "write error, file %d, record %ld: ", 15930870Skarels filen, record); 16030870Skarels if (nw == -1) 16130870Skarels perror(""); 16230870Skarels else 16330870Skarels fprintf(stderr, 16430870Skarels "write (%d) != read (%d)\n", 16530870Skarels nw, nread); 16630870Skarels fprintf(stderr, "copy aborted\n"); 16730870Skarels exit(5); 16830870Skarels } 16930870Skarels } 17030870Skarels size += nread; 17130870Skarels record++; 17230870Skarels } else { 17334185Sbostic if (lastnread <= 0 && lastnread != NOCOUNT) { 17424973Sbloom printf("eot\n"); 17524973Sbloom break; 17624973Sbloom } 17724973Sbloom printf("file %d: eof after %ld records: %ld bytes\n", 17830870Skarels filen, record, size); 17930870Skarels needeof = 1; 18024973Sbloom filen++; 18124973Sbloom tsize += size; 18234185Sbostic size = record = lastrec = 0; 18334185Sbostic lastnread = 0; 18424973Sbloom } 18534185Sbostic lastnread = nread; 18624973Sbloom } 18724973Sbloom printf("total length: %ld bytes\n", tsize); 18834185Sbostic (void)signal(SIGINT, oldsig); 18934911Sbostic if (op >= COPY) { 19034185Sbostic writeop(outp, MTWEOF); 19134185Sbostic writeop(outp, MTWEOF); 19234185Sbostic if (op == COPYVERIFY) { 19334185Sbostic writeop(outp, MTREW); 19434185Sbostic writeop(inp, MTREW); 19534185Sbostic verify(inp, outp, buff); 19634185Sbostic } 19734185Sbostic } 19834185Sbostic exit(0); 19924973Sbloom } 20024973Sbloom 20134185Sbostic verify(inp, outp, outb) 20234185Sbostic register int inp, outp; 20334185Sbostic register char *outb; 20434185Sbostic { 205*35696Sbostic extern int errno; 20634185Sbostic register int eot, inmaxblk, inn, outmaxblk, outn; 20734185Sbostic register char *inb; 20834185Sbostic char *getspace(); 20934185Sbostic 21034185Sbostic inb = getspace(maxblk); 21134185Sbostic inmaxblk = outmaxblk = maxblk; 21234185Sbostic for (eot = 0;; guesslen = 0) { 21334185Sbostic if ((inn = read(inp, inb, inmaxblk)) == -1) { 21434185Sbostic if (guesslen) 21534185Sbostic while (errno == EINVAL && (inmaxblk -= 1024)) { 21634185Sbostic inn = read(inp, inb, inmaxblk); 21734185Sbostic if (inn >= 0) 21834185Sbostic goto r1; 21934185Sbostic } 22034185Sbostic perror("tcopy: read error"); 22134185Sbostic exit(1); 22234185Sbostic } 22334185Sbostic r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 22434185Sbostic if (guesslen) 22534185Sbostic while (errno == EINVAL && (outmaxblk -= 1024)) { 22634185Sbostic outn = read(outp, outb, outmaxblk); 22734185Sbostic if (outn >= 0) 22834185Sbostic goto r2; 22934185Sbostic } 23034185Sbostic perror("tcopy: read error"); 23134185Sbostic exit(1); 23234185Sbostic } 23334185Sbostic r2: if (inn != outn) 23434185Sbostic break; 23534185Sbostic if (!inn) { 23634185Sbostic if (eot++) { 23734185Sbostic puts("tcopy: tapes are identical."); 23834185Sbostic return; 23934185Sbostic } 24034185Sbostic } else { 24134185Sbostic if (bcmp(inb, outb, inn)) 24234185Sbostic break; 24334185Sbostic eot = 0; 24434185Sbostic } 24534185Sbostic } 24634185Sbostic puts("tcopy: tapes are different."); 24734185Sbostic exit(1); 24834185Sbostic } 24934185Sbostic 25030870Skarels intr() 25124973Sbloom { 25230870Skarels if (record) 25330870Skarels if (record - lastrec > 1) 25430870Skarels printf("records %ld to %ld\n", lastrec, record); 25524973Sbloom else 25630870Skarels printf("record %ld\n", lastrec); 25730870Skarels printf("interrupt at file %d: record %ld\n", filen, record); 25834185Sbostic printf("total length: %ld bytes\n", tsize + size); 25924973Sbloom exit(1); 26024973Sbloom } 26134185Sbostic 262*35696Sbostic char * 26334185Sbostic getspace(blk) 26434185Sbostic int blk; 26534185Sbostic { 26634185Sbostic char *bp, *malloc(); 26734185Sbostic 26834185Sbostic if ((bp = malloc((u_int)blk)) == NULL) { 26934185Sbostic fputs("tcopy: no memory\n", stderr); 27034185Sbostic exit(11); 27134185Sbostic } 27234185Sbostic return(bp); 27334185Sbostic } 27434185Sbostic 27534185Sbostic writeop(fd, type) 27634185Sbostic int fd, type; 27734185Sbostic { 27834185Sbostic struct mtop op; 27934185Sbostic 28034185Sbostic op.mt_op = type; 28134185Sbostic op.mt_count = (daddr_t)1; 28234185Sbostic if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) { 28334185Sbostic perror("tcopy: tape op"); 28434185Sbostic exit(6); 28534185Sbostic } 28634185Sbostic } 28734185Sbostic 28834185Sbostic usage() 28934185Sbostic { 29034185Sbostic fputs("usage: tcopy [-cv] [-s maxblk] src [dest]\n", stderr); 29134185Sbostic exit(1); 29234185Sbostic } 293