tcopy.c revision 87709
124143Sjoerg/* 224143Sjoerg * Copyright (c) 1985, 1987, 1993 324143Sjoerg * The Regents of the University of California. All rights reserved. 447901Sn_hibma * 524143Sjoerg * Redistribution and use in source and binary forms, with or without 624143Sjoerg * modification, are permitted provided that the following conditions 724143Sjoerg * are met: 824143Sjoerg * 1. Redistributions of source code must retain the above copyright 938278Swosch * notice, this list of conditions and the following disclaimer. 1038278Swosch * 2. Redistributions in binary form must reproduce the above copyright 1124143Sjoerg * notice, this list of conditions and the following disclaimer in the 1224143Sjoerg * documentation and/or other materials provided with the distribution. 1324143Sjoerg * 3. All advertising materials mentioning features or use of this software 1447901Sn_hibma * must display the following acknowledgement: 1524143Sjoerg * This product includes software developed by the University of 1624143Sjoerg * California, Berkeley and its contributors. 1724143Sjoerg * 4. Neither the name of the University nor the names of its contributors 1824143Sjoerg * may be used to endorse or promote products derived from this software 1924143Sjoerg * without specific prior written permission. 2024143Sjoerg * 2172951Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2224143Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2350477Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2424143Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2524143Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2624143Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2742447Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2824143Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2924143Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3024143Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3124143Sjoerg * SUCH DAMAGE. 3224143Sjoerg */ 3324143Sjoerg 3424143Sjoerg#include <sys/cdefs.h> 3524143Sjoerg 3624143Sjoerg__FBSDID("$FreeBSD: head/usr.bin/tcopy/tcopy.c 87709 2001-12-11 23:44:53Z markm $"); 3727390Speter 3824143Sjoerg#ifndef lint 3924143Sjoergstatic const char copyright[] = 4024143Sjoerg"@(#) Copyright (c) 1985, 1987, 1993\n\ 4124143Sjoerg The Regents of the University of California. All rights reserved.\n"; 4224143Sjoerg#endif 4324143Sjoerg 4424143Sjoerg#ifndef lint 4524143Sjoergstatic const char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94"; 4629904Speter#endif 4729904Speter 4824143Sjoerg#include <sys/types.h> 4924143Sjoerg#include <sys/stat.h> 5024143Sjoerg#include <sys/ioctl.h> 5124143Sjoerg#include <sys/mtio.h> 5224143Sjoerg 5372951Srwatson#include <err.h> 5424143Sjoerg#include <errno.h> 5524143Sjoerg#include <fcntl.h> 5624143Sjoerg#include <paths.h> 5724143Sjoerg#include <signal.h> 5869375Sjhb#include <stdio.h> 5972951Srwatson#include <stdlib.h> 6024143Sjoerg#include <string.h> 6172951Srwatson#include <unistd.h> 6272951Srwatson 6372951Srwatson#define MAXREC (64 * 1024) 6472951Srwatson#define NOCOUNT (-2) 6524143Sjoerg 6624143Sjoergint filen, guesslen, maxblk = MAXREC; 6727340Speteru_int64_t lastrec, record, size, tsize; 6827390SpeterFILE *msg; 6969375Sjhb 7024143Sjoergvoid *getspace __P((int)); 7172951Srwatsonvoid intr __P((int)); 7272951Srwatsonstatic void usage __P((void)); 7324143Sjoergvoid verify __P((int, int, char *)); 7424143Sjoergvoid writeop __P((int, int)); 7524143Sjoergvoid rewind_tape(int); 7624143Sjoerg 7724143Sjoergint 7824143Sjoergmain(argc, argv) 7924143Sjoerg int argc; 8024143Sjoerg char *argv[]; 8124143Sjoerg{ 8224143Sjoerg register int lastnread, nread, nw, inp, outp; 8324143Sjoerg enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 8424143Sjoerg sig_t oldsig; 8524143Sjoerg int ch, needeof; 8669896Smckusick char *buff; 8769896Smckusick const char *inf; 8824143Sjoerg 8924143Sjoerg msg = stdout; 9069896Smckusick guesslen = 1; 9124143Sjoerg while ((ch = getopt(argc, argv, "cs:vx")) != -1) 9224143Sjoerg switch((char)ch) { 9324143Sjoerg case 'c': 9424143Sjoerg op = COPYVERIFY; 9524143Sjoerg break; 9624143Sjoerg case 's': 9724143Sjoerg maxblk = atoi(optarg); 9827340Speter if (maxblk <= 0) { 9972647Smarkm warnx("illegal block size"); 10024143Sjoerg usage(); 10127340Speter } 10272647Smarkm guesslen = 0; 10324143Sjoerg break; 10427340Speter case 'v': 10572647Smarkm op = VERIFY; 10624143Sjoerg break; 10727340Speter case 'x': 10872647Smarkm msg = stderr; 10924143Sjoerg break; 11024143Sjoerg case '?': 11124143Sjoerg default: 11224143Sjoerg usage(); 11324143Sjoerg } 11424143Sjoerg argc -= optind; 11524143Sjoerg argv += optind; 11624143Sjoerg 11724143Sjoerg switch(argc) { 11865557Sjasone case 0: 11924143Sjoerg if (op != READ) 12024143Sjoerg usage(); 12124143Sjoerg inf = _PATH_DEFTAPE; 12224143Sjoerg break; 12324143Sjoerg case 1: 12424143Sjoerg if (op != READ) 12524143Sjoerg usage(); 12624143Sjoerg inf = argv[0]; 12724143Sjoerg break; 12824143Sjoerg case 2: 12924143Sjoerg if (op == READ) 13024143Sjoerg op = COPY; 13124143Sjoerg inf = argv[0]; 13272951Srwatson if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 13324143Sjoerg op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) 13472951Srwatson err(3, "%s", argv[1]); 13524143Sjoerg break; 13624143Sjoerg default: 13724143Sjoerg usage(); 13824143Sjoerg } 13924143Sjoerg 14024143Sjoerg if ((inp = open(inf, O_RDONLY, 0)) < 0) 14124143Sjoerg err(1, "%s", inf); 14224143Sjoerg 14324143Sjoerg buff = getspace(maxblk); 14465557Sjasone 14524143Sjoerg if (op == VERIFY) { 14624143Sjoerg verify(inp, outp, buff); 14765557Sjasone exit(0); 14824143Sjoerg } 14924143Sjoerg 15024143Sjoerg if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 15124143Sjoerg (void) signal(SIGINT, intr); 15224143Sjoerg 15324143Sjoerg needeof = 0; 15424143Sjoerg for (lastnread = NOCOUNT;;) { 15524143Sjoerg if ((nread = read(inp, buff, maxblk)) == -1) { 15624143Sjoerg while (errno == EINVAL && (maxblk -= 1024)) { 15724143Sjoerg nread = read(inp, buff, maxblk); 15824143Sjoerg if (nread >= 0) 15924143Sjoerg goto r1; 16024143Sjoerg } 16124143Sjoerg err(1, "read error, file %d, record %qu", filen, record); 16224143Sjoerg } else if (nread != lastnread) { 16324143Sjoerg if (lastnread != 0 && lastnread != NOCOUNT) { 16424143Sjoerg if (lastrec == 0 && nread == 0) 16524143Sjoerg fprintf(msg, "%qu records\n", record); 16624143Sjoerg else if (record - lastrec > 1) 16724143Sjoerg fprintf(msg, "records %qu to %qu\n", 16824143Sjoerg lastrec, record); 16924143Sjoerg else 17024143Sjoerg fprintf(msg, "record %qu\n", lastrec); 17124143Sjoerg } 17224143Sjoerg if (nread != 0) 17324143Sjoerg fprintf(msg, "file %d: block size %d: ", 17424143Sjoerg filen, nread); 17524143Sjoerg (void) fflush(stdout); 17624143Sjoerg lastrec = record; 17724143Sjoerg } 17824143Sjoergr1: guesslen = 0; 17924143Sjoerg if (nread > 0) { 18024143Sjoerg if (op == COPY || op == COPYVERIFY) { 18124143Sjoerg if (needeof) { 18224143Sjoerg writeop(outp, MTWEOF); 18324143Sjoerg needeof = 0; 18424143Sjoerg } 18524143Sjoerg nw = write(outp, buff, nread); 18624143Sjoerg if (nw != nread) { 18724143Sjoerg if (nw == -1) { 18824143Sjoerg warn("write error, file %d, record %qu", filen, record); 18924143Sjoerg } else { 19024143Sjoerg warnx("write error, file %d, record %qu", filen, record); 19124143Sjoerg warnx("write (%d) != read (%d)", nw, nread); 19224143Sjoerg } 19338278Swosch errx(5, "copy aborted"); 19438278Swosch } 19538278Swosch } 19638278Swosch size += nread; 19738278Swosch record++; 19838278Swosch } else { 19938278Swosch if (lastnread <= 0 && lastnread != NOCOUNT) { 20024143Sjoerg fprintf(msg, "eot\n"); 20124143Sjoerg break; 20224143Sjoerg } 20324143Sjoerg fprintf(msg, 20424143Sjoerg "file %d: eof after %qu records: %qu bytes\n", 20524143Sjoerg filen, record, size); 20624143Sjoerg needeof = 1; 20727340Speter filen++; 20827390Speter tsize += size; 20924143Sjoerg size = record = lastrec = 0; 21027340Speter lastnread = 0; 21128819Speter } 21228819Speter lastnread = nread; 21327340Speter } 21427340Speter fprintf(msg, "total length: %qu bytes\n", tsize); 21527340Speter (void)signal(SIGINT, oldsig); 21627390Speter if (op == COPY || op == COPYVERIFY) { 21727390Speter writeop(outp, MTWEOF); 21827390Speter writeop(outp, MTWEOF); 21927390Speter if (op == COPYVERIFY) { 22027390Speter rewind_tape(outp); 22127390Speter rewind_tape(inp); 22253281Sdavidn verify(inp, outp, buff); 22353281Sdavidn } 22427390Speter } 22572951Srwatson exit(0); 22624143Sjoerg} 22724143Sjoerg 22872951Srwatsonvoid 22924143Sjoergverify(inp, outp, outb) 23024143Sjoerg register int inp, outp; 23124143Sjoerg register char *outb; 23224143Sjoerg{ 23324143Sjoerg register int eot, inmaxblk, inn, outmaxblk, outn; 23424143Sjoerg register char *inb; 23524143Sjoerg 23624143Sjoerg inb = getspace(maxblk); 23724143Sjoerg inmaxblk = outmaxblk = maxblk; 23824143Sjoerg for (eot = 0;; guesslen = 0) { 23924143Sjoerg if ((inn = read(inp, inb, inmaxblk)) == -1) { 24024143Sjoerg if (guesslen) 24124143Sjoerg while (errno == EINVAL && (inmaxblk -= 1024)) { 24224143Sjoerg inn = read(inp, inb, inmaxblk); 24324143Sjoerg if (inn >= 0) 24424143Sjoerg goto r1; 24524143Sjoerg } 24624143Sjoerg warn("read error"); 24724143Sjoerg break; 24824143Sjoerg } 24924143Sjoergr1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 25024143Sjoerg if (guesslen) 25124143Sjoerg while (errno == EINVAL && (outmaxblk -= 1024)) { 25224143Sjoerg outn = read(outp, outb, outmaxblk); 25324143Sjoerg if (outn >= 0) 25438278Swosch goto r2; 25538278Swosch } 25638278Swosch warn("read error"); 25724143Sjoerg break; 25824143Sjoerg } 25924143Sjoergr2: if (inn != outn) { 26024143Sjoerg fprintf(msg, 26124143Sjoerg "%s: tapes have different block sizes; %d != %d.\n", 26224143Sjoerg "tcopy", inn, outn); 26324143Sjoerg break; 26424143Sjoerg } 26524143Sjoerg if (!inn) { 26624143Sjoerg if (eot++) { 26727390Speter fprintf(msg, "tcopy: tapes are identical.\n"); 26824143Sjoerg return; 26927390Speter } 27027390Speter } else { 27127340Speter if (bcmp(inb, outb, inn)) { 27269375Sjhb fprintf(msg, 27324143Sjoerg "tcopy: tapes have different data.\n"); 27427390Speter break; 27524143Sjoerg } 27624143Sjoerg eot = 0; 27724143Sjoerg } 27824143Sjoerg } 27924143Sjoerg exit(1); 28024143Sjoerg} 28124143Sjoerg 28224143Sjoergvoid 28324143Sjoergintr(signo) 28424143Sjoerg int signo __unused; 28524143Sjoerg{ 28624143Sjoerg if (record) { 28724143Sjoerg if (record - lastrec > 1) 28872951Srwatson fprintf(msg, "records %qu to %qu\n", lastrec, record); 28942447Sobrien else 29042447Sobrien fprintf(msg, "record %qu\n", lastrec); 29142447Sobrien } 29224143Sjoerg fprintf(msg, "interrupt at file %d: record %qu\n", filen, record); 29324143Sjoerg fprintf(msg, "total length: %lld bytes\n", (intmax_t)(tsize + size)); 29472951Srwatson exit(1); 29572951Srwatson} 29672951Srwatson 29724143Sjoergvoid * 29824143Sjoerggetspace(blk) 29924143Sjoerg int blk; 30024143Sjoerg{ 30124143Sjoerg void *bp; 30224143Sjoerg 30324143Sjoerg if ((bp = malloc((size_t)blk)) == NULL) 30424143Sjoerg errx(11, "no memory"); 30524143Sjoerg return (bp); 30624143Sjoerg} 30724143Sjoerg 30824143Sjoergvoid 30924143Sjoergwriteop(fd, type) 31024143Sjoerg int fd, type; 31124143Sjoerg{ 31224143Sjoerg struct mtop op; 31324143Sjoerg 31424143Sjoerg op.mt_op = type; 31524143Sjoerg op.mt_count = (daddr_t)1; 31624143Sjoerg if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 31724143Sjoerg err(6, "tape op"); 31824143Sjoerg} 31924143Sjoerg 32024143Sjoergstatic void 32124143Sjoergusage() 32224143Sjoerg{ 32324143Sjoerg fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n"); 32424143Sjoerg exit(1); 32524143Sjoerg} 32624143Sjoerg 32724143Sjoergvoid 32824143Sjoergrewind_tape(int fd) 32924143Sjoerg{ 33072951Srwatson struct stat sp; 33124143Sjoerg 33272951Srwatson if(fstat(fd, &sp)) 33372951Srwatson errx(12, "fstat in rewind"); 33472951Srwatson 33572951Srwatson /* 33672951Srwatson * don't want to do tape ioctl on regular files: 33772951Srwatson */ 33872951Srwatson if( S_ISREG(sp.st_mode) ) { 33972951Srwatson if( lseek(fd, 0, SEEK_SET) == -1 ) 34024143Sjoerg errx(13, "lseek"); 34124143Sjoerg } else 34224143Sjoerg /* assume its a tape */ 34324143Sjoerg writeop(fd, MTREW); 34424143Sjoerg} 34524143Sjoerg