1 /* $NetBSD: tcopy.c,v 1.3 1994/12/09 02:14:39 jtc Exp $ */ 2 3 /* 4 * Copyright (c) 1985, 1987, 1993 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.2 (Berkeley) 4/17/94"; 45 #endif 46 static char rcsid[] = "$NetBSD: tcopy.c,v 1.3 1994/12/09 02:14:39 jtc 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 <errno.h> 55 #include <fcntl.h> 56 #include <signal.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #include "pathnames.h" 63 64 #define MAXREC (64 * 1024) 65 #define NOCOUNT (-2) 66 67 int filen, guesslen, maxblk = MAXREC; 68 long lastrec, record, size, tsize; 69 FILE *msg = stdout; 70 71 void *getspace __P((int)); 72 void intr __P((int)); 73 void usage __P((void)); 74 void verify __P((int, int, char *)); 75 void writeop __P((int, int)); 76 77 int 78 main(argc, argv) 79 int argc; 80 char *argv[]; 81 { 82 register int lastnread, nread, nw, inp, outp; 83 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 84 sig_t oldsig; 85 int ch, needeof; 86 char *buff, *inf; 87 88 guesslen = 1; 89 while ((ch = getopt(argc, argv, "cs:vx")) != EOF) 90 switch((char)ch) { 91 case 'c': 92 op = COPYVERIFY; 93 break; 94 case 's': 95 maxblk = atoi(optarg); 96 if (maxblk <= 0) { 97 fprintf(stderr, "tcopy: illegal block size\n"); 98 usage(); 99 } 100 guesslen = 0; 101 break; 102 case 'v': 103 op = VERIFY; 104 break; 105 case 'x': 106 msg = stderr; 107 break; 108 case '?': 109 default: 110 usage(); 111 } 112 argc -= optind; 113 argv += optind; 114 115 switch(argc) { 116 case 0: 117 if (op != READ) 118 usage(); 119 inf = _PATH_DEFTAPE; 120 break; 121 case 1: 122 if (op != READ) 123 usage(); 124 inf = argv[0]; 125 break; 126 case 2: 127 if (op == READ) 128 op = COPY; 129 inf = argv[0]; 130 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 131 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) { 132 perror(argv[1]); 133 exit(3); 134 } 135 break; 136 default: 137 usage(); 138 } 139 140 if ((inp = open(inf, O_RDONLY, 0)) < 0) { 141 perror(inf); 142 exit(1); 143 } 144 145 buff = getspace(maxblk); 146 147 if (op == VERIFY) { 148 verify(inp, outp, buff); 149 exit(0); 150 } 151 152 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 153 (void) signal(SIGINT, intr); 154 155 needeof = 0; 156 for (lastnread = NOCOUNT;;) { 157 if ((nread = read(inp, buff, maxblk)) == -1) { 158 while (errno == EINVAL && (maxblk -= 1024)) { 159 nread = read(inp, buff, maxblk); 160 if (nread >= 0) 161 goto r1; 162 } 163 fprintf(stderr, "read error, file %d, record %ld: ", 164 filen, record); 165 perror(""); 166 exit(1); 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 fprintf(stderr, 193 "write error, file %d, record %ld: ", 194 filen, record); 195 if (nw == -1) 196 perror(""); 197 else 198 fprintf(stderr, 199 "write (%d) != read (%d)\n", 200 nw, nread); 201 fprintf(stderr, "copy aborted\n"); 202 exit(5); 203 } 204 } 205 size += nread; 206 record++; 207 } else { 208 if (lastnread <= 0 && lastnread != NOCOUNT) { 209 fprintf(msg, "eot\n"); 210 break; 211 } 212 fprintf(msg, 213 "file %d: eof after %ld records: %ld bytes\n", 214 filen, record, size); 215 needeof = 1; 216 filen++; 217 tsize += size; 218 size = record = lastrec = 0; 219 lastnread = 0; 220 } 221 lastnread = nread; 222 } 223 fprintf(msg, "total length: %ld bytes\n", tsize); 224 (void)signal(SIGINT, oldsig); 225 if (op == COPY || op == COPYVERIFY) { 226 writeop(outp, MTWEOF); 227 writeop(outp, MTWEOF); 228 if (op == COPYVERIFY) { 229 writeop(outp, MTREW); 230 writeop(inp, MTREW); 231 verify(inp, outp, buff); 232 } 233 } 234 exit(0); 235 } 236 237 void 238 verify(inp, outp, outb) 239 register int inp, outp; 240 register char *outb; 241 { 242 register int eot, inmaxblk, inn, outmaxblk, outn; 243 register char *inb; 244 245 inb = getspace(maxblk); 246 inmaxblk = outmaxblk = maxblk; 247 for (eot = 0;; guesslen = 0) { 248 if ((inn = read(inp, inb, inmaxblk)) == -1) { 249 if (guesslen) 250 while (errno == EINVAL && (inmaxblk -= 1024)) { 251 inn = read(inp, inb, inmaxblk); 252 if (inn >= 0) 253 goto r1; 254 } 255 perror("tcopy: read error"); 256 break; 257 } 258 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 259 if (guesslen) 260 while (errno == EINVAL && (outmaxblk -= 1024)) { 261 outn = read(outp, outb, outmaxblk); 262 if (outn >= 0) 263 goto r2; 264 } 265 perror("tcopy: read error"); 266 break; 267 } 268 r2: if (inn != outn) { 269 fprintf(msg, 270 "%s: tapes have different block sizes; %d != %d.\n", 271 "tcopy", inn, outn); 272 break; 273 } 274 if (!inn) { 275 if (eot++) { 276 fprintf(msg, "tcopy: tapes are identical.\n"); 277 return; 278 } 279 } else { 280 if (bcmp(inb, outb, inn)) { 281 fprintf(msg, 282 "tcopy: tapes have different data.\n"); 283 break; 284 } 285 eot = 0; 286 } 287 } 288 exit(1); 289 } 290 291 void 292 intr(signo) 293 int signo; 294 { 295 if (record) 296 if (record - lastrec > 1) 297 fprintf(msg, "records %ld to %ld\n", lastrec, record); 298 else 299 fprintf(msg, "record %ld\n", lastrec); 300 fprintf(msg, "interrupt at file %d: record %ld\n", filen, record); 301 fprintf(msg, "total length: %ld bytes\n", tsize + size); 302 exit(1); 303 } 304 305 void * 306 getspace(blk) 307 int blk; 308 { 309 void *bp; 310 311 if ((bp = malloc((size_t)blk)) == NULL) { 312 fprintf(stderr, "tcopy: no memory\n"); 313 exit(11); 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 perror("tcopy: tape op"); 328 exit(6); 329 } 330 } 331 332 void 333 usage() 334 { 335 fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n"); 336 exit(1); 337 } 338