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