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