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