Home | History | Annotate | Line # | Download | only in tcopy
tcopy.c revision 1.5
      1 /*	$NetBSD: tcopy.c,v 1.5 1997/04/15 07:23:08 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 #ifndef lint
     37 static char copyright[] =
     38 "@(#) 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 static char rcsid[] = "$NetBSD: tcopy.c,v 1.5 1997/04/15 07:23:08 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 void	 usage __P((void));
     76 void	 verify __P((int, int, char *));
     77 void	 writeop __P((int, int));
     78 
     79 int
     80 main(argc, argv)
     81 	int argc;
     82 	char *argv[];
     83 {
     84 	int ch, needeof, nw, inp, outp;
     85 	ssize_t lastnread, nread;
     86 	enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
     87 	sig_t oldsig;
     88 	char *buff, *inf;
     89 
     90 	guesslen = 1;
     91 	while ((ch = getopt(argc, argv, "cs:vx")) != EOF)
     92 		switch((char)ch) {
     93 		case 'c':
     94 			op = COPYVERIFY;
     95 			break;
     96 		case 's':
     97 			maxblk = atoi(optarg);
     98 			if (maxblk <= 0) {
     99 				warnx("illegal block size");
    100 				usage();
    101 			}
    102 			guesslen = 0;
    103 			break;
    104 		case 'v':
    105 			op = VERIFY;
    106 			break;
    107 		case 'x':
    108 			msg = stderr;
    109 			break;
    110 		case '?':
    111 		default:
    112 			usage();
    113 		}
    114 	argc -= optind;
    115 	argv += optind;
    116 
    117 	switch(argc) {
    118 	case 0:
    119 		if (op != READ)
    120 			usage();
    121 		inf = _PATH_DEFTAPE;
    122 		break;
    123 	case 1:
    124 		if (op != READ)
    125 			usage();
    126 		inf = argv[0];
    127 		break;
    128 	case 2:
    129 		if (op == READ)
    130 			op = COPY;
    131 		inf = argv[0];
    132 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
    133 		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
    134 			err(3, argv[1]);
    135 		}
    136 		break;
    137 	default:
    138 		usage();
    139 	}
    140 
    141 	if ((inp = open(inf, O_RDONLY, 0)) < 0)
    142 		err(1, inf);
    143 
    144 	buff = getspace(maxblk);
    145 
    146 	if (op == VERIFY) {
    147 		verify(inp, outp, buff);
    148 		exit(0);
    149 	}
    150 
    151 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
    152 		(void) signal(SIGINT, intr);
    153 
    154 	needeof = 0;
    155 	for (lastnread = NOCOUNT;;) {
    156 		if ((nread = read(inp, buff, maxblk)) == -1) {
    157 			while (errno == EINVAL && (maxblk -= 1024)) {
    158 				nread = read(inp, buff, maxblk);
    159 				if (nread >= 0)
    160 					goto r1;
    161 			}
    162 			err(1, "read error, file %d, record %ld",
    163 			    filen, record);
    164 		} else if (nread != lastnread) {
    165 			if (lastnread != 0 && lastnread != NOCOUNT) {
    166 				if (lastrec == 0 && nread == 0)
    167 					fprintf(msg, "%ld records\n", record);
    168 				else if (record - lastrec > 1)
    169 					fprintf(msg, "records %ld to %ld\n",
    170 					    lastrec, record);
    171 				else
    172 					fprintf(msg, "record %ld\n", lastrec);
    173 			}
    174 			if (nread != 0)
    175 				fprintf(msg, "file %d: block size %d: ",
    176 				    filen, nread);
    177 			(void) fflush(stdout);
    178 			lastrec = record;
    179 		}
    180 r1:		guesslen = 0;
    181 		if (nread > 0) {
    182 			if (op == COPY || op == COPYVERIFY) {
    183 				if (needeof) {
    184 					writeop(outp, MTWEOF);
    185 					needeof = 0;
    186 				}
    187 				nw = write(outp, buff, nread);
    188 				if (nw != nread) {
    189 				    int error = errno;
    190 				    fprintf(stderr,
    191 					"write error, file %d, record %ld: ",
    192 					filen, record);
    193 				    if (nw == -1)
    194 					fprintf(stderr,
    195 						": %s", strerror(error));
    196 				    else
    197 					fprintf(stderr,
    198 					    "write (%d) != read (%d)\n",
    199 					    nw, nread);
    200 				    fprintf(stderr, "copy aborted\n");
    201 				    exit(5);
    202 				}
    203 			}
    204 			size += nread;
    205 			record++;
    206 		} else {
    207 			if (lastnread <= 0 && lastnread != NOCOUNT) {
    208 				fprintf(msg, "eot\n");
    209 				break;
    210 			}
    211 			fprintf(msg,
    212 			    "file %d: eof after %ld records: %qd bytes\n",
    213 			    filen, record, size);
    214 			needeof = 1;
    215 			filen++;
    216 			tsize += size;
    217 			size = record = lastrec = 0;
    218 			lastnread = 0;
    219 		}
    220 		lastnread = nread;
    221 	}
    222 	fprintf(msg, "total length: %qd bytes\n", tsize);
    223 	(void)signal(SIGINT, oldsig);
    224 	if (op == COPY || op == COPYVERIFY) {
    225 		writeop(outp, MTWEOF);
    226 		writeop(outp, MTWEOF);
    227 		if (op == COPYVERIFY) {
    228 			writeop(outp, MTREW);
    229 			writeop(inp, MTREW);
    230 			verify(inp, outp, buff);
    231 		}
    232 	}
    233 	exit(0);
    234 }
    235 
    236 void
    237 verify(inp, outp, outb)
    238 	int inp, outp;
    239 	char *outb;
    240 {
    241 	int eot, inmaxblk, inn, outmaxblk, outn;
    242 	char *inb;
    243 
    244 	inb = getspace(maxblk);
    245 	inmaxblk = outmaxblk = maxblk;
    246 	for (eot = 0;; guesslen = 0) {
    247 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
    248 			if (guesslen)
    249 				while (errno == EINVAL && (inmaxblk -= 1024)) {
    250 					inn = read(inp, inb, inmaxblk);
    251 					if (inn >= 0)
    252 						goto r1;
    253 				}
    254 			warn("read error");
    255 			break;
    256 		}
    257 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
    258 			if (guesslen)
    259 				while (errno == EINVAL && (outmaxblk -= 1024)) {
    260 					outn = read(outp, outb, outmaxblk);
    261 					if (outn >= 0)
    262 						goto r2;
    263 				}
    264 			warn("read error");
    265 			break;
    266 		}
    267 r2:		if (inn != outn) {
    268 			fprintf(msg,
    269 			    "%s: tapes have different block sizes; %d != %d.\n",
    270 			    "tcopy", inn, outn);
    271 			break;
    272 		}
    273 		if (!inn) {
    274 			if (eot++) {
    275 				fprintf(msg, "%s: tapes are identical.\n",
    276 					"tcopy");
    277 				return;
    278 			}
    279 		} else {
    280 			if (bcmp(inb, outb, inn)) {
    281 				fprintf(msg,
    282 				    "%s: tapes have different data.\n",
    283 					"tcopy");
    284 				break;
    285 			}
    286 			eot = 0;
    287 		}
    288 	}
    289 	exit(1);
    290 }
    291 
    292 void
    293 intr(signo)
    294 	int signo;
    295 {
    296 	if (record)
    297 		if (record - lastrec > 1)
    298 			fprintf(msg, "records %ld to %ld\n", lastrec, record);
    299 		else
    300 			fprintf(msg, "record %ld\n", lastrec);
    301 	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
    302 	fprintf(msg, "total length: %qd bytes\n", tsize + size);
    303 	exit(1);
    304 }
    305 
    306 void *
    307 getspace(blk)
    308 	int blk;
    309 {
    310 	void *bp;
    311 
    312 	if ((bp = malloc((size_t)blk)) == NULL)
    313 		errx(11, "no memory");
    314 
    315 	return (bp);
    316 }
    317 
    318 void
    319 writeop(fd, type)
    320 	int fd, type;
    321 {
    322 	struct mtop op;
    323 
    324 	op.mt_op = type;
    325 	op.mt_count = (daddr_t)1;
    326 	if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
    327 		err(6, "tape op");
    328 }
    329 
    330 void
    331 usage()
    332 {
    333 
    334 	fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
    335 	exit(1);
    336 }
    337