1 /* 2 * Copyright (c) 1985, 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 36 __FBSDID("$FreeBSD$"); 37 38 #ifndef lint 39 static const char copyright[] = 40 "@(#) Copyright (c) 1985, 1987, 1993\n\ 41 The Regents of the University of California. All rights reserved.\n"; 42 #endif 43 44 #ifndef lint 45 static const char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94"; 46 #endif 47 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <sys/ioctl.h> 51 #include <sys/mtio.h> 52 53 #include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <paths.h> 57 #include <signal.h> 58 #include <stdint.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 u_int64_t lastrec, record, size, tsize; 69 FILE *msg; 70 71 void *getspace(int); 72 void intr(int); 73 static void usage(void); 74 void verify(int, int, char *); 75 void writeop(int, int); 76 void rewind_tape(int); 77 78 int 79 main(argc, argv) 80 int argc; 81 char *argv[]; 82 { 83 register int lastnread, nread, nw, inp, outp; 84 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 85 sig_t oldsig; 86 int ch, needeof; 87 char *buff; 88 const char *inf; 89 90 msg = stdout; 91 guesslen = 1; 92 while ((ch = getopt(argc, argv, "cs:vx")) != -1) 93 switch((char)ch) { 94 case 'c': 95 op = COPYVERIFY; 96 break; 97 case 's': 98 maxblk = atoi(optarg); 99 if (maxblk <= 0) { 100 warnx("illegal block size"); 101 usage(); 102 } 103 guesslen = 0; 104 break; 105 case 'v': 106 op = VERIFY; 107 break; 108 case 'x': 109 msg = stderr; 110 break; 111 case '?': 112 default: 113 usage(); 114 } 115 argc -= optind; 116 argv += optind; 117 118 switch(argc) { 119 case 0: 120 if (op != READ) 121 usage(); 122 inf = _PATH_DEFTAPE; 123 break; 124 case 1: 125 if (op != READ) 126 usage(); 127 inf = argv[0]; 128 break; 129 case 2: 130 if (op == READ) 131 op = COPY; 132 inf = argv[0]; 133 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 134 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) 135 err(3, "%s", argv[1]); 136 break; 137 default: 138 usage(); 139 } 140 141 if ((inp = open(inf, O_RDONLY, 0)) < 0) 142 err(1, "%s", 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 %qu", filen, record); 163 } else if (nread != lastnread) { 164 if (lastnread != 0 && lastnread != NOCOUNT) { 165 if (lastrec == 0 && nread == 0) 166 fprintf(msg, "%qu records\n", record); 167 else if (record - lastrec > 1) 168 fprintf(msg, "records %qu to %qu\n", 169 lastrec, record); 170 else 171 fprintf(msg, "record %qu\n", lastrec); 172 } 173 if (nread != 0) 174 fprintf(msg, "file %d: block size %d: ", 175 filen, 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 if (nw == -1) { 189 warn("write error, file %d, record %qu", filen, record); 190 } else { 191 warnx("write error, file %d, record %qu", filen, record); 192 warnx("write (%d) != read (%d)", nw, nread); 193 } 194 errx(5, "copy aborted"); 195 } 196 } 197 size += nread; 198 record++; 199 } else { 200 if (lastnread <= 0 && lastnread != NOCOUNT) { 201 fprintf(msg, "eot\n"); 202 break; 203 } 204 fprintf(msg, 205 "file %d: eof after %qu records: %qu bytes\n", 206 filen, record, size); 207 needeof = 1; 208 filen++; 209 tsize += size; 210 size = record = lastrec = 0; 211 lastnread = 0; 212 } 213 lastnread = nread; 214 } 215 fprintf(msg, "total length: %qu bytes\n", tsize); 216 (void)signal(SIGINT, oldsig); 217 if (op == COPY || op == COPYVERIFY) { 218 writeop(outp, MTWEOF); 219 writeop(outp, MTWEOF); 220 if (op == COPYVERIFY) { 221 rewind_tape(outp); 222 rewind_tape(inp); 223 verify(inp, outp, buff); 224 } 225 } 226 exit(0); 227 } 228 229 void 230 verify(inp, outp, outb) 231 register int inp, outp; 232 register char *outb; 233 { 234 register int eot, inmaxblk, inn, outmaxblk, outn; 235 register char *inb; 236 237 inb = getspace(maxblk); 238 inmaxblk = outmaxblk = maxblk; 239 for (eot = 0;; guesslen = 0) { 240 if ((inn = read(inp, inb, inmaxblk)) == -1) { 241 if (guesslen) 242 while (errno == EINVAL && (inmaxblk -= 1024)) { 243 inn = read(inp, inb, inmaxblk); 244 if (inn >= 0) 245 goto r1; 246 } 247 warn("read error"); 248 break; 249 } 250 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 251 if (guesslen) 252 while (errno == EINVAL && (outmaxblk -= 1024)) { 253 outn = read(outp, outb, outmaxblk); 254 if (outn >= 0) 255 goto r2; 256 } 257 warn("read error"); 258 break; 259 } 260 r2: if (inn != outn) { 261 fprintf(msg, 262 "%s: tapes have different block sizes; %d != %d.\n", 263 "tcopy", inn, outn); 264 break; 265 } 266 if (!inn) { 267 if (eot++) { 268 fprintf(msg, "tcopy: tapes are identical.\n"); 269 return; 270 } 271 } else { 272 if (bcmp(inb, outb, inn)) { 273 fprintf(msg, 274 "tcopy: tapes have different data.\n"); 275 break; 276 } 277 eot = 0; 278 } 279 } 280 exit(1); 281 } 282 283 void 284 intr(signo) 285 int signo __unused; 286 { 287 if (record) { 288 if (record - lastrec > 1) 289 fprintf(msg, "records %qu to %qu\n", lastrec, record); 290 else 291 fprintf(msg, "record %qu\n", lastrec); 292 } 293 fprintf(msg, "interrupt at file %d: record %qu\n", filen, record); 294 fprintf(msg, "total length: %ju bytes\n", (uintmax_t)(tsize + size)); 295 exit(1); 296 } 297 298 void * 299 getspace(blk) 300 int blk; 301 { 302 void *bp; 303 304 if ((bp = malloc((size_t)blk)) == NULL) 305 errx(11, "no memory"); 306 return (bp); 307 } 308 309 void 310 writeop(fd, type) 311 int fd, type; 312 { 313 struct mtop op; 314 315 op.mt_op = type; 316 op.mt_count = (daddr_t)1; 317 if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 318 err(6, "tape op"); 319 } 320 321 static void 322 usage() 323 { 324 fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n"); 325 exit(1); 326 } 327 328 void 329 rewind_tape(int fd) 330 { 331 struct stat sp; 332 333 if(fstat(fd, &sp)) 334 errx(12, "fstat in rewind"); 335 336 /* 337 * don't want to do tape ioctl on regular files: 338 */ 339 if( S_ISREG(sp.st_mode) ) { 340 if( lseek(fd, 0, SEEK_SET) == -1 ) 341 errx(13, "lseek"); 342 } else 343 /* assume its a tape */ 344 writeop(fd, MTREW); 345 } 346