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