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