Home | History | Annotate | Line # | Download | only in tcopy
tcopy.c revision 1.12
      1 /*	$NetBSD: tcopy.c,v 1.12 2003/08/07 11:16:06 agc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1985, 1987, 1993, 1995
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 __COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1993\n\
     35 	The Regents of the University of California.  All rights reserved.\n");
     36 #endif /* not lint */
     37 
     38 #ifndef lint
     39 #if 0
     40 static char sccsid[] = "@(#)tcopy.c	8.3 (Berkeley) 1/23/95";
     41 #endif
     42 __RCSID("$NetBSD: tcopy.c,v 1.12 2003/08/07 11:16:06 agc Exp $");
     43 #endif /* not lint */
     44 
     45 #include <sys/types.h>
     46 #include <sys/stat.h>
     47 #include <sys/ioctl.h>
     48 #include <sys/mtio.h>
     49 
     50 #include <err.h>
     51 #include <errno.h>
     52 #include <paths.h>
     53 #include <fcntl.h>
     54 #include <signal.h>
     55 #include <stdio.h>
     56 #include <stdlib.h>
     57 #include <string.h>
     58 #include <unistd.h>
     59 
     60 #define	MAXREC	(64 * 1024)
     61 #define	NOCOUNT	(-2)
     62 
     63 int	filen, guesslen, maxblk = MAXREC;
     64 long	lastrec, record;
     65 off_t	size, tsize;
     66 FILE	*msg = stdout;
     67 
     68 void	*getspace __P((int));
     69 void	 intr __P((int));
     70 int	 main __P((int, char **));
     71 void	 usage __P((void));
     72 void	 verify __P((int, int, char *));
     73 void	 writeop __P((int, int));
     74 
     75 int
     76 main(argc, argv)
     77 	int argc;
     78 	char *argv[];
     79 {
     80 	int ch, needeof, nw, inp, outp;
     81 	ssize_t lastnread, nread;
     82 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
     83 	sig_t oldsig;
     84 	char *buff, *inf;
     85 
     86 	outp = 0;
     87 	inf = NULL;
     88 	guesslen = 1;
     89 	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
     90 		switch((char)ch) {
     91 		case 'c':
     92 			op = COPYVERIFY;
     93 			break;
     94 		case 's':
     95 			maxblk = atoi(optarg);
     96 			if (maxblk <= 0) {
     97 				warnx("illegal block size");
     98 				usage();
     99 			}
    100 			guesslen = 0;
    101 			break;
    102 		case 'v':
    103 			op = VERIFY;
    104 			break;
    105 		case 'x':
    106 			msg = stderr;
    107 			break;
    108 		case '?':
    109 		default:
    110 			usage();
    111 		}
    112 	argc -= optind;
    113 	argv += optind;
    114 
    115 	switch(argc) {
    116 	case 0:
    117 		if (op != READ)
    118 			usage();
    119 		inf = _PATH_DEFTAPE;
    120 		break;
    121 	case 1:
    122 		if (op != READ)
    123 			usage();
    124 		inf = argv[0];
    125 		break;
    126 	case 2:
    127 		if (op == READ)
    128 			op = COPY;
    129 		inf = argv[0];
    130 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
    131 		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
    132 			err(3, "%s", argv[1]);
    133 		}
    134 		break;
    135 	default:
    136 		usage();
    137 	}
    138 
    139 	if ((inp = open(inf, O_RDONLY, 0)) < 0)
    140 		err(1, "%s", inf);
    141 
    142 	buff = getspace(maxblk);
    143 
    144 	if (op == VERIFY) {
    145 		verify(inp, outp, buff);
    146 		exit(0);
    147 	}
    148 
    149 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
    150 		(void) signal(SIGINT, intr);
    151 
    152 	needeof = 0;
    153 	for (lastnread = NOCOUNT;;) {
    154 		if ((nread = read(inp, buff, maxblk)) == -1) {
    155 			while (errno == EINVAL && (maxblk -= 1024)) {
    156 				nread = read(inp, buff, maxblk);
    157 				if (nread >= 0)
    158 					goto r1;
    159 			}
    160 			err(1, "read error, file %d, record %ld",
    161 			    filen, record);
    162 		} else if (nread != lastnread) {
    163 			if (lastnread != 0 && lastnread != NOCOUNT) {
    164 				if (lastrec == 0 && nread == 0)
    165 					fprintf(msg, "%ld records\n", record);
    166 				else if (record - lastrec > 1)
    167 					fprintf(msg, "records %ld to %ld\n",
    168 					    lastrec, record);
    169 				else
    170 					fprintf(msg, "record %ld\n", lastrec);
    171 			}
    172 			if (nread != 0)
    173 				fprintf(msg, "file %d: block size %ld: ",
    174 				    filen, (long)nread);
    175 			(void) fflush(stdout);
    176 			lastrec = record;
    177 		}
    178 r1:		guesslen = 0;
    179 		if (nread > 0) {
    180 			if (op == COPY || op == COPYVERIFY) {
    181 				if (needeof) {
    182 					writeop(outp, MTWEOF);
    183 					needeof = 0;
    184 				}
    185 				nw = write(outp, buff, nread);
    186 				if (nw != nread) {
    187 				    int error = errno;
    188 				    fprintf(stderr,
    189 					"write error, file %d, record %ld: ",
    190 					filen, record);
    191 				    if (nw == -1)
    192 					fprintf(stderr,
    193 						": %s", strerror(error));
    194 				    else
    195 					fprintf(stderr,
    196 					    "write (%d) != read (%ld)\n",
    197 					    nw, (long)nread);
    198 				    fprintf(stderr, "copy aborted\n");
    199 				    exit(5);
    200 				}
    201 			}
    202 			size += nread;
    203 			record++;
    204 		} else {
    205 			if (lastnread <= 0 && lastnread != NOCOUNT) {
    206 				fprintf(msg, "eot\n");
    207 				break;
    208 			}
    209 			fprintf(msg,
    210 			    "file %d: eof after %ld records: %lld bytes\n",
    211 			    filen, record, (long long)size);
    212 			needeof = 1;
    213 			filen++;
    214 			tsize += size;
    215 			size = record = lastrec = 0;
    216 			lastnread = 0;
    217 		}
    218 		lastnread = nread;
    219 	}
    220 	fprintf(msg, "total length: %lld bytes\n", (long long)tsize);
    221 	(void)signal(SIGINT, oldsig);
    222 	if (op == COPY || op == COPYVERIFY) {
    223 		writeop(outp, MTWEOF);
    224 		writeop(outp, MTWEOF);
    225 		if (op == COPYVERIFY) {
    226 			writeop(outp, MTREW);
    227 			writeop(inp, MTREW);
    228 			verify(inp, outp, buff);
    229 		}
    230 	}
    231 	exit(0);
    232 }
    233 
    234 void
    235 verify(inp, outp, outb)
    236 	int inp, outp;
    237 	char *outb;
    238 {
    239 	int eot, inmaxblk, inn, outmaxblk, outn;
    240 	char *inb;
    241 
    242 	inb = getspace(maxblk);
    243 	inmaxblk = outmaxblk = maxblk;
    244 	for (eot = 0;; guesslen = 0) {
    245 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
    246 			if (guesslen)
    247 				while (errno == EINVAL && (inmaxblk -= 1024)) {
    248 					inn = read(inp, inb, inmaxblk);
    249 					if (inn >= 0)
    250 						goto r1;
    251 				}
    252 			warn("read error");
    253 			break;
    254 		}
    255 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
    256 			if (guesslen)
    257 				while (errno == EINVAL && (outmaxblk -= 1024)) {
    258 					outn = read(outp, outb, outmaxblk);
    259 					if (outn >= 0)
    260 						goto r2;
    261 				}
    262 			warn("read error");
    263 			break;
    264 		}
    265 r2:		if (inn != outn) {
    266 			fprintf(msg,
    267 			    "%s: tapes have different block sizes; %d != %d.\n",
    268 			    "tcopy", inn, outn);
    269 			break;
    270 		}
    271 		if (!inn) {
    272 			if (eot++) {
    273 				fprintf(msg, "%s: tapes are identical.\n",
    274 					"tcopy");
    275 				return;
    276 			}
    277 		} else {
    278 			if (memcmp(inb, outb, inn)) {
    279 				fprintf(msg,
    280 				    "%s: tapes have different data.\n",
    281 					"tcopy");
    282 				break;
    283 			}
    284 			eot = 0;
    285 		}
    286 	}
    287 	exit(1);
    288 }
    289 
    290 void
    291 intr(signo)
    292 	int signo;
    293 {
    294 	if (record) {
    295 		if (record - lastrec > 1)
    296 			fprintf(msg, "records %ld to %ld\n", lastrec, record);
    297 		else
    298 			fprintf(msg, "record %ld\n", lastrec);
    299 	}
    300 	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
    301 	fprintf(msg, "total length: %lld bytes\n", (long long)(tsize + size));
    302 	exit(1);
    303 }
    304 
    305 void *
    306 getspace(blk)
    307 	int blk;
    308 {
    309 	void *bp;
    310 
    311 	if ((bp = malloc((size_t)blk)) == NULL)
    312 		errx(11, "no memory");
    313 
    314 	return (bp);
    315 }
    316 
    317 void
    318 writeop(fd, type)
    319 	int fd, type;
    320 {
    321 	struct mtop op;
    322 
    323 	op.mt_op = type;
    324 	op.mt_count = (daddr_t)1;
    325 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
    326 		err(6, "tape op");
    327 }
    328 
    329 void
    330 usage()
    331 {
    332 
    333 	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
    334 	exit(1);
    335 }
    336