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 * @(#) Copyright (c) 1985, 1987, 1993 The Regents of the University of California. All rights reserved. 34 * @(#)tcopy.c 8.2 (Berkeley) 4/17/94 35 * $FreeBSD: src/usr.bin/tcopy/tcopy.c,v 1.7.2.1 2002/11/07 17:54:42 imp Exp $ 36 * $DragonFly: src/usr.bin/tcopy/tcopy.c,v 1.2 2003/06/17 04:29:32 dillon Exp $ 37 */ 38 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <sys/ioctl.h> 42 #include <sys/mtio.h> 43 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <signal.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "pathnames.h" 54 55 #define MAXREC (64 * 1024) 56 #define NOCOUNT (-2) 57 58 int filen, guesslen, maxblk = MAXREC; 59 u_int64_t lastrec, record, size, tsize; 60 FILE *msg; 61 62 void *getspace __P((int)); 63 void intr __P((int)); 64 static void usage __P((void)); 65 void verify __P((int, int, char *)); 66 void writeop __P((int, int)); 67 void rewind_tape(int); 68 69 int 70 main(argc, argv) 71 int argc; 72 char *argv[]; 73 { 74 register int lastnread, nread, nw, inp, outp; 75 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 76 sig_t oldsig; 77 int ch, needeof; 78 char *buff, *inf; 79 80 msg = stdout; 81 guesslen = 1; 82 while ((ch = getopt(argc, argv, "cs:vx")) != -1) 83 switch((char)ch) { 84 case 'c': 85 op = COPYVERIFY; 86 break; 87 case 's': 88 maxblk = atoi(optarg); 89 if (maxblk <= 0) { 90 warnx("illegal block size"); 91 usage(); 92 } 93 guesslen = 0; 94 break; 95 case 'v': 96 op = VERIFY; 97 break; 98 case 'x': 99 msg = stderr; 100 break; 101 case '?': 102 default: 103 usage(); 104 } 105 argc -= optind; 106 argv += optind; 107 108 switch(argc) { 109 case 0: 110 if (op != READ) 111 usage(); 112 inf = _PATH_DEFTAPE; 113 break; 114 case 1: 115 if (op != READ) 116 usage(); 117 inf = argv[0]; 118 break; 119 case 2: 120 if (op == READ) 121 op = COPY; 122 inf = argv[0]; 123 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 124 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) 125 err(3, "%s", argv[1]); 126 break; 127 default: 128 usage(); 129 } 130 131 if ((inp = open(inf, O_RDONLY, 0)) < 0) 132 err(1, "%s", inf); 133 134 buff = getspace(maxblk); 135 136 if (op == VERIFY) { 137 verify(inp, outp, buff); 138 exit(0); 139 } 140 141 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 142 (void) signal(SIGINT, intr); 143 144 needeof = 0; 145 for (lastnread = NOCOUNT;;) { 146 if ((nread = read(inp, buff, maxblk)) == -1) { 147 while (errno == EINVAL && (maxblk -= 1024)) { 148 nread = read(inp, buff, maxblk); 149 if (nread >= 0) 150 goto r1; 151 } 152 err(1, "read error, file %d, record %qu", filen, record); 153 } else if (nread != lastnread) { 154 if (lastnread != 0 && lastnread != NOCOUNT) { 155 if (lastrec == 0 && nread == 0) 156 fprintf(msg, "%qu records\n", record); 157 else if (record - lastrec > 1) 158 fprintf(msg, "records %qu to %qu\n", 159 lastrec, record); 160 else 161 fprintf(msg, "record %qu\n", lastrec); 162 } 163 if (nread != 0) 164 fprintf(msg, "file %d: block size %d: ", 165 filen, nread); 166 (void) fflush(stdout); 167 lastrec = record; 168 } 169 r1: guesslen = 0; 170 if (nread > 0) { 171 if (op == COPY || op == COPYVERIFY) { 172 if (needeof) { 173 writeop(outp, MTWEOF); 174 needeof = 0; 175 } 176 nw = write(outp, buff, nread); 177 if (nw != nread) { 178 if (nw == -1) { 179 warn("write error, file %d, record %qu", filen, record); 180 } else { 181 warnx("write error, file %d, record %qu", filen, record); 182 warnx("write (%d) != read (%d)", nw, nread); 183 } 184 errx(5, "copy aborted"); 185 } 186 } 187 size += nread; 188 record++; 189 } else { 190 if (lastnread <= 0 && lastnread != NOCOUNT) { 191 fprintf(msg, "eot\n"); 192 break; 193 } 194 fprintf(msg, 195 "file %d: eof after %qu records: %qu bytes\n", 196 filen, record, size); 197 needeof = 1; 198 filen++; 199 tsize += size; 200 size = record = lastrec = 0; 201 lastnread = 0; 202 } 203 lastnread = nread; 204 } 205 fprintf(msg, "total length: %qu bytes\n", tsize); 206 (void)signal(SIGINT, oldsig); 207 if (op == COPY || op == COPYVERIFY) { 208 writeop(outp, MTWEOF); 209 writeop(outp, MTWEOF); 210 if (op == COPYVERIFY) { 211 rewind_tape(outp); 212 rewind_tape(inp); 213 verify(inp, outp, buff); 214 } 215 } 216 exit(0); 217 } 218 219 void 220 verify(inp, outp, outb) 221 register int inp, outp; 222 register char *outb; 223 { 224 register int eot, inmaxblk, inn, outmaxblk, outn; 225 register char *inb; 226 227 inb = getspace(maxblk); 228 inmaxblk = outmaxblk = maxblk; 229 for (eot = 0;; guesslen = 0) { 230 if ((inn = read(inp, inb, inmaxblk)) == -1) { 231 if (guesslen) 232 while (errno == EINVAL && (inmaxblk -= 1024)) { 233 inn = read(inp, inb, inmaxblk); 234 if (inn >= 0) 235 goto r1; 236 } 237 warn("read error"); 238 break; 239 } 240 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 241 if (guesslen) 242 while (errno == EINVAL && (outmaxblk -= 1024)) { 243 outn = read(outp, outb, outmaxblk); 244 if (outn >= 0) 245 goto r2; 246 } 247 warn("read error"); 248 break; 249 } 250 r2: if (inn != outn) { 251 fprintf(msg, 252 "%s: tapes have different block sizes; %d != %d.\n", 253 "tcopy", inn, outn); 254 break; 255 } 256 if (!inn) { 257 if (eot++) { 258 fprintf(msg, "tcopy: tapes are identical.\n"); 259 return; 260 } 261 } else { 262 if (bcmp(inb, outb, inn)) { 263 fprintf(msg, 264 "tcopy: tapes have different data.\n"); 265 break; 266 } 267 eot = 0; 268 } 269 } 270 exit(1); 271 } 272 273 void 274 intr(signo) 275 int signo; 276 { 277 if (record) { 278 if (record - lastrec > 1) 279 fprintf(msg, "records %qu to %qu\n", lastrec, record); 280 else 281 fprintf(msg, "record %qu\n", lastrec); 282 } 283 fprintf(msg, "interrupt at file %d: record %qu\n", filen, record); 284 fprintf(msg, "total length: %ld bytes\n", tsize + size); 285 exit(1); 286 } 287 288 void * 289 getspace(blk) 290 int blk; 291 { 292 void *bp; 293 294 if ((bp = malloc((size_t)blk)) == NULL) 295 errx(11, "no memory"); 296 return (bp); 297 } 298 299 void 300 writeop(fd, type) 301 int fd, type; 302 { 303 struct mtop op; 304 305 op.mt_op = type; 306 op.mt_count = (daddr_t)1; 307 if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 308 err(6, "tape op"); 309 } 310 311 static void 312 usage() 313 { 314 fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n"); 315 exit(1); 316 } 317 318 void 319 rewind_tape(int fd) 320 { 321 struct stat sp; 322 323 if(fstat(fd, &sp)) 324 errx(12, "fstat in rewind"); 325 326 /* 327 * don't want to do tape ioctl on regular files: 328 */ 329 if( S_ISREG(sp.st_mode) ) { 330 if( lseek(fd, 0, SEEK_SET) == -1 ) 331 errx(13, "lseek"); 332 } else 333 /* assume its a tape */ 334 writeop(fd, MTREW); 335 } 336