Home | History | Annotate | Line # | Download | only in tcopy
tcopy.c revision 1.10
      1 /*	$NetBSD: tcopy.c,v 1.10 2000/07/07 15:13:25 itojun 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.10 2000/07/07 15:13:25 itojun 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 #define	MAXREC	(64 * 1024)
     65 #define	NOCOUNT	(-2)
     66 
     67 int	filen, guesslen, maxblk = MAXREC;
     68 long	lastrec, record;
     69 off_t	size, tsize;
     70 FILE	*msg = stdout;
     71 
     72 void	*getspace __P((int));
     73 void	 intr __P((int));
     74 int	 main __P((int, char **));
     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 	outp = 0;
     91 	inf = NULL;
     92 	guesslen = 1;
     93 	while ((ch = getopt(argc, argv, "cs:vx")) != -1)
     94 		switch((char)ch) {
     95 		case 'c':
     96 			op = COPYVERIFY;
     97 			break;
     98 		case 's':
     99 			maxblk = atoi(optarg);
    100 			if (maxblk <= 0) {
    101 				warnx("illegal block size");
    102 				usage();
    103 			}
    104 			guesslen = 0;
    105 			break;
    106 		case 'v':
    107 			op = VERIFY;
    108 			break;
    109 		case 'x':
    110 			msg = stderr;
    111 			break;
    112 		case '?':
    113 		default:
    114 			usage();
    115 		}
    116 	argc -= optind;
    117 	argv += optind;
    118 
    119 	switch(argc) {
    120 	case 0:
    121 		if (op != READ)
    122 			usage();
    123 		inf = _PATH_DEFTAPE;
    124 		break;
    125 	case 1:
    126 		if (op != READ)
    127 			usage();
    128 		inf = argv[0];
    129 		break;
    130 	case 2:
    131 		if (op == READ)
    132 			op = COPY;
    133 		inf = argv[0];
    134 		if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
    135 		    op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
    136 			err(3, "%s", argv[1]);
    137 		}
    138 		break;
    139 	default:
    140 		usage();
    141 	}
    142 
    143 	if ((inp = open(inf, O_RDONLY, 0)) < 0)
    144 		err(1, "%s", inf);
    145 
    146 	buff = getspace(maxblk);
    147 
    148 	if (op == VERIFY) {
    149 		verify(inp, outp, buff);
    150 		exit(0);
    151 	}
    152 
    153 	if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
    154 		(void) signal(SIGINT, intr);
    155 
    156 	needeof = 0;
    157 	for (lastnread = NOCOUNT;;) {
    158 		if ((nread = read(inp, buff, maxblk)) == -1) {
    159 			while (errno == EINVAL && (maxblk -= 1024)) {
    160 				nread = read(inp, buff, maxblk);
    161 				if (nread >= 0)
    162 					goto r1;
    163 			}
    164 			err(1, "read error, file %d, record %ld",
    165 			    filen, record);
    166 		} else if (nread != lastnread) {
    167 			if (lastnread != 0 && lastnread != NOCOUNT) {
    168 				if (lastrec == 0 && nread == 0)
    169 					fprintf(msg, "%ld records\n", record);
    170 				else if (record - lastrec > 1)
    171 					fprintf(msg, "records %ld to %ld\n",
    172 					    lastrec, record);
    173 				else
    174 					fprintf(msg, "record %ld\n", lastrec);
    175 			}
    176 			if (nread != 0)
    177 				fprintf(msg, "file %d: block size %ld: ",
    178 				    filen, (long)nread);
    179 			(void) fflush(stdout);
    180 			lastrec = record;
    181 		}
    182 r1:		guesslen = 0;
    183 		if (nread > 0) {
    184 			if (op == COPY || op == COPYVERIFY) {
    185 				if (needeof) {
    186 					writeop(outp, MTWEOF);
    187 					needeof = 0;
    188 				}
    189 				nw = write(outp, buff, nread);
    190 				if (nw != nread) {
    191 				    int error = errno;
    192 				    fprintf(stderr,
    193 					"write error, file %d, record %ld: ",
    194 					filen, record);
    195 				    if (nw == -1)
    196 					fprintf(stderr,
    197 						": %s", strerror(error));
    198 				    else
    199 					fprintf(stderr,
    200 					    "write (%d) != read (%ld)\n",
    201 					    nw, (long)nread);
    202 				    fprintf(stderr, "copy aborted\n");
    203 				    exit(5);
    204 				}
    205 			}
    206 			size += nread;
    207 			record++;
    208 		} else {
    209 			if (lastnread <= 0 && lastnread != NOCOUNT) {
    210 				fprintf(msg, "eot\n");
    211 				break;
    212 			}
    213 			fprintf(msg,
    214 			    "file %d: eof after %ld records: %qd bytes\n",
    215 			    filen, record, (long long)size);
    216 			needeof = 1;
    217 			filen++;
    218 			tsize += size;
    219 			size = record = lastrec = 0;
    220 			lastnread = 0;
    221 		}
    222 		lastnread = nread;
    223 	}
    224 	fprintf(msg, "total length: %qd bytes\n", (long long)tsize);
    225 	(void)signal(SIGINT, oldsig);
    226 	if (op == COPY || op == COPYVERIFY) {
    227 		writeop(outp, MTWEOF);
    228 		writeop(outp, MTWEOF);
    229 		if (op == COPYVERIFY) {
    230 			writeop(outp, MTREW);
    231 			writeop(inp, MTREW);
    232 			verify(inp, outp, buff);
    233 		}
    234 	}
    235 	exit(0);
    236 }
    237 
    238 void
    239 verify(inp, outp, outb)
    240 	int inp, outp;
    241 	char *outb;
    242 {
    243 	int eot, inmaxblk, inn, outmaxblk, outn;
    244 	char *inb;
    245 
    246 	inb = getspace(maxblk);
    247 	inmaxblk = outmaxblk = maxblk;
    248 	for (eot = 0;; guesslen = 0) {
    249 		if ((inn = read(inp, inb, inmaxblk)) == -1) {
    250 			if (guesslen)
    251 				while (errno == EINVAL && (inmaxblk -= 1024)) {
    252 					inn = read(inp, inb, inmaxblk);
    253 					if (inn >= 0)
    254 						goto r1;
    255 				}
    256 			warn("read error");
    257 			break;
    258 		}
    259 r1:		if ((outn = read(outp, outb, outmaxblk)) == -1) {
    260 			if (guesslen)
    261 				while (errno == EINVAL && (outmaxblk -= 1024)) {
    262 					outn = read(outp, outb, outmaxblk);
    263 					if (outn >= 0)
    264 						goto r2;
    265 				}
    266 			warn("read error");
    267 			break;
    268 		}
    269 r2:		if (inn != outn) {
    270 			fprintf(msg,
    271 			    "%s: tapes have different block sizes; %d != %d.\n",
    272 			    "tcopy", inn, outn);
    273 			break;
    274 		}
    275 		if (!inn) {
    276 			if (eot++) {
    277 				fprintf(msg, "%s: tapes are identical.\n",
    278 					"tcopy");
    279 				return;
    280 			}
    281 		} else {
    282 			if (memcmp(inb, outb, inn)) {
    283 				fprintf(msg,
    284 				    "%s: tapes have different data.\n",
    285 					"tcopy");
    286 				break;
    287 			}
    288 			eot = 0;
    289 		}
    290 	}
    291 	exit(1);
    292 }
    293 
    294 void
    295 intr(signo)
    296 	int signo;
    297 {
    298 	if (record) {
    299 		if (record - lastrec > 1)
    300 			fprintf(msg, "records %ld to %ld\n", lastrec, record);
    301 		else
    302 			fprintf(msg, "record %ld\n", lastrec);
    303 	}
    304 	fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
    305 	fprintf(msg, "total length: %qd bytes\n", (long long)(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