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