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 6*34911Sbostic * provided that the above copyright notice and this paragraph are 7*34911Sbostic * duplicated in all such forms and that any documentation, 8*34911Sbostic * advertising materials, and other materials related to such 9*34911Sbostic * distribution and use acknowledge that the software was developed 10*34911Sbostic * by the University of California, Berkeley. The name of the 11*34911Sbostic * University may not be used to endorse or promote products derived 12*34911Sbostic * from this software without specific prior written permission. 13*34911Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34911Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34911Sbostic * 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*34911Sbostic static char sccsid[] = "@(#)tcopy.c 5.8 (Berkeley) 06/29/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]; 9534185Sbostic if ((outp = open(argv[1], O_RDWR, 0666)) < 0) { 9634185Sbostic perror(argv[1]); 9734185Sbostic exit(3); 9834185Sbostic } 9934185Sbostic break; 10034185Sbostic default: 10134185Sbostic usage(); 10230870Skarels } 10334185Sbostic 10430870Skarels if ((inp = open(inf, O_RDONLY, 0)) < 0) { 10530870Skarels perror(inf); 10630870Skarels exit(1); 10730870Skarels } 10834185Sbostic 10934185Sbostic buff = getspace(maxblk); 11034185Sbostic 11134185Sbostic if (op == VERIFY) { 11234185Sbostic verify(inp, outp, buff); 11334185Sbostic exit(0); 11424973Sbloom } 11534185Sbostic 11634185Sbostic if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 11730870Skarels (void) signal(SIGINT, intr); 11834185Sbostic 11934185Sbostic needeof = 0; 12034185Sbostic for (lastnread = NOCOUNT;;) { 12134185Sbostic if ((nread = read(inp, buff, maxblk)) == -1) { 12234185Sbostic while (errno == EINVAL && (maxblk -= 1024)) { 12334185Sbostic nread = read(inp, buff, maxblk); 12434185Sbostic if (nread >= 0) 12534185Sbostic goto r1; 12630870Skarels } 12732759Sbostic fprintf(stderr, "read error, file %d, record %ld: ", 12830870Skarels filen, record); 12930870Skarels perror(""); 13034185Sbostic exit(1); 13134185Sbostic } else if (nread != lastnread) { 13234185Sbostic if (lastnread != 0 && lastnread != NOCOUNT) { 13330870Skarels if (lastrec == 0 && nread == 0) 13432759Sbostic printf("%ld records\n", record); 13530870Skarels else if (record - lastrec > 1) 13630870Skarels printf("records %ld to %ld\n", 13730870Skarels lastrec, record); 13830870Skarels else 13930870Skarels printf("record %ld\n", lastrec); 14030870Skarels } 14130870Skarels if (nread != 0) 14230870Skarels printf("file %d: block size %d: ", 14330870Skarels filen, nread); 14432759Sbostic (void) fflush(stdout); 14530870Skarels lastrec = record; 14624973Sbloom } 14734185Sbostic r1: guesslen = 0; 14830870Skarels if (nread > 0) { 149*34911Sbostic if (op >= COPY) { 15030870Skarels if (needeof) { 15134185Sbostic writeop(outp, MTWEOF); 15234185Sbostic needeof = 0; 15330870Skarels } 15430870Skarels nw = write(outp, buff, nread); 15530870Skarels if (nw != nread) { 15630870Skarels fprintf(stderr, 15732759Sbostic "write error, file %d, record %ld: ", 15830870Skarels filen, record); 15930870Skarels if (nw == -1) 16030870Skarels perror(""); 16130870Skarels else 16230870Skarels fprintf(stderr, 16330870Skarels "write (%d) != read (%d)\n", 16430870Skarels nw, nread); 16530870Skarels fprintf(stderr, "copy aborted\n"); 16630870Skarels exit(5); 16730870Skarels } 16830870Skarels } 16930870Skarels size += nread; 17030870Skarels record++; 17130870Skarels } else { 17234185Sbostic if (lastnread <= 0 && lastnread != NOCOUNT) { 17324973Sbloom printf("eot\n"); 17424973Sbloom break; 17524973Sbloom } 17624973Sbloom printf("file %d: eof after %ld records: %ld bytes\n", 17730870Skarels filen, record, size); 17830870Skarels needeof = 1; 17924973Sbloom filen++; 18024973Sbloom tsize += size; 18134185Sbostic size = record = lastrec = 0; 18234185Sbostic lastnread = 0; 18324973Sbloom } 18434185Sbostic lastnread = nread; 18524973Sbloom } 18624973Sbloom printf("total length: %ld bytes\n", tsize); 18734185Sbostic (void)signal(SIGINT, oldsig); 188*34911Sbostic if (op >= COPY) { 18934185Sbostic writeop(outp, MTWEOF); 19034185Sbostic writeop(outp, MTWEOF); 19134185Sbostic if (op == COPYVERIFY) { 19234185Sbostic writeop(outp, MTREW); 19334185Sbostic writeop(inp, MTREW); 19434185Sbostic verify(inp, outp, buff); 19534185Sbostic } 19634185Sbostic } 19734185Sbostic exit(0); 19824973Sbloom } 19924973Sbloom 20034185Sbostic static 20134185Sbostic verify(inp, outp, outb) 20234185Sbostic register int inp, outp; 20334185Sbostic register char *outb; 20434185Sbostic { 20534185Sbostic register int eot, inmaxblk, inn, outmaxblk, outn; 20634185Sbostic register char *inb; 20734185Sbostic char *getspace(); 20834185Sbostic 20934185Sbostic inb = getspace(maxblk); 21034185Sbostic inmaxblk = outmaxblk = maxblk; 21134185Sbostic for (eot = 0;; guesslen = 0) { 21234185Sbostic if ((inn = read(inp, inb, inmaxblk)) == -1) { 21334185Sbostic if (guesslen) 21434185Sbostic while (errno == EINVAL && (inmaxblk -= 1024)) { 21534185Sbostic inn = read(inp, inb, inmaxblk); 21634185Sbostic if (inn >= 0) 21734185Sbostic goto r1; 21834185Sbostic } 21934185Sbostic perror("tcopy: read error"); 22034185Sbostic exit(1); 22134185Sbostic } 22234185Sbostic r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 22334185Sbostic if (guesslen) 22434185Sbostic while (errno == EINVAL && (outmaxblk -= 1024)) { 22534185Sbostic outn = read(outp, outb, outmaxblk); 22634185Sbostic if (outn >= 0) 22734185Sbostic goto r2; 22834185Sbostic } 22934185Sbostic perror("tcopy: read error"); 23034185Sbostic exit(1); 23134185Sbostic } 23234185Sbostic r2: if (inn != outn) 23334185Sbostic break; 23434185Sbostic if (!inn) { 23534185Sbostic if (eot++) { 23634185Sbostic puts("tcopy: tapes are identical."); 23734185Sbostic return; 23834185Sbostic } 23934185Sbostic } else { 24034185Sbostic if (bcmp(inb, outb, inn)) 24134185Sbostic break; 24234185Sbostic eot = 0; 24334185Sbostic } 24434185Sbostic } 24534185Sbostic puts("tcopy: tapes are different."); 24634185Sbostic exit(1); 24734185Sbostic } 24834185Sbostic 24934185Sbostic static 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 26234185Sbostic static 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 static 27634185Sbostic writeop(fd, type) 27734185Sbostic int fd, type; 27834185Sbostic { 27934185Sbostic struct mtop op; 28034185Sbostic 28134185Sbostic op.mt_op = type; 28234185Sbostic op.mt_count = (daddr_t)1; 28334185Sbostic if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) { 28434185Sbostic perror("tcopy: tape op"); 28534185Sbostic exit(6); 28634185Sbostic } 28734185Sbostic } 28834185Sbostic 28934185Sbostic static 29034185Sbostic usage() 29134185Sbostic { 29234185Sbostic fputs("usage: tcopy [-cv] [-s maxblk] src [dest]\n", stderr); 29334185Sbostic exit(1); 29434185Sbostic } 295